org.dbasu.robomvvm.componentmodel.ActionManager.java Source code

Java tutorial

Introduction

Here is the source code for org.dbasu.robomvvm.componentmodel.ActionManager.java

Source

/**
 * @project RoboMVVM
 * @project RoboMVVM(https://github.com/debdattabasu/RoboMVVM)
 * @author Debdatta Basu
 *
 * @license 3-clause BSD license(http://opensource.org/licenses/BSD-3-Clause).
 *      Copyright (c) 2014, Debdatta Basu. All rights reserved.
 *
 *      Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 *      the following conditions are met:
 *
 *          1. Redistributions of source code must retain the above copyright notice, this list of
 *             conditions and the following disclaimer.
 *
 *          2. Redistributions in binary form must reproduce the above copyright notice, this list of
 *             conditions and the following disclaimer in the documentation and/or other materials
 *             provided with the distribution.
 *
 *          3. Neither the name of the copyright holder nor the names of its contributors may be used
 *             to endorse or promote products derived from this software without specific prior
 *             written permission.
 *
 *      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *      INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *      IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 *      OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 *      OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 *      OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *      POSSIBILITY OF SUCH DAMAGE.
 */

package org.dbasu.robomvvm.componentmodel;

import android.app.Activity;
import android.view.View;

import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;

import org.apache.commons.lang3.ClassUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * Package private class used for invoking actions by {@link org.dbasu.robomvvm.componentmodel.Component}.
 */
class ActionManager {

    private static class ActionDescriptor {

        private final Collection<Method> methods;
        private final String name;
        private final Class objectType;

        private ActionDescriptor(Class objectType, String name, Collection<Method> methods) {
            this.methods = methods;
            this.name = name;
            this.objectType = objectType;
        }
    }

    private static final ThreadLocal<ActionManager> instance = new ThreadLocal<ActionManager>() {

        @Override
        protected synchronized ActionManager initialValue() {
            return new ActionManager();
        }
    };

    static ActionManager get() {

        return instance.get();
    }

    private ActionManager() {

    }

    private final Map<String, ActionDescriptor> actionMap = new HashMap<String, ActionDescriptor>();

    private void reallyInvokeAction(Collection<Method> handler, Object targetObject, Object eventArg) {
        try {
            for (Method m : handler) {
                if (m.getParameterTypes().length == 0) {
                    m.invoke(targetObject);
                } else {
                    m.invoke(targetObject, eventArg);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void invokeAction(final Object targetObject, String actionName, final EventArg eventArg) {

        Class targetType = targetObject.getClass();
        final Class<? extends EventArg> eventType = eventArg != null ? eventArg.getClass() : null;

        final ActionDescriptor handlerDescription = getActionDescriptor(targetType, actionName);

        if (handlerDescription == null) {
            throw new RuntimeException(
                    "No Action By Name " + actionName + " Found In Class " + targetType.getName());
        }

        final Collection<Method> relevantMethods = Collections2.filter(handlerDescription.methods,
                new Predicate<Method>() {
                    @Override
                    public boolean apply(Method m) {

                        Class[] params = m.getParameterTypes();

                        return params.length == 0 || (eventType != null && params.length == 1
                                && ClassUtils.isAssignable(eventType, params[0], true));

                    }
                });

        if (relevantMethods.size() == 0) {

            throw new RuntimeException("Action By Name " + actionName + " Does Not Support Actions Of Type "
                    + ((eventType == null) ? " {null} " : eventType.getName()));
        }

        if (targetObject instanceof View) {
            Activity activity = (Activity) ((View) targetObject).getContext();

            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    reallyInvokeAction(relevantMethods, targetObject, eventArg);
                }
            });
        } else {
            reallyInvokeAction(relevantMethods, targetObject, eventArg);
        }
    }

    private ActionDescriptor reallyGetActionDescriptor(Class objectType, final String actionName) {

        Collection<Method> methodList = Collections2.filter(Arrays.asList(objectType.getMethods()),
                new Predicate<Method>() {
                    @Override
                    public boolean apply(Method m) {
                        return m.getName().equals(actionName) && m.getReturnType().equals(Void.TYPE)
                                && m.getParameterTypes().length <= 1;
                    }
                });

        return new ActionDescriptor(objectType, actionName, methodList);
    }

    private ActionDescriptor getActionDescriptor(Class objectType, String actionName) {

        String hash = objectType.getName() + "" + actionName;

        ActionDescriptor ret = actionMap.get(hash);

        if (ret != null)
            return ret;

        ret = reallyGetActionDescriptor(objectType, actionName);

        if (ret == null)
            return null;

        actionMap.put(hash, ret);

        return ret;

    }
}