to build Vitro and deploy to Tomcat's webapps directory.
+
+ The build script may run for as much as five minutes,
+ and creates more than 100 lines of output.
+ The process comprises several steps:
+
+
collecting the source files from the distribution directory,
+
compiling the Java source code,
+
compiling and running unit tests,
+
preparing the Solr search engine,
+
deploying Vitro and Solr to Tomcat.
+
+
+
+ The output of the build may include a variety of warning messages.
+ The Java compiler may warn of code that is outdated.
+ Unit tests may produce warning messages,
+ and some tests may be ignored if they do not produce consistent results.
+
+
+ BUILD SUCCESSFUL Total time: 1 minute 49 seconds
+
+
+ If the output ends with a success message, the build was successful.
+ Proceed to the next step.
+
+
+ BUILD FAILED Total time: 35 seconds
+
+
+ If the output ends with a failure message, the build has failed.
+ Find the cause of the failure, fix the problem, and run the script again.
+
+
VII. Configure Tomcat
Set JVM parameters
diff --git a/webapp/build.xml b/webapp/build.xml
index e168a2dda..3f3f89a40 100644
--- a/webapp/build.xml
+++ b/webapp/build.xml
@@ -188,13 +188,6 @@
-
-
-
-
-
-
-
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java
index f3e9b2618..80b32b478 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java
@@ -74,6 +74,15 @@ public class SimplePermission extends Permission {
"SeeVerbosePropertyInformation");
public static final SimplePermission USE_ADVANCED_DATA_TOOLS_PAGES = new SimplePermission(
"UseAdvancedDataToolsPages");
+ public static final SimplePermission USE_SPARQL_QUERY_PAGE = new SimplePermission(
+ "UseSparqlQueryPage");
+
+ // ----------------------------------------------------------------------
+ // These instances are "catch all" permissions to cover poorly defined
+ // groups of actions until better definitions were found. Don't add usages
+ // of these, and remove existing usages where possible.
+ // ----------------------------------------------------------------------
+
public static final SimplePermission USE_BASIC_AJAX_CONTROLLERS = new SimplePermission(
"UseBasicAjaxControllers");
public static final SimplePermission USE_MISCELLANEOUS_ADMIN_PAGES = new SimplePermission(
@@ -84,8 +93,6 @@ public class SimplePermission extends Permission {
"UseMiscellaneousEditorPages");
public static final SimplePermission USE_MISCELLANEOUS_PAGES = new SimplePermission(
"UseMiscellaneousPages");
- public static final SimplePermission USE_SPARQL_QUERY_PAGE = new SimplePermission(
- "UseSparqlQueryPage");
public static List getAllInstances() {
return new ArrayList(allInstances.values());
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java
index 955a8e2a8..ab848e895 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java
@@ -17,7 +17,7 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader;
+import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration;
import freemarker.template.Configuration;
import freemarker.template.Template;
@@ -73,8 +73,8 @@ public abstract class VitroAjaxController extends HttpServlet {
* Process data through a Freemarker template and output the result.
*/
protected void writeTemplate(String templateName, Map map,
- VitroRequest vreq, HttpServletResponse response) {
- Configuration config = FreemarkerConfigurationLoader.getConfig(vreq);
+ HttpServletRequest req, HttpServletResponse response) {
+ Configuration config = FreemarkerConfiguration.getConfig(req);
try {
Template template = config.getTemplate(templateName);
PrintWriter out = response.getWriter();
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java
index d71dd7366..e01b14cd9 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java
@@ -61,6 +61,8 @@ public class FreemarkerComponentGenerator extends FreemarkerHttpServlet {
return get(templateName, root, request);
}
+ // JB Because this is pretending to be a servlet, but the init method has not been called, providing the context.
+ // Do that in the constructor, and we should be fine. VIVO-251
// RY We need the servlet context in getConfig(). For some reason using the method inherited from
// GenericServlet bombs.
@Override
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java
deleted file mode 100644
index c6bc10185..000000000
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/* $This file is distributed under the terms of the license in /doc/license.txt$ */
-
-package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
-import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
-import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
-import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
-import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants;
-import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel;
-import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
-import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils;
-import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective;
-import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod;
-import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod;
-import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualProfileUrlMethod;
-import freemarker.cache.ClassTemplateLoader;
-import freemarker.cache.FileTemplateLoader;
-import freemarker.cache.MultiTemplateLoader;
-import freemarker.cache.TemplateLoader;
-import freemarker.core.Environment;
-import freemarker.ext.beans.BeansWrapper;
-import freemarker.template.Configuration;
-import freemarker.template.DefaultObjectWrapper;
-import freemarker.template.ObjectWrapper;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateModelException;
-import freemarker.template.utility.DeepUnwrap;
-
-public class FreemarkerConfiguration extends Configuration {
-
- private static final Log log = LogFactory.getLog(FreemarkerConfiguration.class);
-
- private static final String PROPERTY_DEVELOPER_DEFEAT_CACHE = "developer.defeatFreemarkerCache";
- private static final String PROPERTY_DEVELOPER_INSERT_DELIMITERS = "developer.insertFreemarkerDelimiters";
-
- private final String themeDir;
- private final ServletContext context;
- private final ApplicationBean appBean;
- private final ConfigurationProperties props;
-
- FreemarkerConfiguration(String themeDir, ApplicationBean appBean, ServletContext context) {
-
- this.themeDir = themeDir;
- this.context = context;
- this.appBean = appBean;
- this.props = ConfigurationProperties.getBean(context);
-
- String flag = props.getProperty(PROPERTY_DEVELOPER_DEFEAT_CACHE, "false");
- if (Boolean.valueOf(flag.trim())) {
- log.debug("Disabling Freemarker template caching in development build.");
- setTemplateUpdateDelay(0); // no template caching in development
- } else {
- int delay = 60;
- log.debug("Setting Freemarker template cache update delay to " + delay + ".");
- setTemplateUpdateDelay(delay); // in seconds; Freemarker default is 5
- }
-
- // Specify how templates will see the data model.
- // The Freemarker default wrapper exposes set methods and get methods that take
- // arguments. We block exposure to these methods by default.
- BeansWrapper wrapper = new DefaultObjectWrapper();
- wrapper.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY);
- setObjectWrapper(wrapper);
-
- // Set some formatting defaults. These can be overridden at the template
- // or environment (template-processing) level, or for an individual
- // token by using built-ins.
- setLocale(java.util.Locale.US);
-
- String dateFormat = "M/d/yyyy";
- setDateFormat(dateFormat);
- String timeFormat = "h:mm a";
- setTimeFormat(timeFormat);
- setDateTimeFormat(dateFormat + " " + timeFormat);
-
- //config.setNumberFormat("#,##0.##");
-
- try {
- setSetting("url_escaping_charset", "ISO-8859-1");
- } catch (TemplateException e) {
- log.error("Error setting value for url_escaping_charset.");
- }
-
- setTemplateLoader(createTemplateLoader());
-
- setSharedVariables();
-
- }
-
- /**
- * These are values that are accessible to all
- * templates loaded by the Configuration's TemplateLoader. They
- * should be application- rather than request-specific.
- */
- private void setSharedVariables() {
-
- Map sharedVariables = new HashMap();
-
- sharedVariables.put("siteName", appBean.getApplicationName());
- sharedVariables.put("version", getRevisionInfo());
- sharedVariables.put("urls", getSiteUrls());
- sharedVariables.put("themeDir", themeDir);
- sharedVariables.put("currentTheme", themeDir.substring(themeDir.lastIndexOf('/')+1));
-
- sharedVariables.putAll(getDirectives());
- sharedVariables.putAll(getMethods());
- sharedVariables.put("siteTagline", appBean.getShortHand());
-
- //Put in edit configuration constants - useful for freemarker templates/editing
- sharedVariables.put("editConfigurationConstants", EditConfigurationConstants.exportConstants());
-
- for ( Map.Entry variable : sharedVariables.entrySet() ) {
- try {
- setSharedVariable(variable.getKey(), variable.getValue());
- } catch (TemplateModelException e) {
- log.error("Could not set shared variable '" + variable.getKey() + "' in Freemarker configuration");
- }
- }
- }
-
- private final Map getRevisionInfo() {
- Map map = new HashMap();
- map.put("label", RevisionInfoBean.getBean(context)
- .getReleaseLabel());
- map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo"));
- return map;
- }
-
- private final Map getSiteUrls() {
- Map urls = new HashMap();
-
- // Templates use this to construct urls.
- urls.put("base", context.getContextPath());
-
- urls.put("home", UrlBuilder.getHomeUrl());
- urls.put("about", UrlBuilder.getUrl(Route.ABOUT));
- urls.put("search", UrlBuilder.getUrl(Route.SEARCH));
- urls.put("termsOfUse", UrlBuilder.getUrl(Route.TERMS_OF_USE));
- urls.put("login", UrlBuilder.getLoginUrl());
- urls.put("logout", UrlBuilder.getLogoutUrl());
- urls.put("siteAdmin", UrlBuilder.getUrl(Route.SITE_ADMIN));
- urls.put("themeImages", UrlBuilder.getUrl(themeDir + "/images"));
- urls.put("images", UrlBuilder.getUrl("/images"));
- urls.put("theme", UrlBuilder.getUrl(themeDir));
- urls.put("index", UrlBuilder.getUrl("/browse"));
-
- return urls;
- }
-
- public static Map getDirectives() {
- Map map = new HashMap();
- map.put("dump", new freemarker.ext.dump.DumpDirective());
- map.put("dumpAll", new freemarker.ext.dump.DumpAllDirective());
- map.put("help", new freemarker.ext.dump.HelpDirective());
- map.put("shortView", new IndividualShortViewDirective());
- return map;
- }
-
- public static Map getMethods() {
- Map map = new HashMap();
- map.put("profileUrl", new IndividualProfileUrlMethod());
- map.put("localName", new IndividualLocalNameMethod());
- map.put("placeholderImageUrl", new IndividualPlaceholderImageUrlMethod());
- map.put("i18n", new I18nMethodModel());
- return map;
- }
-
- // Define template locations. Template loader will look first in the theme-specific
- // location, then in the vitro location.
- protected final TemplateLoader createTemplateLoader() {
-
- List loaders = new ArrayList();
- MultiTemplateLoader mtl = null;
- try {
- // Theme template loader
- String themeTemplatePath = context.getRealPath(themeDir) + "/templates";
- File themeTemplateDir = new File(themeTemplatePath);
- // Handle the case where there's no theme template directory gracefully
- if (themeTemplateDir.exists()) {
- FileTemplateLoader themeFtl = new FileTemplateLoader(themeTemplateDir);
- loaders.add(themeFtl);
- }
-
- // Vitro template loader
- String vitroTemplatePath = context.getRealPath("/templates/freemarker");
- loaders.add(new FlatteningTemplateLoader(new File(vitroTemplatePath)));
-
- loaders.add(new ClassTemplateLoader(getClass(), ""));
-
- TemplateLoader[] loaderArray = loaders.toArray(new TemplateLoader[loaders.size()]);
- mtl = new MultiTemplateLoader(loaderArray);
-
- } catch (IOException e) {
- log.error("Error creating template loaders");
- }
-
- // Add the ability to add delimiters to the templates, based on
- // settings.
- if (Boolean.valueOf(props.getProperty(PROPERTY_DEVELOPER_INSERT_DELIMITERS))) {
- return new DelimitingTemplateLoader(mtl);
- } else {
- return mtl;
- }
- }
-
- /**
- * Override getTemplate(), so we can apply DataGetters to all included
- * templates.
- *
- * This won't work for top-level Templates, since the Environment hasn't
- * been created yet. When TemplateProcessingHelper creates the Environment,
- * it must call retrieveAndRunDataGetters() for the top-level Template.
- */
- @Override
- public Template getTemplate(String name, Locale locale, String encoding,
- boolean parse) throws IOException {
- Template template = super.getTemplate(name, locale, encoding, parse);
-
- if (template == null) {
- log.debug("Template '" + name + "' not found for locale '" + locale + "'.");
- return template;
- }
-
- Environment env = getEnvironment();
- if (env == null) {
- log.debug("Not fetching data getters for template '" + template.getName() + "'. No environment.");
- return template;
- }
-
- retrieveAndRunDataGetters(env, template.getName());
- return template;
- }
-
-
- /**
- * Find the DataGetters for this template, and apply them to the Freemarker
- * environment.
- */
- public static void retrieveAndRunDataGetters(Environment env, String templateName) {
- HttpServletRequest req = (HttpServletRequest) env.getCustomAttribute("request");
- VitroRequest vreq = new VitroRequest(req);
-
- if (dataGettersAlreadyApplied(env, templateName)) {
- log.debug("DataGetters for '" + templateName+"' have already been applied");
- return;
- }
-
- try {
- List dgList = DataGetterUtils.getDataGettersForTemplate(
- vreq, vreq.getDisplayModel(), templateName);
- log.debug("Retrieved " + dgList.size() + " data getters for template '" + templateName + "'");
-
- @SuppressWarnings("unchecked")
- Map dataMap = (Map) DeepUnwrap.permissiveUnwrap(env.getDataModel());
- for (DataGetter dg : dgList) {
- applyDataGetter(dg, env, dataMap);
- }
- } catch (Exception e) {
- log.warn(e, e);
- }
- }
-
- /**
- * Have the DataGetters for this template already been applied to this environment?
- * If not, record that they are being applied now.
- */
- @SuppressWarnings("unchecked")
- private static boolean dataGettersAlreadyApplied(Environment env, String templateName) {
- Set names;
- Object o = env.getCustomAttribute("dataGettersApplied");
- if (o instanceof Set) {
- names = (Set) o;
- } else {
- names = new HashSet();
- }
-
- boolean added = names.add(templateName);
- if (added) {
- env.setCustomAttribute("dataGettersApplied", names);
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Get the data from a DataGetter, and store it in global variables in the
- * Freemarker environment.
- */
- private static void applyDataGetter(DataGetter dg, Environment env,
- Map dataMap) throws TemplateModelException {
- Map moreData = dg.getData(dataMap);
- ObjectWrapper wrapper = env.getObjectWrapper();
- if (moreData != null) {
- for (String key : moreData.keySet()) {
- Object value = moreData.get(key);
- env.setGlobalVariable(key, wrapper.wrap(value));
- log.debug("Stored in environment: '" + key + "' = '" + value + "'");
- }
- }
- }
-
-}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java
deleted file mode 100644
index b4e206181..000000000
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/* $This file is distributed under the terms of the license in /doc/license.txt$ */
-
-package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.ServletContext;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
-import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-
-public class FreemarkerConfigurationLoader {
- private static final Log log = LogFactory
- .getLog(FreemarkerConfigurationLoader.class);
-
- private static final Map themeToConfigMap = new HashMap();
-
- public static FreemarkerConfiguration getConfig(VitroRequest vreq) {
- String themeDir = getThemeDir(vreq.getAppBean());
- return getConfigForTheme(themeDir, vreq.getAppBean(), vreq.getSession().getServletContext());
- }
-
- private static String getThemeDir(ApplicationBean appBean) {
- if (appBean == null) {
- log.error("Cannot get themeDir from null application bean");
- return null;
- }
-
- String themeDir = appBean.getThemeDir();
- if (themeDir == null) {
- log.error("themeDir is null");
- return null;
- }
-
- return themeDir.replaceAll("/$", "");
- }
-
- /**
- * The Configuration is theme-specific because:
- *
- * 1. The template loader is theme-specific, since it specifies a theme
- * directory to load templates from.
- *
- * 2. Some shared variables are theme-specific.
- */
- private static FreemarkerConfiguration getConfigForTheme(String themeDir,
- ApplicationBean appBean, ServletContext context) {
- synchronized (themeToConfigMap) {
- if (themeToConfigMap.containsKey(themeDir)) {
- return themeToConfigMap.get(themeDir);
- } else {
- FreemarkerConfiguration config = new FreemarkerConfiguration(
- themeDir, appBean, context);
- themeToConfigMap.put(themeDir, config);
- return config;
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java
index 552846a98..135cf29b2 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java
@@ -37,10 +37,12 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Res
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
+import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.User;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.MainMenu;
import freemarker.ext.beans.BeansWrapper;
+import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
@@ -336,7 +338,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
private Map buildRequestUrls(VitroRequest vreq) {
Map requestUrls = new HashMap();
- FreemarkerConfiguration config = FreemarkerConfigurationLoader.getConfig(vreq);
+ Configuration config = FreemarkerConfiguration.getConfig(vreq);
TemplateModel urlModel = config.getSharedVariable("urls");
try {
@@ -427,10 +429,6 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
// the copyright text can be viewed with having to restart Tomcat
map.put("copyright", getCopyrightInfo(appBean));
- map.put("url", new edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective());
- map.put("widget", new edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective());
- map.putAll( FreemarkerConfiguration.getDirectives() );
-
// Add these accumulator objects. They will collect tags so the template can write them
// at the appropriate location.
map.put("stylesheets", new Tags().wrap());
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java
index c1fd229f3..08b89c33c 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java
@@ -13,7 +13,8 @@ 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.freemarker.config.FreemarkerConfiguration;
+import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfigurationImpl;
import freemarker.core.Environment;
import freemarker.template.Configuration;
import freemarker.template.Template;
@@ -24,13 +25,9 @@ public class TemplateProcessingHelper {
private static final Log log = LogFactory.getLog(TemplateProcessingHelper.class);
private Configuration config = null;
- private HttpServletRequest request = null;
- private ServletContext context = null;
public TemplateProcessingHelper(HttpServletRequest request, ServletContext context) {
- this.config = FreemarkerConfigurationLoader.getConfig(new VitroRequest(request));
- this.request = request;
- this.context = context;
+ this.config = FreemarkerConfiguration.getConfig(request);
}
public StringWriter processTemplate(String templateName, Map map)
@@ -46,14 +43,6 @@ public class TemplateProcessingHelper {
try {
Environment env = template.createProcessingEnvironment(map, writer);
- // Add request and servlet context as custom attributes of the environment, so they
- // can be used in directives.
- env.setCustomAttribute("request", request);
- env.setCustomAttribute("context", context);
-
- // Set the Locale from the request into the environment, so date builtins will be
- // Locale-dependent
- env.setLocale(request.getLocale());
// Define a setup template to be included by every page template
String templateType = (String) map.get("templateType");
@@ -62,7 +51,8 @@ public class TemplateProcessingHelper {
}
// Apply any data-getters that are associated with this template.
- FreemarkerConfiguration.retrieveAndRunDataGetters(env, template.getName());
+ // TODO clean this up VIVO-249
+ FreemarkerConfigurationImpl.retrieveAndRunDataGetters(env, template.getName());
// Now process it.
env.process();
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/GetDataForPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/GetDataForPage.java
deleted file mode 100644
index 632a0a611..000000000
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/GetDataForPage.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* $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.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.json.JSONObject;
-
-import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter.PageDataGetterUtils;
-
-/**
- * Gets data based on data getter for page uri and returns in the form of Json objects
- */
-public class GetDataForPage extends JsonObjectProducer {
- private static final Log log = LogFactory.getLog(GetDataForPage.class);
-
- protected GetDataForPage(VitroRequest vreq) {
- super(vreq);
- }
-
- @Override
- protected JSONObject process() throws Exception {
- JSONObject rObj = null;
- String pageUri = vreq.getParameter("pageUri");
- if(pageUri != null && !pageUri.isEmpty()) {
- Map data = PageDataGetterUtils.getDataForPage(pageUri, vreq, ctx);
- //Convert to json version based on type of page
- if(data != null) {
- //Convert to json version based on type of page
- rObj = PageDataGetterUtils.covertDataToJSONForPage(pageUri, data, vreq, ctx);
- }
- }
- return rObj;
- }
-
-}
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 2fbd9d09f..3f516e109 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
@@ -3,8 +3,11 @@
package edu.cornell.mannlib.vitro.webapp.controller.json;
import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Enumeration;
import java.util.List;
import java.util.Map;
@@ -15,17 +18,21 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.json.JSONArray;
import org.json.JSONObject;
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
+import edu.cornell.mannlib.vitro.webapp.beans.VClass;
+import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils;
-import edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter.PageDataGetterUtils;
/**
* This servlet is for servicing requests for JSON objects/data.
@@ -69,7 +76,9 @@ public class JsonServlet extends VitroHttpServlet {
log.debug("AJAX request to retrieve individuals by vclasses");
new GetSolrIndividualsByVClasses(vreq).process(resp);
} else if( vreq.getParameter("getDataForPage") != null ){
- new GetDataForPage(vreq).process(resp);
+ throw new IllegalArgumentException("The call invoked deprecated classes " +
+ "and the parameter for this call appeared nowhere in the code base, " +
+ "so it was removed in Aug 5th 2013.");
}else if( vreq.getParameter("getRenderedSolrIndividualsByVClass") != null ){
new GetRenderedSolrIndividualsByVClass(vreq).process(resp);
}else if( vreq.getParameter("getRandomSolrIndividualsByVClass") != null ){
@@ -85,7 +94,7 @@ public class JsonServlet extends VitroHttpServlet {
Map map = getSolrVClassIntersectionResults(vclassURIs, vreq, context);
//last parameter indicates single vclass instead of multiple vclasses
- return processVClassResults(map, vreq, context, false);
+ return processVclassResultsJSON(map, vreq, false);
}
public static JSONObject getSolrIndividualsByVClasses(List vclassURIs, HttpServletRequest req, ServletContext context) throws Exception {
@@ -93,8 +102,8 @@ public class JsonServlet extends VitroHttpServlet {
log.debug("Retrieve solr results for vclasses" + vclassURIs.toString());
Map map = getSolrVClassIntersectionResults(vclassURIs, vreq, context);
log.debug("Results returned from Solr for " + vclassURIs.toString() + " are of size " + map.size());
- JSONObject rObj = processVClassResults(map, vreq, context, true);
- return rObj;
+
+ return processVclassResultsJSON(map, vreq, true);
}
//Including version for Solr query for Vclass Intersections
@@ -119,10 +128,10 @@ public class JsonServlet extends VitroHttpServlet {
}
// Map given to process method includes the actual individuals returned from the search
- public static JSONObject processVClassResults(Map map, VitroRequest vreq, ServletContext context, boolean multipleVclasses) throws Exception{
- JSONObject rObj = PageDataGetterUtils.processVclassResultsJSON(map, vreq, multipleVclasses);
- return rObj;
- }
+// public static JSONObject processVClassResults(Map map, VitroRequest vreq, ServletContext context, boolean multipleVclasses) throws Exception{
+// JSONObject rObj = processVclassResultsJSON(map, vreq, multipleVclasses);
+// return rObj;
+// }
public static Collection getMostSpecificTypes(Individual individual, WebappDaoFactory wdf) {
ObjectPropertyStatementDao opsDao = wdf.getObjectPropertyStatementDao();
@@ -143,7 +152,7 @@ public class JsonServlet extends VitroHttpServlet {
Map map = getRandomSolrVClassResults(vclassURI, vreq, context);
//last parameter indicates single vclass instead of multiple vclasses
- return processVClassResults(map, vreq, context, false);
+ return processVclassResultsJSON(map, vreq, false);
}
//Including version for Random Solr query for Vclass Intersections
@@ -169,4 +178,120 @@ public class JsonServlet extends VitroHttpServlet {
}
+ /**
+ * Process results related to VClass or vclasses. Handles both single and multiple vclasses being sent.
+ */
+ public static JSONObject processVclassResultsJSON(Map map, VitroRequest vreq, boolean multipleVclasses) {
+ JSONObject rObj = new JSONObject();
+ VClass vclass=null;
+
+ try {
+
+ // Properties from ontologies used by VIVO - should not be in vitro
+ DataProperty fNameDp = (new DataProperty());
+ fNameDp.setURI("http://xmlns.com/foaf/0.1/firstName");
+ DataProperty lNameDp = (new DataProperty());
+ lNameDp.setURI("http://xmlns.com/foaf/0.1/lastName");
+ DataProperty preferredTitleDp = (new DataProperty());
+ preferredTitleDp.setURI("http://vivoweb.org/ontology/core#preferredTitle");
+
+ if( log.isDebugEnabled() ){
+ @SuppressWarnings("unchecked")
+ Enumeration e = vreq.getParameterNames();
+ while(e.hasMoreElements()){
+ String name = e.nextElement();
+ log.debug("parameter: " + name);
+ for( String value : vreq.getParameterValues(name) ){
+ log.debug("value for " + name + ": '" + value + "'");
+ }
+ }
+ }
+
+ //need an unfiltered dao to get firstnames and lastnames
+ WebappDaoFactory fullWdf = vreq.getUnfilteredWebappDaoFactory();
+
+ String[] vitroClassIdStr = vreq.getParameterValues("vclassId");
+ if ( vitroClassIdStr != null && vitroClassIdStr.length > 0){
+ for(String vclassId: vitroClassIdStr) {
+ vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassId);
+ if (vclass == null) {
+ log.error("Couldn't retrieve vclass ");
+ throw new Exception ("Class " + vclassId + " not found");
+ }
+ }
+ }else{
+ log.error("parameter vclassId URI parameter expected ");
+ throw new Exception("parameter vclassId URI parameter expected ");
+ }
+ List vclassIds = Arrays.asList(vitroClassIdStr);
+ //if single vclass expected, then include vclass. This relates to what the expected behavior is, not size of list
+ if(!multipleVclasses) {
+ //currently used for ClassGroupPage
+ rObj.put("vclass",
+ new JSONObject().put("URI",vclass.getURI())
+ .put("name",vclass.getName()));
+ } else {
+ //For now, utilize very last VClass (assume that that is the one to be employed)
+ //TODO: Find more general way of dealing with this
+ //put multiple ones in?
+ if(vclassIds.size() > 0) {
+ int numberVClasses = vclassIds.size();
+ vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassIds.get(numberVClasses - 1));
+ rObj.put("vclass", new JSONObject().put("URI",vclass.getURI())
+ .put("name",vclass.getName()));
+ }
+ // rObj.put("vclasses", new JSONObject().put("URIs",vitroClassIdStr)
+ // .put("name",vclass.getName()));
+ }
+ if (vclass != null) {
+
+ rObj.put("totalCount", map.get("totalCount"));
+ rObj.put("alpha", map.get("alpha"));
+
+ List inds = (List)map.get("entities");
+ log.debug("Number of individuals returned from request: " + inds.size());
+ JSONArray jInds = new JSONArray();
+ for(Individual ind : inds ){
+ JSONObject jo = new JSONObject();
+ jo.put("URI", ind.getURI());
+ jo.put("label",ind.getRdfsLabel());
+ jo.put("name",ind.getName());
+ jo.put("thumbUrl", ind.getThumbUrl());
+ jo.put("imageUrl", ind.getImageUrl());
+ jo.put("profileUrl", UrlBuilder.getIndividualProfileUrl(ind, vreq));
+
+ jo.put("mostSpecificTypes", JsonServlet.getMostSpecificTypes(ind,fullWdf));
+ jo.put("preferredTitle", JsonServlet.getDataPropertyValue(ind, preferredTitleDp, fullWdf));
+
+ jInds.put(jo);
+ }
+ rObj.put("individuals", jInds);
+
+ JSONArray wpages = new JSONArray();
+ //Made sure that PageRecord here is SolrIndividualListController not IndividualListController
+ List pages = (List)map.get("pages");
+ for( PageRecord pr: pages ){
+ JSONObject p = new JSONObject();
+ p.put("text", pr.text);
+ p.put("param", pr.param);
+ p.put("index", pr.index);
+ wpages.put( p );
+ }
+ rObj.put("pages",wpages);
+
+ JSONArray jletters = new JSONArray();
+ List letters = Controllers.getLetters();
+ for( String s : letters){
+ JSONObject jo = new JSONObject();
+ jo.put("text", s);
+ jo.put("param", "alpha=" + URLEncoder.encode(s, "UTF-8"));
+ jletters.put( jo );
+ }
+ rObj.put("letters", jletters);
+ }
+ } catch(Exception ex) {
+ log.error("Error occurred in processing JSON object", ex);
+ }
+ return rObj;
+ }
}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java
index 5068e2b1b..a214814f7 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java
@@ -23,11 +23,11 @@ import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader;
import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo;
+import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration;
import freemarker.template.Configuration;
public class EditConfigurationUtils {
@@ -272,7 +272,7 @@ public class EditConfigurationUtils {
//Generate HTML for a specific field name given
public static String generateHTMLForElement(VitroRequest vreq, String fieldName, EditConfigurationVTwo editConfig) {
String html = "";
- Configuration fmConfig = FreemarkerConfigurationLoader.getConfig(vreq);
+ Configuration fmConfig = FreemarkerConfiguration.getConfig(vreq);
FieldVTwo field = editConfig == null ? null : editConfig.getField(fieldName);
MultiValueEditSubmission editSub = EditSubmissionUtils.getEditSubmissionFromSession(vreq.getSession(), editConfig);
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java
index 84f0c1fcd..3f9d3d852 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java
@@ -25,9 +25,9 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
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.freemarker.config.FreemarkerConfiguration;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
+import freemarker.template.Configuration;
/**
* A factory that creates Freemarker-based email messages.
@@ -59,8 +59,7 @@ public class FreemarkerEmailFactory {
}
FreemarkerEmailFactory factory = getFactory(vreq);
- FreemarkerConfiguration fConfig = FreemarkerConfigurationLoader
- .getConfig(vreq);
+ Configuration fConfig = FreemarkerConfiguration.getConfig(vreq);
return new FreemarkerEmailMessage(vreq, fConfig,
factory.getEmailSession(), factory.getReplyToAddress());
}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java
index 0dd14a2f3..710242dd9 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java
@@ -28,10 +28,8 @@ 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.web.directives.EmailDirective;
-import freemarker.core.Environment;
-import freemarker.template.Template;
+import freemarker.template.Configuration;
import freemarker.template.TemplateException;
/**
@@ -51,7 +49,7 @@ public class FreemarkerEmailMessage {
private final VitroRequest vreq;
private final Session mailSession;
- private final FreemarkerConfiguration config;
+ private final Configuration config;
private final List recipients = new ArrayList();
private final InternetAddress replyToAddress;
@@ -66,7 +64,7 @@ public class FreemarkerEmailMessage {
/**
* Package access - should only be created by the factory.
*/
- FreemarkerEmailMessage(VitroRequest vreq, FreemarkerConfiguration fConfig,
+ FreemarkerEmailMessage(VitroRequest vreq, Configuration fConfig,
Session mailSession, InternetAddress replyToAddress) {
this.vreq = vreq;
this.mailSession = mailSession;
@@ -144,14 +142,8 @@ public class FreemarkerEmailMessage {
bodyMap.put("email", new EmailDirective(this));
try {
- Template template = config.getTemplate(templateName);
-
- Environment env = template.createProcessingEnvironment(bodyMap,
+ config.getTemplate(templateName).process(bodyMap,
new StringWriter());
- env.setCustomAttribute("request", vreq);
- env.setCustomAttribute("context", vreq.getSession()
- .getServletContext());
- env.process();
} catch (TemplateException e) {
log.error(e, e);
} catch (IOException e) {
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/StreamingMultipartHttpServletRequest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/StreamingMultipartHttpServletRequest.java
index 7b74a2041..e5e32c5c9 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/StreamingMultipartHttpServletRequest.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/StreamingMultipartHttpServletRequest.java
@@ -1,13 +1,9 @@
-package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest;
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
+package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest;
import javax.servlet.http.HttpServletRequest;
-import org.apache.commons.fileupload.FileItem;
-import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
@@ -26,8 +22,7 @@ public class StreamingMultipartHttpServletRequest extends
* to deal with inputs of very large sizes.
*
*/
- public StreamingMultipartHttpServletRequest(HttpServletRequest request)
- throws IOException{
+ public StreamingMultipartHttpServletRequest(HttpServletRequest request) {
super(request);
//use a file uploader that does not save the files to a temporary directory.
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java
new file mode 100644
index 000000000..fe7555d35
--- /dev/null
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java
@@ -0,0 +1,293 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vitro.webapp.freemarker.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
+import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
+import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.DelimitingTemplateLoader;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FlatteningTemplateLoader;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants;
+import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
+import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective;
+import edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective;
+import edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective;
+import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod;
+import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod;
+import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualProfileUrlMethod;
+import freemarker.cache.ClassTemplateLoader;
+import freemarker.cache.FileTemplateLoader;
+import freemarker.cache.MultiTemplateLoader;
+import freemarker.cache.TemplateLoader;
+import freemarker.ext.beans.BeansWrapper;
+import freemarker.template.Configuration;
+import freemarker.template.DefaultObjectWrapper;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModelException;
+
+/**
+ * Access point for a singleton Configuration instance.
+ *
+ * The instance is created at system startup, so we can fail early if there are
+ * any problems.
+ *
+ * The Configuration is slightly extended to hold request-based information in a
+ * ThreadLocal. The net result is although there is only one configuration (and
+ * hence only one template cache), each request gets a customization with its
+ * own locale, etc.
+ *
+ * Each time a request asks for the configuration, check to see whether the
+ * cache is still valid, and whether the theme has changed (needs a new
+ * TemplateLoader). Store the request info to the ThreadLocal.
+ */
+public abstract class FreemarkerConfiguration {
+ private static final Log log = LogFactory
+ .getLog(FreemarkerConfiguration.class);
+
+ private static final String PROPERTY_DEFEAT_CACHE = "developer.defeatFreemarkerCache";
+ private static final String PROPERTY_INSERT_DELIMITERS = "developer.insertFreemarkerDelimiters";
+
+ private static volatile FreemarkerConfigurationImpl instance;
+ private static volatile String previousThemeDir;
+
+ public static Configuration getConfig(HttpServletRequest req) {
+ confirmInstanceIsSet();
+
+ synchronized (instance) {
+ clearTemplateCacheIfRequested(req);
+ keepTemplateLoaderCurrentWithThemeDirectory(req);
+ setThreadLocalsForRequest(req);
+ return instance;
+ }
+ }
+
+ private static void confirmInstanceIsSet() {
+ if (instance == null) {
+ throw new IllegalStateException(
+ "VitroFreemarkerConfiguration has not been set.");
+ }
+ }
+
+ private static void clearTemplateCacheIfRequested(HttpServletRequest req) {
+ if (isTemplateCacheInvalid(req)) {
+ instance.clearTemplateCache();
+ }
+ }
+
+ private static boolean isTemplateCacheInvalid(HttpServletRequest req) {
+ ConfigurationProperties props = ConfigurationProperties.getBean(req);
+
+ // If the developer doesn't want the cache, it's invalid.
+ if (Boolean.valueOf(props.getProperty(PROPERTY_DEFEAT_CACHE))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Keep track of the theme directory. If it changes, create an appropriate
+ * new TemplateLoader.
+ *
+ * Note that setting a new TemplateLoader on the context Configuration also
+ * creates a new, empty TemplateCache.
+ */
+ private static void keepTemplateLoaderCurrentWithThemeDirectory(
+ HttpServletRequest req) {
+ String themeDir = getThemeDirectory(req);
+ if (hasThemeDirectoryChanged(themeDir)) {
+ TemplateLoader tl = createTemplateLoader(req, themeDir);
+ instance.setTemplateLoader(tl);
+ }
+ }
+
+ private static String getThemeDirectory(HttpServletRequest req) {
+ return new VitroRequest(req).getAppBean().getThemeDir();
+ }
+
+ private static boolean hasThemeDirectoryChanged(String themeDir) {
+ synchronized (instance) {
+ if (StringUtils.equals(themeDir, previousThemeDir)) {
+ return false;
+ } else {
+ previousThemeDir = themeDir;
+ return true;
+ }
+ }
+ }
+
+ private static TemplateLoader createTemplateLoader(HttpServletRequest req,
+ String themeDir) {
+ ServletContext ctx = req.getSession().getServletContext();
+ ConfigurationProperties props = ConfigurationProperties.getBean(ctx);
+
+ List loaders = new ArrayList();
+
+ // Theme template loader
+ String themeTemplatePath = ctx.getRealPath(themeDir) + "/templates";
+ File themeTemplateDir = new File(themeTemplatePath);
+ // A theme need not contain a template directory.
+ if (themeTemplateDir.exists()) {
+ try {
+ FileTemplateLoader themeFtl = new FileTemplateLoader(
+ themeTemplateDir);
+ loaders.add(themeFtl);
+ } catch (IOException e) {
+ log.error("Error creating theme template loader", e);
+ }
+ }
+
+ // Vitro template loader
+ String vitroTemplatePath = ctx.getRealPath("/templates/freemarker");
+ loaders.add(new FlatteningTemplateLoader(new File(vitroTemplatePath)));
+
+ // TODO VIVO-243 Why is this here?
+ loaders.add(new ClassTemplateLoader(FreemarkerConfiguration.class, ""));
+
+ TemplateLoader[] loaderArray = loaders
+ .toArray(new TemplateLoader[loaders.size()]);
+ MultiTemplateLoader mtl = new MultiTemplateLoader(loaderArray);
+
+ // If requested, add delimiters to the templates.
+ if (Boolean.valueOf(props.getProperty(PROPERTY_INSERT_DELIMITERS))) {
+ return new DelimitingTemplateLoader(mtl);
+ } else {
+ return mtl;
+ }
+ }
+
+ private static void setThreadLocalsForRequest(HttpServletRequest req) {
+ instance.setRequestInfo(req);
+ }
+
+ // ----------------------------------------------------------------------
+ // Setup class
+ // ----------------------------------------------------------------------
+
+ public static class Setup implements ServletContextListener {
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ ServletContext ctx = sce.getServletContext();
+ StartupStatus ss = StartupStatus.getBean(ctx);
+ try {
+ instance = createConfiguration(ctx);
+ ss.info(this, "Initialized the Freemarker configuration.");
+ } catch (Exception e) {
+ ss.fatal(this,
+ "Failed to initialize the Freemarker configuration.", e);
+ }
+ }
+
+ private FreemarkerConfigurationImpl createConfiguration(
+ ServletContext ctx) throws TemplateModelException {
+ FreemarkerConfigurationImpl c = new FreemarkerConfigurationImpl();
+
+ setMiscellaneousProperties(c);
+ setSharedVariables(c, ctx);
+ addDirectives(c);
+ addMethods(c);
+
+ return c;
+ }
+
+ private void setMiscellaneousProperties(FreemarkerConfigurationImpl c) {
+ /*
+ * Lengthen the cache time.
+ */
+ c.setTemplateUpdateDelay(60); // increase from the 5-second default
+
+ /*
+ * On most template models, hide the getters and setters that take
+ * arguments.
+ */
+ BeansWrapper wrapper = new DefaultObjectWrapper();
+ wrapper.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY);
+ c.setObjectWrapper(wrapper);
+
+ /*
+ * Set a default Locale, but expect it to be overridden by the
+ * request.
+ */
+ c.setLocale(java.util.Locale.US);
+
+ /*
+ * This is how we like our date and time strings to look.
+ */
+ String dateFormat = "M/d/yyyy";
+ c.setDateFormat(dateFormat);
+ String timeFormat = "h:mm a";
+ c.setTimeFormat(timeFormat);
+ c.setDateTimeFormat(dateFormat + " " + timeFormat);
+
+ /*
+ * What character set is used when escaping special characters in a
+ * URL?
+ */
+ try {
+ c.setSetting("url_escaping_charset", "ISO-8859-1");
+ } catch (TemplateException e) {
+ log.error("Error setting value for url_escaping_charset.");
+ }
+ }
+
+ private void setSharedVariables(FreemarkerConfigurationImpl c,
+ ServletContext ctx) throws TemplateModelException {
+ c.setSharedVariable("version", getRevisionInfo(ctx));
+
+ /*
+ * Put in edit configuration constants - useful for freemarker
+ * templates/editing
+ */
+ c.setSharedVariable("editConfigurationConstants",
+ EditConfigurationConstants.exportConstants());
+ }
+
+ private void addDirectives(FreemarkerConfigurationImpl c) {
+ c.setSharedVariable("dump", new freemarker.ext.dump.DumpDirective());
+ c.setSharedVariable("dumpAll",
+ new freemarker.ext.dump.DumpAllDirective());
+ c.setSharedVariable("help", new freemarker.ext.dump.HelpDirective());
+ c.setSharedVariable("shortView", new IndividualShortViewDirective());
+ c.setSharedVariable("url", new UrlDirective());
+ c.setSharedVariable("widget", new WidgetDirective());
+ }
+
+ private void addMethods(FreemarkerConfigurationImpl c) {
+ c.setSharedVariable("profileUrl", new IndividualProfileUrlMethod());
+ c.setSharedVariable("localName", new IndividualLocalNameMethod());
+ c.setSharedVariable("placeholderImageUrl",
+ new IndividualPlaceholderImageUrlMethod());
+ c.setSharedVariable("i18n", new I18nMethodModel());
+ }
+
+ private Map getRevisionInfo(ServletContext ctx) {
+ Map map = new HashMap();
+ map.put("label", RevisionInfoBean.getBean(ctx).getReleaseLabel());
+ map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo"));
+ return map;
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ instance = null;
+ }
+ }
+}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java
new file mode 100644
index 000000000..b4318c97f
--- /dev/null
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java
@@ -0,0 +1,309 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vitro.webapp.freemarker.config;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
+import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
+import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
+import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils;
+import freemarker.core.Environment;
+import freemarker.template.Configuration;
+import freemarker.template.ObjectWrapper;
+import freemarker.template.SimpleScalar;
+import freemarker.template.Template;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.utility.DeepUnwrap;
+
+/**
+ * Extend the Freemarker Configuration class to include some information that is
+ * particular to the current request.
+ *
+ * Takes advantage of the fact that each servlet request runs in a separate
+ * thread. Stores the request-based information in a ThreadLocal. Override any
+ * methods that should return that information instead of (or in addition to)
+ * the common info.
+ *
+ * Only the getters are overridden, not the setters. So if you call
+ * setAllSharedVariables(), for example, it will have no effect on the
+ * request-based information.
+ */
+public class FreemarkerConfigurationImpl extends Configuration {
+ private static final Log log = LogFactory
+ .getLog(FreemarkerConfigurationImpl.class);
+
+ private final ThreadLocal rbiRef = new ThreadLocal<>();
+
+ void setRequestInfo(HttpServletRequest req) {
+ rbiRef.set(new RequestBasedInformation(req, this));
+ }
+
+ @Override
+ public Object getCustomAttribute(String name) {
+ Map attribs = rbiRef.get().getCustomAttributes();
+ if (attribs.containsKey(name)) {
+ return attribs.get(name);
+ } else {
+ return super.getCustomAttribute(name);
+ }
+ }
+
+ @Override
+ public String[] getCustomAttributeNames() {
+ Set rbiNames = rbiRef.get().getCustomAttributes().keySet();
+ return joinNames(rbiNames, super.getCustomAttributeNames());
+ }
+
+ @Override
+ public TemplateModel getSharedVariable(String name) {
+ Map vars = rbiRef.get().getSharedVariables();
+ if (vars.containsKey(name)) {
+ return vars.get(name);
+ } else {
+ return super.getSharedVariable(name);
+ }
+ }
+
+ @Override
+ public Set getSharedVariableNames() {
+ Set rbiNames = rbiRef.get().getSharedVariables().keySet();
+
+ @SuppressWarnings("unchecked")
+ Set superNames = super.getSharedVariableNames();
+
+ Set allNames = new HashSet<>(superNames);
+ allNames.addAll(rbiNames);
+ return allNames;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return rbiRef.get().getReq().getLocale();
+ }
+
+ private String[] joinNames(Set nameSet, String[] nameArray) {
+ Set allNames = new HashSet<>(nameSet);
+ for (String n : nameArray) {
+ allNames.add(n);
+ }
+ return (String[]) allNames.toArray();
+ }
+
+ // ----------------------------------------------------------------------
+ // Apply DataGetters to templates when loading.
+ //
+ // TODO Clean this up VIVO-249
+ // ----------------------------------------------------------------------
+
+ /**
+ * Override getTemplate(), so we can apply DataGetters to all included
+ * templates.
+ *
+ * This won't work for top-level Templates, since the Environment hasn't
+ * been created yet. When TemplateProcessingHelper creates the Environment,
+ * it must call retrieveAndRunDataGetters() for the top-level Template.
+ */
+ @Override
+ public Template getTemplate(String name, Locale locale, String encoding,
+ boolean parse) throws IOException {
+ Template template = super.getTemplate(name, locale, encoding, parse);
+
+ if (template == null) {
+ log.debug("Template '" + name + "' not found for locale '" + locale
+ + "'.");
+ return template;
+ }
+
+ Environment env = getEnvironment();
+ if (env == null) {
+ log.debug("Not fetching data getters for template '"
+ + template.getName() + "'. No environment.");
+ return template;
+ }
+
+ retrieveAndRunDataGetters(env, template.getName());
+ return template;
+ }
+
+ /**
+ * Find the DataGetters for this template, and apply them to the Freemarker
+ * environment.
+ */
+ public static void retrieveAndRunDataGetters(Environment env,
+ String templateName) {
+ HttpServletRequest req = (HttpServletRequest) env
+ .getCustomAttribute("request");
+ VitroRequest vreq = new VitroRequest(req);
+
+ if (dataGettersAlreadyApplied(env, templateName)) {
+ log.debug("DataGetters for '" + templateName
+ + "' have already been applied");
+ return;
+ }
+
+ try {
+ List dgList = DataGetterUtils
+ .getDataGettersForTemplate(vreq, vreq.getDisplayModel(),
+ templateName);
+ log.debug("Retrieved " + dgList.size()
+ + " data getters for template '" + templateName + "'");
+
+ @SuppressWarnings("unchecked")
+ Map dataMap = (Map) DeepUnwrap
+ .permissiveUnwrap(env.getDataModel());
+ for (DataGetter dg : dgList) {
+ applyDataGetter(dg, env, dataMap);
+ }
+ } catch (Exception e) {
+ log.warn(e, e);
+ }
+ }
+
+ /**
+ * Have the DataGetters for this template already been applied to this
+ * environment? If not, record that they are being applied now.
+ */
+ @SuppressWarnings("unchecked")
+ private static boolean dataGettersAlreadyApplied(Environment env,
+ String templateName) {
+ Set names;
+ Object o = env.getCustomAttribute("dataGettersApplied");
+ if (o instanceof Set) {
+ names = (Set) o;
+ } else {
+ names = new HashSet();
+ }
+
+ boolean added = names.add(templateName);
+ if (added) {
+ env.setCustomAttribute("dataGettersApplied", names);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Get the data from a DataGetter, and store it in global variables in the
+ * Freemarker environment.
+ */
+ private static void applyDataGetter(DataGetter dg, Environment env,
+ Map dataMap) throws TemplateModelException {
+ Map moreData = dg.getData(dataMap);
+ ObjectWrapper wrapper = env.getObjectWrapper();
+ if (moreData != null) {
+ for (String key : moreData.keySet()) {
+ Object value = moreData.get(key);
+ env.setGlobalVariable(key, wrapper.wrap(value));
+ log.debug("Stored in environment: '" + key + "' = '" + value
+ + "'");
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Helper class
+ // ----------------------------------------------------------------------
+
+ /**
+ * Holds the request-based information. Currently, it's shared variables, a
+ * custom attribute, and the locale. In the future, it could be more.
+ */
+ private static class RequestBasedInformation {
+ private final HttpServletRequest req;
+ private final Configuration c;
+ private final Map customAttributes = new HashMap<>();
+ private final Map sharedVariables = new HashMap<>();
+
+ public RequestBasedInformation(HttpServletRequest req, Configuration c) {
+ this.req = req;
+ this.c = c;
+
+ setSharedVariables(req);
+ setCustomAttributes(req);
+ }
+
+ public HttpServletRequest getReq() {
+ return req;
+ }
+
+ public Map getCustomAttributes() {
+ return customAttributes;
+ }
+
+ public Map getSharedVariables() {
+ return sharedVariables;
+ }
+
+ private void setSharedVariables(HttpServletRequest req) {
+ ServletContext ctx = req.getSession().getServletContext();
+ VitroRequest vreq = new VitroRequest(req);
+ ApplicationBean appBean = vreq.getAppBean();
+ String siteName = appBean.getApplicationName();
+ String tagLine = appBean.getShortHand();
+ String themeDir = appBean.getThemeDir().replaceAll("/$", "");
+ String currentTheme = themeDir
+ .substring(themeDir.lastIndexOf('/') + 1);
+ Map siteUrls = getSiteUrls(ctx, themeDir);
+
+ sharedVariables.put("siteName", wrap(siteName));
+ sharedVariables.put("themeDir", wrap(themeDir));
+ sharedVariables.put("currentTheme", wrap(currentTheme));
+ sharedVariables.put("siteTagline", wrap(tagLine));
+ sharedVariables.put("urls", wrap(siteUrls));
+ }
+
+ private Map getSiteUrls(ServletContext ctx,
+ String themeDir) {
+ Map urls = new HashMap();
+
+ // Templates use this to construct urls.
+ urls.put("base", ctx.getContextPath());
+ urls.put("home", UrlBuilder.getHomeUrl());
+ urls.put("about", UrlBuilder.getUrl(Route.ABOUT));
+ urls.put("search", UrlBuilder.getUrl(Route.SEARCH));
+ urls.put("termsOfUse", UrlBuilder.getUrl(Route.TERMS_OF_USE));
+ urls.put("login", UrlBuilder.getLoginUrl());
+ urls.put("logout", UrlBuilder.getLogoutUrl());
+ urls.put("siteAdmin", UrlBuilder.getUrl(Route.SITE_ADMIN));
+
+ urls.put("themeImages", UrlBuilder.getUrl(themeDir + "/images"));
+ urls.put("images", UrlBuilder.getUrl("/images"));
+ urls.put("theme", UrlBuilder.getUrl(themeDir));
+ urls.put("index", UrlBuilder.getUrl("/browse"));
+
+ return urls;
+ }
+
+ private TemplateModel wrap(Object o) {
+ try {
+ return c.getObjectWrapper().wrap(o);
+ } catch (TemplateModelException e) {
+ log.error("Failed to wrap this "
+ + "for the Freemarker configuration: " + o, e);
+ return new SimpleScalar(String.valueOf(o));
+ }
+ }
+
+ private void setCustomAttributes(HttpServletRequest req) {
+ customAttributes.put("request", req);
+ }
+
+ }
+}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/AutocompleteController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/AutocompleteController.java
index 359a53529..51958ba45 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/AutocompleteController.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/AutocompleteController.java
@@ -33,7 +33,7 @@ import edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup;
/**
* AutocompleteController generates autocomplete content
- * via the search index.
+ * via the search index.
*/
public class AutocompleteController extends VitroAjaxController {
@@ -49,7 +49,7 @@ public class AutocompleteController extends VitroAjaxController {
String NORESULT_MSG = "";
- private static final int DEFAULT_MAX_HIT_COUNT = 1000;
+ private static final int DEFAULT_MAX_HIT_COUNT = 1000;
public static final int MAX_QUERY_LENGTH = 500;
@@ -57,50 +57,50 @@ public class AutocompleteController extends VitroAjaxController {
protected Actions requiredActions(VitroRequest vreq) {
return SimplePermission.USE_BASIC_AJAX_CONTROLLERS.ACTIONS;
}
-
+
@Override
protected void doRequest(VitroRequest vreq, HttpServletResponse response)
throws IOException, ServletException {
-
+
try {
-
+
String qtxt = vreq.getParameter(PARAM_QUERY);
-
- SolrQuery query = getQuery(qtxt, vreq);
+
+ SolrQuery query = getQuery(qtxt, vreq);
if (query == null ) {
log.debug("query for '" + qtxt +"' is null.");
doNoQuery(response);
return;
}
log.debug("query for '" + qtxt +"' is " + query.toString());
-
+
SolrServer solr = SolrSetup.getSolrServer(getServletContext());
QueryResponse queryResponse = solr.query(query);
if ( queryResponse == null) {
- log.error("Query response for a search was null");
+ log.error("Query response for a search was null");
doNoSearchResults(response);
return;
}
-
+
SolrDocumentList docs = queryResponse.getResults();
if ( docs == null) {
- log.error("Docs for a search was null");
+ log.error("Docs for a search was null");
doNoSearchResults(response);
return;
}
-
+
long hitCount = docs.getNumFound();
log.debug("Total number of hits = " + hitCount);
- if ( hitCount < 1 ) {
+ if ( hitCount < 1 ) {
doNoSearchResults(response);
return;
- }
+ }
List results = new ArrayList();
for (SolrDocument doc : docs) {
- try {
+ try {
String uri = doc.get(VitroSearchTermNames.URI).toString();
// RY 7/1/2011
// Comment was: VitroSearchTermNames.NAME_RAW is a multivalued field, so doc.get() returns a list.
@@ -116,61 +116,71 @@ public class AutocompleteController extends VitroAjaxController {
} else {
name = (String) nameRaw;
}
- SearchResult result = new SearchResult(name, uri);
+
+ Object mostSpecificType = doc.get(VitroSearchTermNames.MOST_SPECIFIC_TYPE_URIS);
+ String mst = null;
+ if (mostSpecificType instanceof List>) {
+ @SuppressWarnings("unchecked")
+ List mstList = (List) mostSpecificType;
+ mst = mstList.get(0);
+ } else {
+ mst = (String) mostSpecificType;
+ }
+
+ SearchResult result = new SearchResult(name, uri, mst);
results.add(result);
+ log.debug("results = " + results.toString());
} catch(Exception e){
log.error("problem getting usable individuals from search " +
"hits" + e.getMessage());
}
- }
+ }
Collections.sort(results);
-
+
JSONArray jsonArray = new JSONArray();
for (SearchResult result : results) {
jsonArray.put(result.toMap());
}
response.getWriter().write(jsonArray.toString());
-
+
} catch (Throwable e) {
- log.error(e, e);
+ log.error(e, e);
doSearchError(response);
}
}
private SolrQuery getQuery(String queryStr, VitroRequest vreq) {
-
+
if ( queryStr == null) {
- log.error("There was no parameter '"+ PARAM_QUERY
- +"' in the request.");
+ log.error("There was no parameter '"+ PARAM_QUERY
+ +"' in the request.");
return null;
} else if( queryStr.length() > MAX_QUERY_LENGTH ) {
log.debug("The search was too long. The maximum " +
"query length is " + MAX_QUERY_LENGTH );
return null;
}
-
+
SolrQuery query = new SolrQuery();
query.setStart(0)
- .setRows(DEFAULT_MAX_HIT_COUNT);
-
+ .setRows(DEFAULT_MAX_HIT_COUNT);
setNameQuery(query, queryStr, vreq);
-
// Filter by type
String typeParam = (String) vreq.getParameter(PARAM_RDFTYPE);
String multipleTypesParam = (String) vreq.getParameter(PARAM_MULTIPLE_RDFTYPE);
if (typeParam != null) {
addFilterQuery(query, typeParam, multipleTypesParam);
- }
-
- query.setFields(VitroSearchTermNames.NAME_RAW, VitroSearchTermNames.URI); // fields to retrieve
-
+ }
+
+ query.setFields(VitroSearchTermNames.NAME_RAW, VitroSearchTermNames.URI, VitroSearchTermNames.MOST_SPECIFIC_TYPE_URIS); // fields to retrieve
+
// Can't sort on multivalued field, so we sort the results in Java when we get them.
// query.setSortField(VitroSearchTermNames.NAME_LOWERCASE, SolrQuery.ORDER.asc);
-
+
return query;
}
-
+
private void addFilterQuery(SolrQuery query, String typeParam, String multipleTypesParam) {
if(multipleTypesParam == null || multipleTypesParam.equals("null") || multipleTypesParam.isEmpty()) {
//Single type parameter, process as usual
@@ -181,15 +191,13 @@ public class AutocompleteController extends VitroAjaxController {
int len = typeParams.length;
int i;
List filterQueries = new ArrayList();
-
+
for(i = 0; i < len; i++) {
filterQueries.add(VitroSearchTermNames.RDFTYPE + ":\"" + typeParams[i] + "\" ");
}
String filterQuery = StringUtils.join(filterQueries, " OR ");
query.addFilterQuery(filterQuery);
}
-
-
}
private void setNameQuery(SolrQuery query, String queryStr, HttpServletRequest request) {
@@ -197,10 +205,9 @@ public class AutocompleteController extends VitroAjaxController {
if (StringUtils.isBlank(queryStr)) {
log.error("No query string");
}
-
- String tokenizeParam = (String) request.getParameter("tokenize");
+ String tokenizeParam = (String) request.getParameter("tokenize");
boolean tokenize = "true".equals(tokenizeParam);
-
+
// Note: Stemming is only relevant if we are tokenizing: an untokenized name
// query will not be stemmed. So we don't look at the stem parameter until we get to
// setTokenizedNameQuery().
@@ -210,43 +217,43 @@ public class AutocompleteController extends VitroAjaxController {
setUntokenizedNameQuery(query, queryStr);
}
}
-
+
private void setTokenizedNameQuery(SolrQuery query, String queryStr, HttpServletRequest request) {
/* We currently have no use case for a tokenized, unstemmed autocomplete search field, so the option
* has been disabled. If needed in the future, will need to add a new field and field type which
* is like AC_NAME_STEMMED but doesn't include the stemmer.
- String stemParam = (String) request.getParameter("stem");
+ String stemParam = (String) request.getParameter("stem");
boolean stem = "true".equals(stemParam);
if (stem) {
String acTermName = VitroSearchTermNames.AC_NAME_STEMMED;
String nonAcTermName = VitroSearchTermNames.NAME_STEMMED;
} else {
String acTermName = VitroSearchTermNames.AC_NAME_UNSTEMMED;
- String nonAcTermName = VitroSearchTermNames.NAME_UNSTEMMED;
+ String nonAcTermName = VitroSearchTermNames.NAME_UNSTEMMED;
}
*/
-
+
String acTermName = VitroSearchTermNames.AC_NAME_STEMMED;
String nonAcTermName = VitroSearchTermNames.NAME_STEMMED;
String acQueryStr;
-
+
if (queryStr.endsWith(" ")) {
- acQueryStr = makeTermQuery(nonAcTermName, queryStr, true);
+ acQueryStr = makeTermQuery(nonAcTermName, queryStr, true);
} else {
int indexOfLastWord = queryStr.lastIndexOf(" ") + 1;
List terms = new ArrayList(2);
-
+
String allButLastWord = queryStr.substring(0, indexOfLastWord);
if (StringUtils.isNotBlank(allButLastWord)) {
terms.add(makeTermQuery(nonAcTermName, allButLastWord, true));
}
-
+
String lastWord = queryStr.substring(indexOfLastWord);
if (StringUtils.isNotBlank(lastWord)) {
terms.add(makeTermQuery(acTermName, lastWord, false));
}
-
+
acQueryStr = StringUtils.join(terms, " AND ");
}
@@ -255,26 +262,26 @@ public class AutocompleteController extends VitroAjaxController {
}
- private void setUntokenizedNameQuery(SolrQuery query, String queryStr) {
- queryStr = queryStr.trim();
+ private void setUntokenizedNameQuery(SolrQuery query, String queryStr) {
+ queryStr = queryStr.trim();
queryStr = makeTermQuery(VitroSearchTermNames.AC_NAME_UNTOKENIZED, queryStr, true);
query.setQuery(queryStr);
}
-
+
private String makeTermQuery(String term, String queryStr, boolean mayContainWhitespace) {
if (mayContainWhitespace) {
queryStr = "\"" + escapeWhitespaceInQueryString(queryStr) + "\"";
}
return term + ":" + queryStr;
}
-
+
private String escapeWhitespaceInQueryString(String queryStr) {
// Solr wants whitespace to be escaped with a backslash
return queryStr.replaceAll("\\s+", "\\\\ ");
}
-
+
private void doNoQuery(HttpServletResponse response) throws IOException {
- // For now, we are not sending an error message back to the client because
+ // For now, we are not sending an error message back to the client because
// with the default autocomplete configuration it chokes.
doNoSearchResults(response);
}
@@ -288,36 +295,46 @@ public class AutocompleteController extends VitroAjaxController {
private void doNoSearchResults(HttpServletResponse response) throws IOException {
response.getWriter().write("[]");
}
-
+
public class SearchResult implements Comparable