Handle custom search views used on individual list page.

This commit is contained in:
rjy7 2010-05-28 21:44:59 +00:00
parent a4f652ddbf
commit c2fa2c4e37
9 changed files with 143 additions and 39 deletions

View file

@ -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.ContactMailServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; 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.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.view.fileList.ScriptList; import edu.cornell.mannlib.vitro.webapp.view.fileList.ScriptList;
import edu.cornell.mannlib.vitro.webapp.view.fileList.StylesheetList; 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)); 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) { 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("search", urlBuilder.getPortalUrl(Route.SEARCH));
urls.put("termsOfUse", urlBuilder.getPortalUrl(Routes.TERMS_OF_USE)); urls.put("termsOfUse", urlBuilder.getPortalUrl(Route.TERMS_OF_USE));
urls.put("login", urlBuilder.getPortalUrl(Routes.LOGIN)); urls.put("login", urlBuilder.getPortalUrl(Route.LOGIN));
urls.put("logout", urlBuilder.getLogoutUrl()); urls.put("logout", urlBuilder.getLogoutUrl());
urls.put("siteAdmin", urlBuilder.getPortalUrl(Routes.LOGIN)); urls.put("siteAdmin", urlBuilder.getPortalUrl(Route.LOGIN));
setSharedVariable("urls", urls); setSharedVariable("urls", urls);
} }

View file

@ -10,7 +10,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties; 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.Configuration;
import freemarker.template.DefaultObjectWrapper; import freemarker.template.DefaultObjectWrapper;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
@ -52,7 +52,7 @@ public class FreeMarkerSetup implements ServletContextListener {
FreeMarkerHttpServlet.config = cfg; FreeMarkerHttpServlet.config = cfg;
FreeMarkerHttpServlet.context = sc; FreeMarkerHttpServlet.context = sc;
ViewObject.context = sc;
UrlBuilder.contextPath = sc.getContextPath(); UrlBuilder.contextPath = sc.getContextPath();
} }

View file

@ -18,22 +18,17 @@ public class UrlBuilder {
private static final Log log = LogFactory.getLog(UrlBuilder.class.getName()); private static final Log log = LogFactory.getLog(UrlBuilder.class.getName());
protected static String contextPath = null;
private static boolean addPortalParam = PortalPickerFilter.isPortalPickingActive();
private Portal portal; private Portal portal;
// This is static so that getUrl() can be static and refer to contextPath. public enum Route {
// 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 {
ABOUT("/about"), ABOUT("/about"),
BROWSE("/browse"), BROWSE("/browse"),
CONTACT("/contact"), CONTACT("/contact"),
INDIVIDUAL("/individual"), INDIVIDUAL("/individual"),
INDIVIDUAL_LIST("/entitylist"), // "/individuallist" INDIVIDUAL_LIST("/individuallist"), // individuallist entitylist
SEARCH("/search"), SEARCH("/search"),
TERMS_OF_USE("/termsOfUse"), TERMS_OF_USE("/termsOfUse"),
@ -44,7 +39,7 @@ public class UrlBuilder {
private final String path; private final String path;
Routes(String path) { Route(String path) {
this.path = path; this.path = path;
} }
@ -75,7 +70,7 @@ public class UrlBuilder {
} }
public String getLogoutUrl() { public String getLogoutUrl() {
return getPortalUrl(Routes.LOGOUT.url(), new Params("loginSubmitMode", "logout")); return getPortalUrl(Route.LOGOUT.url(), new Params("loginSubmitMode", "logout"));
} }
public Params getPortalParam() { public Params getPortalParam() {
@ -83,21 +78,21 @@ public class UrlBuilder {
} }
public String getPortalUrl(String path) { 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) { public String getPortalUrl(String path, Params params) {
if (isMultiPortal) { if (addPortalParam) {
params.putAll(getPortalParam()); params.putAll(getPortalParam());
} }
return getUrl(path, params); return getUrl(path, params);
} }
public String getPortalUrl(Routes route) { public String getPortalUrl(Route route) {
return getPortalUrl(route.path()); return getPortalUrl(route.path());
} }
public String getPortalUrl(Routes route, Params params) { public String getPortalUrl(Route route, Params params) {
return getPortalUrl(route.path(), params); return getPortalUrl(route.path(), params);
} }

View file

@ -6,14 +6,15 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; 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.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.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.view.ViewFinder.ClassView;
public class IndividualView extends ViewObject { public class IndividualView extends ViewObject {
private static final Log log = LogFactory.getLog(IndividualView.class.getName()); 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; private Individual individual;
@ -44,13 +45,10 @@ public class IndividualView extends ViewObject {
return getUrl("/individual/" + individual.getLocalName()); return getUrl("/individual/" + individual.getLocalName());
} }
public String getListView() { public String getSearchView() {
// TODO
// iterate through class hierarchy looking for a custom short view. If none, use ViewFinder vf = new ViewFinder(ClassView.SEARCH);
// default individual short view. template will just do an include on individual.shortView return vf.findView(individual, context);
// 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 getCustomView() { public String getCustomView() {

View file

@ -7,12 +7,12 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.VClass; 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.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 { public class VClassView extends ViewObject {
private static final Log log = LogFactory.getLog(VClassView.class.getName()); 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; private VClass vclass;

View file

@ -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<VClass> 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<VClass> 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;
}
}

View file

@ -2,6 +2,8 @@
package edu.cornell.mannlib.vitro.webapp.view; package edu.cornell.mannlib.vitro.webapp.view;
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;
@ -12,6 +14,8 @@ public abstract class ViewObject {
private static final Log log = LogFactory.getLog(ViewObject.class.getName()); private static final Log log = LogFactory.getLog(ViewObject.class.getName());
public static ServletContext context = 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) {
return UrlBuilder.getUrl(path); return UrlBuilder.getUrl(path);

View file

@ -16,7 +16,7 @@
<ul> <ul>
<#list individuals as individual> <#list individuals as individual>
<li> <li>
<#include "partials/defaultIndividualListView.ftl"> <#include "partials/class/view/search/${individual.searchView}">
</li> </li>
</#list> </#list>
</ul> </ul>