Updates to ViewFinder class to find custom templates

This commit is contained in:
rjy7 2010-08-25 14:45:02 +00:00
parent d48efa96cf
commit ff0aa17398
4 changed files with 85 additions and 56 deletions

View file

@ -30,6 +30,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.web.BreadCrumbsUtil; import edu.cornell.mannlib.vitro.webapp.web.BreadCrumbsUtil;
import edu.cornell.mannlib.vitro.webapp.web.PortalWebUtil; import edu.cornell.mannlib.vitro.webapp.web.PortalWebUtil;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.files.Scripts; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.files.Scripts;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.files.Stylesheets; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.files.Stylesheets;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.TabMenu; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.TabMenu;
@ -57,7 +58,10 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
try { try {
VitroRequest vreq = new VitroRequest(request); VitroRequest vreq = new VitroRequest(request);
BaseTemplateModel.setVitroRequest(vreq);
Configuration config = getConfig(vreq); Configuration config = getConfig(vreq);
vreq.setAttribute("freemarkerConfig", config);
// We can't use shared variables in the Freemarker configuration to store anything // We can't use shared variables in the Freemarker configuration to store anything
// except theme-specific data, because multiple portals or apps might share the same theme. So instead // except theme-specific data, because multiple portals or apps might share the same theme. So instead
@ -127,7 +131,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
config.setTemplateUpdateDelay(60); // in seconds; Freemarker default is 5 config.setTemplateUpdateDelay(60); // in seconds; Freemarker default is 5
} }
// Specify how templates will see the data-model. // Specify how templates will see the data model.
// The default wrapper exposes set methods unless exposure level is set. // The default wrapper exposes set methods unless exposure level is set.
// By default we want to block exposure of set methods. // By default we want to block exposure of set methods.
BeansWrapper wrapper = new DefaultObjectWrapper(); BeansWrapper wrapper = new DefaultObjectWrapper();

View file

