VIVO-10 Add the ability to associate a DataGetter with a Freemarker template.
This commit is contained in:
parent
caf16c392b
commit
6901a67670
3 changed files with 167 additions and 63 deletions
|
@ -5,11 +5,16 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
@ -17,9 +22,12 @@ import org.apache.commons.logging.LogFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
||||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||||
import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
|
import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants;
|
||||||
import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel;
|
import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective;
|
import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod;
|
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod;
|
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod;
|
||||||
|
@ -28,11 +36,15 @@ import freemarker.cache.ClassTemplateLoader;
|
||||||
import freemarker.cache.FileTemplateLoader;
|
import freemarker.cache.FileTemplateLoader;
|
||||||
import freemarker.cache.MultiTemplateLoader;
|
import freemarker.cache.MultiTemplateLoader;
|
||||||
import freemarker.cache.TemplateLoader;
|
import freemarker.cache.TemplateLoader;
|
||||||
|
import freemarker.core.Environment;
|
||||||
import freemarker.ext.beans.BeansWrapper;
|
import freemarker.ext.beans.BeansWrapper;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.DefaultObjectWrapper;
|
import freemarker.template.DefaultObjectWrapper;
|
||||||
|
import freemarker.template.ObjectWrapper;
|
||||||
|
import freemarker.template.Template;
|
||||||
import freemarker.template.TemplateException;
|
import freemarker.template.TemplateException;
|
||||||
import freemarker.template.TemplateModelException;
|
import freemarker.template.TemplateModelException;
|
||||||
|
import freemarker.template.utility.DeepUnwrap;
|
||||||
|
|
||||||
public class FreemarkerConfiguration extends Configuration {
|
public class FreemarkerConfiguration extends Configuration {
|
||||||
|
|
||||||
|
@ -203,4 +215,101 @@ public class FreemarkerConfiguration extends Configuration {
|
||||||
return mtl;
|
return mtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override getTemplate(), so we can apply DataGetters to all included
|
||||||
|
* templates.
|
||||||
|
*
|
||||||
|
* This won't work for top-level Templates, since the Environment hasn't
|
||||||
|
* been created yet. When TemplateProcessingHelper creates the Environment,
|
||||||
|
* it must call retrieveAndRunDataGetters() for the top-level Template.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Template getTemplate(String name, Locale locale, String encoding,
|
||||||
|
boolean parse) throws IOException {
|
||||||
|
Template template = super.getTemplate(name, locale, encoding, parse);
|
||||||
|
|
||||||
|
if (template == null) {
|
||||||
|
log.debug("Template '" + name + "' not found for locale '" + locale + "'.");
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
Environment env = getEnvironment();
|
||||||
|
if (env == null) {
|
||||||
|
log.debug("Not fetching data getters for template '" + template.getName() + "'. No environment.");
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
retrieveAndRunDataGetters(env, template.getName());
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the DataGetters for this template, and apply them to the Freemarker
|
||||||
|
* environment.
|
||||||
|
*/
|
||||||
|
public static void retrieveAndRunDataGetters(Environment env, String templateName) {
|
||||||
|
HttpServletRequest req = (HttpServletRequest) env.getCustomAttribute("request");
|
||||||
|
VitroRequest vreq = new VitroRequest(req);
|
||||||
|
|
||||||
|
if (dataGettersAlreadyApplied(env, templateName)) {
|
||||||
|
log.debug("DataGetters for '" + templateName+"' have already been applied");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<DataGetter> dgList = DataGetterUtils.getDataGettersForTemplate(
|
||||||
|
vreq, vreq.getDisplayModel(), templateName);
|
||||||
|
log.debug("Retrieved " + dgList.size() + " data getters for template '" + templateName + "'");
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> dataMap = (Map<String, Object>) DeepUnwrap.permissiveUnwrap(env.getDataModel());
|
||||||
|
for (DataGetter dg : dgList) {
|
||||||
|
applyDataGetter(dg, env, dataMap);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn(e, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have the DataGetters for this template already been applied to this environment?
|
||||||
|
* If not, record that they are being applied now.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static boolean dataGettersAlreadyApplied(Environment env, String templateName) {
|
||||||
|
Set<String> names;
|
||||||
|
Object o = env.getCustomAttribute("dataGettersApplied");
|
||||||
|
if (o instanceof Set) {
|
||||||
|
names = (Set<String>) o;
|
||||||
|
} else {
|
||||||
|
names = new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean added = names.add(templateName);
|
||||||
|
if (added) {
|
||||||
|
env.setCustomAttribute("dataGettersApplied", names);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data from a DataGetter, and store it in global variables in the
|
||||||
|
* Freemarker environment.
|
||||||
|
*/
|
||||||
|
private static void applyDataGetter(DataGetter dg, Environment env,
|
||||||
|
Map<String, Object> dataMap) throws TemplateModelException {
|
||||||
|
Map<String, Object> moreData = dg.getData(dataMap);
|
||||||
|
ObjectWrapper wrapper = env.getObjectWrapper();
|
||||||
|
if (moreData != null) {
|
||||||
|
for (String key : moreData.keySet()) {
|
||||||
|
Object value = moreData.get(key);
|
||||||
|
env.setGlobalVariable(key, wrapper.wrap(value));
|
||||||
|
log.debug("Stored in environment: '" + key + "' = '" + value + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ public class TemplateProcessingHelper {
|
||||||
env.include(getTemplate("pageSetup.ftl"));
|
env.include(getTemplate("pageSetup.ftl"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply any data-getters that are associated with this template.
|
||||||
|
FreemarkerConfiguration.retrieveAndRunDataGetters(env, template.getName());
|
||||||
|
|
||||||
|
// Now process it.
|
||||||
env.process();
|
env.process();
|
||||||
} catch (TemplateException e) {
|
} catch (TemplateException e) {
|
||||||
throw new TemplateProcessingException("TemplateException creating processing environment", e);
|
throw new TemplateProcessingException("TemplateException creating processing environment", e);
|
||||||
|
|
|
@ -61,35 +61,54 @@ public class DataGetterUtils {
|
||||||
*/
|
*/
|
||||||
public static List<DataGetter> getDataGettersForPage(VitroRequest vreq, Model displayModel, String pageURI)
|
public static List<DataGetter> getDataGettersForPage(VitroRequest vreq, Model displayModel, String pageURI)
|
||||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException {
|
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException {
|
||||||
//get data getter uris for pageURI
|
List<String> dgUris = getDataGetterURIsForAssociatedURI(displayModel, pageURI);
|
||||||
List<String> dgUris = getDataGetterURIsForPageURI( displayModel, pageURI);
|
List<DataGetter> dgList = dataGettersForURIs(vreq, displayModel, dgUris);
|
||||||
|
|
||||||
List<DataGetter> dgList = new ArrayList<DataGetter>();
|
|
||||||
for( String dgURI: dgUris){
|
|
||||||
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ;
|
|
||||||
if( dg != null )
|
|
||||||
dgList.add(dg);
|
|
||||||
}
|
|
||||||
log.debug("getDataGettersForPage: " + dgList);
|
log.debug("getDataGettersForPage: " + dgList);
|
||||||
return dgList;
|
return dgList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of DataGetter objects that are associated with a JAVA class.
|
* Get a list of DataGetter objects that are associated with a Vitro VClass.
|
||||||
* This allows the individual profile for an individual of a specific class to be returned .
|
* This allows the individual profile for an individual of a specific class to be returned .
|
||||||
*/
|
*/
|
||||||
public static List<DataGetter> getDataGettersForClass( VitroRequest vreq, Model displayModel, String classURI)
|
public static List<DataGetter> getDataGettersForClass( VitroRequest vreq, Model displayModel, String classURI)
|
||||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
|
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
|
||||||
//get data getter uris for pageURI
|
List<String> dgUris = getDataGetterURIsForAssociatedURI( displayModel, classURI);
|
||||||
List<String> dgUris = getDataGetterURIsForClassURI( displayModel, classURI);
|
List<DataGetter> dgList = dataGettersForURIs(vreq, displayModel, dgUris);
|
||||||
|
log.debug("getDataGettersForClass: " + dgList);
|
||||||
|
return dgList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of DataGetter objects that are associated with a Freemarker template.
|
||||||
|
* @param templateName a filename like "index.ftl", which will be used as a URI like "freemarker:index.ftl".
|
||||||
|
*/
|
||||||
|
public static List<DataGetter> getDataGettersForTemplate( VitroRequest vreq, Model displayModel, String templateName)
|
||||||
|
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
|
||||||
|
String templateUri = "freemarker:" + templateName;
|
||||||
|
List<String> dgUris = getDataGetterURIsForAssociatedURI( displayModel, templateUri);
|
||||||
|
List<DataGetter> dgList = dataGettersForURIs(vreq, displayModel, dgUris);
|
||||||
|
log.debug("getDataGettersForTemplate '" + templateName + "': " + dgList);
|
||||||
|
return dgList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of DataGetters from the list of URIs. Each DataGetter will be configured from information
|
||||||
|
* in the displayModel.
|
||||||
|
*
|
||||||
|
* Problems instantiating and configuring a particular DataGetter may result in an exception,
|
||||||
|
* or may just mean that there will be no entry in the result for that URI.
|
||||||
|
*
|
||||||
|
* May return an empty list, but will not return null.
|
||||||
|
*/
|
||||||
|
private static List<DataGetter> dataGettersForURIs(VitroRequest vreq, Model displayModel, List<String> dgUris)
|
||||||
|
throws InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException {
|
||||||
List<DataGetter> dgList = new ArrayList<DataGetter>();
|
List<DataGetter> dgList = new ArrayList<DataGetter>();
|
||||||
for( String dgURI: dgUris){
|
for( String dgURI: dgUris){
|
||||||
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ;
|
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ;
|
||||||
if( dg != null )
|
if( dg != null )
|
||||||
dgList.add(dg);
|
dgList.add(dg);
|
||||||
}
|
}
|
||||||
log.debug("getDataGettersForClass: " + dgList);
|
|
||||||
return dgList;
|
return dgList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +122,7 @@ public class DataGetterUtils {
|
||||||
* that does not implement the DataGetter interface.
|
* that does not implement the DataGetter interface.
|
||||||
*/
|
*/
|
||||||
public static DataGetter dataGetterForURI(VitroRequest vreq, Model displayModel, String dataGetterURI)
|
public static DataGetter dataGetterForURI(VitroRequest vreq, Model displayModel, String dataGetterURI)
|
||||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchMethodException
|
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, SecurityException
|
||||||
{
|
{
|
||||||
//get java class for dataGetterURI
|
//get java class for dataGetterURI
|
||||||
String dgClassName = getJClassForDataGetterURI(displayModel, dataGetterURI);
|
String dgClassName = getJClassForDataGetterURI(displayModel, dataGetterURI);
|
||||||
|
@ -180,47 +199,18 @@ public class DataGetterUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static List<String> getDataGetterURIsForPageURI(Model displayModel, String pageURI) {
|
private static List<String> getDataGetterURIsForAssociatedURI(Model displayModel, String associatedURI) {
|
||||||
String query = prefixes +
|
String query = prefixes +
|
||||||
"SELECT ?dataGetter WHERE { ?pageURI display:hasDataGetter ?dataGetter. }";
|
"SELECT ?dataGetter WHERE { ?associatedURI display:hasDataGetter ?dataGetter }";
|
||||||
Query dgForPageQuery = QueryFactory.create(query);
|
Query dgForUriQuery = QueryFactory.create(query);
|
||||||
|
|
||||||
QuerySolutionMap initialBindings = new QuerySolutionMap();
|
QuerySolutionMap initialBindings = new QuerySolutionMap();
|
||||||
initialBindings.add("pageURI", ResourceFactory.createResource( pageURI ));
|
initialBindings.add("associatedURI", ResourceFactory.createResource( associatedURI ));
|
||||||
|
|
||||||
List<String> dgURIs = new ArrayList<String>();
|
List<String> dgURIs = new ArrayList<String>();
|
||||||
displayModel.enterCriticalSection(false);
|
displayModel.enterCriticalSection(false);
|
||||||
try{
|
try{
|
||||||
QueryExecution qexec = QueryExecutionFactory.create(dgForPageQuery,displayModel,initialBindings );
|
QueryExecution qexec = QueryExecutionFactory.create(dgForUriQuery,displayModel,initialBindings );
|
||||||
try{
|
|
||||||
ResultSet results = qexec.execSelect();
|
|
||||||
while (results.hasNext()) {
|
|
||||||
QuerySolution soln = results.nextSolution();
|
|
||||||
Resource dg = soln.getResource("dataGetter");
|
|
||||||
if( dg != null && dg.getURI() != null){
|
|
||||||
dgURIs.add( dg.getURI());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}finally{ qexec.close(); }
|
|
||||||
}finally{ displayModel.leaveCriticalSection(); }
|
|
||||||
|
|
||||||
return dgURIs;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get data getters for a specific JAVA class - associates data getters with individuals for a specific JAVA class
|
|
||||||
private static List<String> getDataGetterURIsForClassURI(Model displayModel, String classURI) {
|
|
||||||
//Class URI will be substituted in so this is for a specific class uri
|
|
||||||
String query = prefixes +
|
|
||||||
"SELECT ?dataGetter WHERE { ?classURI display:hasDataGetter ?dataGetter }";
|
|
||||||
Query dgForPageQuery = QueryFactory.create(query);
|
|
||||||
|
|
||||||
QuerySolutionMap initialBindings = new QuerySolutionMap();
|
|
||||||
initialBindings.add("classURI", ResourceFactory.createResource( classURI ));
|
|
||||||
|
|
||||||
List<String> dgURIs = new ArrayList<String>();
|
|
||||||
displayModel.enterCriticalSection(false);
|
|
||||||
try{
|
|
||||||
QueryExecution qexec = QueryExecutionFactory.create(dgForPageQuery,displayModel,initialBindings );
|
|
||||||
try{
|
try{
|
||||||
ResultSet results = qexec.execSelect();
|
ResultSet results = qexec.execSelect();
|
||||||
while (results.hasNext()) {
|
while (results.hasNext()) {
|
||||||
|
@ -233,6 +223,7 @@ public class DataGetterUtils {
|
||||||
}finally{ qexec.close(); }
|
}finally{ qexec.close(); }
|
||||||
}finally{ displayModel.leaveCriticalSection(); }
|
}finally{ displayModel.leaveCriticalSection(); }
|
||||||
|
|
||||||
|
log.debug("Found " + dgURIs.size() +" DataGetter URIs for '" + associatedURI + "': " + dgURIs);
|
||||||
return dgURIs;
|
return dgURIs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue