|
|
|
@ -27,7 +27,6 @@ import java.util.Map; |
|
|
|
import javax.script.Invocable; |
|
|
|
import javax.script.Invocable; |
|
|
|
import javax.script.ScriptEngine; |
|
|
|
import javax.script.ScriptEngine; |
|
|
|
import javax.script.ScriptEngineManager; |
|
|
|
import javax.script.ScriptEngineManager; |
|
|
|
import javax.script.ScriptException; |
|
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
|
|
|
|
|
|
|
|
@ -46,8 +45,8 @@ import org.springframework.util.StringUtils; |
|
|
|
import org.springframework.web.servlet.view.AbstractUrlBasedView; |
|
|
|
import org.springframework.web.servlet.view.AbstractUrlBasedView; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* An {@link org.springframework.web.servlet.view.AbstractUrlBasedView AbstractUrlBasedView} |
|
|
|
* An {@link AbstractUrlBasedView} subclass designed to run any template library |
|
|
|
* designed to run any template library based on a JSR-223 script engine. |
|
|
|
* based on a JSR-223 script engine. |
|
|
|
* |
|
|
|
* |
|
|
|
* <p>If not set, each property is auto-detected by looking up up a single |
|
|
|
* <p>If not set, each property is auto-detected by looking up up a single |
|
|
|
* {@link ScriptTemplateConfig} bean in the web application context and using |
|
|
|
* {@link ScriptTemplateConfig} bean in the web application context and using |
|
|
|
@ -69,13 +68,14 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
private static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:"; |
|
|
|
private static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ScriptEngine engine; |
|
|
|
private final ThreadLocal<ScriptEngine> engineHolder = new NamedThreadLocal<ScriptEngine>("ScriptTemplateView engine"); |
|
|
|
|
|
|
|
|
|
|
|
private final ThreadLocal<ScriptEngine> engineHolder = |
|
|
|
private ScriptEngine engine; |
|
|
|
new NamedThreadLocal<ScriptEngine>("ScriptTemplateView engine"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String engineName; |
|
|
|
private String engineName; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Boolean sharedEngine; |
|
|
|
|
|
|
|
|
|
|
|
private String[] scripts; |
|
|
|
private String[] scripts; |
|
|
|
|
|
|
|
|
|
|
|
private String renderObject; |
|
|
|
private String renderObject; |
|
|
|
@ -88,8 +88,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
|
|
|
|
|
|
|
|
private String resourceLoaderPath; |
|
|
|
private String resourceLoaderPath; |
|
|
|
|
|
|
|
|
|
|
|
private Boolean sharedEngine; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* See {@link ScriptTemplateConfigurer#setEngine(ScriptEngine)} documentation. |
|
|
|
* See {@link ScriptTemplateConfigurer#setEngine(ScriptEngine)} documentation. |
|
|
|
@ -99,48 +97,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
this.engine = engine; |
|
|
|
this.engine = engine; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected ScriptEngine getEngine() { |
|
|
|
|
|
|
|
if (Boolean.FALSE.equals(this.sharedEngine)) { |
|
|
|
|
|
|
|
ScriptEngine engine = this.engineHolder.get(); |
|
|
|
|
|
|
|
if (engine == null) { |
|
|
|
|
|
|
|
engine = createEngineFromName(); |
|
|
|
|
|
|
|
this.engineHolder.set(engine); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return engine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (this.engine == null) { |
|
|
|
|
|
|
|
setEngine(createEngineFromName()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return this.engine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected ScriptEngine createEngineFromName() { |
|
|
|
|
|
|
|
Assert.notNull(this.engineName); |
|
|
|
|
|
|
|
ScriptEngine engine = new ScriptEngineManager().getEngineByName(this.engineName); |
|
|
|
|
|
|
|
Assert.state(engine != null, "No engine \"" + this.engineName + "\" found."); |
|
|
|
|
|
|
|
loadScripts(engine); |
|
|
|
|
|
|
|
return engine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void loadScripts(ScriptEngine engine) { |
|
|
|
|
|
|
|
Assert.notNull(engine); |
|
|
|
|
|
|
|
if (this.scripts != null) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
for (String script : this.scripts) { |
|
|
|
|
|
|
|
Resource resource = this.resourceLoader.getResource(script); |
|
|
|
|
|
|
|
Assert.state(resource.exists(), "Resource " + script + " not found."); |
|
|
|
|
|
|
|
engine.eval(new InputStreamReader(resource.getInputStream())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (ScriptException e) { |
|
|
|
|
|
|
|
throw new IllegalStateException("could not load script", e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (IOException e) { |
|
|
|
|
|
|
|
throw new IllegalStateException("could not load script", e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* See {@link ScriptTemplateConfigurer#setEngineName(String)} documentation. |
|
|
|
* See {@link ScriptTemplateConfigurer#setEngineName(String)} documentation. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -148,6 +104,13 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
this.engineName = engineName; |
|
|
|
this.engineName = engineName; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* See {@link ScriptTemplateConfigurer#setSharedEngine(Boolean)} documentation. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void setSharedEngine(Boolean sharedEngine) { |
|
|
|
|
|
|
|
this.sharedEngine = sharedEngine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* See {@link ScriptTemplateConfigurer#setScripts(String...)} documentation. |
|
|
|
* See {@link ScriptTemplateConfigurer#setScripts(String...)} documentation. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -183,12 +146,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
this.resourceLoaderPath = resourceLoaderPath; |
|
|
|
this.resourceLoaderPath = resourceLoaderPath; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* See {@link ScriptTemplateConfigurer#setSharedEngine(Boolean)} documentation. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void setSharedEngine(Boolean sharedEngine) { |
|
|
|
|
|
|
|
this.sharedEngine = sharedEngine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected void initApplicationContext(ApplicationContext context) { |
|
|
|
protected void initApplicationContext(ApplicationContext context) { |
|
|
|
@ -211,36 +168,78 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
this.renderFunction = viewConfig.getRenderFunction(); |
|
|
|
this.renderFunction = viewConfig.getRenderFunction(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.charset == null) { |
|
|
|
if (this.charset == null) { |
|
|
|
this.charset = viewConfig.getCharset() == null ? DEFAULT_CHARSET : viewConfig.getCharset(); |
|
|
|
this.charset = (viewConfig.getCharset() != null ? viewConfig.getCharset() : DEFAULT_CHARSET); |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.resourceLoaderPath == null) { |
|
|
|
if (this.resourceLoaderPath == null) { |
|
|
|
this.resourceLoaderPath = viewConfig.getResourceLoaderPath() == null ? |
|
|
|
this.resourceLoaderPath = (viewConfig.getResourceLoaderPath() != null ? |
|
|
|
DEFAULT_RESOURCE_LOADER_PATH : viewConfig.getResourceLoaderPath(); |
|
|
|
viewConfig.getResourceLoaderPath() : DEFAULT_RESOURCE_LOADER_PATH); |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.resourceLoader == null) { |
|
|
|
if (this.resourceLoader == null) { |
|
|
|
this.resourceLoader = new DefaultResourceLoader(createClassLoader()); |
|
|
|
this.resourceLoader = new DefaultResourceLoader(createClassLoader()); |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.sharedEngine == null && viewConfig.isShareEngine() != null) { |
|
|
|
if (this.sharedEngine == null && viewConfig.isSharedEngine() != null) { |
|
|
|
this.sharedEngine = viewConfig.isShareEngine(); |
|
|
|
this.sharedEngine = viewConfig.isSharedEngine(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Assert.state(!(this.engine != null && this.engineName != null), |
|
|
|
Assert.isTrue(!(this.engine != null && this.engineName != null), |
|
|
|
"You should define engine or engineName properties, not both."); |
|
|
|
"You should define either 'engine' or 'engineName', not both."); |
|
|
|
Assert.state(!(this.engine == null && this.engineName == null), |
|
|
|
Assert.isTrue(!(this.engine == null && this.engineName == null), |
|
|
|
"No script engine found, please specify valid engine or engineName properties."); |
|
|
|
"No script engine found, please specify either 'engine' or 'engineName'."); |
|
|
|
|
|
|
|
|
|
|
|
if (Boolean.FALSE.equals(this.sharedEngine)) { |
|
|
|
if (Boolean.FALSE.equals(this.sharedEngine)) { |
|
|
|
Assert.state(this.engineName != null, |
|
|
|
Assert.isTrue(this.engineName != null, |
|
|
|
"When sharedEngine property is set to false, you should specify the " + |
|
|
|
"When 'sharedEngine' is set to false, you should specify the " + |
|
|
|
"script engine using the engineName property, not the engine one."); |
|
|
|
"script engine using the 'engineName' property, not the 'engine' one."); |
|
|
|
} |
|
|
|
} |
|
|
|
Assert.state(this.renderFunction != null, "renderFunction property must be defined."); |
|
|
|
else if (this.engine != null) { |
|
|
|
|
|
|
|
|
|
|
|
if (this.engine != null) { |
|
|
|
|
|
|
|
loadScripts(this.engine); |
|
|
|
loadScripts(this.engine); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
setEngine(createEngineFromName()); |
|
|
|
setEngine(createEngineFromName()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert.isTrue(this.renderFunction != null, "The 'renderFunction' property must be defined."); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected ScriptEngine getEngine() { |
|
|
|
|
|
|
|
if (Boolean.FALSE.equals(this.sharedEngine)) { |
|
|
|
|
|
|
|
ScriptEngine engine = this.engineHolder.get(); |
|
|
|
|
|
|
|
if (engine == null) { |
|
|
|
|
|
|
|
engine = createEngineFromName(); |
|
|
|
|
|
|
|
this.engineHolder.set(engine); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return engine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
// Simply return the configured ScriptEngine...
|
|
|
|
|
|
|
|
return this.engine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected ScriptEngine createEngineFromName() { |
|
|
|
|
|
|
|
ScriptEngine engine = new ScriptEngineManager().getEngineByName(this.engineName); |
|
|
|
|
|
|
|
if (engine == null) { |
|
|
|
|
|
|
|
throw new IllegalStateException("No engine with name '" + this.engineName + "' found"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
loadScripts(engine); |
|
|
|
|
|
|
|
return engine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void loadScripts(ScriptEngine engine) { |
|
|
|
|
|
|
|
if (this.scripts != null) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
for (String script : this.scripts) { |
|
|
|
|
|
|
|
Resource resource = this.resourceLoader.getResource(script); |
|
|
|
|
|
|
|
if (!resource.exists()) { |
|
|
|
|
|
|
|
throw new IllegalStateException("Resource " + script + " not found"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
engine.eval(new InputStreamReader(resource.getInputStream())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (Exception ex) { |
|
|
|
|
|
|
|
throw new IllegalStateException("Failed to load script", ex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected ClassLoader createClassLoader() { |
|
|
|
protected ClassLoader createClassLoader() { |
|
|
|
@ -257,8 +256,9 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (IOException e) { |
|
|
|
} |
|
|
|
throw new IllegalStateException("Cannot create class loader: " + e.getMessage()); |
|
|
|
catch (IOException ex) { |
|
|
|
|
|
|
|
throw new IllegalStateException("Cannot create class loader: " + ex.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
ClassLoader classLoader = getApplicationContext().getClassLoader(); |
|
|
|
ClassLoader classLoader = getApplicationContext().getClassLoader(); |
|
|
|
return (urls.size() > 0 ? new URLClassLoader(urls.toArray(new URL[urls.size()]), classLoader) : classLoader); |
|
|
|
return (urls.size() > 0 ? new URLClassLoader(urls.toArray(new URL[urls.size()]), classLoader) : classLoader); |
|
|
|
@ -275,30 +275,33 @@ public class ScriptTemplateView extends AbstractUrlBasedView { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { |
|
|
|
protected void renderMergedOutputModel( |
|
|
|
Assert.notNull("Render function must not be null", this.renderFunction); |
|
|
|
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
|
|
|
|
ScriptEngine engine = getEngine(); |
|
|
|
|
|
|
|
Invocable invocable = (Invocable) engine; |
|
|
|
String template = getTemplate(getUrl()); |
|
|
|
String template = getTemplate(getUrl()); |
|
|
|
Object html; |
|
|
|
Object html; |
|
|
|
if (this.renderObject != null) { |
|
|
|
if (this.renderObject != null) { |
|
|
|
Object thiz = engine.eval(this.renderObject); |
|
|
|
Object thiz = engine.eval(this.renderObject); |
|
|
|
html = ((Invocable)getEngine()).invokeMethod(thiz, this.renderFunction, template, model); |
|
|
|
html = invocable.invokeMethod(thiz, this.renderFunction, template, model); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
html = ((Invocable)getEngine()).invokeFunction(this.renderFunction, template, model); |
|
|
|
html = invocable.invokeFunction(this.renderFunction, template, model); |
|
|
|
} |
|
|
|
} |
|
|
|
response.getWriter().write(String.valueOf(html)); |
|
|
|
response.getWriter().write(String.valueOf(html)); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception e) { |
|
|
|
catch (Exception ex) { |
|
|
|
throw new IllegalStateException("failed to render template", e); |
|
|
|
throw new IllegalStateException("Failed to render script template", ex); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected String getTemplate(String path) throws IOException { |
|
|
|
protected String getTemplate(String path) throws IOException { |
|
|
|
Resource resource = this.resourceLoader.getResource(path); |
|
|
|
Resource resource = this.resourceLoader.getResource(path); |
|
|
|
Assert.state(resource.exists(), "Resource " + path + " not found."); |
|
|
|
|
|
|
|
return StreamUtils.copyToString(resource.getInputStream(), this.charset); |
|
|
|
return StreamUtils.copyToString(resource.getInputStream(), this.charset); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|