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.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
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.config.ConfigurationProperties;
|
||||
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.edit.n3editing.configuration.EditConfigurationConstants;
|
||||
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.methods.IndividualLocalNameMethod;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod;
|
||||
|
@ -28,11 +36,15 @@ import freemarker.cache.ClassTemplateLoader;
|
|||
import freemarker.cache.FileTemplateLoader;
|
||||
import freemarker.cache.MultiTemplateLoader;
|
||||
import freemarker.cache.TemplateLoader;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.DefaultObjectWrapper;
|
||||
import freemarker.template.ObjectWrapper;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
import freemarker.template.TemplateModelException;
|
||||
import freemarker.template.utility.DeepUnwrap;
|
||||
|
||||
public class FreemarkerConfiguration extends Configuration {
|
||||
|
||||
|
@ -203,4 +215,101 @@ public class FreemarkerConfiguration extends Configuration {
|
|||
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"));
|
||||
}
|
||||
|
||||
// Apply any data-getters that are associated with this template.
|
||||
FreemarkerConfiguration.retrieveAndRunDataGetters(env, template.getName());
|
||||
|
||||
// Now process it.
|
||||
env.process();
|
||||
} catch (TemplateException e) {
|
||||
throw new TemplateProcessingException("TemplateException creating processing environment", e);
|
||||
|
|
|
@ -59,39 +59,58 @@ public class DataGetterUtils {
|
|||
* This should not return PageDataGetters and should not throw an
|
||||
* exception if a page has PageDataGetters.
|
||||
*/
|
||||
public static List<DataGetter> getDataGettersForPage( VitroRequest vreq, Model displayModel, String pageURI)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
|
||||
//get data getter uris for pageURI
|
||||
List<String> dgUris = getDataGetterURIsForPageURI( displayModel, pageURI);
|
||||
public static List<DataGetter> getDataGettersForPage(VitroRequest vreq, Model displayModel, String pageURI)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException {
|
||||
List<String> dgUris = getDataGetterURIsForAssociatedURI(displayModel, pageURI);
|
||||
List<DataGetter> dgList = dataGettersForURIs(vreq, displayModel, dgUris);
|
||||
log.debug("getDataGettersForPage: " + dgList);
|
||||
return dgList;
|
||||
}
|
||||
|
||||
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);
|
||||
/**
|
||||
* 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 .
|
||||
*/
|
||||
public static List<DataGetter> getDataGettersForClass( VitroRequest vreq, Model displayModel, String classURI)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
|
||||
List<String> dgUris = getDataGetterURIsForAssociatedURI( 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 JAVA class.
|
||||
* This allows the individual profile for an individual of a specific class to be returned .
|
||||
* 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> getDataGettersForClass( VitroRequest vreq, Model displayModel, String classURI)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
|
||||
//get data getter uris for pageURI
|
||||
List<String> dgUris = getDataGetterURIsForClassURI( displayModel, classURI);
|
||||
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;
|
||||
}
|
||||
|
||||
List<DataGetter> dgList = new ArrayList<DataGetter>();
|
||||
for( String dgURI: dgUris){
|
||||
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ;
|
||||
if( dg != null )
|
||||
dgList.add(dg);
|
||||
}
|
||||
log.debug("getDataGettersForClass: " + 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>();
|
||||
for( String dgURI: dgUris){
|
||||
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ;
|
||||
if( dg != null )
|
||||
dgList.add(dg);
|
||||
}
|
||||
return dgList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DataGetter using information in the
|
||||
|
@ -103,7 +122,7 @@ public class DataGetterUtils {
|
|||
* that does not implement the DataGetter interface.
|
||||
*/
|
||||
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
|
||||
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 +
|
||||
"SELECT ?dataGetter WHERE { ?pageURI display:hasDataGetter ?dataGetter. }";
|
||||
Query dgForPageQuery = QueryFactory.create(query);
|
||||
"SELECT ?dataGetter WHERE { ?associatedURI display:hasDataGetter ?dataGetter }";
|
||||
Query dgForUriQuery = QueryFactory.create(query);
|
||||
|
||||
QuerySolutionMap initialBindings = new QuerySolutionMap();
|
||||
initialBindings.add("pageURI", ResourceFactory.createResource( pageURI ));
|
||||
initialBindings.add("associatedURI", ResourceFactory.createResource( associatedURI ));
|
||||
|
||||
List<String> dgURIs = new ArrayList<String>();
|
||||
displayModel.enterCriticalSection(false);
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create(dgForPageQuery,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 );
|
||||
QueryExecution qexec = QueryExecutionFactory.create(dgForUriQuery,displayModel,initialBindings );
|
||||
try{
|
||||
ResultSet results = qexec.execSelect();
|
||||
while (results.hasNext()) {
|
||||
|
@ -233,6 +223,7 @@ public class DataGetterUtils {
|
|||
}finally{ qexec.close(); }
|
||||
}finally{ displayModel.leaveCriticalSection(); }
|
||||
|
||||
log.debug("Found " + dgURIs.size() +" DataGetter URIs for '" + associatedURI + "': " + dgURIs);
|
||||
return dgURIs;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue