diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/GetRenderedSolrIndividualsByVClass.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/GetRenderedSolrIndividualsByVClass.java new file mode 100644 index 000000000..5e693ee5e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/GetRenderedSolrIndividualsByVClass.java @@ -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 modelMap = new HashMap(); + modelMap.put("individual", + new IndividualTemplateModel(individual, vreq)); + modelMap.put("vclass", vclassName); + + ShortViewService svs = ShortViewServiceSetup.getService(ctx); + return svs.renderShortView(individual, ShortViewContext.BROWSE, + modelMap, vreq); + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java index 58b61de2d..be3c2eb01 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java @@ -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); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingService.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingService.java new file mode 100644 index 000000000..88abf65cf --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingService.java @@ -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 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); + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java new file mode 100644 index 000000000..dfcc0156b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java @@ -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 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 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); + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceSetup.java new file mode 100644 index 000000000..c3b6e5e1b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceSetup.java @@ -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(); + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewService.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewService.java index d0cd0d9b1..7a494c375 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewService.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewService.java @@ -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; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java index 7fd3038fe..822577cd7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java @@ -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 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 supplementalData = tsd.getSupplementalData(); - // TODO Auto-generated method stub - throw new RuntimeException( - "ShortViewService.renderShortView() not implemented."); + try { + Map fullModelMap = new HashMap( + modelMap); + fullModelMap.putAll(supplementalData); + + FreemarkerProcessingService fps = FreemarkerProcessingServiceSetup + .getService(vreq.getSession().getServletContext()); + + if (!fps.isTemplateAvailable(templateName, vreq)) { + return "

Can't locate short view template '" + templateName + + "' for " + individual.getName() + "

"; + } + + return fps.renderTemplate(templateName, fullModelMap, vreq); + } catch (TemplateParsingException e) { + return "

Can't parse the short view template '" + templateName + + "' for " + individual.getName() + "

"; + } catch (Exception e) { + log.error(e, e); + return "

Failed to render the short view for " + + individual.getName() + "

"; + } } @Override public TemplateAndSupplementalData getShortViewInfo(Individual individual, ShortViewContext svContext, VitroRequest vreq) { TemplateAndDataGetters tdg = fetchTemplateAndDataGetters(individual, - svContext); + svContext, vreq); Map 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 classUris = new ArrayList(); 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()); }