/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.qrone.r7.script; import java.lang.reflect.Constructor; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import org.mozilla.javascript.Context; import org.mozilla.javascript.NativeJavaObject; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.WrapFactory; import org.qrone.r7.Extendable; import org.qrone.r7.script.ext.ScriptablePrototype; /** * Wraps Java objects by adding support for function extensions, which are * functions that extend existing Java objects at the Rhino level. */ public class SugarWrapFactory extends WrapFactory implements Extendable { private Map<Class, Class> wmap = new Hashtable<Class, Class>(); private Map<Class, List<Class<? extends ScriptablePrototype>>> map = new Hashtable<Class, List<Class<? extends ScriptablePrototype>>>(); public SugarWrapFactory() { super(); } private static Class getInterfaceGenericType(Class cls) { Type[] types = cls.getGenericInterfaces(); for (int i = 0; i < types.length; i++) { if(types[i] instanceof ParameterizedType){ ParameterizedType ty = (ParameterizedType) types[i]; if(ty.getRawType().equals(ScriptablePrototype.class)){ Type[] actualType = ty.getActualTypeArguments(); if (actualType.length > 0 && actualType[0] instanceof Class) { return (Class) actualType[0]; } } } } return null; } public void addExtension(Class wrapper) { if(ScriptablePrototype.class.isAssignableFrom(wrapper)){ Class cls = getInterfaceGenericType(wrapper); addPrototypeClass(cls, wrapper); } } public void setWrapperClass(Class target, Class wrapper){ wmap.put(target, wrapper); } public void addPrototypeClass(Class target, Class<? extends ScriptablePrototype> wrapper){ List<Class<? extends ScriptablePrototype>> l = map.get(target); if(l == null){ l = new ArrayList<Class<? extends ScriptablePrototype>>(); map.put(target, l); } l.add(wrapper); } public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class staticType) { try { NativeJavaObject wrapper = new NativeJavaObject(scope, javaObject, staticType); for (Iterator<Class> i = map.keySet().iterator(); i.hasNext();) { Class type = i.next(); if (type.isInstance(javaObject)) { List<Class<? extends ScriptablePrototype>> l = map.get(type); NativeJavaObject last = wrapper; for (Iterator<Class<? extends ScriptablePrototype>> iter = l.iterator(); iter.hasNext();) { Class<? extends ScriptablePrototype> cls = iter.next(); ScriptablePrototype sjo = null; try{ try{ Constructor<? extends ScriptablePrototype> cr = cls.getConstructor(Scriptable.class, type); sjo = cr.newInstance(scope, javaObject); }catch(Exception e1){ Constructor<? extends ScriptablePrototype> cr = cls.getConstructor(type); sjo = cr.newInstance(javaObject); } }catch(Exception e1){ Constructor<? extends ScriptablePrototype> cr = cls.getConstructor(); sjo = cr.newInstance(); } if(sjo instanceof Scriptable){ return (Scriptable)sjo; } NativeJavaObject wsjo = new NativeJavaObject(scope, sjo, null); last.setPrototype(wsjo); last = wsjo; } return wrapper; } } return wrapper; } catch (Exception e) { e.printStackTrace(); } return super.wrapAsJavaObject(cx, scope, javaObject, staticType); } }