Show TemplateProcessor.java syntax highlighted
package org.integratedmodelling.thinkcap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.StringWriter;
import java.util.HashMap;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.integratedmodelling.thinkcap.exceptions.ThinkcapException;
import org.integratedmodelling.thinklab.KnowledgeManager;
import org.integratedmodelling.thinklab.exception.ThinklabException;
import org.integratedmodelling.thinklab.interfaces.IAlgorithmInterpreter;
import org.integratedmodelling.thinklab.interfaces.IConcept;
import org.integratedmodelling.thinklab.interfaces.ISession;
import org.integratedmodelling.thinklab.interpreter.AlgorithmInterpreterFactory;
import org.integratedmodelling.thinklab.value.AlgorithmValue;
import org.integratedmodelling.utils.MiscUtilities;
/**
* Extracts and transforms code embedded in templates, so that we can write commands as one
* template with no need to define a ThinkcapCommand and all that.
*
* TODO extend template syntax to use plugins to support e.g. embedded wiki notation and
* openlaszlo xml. This requires writing the actual template in different ways, so it should
* be integrated in the plugin notifier, not here, but when it is done, the code mechanism
* should work the same way.
*
* @author Ferdinando Villa
*
*/
public class TemplateProcessor {
private HashMap<String, String> codeSegments = new HashMap<String, String>();
private HashMap<String, IConcept> codeTypes = new HashMap<String, IConcept>();
final static String declPattern =
"@publish ([a-zA-Z\\-_]+)";
final static String replPattern =
"velocityContext.put(\"$1\", $1);";
final static String declPattern1 =
"@widget ([a-zA-Z\\-_]+)";
final static String replPattern2 =
"widgetManager.addWidget($1);";
static TemplateProcessor TP = null;
private String imports =
"import org.integratedmodelling.ima.core.*;" +
"import org.integratedmodelling.ima.core.exception.*;\r\n" +
"import org.integratedmodelling.ima.core.interfaces.*;\r\n" +
"import org.integratedmodelling.thinkcap.widget.*;\r\n" +
"import org.integratedmodelling.thinkcap.exceptions.*;\r\n" +
"import org.integratedmodelling.thinkcap.*;\r\n";
public static TemplateProcessor get() {
if (TP == null) {
TP = new TemplateProcessor();
}
return TP;
}
/**
* Plugins should use this one to make available classes that can be used in
* embedded code.
* @param s
*/
public void addImport(String s) {
imports += "\n" + s;
}
public synchronized void parseTemplate(File template) throws ThinklabException {
String code = "";
String type = "groovy:GroovyCode";
try {
BufferedReader input = new BufferedReader( new FileReader(template) );
String line = null;
boolean reading = false;
while ( (line = input.readLine()) != null) {
if (reading && line.startsWith("@end -->"))
reading = false;
else if (!reading && line.startsWith("<!-- @code")) {
// TODO read code class in parentheses after prefix and set type from it
reading = true;
}
else if (reading) {
code += line + "\n";
}
}
} catch (Exception e) {
// most exceptions won't happen in this specific context, as we start with files that are there
// and readable by definition. Whatever happens, we just end up with no associated code.
code = "";
}
if (!code.equals("")) {
/* prefix code with all imports set by us and plugins */
code = imports + "\n" + code;
/* transform @publish and @widget directives into calls to context setting */
code = code.replaceAll(declPattern, replPattern);
code = code.replaceAll(declPattern1, replPattern2);
String tName = MiscUtilities.getFileBaseName(template.toString());
codeSegments.put(tName, code);
codeTypes.put(tName, KnowledgeManager.KM().requireConcept(type));
}
}
private AlgorithmValue getCodeSegment(String template, VelocityContext context) throws ThinklabException {
AlgorithmValue ret = null;
String code = codeSegments.get(template);
if (code != null) {
/* perform standard substitutions from Velocity context */
StringWriter out = new StringWriter();
try {
Velocity.evaluate(context, out, "groovy code", code);
} catch (Exception e) {
throw new ThinkcapException("embedded code in template " + template + " contains invalid VTL");
}
code = out.getBuffer().toString();
/* create algorithm with proper class */
IConcept aclass = codeTypes.get(template);
ret = (AlgorithmValue) KnowledgeManager.KM().validateLiteral(aclass, code, null);
}
return ret;
}
public void processTemplate(String template, VelocityContext context) throws ThinklabException {
AlgorithmValue alg = getCodeSegment(template, context);
if (alg != null) {
ISession sess = (ISession) context.get("thinkcapSession");
/* retrieve an interpreter */
IAlgorithmInterpreter interpreter =
AlgorithmInterpreterFactory.get().getInterpreter(alg, sess);
/*
* obtain a context; the session should be bound to it, but that
* depends on the language.
*/
IAlgorithmInterpreter.IContext ctext =
AlgorithmInterpreterFactory.get().getNewContext(alg, sess);
/* TODO bind other useful globals. */
ctext.bind(context, "velocityContext");
ctext.bind(context.get("WidgetManager"), "widgetManager");
ctext.bind(context.get("pageSpecs"), "pageManager");
/* exec in current session */
interpreter.execute(alg, ctext);
}
}
}
See more files for this project here