/*
 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.script.util;

import javax.script.*;
import java.lang.reflect.*;
import java.security.*;
import sun.reflect.misc.ReflectUtil;

/*
 * java.lang.reflect.Proxy based interface implementor. This is meant
 * to be used to implement Invocable.getInterface.
 *
 * @author Mike Grogan
 * @since 1.6
 */
public class InterfaceImplementor {

    private Invocable engine;

    
Creates a new instance of Invocable
/** Creates a new instance of Invocable */
public InterfaceImplementor(Invocable engine) { this.engine = engine; } private final class InterfaceImplementorInvocationHandler implements InvocationHandler { private Object thiz; private AccessControlContext accCtxt; public InterfaceImplementorInvocationHandler(Object thiz, AccessControlContext accCtxt) { this.thiz = thiz; this.accCtxt = accCtxt; } public Object invoke(Object proxy , Method method, Object[] args) throws java.lang.Throwable { // give chance to convert input args args = convertArguments(method, args); Object result; final Method m = method; final Object[] a = args; result = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { if (thiz == null) { return engine.invokeFunction(m.getName(), a); } else { return engine.invokeMethod(thiz, m.getName(), a); } } }, accCtxt); // give chance to convert the method result return convertResult(method, result); } } public <T> T getInterface(Object thiz, Class<T> iface) throws ScriptException { if (iface == null || !iface.isInterface()) { throw new IllegalArgumentException("interface Class expected"); } if (! isImplemented(thiz, iface)) { return null; } if (System.getSecurityManager() != null && !Modifier.isPublic(iface.getModifiers())) { throw new SecurityException("attempt to implement non-public interface"); } // make sure restricted package interfaces are not attempted. ReflectUtil.checkPackageAccess(iface.getName()); AccessControlContext accCtxt = AccessController.getContext(); return iface.cast(Proxy.newProxyInstance( getLoaderForProxy(iface), new Class[]{iface}, new InterfaceImplementorInvocationHandler(thiz, accCtxt))); } protected boolean isImplemented(Object thiz, Class<?> iface) { return true; } // called to convert method result after invoke protected Object convertResult(Method method, Object res) throws ScriptException { // default is identity conversion return res; } // called to convert method arguments before invoke protected Object[] convertArguments(Method method, Object[] args) throws ScriptException { // default is identity conversion return args; } // get appropriate ClassLoader for generated Proxy class private static ClassLoader getLoaderForProxy(Class<?> iface) { ClassLoader loader = iface.getClassLoader(); // if bootstrap class, try TCCL if (loader == null) { loader = Thread.currentThread().getContextClassLoader(); } // if TCCL is also null, try System class loader if (loader == null) { loader = ClassLoader.getSystemClassLoader(); } return loader; } }