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

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

The 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.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext;

import io.soluble.pjb.bridge.Util;
import io.soluble.pjb.bridge.http.AbstractChannelName;
import io.soluble.pjb.bridge.http.ContextServer;
import io.soluble.pjb.bridge.http.HeaderParser;
import io.soluble.pjb.bridge.http.IContext;
import io.soluble.pjb.bridge.http.IContextFactory;
import io.soluble.pjb.bridge.http.WriterOutputStream;

/**
 * This class implements the ScriptEngine.

* * @see io.soluble.pjb.script.InvocablePhpScriptEngine * @see io.soluble.pjb.script.PhpScriptEngine */ abstract class AbstractPhpScriptEngine extends AbstractScriptEngine implements IPhpScriptEngine, Compilable, java.io.FileFilter, CloneableScript { /** * The allocated script */ protected Object script = null; protected Object scriptClosure = null; /** * The continuation of the script */ protected Continuation continuation = null; protected Map env = null; protected IContextFactory ctx = null; private ScriptEngineFactory factory = null; protected ResultProxy resultProxy; protected File compilerOutputFile; private boolean isCompiled; static HashMap getProcessEnvironment() { return Util.COMMON_ENVIRONMENT; } /** * Create a new ScriptEngine from a factory. * * @param factory The factory * @see #getFactory() */ public AbstractPhpScriptEngine(PhpScriptEngineFactory factory) { super(); this.factory = factory; getContext(); // update context in parent as a side effect } /** * Set the context id (X_JAVABRIDGE_CONTEXT) and the override flag (X_JAVABRIDGE_OVERRIDE_HOSTS) into env * * @param env the environment which will be passed to PHP */ protected void setStandardEnvironmentValues(Map env) { /* send the session context now, otherwise the client has to * call handleRedirectConnection */ env.put(Util.X_JAVABRIDGE_CONTEXT, ctx.getId()); } protected void addNewContextFactory() { ctx = PhpScriptContextFactory.addNew((IContext) getContext()); } protected ContextServer getContextServer() { return ((IPhpScriptContext) getContext()).getContextServer(); } /** * Create a new context ID and a environment map which we send to the client. */ protected void setNewContextFactory() { env = (Map) getProcessEnvironment().clone(); addNewContextFactory(); // short path S1: no PUT request ContextServer contextServer = getContextServer(); AbstractChannelName channelName = contextServer.getChannelName(ctx); if (channelName != null) { env.put("X_JAVABRIDGE_REDIRECT", channelName.getName()); ctx.getBridge(); contextServer.start(channelName, Util.getLogger()); } setStandardEnvironmentValues(env); } /* (non-Javadoc) * @see javax.script.ScriptEngine#eval(java.io.Reader, javax.script.ScriptContext) */ @Override public Object eval(Reader reader, ScriptContext context) throws ScriptException { return evalPhp(reader, context); } protected Object evalPhp(Reader reader, ScriptContext context) throws ScriptException { if (isCompiled) throw new IllegalStateException("already compiled"); ScriptContext current = getContext(); if (current != context) try { setContext(context); return doEvalPhp(reader, context); } finally { setContext(current); } else return doEvalPhp(reader, current); } protected Object evalCompiledPhp(Reader reader, ScriptContext context) throws ScriptException { ScriptContext current = getContext(); if (current != context) try { setContext(context); return doEvalCompiledPhp(reader, context); } finally { setContext(current); } else return doEvalCompiledPhp(reader, current); } protected void compilePhp(Reader reader) throws IOException { this.isCompiled = true; if (compilerOutputFile == null) { compilerOutputFile = File.createTempFile("compiled-", ".php", null); } FileWriter writer = new FileWriter(compilerOutputFile); char[] buf = new char[Util.BUF_SIZE]; try (Reader localReader = getLocalReader(reader, true)) { int c; while ((c = localReader.read(buf)) > 0) writer.write(buf, 0, c); writer.close(); } } private void updateGlobalEnvironment() throws IOException { if (isCompiled) { if (compilerOutputFile == null) throw new NullPointerException("SCRIPT_FILENAME"); env.put("SCRIPT_FILENAME", compilerOutputFile.getCanonicalPath()); } } private final class SimpleHeaderParser extends HeaderParser { private final WriterOutputStream writer; public SimpleHeaderParser(WriterOutputStream writer) { this.writer = writer; } @Override public void parseHeader(String header) { if (header == null) return; int idx = header.indexOf(':'); if (idx == -1) return; String key = header.substring(0, idx).trim().toLowerCase(); String val = header.substring(idx + 1).trim(); addHeader(key, val); } @Override public void addHeader(String key, String val) { if (val != null && key.equals("content-type")) { int idx = val.indexOf(';'); if (idx == -1) return; String enc = val.substring(idx + 1).trim(); idx = enc.indexOf('='); if (idx == -1) return; enc = enc.substring(idx + 1); writer.setEncoding(enc); } } } protected Continuation getContinuation(Reader reader, ScriptContext context) throws IOException { HeaderParser headerParser = HeaderParser.DEFAULT_HEADER_PARSER; // ignore encoding, we pass everything directly IPhpScriptContext phpScriptContext = (IPhpScriptContext) context; updateGlobalEnvironment(); OutputStream out = ((PhpScriptWriter) (context.getWriter())).getOutputStream(); OutputStream err = ((PhpScriptWriter) (context.getErrorWriter())).getOutputStream(); /* * encode according to content-type charset */ if (out instanceof WriterOutputStream) headerParser = new SimpleHeaderParser((WriterOutputStream) out); Continuation kont = phpScriptContext.createContinuation(reader, env, out, err, headerParser, resultProxy = new ResultProxy(this), Util.getLogger(), isCompiled); phpScriptContext.setContinuation(kont); phpScriptContext.startContinuation(); return kont; } /** * Method called to evaluate a PHP file w/o compilation */ protected abstract Object doEvalPhp(Reader reader, ScriptContext context) throws ScriptException; protected abstract Object doEvalCompiledPhp(Reader reader, ScriptContext context) throws ScriptException; protected abstract Reader getLocalReader(Reader reader, boolean embedJavaInc) throws IOException; /* * Obtain a PHP instance for url. */ final protected Object doEval(Reader reader, ScriptContext context) throws Exception { continuation = getContinuation(reader, context); return continuation.getPhpScript(); } /* (non-Javadoc) * @see javax.script.ScriptEngine#eval(java.lang.String, javax.script.ScriptContext) */ /** * {@inheritDoc} */ @Override public Object eval(String script, ScriptContext context) throws ScriptException { if (script == null) return evalPhp((Reader) null, context); script = script.trim(); Reader localReader = new StringReader(script); try { return eval(localReader, context); } finally { try { localReader.close(); } catch (IOException e) {/*ignore*/} } } /** * {@inheritDoc} */ @Override public ScriptEngineFactory getFactory() { return this.factory; } /** * Release the continuation */ @Override public void release() { if (continuation != null) { try { continuation.release(); ctx.releaseManaged(); } catch (InterruptedException e) { return; } ctx = null; continuation = null; script = null; scriptClosure = null; try { getContext().getWriter().flush(); } catch (Exception e) { Util.printStackTrace(e); } try { getContext().getErrorWriter().flush(); } catch (Exception e) { Util.printStackTrace(e); } } } /* (non-Javadoc) * @see javax.script.ScriptEngine#createBindings() */ /** * {@inheritDoc} */ public Bindings createBindings() { return new SimpleBindings(); } /** * Release the script engine. * * @throws IOException */ public void close() throws IOException { release(); } /** * {@inheritDoc} */ public CompiledScript compile(String script) throws ScriptException { Reader reader = new StringReader(script); try { return compile(reader); } finally { try { reader.close(); } catch (IOException e) { Util.printStackTrace(e); } } } static final void throwNoOutputFile() { throw new IllegalStateException("No compilation output file has been set!"); } static final Reader DUMMY_READER = new Reader() { /** {@inheritDoc} */ public void close() throws IOException { throwNoOutputFile(); } /** {@inheritDoc} */ public int read(char[] cbuf, int off, int len) throws IOException { throwNoOutputFile(); return 0; } }; private static final String STANDARD_HEADER = new String("getBindings(100);" + "$java_scriptname = @java_values($java_bindings['javax.script.filename']);" + "if(!isset($argv)) $argv = @java_values($java_bindings['javax.script.argv']);" + "if(!isset($argv)) $argv=array();\n" + "$_SERVER['SCRIPT_FILENAME'] = isset($java_scriptname) ? $java_scriptname : '';" + "array_unshift($argv, $_SERVER['SCRIPT_FILENAME']);" + "if (!isset($argc)) $argc = count($argv);" + "$_SERVER['argv'] = $argv;" + "?>"); private static final String STANDARD_HEADER_EMBEDDED = new String("getBindings(100);" + "$java_scriptname = @java_values($java_bindings['javax.script.filename']);" + "if(!isset($argv)) $argv = @java_values($java_bindings['javax.script.argv']);" + "if(!isset($argv)) $argv=array();\n" + "$_SERVER['SCRIPT_FILENAME'] = isset($java_scriptname) ? $java_scriptname : '';" + "array_unshift($argv, $_SERVER['SCRIPT_FILENAME']);" + "if (!isset($argc)) $argc = count($argv);" + "$_SERVER['argv'] = $argv;" + "?>"); /** * {@inheritDoc} */ public CompiledScript compile(final Reader reader) throws ScriptException { try { compilePhp(reader); return new CompiledPhpScript(this); } catch (IOException e) { throw new ScriptException(e); } } private String cachedSimpleStandardHeader; private ScriptContext ctxCache; private String cachedEmbeddedStandardHeader; /** * {@inheritDoc} */ protected ScriptContext getScriptContext(Bindings bindings) { return new PhpScriptContext(super.getScriptContext(bindings)); } /** * {@inheritDoc} */ public ScriptContext getContext() { if (ctxCache == null) { ctxCache = super.getContext(); if (!(ctxCache instanceof IPhpScriptContext)) { if (ctxCache == null) ctxCache = new SimpleScriptContext(); ctxCache = new PhpScriptContext(ctxCache); super.setContext(ctxCache); } } return ctxCache; } /** * {@inheritDoc} */ public void setContext(ScriptContext context) { super.setContext(context); this.ctxCache = null; getContext(); } private String getSimpleStandardHeader(String filePath) { if (cachedSimpleStandardHeader != null) return cachedSimpleStandardHeader; StringBuffer buf = new StringBuffer(STANDARD_HEADER); buf.insert(20, filePath); return cachedSimpleStandardHeader = buf.toString(); } /** * {@inheritDoc} */ public boolean accept(File outputFile) { this.compilerOutputFile = outputFile; return true; } private String getEmbeddedStandardHeader(String filePath) throws IOException { if (cachedEmbeddedStandardHeader != null) return cachedEmbeddedStandardHeader; try { ByteArrayOutputStream out = new ByteArrayOutputStream(); Field f = Util.JAVA_INC.getField("bytes"); byte[] buf = (byte[]) f.get(Util.JAVA_INC); out.write(buf); OutputStreamWriter writer = new OutputStreamWriter(out); writer.write(STANDARD_HEADER_EMBEDDED); writer.close(); return cachedEmbeddedStandardHeader = out.toString(Util.ASCII); } catch (Exception e) { IOException ex = new IOException("Cannot create standard header"); ex.initCause(e); throw ex; } } protected String getStandardHeader(String filePath) throws IOException { return filePath == null ? getEmbeddedStandardHeader(filePath) : getSimpleStandardHeader(filePath); } /** * {@inheritDoc} */ public Object clone() { AbstractPhpScriptEngine other = (AbstractPhpScriptEngine) getFactory().getScriptEngine(); other.isCompiled = isCompiled; other.compilerOutputFile = compilerOutputFile; return other; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy