Rewrote IndividualListController to handle error conditions from within FreeMarker. Reorganized controller control flow to account for interdependencies between body and title.

This commit is contained in:
rjy7 2010-05-25 19:20:25 +00:00
parent f40e2d1af7
commit fbdba79833
11 changed files with 307 additions and 280 deletions

View file

@ -2,7 +2,9 @@
package edu.cornell.mannlib.vitro.webapp.controller.freemarker; package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -24,6 +26,13 @@ public class AboutController extends FreeMarkerHttpServlet {
body.put("aboutText", portal.getAboutText()); body.put("aboutText", portal.getAboutText());
body.put("acknowledgeText", portal.getAcknowledgeText()); body.put("acknowledgeText", portal.getAcknowledgeText());
// Test of #list directive in template on undefined, null, or empty values
// Basic idea: empty list okay, null or undefined value not okay
// List<String> apples = new ArrayList<String>(); // no error
// List<String> apples = null; // error
// body.put("apples", apples);
// no apples in body: error
String bodyTemplate = "about.ftl"; String bodyTemplate = "about.ftl";
return mergeBodyToTemplate(bodyTemplate, body); return mergeBodyToTemplate(bodyTemplate, body);

View file

@ -18,12 +18,11 @@ import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
import edu.cornell.mannlib.vitro.webapp.flags.PortalFlag; import edu.cornell.mannlib.vitro.webapp.flags.PortalFlag;
import edu.cornell.mannlib.vitro.webapp.view.VClassGroupView; import edu.cornell.mannlib.vitro.webapp.view.VClassGroupView;
import freemarker.template.SimpleSequence;
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 freemarker.template.*;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import java.util.*; import java.util.*;
@ -69,7 +68,9 @@ public class BrowseController extends FreeMarkerHttpServlet {
protected String getBody() { protected String getBody() {
Map body = new HashMap(); Map<String, Object> body = new HashMap<String, Object>();
String bodyTemplate = "classGroups.ftl";
String message = null;
// Set main page template attributes specific to this page // Set main page template attributes specific to this page
// But the template should control this! Try putting in a div inside the content. // But the template should control this! Try putting in a div inside the content.
@ -80,22 +81,25 @@ public class BrowseController extends FreeMarkerHttpServlet {
//PortalFlag portalState= vreq.getPortalFlag(); //PortalFlag portalState= vreq.getPortalFlag();
String message = ""; List<VClassGroup> groups = getGroups(vreq.getWebappDaoFactory().getVClassGroupDao(), portalId);
List<VClassGroup> groups = getGroups(vreq.getWebappDaoFactory().getVClassGroupDao(), vreq.getPortal().getPortalId());
if (groups == null || groups.isEmpty()) { if (groups == null || groups.isEmpty()) {
message = "There are not yet any items in the system."; message = "There are not yet any items in the system.";
body.put("message", message);
} }
else { else {
// FreeMarker will wrap vcgroups in a SimpleSequence. So do we want to create the SimpleSequence directly?
// But, makes code less portable to another system.
// SimpleSequence vcgroups = new SimpleSequence(groups.size());
List<VClassGroupView> vcgroups = new ArrayList<VClassGroupView>(groups.size()); List<VClassGroupView> vcgroups = new ArrayList<VClassGroupView>(groups.size());
Iterator<VClassGroup> i = groups.iterator(); for (VClassGroup g: groups) {
while (i.hasNext()) { vcgroups.add(new VClassGroupView(g));
vcgroups.add(new VClassGroupView(i.next()));
} }
body.put("classGroups", vcgroups); body.put("classGroups", vcgroups);
} }
String bodyTemplate = "classGroups.ftl"; if (message != null) {
body.put("message", message);
}
return mergeBodyToTemplate(bodyTemplate, body); return mergeBodyToTemplate(bodyTemplate, body);
} }

View file

@ -66,17 +66,12 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
protected String appName; protected String appName;
protected Map<String, Object> root = new HashMap<String, Object>(); protected Map<String, Object> root = new HashMap<String, Object>();
// Some servlets have their own doGet() method, in which case they need to call
// doSetup(), setTitle(), setBody(), and write() themselves. Other servlets define only
// a getBody() and getTitle() method and use the parent doGet() method.
public void doGet( HttpServletRequest request, HttpServletResponse response ) public void doGet( HttpServletRequest request, HttpServletResponse response )
throws IOException, ServletException { throws IOException, ServletException {
try { try {
callSuperGet(request, response); // ??
doSetup(request, response); doSetup(request, response);
setTitle(); setTitleAndBody();
setBody();
write(response); write(response);
} catch (Throwable e) { } catch (Throwable e) {
@ -91,88 +86,21 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
doGet(request, response); doGet(request, response);
} }
protected void setBody() { // Basic setup needed by all controllers
root.put("body", getBody());
}
protected void setSharedVariable(String key, Object value) {
try {
config.setSharedVariable(key, value);
} catch (TemplateModelException e) {
log.error("Can't set shared variable '" + key + "'.");
}
}
protected void setTitle() {
setSharedVariable("title", getTitle());
}
protected String getTitle() {
return null;
}
protected String getBody() {
return null;
}
protected StringWriter mergeToTemplate(String templateName, Map<String, Object> map) {
Template template = null;
try {
template = config.getTemplate(templateName);
} catch (IOException e) {
log.error("Cannot get template " + templateName);
}
StringWriter sw = new StringWriter();
if (template != null) {
try {
template.process(map, sw);
} catch (TemplateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return sw;
}
protected String mergeBodyToTemplate(String templateName, Map<String, Object> map) {
templateName = "body/" + templateName;
String body = mergeToTemplate(templateName, map).toString();
return body;
}
protected void write(HttpServletResponse response) {
String templateName = "page/default.ftl";
StringWriter sw = mergeToTemplate(templateName, root);
try {
PrintWriter out = response.getWriter();
out.print(sw);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void callSuperGet(HttpServletRequest request, HttpServletResponse response) {
try {
super.doGet(request,response);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// RY This needs to be broken out as is for FreeMarkerComponentGenerator, which should not
// include callSuperGet(). So it's only temporary.
protected void doSetup(HttpServletRequest request, HttpServletResponse response) { protected void doSetup(HttpServletRequest request, HttpServletResponse response) {
if ( !(this instanceof FreeMarkerComponentGenerator) ) {
try {
super.doGet(request,response);
} catch (ServletException e) {
log.error("Servlet exception calling VitroHttpRequest.doGet()");
e.printStackTrace();
} catch (IOException e) {
log.error("IO exception calling VitroHttpRequest.doGet()");
e.printStackTrace();
}
}
vreq = new VitroRequest(request); vreq = new VitroRequest(request);
this.response = response; this.response = response;
portal = vreq.getPortal(); portal = vreq.getPortal();
@ -211,6 +139,34 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
setSharedVariable("scripts", new ScriptList()); setSharedVariable("scripts", new ScriptList());
} }
// Define template locations. Template loader will look first in the theme-specific
// location, then in the vitro location.
// RY We cannot do this in FreeMarkerSetup because (a) the theme depends on the portal,
// and we have multi-portal installations, and (b) we need to support theme-switching on the fly.
// To make more efficient, we could do this once, and then have a listener that does it again
// when theme is switched. BUT this doesn't support (a), only (b), so we have to do it on every request.
protected final void setTemplateLoader() {
String themeTemplateDir = context.getRealPath(getThemeDir()) + "/ftl";
String vitroTemplateDir = context.getRealPath("/templates/freemarker");
try {
FileTemplateLoader themeFtl = new FileTemplateLoader(new File(themeTemplateDir));
FileTemplateLoader vitroFtl = new FileTemplateLoader(new File(vitroTemplateDir));
ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), "");
TemplateLoader[] loaders = new TemplateLoader[] { themeFtl, vitroFtl, ctl };
MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);
config.setTemplateLoader(mtl);
} catch (IOException e) {
log.error("Error loading templates");
}
}
private TabMenu getTabMenu() {
return new TabMenu(vreq, portalId);
}
public String getThemeDir() { public String getThemeDir() {
return portal.getThemeDir().replaceAll("/$", ""); return portal.getThemeDir().replaceAll("/$", "");
} }
@ -252,31 +208,31 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
setSharedVariable("urls", urls); setSharedVariable("urls", urls);
} }
private final void setLoginInfo() { private final void setLoginInfo() {
String loginName = null; String loginName = null;
int securityLevel; int securityLevel;
HttpSession session = vreq.getSession(); HttpSession session = vreq.getSession();
LoginFormBean loginBean = (LoginFormBean) session.getAttribute("loginHandler"); LoginFormBean loginBean = (LoginFormBean) session.getAttribute("loginHandler");
if (loginBean != null && loginBean.testSessionLevel(vreq) > -1) { if (loginBean != null && loginBean.testSessionLevel(vreq) > -1) {
loginName = loginBean.getLoginName(); loginName = loginBean.getLoginName();
securityLevel = Integer.parseInt(loginBean.getLoginRole()); securityLevel = Integer.parseInt(loginBean.getLoginRole());
} }
if (loginName != null) { if (loginName != null) {
root.put("loginName", loginName); root.put("loginName", loginName);
securityLevel = Integer.parseInt(loginBean.getLoginRole()); securityLevel = Integer.parseInt(loginBean.getLoginRole());
if (securityLevel >= FILTER_SECURITY_LEVEL) { if (securityLevel >= FILTER_SECURITY_LEVEL) {
ApplicationBean appBean = vreq.getAppBean(); ApplicationBean appBean = vreq.getAppBean();
if (appBean.isFlag1Active()) { if (appBean.isFlag1Active()) {
root.put("showFlag1SearchField", true); root.put("showFlag1SearchField", true);
} }
} }
} }
} }
private final void setCopyrightInfo() { private final void setCopyrightInfo() {
String copyrightText = portal.getCopyrightAnchor(); String copyrightText = portal.getCopyrightAnchor();
if ( ! StringUtils.isEmpty(copyrightText) ) { if ( ! StringUtils.isEmpty(copyrightText) ) {
@ -289,13 +245,13 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
copyright.put("url", portal.getCopyrightURL()); copyright.put("url", portal.getCopyrightURL());
root.put("copyright", copyright); root.put("copyright", copyright);
} }
} }
private final void setThemeInfo(String themeDir) { private final void setThemeInfo(String themeDir) {
// This value will be available to any template as a path for adding a new stylesheet. // This value will be available to any template as a path for adding a new stylesheet.
// It does not contain the context path, because the methods to generate the href // It does not contain the context path, because the methods to generate the href
// attribute from the string passed in by the template automatically add the context path. // attribute from the string passed in by the template automatically add the context path.
setSharedVariable("stylesheetDir", themeDir + "/css"); setSharedVariable("stylesheetDir", themeDir + "/css");
String themeDirWithContext = getUrl(themeDir); String themeDirWithContext = getUrl(themeDir);
@ -305,41 +261,107 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
setSharedVariable("siteIconPath", themeDirWithContext + "/site_icons"); setSharedVariable("siteIconPath", themeDirWithContext + "/site_icons");
}
// Default case is to set title first, because it's used in the body. However, in some cases
// the title is based on values computed during compilation of the body (e.g., IndividualListController).
// Individual controllers can override this method to set title and body together. End result must be:
// body is added to root with key "body"
// title is set as a shared variable with key "title"
// This can be achieved by making sure setBody() and setTitle() are called.
protected void setTitleAndBody() {
setTitle();
setBody();
}
protected void setBody() {
root.put("body", getBody());
} }
// Define template locations. Template loader will look first in the theme-specific protected String getBody() {
// location, then in the vitro location. return ""; // body should never be null
// RY We cannot do this in FreeMarkerSetup because (a) the theme depends on the portal, }
// and we have multi-portal installations, and (b) we need to support theme-switching on the fly.
// To make more efficient, we could do this once, and then have a listener that does it again
// when theme is switched. BUT this doesn't support (a), only (b), so we have to do it on every request.
protected final void setTemplateLoader() {
String themeTemplateDir = context.getRealPath(getThemeDir()) + "/ftl"; protected void setTitle() {
String vitroTemplateDir = context.getRealPath("/templates/freemarker"); String title = getTitle();
// If the individual controller fails to assign a non-null, non-empty title
if (StringUtils.isEmpty(title)) {
title = appName;
}
// Title is a shared variable because it's used in both body and head elements.
setSharedVariable("title", title);
}
protected String getTitle() {
return "";
}
protected void setSharedVariable(String key, Object value) {
try { try {
FileTemplateLoader themeFtl = new FileTemplateLoader(new File(themeTemplateDir)); config.setSharedVariable(key, value);
FileTemplateLoader vitroFtl = new FileTemplateLoader(new File(vitroTemplateDir)); } catch (TemplateModelException e) {
ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), ""); log.error("Can't set shared variable '" + key + "'.");
TemplateLoader[] loaders = new TemplateLoader[] { themeFtl, vitroFtl, ctl };
MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);
config.setTemplateLoader(mtl);
} catch (IOException e) {
log.error("Error loading templates");
} }
}
} protected StringWriter mergeToTemplate(String templateName, Map<String, Object> map) {
private TabMenu getTabMenu() { Template template = null;
return new TabMenu(vreq, portalId); try {
} template = config.getTemplate(templateName);
} catch (IOException e) {
log.error("Cannot get template " + templateName);
}
StringWriter sw = new StringWriter();
if (template != null) {
try {
template.process(map, sw);
} catch (TemplateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return sw;
}
protected String mergeBodyToTemplate(String templateName, Map<String, Object> map) {
templateName = "body/" + templateName;
String body = mergeToTemplate(templateName, map).toString();
return body;
}
protected void write(HttpServletResponse response) {
String templateName = "page/" + getPageTemplateName();
StringWriter sw = mergeToTemplate(templateName, root);
try {
PrintWriter out = response.getWriter();
out.print(sw);
} catch (IOException e) {
log.error("FreeMarkerHttpServlet cannot write output");
e.printStackTrace();
}
}
// Can be overridden by individual controllers
protected String getPageTemplateName() {
return "default.ftl";
}
public static boolean isConfigured() {
return config != null;
}
// TEMPORARY for transition from JSP to FreeMarker. Once transition // TEMPORARY for transition from JSP to FreeMarker. Once transition
// is complete and no more pages are generated in JSP, this can be removed. // is complete and no more pages are generated in JSP, this can be removed.
// Do this if FreeMarker is configured (i.e., not Datastar) and if we are not in // Do this if FreeMarker is configured (i.e., not Datastar) and if we are not in
// a FreeMarkerHttpServlet, which will generate identity, menu, and footer from the page template. // a FreeMarkerHttpServlet, which will generate identity, menu, and footer from the page template.
// It's a static method because it needs to be called from JSPs that don't go through a servlet. // It's a static method because it needs to be called from JSPs that don't go through a servlet.
public static void getFreeMarkerComponentsForJsp(HttpServletRequest request, HttpServletResponse response) { public static void getFreeMarkerComponentsForJsp(HttpServletRequest request, HttpServletResponse response) {
FreeMarkerComponentGenerator fcg = new FreeMarkerComponentGenerator(request, response); FreeMarkerComponentGenerator fcg = new FreeMarkerComponentGenerator(request, response);
request.setAttribute("ftl_identity", fcg.getIdentity()); request.setAttribute("ftl_identity", fcg.getIdentity());
@ -348,11 +370,7 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
request.setAttribute("ftl_footer", fcg.getFooter()); request.setAttribute("ftl_footer", fcg.getFooter());
} }
public static boolean isConfigured() { /* ******************** Static utilities ******************* */
return config != null;
}
/* ******************** Utilities ******************* */
public static String getUrl(String path) { public static String getUrl(String path) {
if ( ! path.startsWith("/") ) { if ( ! path.startsWith("/") ) {

View file

@ -2,144 +2,119 @@
package edu.cornell.mannlib.vitro.webapp.controller.freemarker; package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.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.beans.VClassGroup; import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.view.IndividualView; import edu.cornell.mannlib.vitro.webapp.view.IndividualView;
/**
* Generates a list of individuals for display in a template
*/
public class IndividualListController extends FreeMarkerHttpServlet { public class IndividualListController extends FreeMarkerHttpServlet {
long startTime = -1;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(IndividualListController.class.getName()); private static final Log log = LogFactory.getLog(IndividualListController.class.getName());
private VClass vclass = null; private VClass vclass = null;
private String title = null;
/** protected void setTitleAndBody() {
* This generates a list of entities and then sends that setBody();
* off to a jsp to be displayed. }
*
* Expected parameters: protected String getBody() {
*
* Expected Attributes: Map<String, Object> body = new HashMap<String, Object>();
* entity - set to entity to display properties for. String bodyTemplate = "individualList.ftl";
* String errorMessage = null;
* @author bdc34 String message = null;
*/
// TODO Rewrite error cases to use FreeMarker templates. Restructure so we're always doing the body
// and then calling writeOutput().
public void doGet( HttpServletRequest req, HttpServletResponse res )
throws IOException, ServletException {
startTime = System.currentTimeMillis(); // TODO: remove
try { try {
super.doSetup(req, res);
Object obj = vreq.getAttribute("vclass"); Object obj = vreq.getAttribute("vclass");
vclass=null; vclass = null;
if( obj == null ) { // look for vitroclass id parameter if ( obj == null ) { // look for vitroclass id parameter
String vitroClassIdStr=req.getParameter("vclassId"); String vitroClassIdStr = vreq.getParameter("vclassId");
if (vitroClassIdStr!=null && !vitroClassIdStr.equals("")) { if ( !StringUtils.isEmpty(vitroClassIdStr)) {
try { try {
//TODO have to change this so vclass's group and entity count are populated //TODO have to change this so vclass's group and entity count are populated
vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vitroClassIdStr); vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vitroClassIdStr);
if (vclass == null) { if (vclass == null) {
log.error("Couldn't retrieve vclass "+vitroClassIdStr); log.error("Couldn't retrieve vclass " + vitroClassIdStr);
response.sendRedirect(Routes.BROWSE + "?"+vreq.getQueryString()); errorMessage = "Class " + vitroClassIdStr + " not found";
} }
} catch (Exception ex) { } catch (Exception ex) {
throw new HelpException("IndividualListController: request parameter 'vclassId' must be a URI string"); throw new HelpException("IndividualListController: request parameter 'vclassId' must be a URI string.");
} }
} }
} else if (obj instanceof VClass) { } else if (obj instanceof VClass) {
vclass = (VClass)obj; vclass = (VClass)obj;
} else { } else {
throw new HelpException("IndividualListController: attribute 'vclass' must be of type " throw new HelpException("IndividualListController: attribute 'vclass' must be of type "
+ VClass.class.getName() ); + VClass.class.getName() + ".");
} }
if (vclass!=null){
setBody(); if (vclass != null) {
write(response); // Create list of individual view objects
List<Individual> individualList = vreq.getWebappDaoFactory().getIndividualDao().getIndividualsByVClass(vclass);
List<IndividualView> individuals = new ArrayList<IndividualView>(individualList.size());
if (individualList == null) {
// RY Is this really an error?
log.error("individuals list is null");
message = "No individuals to display.";
} else {
for (Individual i: individualList) {
individuals.add(new IndividualView(i));
}
}
// Set title and subtitle. Title will be retrieved later in getTitle().
VClassGroup classGroup = vclass.getGroup();
if (classGroup == null) {
title = vclass.getName();
} else {
title = classGroup.getPublicName();
body.put("subtitle", vclass.getName());
}
body.put("individuals", individuals);
} }
// RY Rewrite error cases for FreeMarker, not JSP
} catch (HelpException help){ } catch (HelpException help){
doHelp(response); errorMessage = "Request attribute 'vclass' or request parameter 'vclassId' must be set before calling. Its value must be a class uri.";
} catch (Throwable e) { } catch (Throwable e) {
vreq.setAttribute("javax.servlet.jsp.jspException",e); bodyTemplate = "error.ftl";
RequestDispatcher rd = req.getRequestDispatcher("/error.jsp");
rd.forward(vreq, response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException,IOException {
doGet(request, response);
}
protected String getBody() {
Map<String, Object> body = new HashMap<String, Object>();
// Create list of individuals
List<Individual> individualList = vreq.getWebappDaoFactory().getIndividualDao().getIndividualsByVClass(vclass);
List<IndividualView> individuals = new ArrayList<IndividualView>(individualList.size());
Iterator<Individual> i = individualList.iterator();
while (i.hasNext()) {
individuals.add(new IndividualView(i.next()));
}
body.put("individuals", individuals);
// But the JSP version includes url rewriting via URLRewritingHttpServletResponse
// RY *** FIX - define getUrl method of IndividualView
body.put("individualUrl", getUrl("/entity?home=" + portalId + "&uri="));
if (individuals == null) {
log.error("individuals list is null");
} }
// Use instead of getTitle(), because we have a subtitle too if (errorMessage != null) {
String title = ""; bodyTemplate = "errorMessage.ftl";
VClassGroup classGroup=vclass.getGroup(); body.put("errorMessage", errorMessage);
if (classGroup==null) { } else if (message != null) {
title = vclass.getName(); body.put("message", message);
} else {
title = classGroup.getPublicName();
setSharedVariable("subTitle", vclass.getName());
} }
setSharedVariable("title", title);
String templateName = "individualList.ftl"; setTitle();
return mergeBodyToTemplate(templateName, body);
return mergeBodyToTemplate(bodyTemplate, body);
} }
// RY Rewrite as a template protected String getTitle() {
private void doHelp(HttpServletResponse res) // The title is determined during compilation of the body, so we put it in an instance variable
throws IOException, ServletException { // to be retrieved later.
ServletOutputStream out = res.getOutputStream(); return title;
res.setContentType("text/html; charset=UTF-8");
out.println("<html><body><h2>Quick Notes on using EntityList:</h2>");
out.println("<p>request.attributes 'entities' must be set by servlet before calling."
+" It must be a List of Entity objects </p>");
out.println("</body></html>");
} }
private class HelpException extends Throwable{ private class HelpException extends Throwable {
private static final long serialVersionUID = 1L;
public HelpException(String string) { public HelpException(String string) {
super(string); super(string);
} }

View file

@ -11,7 +11,7 @@ public class Routes {
public static final String BROWSE = "/browse"; public static final String BROWSE = "/browse";
public static final String COMMENT_FORM = "/comments"; public static final String COMMENT_FORM = "/comments";
public static final String INDIVIDUAL = "/individual"; public static final String INDIVIDUAL = "/individual";
public static final String INDIVIDUAL_LIST = "/entitylist"; // "/individuallist"; public static final String INDIVIDUAL_LIST = "/individuallist"; // "/entitylist"; "/individuallist";
public static final String SEARCH = "/search"; public static final String SEARCH = "/search";
public static final String TERMS_OF_USE = "/termsOfUse"; public static final String TERMS_OF_USE = "/termsOfUse";

View file

@ -25,6 +25,8 @@ public class IndividualView extends ViewObject {
return individual.getName(); return individual.getName();
} }
// RY However, the moniker should undergo p:process but the class name shouldn't!
// So, it needs to be callable from Java.
public String getTagline() { public String getTagline() {
String tagline = individual.getMoniker(); String tagline = individual.getMoniker();
return StringUtils.isEmpty(tagline) ? individual.getVClass().getName() : tagline; return StringUtils.isEmpty(tagline) ? individual.getVClass().getName() : tagline;

View file

@ -1,6 +1,6 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> <#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Comment form --> <#-- Contact form -->
<div class="staticPageBackground feedbackForm"> <div class="staticPageBackground feedbackForm">

View file

@ -0,0 +1,7 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Template for general system error. -->
<p>There was an error in the system.</p>
<p>Return to the <a href="${urls.home}">home page</a>.</p>

View file

@ -0,0 +1,7 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Standard template to display an error message generated from any controller. Keeps this out of individual templates. -->
<#if errorMessage??>
<p>${errorMessage}</p>
</#if>

View file

@ -7,16 +7,21 @@
<div class="individualList"> <div class="individualList">
<h2>${title}</h2> <h2>${title}</h2>
<#if subtitle??> <#if subtitle??>
<h4>${subTitle}"</h4> <h4>${subtitle}</h4>
</#if> </#if>
<#-- RY NEED TO ACCOUNT FOR p:process stuff --> <#if message??>
<ul> <p>${message}</p>
<#list individuals as individual> <#else>
<li> <#-- RY NEED TO ACCOUNT FOR p:process stuff -->
<a href="${individual.profileUrl}">${individual.name}</a> ${individual.tagline} <ul>
</li> <#list individuals as individual>
</#list> <li>
</ul> <a href="${individual.profileUrl}">${individual.name}</a> ${individual.tagline}
</li>
</#list>
</ul>
</#if>
</div> </div>
</div> </div>