com.tealeaf.plugin.PluginEvent.java Source code

Java tutorial

Introduction

Here is the source code for com.tealeaf.plugin.PluginEvent.java

Source

/* @license
 * This file is part of the Game Closure SDK.
 *
 * The Game Closure SDK is free software: you can redistribute it and/or modify
 * it under the terms of the Mozilla Public License v. 2.0 as published by Mozilla.
    
 * The Game Closure SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * Mozilla Public License v. 2.0 for more details.
    
 * You should have received a copy of the Mozilla Public License v. 2.0
 * along with the Game Closure SDK.  If not, see <http://mozilla.org/MPL/2.0/>.
 */
package com.tealeaf.plugin;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map.Entry;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import com.tealeaf.logger;
import com.tealeaf.EventQueue;
import com.tealeaf.event.Event;
import org.json.JSONObject;
import org.json.JSONException;

import dalvik.system.DexFile;

class PluginEvent extends Event {
    String eventName;
    String pluginName;
    Object data;

    public PluginEvent(String eventName, String pluginName, Object data) {
        super("pluginEvent");
        this.eventName = eventName;
        this.pluginName = pluginName;
        this.data = data;
    }

    @Override
    public String pack() {
        // Handle case where data is a JSONObject and do smarter serialization
        // Will this break old plugins who expect strings from Java?
        if (this.data instanceof JSONObject) {
            try {
                JSONObject obj = new JSONObject();
                obj.put("name", this.name);
                obj.put("eventName", this.eventName);
                obj.put("pluginName", this.pluginName);
                obj.put("data", this.data);

                return obj.toString();
            } catch (JSONException e) {
                return super.pack();
            }
        }

        return super.pack();
    }
}

class ResponseWrapper extends Event {
    String error;
    Object response;
    int _requestId;

    public ResponseWrapper(Object response, String error, int requestId) {
        super("plugins");
        this.error = error;
        this.response = response;
        this._requestId = requestId;
    }

    @Override
    public String pack() {
        if (this.response instanceof JSONObject) {
            JSONObject res = new JSONObject();
            try {
                res.put("name", "plugins");
                res.put("error", this.error);
                res.put("response", this.response);
                res.put("_requestId", this._requestId);
                return res.toString();
            } catch (JSONException e) {
                // pass
            }
        }

        return super.pack();
    }
}

public class PluginManager {
    private static String PACKAGE_NAME = "com.tealeaf";
    private static String PLUGINS_PACKAGE_NAME = "com.tealeaf.plugin.plugins";
    private static HashMap<String, Object> classMap = new HashMap<String, Object>();

    private static boolean initialized = false;

    public static void init(Context context) {
        if (initialized) {
            return;
        }
        initialized = true;
        ArrayList<String> classNames = new ArrayList<String>();

        try {
            String apkName = null;

            try {
                apkName = context.getPackageManager()
                        .getApplicationInfo(context.getApplicationContext().getPackageName(), 0).sourceDir;
            } catch (NameNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            DexFile dexFile = new DexFile(new File(apkName));
            Enumeration<String> enumeration = dexFile.entries();

            int pluginsPackageStrLen = PLUGINS_PACKAGE_NAME.length();

            while (enumeration.hasMoreElements()) {
                String className = enumeration.nextElement();

                if (className.length() < pluginsPackageStrLen)
                    continue;

                if (!className.contains("$")) {
                    if (className.subSequence(0, pluginsPackageStrLen).equals(PLUGINS_PACKAGE_NAME)) {
                        classNames.add(className);
                    }
                }
            }
        } catch (IOException e) {
            logger.log(e);
        }

        if (classNames.size() > 0) {
            String[] classNamesArr = new String[classNames.size()];
            classNames.toArray(classNamesArr);

            for (String name : classNamesArr) {
                try {
                    Class objcls = Class.forName(name);

                    if (IPlugin.class.isAssignableFrom(objcls)) {
                        Object instance = objcls.newInstance();

                        if (instance != null) {
                            logger.log("{plugins} Instantiated:", name);
                            classMap.put(name, instance);
                        } else {
                            logger.log("{plugins} WARNING: Class not found:", name);
                        }
                    } else {
                        logger.log("{plugins} Ignoring class that does not derive from IPlugin:", name);
                    }
                } catch (ClassNotFoundException e) {
                    logger.log("{plugins} WARNING: Class not found:", name);
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    private static String invokeMethod(Object targetObject, Object[] parameters, String methodName,
            String className) {
        String retStr = "{}";

        if (targetObject == null) {
            logger.log("{plugins} WARNING: Event could not be delivered for missing plugin:", className);
            return retStr;
        }

        boolean found = false;

        for (Method method : targetObject.getClass().getMethods()) {
            if (!method.getName().equals(methodName)) {
                continue;
            }

            Class<?>[] parameterTypes = method.getParameterTypes();
            boolean match = true;

            for (int i = 0; i < parameterTypes.length; i++) {
                if (parameters[i] == null) {
                    continue;
                }
                if (!parameterTypes[i].isAssignableFrom(parameters[i].getClass())) {
                    match = false;
                    break;
                }
            }

            if (!match && parameters.length != 0) {
                try {
                    // try and coerce string argument in the first place to a JSONObject
                    if (parameters[0] instanceof String) {
                        JSONObject arg = new JSONObject((String) parameters[0]);
                        parameters[0] = arg;
                        if (parameterTypes[0].isAssignableFrom(parameters[0].getClass())) {
                            match = true;
                        }
                    }
                } catch (JSONException e) {
                    // first param is not valid JSON. Pass.
                }
            }

            if (match) {
                try {
                    if (method.getReturnType().equals(Void.TYPE)) {
                        method.invoke(targetObject, parameters);
                    } else if (method.getReturnType().equals(String.class)) {
                        retStr = (String) method.invoke(targetObject, parameters);
                    } else {
                        retStr = "" + method.invoke(targetObject, parameters);
                    }

                    found = true;
                } catch (IllegalArgumentException e) {
                    logger.log(e);
                } catch (IllegalAccessException e) {
                    logger.log(e);
                } catch (InvocationTargetException e) {
                    logger.log(e);
                }
            }
        }

        if (!found) {
            logger.log("{plugins} WARNING: Unknown event could not be delivered for plugin:", className,
                    ", method:", methodName);
        }
        if (retStr == null) {
            retStr = "{}";
        }

        return retStr;
    }

    public static String[] callAll(String methodName, Object... params) {
        String[] strs = new String[classMap.size()];
        int i = 0;

        for (Entry<String, Object> classEntry : classMap.entrySet()) {
            String s = (String) invokeMethod(classEntry.getValue(), params, methodName, "any");
            strs[i++] = s;
        }

        return strs;
    }

    public static String call(String className, String methodName, Object... params) {
        return invokeMethod(classMap.get("com.tealeaf.plugin.plugins." + className), params, methodName, className);
    }

    public static void request(String className, String methodName, Object[] params, int requestId) {
        //add the requestId the the parameters being passed to the plugin method   
        Object[] parametersWithRequestId = new Object[params.length + 1];
        System.arraycopy(params, 0, parametersWithRequestId, 0, params.length);
        parametersWithRequestId[parametersWithRequestId.length - 1] = requestId;
        call(className, methodName, parametersWithRequestId);
    }

    public static void sendResponse(Object response, String error, int requestId) {
        EventQueue.pushEvent(new ResponseWrapper(response, error, requestId));
    }

    public static void sendEvent(String eventName, String pluginName, Object data) {
        EventQueue.pushEvent(new PluginEvent(eventName, pluginName, data));
    }
}