NIHVIVO-2411 Implement the BROWSE short view, which uses AJAX calls and so requires a FreemarkerProcessingService to render the view into HTML.
This commit is contained in:
parent
cf94490842
commit
47b3565e58
7 changed files with 322 additions and 10 deletions
|
@ -0,0 +1,79 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
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.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.shortview.ShortViewService;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.shortview.ShortViewService.ShortViewContext;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.shortview.ShortViewServiceSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
|
||||
|
||||
/**
|
||||
* Does a Solr search for individuals, and uses the short view to render each of
|
||||
* the results.
|
||||
*/
|
||||
public class GetRenderedSolrIndividualsByVClass extends JsonObjectProducer {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(GetRenderedSolrIndividualsByVClass.class);
|
||||
|
||||
protected GetRenderedSolrIndividualsByVClass(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for individuals by VClass. The class URI and the paging
|
||||
* information are in the request parameters.
|
||||
*/
|
||||
@Override
|
||||
protected JSONObject process() throws Exception {
|
||||
JSONObject rObj = null;
|
||||
VClass vclass = getVclassParameter(vreq);
|
||||
String vclassId = vclass.getURI();
|
||||
|
||||
vreq.setAttribute("displayType", vclassId);
|
||||
rObj = JsonServlet.getSolrIndividualsByVClass(vclassId, vreq, ctx);
|
||||
addShortViewRenderings(rObj);
|
||||
|
||||
return rObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look through the return object. For each individual, render the short
|
||||
* view and insert the resulting HTML into the object.
|
||||
*/
|
||||
private void addShortViewRenderings(JSONObject rObj) throws JSONException {
|
||||
JSONArray individuals = rObj.getJSONArray("individuals");
|
||||
String vclassName = rObj.getJSONObject("vclass").getString("name");
|
||||
for (int i = 0; i < individuals.length(); i++) {
|
||||
JSONObject individual = individuals.getJSONObject(i);
|
||||
individual.put("shortViewHtml",
|
||||
renderShortView(individual.getString("URI"), vclassName));
|
||||
}
|
||||
}
|
||||
|
||||
private String renderShortView(String individualUri, String vclassName) {
|
||||
IndividualDao iDao = vreq.getWebappDaoFactory().getIndividualDao();
|
||||
Individual individual = iDao.getIndividualByURI(individualUri);
|
||||
|
||||
Map<String, Object> modelMap = new HashMap<String, Object>();
|
||||
modelMap.put("individual",
|
||||
new IndividualTemplateModel(individual, vreq));
|
||||
modelMap.put("vclass", vclassName);
|
||||
|
||||
ShortViewService svs = ShortViewServiceSetup.getService(ctx);
|
||||
return svs.renderShortView(individual, ShortViewContext.BROWSE,
|
||||
modelMap, vreq);
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ import edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter.PageDataGetterUtils
|
|||
* It could be generalized to get other types of data ex. XML, HTML etc
|
||||
* @author bdc34
|
||||
*
|
||||
* Moved most of the logic into a group of JsonProducer classes. jeb228
|
||||
*/
|
||||
public class JsonServlet extends VitroHttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -69,8 +70,8 @@ public class JsonServlet extends VitroHttpServlet {
|
|||
new GetSolrIndividualsByVClasses(vreq).process(resp);
|
||||
} else if( vreq.getParameter("getDataForPage") != null ){
|
||||
new GetDataForPage(vreq).process(resp);
|
||||
// }else if( vreq.getParameter("getRenderedSolrIndividualsByVClass") != null ){
|
||||
// new GetRenderedSolrIndividualsByVClass(vreq).process(resp);
|
||||
}else if( vreq.getParameter("getRenderedSolrIndividualsByVClass") != null ){
|
||||
new GetRenderedSolrIndividualsByVClass(vreq).process(resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.services.freemarker;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Provide the ability to process a Freemarker template outside of the context
|
||||
* of a FreemarkerHttpServlet.
|
||||
*
|
||||
* The most likely place to use this is when rendering a short view that was
|
||||
* invoked through an AJAX call.
|
||||
*/
|
||||
public interface FreemarkerProcessingService {
|
||||
/**
|
||||
* Is there an accessible template by this name?
|
||||
*
|
||||
* The question is asked in the context of the current request, which
|
||||
* determines the theme directory.
|
||||
*
|
||||
* @throws TemplateProcessingException
|
||||
* If the template is found, but cannot be parsed.
|
||||
*/
|
||||
boolean isTemplateAvailable(String templateName, HttpServletRequest req)
|
||||
throws TemplateProcessingException;
|
||||
|
||||
/**
|
||||
* Process a Freemarker template with a data map, producing string of HTML.
|
||||
*
|
||||
* This is done in the context of the current HttpServletRequest, which
|
||||
* provides a wide range of ancillary information, including (but not
|
||||
* limited to) theme directory, context path, info on logged-in user,
|
||||
* authorizations for the current user, etc., etc.
|
||||
*/
|
||||
String renderTemplate(String templateName, Map<String, Object> map,
|
||||
HttpServletRequest req) throws TemplateProcessingException;
|
||||
|
||||
/**
|
||||
* Indicates a failure to render the given template with the given data.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static class TemplateProcessingException extends Exception {
|
||||
|
||||
public TemplateProcessingException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TemplateProcessingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TemplateProcessingException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public TemplateProcessingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template parser detected a problem.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static class TemplateParsingException extends
|
||||
TemplateProcessingException {
|
||||
|
||||
public TemplateParsingException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TemplateParsingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TemplateParsingException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public TemplateParsingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.services.freemarker;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
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.FreemarkerConfiguration;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.core.ParseException;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
|
||||
/**
|
||||
* An implementation of the FreemarkerProcessingService.
|
||||
*/
|
||||
public class FreemarkerProcessingServiceImpl implements
|
||||
FreemarkerProcessingService {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(FreemarkerProcessingServiceImpl.class);
|
||||
|
||||
@Override
|
||||
public boolean isTemplateAvailable(String templateName,
|
||||
HttpServletRequest req) throws TemplateProcessingException {
|
||||
return null != getTemplate(templateName, req);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String renderTemplate(String templateName, Map<String, Object> map,
|
||||
HttpServletRequest req) throws TemplateProcessingException {
|
||||
log.debug("renderTemplate: '" + templateName + "' with "
|
||||
+ LogUtils.deepFormatForLog(log, "debug", map));
|
||||
Template template = getTemplate(templateName, req);
|
||||
return processTemplate(template, map, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch this template from a file and parse it. If there are any problems,
|
||||
* return "null".
|
||||
*/
|
||||
private Template getTemplate(String templateName, HttpServletRequest req)
|
||||
throws TemplateProcessingException {
|
||||
Template template = null;
|
||||
try {
|
||||
Configuration config = FreemarkerConfigurationLoader
|
||||
.getConfig(new VitroRequest(req));
|
||||
template = config.getTemplate(templateName);
|
||||
} catch (ParseException e) {
|
||||
log.warn("Failed to parse the template at '" + templateName + "'"
|
||||
+ e);
|
||||
throw new TemplateParsingException(e);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.debug("No template found for '" + templateName + "'");
|
||||
throw new TemplateProcessingException(e);
|
||||
} catch (IOException e) {
|
||||
log.warn("Failed to read the template at '" + templateName + "'", e);
|
||||
throw new TemplateProcessingException(e);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
private String processTemplate(Template template, Map<String, Object> map,
|
||||
HttpServletRequest req) throws TemplateProcessingException {
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
// Add directives to the map. For some reason, having them in the
|
||||
// configuration is not enough.
|
||||
map.putAll(FreemarkerConfiguration.getDirectives());
|
||||
|
||||
// Add request and servlet context as custom attributes of the
|
||||
// environment, so they
|
||||
// can be used in directives.
|
||||
Environment env = template.createProcessingEnvironment(map, writer);
|
||||
env.setCustomAttribute("request", req);
|
||||
env.setCustomAttribute("context", req.getSession()
|
||||
.getServletContext());
|
||||
env.process();
|
||||
return writer.toString();
|
||||
} catch (TemplateException e) {
|
||||
throw new TemplateProcessingException(
|
||||
"TemplateException creating processing environment", e);
|
||||
} catch (IOException e) {
|
||||
throw new TemplateProcessingException(
|
||||
"IOException creating processing environment", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.services.freemarker;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
/**
|
||||
* This would be used to create and publish such a service, but for now we can
|
||||
* simply create a fresh copy every time someone asks for one.
|
||||
*/
|
||||
public class FreemarkerProcessingServiceSetup {
|
||||
public static FreemarkerProcessingService getService(ServletContext ctx) {
|
||||
return new FreemarkerProcessingServiceImpl();
|
||||
}
|
||||
}
|
|
@ -67,7 +67,8 @@ public interface ShortViewService {
|
|||
* The available contexts for short views.
|
||||
*/
|
||||
public enum ShortViewContext {
|
||||
SEARCH("view-search-default.ftl"), INDEX("listedIndividual.ftl");
|
||||
SEARCH("view-search-default.ftl"), INDEX("listedIndividual.ftl"), BROWSE(
|
||||
"view-browse-default.ftl");
|
||||
|
||||
private final String defaultTemplateName;
|
||||
|
||||
|
|
|
@ -13,10 +13,16 @@ import java.util.TreeSet;
|
|||
|
||||
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.ObjectPropertyStatement;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService.TemplateParsingException;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingServiceSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.shortview.FakeApplicationOntologyService.TemplateAndDataGetters;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
|
||||
|
||||
|
@ -24,6 +30,9 @@ import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
|
|||
* The basic implementation of ShortViewService
|
||||
*/
|
||||
public class ShortViewServiceImpl implements ShortViewService {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(ShortViewServiceImpl.class);
|
||||
|
||||
private static final Map<String, Object> EMPTY_MAP = Collections.emptyMap();
|
||||
|
||||
private final FakeApplicationOntologyService faker;
|
||||
|
@ -39,17 +48,38 @@ public class ShortViewServiceImpl implements ShortViewService {
|
|||
|
||||
TemplateAndSupplementalData tsd = getShortViewInfo(individual, context,
|
||||
vreq);
|
||||
String templateName = tsd.getTemplateName();
|
||||
Map<String, Object> supplementalData = tsd.getSupplementalData();
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
throw new RuntimeException(
|
||||
"ShortViewService.renderShortView() not implemented.");
|
||||
try {
|
||||
Map<String, Object> fullModelMap = new HashMap<String, Object>(
|
||||
modelMap);
|
||||
fullModelMap.putAll(supplementalData);
|
||||
|
||||
FreemarkerProcessingService fps = FreemarkerProcessingServiceSetup
|
||||
.getService(vreq.getSession().getServletContext());
|
||||
|
||||
if (!fps.isTemplateAvailable(templateName, vreq)) {
|
||||
return "<p>Can't locate short view template '" + templateName
|
||||
+ "' for " + individual.getName() + "</p>";
|
||||
}
|
||||
|
||||
return fps.renderTemplate(templateName, fullModelMap, vreq);
|
||||
} catch (TemplateParsingException e) {
|
||||
return "<p>Can't parse the short view template '" + templateName
|
||||
+ "' for " + individual.getName() + "</p>";
|
||||
} catch (Exception e) {
|
||||
log.error(e, e);
|
||||
return "<p>Failed to render the short view for "
|
||||
+ individual.getName() + "</p>";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateAndSupplementalData getShortViewInfo(Individual individual,
|
||||
ShortViewContext svContext, VitroRequest vreq) {
|
||||
TemplateAndDataGetters tdg = fetchTemplateAndDataGetters(individual,
|
||||
svContext);
|
||||
svContext, vreq);
|
||||
Map<String, Object> gotData = runDataGetters(tdg.getDataGetters(), vreq);
|
||||
return new TemplateAndSupplementalDataImpl(tdg.getTemplateName(),
|
||||
gotData);
|
||||
|
@ -68,18 +98,19 @@ public class ShortViewServiceImpl implements ShortViewService {
|
|||
|
||||
/** Find the template and data getters for this individual in this context. */
|
||||
private TemplateAndDataGetters fetchTemplateAndDataGetters(
|
||||
Individual individual, ShortViewContext svContext) {
|
||||
Individual individual, ShortViewContext svContext, VitroRequest vreq) {
|
||||
List<String> classUris = new ArrayList<String>();
|
||||
classUris.addAll(figureMostSpecificClassUris(individual));
|
||||
|
||||
for (String classUri : classUris) {
|
||||
TemplateAndDataGetters tdg = faker.getShortViewProperties(classUri,
|
||||
TemplateAndDataGetters tdg = faker.getShortViewProperties(
|
||||
vreq.getWebappDaoFactory(), individual, classUri,
|
||||
svContext.name());
|
||||
if (tdg != null) {
|
||||
return tdg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Didn't find one? Use the default values.
|
||||
return new TemplateAndDataGetters(svContext.getDefaultTemplateName());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue