From 9f1b9f6bebf96ca4176cd018dc9d63bbfaaf2c7f Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 25 Jul 2013 11:51:45 -0400 Subject: [PATCH 01/16] Add license tag line. Remove unused imports. VIVO-222 --- .../StreamingMultipartHttpServletRequest.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) 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. From 50a6be56a2986adb406d59b3fec2b494b1fa9a85 Mon Sep 17 00:00:00 2001 From: j2blake Date: Mon, 29 Jul 2013 14:30:49 -0400 Subject: [PATCH 02/16] VIVO-39 Deprecate the SimplePermission instances that we would like to see go away. --- .../auth/permissions/SimplePermission.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) 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..17460e61f 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,19 +74,32 @@ public class SimplePermission extends Permission { "SeeVerbosePropertyInformation"); public static final SimplePermission USE_ADVANCED_DATA_TOOLS_PAGES = new SimplePermission( "UseAdvancedDataToolsPages"); - public static final SimplePermission USE_BASIC_AJAX_CONTROLLERS = new SimplePermission( - "UseBasicAjaxControllers"); - public static final SimplePermission USE_MISCELLANEOUS_ADMIN_PAGES = new SimplePermission( - "UseMiscellaneousAdminPages"); - public static final SimplePermission USE_MISCELLANEOUS_CURATOR_PAGES = new SimplePermission( - "UseMiscellaneousCuratorPages"); - public static final SimplePermission USE_MISCELLANEOUS_EDITOR_PAGES = new SimplePermission( - "UseMiscellaneousEditorPages"); - public static final SimplePermission USE_MISCELLANEOUS_PAGES = new SimplePermission( - "UseMiscellaneousPages"); public static final SimplePermission USE_SPARQL_QUERY_PAGE = new SimplePermission( "UseSparqlQueryPage"); + // ---------------------------------------------------------------------- + // These deprecated 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. + // ---------------------------------------------------------------------- + + @Deprecated + public static final SimplePermission USE_BASIC_AJAX_CONTROLLERS = new SimplePermission( + "UseBasicAjaxControllers"); + @Deprecated + public static final SimplePermission USE_MISCELLANEOUS_ADMIN_PAGES = new SimplePermission( + "UseMiscellaneousAdminPages"); + @Deprecated + public static final SimplePermission USE_MISCELLANEOUS_CURATOR_PAGES = new SimplePermission( + "UseMiscellaneousCuratorPages"); + @Deprecated + public static final SimplePermission USE_MISCELLANEOUS_EDITOR_PAGES = new SimplePermission( + "UseMiscellaneousEditorPages"); + @Deprecated + public static final SimplePermission USE_MISCELLANEOUS_PAGES = new SimplePermission( + "UseMiscellaneousPages"); + public static List getAllInstances() { return new ArrayList(allInstances.values()); } From 914bb18278802b8b50d9aca4dfca8552eea9f971 Mon Sep 17 00:00:00 2001 From: j2blake Date: Wed, 31 Jul 2013 16:30:40 -0400 Subject: [PATCH 03/16] VIVO-64 Modify UpdateKnowledgeBase so it doesn't require an empty directory. It will create any directories that it needs. It will also store them in [vitro.home]/upgrade/knowledgeBase instead of [webapps]/vivo/WEB-INF/ontologies/upgrade --- .../servlet/setup/UpdateKnowledgeBase.java | 104 +++++++++--------- .../setup/UpdatePermissionSetUris.java | 2 +- 2 files changed, 56 insertions(+), 50 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java index 28fa02f5e..6dda504f2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java @@ -5,7 +5,11 @@ package edu.cornell.mannlib.vitro.webapp.servlet.setup; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -31,11 +35,13 @@ import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; +import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.ontology.update.KnowledgeBaseUpdater; import edu.cornell.mannlib.vitro.webapp.ontology.update.UpdateSettings; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** * Invokes process to test whether the knowledge base needs any updating @@ -44,21 +50,10 @@ import edu.cornell.mannlib.vitro.webapp.ontology.update.UpdateSettings; * */ public class UpdateKnowledgeBase implements ServletContextListener { - public static final String KBM_REQURIED_AT_STARTUP = "KNOWLEDGE_BASE_MIGRATION_REQUIRED_AT_STARTUP"; private final static Log log = LogFactory.getLog(UpdateKnowledgeBase.class); private static final String DATA_DIR = "/WEB-INF/ontologies/update/"; - private static final String LOG_DIR = "logs/"; - private static final String CHANGED_DATA_DIR = "changedData/"; - private static final String ASK_QUERY_FILE = DATA_DIR + "askUpdated.sparql"; - private static final String SUCCESS_ASSERTIONS_FILE = DATA_DIR + "success.n3"; - private static final String SUCCESS_RDF_FORMAT = "N3"; - private static final String DIFF_FILE = DATA_DIR + "diff.tab.txt"; - private static final String REMOVED_DATA_FILE = DATA_DIR + CHANGED_DATA_DIR + "removedData.n3"; - private static final String ADDED_DATA_FILE = DATA_DIR + CHANGED_DATA_DIR + "addedData.n3"; - private static final String SPARQL_CONSTRUCT_ADDITIONS_DIR = DATA_DIR + "sparqlConstructs/additions/"; - private static final String SPARQL_CONSTRUCT_DELETIONS_DIR = DATA_DIR + "sparqlConstructs/deletions/"; private static final String OLD_TBOX_MODEL_DIR = DATA_DIR + "oldVersion/"; private static final String NEW_TBOX_MODEL_DIR = "/WEB-INF/filegraph/tbox/"; private static final String OLD_TBOX_ANNOTATIONS_DIR = DATA_DIR + "oldAnnotations/"; @@ -72,33 +67,15 @@ public class UpdateKnowledgeBase implements ServletContextListener { private static final String LOADED_STARTUPT_DISPLAYMODEL_DIR = "/WEB-INF/ontologies/app/loadedAtStartup/"; private static final String OLD_DISPLAYMODEL_VIVOLISTVIEW_PATH = DATA_DIR + "oldDisplayModel/vivoListViewConfig.rdf"; + @Override public void contextInitialized(ServletContextEvent sce) { - try { - ServletContext ctx = sce.getServletContext(); - - // If the DATA_DIR directory doesn't exist no migration check will be done. - // This is a normal situation for Vitro. - File updateDirectory = new File(ctx.getRealPath(DATA_DIR)); - if (!updateDirectory.exists()) { - log.debug("Directory " + ctx.getRealPath(DATA_DIR) + " does not exist, no migration check will be attempted."); - return; - } + ServletContext ctx = sce.getServletContext(); + StartupStatus ss = StartupStatus.getBean(ctx); - String logFileName = DATA_DIR + LOG_DIR + timestampedFileName("knowledgeBaseUpdate", "log"); - String errorLogFileName = DATA_DIR + LOG_DIR + timestampedFileName("knowledgeBaseUpdate.error", "log"); - + try { UpdateSettings settings = new UpdateSettings(); - settings.setAskUpdatedQueryFile(getAskUpdatedQueryPath(ctx)); - settings.setDataDir(ctx.getRealPath(DATA_DIR)); - settings.setSparqlConstructAdditionsDir(ctx.getRealPath(SPARQL_CONSTRUCT_ADDITIONS_DIR)); - settings.setSparqlConstructDeletionsDir(ctx.getRealPath(SPARQL_CONSTRUCT_DELETIONS_DIR)); - settings.setDiffFile(ctx.getRealPath(DIFF_FILE)); - settings.setSuccessAssertionsFile(ctx.getRealPath(SUCCESS_ASSERTIONS_FILE)); - settings.setSuccessRDFFormat(SUCCESS_RDF_FORMAT); - settings.setLogFile(ctx.getRealPath(logFileName)); - settings.setErrorLogFile(ctx.getRealPath(errorLogFileName)); - settings.setAddedDataFile(ctx.getRealPath(ADDED_DATA_FILE)); - settings.setRemovedDataFile(ctx.getRealPath(REMOVED_DATA_FILE)); + putReportingPathsIntoSettings(ctx, settings); + WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory(); settings.setDefaultNamespace(wadf.getDefaultNamespace()); settings.setAssertionOntModelSelector(ModelAccess.on(ctx).getBaseOntModelSelector()); @@ -157,21 +134,54 @@ public class UpdateKnowledgeBase implements ServletContextListener { } } } catch (Exception ioe) { - String errMsg = "Exception updating knowledge base " + - "for ontology changes: "; - // Tomcat doesn't always seem to print exceptions thrown from - // context listeners - System.out.println(errMsg); - ioe.printStackTrace(); - throw new RuntimeException(errMsg, ioe); + ss.fatal(this, "Exception updating knowledge base for ontology changes: ", ioe); } } catch (Throwable t){ - log.warn("warning", t); + ss.fatal(this, "Exception updating knowledge base for ontology changes: ", t); } } catch (Throwable t) { - t.printStackTrace(); + ss.fatal(this, "Exception updating knowledge base for ontology changes: ", t); } } + + /** + * Create the directories where we will report on the update. + * Put the paths for the directories and files into the settings object. + */ + private void putReportingPathsIntoSettings(ServletContext ctx, UpdateSettings settings) throws IOException { + ConfigurationProperties props = ConfigurationProperties.getBean(ctx); + Path homeDir = Paths.get(props.getProperty("vitro.home")); + + Path dataDir = createDirectory(homeDir, "upgrade", "knowledgeBase"); + settings.setDataDir(dataDir.toString()); + StartupStatus.getBean(ctx).info(this, "Updating knowledge base: reports are in '" + dataDir + "'"); + + settings.setAskUpdatedQueryFile(dataDir.resolve("askUpdated.sparql").toString()); + settings.setDiffFile(dataDir.resolve("diff.tab.txt").toString()); + settings.setSuccessAssertionsFile(dataDir.resolve("success.n3").toString()); + settings.setSuccessRDFFormat("N3"); + + settings.setSparqlConstructAdditionsDir(createDirectory(dataDir, "sparqlConstructs", "additions").toString()); + settings.setSparqlConstructDeletionsDir(createDirectory(dataDir, "sparqlConstructs", "deletions").toString()); + + Path changedDir = createDirectory(dataDir, "changedData"); + settings.setAddedDataFile(changedDir.resolve("addedData.n3").toString()); + settings.setRemovedDataFile(changedDir.resolve("removedData.n3").toString()); + + Path logDir = createDirectory(dataDir, "logs"); + settings.setLogFile(logDir.resolve(timestampedFileName("knowledgeBaseUpdate", "log")).toString()); + settings.setErrorLogFile(logDir.resolve(timestampedFileName("knowledgeBaseUpdate.error", "log")).toString()); + } + + private Path createDirectory(Path parent, String... children) throws IOException { + Path dir = parent; + for (String child : children) { + dir = dir.resolve(child); + } + Files.createDirectories(dir); + return dir; + } + //Multiple changes from 1.4 to 1.5 will occur //update migration model @@ -473,15 +483,11 @@ public class UpdateKnowledgeBase implements ServletContextListener { } } + @Override public void contextDestroyed(ServletContextEvent arg0) { // nothing to do } - public static String getAskUpdatedQueryPath(ServletContext ctx) { - return ctx.getRealPath(ASK_QUERY_FILE); - - } - private static String timestampedFileName(String prefix, String suffix) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-sss"); return prefix + "." + sdf.format(new Date()) + "." + suffix; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdatePermissionSetUris.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdatePermissionSetUris.java index ec03f70ff..e8a66561e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdatePermissionSetUris.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdatePermissionSetUris.java @@ -190,7 +190,7 @@ public class UpdatePermissionSetUris implements ServletContextListener { File homeDirectory = new File(homeDirectoryPath); confirmIsDirectory(homeDirectory); - File upgradeDirectory = createDirectory(homeDirectory, "upgrade"); + File upgradeDirectory = createDirectory(homeDirectory, "upgrade/permissions"); String filename = timestampedFilename("UpgradePermissionSetUris", ".txt"); this.file = new File(upgradeDirectory, filename); From 6b3d9a28c7d5deb96ffc7d375c4886aede8b78fa Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 1 Aug 2013 15:08:15 -0400 Subject: [PATCH 04/16] VIVO-234 Ignore a runtime.properties file in the distribution directory --- webapp/build.xml | 1036 +++++++++++++++++++++++----------------------- 1 file changed, 514 insertions(+), 522 deletions(-) diff --git a/webapp/build.xml b/webapp/build.xml index a144f0665..05e3edec9 100644 --- a/webapp/build.xml +++ b/webapp/build.xml @@ -1,522 +1,514 @@ - - - - - - - - - - - - - - - - - - - - The Vitro build script requires Java 7 or later. - Java system property java.version = ${java.version} - Java system property java.home = ${java.home} - JAVA_HOME environment variable = ${env.JAVA_HOME} - - - - - - - - - - The Vitro build script requires Ant 1.8 or later. - Ant property ant.version = ${ant.version} - Ant property ant.home = ${ant.home} - ANT_HOME environment variable = ${env.ANT_HOME} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${revisionInfo.timestamp} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -all - Runs "clean", then "deploy". -clean - Delete all artifacts so the next build will be from scratch. -compile - Compile the Java source files. -orng - Configure and deploy the ORNG Shindig application. -test - Compile and run the JUnit tests. -distribute - Create WAR files to be deployed in a servlet container. -deploy - Deploy the application directly into the Tomcat webapps directory. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + The Vitro build script requires Java 7 or later. + Java system property java.version = ${java.version} + Java system property java.home = ${java.home} + JAVA_HOME environment variable = ${env.JAVA_HOME} + + + + + + + + + + The Vitro build script requires Ant 1.8 or later. + Ant property ant.version = ${ant.version} + Ant property ant.home = ${ant.home} + ANT_HOME environment variable = ${env.ANT_HOME} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${revisionInfo.timestamp} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +all - Runs "clean", then "deploy". +clean - Delete all artifacts so the next build will be from scratch. +compile - Compile the Java source files. +orng - Configure and deploy the ORNG Shindig application. +test - Compile and run the JUnit tests. +distribute - Create WAR files to be deployed in a servlet container. +deploy - Deploy the application directly into the Tomcat webapps directory. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 036d20b8926f2e34d63485efb1de3a53e3016a96 Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 1 Aug 2013 15:24:33 -0400 Subject: [PATCH 05/16] VIVO-227 Remove warning message from JsonServletTest --- .../mannlib/vitro/webapp/controller/json/JsonServletTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServletTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServletTest.java index 3b6e103be..9128b6f0e 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServletTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServletTest.java @@ -192,6 +192,7 @@ public class JsonServletTest extends AbstractTestClass { public void individualsByClassNoIndividuals() throws ServletException, IOException { setLoggerLevel(JsonServlet.class, Level.FATAL); + setLoggerLevel(ModelAccess.class, Level.ERROR); String vclassId = "http://myVclass"; vcDao.setVClass(vclassId, new VClass(vclassId)); req.addParameter(GET_SOLR_INDIVIDUALS_BY_VCLASS, "true"); From 56b963d8bc66171f340143fbbd2e1f9ba9c921e5 Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 1 Aug 2013 16:04:42 -0400 Subject: [PATCH 06/16] VIVO-235 Reduce "deprecation" messages in the build The benefit of making these instances deprecated is very small. The annoyance of having deprecation messages in the build is very real. --- .../webapp/auth/permissions/SimplePermission.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) 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 17460e61f..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 @@ -78,25 +78,19 @@ public class SimplePermission extends Permission { "UseSparqlQueryPage"); // ---------------------------------------------------------------------- - // These deprecated 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. + // 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. // ---------------------------------------------------------------------- - @Deprecated public static final SimplePermission USE_BASIC_AJAX_CONTROLLERS = new SimplePermission( "UseBasicAjaxControllers"); - @Deprecated public static final SimplePermission USE_MISCELLANEOUS_ADMIN_PAGES = new SimplePermission( "UseMiscellaneousAdminPages"); - @Deprecated public static final SimplePermission USE_MISCELLANEOUS_CURATOR_PAGES = new SimplePermission( "UseMiscellaneousCuratorPages"); - @Deprecated public static final SimplePermission USE_MISCELLANEOUS_EDITOR_PAGES = new SimplePermission( "UseMiscellaneousEditorPages"); - @Deprecated public static final SimplePermission USE_MISCELLANEOUS_PAGES = new SimplePermission( "UseMiscellaneousPages"); From c75c0d0f9f11e49fb670ef9a7c2c982f40561f68 Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 1 Aug 2013 16:06:59 -0400 Subject: [PATCH 07/16] VIVO-235 Reduce "deprecation" messages in the build It's OK for these stub classes to implement deprecated methods in the interfaces, as long as they declare those methods with @Override and @Deprecated. --- .../javax/servlet/ServletContextStub.java | 4 ++ .../servlet/http/HttpServletRequestStub.java | 57 +++++++++++++++---- .../javax/servlet/http/HttpSessionStub.java | 4 ++ 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/webapp/test/stubs/javax/servlet/ServletContextStub.java b/webapp/test/stubs/javax/servlet/ServletContextStub.java index cc4e9ca32..46e592d60 100644 --- a/webapp/test/stubs/javax/servlet/ServletContextStub.java +++ b/webapp/test/stubs/javax/servlet/ServletContextStub.java @@ -200,6 +200,7 @@ public class ServletContextStub implements ServletContext { } @Override + @Deprecated public Servlet getServlet(String arg0) throws ServletException { throw new RuntimeException( "ServletContextStub.getServlet() not implemented."); @@ -213,6 +214,7 @@ public class ServletContextStub implements ServletContext { @Override @SuppressWarnings("rawtypes") + @Deprecated public Enumeration getServletNames() { throw new RuntimeException( "ServletContextStub.getServletNames() not implemented."); @@ -220,6 +222,7 @@ public class ServletContextStub implements ServletContext { @Override @SuppressWarnings("rawtypes") + @Deprecated public Enumeration getServlets() { throw new RuntimeException( "ServletContextStub.getServlets() not implemented."); @@ -231,6 +234,7 @@ public class ServletContextStub implements ServletContext { } @Override + @Deprecated public void log(Exception arg0, String arg1) { throw new RuntimeException("ServletContextStub.log() not implemented."); } diff --git a/webapp/test/stubs/javax/servlet/http/HttpServletRequestStub.java b/webapp/test/stubs/javax/servlet/http/HttpServletRequestStub.java index a35924ddf..d1b2c4dd0 100644 --- a/webapp/test/stubs/javax/servlet/http/HttpServletRequestStub.java +++ b/webapp/test/stubs/javax/servlet/http/HttpServletRequestStub.java @@ -60,8 +60,8 @@ public class HttpServletRequestStub implements HttpServletRequest { /** * Supply the request URL as a single URL. We will parse it on the - * assumption that the contextPath and the pathInfo are empty. - * Don't include a query string. Instead, set parameters. + * assumption that the contextPath and the pathInfo are empty. Don't include + * a query string. Instead, set parameters. */ public void setRequestUrl(URL url) { this.contextPath = ""; @@ -81,8 +81,7 @@ public class HttpServletRequestStub implements HttpServletRequest { /** * Supply the pieces of the request URL, so we can respond correctly when - * asked for a piece. - * Don't include a query string. Instead, set parameters. + * asked for a piece. Don't include a query string. Instead, set parameters. */ public void setRequestUrlByParts(String shemeHostPort, String contextPath, String servletPath, String pathInfo) { @@ -102,8 +101,9 @@ public class HttpServletRequestStub implements HttpServletRequest { } this.servletPath = servletPath; - this.requestUri = contextPath + servletPath + ((pathInfo == null) ? "" : pathInfo); - + this.requestUri = contextPath + servletPath + + ((pathInfo == null) ? "" : pathInfo); + if (shemeHostPort == null) { throw new NullPointerException("shemeHostPort may not be null."); } @@ -183,21 +183,21 @@ public class HttpServletRequestStub implements HttpServletRequest { public String getServletPath() { return servletPath; } - + @Override public String getPathInfo() { return pathInfo; } - + @Override public String getQueryString() { if (parameters.isEmpty()) { return null; } - + String qs = ""; - for (String key:parameters.keySet()) { - for (String value: parameters.get(key)) { + for (String key : parameters.keySet()) { + for (String value : parameters.get(key)) { qs += "&" + key + "=" + URLEncoder.encode(value); } } @@ -302,167 +302,202 @@ public class HttpServletRequestStub implements HttpServletRequest { // Un-implemented methods // ---------------------------------------------------------------------- + @Override public String getAuthType() { throw new RuntimeException( "HttpServletRequestStub.getAuthType() not implemented."); } + @Override public Cookie[] getCookies() { throw new RuntimeException( "HttpServletRequestStub.getCookies() not implemented."); } + @Override public long getDateHeader(String arg0) { throw new RuntimeException( "HttpServletRequestStub.getDateHeader() not implemented."); } + @Override public int getIntHeader(String arg0) { throw new RuntimeException( "HttpServletRequestStub.getIntHeader() not implemented."); } + @Override public String getPathTranslated() { throw new RuntimeException( "HttpServletRequestStub.getPathTranslated() not implemented."); } + @Override public String getRemoteUser() { throw new RuntimeException( "HttpServletRequestStub.getRemoteUser() not implemented."); } + @Override public String getRequestedSessionId() { throw new RuntimeException( "HttpServletRequestStub.getRequestedSessionId() not implemented."); } + @Override public Principal getUserPrincipal() { throw new RuntimeException( "HttpServletRequestStub.getUserPrincipal() not implemented."); } + @Override public boolean isRequestedSessionIdFromCookie() { throw new RuntimeException( "HttpServletRequestStub.isRequestedSessionIdFromCookie() not implemented."); } + @Override public boolean isRequestedSessionIdFromURL() { throw new RuntimeException( "HttpServletRequestStub.isRequestedSessionIdFromURL() not implemented."); } + @Override + @Deprecated public boolean isRequestedSessionIdFromUrl() { throw new RuntimeException( "HttpServletRequestStub.isRequestedSessionIdFromUrl() not implemented."); } + @Override public boolean isRequestedSessionIdValid() { throw new RuntimeException( "HttpServletRequestStub.isRequestedSessionIdValid() not implemented."); } + @Override public boolean isUserInRole(String arg0) { throw new RuntimeException( "HttpServletRequestStub.isUserInRole() not implemented."); } + @Override public String getCharacterEncoding() { throw new RuntimeException( "HttpServletRequestStub.getCharacterEncoding() not implemented."); } + @Override public int getContentLength() { throw new RuntimeException( "HttpServletRequestStub.getContentLength() not implemented."); } + @Override public String getContentType() { throw new RuntimeException( "HttpServletRequestStub.getContentType() not implemented."); } + @Override public ServletInputStream getInputStream() throws IOException { throw new RuntimeException( "HttpServletRequestStub.getInputStream() not implemented."); } + @Override public String getLocalAddr() { throw new RuntimeException( "HttpServletRequestStub.getLocalAddr() not implemented."); } + @Override public String getLocalName() { throw new RuntimeException( "HttpServletRequestStub.getLocalName() not implemented."); } + @Override public int getLocalPort() { throw new RuntimeException( "HttpServletRequestStub.getLocalPort() not implemented."); } + @Override public Locale getLocale() { throw new RuntimeException( "HttpServletRequestStub.getLocale() not implemented."); } + @Override @SuppressWarnings("rawtypes") public Enumeration getLocales() { throw new RuntimeException( "HttpServletRequestStub.getLocales() not implemented."); } + @Override public String getProtocol() { throw new RuntimeException( "HttpServletRequestStub.getProtocol() not implemented."); } + @Override public BufferedReader getReader() throws IOException { throw new RuntimeException( "HttpServletRequestStub.getReader() not implemented."); } + @Override + @Deprecated public String getRealPath(String arg0) { throw new RuntimeException( "HttpServletRequestStub.getRealPath() not implemented."); } + @Override public String getRemoteHost() { throw new RuntimeException( "HttpServletRequestStub.getRemoteHost() not implemented."); } + @Override public int getRemotePort() { throw new RuntimeException( "HttpServletRequestStub.getRemotePort() not implemented."); } + @Override public RequestDispatcher getRequestDispatcher(String arg0) { throw new RuntimeException( "HttpServletRequestStub.getRequestDispatcher() not implemented."); } + @Override public String getScheme() { throw new RuntimeException( "HttpServletRequestStub.getScheme() not implemented."); } + @Override public String getServerName() { throw new RuntimeException( "HttpServletRequestStub.getServerName() not implemented."); } + @Override public int getServerPort() { throw new RuntimeException( "HttpServletRequestStub.getServerPort() not implemented."); } + @Override public boolean isSecure() { throw new RuntimeException( "HttpServletRequestStub.isSecure() not implemented."); } + @Override public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException { throw new RuntimeException( diff --git a/webapp/test/stubs/javax/servlet/http/HttpSessionStub.java b/webapp/test/stubs/javax/servlet/http/HttpSessionStub.java index cd71d4cef..7cc87b26b 100644 --- a/webapp/test/stubs/javax/servlet/http/HttpSessionStub.java +++ b/webapp/test/stubs/javax/servlet/http/HttpSessionStub.java @@ -126,12 +126,14 @@ public class HttpSessionStub implements HttpSession { } @Override + @Deprecated public Object getValue(String arg0) { throw new RuntimeException( "HttpSessionStub.getValue() not implemented."); } @Override + @Deprecated public String[] getValueNames() { throw new RuntimeException( "HttpSessionStub.getValueNames() not implemented."); @@ -149,12 +151,14 @@ public class HttpSessionStub implements HttpSession { } @Override + @Deprecated public void putValue(String arg0, Object arg1) { throw new RuntimeException( "HttpSessionStub.putValue() not implemented."); } @Override + @Deprecated public void removeValue(String arg0) { throw new RuntimeException( "HttpSessionStub.removeValue() not implemented."); From 1b1c28f21678df86739f3aff5eaadbb30bd17921 Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 1 Aug 2013 16:07:55 -0400 Subject: [PATCH 08/16] VIVO-235 Reduce "deprecation" messages in the build The @SuppressWarnings("deprecation") annotation doesn't apply to an import statement, but it does apply if the class is fully-qualified when created. --- .../freemarker/ImageUploaderThumbnailerTester_2.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploaderThumbnailerTester_2.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploaderThumbnailerTester_2.java index 2a2314999..aef00d0ac 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploaderThumbnailerTester_2.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploaderThumbnailerTester_2.java @@ -23,7 +23,6 @@ import java.util.Set; import javax.media.jai.JAI; import javax.media.jai.RenderedOp; import javax.media.jai.operator.StreamDescriptor; -import javax.media.jai.widget.ImageCanvas; import javax.swing.BorderFactory; import javax.swing.JPanel; @@ -107,7 +106,7 @@ public class ImageUploaderThumbnailerTester_2 extends Frame { JPanel p = new JPanel(); p.setLayout(new BorderLayout()); p.add("South", l); - p.add("Center", new ImageCanvas(image)); + p.add("Center", new javax.media.jai.widget.ImageCanvas(image)); p.setBackground(new Color(0xFFFFFF)); p.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); From 65aafbc64cb5ec90bc18f8da191c0943fe39e27d Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 1 Aug 2013 17:18:06 -0400 Subject: [PATCH 09/16] VIVO-235 Improve build instructions. Tell the user what to expect when they run "ant all", and how to distinguish success from failure. --- doc/install.html | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/doc/install.html b/doc/install.html index 101ae54b8..6f5091d39 100644 --- a/doc/install.html +++ b/doc/install.html @@ -774,6 +774,39 @@

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

