From c2fa2c4e37bdca03a0848bb6933ec473ca292ef7 Mon Sep 17 00:00:00 2001 From: rjy7 Date: Fri, 28 May 2010 21:44:59 +0000 Subject: [PATCH] Handle custom search views used on individual list page. --- .../freemarker/FreeMarkerHttpServlet.java | 14 +-- .../freemarker/FreeMarkerSetup.java | 4 +- .../controller/freemarker/UrlBuilder.java | 27 ++--- .../vitro/webapp/view/IndividualView.java | 16 ++- .../mannlib/vitro/webapp/view/VClassView.java | 4 +- .../mannlib/vitro/webapp/view/ViewFinder.java | 107 ++++++++++++++++++ .../mannlib/vitro/webapp/view/ViewObject.java | 4 + .../freemarker/body/individualList.ftl | 4 +- .../view/search/default.ftl} | 2 +- 9 files changed, 143 insertions(+), 39 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewFinder.java rename webapp/web/templates/freemarker/body/partials/{defaultIndividualListView.ftl => class/view/search/default.ftl} (89%) 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 8beb8a154..6ff00d814 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 @@ -25,7 +25,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.Portal; import edu.cornell.mannlib.vitro.webapp.controller.ContactMailServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Routes; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; import edu.cornell.mannlib.vitro.webapp.view.fileList.ScriptList; import edu.cornell.mannlib.vitro.webapp.view.fileList.StylesheetList; @@ -180,15 +180,15 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet { root.put("bannerImage", UrlBuilder.getUrl(themeDir + "site_icons/" + bannerImage)); } - urls.put("about", urlBuilder.getPortalUrl(Routes.ABOUT)); + urls.put("about", urlBuilder.getPortalUrl(Route.ABOUT)); if (ContactMailServlet.getSmtpHostFromProperties() != null) { - urls.put("contact", urlBuilder.getPortalUrl(Routes.CONTACT)); + urls.put("contact", urlBuilder.getPortalUrl(Route.CONTACT)); } - urls.put("search", urlBuilder.getPortalUrl(Routes.SEARCH)); - urls.put("termsOfUse", urlBuilder.getPortalUrl(Routes.TERMS_OF_USE)); - urls.put("login", urlBuilder.getPortalUrl(Routes.LOGIN)); + urls.put("search", urlBuilder.getPortalUrl(Route.SEARCH)); + urls.put("termsOfUse", urlBuilder.getPortalUrl(Route.TERMS_OF_USE)); + urls.put("login", urlBuilder.getPortalUrl(Route.LOGIN)); urls.put("logout", urlBuilder.getLogoutUrl()); - urls.put("siteAdmin", urlBuilder.getPortalUrl(Routes.LOGIN)); + urls.put("siteAdmin", urlBuilder.getPortalUrl(Route.LOGIN)); setSharedVariable("urls", urls); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreeMarkerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreeMarkerSetup.java index 406fbff9b..6e51375b6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreeMarkerSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreeMarkerSetup.java @@ -10,7 +10,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreeMarkerHttpServlet; +import edu.cornell.mannlib.vitro.webapp.view.ViewObject; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.TemplateException; @@ -52,7 +52,7 @@ public class FreeMarkerSetup implements ServletContextListener { FreeMarkerHttpServlet.config = cfg; FreeMarkerHttpServlet.context = sc; - + ViewObject.context = sc; UrlBuilder.contextPath = sc.getContextPath(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java index 4d463313c..64f3043c3 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java @@ -17,23 +17,18 @@ import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; public class UrlBuilder { private static final Log log = LogFactory.getLog(UrlBuilder.class.getName()); + + protected static String contextPath = null; + private static boolean addPortalParam = PortalPickerFilter.isPortalPickingActive(); private Portal portal; - // This is static so that getUrl() can be static and refer to contextPath. - // getUrl() is static so that view objects can call it without - // having to instantiate an object and inject knowledge of the context path, which - // they don't have. - protected static String contextPath = null; - - private static boolean isMultiPortal = PortalPickerFilter.isPortalPickingActive(); - - public enum Routes { + public enum Route { ABOUT("/about"), BROWSE("/browse"), CONTACT("/contact"), INDIVIDUAL("/individual"), - INDIVIDUAL_LIST("/entitylist"), // "/individuallist" + INDIVIDUAL_LIST("/individuallist"), // individuallist entitylist SEARCH("/search"), TERMS_OF_USE("/termsOfUse"), @@ -44,7 +39,7 @@ public class UrlBuilder { private final String path; - Routes(String path) { + Route(String path) { this.path = path; } @@ -75,7 +70,7 @@ public class UrlBuilder { } public String getLogoutUrl() { - return getPortalUrl(Routes.LOGOUT.url(), new Params("loginSubmitMode", "logout")); + return getPortalUrl(Route.LOGOUT.url(), new Params("loginSubmitMode", "logout")); } public Params getPortalParam() { @@ -83,21 +78,21 @@ public class UrlBuilder { } public String getPortalUrl(String path) { - return isMultiPortal ? getUrl(path, getPortalParam()) : getUrl(path); + return addPortalParam ? getUrl(path, getPortalParam()) : getUrl(path); } public String getPortalUrl(String path, Params params) { - if (isMultiPortal) { + if (addPortalParam) { params.putAll(getPortalParam()); } return getUrl(path, params); } - public String getPortalUrl(Routes route) { + public String getPortalUrl(Route route) { return getPortalUrl(route.path()); } - public String getPortalUrl(Routes route, Params params) { + public String getPortalUrl(Route route, Params params) { return getPortalUrl(route.path(), params); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/view/IndividualView.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/IndividualView.java index a2eb5270a..079dc678d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/view/IndividualView.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/IndividualView.java @@ -6,14 +6,15 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Routes; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; +import edu.cornell.mannlib.vitro.webapp.view.ViewFinder.ClassView; public class IndividualView extends ViewObject { private static final Log log = LogFactory.getLog(IndividualView.class.getName()); - private static final String PATH = Routes.INDIVIDUAL.path(); + private static final String PATH = Route.INDIVIDUAL.path(); private Individual individual; @@ -44,13 +45,10 @@ public class IndividualView extends ViewObject { return getUrl("/individual/" + individual.getLocalName()); } - public String getListView() { - // TODO - // iterate through class hierarchy looking for a custom short view. If none, use - // default individual short view. template will just do an include on individual.shortView - // Use individual.getVClasses() - this is the class hierarchy - // Question: what order are they returned in ? If from specific to general, break out of the iteration as soon as we find one. - return "defaultIndividualListView.ftl"; + public String getSearchView() { + + ViewFinder vf = new ViewFinder(ClassView.SEARCH); + return vf.findView(individual, context); } public String getCustomView() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/view/VClassView.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/VClassView.java index 3c536df5d..979149efd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/view/VClassView.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/VClassView.java @@ -7,12 +7,12 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Params; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Routes; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; public class VClassView extends ViewObject { private static final Log log = LogFactory.getLog(VClassView.class.getName()); - private static final String PATH = Routes.INDIVIDUAL_LIST.path(); + private static final String PATH = Route.INDIVIDUAL_LIST.path(); private VClass vclass; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewFinder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewFinder.java new file mode 100644 index 000000000..346102269 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewFinder.java @@ -0,0 +1,107 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.view; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +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.utils.StringUtils; + +/** + * Class to find custom class views for individuals + * @author rjy7 + * + */ +public class ViewFinder { + + private static final Log log = LogFactory.getLog(ViewFinder.class.getName()); + + public enum ClassView { + DISPLAY("getCustomDisplayView", "/view/display"), + FORM("getCustomEntryForm", "/form"), + SEARCH("getCustomSearchView", "/view/search"), + SHORT("getCustomShortView", "/view/short"); + + private static String TEMPLATE_PATH = "/templates/freemarker/body/partials/class"; + + private Method method = null; + private String path = null; + + ClassView(String methodName, String path) { + Class vc = VClass.class; + this.path = path; + try { + method = vc.getMethod(methodName); + } catch (SecurityException e) { + log.error("Access denied to method " + methodName + " or class " + vc.getName()); + } catch (NoSuchMethodException e) { + log.error("Method " + methodName + " not defined for class " + vc.getName()); + } + } + + protected Method getMethod() { + return method; + } + + protected String getPath() { + return TEMPLATE_PATH + path; + } + + } + + private ClassView view; + + public ViewFinder(ClassView view) { + this.view = view; + } + + public String findView(Individual individual, ServletContext context) { + String viewName = "default.ftl"; + // For now, all custom views are attached to classes. + List vclasses = individual.getVClasses(); + Method method = view.getMethod(); + /* 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 + * specific custom view applicable to the individual. + * The logic is complex because individuals can belong + * to multiple classes, and classes can subclass multiple + * classes. If there are two competing custom views at the + * same level of specificity, what should we do? Also, if we + * are displaying a list of individuals belonging to a certain + * class, we may want to use only a custom view defined for that + * class and NOT a more specific one. See NIHVIVO-568. + */ + 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()."); + } + + } + return viewName; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewObject.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewObject.java index cbe5c9998..1943a8625 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewObject.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/view/ViewObject.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.view; +import javax.servlet.ServletContext; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -11,6 +13,8 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Params; public abstract class ViewObject { private static final Log log = LogFactory.getLog(ViewObject.class.getName()); + + public static ServletContext context = null; // Wrap UrlBuilder method so templates can call ${item.url} public String getUrl(String path) { diff --git a/webapp/web/templates/freemarker/body/individualList.ftl b/webapp/web/templates/freemarker/body/individualList.ftl index 64b99be3d..c864ceae1 100644 --- a/webapp/web/templates/freemarker/body/individualList.ftl +++ b/webapp/web/templates/freemarker/body/individualList.ftl @@ -14,9 +14,9 @@ <#else> <#-- RY NEED TO ACCOUNT FOR p:process stuff -->
    - <#list individuals as individual> + <#list individuals as individual>
  • - <#include "partials/defaultIndividualListView.ftl"> + <#include "partials/class/view/search/${individual.searchView}">
diff --git a/webapp/web/templates/freemarker/body/partials/defaultIndividualListView.ftl b/webapp/web/templates/freemarker/body/partials/class/view/search/default.ftl similarity index 89% rename from webapp/web/templates/freemarker/body/partials/defaultIndividualListView.ftl rename to webapp/web/templates/freemarker/body/partials/class/view/search/default.ftl index 4213143e6..ae38c697d 100644 --- a/webapp/web/templates/freemarker/body/partials/defaultIndividualListView.ftl +++ b/webapp/web/templates/freemarker/body/partials/class/view/search/default.ftl @@ -1,3 +1,3 @@ <#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> -${individual.name} ${individual.tagline} +${individual.name} ${individual.tagline}