1 /*
   2  * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.script.javascript;
  27 
  28 import javax.script.Invocable;
  29 import sun.org.mozilla.javascript.internal.*;
  30 
  31 /**
  32  * This class implements Rhino-like JavaAdapter to help implement a Java
  33  * interface in JavaScript. We support this using Invocable.getInterface.
  34  * Using this JavaAdapter, script author could write:
  35  *
  36  *    var r = new java.lang.Runnable() {
  37  *                run: function() { script... }
  38  *            };
  39  *
  40  *    r.run();
  41  *    new java.lang.Thread(r).start();
  42  *
  43  * Note that Rhino's JavaAdapter support allows extending a Java class and/or
  44  * implementing one or more interfaces. This JavaAdapter implementation does
  45  * not support these.
  46  *
  47  * @author A. Sundararajan
  48  * @since 1.6
  49  */
  50 final class JavaAdapter extends ScriptableObject implements Function {
  51     private JavaAdapter(Invocable engine) {
  52         this.engine = engine;
  53     }
  54 
  55     static void init(Context cx, Scriptable scope, boolean sealed)
  56     throws RhinoException {
  57         RhinoTopLevel topLevel = (RhinoTopLevel) scope;
  58         Invocable engine = topLevel.getScriptEngine();
  59         JavaAdapter obj = new JavaAdapter(engine);
  60         obj.setParentScope(scope);
  61         obj.setPrototype(getFunctionPrototype(scope));
  62         /*
  63          * Note that we can't use defineProperty. A property of this
  64          * name is already defined in Context.initStandardObjects. We
  65          * simply overwrite the property value!
  66          */
  67         ScriptableObject.putProperty(topLevel, "JavaAdapter", obj);
  68     }
  69 
  70     public String getClassName() {
  71         return "JavaAdapter";
  72     }
  73 
  74     public Object call(Context cx, Scriptable scope, Scriptable thisObj,
  75             Object[] args) throws RhinoException {
  76         return construct(cx, scope, args);
  77     }
  78 
  79     public Scriptable construct(Context cx, Scriptable scope, Object[] args)
  80     throws RhinoException {
  81         if (args.length == 2) {
  82             Class<?> clazz = null;
  83             Object obj1 = args[0];
  84             if (obj1 instanceof Wrapper) {
  85                 Object o = ((Wrapper)obj1).unwrap();
  86                 if (o instanceof Class && ((Class)o).isInterface()) {
  87                     clazz = (Class) o;
  88                 }
  89             } else if (obj1 instanceof Class) {
  90                 if (((Class)obj1).isInterface()) {
  91                     clazz = (Class) obj1;
  92                 }
  93             }
  94             if (clazz == null) {
  95                 throw Context.reportRuntimeError("JavaAdapter: first arg should be interface Class");
  96             }
  97 
  98             Scriptable topLevel = ScriptableObject.getTopLevelScope(scope);
  99             return cx.toObject(engine.getInterface(args[1],  clazz), topLevel);
 100         } else {
 101             throw Context.reportRuntimeError("JavaAdapter requires two arguments");
 102         }
 103     }
 104 
 105     private Invocable engine;
 106 }