@ -2,7 +2,7 @@
package edu.cornell.mannlib.vitro.webapp.web; package edu.cornell.mannlib.vitro.webapp.web;
import java.io.File; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List; import java.util.List;
@ -14,7 +14,10 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
/** /**
* Class to find custom class views for individuals * Class to find custom class views for individuals
@ -23,23 +26,22 @@ import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
*/ */
public class ViewFinder { public class ViewFinder {
private static final Log log = LogFactory.getLog(ViewFinder.class.getName()); private static final Log log = LogFactory.getLog(ViewFinder.class);
public enum ClassView { public enum ClassView {
DISPLAY("getCustomDisplayView", "/view-display"), DISPLAY("getCustomDisplayView", "view-display-default.ftl"),
// NB this is not the value currently used for custom forms - we use the value on the object property // NB this is not the value currently used for custom forms - we use the value on the object property.
FORM("getCustomEntryForm", "/form"), // This value is specifiable from the backend editor, however.
SEARCH("getCustomSearchView", "/view-search"), FORM("getCustomEntryForm", "form-default.ftl"),
SHORT("getCustomShortView", "/view-short"); SEARCH("getCustomSearchView", "view-search-default.ftl"),
SHORT("getCustomShortView", "view-short-default.ftl");
private static String TEMPLATE_PATH = "/templates/freemarker";
private Method method = null; private Method method = null;
private String path = null; private String defaultTemplate = null;
ClassView(String methodName, String path) { ClassView(String methodName, String defaultTemplate) {
Class<VClass> vc = VClass.class; Class<VClass> vc = VClass.class;
this.path = path; this.defaultTemplate = defaultTemplate;
try { try {
method = vc.getMethod(methodName); method = vc.getMethod(methodName);
} catch (SecurityException e) { } catch (SecurityException e) {
@ -53,8 +55,8 @@ public class ViewFinder {
return method; return method;
} }
protected String getPath() { protected String getDefaultTemplate() {
return TEMPLATE_PATH + path; return defaultTemplate;
} }
} }
@ -65,10 +67,11 @@ public class ViewFinder {
this.view = view; this.view = view;
} }
public String findClassView(Individual individual, ServletContext context) { public String findClassView(Individual individual, ServletContext context, VitroRequest vreq) {
String viewName = "default.ftl"; String templateName = view.getDefaultTemplate();
List<VClass> vclasses = individual.getVClasses();
Method method = view.getMethod(); Method method = view.getMethod();
TemplateLoader templateLoader = ((Configuration) vreq.getAttribute("freemarkerConfig")).getTemplateLoader();
/* RY The logic here is incorrect. The vclasses are /* RY The logic here is incorrect. The vclasses are
* returned in a random order, whereas we need to * returned in a random order, whereas we need to
* traverse the class hierarchy and find the most * traverse the class hierarchy and find the most
@ -87,27 +90,56 @@ public class ViewFinder {
* RY 7/19/10 Use distinction between asserted and inferred vclasses * RY 7/19/10 Use distinction between asserted and inferred vclasses
* as a starting point: see MiscWebUtils.getCustomShortView(). * as a starting point: see MiscWebUtils.getCustomShortView().
*/ */
List<VClass> vclasses = individual.getVClasses();
String customTemplate = null;
for (VClass vc : vclasses) { for (VClass vc : vclasses) {
try { customTemplate = findCustomTemplateForVClass(vc, method, templateLoader);
String v = (String) method.invoke(vc); if (customTemplate != null) {
if (!StringUtils.isEmpty(v)) { templateName = customTemplate;
String pathToView = context.getRealPath(view.getPath() + "-" + v);
File viewFile = new File(pathToView);
if (viewFile.isFile() && viewFile.canRead()) {
viewName = v;
break; break;
} }
} }
log.debug("Using template " + templateName + " for individual " + individual.getName());
return templateName;
}
private String findCustomTemplateForVClass(VClass vclass, Method method, TemplateLoader templateLoader) {
String customTemplate = null;
String vClassCustomTemplate = null;
try {
vClassCustomTemplate = (String) method.invoke(vclass);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
log.error("Incorrect arguments passed to method " + method.getName() + " in findView()."); log.error("Incorrect arguments passed to method " + method.getName() + " in findCustomTemplateForVClass().");
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
log.error("Method " + method.getName() + " cannot be accessed in findView()."); log.error("Method " + method.getName() + " cannot be accessed in findCustomTemplateForVClass().");
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
log.error("Exception thrown by method " + method.getName() + " in findView()."); log.error("Exception thrown by method " + method.getName() + " in findCustomTemplateForVClass().");
} }
} if (!StringUtils.isEmpty(vClassCustomTemplate)) {
return viewName; log.debug("Custom template " + vClassCustomTemplate + " defined for class " + vclass.getName());
try {
// Make sure the template exists
if (templateLoader.findTemplateSource(vClassCustomTemplate) != null) {
log.debug("Found defined custom template " + vClassCustomTemplate + " for class " + vclass.getName());
customTemplate = vClassCustomTemplate;
} else {
log.warn("Custom template " + vClassCustomTemplate + " for class " + vclass.getName() + " defined but does not exist.");
}
} catch (IOException e) {
log.error("IOException looking for source for template " + vClassCustomTemplate);
}
}
if (log.isDebugEnabled()) {
if (customTemplate != null) {
log.debug("Using custom template " + customTemplate + " for class " + vclass.getName());
} else {
log.debug("No custom template found for class " + vclass.getName());
}
}
return customTemplate;
} }
} }

View file

@ -7,6 +7,7 @@ import javax.servlet.ServletContext;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Params; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Params;
@ -15,6 +16,7 @@ public abstract class BaseTemplateModel {
private static final Log log = LogFactory.getLog(BaseTemplateModel.class.getName()); private static final Log log = LogFactory.getLog(BaseTemplateModel.class.getName());
protected static ServletContext servletContext = null; protected static ServletContext servletContext = null;
protected static VitroRequest vreq = null;
// Wrap UrlBuilder method so templates can call ${item.url} // Wrap UrlBuilder method so templates can call ${item.url}
public String getUrl(String path) { public String getUrl(String path) {
@ -31,28 +33,19 @@ public abstract class BaseTemplateModel {
} }
public static void setServletContext(ServletContext context) { public static void setServletContext(ServletContext context) {
BaseTemplateModel.servletContext = context; servletContext = context;
}
public static VitroRequest getVitroRequest() {
return vreq;
}
public static void setVitroRequest(VitroRequest vrequest) {
vreq = vrequest;
} }
public String dump() { public String dump() {
return "I'm a BaseTemplateModel object"; return "I'm a BaseTemplateModel object";
} }
/*
* public static List<?> wrapList(List<?> list, Class cl)
* throw error if cl not a child of ViewObject
* This block of code is going to be repeated a lot:
List<VClassGroup> groups = // code to get the data
List<VClassGroupView> vcgroups = new ArrayList<VClassGroupView>(groups.size());
Iterator<VClassGroup> i = groups.iterator();
while (i.hasNext()) {
vcgroups.add(new VClassGroupView(i.next()));
}
body.put("classGroups", vcgroups);
Can we generalize it to a generic method of ViewObject - wrapList() ?
static method of ViewObject
Params: groups, VClassGroupView (the name of the class) - but must be a child of ViewObject
Return: List<viewObjectType>
*/
} }

View file

@ -58,7 +58,7 @@ public class IndividualTemplateModel extends BaseTemplateModel {
private String getView(ClassView view) { private String getView(ClassView view) {
ViewFinder vf = new ViewFinder(view); ViewFinder vf = new ViewFinder(view);
return vf.findClassView(individual, servletContext); return vf.findClassView(individual, servletContext, vreq);
} }
public Link getPrimaryLink() { public Link getPrimaryLink() {