All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.soluble.pjb.script.InvocablePhpScriptEngine Maven / Gradle / Ivy

There is a newer version: 7.1.3
Show newest version
/*-*- mode: Java; tab-width:8 -*-*/

package io.soluble.pjb.script;

/*
 * Copyright (C) 2003-2007 Jost Boekemeier
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.script.Bindings;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptException;

import io.soluble.pjb.bridge.PhpProcedure;
import io.soluble.pjb.bridge.Request;
import io.soluble.pjb.bridge.Util;
import io.soluble.pjb.bridge.http.IContext;

/**
 * This class implements the ScriptEngine and the Invocable interface.

* Example: *

* * ScriptEngine e = (new ScriptEngineManager()).getEngineByName("php-invocable");
* e.eval(<? function f() {return java_server_name();}?>
* System.out.println(((Invocable)e).invokeFunction("f", new Object[]{}));
* ((Closeable)e).close();
*
*

* Another example which invokes a remote PHP "method" bound in the closed-over PHP environment. The PHP script "hello.php": *
* * <?php require_once("java/Java.inc");
* function f() {return java_server_name();};
* java_call_with_continuation(java_closure());
* ?>
*
*

* The Java code: *
* * ScriptEngine e = (new ScriptEngineManager()).getEngineByName("php-invocable");
* e.eval(new io.soluble.pjb.script.URLReader(new URL("http://localhost/hello.php")));
* System.out.println(((Invocable)e).invokeMethod(e.get("io.soluble.pjb.PhpProcedure"), "f", new Object[]{}));
* ((Closeable)e).close();
*
*
*/ public class InvocablePhpScriptEngine extends AbstractPhpScriptEngine implements Invocable { private static final String X_JAVABRIDGE_INCLUDE = Util.X_JAVABRIDGE_INCLUDE; private static final String PHP_JAVA_CONTEXT_CALL_JAVA_CLOSURE = "call(java_closure()); ?>"; protected static final Object EMPTY_INCLUDE = "@"; private static boolean registeredHook = false; private static final List engines = new LinkedList(); private static final String PHP_EMPTY_SCRIPT = ""; /** * Create a new ScriptEngine with a default context. */ public InvocablePhpScriptEngine() { this(new PhpScriptEngineFactory()); } /** * Create a new ScriptEngine from a factory. * * @param factory The factory * @see #getFactory() */ public InvocablePhpScriptEngine(PhpScriptEngineFactory factory) { super(factory); } /** * Create a new ScriptEngine with bindings. * * @param n the bindings */ public InvocablePhpScriptEngine(Bindings n) { this(); setBindings(n, ScriptContext.ENGINE_SCOPE); } /* (non-Javadoc) * @see javax.script.Invocable#call(java.lang.String, java.lang.Object[]) */ protected Object invoke(String methodName, Object[] args) throws ScriptException, NoSuchMethodException { if (methodName == null) { release(); return null; } if (scriptClosure == null) { if (Util.logLevel > 4) Util.warn("Evaluating an empty script either because eval() has not been called or release() has been called."); eval(PHP_EMPTY_SCRIPT); } try { return invoke(scriptClosure, methodName, args); } catch (Request.AbortException e) { release(); throw new ScriptException(e); } catch (NoSuchMethodError e) { // conform to jsr223 throw new NoSuchMethodException(String.valueOf(e.getMessage())); } } /** * {@inheritDoc} */ public Object invokeFunction(String methodName, Object[] args) throws ScriptException, NoSuchMethodException { return invoke(methodName, args); } private void checkPhpClosure(Object thiz) { if (thiz == null) throw new IllegalStateException("PHP script did not pass its continuation to us!. Please check if the previous call to eval() reported any errors. Or else check if it called OUR continuation."); } /* (non-Javadoc) * @see javax.script.Invocable#call(java.lang.String, java.lang.Object, java.lang.Object[]) */ protected Object invoke(Object thiz, String methodName, Object[] args) throws ScriptException, NoSuchMethodException { checkPhpClosure(thiz); PhpProcedure proc = (PhpProcedure) (Proxy.getInvocationHandler(thiz)); try { return proc.invoke(script, methodName, args); } catch (ScriptException e) { throw e; } catch (NoSuchMethodException e) { throw e; } catch (RuntimeException e) { throw e; // don't wrap RuntimeException } catch (NoSuchMethodError e) { // conform to jsr223 throw new NoSuchMethodException(String.valueOf(e.getMessage())); } catch (Error er) { throw er; } catch (Throwable e) { throw new PhpScriptException("Invocation threw exception ", e); } } /** * {@inheritDoc} */ public Object invokeMethod(Object thiz, String methodName, Object[] args) throws ScriptException, NoSuchMethodException { return invoke(thiz, methodName, args); } /** * {@inheritDoc} */ public Object getInterface(Class clasz) { checkPhpClosure(script); return getInterface(script, clasz); } /** * {@inheritDoc} */ public Object getInterface(Object thiz, Class clasz) { checkPhpClosure(thiz); Class[] interfaces = clasz == null ? Util.ZERO_PARAM : new Class[]{clasz}; return PhpProcedure.createProxy(interfaces, (PhpProcedure) Proxy.getInvocationHandler(thiz)); } protected Reader getLocalReader(Reader reader, boolean embedJavaInc) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = new OutputStreamWriter(out); String stdHeader = embedJavaInc ? null : ((IContext) getContext()).getRedirectURL("/JavaBridge"); Reader localReader = new StringReader(getStandardHeader(stdHeader)); char[] buf = new char[Util.BUF_SIZE]; int c; try { /* header: /JavaBridge/java/Java.inc"); ?> */ while ((c = localReader.read(buf)) > 0) w.write(buf, 0, c); localReader.close(); localReader = null; /* the script: */ while ((c = reader.read(buf)) > 0) w.write(buf, 0, c); /* get the default, top-level, closure and call it, to stop the script from terminating */ localReader = new StringReader(PHP_JAVA_CONTEXT_CALL_JAVA_CLOSURE); while ((c = localReader.read(buf)) > 0) w.write(buf, 0, c); localReader.close(); localReader = null; w.close(); w = null; /* now evaluate our script */ localReader = new InputStreamReader(new ByteArrayInputStream(out.toByteArray())); return localReader; } finally { if (w != null) try { w.close(); } catch (IOException e) {/*ignore*/} } } protected Object doEvalPhp(Reader reader, ScriptContext context) throws ScriptException { if (reader instanceof URLReader) return eval((URLReader) reader, context); if ((continuation != null) || (reader == null)) release(); if (reader == null) return null; setNewContextFactory(); env.put(X_JAVABRIDGE_INCLUDE, EMPTY_INCLUDE); Reader localReader = null; try { localReader = getLocalReader(reader, false); this.script = doEval(localReader, context); if (this.script != null) { /* get the proxy, either the one from the user script or our default proxy */ this.scriptClosure = script; } } catch (Exception e) { Util.printStackTrace(e); if (e instanceof RuntimeException) throw (RuntimeException) e; if (e instanceof ScriptException) throw (ScriptException) e; throw new ScriptException(e); } finally { if (localReader != null) try { localReader.close(); } catch (IOException e) {/*ignore*/} handleRelease(); } return resultProxy; } protected Object doEvalCompiledPhp(Reader reader, ScriptContext context) throws ScriptException { if ((continuation != null) || (reader == null)) release(); if (reader == null) return null; setNewContextFactory(); env.put(X_JAVABRIDGE_INCLUDE, EMPTY_INCLUDE); try { this.script = doEval(reader, context); if (this.script != null) { /* get the proxy, either the one from the user script or our default proxy */ this.scriptClosure = script; } } catch (Exception e) { Util.printStackTrace(e); if (e instanceof RuntimeException) throw (RuntimeException) e; if (e instanceof ScriptException) throw (ScriptException) e; throw new ScriptException(e); } finally { handleRelease(); } return resultProxy; } protected Object eval(URLReader reader, ScriptContext context) throws ScriptException { if ((continuation != null) || (reader == null)) release(); if (reader == null) return null; setNewContextFactory(); env.put(X_JAVABRIDGE_INCLUDE, EMPTY_INCLUDE); ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = new OutputStreamWriter(out); try { this.script = doEval(reader, context); if (this.script != null) { /* get the proxy, either the one from the user script or our default proxy */ this.scriptClosure = script; } } catch (Exception e) { Util.printStackTrace(e); if (e instanceof RuntimeException) throw (RuntimeException) e; if (e instanceof ScriptException) throw (ScriptException) e; throw new ScriptException(e); } finally { if (w != null) try { w.close(); } catch (IOException e) {/*ignore*/} handleRelease(); } return resultProxy; } protected void handleRelease() { // make sure to properly release them upon System.exit(). synchronized (engines) { if (!registeredHook) { registeredHook = true; try { Runtime.getRuntime().addShutdownHook(new Util.Thread() { public void run() { if (engines == null) return; synchronized (engines) { for (Iterator ii = engines.iterator(); ii.hasNext(); ii.remove()) { InvocablePhpScriptEngine e = (InvocablePhpScriptEngine) ii.next(); e.releaseInternal(); } } } }); } catch (SecurityException e) {/*ignore*/} } engines.add(this); } } private void releaseInternal() { super.release(); } /** * {@inheritDoc} */ public void release() { synchronized (engines) { releaseInternal(); engines.remove(this); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy