| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.monkeyrunner; |
| |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Maps; |
| import com.google.common.collect.ImmutableMap.Builder; |
| |
| import com.android.monkeyrunner.doc.MonkeyRunnerExported; |
| |
| import org.python.core.ArgParser; |
| import org.python.core.PyDictionary; |
| import org.python.core.PyFloat; |
| import org.python.core.PyInteger; |
| import org.python.core.PyList; |
| import org.python.core.PyObject; |
| import org.python.core.PyString; |
| import org.python.core.PyTuple; |
| |
| import java.lang.reflect.Method; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * Collection of useful utilities function for interacting with the Jython interpreter. |
| */ |
| public final class JythonUtils { |
| private static final Logger LOG = Logger.getLogger(JythonUtils.class.getCanonicalName()); |
| private JythonUtils() { } |
| |
| /** |
| * Mapping of PyObject classes to the java class we want to convert them to. |
| */ |
| private static final Map<Class<? extends PyObject>, Class<?>> PYOBJECT_TO_JAVA_OBJECT_MAP; |
| static { |
| Builder<Class<? extends PyObject>, Class<?>> builder = ImmutableMap.builder(); |
| |
| builder.put(PyString.class, String.class); |
| builder.put(PyFloat.class, Float.class); |
| builder.put(PyInteger.class, Integer.class); |
| |
| PYOBJECT_TO_JAVA_OBJECT_MAP = builder.build(); |
| } |
| |
| /** |
| * Utility method to be called from Jython bindings to give proper handling of keyword and |
| * positional arguments. |
| * |
| * @param args the PyObject arguments from the binding |
| * @param kws the keyword arguments from the binding |
| * @return an ArgParser for this binding, or null on error |
| */ |
| public static ArgParser createArgParser(PyObject[] args, String[] kws) { |
| StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); |
| // Up 2 levels in the current stack to give us the calling function |
| StackTraceElement element = stackTrace[2]; |
| |
| String methodName = element.getMethodName(); |
| String className = element.getClassName(); |
| |
| Class<?> clz; |
| try { |
| clz = Class.forName(className); |
| } catch (ClassNotFoundException e) { |
| LOG.log(Level.SEVERE, "Got exception: ", e); |
| return null; |
| } |
| |
| Method m; |
| |
| try { |
| m = MonkeyRunner.class.getMethod(methodName, PyObject[].class, String[].class); |
| } catch (SecurityException e) { |
| LOG.log(Level.SEVERE, "Got exception: ", e); |
| return null; |
| } catch (NoSuchMethodException e) { |
| LOG.log(Level.SEVERE, "Got exception: ", e); |
| return null; |
| } |
| |
| MonkeyRunnerExported annotation = m.getAnnotation(MonkeyRunnerExported.class); |
| return new ArgParser(methodName, args, kws, |
| annotation.args()); |
| } |
| |
| /** |
| * Get a python floating point value from an ArgParser. |
| * |
| * @param ap the ArgParser to get the value from. |
| * @param position the position in the parser |
| * @return the double value |
| */ |
| public static double getFloat(ArgParser ap, int position) { |
| // cast is safe as getPyObjectbyType ensures it |
| PyFloat object = (PyFloat) ap.getPyObjectByType(position, PyFloat.TYPE); |
| return object.asDouble(); |
| } |
| |
| /** |
| * Get a list of arguments from an ArgParser. |
| * |
| * @param <T> the type of list items to return |
| * @param ap the ArgParser |
| * @param position the position in the parser to get the argument from |
| * @param clz the type of items to return |
| * @return a list of those items |
| */ |
| @SuppressWarnings("unchecked") |
| public static <T> List<T> getList(ArgParser ap, int position, Class<?> clz) { |
| List<T> ret = Lists.newArrayList(); |
| // cast is safe as getPyObjectbyType ensures it |
| PyList array = (PyList) ap.getPyObjectByType(position, PyList.TYPE); |
| for (int x = 0; x < array.__len__(); x++) { |
| T item = (T) array.__getitem__(x).__tojava__(clz); |
| ret.add(item); |
| } |
| return ret; |
| } |
| |
| /** |
| * Get a dictionary from an ArgParser. |
| * |
| * @param ap the ArgParser to work with |
| * @param position the position in the parser to get. |
| * @return a Map mapping the String key to their underlying type. |
| */ |
| public static Map<String, Object> getMap(ArgParser ap, int position) { |
| Map<String, Object> ret = Maps.newHashMap(); |
| // cast is safe as getPyObjectbyType ensures it |
| PyDictionary dict = (PyDictionary) ap.getPyObjectByType(position, PyDictionary.TYPE); |
| PyList items = dict.items(); |
| for (int x = 0; x < items.__len__(); x++) { |
| // It's a list of tuples |
| PyTuple item = (PyTuple) items.__getitem__(x); |
| String key = (String) item.__getitem__(0).__tojava__(String.class); |
| PyObject value = item.__getitem__(1); |
| |
| // Look up the conversion type and convert the value |
| Class<?> javaClass = PYOBJECT_TO_JAVA_OBJECT_MAP.get(value.getClass()); |
| if (javaClass != null) { |
| ret.put(key, value.__tojava__(javaClass)); |
| } |
| } |
| return ret; |
| } |
| } |