/**
* 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.compiler;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.jsp.tagext.BodyContent;
import lucee.commons.digest.HashUtil;
import lucee.commons.lang.ClassUtil;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.MemoryClassLoader;
import lucee.loader.engine.CFMLEngine;
import lucee.runtime.Page;
import lucee.runtime.PageContext;
import lucee.runtime.PageSource;
import lucee.runtime.config.ConfigImpl;
import lucee.runtime.config.ConfigWeb;
import lucee.runtime.config.ConfigWebImpl;
import lucee.runtime.config.Constants;
import lucee.runtime.exp.PageException;
import lucee.runtime.op.Caster;
import lucee.transformer.util.SourceCode;
public class Renderer {
private static final long MAX_SIZE = 1024*1024;
private static MemoryClassLoader mcl;
private static Map<String,Page> pages=new HashMap<String,Page>();
private static Class<? extends Page> loadClass(ConfigWeb config, String className, String cfml, int dialect, boolean ignoreScopes) throws Exception{
ConfigWebImpl cw = (ConfigWebImpl)config;
CFMLCompilerImpl compiler = cw.getCompiler();
// create className based o the content
Class<? extends Page> clazz=null;
if(mcl==null) {
mcl=createMemoryClassLoader(cw);
}
else clazz=ClassUtil.loadClass(mcl, className, null);
if(clazz!=null) return clazz;
SourceCode sc=new SourceCode(cfml, false,dialect);
// compile
lucee.runtime.compiler.CFMLCompilerImpl.Result result =
compiler.compile(cw, sc, cw.getTLDs(dialect), cw.getFLDs(dialect), null, className,true,ignoreScopes);
// before we add a new class, we make sure we are still in range
if(mcl.getSize()+result.barr.length>MAX_SIZE) {
mcl=createMemoryClassLoader(cw);
pages.clear();
}
return (Class<? extends Page>) mcl.loadClass(className, result.barr);
}
private static MemoryClassLoader createMemoryClassLoader(ConfigWebImpl cw) throws IOException {
return new MemoryClassLoader(cw, cw.getClass().getClassLoader());
}
private static Page loadPage(ConfigWeb cw,PageSource ps, String cfml, int dialect, boolean ignoreScopes) throws Exception{
String className=HashUtil.create64BitHashAsString(cfml);
// do we already have the page?
Page p=pages.get(className);
if(p!=null) return p;
// load class
Constructor<? extends Page> constr = loadClass(cw, className,cfml,dialect,ignoreScopes).getDeclaredConstructor(PageSource.class);
p= constr.newInstance(ps);
pages.put(className, p);
return p;
}
public static Result script(PageContext pc, String cfml, int dialect, boolean catchOutput, boolean ignoreScopes) throws PageException {
String prefix = ((ConfigImpl)pc.getConfig()).getCoreTagLib(dialect).getNameSpaceAndSeparator();
String name= prefix+(dialect==CFMLEngine.DIALECT_CFML?Constants.CFML_SCRIPT_TAG_NAME:Constants.LUCEE_SCRIPT_TAG_NAME);
return tag(pc, "<"+name+">"+cfml+"</"+name+">",dialect,catchOutput,ignoreScopes);
}
public static Result tag(PageContext pc, String cfml, int dialect, boolean catchOutput, boolean ignoreScopes) throws PageException {
// execute
Result res=new Result();
BodyContent bc=null;
//Variables before = pc.variablesScope();
try{
if(catchOutput)bc = pc.pushBody();
//if(variables!=null)pc.setVariablesScope(variables);
res.value=loadPage(pc.getConfig(), null, cfml,dialect,ignoreScopes).call(pc);
}
catch(Throwable t){
ExceptionUtil.rethrowIfNecessary(t);
throw Caster.toPageException(t);
}
finally{
//if(variables!=null)pc.setVariablesScope(before);
if(catchOutput) {
if(bc!=null)res.output=bc.getString();
pc.popBody();
}
//pc.flush();
}
return res;
}
public static class Result {
private String output;
private Object value;
public String getOutput() {
return output==null?"":output;
}
public Object getValue() {
return value;
}
public String toString(){
return "output:"+output+";value:"+value;
}
}
}