PageRenderTime 12ms CodeModel.GetById 1ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/zeroxlab/wookieerunner/WookieeRunnerStarter.java

https://code.google.com/
Java | 211 lines | 156 code | 23 blank | 32 comment | 14 complexity | f30a2927da5bf1f5913a7f2610f732e4 MD5 | raw file
  1/*
  2 * Copyright (C) 2011 0xlab - http://0xlab.org/
  3 * Copyright (C) 2010 The Android Open Source Project
  4 *
  5 * Licensed under the Apache License, Version 2.0 (the "License");
  6 * you may not use this file except in compliance with the License.
  7 * You may obtain a copy of the License at
  8 *
  9 *      http://www.apache.org/licenses/LICENSE-2.0
 10 *
 11 * Unless required by applicable law or agreed to in writing, software
 12 * distributed under the License is distributed on an "AS IS" BASIS,
 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14 * See the License for the specific language governing permissions and
 15 * limitations under the License.
 16 *
 17 * Owl integration for Aster by Wei-Ning Huang <azhuang@0xlab.org>
 18 */
 19package org.zeroxlab.wookieerunner;
 20
 21import com.google.common.base.Predicate;
 22import com.google.common.base.Predicates;
 23import com.google.common.collect.ImmutableMap;
 24
 25import com.android.chimpchat.ChimpChat;
 26
 27import com.android.monkeyrunner.MonkeyFormatter;
 28import com.android.monkeyrunner.MonkeyRunnerOptions;
 29import com.android.monkeyrunner.doc.MonkeyRunnerExported;
 30
 31import org.zeroxlab.wookieerunner.ScriptRunner;
 32
 33import org.python.util.PythonInterpreter;
 34
 35import java.io.File;
 36import java.io.IOException;
 37import java.net.MalformedURLException;
 38import java.net.URL;
 39import java.net.URLClassLoader;
 40import java.util.Enumeration;
 41import java.util.Map;
 42import java.util.TreeMap;
 43import java.util.jar.Attributes;
 44import java.util.jar.JarFile;
 45import java.util.jar.Manifest;
 46import java.util.logging.Formatter;
 47import java.util.logging.Handler;
 48import java.util.logging.Level;
 49import java.util.logging.LogManager;
 50import java.util.logging.Logger;
 51
 52/**
 53 *  MonkeyRunner is a host side application to control a monkey instance on a
 54 *  device. MonkeyRunner provides some useful helper functions to control the
 55 *  device as well as various other methods to help script tests.  This class bootstraps
 56 *  MonkeyRunner.
 57 */
 58public class WookieeRunnerStarter {
 59    private static final Logger LOG = Logger.getLogger(WookieeRunnerStarter.class.getName());
 60    private static final String MONKEY_RUNNER_MAIN_MANIFEST_NAME = "MonkeyRunnerStartupRunner";
 61
 62    private final ChimpChat chimp;
 63    private final MonkeyRunnerOptions options;
 64    private final ScriptRunner scriptrunner;
 65
 66    public WookieeRunnerStarter(MonkeyRunnerOptions options) {
 67        Map<String, String> chimp_options = new TreeMap<String, String>();
 68        chimp_options.put("backend", options.getBackendName());
 69        this.options = options;
 70        this.chimp = ChimpChat.getInstance(chimp_options);
 71        WookieeRunner.setChimpChat(chimp);
 72
 73        String wookieeRunnerPath = System.getProperty("com.android.wookieerunner.bindir") +
 74                File.separator + "wookieerunner";
 75        Map<String, Predicate<PythonInterpreter>> plugins = handlePlugins();
 76        scriptrunner = ScriptRunner.newInstance(null, null, wookieeRunnerPath);
 77    }
 78
 79    public void runString(String source) {
 80        scriptrunner.runStringLocal(source);
 81    }
 82
 83    private int run() {
 84        // This system property gets set by the included starter script
 85        String wookieeRunnerPath = System.getProperty("com.android.wookieerunner.bindir") +
 86                File.separator + "wookieerunner";
 87
 88        Map<String, Predicate<PythonInterpreter>> plugins = handlePlugins();
 89        if (options.getScriptFile() == null) {
 90            ScriptRunner.console(wookieeRunnerPath);
 91            chimp.shutdown();
 92            return 0;
 93        } else {
 94            int error = ScriptRunner.run(wookieeRunnerPath, options.getScriptFile().getAbsolutePath(),
 95                    options.getArguments(), plugins);
 96            chimp.shutdown();
 97            return error;
 98        }
 99    }
100
101    private Predicate<PythonInterpreter> handlePlugin(File f) {
102        JarFile jarFile;
103        try {
104            jarFile = new JarFile(f);
105        } catch (IOException e) {
106            LOG.log(Level.SEVERE, "Unable to open plugin file.  Is it a jar file? " +
107                    f.getAbsolutePath(), e);
108            return Predicates.alwaysFalse();
109        }
110        Manifest manifest;
111        try {
112            manifest = jarFile.getManifest();
113        } catch (IOException e) {
114            LOG.log(Level.SEVERE, "Unable to get manifest file from jar: " +
115                    f.getAbsolutePath(), e);
116            return Predicates.alwaysFalse();
117        }
118        Attributes mainAttributes = manifest.getMainAttributes();
119        String pluginClass = mainAttributes.getValue(MONKEY_RUNNER_MAIN_MANIFEST_NAME);
120        if (pluginClass == null) {
121            // No main in this plugin, so it always succeeds.
122            return Predicates.alwaysTrue();
123        }
124        URL url;
125        try {
126            url =  f.toURI().toURL();
127        } catch (MalformedURLException e) {
128            LOG.log(Level.SEVERE, "Unable to convert file to url " + f.getAbsolutePath(),
129                    e);
130            return Predicates.alwaysFalse();
131        }
132        URLClassLoader classLoader = new URLClassLoader(new URL[] { url },
133                ClassLoader.getSystemClassLoader());
134        Class<?> clz;
135        try {
136            clz = Class.forName(pluginClass, true, classLoader);
137        } catch (ClassNotFoundException e) {
138            LOG.log(Level.SEVERE, "Unable to load the specified plugin: " + pluginClass, e);
139            return Predicates.alwaysFalse();
140        }
141        Object loadedObject;
142        try {
143            loadedObject = clz.newInstance();
144        } catch (InstantiationException e) {
145            LOG.log(Level.SEVERE, "Unable to load the specified plugin: " + pluginClass, e);
146            return Predicates.alwaysFalse();
147        } catch (IllegalAccessException e) {
148            LOG.log(Level.SEVERE, "Unable to load the specified plugin " +
149                    "(did you make it public?): " + pluginClass, e);
150            return Predicates.alwaysFalse();
151        }
152        // Cast it to the right type
153        if (loadedObject instanceof Runnable) {
154            final Runnable run = (Runnable) loadedObject;
155            return new Predicate<PythonInterpreter>() {
156                public boolean apply(PythonInterpreter i) {
157                    run.run();
158                    return true;
159                }
160            };
161        } else if (loadedObject instanceof Predicate<?>) {
162            return (Predicate<PythonInterpreter>) loadedObject;
163        } else {
164            LOG.severe("Unable to coerce object into correct type: " + pluginClass);
165            return Predicates.alwaysFalse();
166        }
167    }
168
169    private Map<String, Predicate<PythonInterpreter>> handlePlugins() {
170        ImmutableMap.Builder<String, Predicate<PythonInterpreter>> builder = ImmutableMap.builder();
171        for (File f : options.getPlugins()) {
172            builder.put(f.getAbsolutePath(), handlePlugin(f));
173        }
174        return builder.build();
175    }
176
177        /* Similar to above, when this fails, it no longer throws a
178         * runtime exception, but merely will log the failure.
179         */
180
181
182    private static final void replaceAllLogFormatters(Formatter form, Level level) {
183        LogManager mgr = LogManager.getLogManager();
184        Enumeration<String> loggerNames = mgr.getLoggerNames();
185        while (loggerNames.hasMoreElements()) {
186            String loggerName = loggerNames.nextElement();
187            Logger logger = mgr.getLogger(loggerName);
188            for (Handler handler : logger.getHandlers()) {
189                handler.setFormatter(form);
190                handler.setLevel(level);
191            }
192        }
193    }
194
195    public static void main(String[] args) {
196        MonkeyRunnerOptions options = MonkeyRunnerOptions.processOptions(args);
197
198        if (options == null) {
199            return;
200        }
201
202        // logging property files are difficult
203        replaceAllLogFormatters(MonkeyFormatter.DEFAULT_INSTANCE, options.getLogLevel());
204
205        WookieeRunnerStarter runner = new WookieeRunnerStarter(options);
206        int error = runner.run();
207
208        // This will kill any background threads as well.
209        System.exit(error);
210    }
211}