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.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);
}

View file

@ -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();
}

View file

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

View file

@ -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() {

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.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;

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;
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) {

View file

@ -14,9 +14,9 @@
<#else>
<#-- RY NEED TO ACCOUNT FOR p:process stuff -->
<ul>
<#list individuals as individual>
<#list individuals as individual>
<li>
<#include "partials/defaultIndividualListView.ftl">
<#include "partials/class/view/search/${individual.searchView}">
</li>
</#list>
</ul>

View file

@ -1,3 +1,3 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<a href="${individual.profileUrl}">${individual.name}</a> ${individual.tagline}
<a href="${individual.profileUrl}">${individual.name}</a> ${individual.tagline}