/**
* Copyright (c) 2015, Lucee Assosication Switzerland. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.runtime.jsr223;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
import lucee.commons.io.IOUtil;
import lucee.commons.io.SystemUtil;
import lucee.runtime.PageContext;
import lucee.runtime.compiler.Renderer;
import lucee.runtime.compiler.Renderer.Result;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.PageException;
import lucee.runtime.op.Caster;
import lucee.runtime.type.KeyImpl;
import lucee.runtime.type.scope.Variables;
import lucee.runtime.util.PageContextUtil;
public class ScriptEngineImpl implements ScriptEngine {
private ScriptEngineFactoryImpl factory;
private ScriptContext context;
private PageContext pc;
public ScriptEngineImpl(ScriptEngineFactoryImpl factory) {
this.factory=factory;
pc = createPageContext();
}
@Override
public Object eval(String script, ScriptContext context) throws ScriptException {
if(context==null)context=getContext();
PageContext oldPC = ThreadLocalPageContext.get();
PageContext pc=getPageContext(context);
try{
Result res = factory.tag?Renderer.tag(pc, script,factory.dialect,false,true):Renderer.script(pc, script,factory.dialect,false,true);
return res.getValue();
}
catch (PageException pe) {
throw toScriptException(pe);
}
finally{
releasePageContext(pc,oldPC);
}
}
@Override
public void put(String key, Object value) {
PageContext oldPC = ThreadLocalPageContext.get();
PageContext pc=getPageContext(getContext());
try{
pc.undefinedScope().set(KeyImpl.init(key), value);
}
catch (PageException e) {
// ignored
}
finally{
releasePageContext(pc,oldPC);
}
}
@Override
public Object get(String key) {
PageContext oldPC = ThreadLocalPageContext.get();
PageContext pc=getPageContext(getContext());
try{
return pc.undefinedScope().get(KeyImpl.init(key),null);
}
finally{
releasePageContext(pc,oldPC);
}
}
@Override
public Bindings getBindings(int scope) {
return getContext().getBindings(scope);
}
@Override
public void setBindings(Bindings bindings, int scope) {
getContext().setBindings(bindings, scope);
}
private ScriptException toScriptException(Exception e) {
ScriptException se = new ScriptException(e);
se.setStackTrace(e.getStackTrace());
return se;
}
@Override
public ScriptContext getContext() {
if(context==null) {
context = new SimpleScriptContext();
context.setBindings(new VariablesBinding(), ScriptContext.ENGINE_SCOPE); // we do our own
}
return context;
}
private ScriptContext getContext(Bindings b) {
ScriptContext def = getContext();
SimpleScriptContext custom = new SimpleScriptContext();
Bindings gs = getBindings(ScriptContext.GLOBAL_SCOPE);
if (gs != null) custom.setBindings(gs, ScriptContext.GLOBAL_SCOPE);
custom.setBindings(b,ScriptContext.ENGINE_SCOPE);
custom.setReader(def.getReader());
custom.setWriter(def.getWriter());
custom.setErrorWriter(def.getErrorWriter());
return custom;
}
@Override
public void setContext(ScriptContext context) {
this.context= context;
}
@Override
public Bindings createBindings() {
return new VariablesBinding();
}
private PageContext getPageContext(ScriptContext context) {
pc.setVariablesScope(toVariables(context.getBindings(ScriptContext.ENGINE_SCOPE)));
ThreadLocalPageContext.register(pc);
return pc;
}
private void releasePageContext(PageContext pc, PageContext oldPC) {
pc.flush();
ThreadLocalPageContext.release();
if(oldPC!=null)ThreadLocalPageContext.register(oldPC);
}
private Variables toVariables(Bindings bindings) {
if(bindings instanceof VariablesBinding) return ((VariablesBinding) bindings).getVaraibles();
RuntimeException t = new RuntimeException("not supported! "+bindings.getClass().getName());
t.printStackTrace();
throw t;
//return new BindingsAsVariables(bindings);
}
private PageContext createPageContext() {
try {
File root = new File(factory.engine.getCFMLEngineFactory().getResourceRoot(),"jsr223-webroot");
return PageContextUtil.getPageContext(null,null,root,"localhost", "/index.cfm", "", null, null, null, null, System.out, false,Long.MAX_VALUE,
Caster.toBooleanValue(SystemUtil.getSystemPropOrEnvVar("lucee.ignore.scopes", null),false));
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
///////////// calling other methods of the same class /////////////////
@Override
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
try {
return eval(IOUtil.toString(reader),context);
} catch (IOException ioe) {
throw toScriptException(ioe);
}
}
@Override
public Object eval(String script) throws ScriptException {
return eval(script,getContext());
}
@Override
public Object eval(Reader reader) throws ScriptException {
return eval(reader,getContext());
}
@Override
public Object eval(String script, Bindings b) throws ScriptException { // TODO
return eval(script,getContext(b));
}
@Override
public Object eval(Reader reader, Bindings b) throws ScriptException {// TODO
return eval(reader,getContext(b));
}
@Override
public ScriptEngineFactory getFactory() {
return factory;
}
}