From f5161e14b72836958f8b029c27e1f42728163628 Mon Sep 17 00:00:00 2001 From: Brian Caruso Date: Mon, 5 Aug 2013 12:41:15 -0400 Subject: [PATCH 10/16] Removing PageDataGetters and its related servlets and tests. VIVO-218 --- .../controller/json/GetDataForPage.java | 39 -- .../webapp/controller/json/JsonServlet.java | 145 +++++++- .../pageDataGetter/BrowseDataGetter.java | 234 ------------ .../pageDataGetter/ClassGroupPageData.java | 155 -------- .../IndividualsForClassesDataGetter.java | 316 ---------------- .../utils/pageDataGetter/PageDataGetter.java | 27 -- .../pageDataGetter/PageDataGetterUtils.java | 339 ------------------ .../utils/dataGetter/DataGetterUtilsTest.java | 11 +- .../dataGetter/resources/dataGetterTest.n3 | 11 +- .../PageDataGetterUtilsTest.java | 68 ---- .../resources/pageDataGetter.n3 | 30 -- 11 files changed, 137 insertions(+), 1238 deletions(-) delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/GetDataForPage.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/BrowseDataGetter.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/ClassGroupPageData.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/IndividualsForClassesDataGetter.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetter.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtils.java delete mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtilsTest.java delete mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/resources/pageDataGetter.n3 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/utils/pageDataGetter/BrowseDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/BrowseDataGetter.java deleted file mode 100644 index 7fbd63ada..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/BrowseDataGetter.java +++ /dev/null @@ -1,234 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletContext; - -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.Individual; -import edu.cornell.mannlib.vitro.webapp.beans.VClass; -import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; -import edu.cornell.mannlib.vitro.webapp.controller.json.JsonServlet; -import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; -import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest; -import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache; -import edu.cornell.mannlib.vitro.webapp.utils.JsonToFmModel; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.VClassGroupTemplateModel; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.VClassTemplateModel; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.ListedIndividual; - -public class BrowseDataGetter implements PageDataGetter { - final static Log log = LogFactory.getLog(BrowseDataGetter.class); - - @Override - public Map getData(ServletContext context, - VitroRequest vreq, String pageUri, Map page) { - try{ - Map params = vreq.getParameterMap(); - - Mode mode = getMode( vreq, params ); - switch( mode ){ - case VCLASS_ALPHA: - return doClassAlphaDisplay(params,vreq,context); - case CLASS_GROUP: - return doClassGroupDisplay(params, vreq, context); - case VCLASS: - return doClassDisplay(params, vreq, context); - case ALL_CLASS_GROUPS: - return doAllClassGroupsDisplay( params, page, vreq, context); - default: - return doAllClassGroupsDisplay( params, page, vreq, context); - } - }catch(Throwable th){ - log.error(th,th); - return Collections.emptyMap(); - } - } - - @Override - public String getType() { - return DisplayVocabulary.HOME_PAGE_TYPE; - } - - //Get data servuice - @Override - public String getDataServiceUrl() { - return UrlBuilder.getUrl("/dataservice?getSolrIndividualsByVClass=1&vclassId="); - } - private Map doClassAlphaDisplay( Map params, VitroRequest request, ServletContext context) throws Exception { - Map body = new HashMap(); - body.putAll(getCommonValues(context, request)); - body.putAll(getClassAlphaValues(params,request,context)); - return body; - } - - private Map getClassAlphaValues( Map params, VitroRequest request, ServletContext context) throws Exception{ - Map map= new HashMap(); - - String classUri = getParam(Mode.VCLASS, request, params); - VitroRequest vreq = new VitroRequest(request); - VClass vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(classUri); - map.put("class", new VClassTemplateModel(vclass)); - - JSONObject vclassRes = JsonServlet.getSolrIndividualsByVClass(vclass.getURI(), request, context); - map.put("totalCount", JsonToFmModel.convertJSONObjectToMap( (String) vclassRes.get("totalCount") )); - map.put("alpha", JsonToFmModel.convertJSONObjectToMap( (String) vclassRes.get("alpha") )); - map.put("individuals", JsonToFmModel.convertJSONArrayToList( (JSONArray) vclassRes.get("individuals") )); - map.put("pages", JsonToFmModel.convertJSONArrayToList( (JSONArray) vclassRes.get("pages") )); - map.put("letters", JsonToFmModel.convertJSONArrayToList( (JSONArray) vclassRes.get("letters") )); - - return map; - } - - private Map getCommonValues( ServletContext context, VitroRequest vreq){ - Map values = new HashMap(); - - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(vreq); - List cgList = vcgc.getGroups(); - LinkedList cgtmList = new LinkedList(); - for( VClassGroup classGroup : cgList){ - cgtmList.add( new VClassGroupTemplateModel( classGroup )); - } - values.put("vClassGroups",cgtmList); - - return values; - } - - protected Map doAllClassGroupsDisplay( Map params, Map page, VitroRequest request, ServletContext context) { - Map body = new HashMap(); - body.putAll(getCommonValues(context,request)); - body.putAll(getAllClassGroupData(request, params, page, context)); - - return body; - } - - /** - * Gets a list of all VClassGroups with vclasses with individual counts. - * @param params2 - */ - protected Map getAllClassGroupData(VitroRequest request, Map params, Map page, ServletContext context){ - Map map = new HashMap(); - return map; - } - - protected Map doClassDisplay( Map params, - VitroRequest request, ServletContext context) { - Map body = new HashMap(); - - body.putAll(getCommonValues(context,request)); - body.putAll(getClassData(request,params,context)); - - return body; - } - - private Map getClassData(VitroRequest request, Map params, ServletContext context) { - Map map = new HashMap(); - - map.putAll(getClassGroupData(request, params,context)); - - String classUri = getParam(Mode.VCLASS, request, params); - VitroRequest vreq = new VitroRequest(request); - VClass vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(classUri); - map.put("class", new VClassTemplateModel(vclass)); - - List inds = vreq.getWebappDaoFactory().getIndividualDao() - .getIndividualsByVClass(vclass); - - List tInds = new ArrayList(inds.size()); - for( Individual ind : inds){ - tInds.add(new ListedIndividual(ind, vreq)); - } - map.put("individualsInClass", tInds); - - return map; - } - - protected Map doClassGroupDisplay(Map params, VitroRequest request, ServletContext context) { - Map body = new HashMap(); - body.putAll(getCommonValues(context,request)); - body.putAll( getClassGroupData(request,params, context)); - - return body; - } - - protected Map getClassGroupData(VitroRequest request, Map params, ServletContext context) { - Map map = new HashMap(); - - String vcgUri = getParam(Mode.CLASS_GROUP, request, params); - VitroRequest vreq = new VitroRequest(request); - - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(request); - VClassGroup vcg = vcgc.getGroup(vcgUri); - - ArrayList classes = new ArrayList(vcg.size()); - for( VClass vc : vcg){ - classes.add(new VClassTemplateModel(vc)); - } - map.put("classes", classes); - - map.put("classGroup", new VClassGroupTemplateModel(vcg)); - - return map; - } - - - enum Mode{ - VCLASS_ALPHA("vclassAlpha"), - VCLASS("vclassUri"), - CLASS_GROUP("classgroupUri"), - ALL_CLASS_GROUPS("all"); - String param; - Mode(String param){ - this.param = param; - } - } - - protected final static Mode DEFAULT_MODE = Mode.ALL_CLASS_GROUPS; - - protected Mode getMode(VitroRequest request, Map params){ - for( Mode mode : Mode.values()){ - String queryParam = request.getParameter( mode.param ); - if( queryParam != null && !queryParam.isEmpty() ){ - return mode; - } - Object obj = params.get( mode.param ); - String param = obj != null ? obj.toString():null; - if( param != null && !param.isEmpty() ){ - return mode; - } - } - return DEFAULT_MODE; - } - - public static String getParam(Mode mode, VitroRequest request, Map params){ - if( request.getParameter(mode.param) != null ) - return request.getParameter(mode.param); - if( params.get(mode.param) != null ) - return params.get(mode.param).toString(); - else - return null; - } - - /** - * For processig of JSONObject - */ - public JSONObject convertToJSON(Map dataMap, VitroRequest vreq) { - JSONObject rObj = null; - return rObj; - } - - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/ClassGroupPageData.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/ClassGroupPageData.java deleted file mode 100644 index 0e68dd4b9..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/ClassGroupPageData.java +++ /dev/null @@ -1,155 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.json.JSONObject; - -import edu.cornell.mannlib.vitro.webapp.beans.VClass; -import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; -import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest; -import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.VClassGroupTemplateModel; - -/** - * This will pass these variables to the template: - * classGroupUri: uri of the classgroup associated with this page. - * vClassGroup: a data structure that is the classgroup associated with this page. - */ -public class ClassGroupPageData implements PageDataGetter{ - private static final Log log = LogFactory.getLog(ClassGroupPageData.class); - - @Override - public Map getData(ServletContext context, VitroRequest vreq, String pageUri, Map page ){ - HashMap data = new HashMap(); - String classGroupUri = vreq.getWebappDaoFactory().getPageDao().getClassGroupPage(pageUri); - data.put("classGroupUri", classGroupUri); - - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(vreq); - List vcgList = vcgc.getGroups(); - VClassGroup group = null; - for( VClassGroup vcg : vcgList){ - if( vcg.getURI() != null && vcg.getURI().equals(classGroupUri)){ - group = vcg; - break; - } - } - if( classGroupUri != null && !classGroupUri.isEmpty() && group == null ){ - /*This could be for two reasons: one is that the classgroup doesn't exist - * The other is that there are no individuals in any of the classgroup's classes */ - group = vreq.getWebappDaoFactory().getVClassGroupDao().getGroupByURI(classGroupUri); - if( group != null ){ - List vcgFullList = vreq.getWebappDaoFactory().getVClassGroupDao() - .getPublicGroupsWithVClasses(false, true, false); - for( VClassGroup vcg : vcgFullList ){ - if( classGroupUri.equals(vcg.getURI()) ){ - group = vcg; - break; - } - } - if( group == null ){ - log.error("Cannot get classgroup '" + classGroupUri + "' for page '" + pageUri + "'"); - }else{ - setAllClassCountsToZero(group); - } - }else{ - log.error("classgroup " + classGroupUri + " does not exist in the system"); - } - - } - log.debug("Retrieved class group " + group.getURI() + " and returning to template"); - //if debug enabled, print out the number of entities within each class in the class gorup - if(log.isDebugEnabled()){ - List groupClasses = group.getVitroClassList(); - for(VClass v: groupClasses) { - log.debug("Class " + v.getName() + " - " + v.getURI() + " has " + v.getEntityCount() + " entities"); - } - } - data.put("vClassGroup", group); //may put null - - //This page level data getters tries to set its own template, - // not all of the data getters need to do this. - data.put("bodyTemplate", "page-classgroup.ftl"); - - //Also add data service url - //Hardcoding for now, need a more dynamic way of doing this - data.put("dataServiceUrlIndividualsByVClass", this.getDataServiceUrl()); - return data; - } - - public static VClassGroupTemplateModel getClassGroup(String classGroupUri, ServletContext context, VitroRequest vreq){ - - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(vreq); - List vcgList = vcgc.getGroups(); - VClassGroup group = null; - for( VClassGroup vcg : vcgList){ - if( vcg.getURI() != null && vcg.getURI().equals(classGroupUri)){ - group = vcg; - break; - } - } - - if( classGroupUri != null && !classGroupUri.isEmpty() && group == null ){ - /*This could be for two reasons: one is that the classgroup doesn't exist - * The other is that there are no individuals in any of the classgroup's classes */ - group = vreq.getWebappDaoFactory().getVClassGroupDao().getGroupByURI(classGroupUri); - if( group != null ){ - List vcgFullList = vreq.getWebappDaoFactory().getVClassGroupDao() - .getPublicGroupsWithVClasses(false, true, false); - for( VClassGroup vcg : vcgFullList ){ - if( classGroupUri.equals(vcg.getURI()) ){ - group = vcg; - break; - } - } - if( group == null ){ - log.error("Cannot get classgroup '" + classGroupUri + "'"); - return null; - }else{ - setAllClassCountsToZero(group); - } - }else{ - log.error("classgroup " + classGroupUri + " does not exist in the system"); - return null; - } - } - - return new VClassGroupTemplateModel(group); - } - - @Override - public String getType(){ - return PageDataGetterUtils.generateDataGetterTypeURI(ClassGroupPageData.class.getName()); - } - - //Get data servuice - @Override - public String getDataServiceUrl() { - return UrlBuilder.getUrl("/dataservice?getSolrIndividualsByVClass=1&vclassId="); - } - - - /** - * For processing of JSONObject - */ - //Currently empty, TODO: Review requirements - @Override - public JSONObject convertToJSON(Map dataMap, VitroRequest vreq) { - JSONObject rObj = null; - return rObj; - } - protected static void setAllClassCountsToZero(VClassGroup vcg){ - for(VClass vc : vcg){ - vc.setEntityCount(0); - } - } -} \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/IndividualsForClassesDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/IndividualsForClassesDataGetter.java deleted file mode 100644 index 902f8ca9d..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/IndividualsForClassesDataGetter.java +++ /dev/null @@ -1,316 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter; - -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletContext; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.json.JSONObject; - -import edu.cornell.mannlib.vitro.webapp.beans.VClass; -import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; -import edu.cornell.mannlib.vitro.webapp.dao.PageDao; -import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest; -import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.VClassGroupTemplateModel; - -/** - * This will pass these variables to the template: - * classGroupUri: uri of the classgroup associated with this page. - * vClassGroup: a data structure that is the classgroup associated with this page. - */ -public class IndividualsForClassesDataGetter implements PageDataGetter{ - private static final Log log = LogFactory.getLog(IndividualsForClassesDataGetter.class); - protected static String restrictClassesTemplateName = null; - @Override - public Map getData(ServletContext context, VitroRequest vreq, String pageUri, Map page ){ - this.setTemplateName(); - HashMap data = new HashMap(); - //This is the old technique of getting class intersections - PageDao pageDao = vreq.getWebappDaoFactory().getPageDao(); - Map classIntersectionsMap = getClassIntersectionsMap(pageDao, pageUri); - - try{ - List classes = retrieveClasses(context, classIntersectionsMap); - List restrictClasses = retrieveRestrictClasses(context, classIntersectionsMap); - log.debug("Retrieving classes for " + classes.toString() + " and restricting by " + restrictClasses.toString()); - processClassesAndRestrictions(vreq, context, data, classes, restrictClasses); - //Also add data service url - //Hardcoding for now, need a more dynamic way of doing this - data.put("dataServiceUrlIndividualsByVClass", this.getDataServiceUrl()); - //this is the class group associated with the data getter utilized for display on menu editing, not the custom one created - data.put("classGroupUri", pageDao.getClassGroupPage(pageUri)); - } catch(Exception ex) { - log.error("An error occurred retrieving Vclass Intersection individuals", ex); - } - - return data; - } - - protected void setTemplateName() { - this.restrictClassesTemplateName = "restricted"; - } - - protected Map getClassIntersectionsMap(PageDao pageDao, - String pageUri) { - // TODO Auto-generated method stub - return pageDao.getClassesAndRestrictionsForPage(pageUri); - } - - protected List retrieveClasses( - ServletContext context, Map classIntersectionsMap) { - List restrictClasses = (List) classIntersectionsMap.get("classes"); - return restrictClasses; - } - - protected List retrieveRestrictClasses( - ServletContext context, Map classIntersectionsMap) { - List restrictClasses = (List) classIntersectionsMap.get("restrictClasses"); - return restrictClasses; - } - - protected void processClassesAndRestrictions(VitroRequest vreq, ServletContext context, - HashMap data, List classes, List restrictClasses ) { - processClassesForDisplay(vreq, context, data, classes); - processRestrictionClasses(vreq, context, data, restrictClasses); - processIntersections(vreq, context, data); - - } - - - - //At this point, data specifices whether or not intersections included - private void processIntersections(VitroRequest vreq, - ServletContext context, HashMap data) { - VClassGroup classesGroup = (VClassGroup) data.get("vClassGroup"); - List vclassList = classesGroup.getVitroClassList(); - List restrictClasses = (List) data.get("restrictVClasses"); - //if there are restrict classes, then update counts - if(restrictClasses.size() > 0) { - log.debug("Restriction classes exist"); - List newVClassList = new ArrayList(); - //Iterate through vclasses and get updated counts, iterated and saved in same order as initially included - for(VClass v: vclassList) { - int oldCount = v.getEntityCount(); - //Making a copy so as to ensure we don't touch the values in the cache - VClass copyVClass = makeCopyVClass(v); - int count = retrieveCount(vreq, context, v, restrictClasses); - if(oldCount != count) { - log.debug("Old count was " + v.getEntityCount() + " and New count for " + v.getURI() + " is " + count); - copyVClass.setEntityCount(count); - } - newVClassList.add(copyVClass); - } - classesGroup.setVitroClassList(newVClassList); - //TODO: Do we need to do this again or will this already be reset? - data.put("vClassGroup", classesGroup); - } - } - - private VClass makeCopyVClass(VClass v) { - VClass copyVClass = new VClass(v.getURI()); - copyVClass.setLocalName(copyVClass.getLocalName()); - copyVClass.setDisplayRank(v.getDisplayRank()); - copyVClass.setName(v.getName()); - copyVClass.setNamespace(v.getNamespace()); - copyVClass.setEntityCount(v.getEntityCount()); - return copyVClass; - } - - //update class count based on restrict classes - private int retrieveCount(VitroRequest vreq, ServletContext context, VClass v, List restrictClasses) { - //Execute solr query that returns only count of individuals - log.debug("Entity count is " + v.getEntityCount()); - List classUris = new ArrayList(); - classUris.add(v.getURI()); - for(VClass r: restrictClasses) { - classUris.add(r.getURI()); - } - long count = PageDataGetterUtils.getIndividualCountForIntersection(vreq, context, classUris); - return new Long(count).intValue(); - - } - - private void processClassesForDisplay(VitroRequest vreq, ServletContext context, HashMap data, List classes) { - VClassGroup classesGroup = new VClassGroup(); - classesGroup.setURI("displayClasses"); - log.debug("Processing classes that will be displayed"); - List vClasses = new ArrayList(); - - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(vreq); - for(String classUri: classes) { - //Retrieve vclass from cache to get the count - VClass vclass = vcgc.getCachedVClass(classUri); - //if not found in cache, possibly due to not being in any class group - if(vclass == null) { - vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(classUri); - } - if(vclass != null) { - log.debug("VClass does exist for " + classUri + " and entity count is " + vclass.getEntityCount()); - vClasses.add(vclass); - } else { - log.debug("Vclass " + classUri + " does not exist in the cache"); - log.error("Error occurred, vclass does not exist for this uri " + classUri); - //Throw exception here - } - } - //Sort these classes - Collections.sort(vClasses); - log.debug("Sorting complete for V Classes"); - classesGroup.setVitroClassList(vClasses); - log.debug("Returning vitro class list in data for template"); - //Set vclass group - data.put("vClassGroup", classesGroup); - } - - private void processRestrictionClasses(VitroRequest vreq, ServletContext context, - HashMap data, List restrictClasses) { - try { - VClassGroup restrictClassesGroup = new VClassGroup(); - restrictClassesGroup.setURI("restrictClasses"); - - List restrictVClasses = new ArrayList(); - - List urlEncodedRestrictClasses = new ArrayList(); - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(vreq); - - if(restrictClasses.size() > 0) { - //classes for restriction are not displayed so don't need to include their class individual counts - for(String restrictClassUri: restrictClasses) { - //Also uses cache to remain consistent with process classes and also allow - //vclasses to be returned even if switched to display model, although - //uris used within display model editing and not vclass objects - VClass vclass = vcgc.getCachedVClass(restrictClassUri); - //if not found in cache, possibly due to not being in any class group - if(vclass == null) { - vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(restrictClassUri); - } - if(vclass != null) { - log.debug("Found restrict class and adding to list " + restrictClassUri); - restrictVClasses.add(vclass); - } else { - log.error("Error occurred, vclass does not exist for this uri " + restrictClassUri); - } - //Assuming utf-8? - urlEncodedRestrictClasses.add(URLEncoder.encode(restrictClassUri, "UTF-8")); - } - - restrictClassesGroup.setVitroClassList(restrictVClasses); - restrictClassesGroup.setIndividualCount(restrictVClasses.size()); - } else { - - } - String[] restrictClassesArray = new String[urlEncodedRestrictClasses.size()]; - restrictClassesArray = urlEncodedRestrictClasses.toArray(restrictClassesArray); - - //In case just want uris - log.debug("Variable name for including restriction classes " + getRestrictClassesTemplateName()); - data.put(getRestrictClassesTemplateName(), StringUtils.join(restrictClassesArray, ",")); - data.put("restrictVClasses", restrictVClasses); - //not sure if this is useful - data.put("restrictVClassGroup", restrictClassesGroup); - } catch(Exception ex) { - log.error("An error occurred in processing restriction classes ", ex); - } - } - - public static VClassGroupTemplateModel getClassGroup(String classGroupUri, ServletContext context, VitroRequest vreq){ - - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(vreq); - List vcgList = vcgc.getGroups(); - VClassGroup group = null; - for( VClassGroup vcg : vcgList){ - if( vcg.getURI() != null && vcg.getURI().equals(classGroupUri)){ - group = vcg; - break; - } - } - - if( classGroupUri != null && !classGroupUri.isEmpty() && group == null ){ - /*This could be for two reasons: one is that the classgroup doesn't exist - * The other is that there are no individuals in any of the classgroup's classes */ - group = vreq.getWebappDaoFactory().getVClassGroupDao().getGroupByURI(classGroupUri); - if( group != null ){ - List vcgFullList = vreq.getWebappDaoFactory().getVClassGroupDao() - .getPublicGroupsWithVClasses(false, true, false); - for( VClassGroup vcg : vcgFullList ){ - if( classGroupUri.equals(vcg.getURI()) ){ - group = vcg; - break; - } - } - if( group == null ){ - log.error("Cannot get classgroup '" + classGroupUri + "'"); - return null; - }else{ - setAllClassCountsToZero(group); - } - }else{ - log.error("classgroup " + classGroupUri + " does not exist in the system"); - return null; - } - } - - return new VClassGroupTemplateModel(group); - } - - @Override - public String getType(){ - return PageDataGetterUtils.generateDataGetterTypeURI(IndividualsForClassesDataGetter.class.getName()); - } - - //Get data servuice - @Override - public String getDataServiceUrl() { - return UrlBuilder.getUrl("/dataservice?getSolrIndividualsByVClasses=1&vclassId="); - } - /** - * For processig of JSONObject - */ - @Override - public JSONObject convertToJSON(Map map, VitroRequest vreq) { - JSONObject rObj = PageDataGetterUtils.processVclassResultsJSON(map, vreq, true); - return rObj; - } - - protected static void setAllClassCountsToZero(VClassGroup vcg){ - for(VClass vc : vcg){ - vc.setEntityCount(0); - } - } - - protected static String getAlphaParameter(VitroRequest request){ - return request.getParameter("alpha"); - } - - protected static int getPageParameter(VitroRequest request) { - String pageStr = request.getParameter("page"); - if( pageStr != null ){ - try{ - return Integer.parseInt(pageStr); - }catch(NumberFormatException nfe){ - log.debug("could not parse page parameter"); - return 1; - } - }else{ - return 1; - } - } - - //Get template parameter - private static String getRestrictClassesTemplateName() { - return restrictClassesTemplateName; - - } -} \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetter.java deleted file mode 100644 index 724ed0353..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetter.java +++ /dev/null @@ -1,27 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter; - -import java.util.Map; - -import javax.servlet.ServletContext; - -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; - -import org.json.JSONObject; - -public interface PageDataGetter{ - Map getData(ServletContext contect, VitroRequest vreq, String pageUri, Map page ); - - /** Gets the type that this class applies to */ - //This has been changed to return the class name for data getter used in menu management - String getType(); - - //get data service url based on data getter requirements - //Get data servuice - String getDataServiceUrl(); - - /**Convert data to JSONObject based on what's required for the data processing**/ - JSONObject convertToJSON(Map map, VitroRequest vreq); -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtils.java deleted file mode 100644 index 94dd8d378..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtils.java +++ /dev/null @@ -1,339 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter; - -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -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.beans.VClassGroup; -import edu.cornell.mannlib.vitro.webapp.controller.Controllers; -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.controller.json.JsonServlet; -import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache; - -public class PageDataGetterUtils { - protected static final String DATA_GETTER_MAP = "pageTypeToDataGetterMap"; - private static final Log log = LogFactory.getLog(PageDataGetterUtils.class); - - public static Map getDataForPage(String pageUri, VitroRequest vreq, ServletContext context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { - //Based on page type get the appropriate data getter - Map page = vreq.getWebappDaoFactory().getPageDao().getPage(pageUri); - - Map data = new HashMap(); - List dataGetters = getPageDataGetterObjects(vreq, pageUri); - for(PageDataGetter getter: dataGetters) { - try{ - Map moreData = null; - moreData = getAdditionalData(pageUri, getter.getType(), page, vreq, getter, context); - if( moreData != null) - data.putAll(moreData); - }catch(Throwable th){ - log.error(th,th); - } - } - return data; - } - - /** - * - * Convert data to JSON for page uri based on type and related datagetters - * TODO: How to handle different data getters? Will this replace json fields or add to them? - * @throws ClassNotFoundException - * @throws IllegalAccessException - * @throws InstantiationException - */ - public static JSONObject covertDataToJSONForPage(String pageUri, Map data, VitroRequest vreq, ServletContext context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { - //Get PageDataGetter types associated with pageUri - JSONObject rObj = null; - List dataGetters = getPageDataGetterObjects(vreq, pageUri); - for(PageDataGetter getter: dataGetters) { - JSONObject typeObj = null; - try{ - typeObj = getter.convertToJSON(data, vreq); - if( typeObj != null) { - //Copy over everything from this type Obj to - //TODO: Review how to handle duplicate keys, etc. - if(rObj != null) { - //For now, just nests as separate entry - rObj.put(getter.getType(), typeObj); - } else { - rObj = typeObj; - } - } - - } catch(Throwable th){ - log.error(th,th); - } - } - return rObj; - } - - public static Map getAdditionalData( - String pageUri, String dataGetterName, Map page, VitroRequest vreq, PageDataGetter getter, ServletContext context) { - if(dataGetterName == null || dataGetterName.isEmpty()) - return Collections.emptyMap(); - - - if( getter != null ){ - try{ - log.debug("Retrieve data for this data getter for " + pageUri); - return getter.getData(context, vreq, pageUri, page); - }catch(Throwable th){ - log.error(th,th); - return Collections.emptyMap(); - } - } else { - return Collections.emptyMap(); - } - } - - /*** - * For the page, get the actual Data Getters to be employed. - * @throws ClassNotFoundException - * @throws IllegalAccessException - * @throws InstantiationException - */ - public static List getPageDataGetterObjects(VitroRequest vreq, String pageUri) throws InstantiationException, IllegalAccessException, ClassNotFoundException { - List dataGetterObjects = new ArrayList(); - - List dataGetterClassNames = vreq.getWebappDaoFactory().getPageDao().getDataGetterClass(pageUri); - if( dataGetterClassNames == null ) - return Collections.emptyList(); - - for(String dgClassName: dataGetterClassNames) { - String className = getClassNameFromUri(dgClassName); - Class clz = Class.forName(className); - - if( PageDataGetter.class.isAssignableFrom(clz)){ - PageDataGetter pg = (PageDataGetter) clz.newInstance(); - dataGetterObjects.add(pg); - }// else skip if class does not implement PageDataGetter - } - - return dataGetterObjects; - } - - //Class URIs returned include "java:" and to instantiate object need to remove java: portion - public static String getClassNameFromUri(String dataGetterClassUri) { - if( !StringUtils.isEmpty(dataGetterClassUri) && dataGetterClassUri.contains("java:")) { - String[] splitArray = dataGetterClassUri.split("java:"); - if(splitArray.length > 1) { - return splitArray[1]; - } - } - return dataGetterClassUri; - } - - /** - * Get Individual count for Solr query for intersection of multiple classes - */ - public static long getIndividualCountForIntersection(VitroRequest vreq, ServletContext context, List classUris) { - return IndividualListController.getIndividualCount(classUris, vreq.getWebappDaoFactory().getIndividualDao(), context); - } - - - /** - * 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; - } - - /* - * Copied from JSONServlet as expect this to be related to VitroClassGroup - */ - public static JSONObject processVClassGroupJSON(VitroRequest vreq, ServletContext context, VClassGroup vcg) { - JSONObject map = new JSONObject(); - try { - ArrayList classes = new ArrayList(vcg.size()); - for( VClass vc : vcg){ - JSONObject vcObj = new JSONObject(); - vcObj.put("name", vc.getName()); - vcObj.put("URI", vc.getURI()); - vcObj.put("entityCount", vc.getEntityCount()); - classes.add(vcObj); - } - map.put("classes", classes); - map.put("classGroupName", vcg.getPublicName()); - map.put("classGroupUri", vcg.getURI()); - - } catch(Exception ex) { - log.error("Error occurred in processing VClass group ", ex); - } - return map; - } - - - //Get All VClass Groups information - //Used within menu management and processing - //TODO: Check if more appropriate location possible - public static List> getClassGroups(HttpServletRequest req) { - //Wanted this to be - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(req); - List vcgList = vcgc.getGroups(); - //For now encoding as hashmap with label and URI as trying to retrieve class group - //results in errors for some reason - List> classGroups = new ArrayList>(); - for(VClassGroup vcg: vcgList) { - HashMap hs = new HashMap(); - hs.put("publicName", vcg.getPublicName()); - hs.put("URI", vcg.getURI()); - classGroups.add(hs); - } - return classGroups; - } - - //Return data getter type to be employed in display model - public static String generateDataGetterTypeURI(String dataGetterClassName) { - return "java:" + dataGetterClassName; - } - - //TODO: Check whether this needs to be put here or elsewhere, as this is data getter specific - //with respect to class groups - //Need to use VClassGroupCache to retrieve class group information - this is the information returned from "for class group" - public static void getClassGroupForDataGetter(HttpServletRequest req, Map pageData, Map templateData) { - //Get the class group from VClassGroup, this is the same as the class group for the class group page data getter - //and the associated class group (not custom) for individuals datagetter - String classGroupUri = (String) pageData.get("classGroupUri"); - VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(req); - VClassGroup group = vcgc.getGroup(classGroupUri); - - templateData.put("classGroup", group); - templateData.put("associatedPage", group.getPublicName()); - templateData.put("associatedPageURI", group.getURI()); - } - -} \ No newline at end of file diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java index 3c03fd856..a788e179e 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java @@ -67,15 +67,6 @@ public class DataGetterUtilsTest extends AbstractTestClass{ } - @Test - public void testNonPageDataGetter() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException{ - DataGetter dg = DataGetterUtils.dataGetterForURI(vreq, displayModel,dataGetterX); - Assert.assertNull(dg); - - List dgList = - DataGetterUtils.getDataGettersForPage(vreq, displayModel, pageX); - Assert.assertNotNull(dgList); - Assert.assertTrue("List should be, it was not", dgList.size() == 0); - } + } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/resources/dataGetterTest.n3 b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/resources/dataGetterTest.n3 index 4e1f95ad0..4c9ecc56c 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/resources/dataGetterTest.n3 +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/resources/dataGetterTest.n3 @@ -20,14 +20,5 @@ display:query1data display:saveToVar "people" . -### test of what happens with a PageDataGetter instead of a DataGetter ### - -display:pageX - a display:Page ; - display:title "A PageDataGetter, not a DataGetter" ; - display:urlMapping "/query2" ; - display:hasDataGetter display:pageDataGetterX . - -display:pageDataGetterX - a . + \ No newline at end of file diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtilsTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtilsTest.java deleted file mode 100644 index a6745102c..000000000 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/PageDataGetterUtilsTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter; - -import java.io.InputStream; -import java.util.List; - -import org.apache.log4j.Level; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import stubs.javax.servlet.http.HttpServletRequestStub; - -import com.hp.hpl.jena.ontology.OntModel; -import com.hp.hpl.jena.ontology.OntModelSpec; -import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.impl.RDFDefaultErrorHandler; - -import edu.cornell.mannlib.vitro.testing.AbstractTestClass; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.dao.jena.SimpleOntModelSelector; -import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; - -public class PageDataGetterUtilsTest extends AbstractTestClass{ - OntModel displayModel; - WebappDaoFactory wdf; - - String pageURI = "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#pageX"; - String pageURI_2 = "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#SPARQLPage"; - - @Before - public void setUp() throws Exception { - // Suppress error logging. - setLoggerLevel(RDFDefaultErrorHandler.class, Level.OFF); - - OntModel model = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM); - InputStream in = PageDataGetterUtilsTest.class.getResourceAsStream("resources/pageDataGetter.n3"); - model.read(in,"","N3"); - displayModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM,model); - - SimpleOntModelSelector sos = new SimpleOntModelSelector( ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM)); - sos.setDisplayModel(displayModel); - - wdf = new WebappDaoFactoryJena(sos); - } - - @Test - public void testGetPageDataGetterObjects() throws Exception{ - VitroRequest vreq = new VitroRequest( new HttpServletRequestStub() ); - ModelAccess.on(vreq).setWebappDaoFactory(wdf); - - List pdgList = PageDataGetterUtils.getPageDataGetterObjects(vreq, pageURI); - Assert.assertNotNull(pdgList); - Assert.assertTrue("should have one PageDataGetter", pdgList.size() == 1); - } - - @Test - public void testGetNonPageDataGetterObjects() throws Exception{ - VitroRequest vreq = new VitroRequest( new HttpServletRequestStub() ); - ModelAccess.on(vreq).setWebappDaoFactory(wdf); - - List pdgList = PageDataGetterUtils.getPageDataGetterObjects(vreq, pageURI_2); - Assert.assertNotNull(pdgList); - Assert.assertTrue("should have no PageDataGetters", pdgList.size() == 0); - } -} diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/resources/pageDataGetter.n3 b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/resources/pageDataGetter.n3 deleted file mode 100644 index f3ec2f4c0..000000000 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/resources/pageDataGetter.n3 +++ /dev/null @@ -1,30 +0,0 @@ -# $This file is distributed under the terms of the license in /doc/license.txt$ - -@prefix owl: . -@prefix display: . -@prefix rdf: . -@prefix core: . -@prefix xsd: . - -### This file is for the test PageDataGetterUtilsTest.java - -display:SPARQLPage - a display:Page ; - display:title "TestQuery" ; - display:urlMapping "/query1" ; - display:hasDataGetter display:query1data . - -display:query1data - a ; - display:query "SELECT * WHERE { ?uri a } " ; - display:saveToVar "people" . - -display:pageX - a display:Page ; - display:title "A PageDataGetter, not a DataGetter" ; - display:urlMapping "/query2" ; - display:hasDataGetter display:pageDataGetterX . - -display:pageDataGetterX - a . - \ No newline at end of file From 37142c0231a98d6c645dfd41f06acfd9b2bf8e0d Mon Sep 17 00:00:00 2001 From: tworrall Date: Mon, 5 Aug 2013 15:12:24 -0400 Subject: [PATCH 11/16] VIVO-208: all fields now displayed when custom forms are rendered; customized 2-stage forms will still work as before --- .../controller/AutocompleteController.java | 139 ++++++++++-------- .../forms/js/customFormWithAutocomplete.js | 92 ++++++++---- 2 files changed, 143 insertions(+), 88 deletions(-) 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 { private String label; private String uri; - - SearchResult(String label, String uri) { + private String msType; + + SearchResult(String label, String uri, String msType) { this.label = label; this.uri = uri; + this.msType = msType; } - + public String getLabel() { return label; } - + public String getJsonLabel() { return JSONObject.quote(label); } - + public String getUri() { return uri; } - + public String getJsonUri() { return JSONObject.quote(uri); } + public String getMsType() { + return msType; + } + + public String getJsonMsType() { + return JSONObject.quote(msType); + } Map toMap() { Map map = new HashMap(); map.put("label", label); map.put("uri", uri); + map.put("msType", msType); return map; } diff --git a/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js b/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js index 1489a0038..d02e8e8d0 100644 --- a/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js +++ b/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js @@ -55,7 +55,12 @@ var customForm = { // the verify popup window. Although there could be multiple verifyMatch objects // selecting one and binding the event works for all of them this.verifyMatch = this.form.find('.verifyMatch'); - + this.defaultAcType = ""; // will be set in setType() first time through + this.templateDefinedAcTypes = false; + if ( this.acTypes != undefined ) { + this.templateDefinedAcTypes = true; + } + // find all the acSelector input elements this.acSelectors = [] ; @@ -86,7 +91,7 @@ var customForm = { // Used with the cancel link. If the user cancels after a type selection, this check // ensures that any a/c fields (besides the one associated with the type) will be reset this.clearAcSelections = false; - + }, // Set up the form on page load @@ -126,6 +131,10 @@ var customForm = { this.initFormView(); + // Set the initial autocomplete help text in the acSelector fields. + $.each(this.acSelectors, function() { + customForm.addAcHelpText($(this)); + }); }, initFormView: function() { @@ -288,7 +297,7 @@ var customForm = { //to the filtering list this.getAcFilterForIndividuals(); this.acCache = {}; - + $(selectedObj).autocomplete({ minLength: 3, source: function(request, response) { @@ -312,8 +321,9 @@ var customForm = { }, complete: function(xhr, status) { // Not sure why, but we need an explicit json parse here. - var results = $.parseJSON(xhr.responseText), + var results = $.parseJSON(xhr.responseText), filteredResults = customForm.filterAcResults(results); + customForm.acCache[request.term] = filteredResults; response(filteredResults); } @@ -321,6 +331,9 @@ var customForm = { }, select: function(event, ui) { customForm.showAutocompleteSelection(ui.item.label, ui.item.uri, $(selectedObj)); + if ( $(selectedObj).attr('acGroupName') == customForm.typeSelector.attr('acGroupName') ) { + customForm.typeSelector.val(ui.item.msType); + } } }); }, @@ -420,17 +433,24 @@ var customForm = { // provides a way to monitor selection in other js files, e.g. to hide fields upon selection $acDiv.addClass("userSelected"); - // If the form has a type selector, add type name to label in add mode. In edit mode, use typeSelectorSpan - // html. The second case is an "else if" and not an else because the template may not be passing the label - // to the acSelection macro or it may not be using the macro at all and the label is hard-coded in the html. - if ( this.typeSelector.length && ($acDiv.attr('acGroupName') == this.typeSelector.attr('acGroupName')) ) { - $acDiv.find('label').html('Selected ' + this.typeName + ':'); - } - else if ( this.typeSelectorSpan.html() && ($acDiv.attr('acGroupName') == this.typeSelectorInput.attr('acGroupName')) ) { - $acDiv.find('label').html('Selected ' + this.typeSelectorSpan.html() + ':'); - } - else if ( $acDiv.find('label').html() == '' ) { - $acDiv.find('label').html('Selected ' + this.multipleTypeNames[$(selectedObj).attr('acGroupName')] + ':'); + // If the form has a type selector, add type name to label in add mode. In edit mode, + // use typeSelectorSpan html. The second case is an "else if" and not an else because + // the template may not be passing the label to the acSelection macro or it may not be + // using the macro at all and the label is hard-coded in the html. + // ** With release 1.6 and display of all fields, more labels are hard-coded in html. + // ** So check if there's a label before doing anything else. + + if ( $acDiv.find('label').html().length === 0 ) { + + if ( this.typeSelector.length && ($acDiv.attr('acGroupName') == this.typeSelector.attr('acGroupName')) ) { + $acDiv.find('label').html('Selected ' + this.typeName + ':'); + } + else if ( this.typeSelectorSpan.html() && ($acDiv.attr('acGroupName') == this.typeSelectorInput.attr('acGroupName')) ) { + $acDiv.find('label').html('Selected ' + this.typeSelectorSpan.html() + ':'); + } + else if ( $acDiv.find('label').html() == '' ) { + $acDiv.find('label').html('Selected ' + this.multipleTypeNames[$(selectedObj).attr('acGroupName')] + ':'); + } } $acDiv.show(); @@ -447,7 +467,6 @@ var customForm = { //On initialization in this mode, submit button is disabled this.enableSubmit(); } - }, undoAutocompleteSelection: function(selectedObj) { @@ -482,11 +501,12 @@ var customForm = { $acSelector = customForm.getAcSelector($checkSelection); $acSelector.parent('p').show(); } - }); - } + }); + } } else { $acSelectionObj = $(selectedObj); + customForm.typeSelector.val(''); } $acSelector = this.getAcSelector($acSelectionObj); @@ -530,10 +550,9 @@ var customForm = { // Note: we still need this in edit mode, to set the text values. setType: function() { var selectedType; - // If there's no type selector, these values have been specified in customFormData, // and will not change over the life of the form. - if (!this.typeSelector.length) { + if (!this.typeSelector.length) { if ( this.editMode == 'edit' && (this.typeSelectorSpan.html() != null && this.typeSelectorInput.val() != null) ) { this.typeName = this.typeSelectorSpan.html(); this.acTypes[this.typeSelectorInput.attr('acGroupName')] = this.typeSelectorInput.val(); @@ -542,7 +561,11 @@ var customForm = { } selectedType = this.typeSelector.find(':selected'); - var acTypeKey = this.typeSelector.attr('acGroupName'); + var acTypeKey = this.typeSelector.attr('acGroupName'); + + if ( this.templateDefinedAcTypes && !this.defaultAcType.length ) { + this.defaultAcType = this.acTypes[acTypeKey]; + } if (selectedType.val().length) { this.acTypes[acTypeKey] = selectedType.val(); this.typeName = selectedType.html(); @@ -551,15 +574,20 @@ var customForm = { $acSelect.find('label').html( customForm.selectedString + ' ' + this.typeName + ':'); } } - // reset to empty values; may not need + // reset to empty values; else { - delete this.acTypes[acTypeKey]; - this.typeName = ''; + if ( this.templateDefinedAcTypes ) { + this.acTypes[acTypeKey] = this.defaultAcType; + } + else { + this.acTypes = new Object(); + } + this.typeName = this.defaultTypeName; } }, // Set field labels based on type selection. Although these won't change in edit - // mode, it's easier to specify the text here than in the jsp. + // mode, it's easier to specify the text here than in the ftl. setLabels: function() { var typeName = this.getTypeNameForLabels(); @@ -575,10 +603,20 @@ var customForm = { // or in repair mode in a two-step form with no type selected. Use the default type // name specified in the form data. if ( !selectedObj || !this.hasMultipleTypeNames ) { - return this.acTypes ? this.typeName : this.capitalize(this.defaultTypeName); + if ( this.acTypes && this.typeName ) { + return this.typeName; + } + else { + return this.capitalize(this.defaultTypeName); + } } else if ( selectedObj && ( $(selectedObj).attr('acGroupName') == this.typeSelector.attr('acGroupName') ) ) { - return this.acTypes ? this.typeName : this.capitalize(this.defaultTypeName); + if ( this.acTypes && this.typeName ) { + return this.typeName; + } + else { + return this.capitalize(this.defaultTypeName); + } } else { var name = customForm.multipleTypeNames[$(selectedObj).attr('id')]; From 9a0ec5a76ef60d44dff3568c0879390714615afb Mon Sep 17 00:00:00 2001 From: j2blake Date: Mon, 5 Aug 2013 16:15:37 -0400 Subject: [PATCH 12/16] VIVO-96 Recognize language support within editing framework. Instead of adding the same kluge in another location (and passing the necessary info through six layers of framework), modify the FreemarkerConfiguration to directly hold request info. Storing it in a ThreadLocal means that each thread sees its own request info, without confusion. There is still only one instance of FreemarkerConfiguration, so the template cache is shared as before. --- .../freemarker/FreemarkerConfiguration.java | 51 +++++++++++++++++++ .../FreemarkerConfigurationLoader.java | 4 +- .../freemarker/TemplateProcessingHelper.java | 8 --- .../webapp/email/FreemarkerEmailMessage.java | 10 +--- .../FreemarkerProcessingServiceImpl.java | 2 - .../IndividualShortViewDirective.java | 8 +-- .../vitro/webapp/web/widgets/Widget.java | 13 +---- 7 files changed, 61 insertions(+), 35 deletions(-) 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 index c6bc10185..db5672af9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -319,4 +320,54 @@ public class FreemarkerConfiguration extends Configuration { } } + // ---------------------------------------------------------------------- + // Request info and overrides + // ---------------------------------------------------------------------- + + private ThreadLocal reqInfo = new ThreadLocal<>(); + + void setRequestInfo(HttpServletRequest req) { + reqInfo.set(new FreemarkerRequestInfo(req)); + } + + @Override + public Object getCustomAttribute(String name) { + if ("request".equals(name)) { + return reqInfo.get().getRequest(); + } else { + return super.getCustomAttribute(name); + } + } + + @Override + public String[] getCustomAttributeNames() { + String[] nameArray = super.getCustomAttributeNames(); + Set nameSet = new HashSet(Arrays.asList(nameArray)); + nameSet.add("request"); + return nameSet.toArray(new String[nameSet.size()]); + } + + @Override + public Locale getLocale() { + return reqInfo.get().getLocale(); + } + + + + public static class FreemarkerRequestInfo { + private final HttpServletRequest req; + + public FreemarkerRequestInfo(HttpServletRequest req) { + this.req = req; + } + + public HttpServletRequest getRequest() { + return req; + } + + public Locale getLocale() { + return req.getLocale(); + } + } + } 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 index b4e206181..340686d19 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java @@ -21,7 +21,9 @@ public class FreemarkerConfigurationLoader { public static FreemarkerConfiguration getConfig(VitroRequest vreq) { String themeDir = getThemeDir(vreq.getAppBean()); - return getConfigForTheme(themeDir, vreq.getAppBean(), vreq.getSession().getServletContext()); + FreemarkerConfiguration config = getConfigForTheme(themeDir, vreq.getAppBean(), vreq.getSession().getServletContext()); + config.setRequestInfo(vreq); + return config; } private static String getThemeDir(ApplicationBean appBean) { 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..52fb2f343 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 @@ -46,14 +46,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"); 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..1b3cd9a53 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java @@ -30,8 +30,6 @@ 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.TemplateException; /** @@ -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/services/freemarker/FreemarkerProcessingServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java index dfcc0156b..fde6152b1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java @@ -84,8 +84,6 @@ public class FreemarkerProcessingServiceImpl implements // 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) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/IndividualShortViewDirective.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/IndividualShortViewDirective.java index d12f5c0b7..fac33222c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/IndividualShortViewDirective.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/IndividualShortViewDirective.java @@ -77,10 +77,10 @@ public class IndividualShortViewDirective extends BaseTemplateDirectiveModel { private void renderShortView(Individual individual, ShortViewContext svContext) { Environment env = Environment.getCurrentEnvironment(); + HttpServletRequest request = (HttpServletRequest) env + .getCustomAttribute("request"); + ServletContext ctx = request.getSession().getServletContext(); - ServletContext ctx = (ServletContext) env.getCustomAttribute("context"); - VitroRequest vreq = new VitroRequest( - (HttpServletRequest) env.getCustomAttribute("request")); ShortViewService svs = ShortViewServiceSetup.getService(ctx); if (svs == null) { log.warn("ShortViewService was not initialized properly."); @@ -88,7 +88,7 @@ public class IndividualShortViewDirective extends BaseTemplateDirectiveModel { } TemplateAndSupplementalData svInfo = svs.getShortViewInfo(individual, - svContext, vreq); + svContext, new VitroRequest(request)); ObjectWrapper objectWrapper = env.getConfiguration().getObjectWrapper(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/Widget.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/Widget.java index e7e2741d5..9f82c1910 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/Widget.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/Widget.java @@ -10,7 +10,6 @@ import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; -import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; @@ -57,7 +56,7 @@ public abstract class Widget { public String doMarkup(Environment env, Map params) { HttpServletRequest request = (HttpServletRequest) env.getCustomAttribute("request"); - ServletContext context = (ServletContext) env.getCustomAttribute("context"); + ServletContext context = request.getSession().getServletContext(); WidgetTemplateValues values = null; @@ -120,15 +119,7 @@ public abstract class Widget { // We need to give each widget macro template a unique key in the StringTemplateLoader, and check // if it's already there or else add it. Leave this for later. Template template = new Template("widget", new StringReader(templateString), env.getConfiguration()); - - // JB KLUGE The widget is processed in its own environment, which doesn't include these custom attributes. - // JB KLUGE Put them in. - Environment widgetEnv = template.createProcessingEnvironment(map, out); - ServletRequest request = (ServletRequest) env.getCustomAttribute("request"); - widgetEnv.setCustomAttribute("request", request); - widgetEnv.setCustomAttribute("context", env.getCustomAttribute("context")); - widgetEnv.setLocale(request.getLocale()); - widgetEnv.process(); + template.process(map, out); } catch (Exception e) { log.error("Could not process widget " + widgetName, e); } From 7083d8acc4ab5eecc250d235280607e99cb6c76b Mon Sep 17 00:00:00 2001 From: j2blake Date: Mon, 5 Aug 2013 16:54:49 -0400 Subject: [PATCH 13/16] VIVO-246 Set up the Freemarker directives in only one place. --- .../freemarker/FreemarkerConfiguration.java | 8 +++++++- .../freemarker/FreemarkerHttpServlet.java | 4 ---- .../freemarker/FreemarkerProcessingServiceImpl.java | 13 +------------ 3 files changed, 8 insertions(+), 17 deletions(-) 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 index db5672af9..aa849ffdd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java @@ -29,6 +29,8 @@ 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.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; @@ -167,12 +169,16 @@ public class FreemarkerConfiguration extends Configuration { return urls; } - public static Map getDirectives() { + private 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()); + map.put("url", new UrlDirective()); + map.put("widget", new WidgetDirective()); + + return map; } 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..3cf0faeb0 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 @@ -427,10 +427,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/services/freemarker/FreemarkerProcessingServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java index fde6152b1..2f53a8459 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java @@ -13,10 +13,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.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; @@ -75,16 +73,7 @@ public class FreemarkerProcessingServiceImpl implements 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.process(); + template.process(map, writer); return writer.toString(); } catch (TemplateException e) { throw new TemplateProcessingException( From 969569c3851782b4cf6fdabdc90db656d1d548fd Mon Sep 17 00:00:00 2001 From: j2blake Date: Mon, 5 Aug 2013 17:10:55 -0400 Subject: [PATCH 14/16] VIVO-246 Continue cleanup --- .../webapp/controller/freemarker/FreemarkerConfiguration.java | 2 +- .../controller/freemarker/TemplateProcessingHelper.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) 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 index aa849ffdd..b358b87b6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java @@ -182,7 +182,7 @@ public class FreemarkerConfiguration extends Configuration { return map; } - public static Map getMethods() { + private static Map getMethods() { Map map = new HashMap(); map.put("profileUrl", new IndividualProfileUrlMethod()); map.put("localName", new IndividualLocalNameMethod()); 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 52fb2f343..828b09555 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 @@ -24,13 +24,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; } public StringWriter processTemplate(String templateName, Map map) From 98bb7236d11a40834a95446d805242b3c63968f7 Mon Sep 17 00:00:00 2001 From: tworrall Date: Tue, 6 Aug 2013 14:31:26 -0400 Subject: [PATCH 15/16] replaced reference to the sirceforge wiki with a reference to the duraspace wiki --- webapp/web/WEB-INF/resources/shortview_config.n3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/web/WEB-INF/resources/shortview_config.n3 b/webapp/web/WEB-INF/resources/shortview_config.n3 index ace0ff7ad..c4c2abfe4 100644 --- a/webapp/web/WEB-INF/resources/shortview_config.n3 +++ b/webapp/web/WEB-INF/resources/shortview_config.n3 @@ -9,5 +9,5 @@ # Ontology is complete. # # Find out how to use this file at -# https://sourceforge.net/apps/mediawiki/vivo/index.php?title=Using_Short_Views_in_Release_1.5 +# https://wiki.duraspace.org/display/VIVO/Using+Short+Views+in+Release+1.5 # From 3f061da0060ffde44b099d89900b27da14e5653b Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 8 Aug 2013 13:22:16 -0400 Subject: [PATCH 16/16] VIVO-246 Re-implement the FreemarkerConfiguration The Configuration must contain mutable information like the theme directory and the TemplateLoader. It must also be request-specific so it can have the correct Locale for language support. But we should only have one instance, so there is only one TemplateCache (alternatively, one TemplateCache per theme). Previously, this was addressed by intercepting the Template processing and adding the request-based info to the Environment. However, this interception code needed to appear each time a Template was processed. This was sometimes overlooked, and at best introduced a bunch of duplicated code. Instead, I extended the freemarker Configuration class to include a ThreadLocal that holds request-specific information. --- .../controller/ajax/VitroAjaxController.java | 6 +- .../FreemarkerComponentGenerator.java | 2 + .../freemarker/FreemarkerConfiguration.java | 379 ------------------ .../FreemarkerConfigurationLoader.java | 66 --- .../freemarker/FreemarkerHttpServlet.java | 4 +- .../freemarker/TemplateProcessingHelper.java | 8 +- .../VTwo/EditConfigurationUtils.java | 4 +- .../webapp/email/FreemarkerEmailFactory.java | 7 +- .../webapp/email/FreemarkerEmailMessage.java | 6 +- .../config/FreemarkerConfiguration.java | 293 ++++++++++++++ .../config/FreemarkerConfigurationImpl.java | 309 ++++++++++++++ .../FreemarkerProcessingServiceImpl.java | 6 +- .../individual/DataPropertyTemplateModel.java | 7 +- .../ObjectPropertyTemplateModel.java | 4 +- .../WEB-INF/resources/startup_listeners.txt | 1 + 15 files changed, 630 insertions(+), 472 deletions(-) delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java 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 b358b87b6..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java +++ /dev/null @@ -1,379 +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.Arrays; -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.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.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; - } - - private 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()); - map.put("url", new UrlDirective()); - map.put("widget", new WidgetDirective()); - - - return map; - } - - private 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 + "'"); - } - } - } - - // ---------------------------------------------------------------------- - // Request info and overrides - // ---------------------------------------------------------------------- - - private ThreadLocal reqInfo = new ThreadLocal<>(); - - void setRequestInfo(HttpServletRequest req) { - reqInfo.set(new FreemarkerRequestInfo(req)); - } - - @Override - public Object getCustomAttribute(String name) { - if ("request".equals(name)) { - return reqInfo.get().getRequest(); - } else { - return super.getCustomAttribute(name); - } - } - - @Override - public String[] getCustomAttributeNames() { - String[] nameArray = super.getCustomAttributeNames(); - Set nameSet = new HashSet(Arrays.asList(nameArray)); - nameSet.add("request"); - return nameSet.toArray(new String[nameSet.size()]); - } - - @Override - public Locale getLocale() { - return reqInfo.get().getLocale(); - } - - - - public static class FreemarkerRequestInfo { - private final HttpServletRequest req; - - public FreemarkerRequestInfo(HttpServletRequest req) { - this.req = req; - } - - public HttpServletRequest getRequest() { - return req; - } - - public Locale getLocale() { - return req.getLocale(); - } - } - -} 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 340686d19..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java +++ /dev/null @@ -1,66 +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()); - FreemarkerConfiguration config = getConfigForTheme(themeDir, vreq.getAppBean(), vreq.getSession().getServletContext()); - config.setRequestInfo(vreq); - return config; - } - - 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 3cf0faeb0..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 { 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 828b09555..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; @@ -26,7 +27,7 @@ public class TemplateProcessingHelper { private Configuration config = null; public TemplateProcessingHelper(HttpServletRequest request, ServletContext context) { - this.config = FreemarkerConfigurationLoader.getConfig(new VitroRequest(request)); + this.config = FreemarkerConfiguration.getConfig(request); } public StringWriter processTemplate(String templateName, Map map) @@ -50,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/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 1b3cd9a53..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,8 +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.template.Configuration; import freemarker.template.TemplateException; /** @@ -49,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; @@ -64,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; 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/services/freemarker/FreemarkerProcessingServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java index 2f53a8459..b6ccfd536 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java @@ -12,8 +12,7 @@ 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.FreemarkerConfigurationLoader; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils; import freemarker.core.ParseException; import freemarker.template.Configuration; @@ -51,8 +50,7 @@ public class FreemarkerProcessingServiceImpl implements throws TemplateProcessingException { Template template = null; try { - Configuration config = FreemarkerConfigurationLoader - .getConfig(new VitroRequest(req)); + Configuration config = FreemarkerConfiguration.getConfig(req); template = config.getTemplate(templateName); } catch (ParseException e) { log.warn("Failed to parse the template at '" + templateName + "'" diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java index f5036463c..b70c24818 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java @@ -5,8 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -21,13 +19,12 @@ import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.DataPropertyListConfig; import freemarker.cache.TemplateLoader; @@ -136,7 +133,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { } protected TemplateLoader getFreemarkerTemplateLoader() { - return FreemarkerConfigurationLoader.getConfig(vreq).getTemplateLoader(); + return FreemarkerConfiguration.getConfig(vreq).getTemplateLoader(); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java index 49e36d284..701ad0320 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java @@ -22,12 +22,12 @@ import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.PropertyListConfig; import freemarker.cache.TemplateLoader; @@ -152,7 +152,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel * This will do for now. */ protected TemplateLoader getFreemarkerTemplateLoader() { - return FreemarkerConfigurationLoader.getConfig(vreq).getTemplateLoader(); + return FreemarkerConfiguration.getConfig(vreq).getTemplateLoader(); } protected List> getStatementData() { diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index d7e47e9d9..7f83a702a 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -65,6 +65,7 @@ edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionSetup edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerSetup +edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration$Setup # On shutdown, this will kill the background thread started by Apache Commons File Upload org.apache.commons.fileupload.servlet.FileCleanerCleanup