From ff0aa173985e7f68cb99037e2c3cb81e19202986 Mon Sep 17 00:00:00 2001 From: rjy7 Date: Wed, 25 Aug 2010 14:45:02 +0000 Subject: [PATCH] Updates to ViewFinder class to find custom templates --- .../freemarker/FreemarkerHttpServlet.java | 6 +- .../mannlib/vitro/webapp/web/ViewFinder.java | 104 ++++++++++++------ .../web/templatemodels/BaseTemplateModel.java | 29 ++--- .../IndividualTemplateModel.java | 2 +- 4 files changed, 85 insertions(+), 56 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index e35c3a4ae..12d8cf988 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -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.web.BreadCrumbsUtil; 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.Stylesheets; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.TabMenu; @@ -57,7 +58,10 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { try { VitroRequest vreq = new VitroRequest(request); + BaseTemplateModel.setVitroRequest(vreq); + Configuration config = getConfig(vreq); + vreq.setAttribute("freemarkerConfig", config); // 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 @@ -127,7 +131,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { 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. // By default we want to block exposure of set methods. BeansWrapper wrapper = new DefaultObjectWrapper(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/ViewFinder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/ViewFinder.java index 9e14e05c9..b3b326877 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/ViewFinder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/ViewFinder.java @@ -2,7 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.web; -import java.io.File; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; 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.VClass; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; +import freemarker.cache.TemplateLoader; +import freemarker.template.Configuration; /** * Class to find custom class views for individuals @@ -23,23 +26,22 @@ import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; */ 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 { - DISPLAY("getCustomDisplayView", "/view-display"), - // NB this is not the value currently used for custom forms - we use the value on the object property - FORM("getCustomEntryForm", "/form"), - SEARCH("getCustomSearchView", "/view-search"), - SHORT("getCustomShortView", "/view-short"); - - private static String TEMPLATE_PATH = "/templates/freemarker"; + 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. + // This value is specifiable from the backend editor, however. + FORM("getCustomEntryForm", "form-default.ftl"), + SEARCH("getCustomSearchView", "view-search-default.ftl"), + SHORT("getCustomShortView", "view-short-default.ftl"); private Method method = null; - private String path = null; + private String defaultTemplate = null; - ClassView(String methodName, String path) { + ClassView(String methodName, String defaultTemplate) { Class vc = VClass.class; - this.path = path; + this.defaultTemplate = defaultTemplate; try { method = vc.getMethod(methodName); } catch (SecurityException e) { @@ -53,9 +55,9 @@ public class ViewFinder { return method; } - protected String getPath() { - return TEMPLATE_PATH + path; - } + protected String getDefaultTemplate() { + return defaultTemplate; + } } @@ -65,10 +67,11 @@ public class ViewFinder { this.view = view; } - public String findClassView(Individual individual, ServletContext context) { - String viewName = "default.ftl"; - List vclasses = individual.getVClasses(); + public String findClassView(Individual individual, ServletContext context, VitroRequest vreq) { + String templateName = view.getDefaultTemplate(); Method method = view.getMethod(); + TemplateLoader templateLoader = ((Configuration) vreq.getAttribute("freemarkerConfig")).getTemplateLoader(); + /* RY The logic here is incorrect. The vclasses are * returned in a random order, whereas we need to * 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 * as a starting point: see MiscWebUtils.getCustomShortView(). */ + List vclasses = individual.getVClasses(); + String customTemplate = null; for (VClass vc : vclasses) { - try { - String v = (String) method.invoke(vc); - if (!StringUtils.isEmpty(v)) { - String pathToView = context.getRealPath(view.getPath() + "-" + v); - File viewFile = new File(pathToView); - if (viewFile.isFile() && viewFile.canRead()) { - viewName = v; - break; - } - } - } catch (IllegalArgumentException e) { - log.error("Incorrect arguments passed to method " + method.getName() + " in findView()."); - } catch (IllegalAccessException e) { - log.error("Method " + method.getName() + " cannot be accessed in findView()."); - } catch (InvocationTargetException e) { - log.error("Exception thrown by method " + method.getName() + " in findView()."); + customTemplate = findCustomTemplateForVClass(vc, method, templateLoader); + if (customTemplate != null) { + templateName = customTemplate; + break; } - } - return viewName; + 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) { + log.error("Incorrect arguments passed to method " + method.getName() + " in findCustomTemplateForVClass()."); + } catch (IllegalAccessException e) { + log.error("Method " + method.getName() + " cannot be accessed in findCustomTemplateForVClass()."); + } catch (InvocationTargetException e) { + log.error("Exception thrown by method " + method.getName() + " in findCustomTemplateForVClass()."); + } + + if (!StringUtils.isEmpty(vClassCustomTemplate)) { + 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; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java index fd7d54126..797bf2103 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java @@ -7,6 +7,7 @@ import javax.servlet.ServletContext; import org.apache.commons.logging.Log; 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.Params; @@ -15,6 +16,7 @@ public abstract class BaseTemplateModel { private static final Log log = LogFactory.getLog(BaseTemplateModel.class.getName()); protected static ServletContext servletContext = null; + protected static VitroRequest vreq = null; // Wrap UrlBuilder method so templates can call ${item.url} public String getUrl(String path) { @@ -31,28 +33,19 @@ public abstract class BaseTemplateModel { } 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() { 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 groups = // code to get the data - List vcgroups = new ArrayList(groups.size()); - Iterator 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 - */ - } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/IndividualTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/IndividualTemplateModel.java index 10835ad24..e739b6a18 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/IndividualTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/IndividualTemplateModel.java @@ -58,7 +58,7 @@ public class IndividualTemplateModel extends BaseTemplateModel { private String getView(ClassView view) { ViewFinder vf = new ViewFinder(view); - return vf.findClassView(individual, servletContext); + return vf.findClassView(individual, servletContext, vreq); } public Link getPrimaryLink() {