From ebb31eb081a444795fb013fdc67efaaccc006a35 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Thu, 13 Nov 2014 17:11:11 -0500 Subject: [PATCH] VIVO-906 Assemble application at runtime. Create an object to represent VitroHomeDirectory Instantiate TripleSources, FileStorage, etc, based on the config file. --- webapp/build.xml | 6 + .../webapp/application/ApplicationImpl.java | 214 ++++++++++++++---- .../webapp/application/ApplicationSetup.java | 115 ++++++++++ .../webapp/application/ApplicationUtils.java | 5 +- .../webapp/application/BuildProperties.java | 54 +++++ .../application/VitroHomeDirectory.java | 213 +++++++++++++++++ .../config/ConfigurationPropertiesSetup.java | 173 +------------- .../ConfigurationPropertiesSmokeTests.java | 38 ---- .../freemarker/ContactMailController.java | 22 +- .../impl/FileStorageImplWrapper.java | 21 +- .../vitro/webapp/modules/Application.java | 11 + .../InstrumentedSearchEngineWrapper.java | 23 +- .../setup/ConfigurationModelsSetup.java | 5 +- .../servlet/setup/ContentModelSetup.java | 10 +- .../webapp/servlet/setup/FileGraphSetup.java | 4 +- .../webapp/servlet/setup/RDFFilesLoader.java | 22 +- .../servlet/setup/UpdateKnowledgeBase.java | 7 +- .../servlet/setup/rdfsetup/RDFSetup.java | 113 --------- .../utils/developer/DeveloperSettings.java | 10 +- .../developer/loggers/StackTraceUtility.java | 5 +- .../vitro/webapp/modules/ApplicationStub.java | 27 +++ .../WEB-INF/resources/startup_listeners.txt | 7 +- 22 files changed, 665 insertions(+), 440 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationSetup.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/application/BuildProperties.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/application/VitroHomeDirectory.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/rdfsetup/RDFSetup.java diff --git a/webapp/build.xml b/webapp/build.xml index f62e2d8dd..543ecf0c4 100644 --- a/webapp/build.xml +++ b/webapp/build.xml @@ -269,6 +269,12 @@ + + + + + + diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java index 6ecdf18f7..544340e00 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java @@ -2,21 +2,28 @@ package edu.cornell.mannlib.vitro.webapp.application; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService.CONFIGURATION; + import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageImplWrapper; -import edu.cornell.mannlib.vitro.webapp.imageprocessor.jai.JaiImageProcessor; +import com.hp.hpl.jena.ontology.OntDocumentManager; + +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage; import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; -import edu.cornell.mannlib.vitro.webapp.searchengine.InstrumentedSearchEngineWrapper; -import edu.cornell.mannlib.vitro.webapp.searchengine.solr.SolrSearchEngine; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; +import edu.cornell.mannlib.vitro.webapp.triplesource.impl.BasicCombinedTripleSource; import edu.cornell.mannlib.vitro.webapp.startup.ComponentStartupStatusImpl; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; /** * The basic implementation of the Application interface. @@ -26,12 +33,16 @@ public class ApplicationImpl implements Application { // The instance // ---------------------------------------------------------------------- - private final ServletContext ctx; + private ServletContext ctx; + private VitroHomeDirectory homeDirectory; + private SearchEngine searchEngine; private ImageProcessor imageProcessor; private FileStorage fileStorage; + private ContentTripleSource contentTripleSource; + private ConfigurationTripleSource configurationTripleSource; - public ApplicationImpl(ServletContext ctx) { + public void setServletContext(ServletContext ctx) { this.ctx = ctx; } @@ -40,13 +51,29 @@ public class ApplicationImpl implements Application { return ctx; } + @Override + public VitroHomeDirectory getHomeDirectory() { + return homeDirectory; + } + + public void setHomeDirectory(VitroHomeDirectory homeDirectory) { + this.homeDirectory = homeDirectory; + } + @Override public SearchEngine getSearchEngine() { return searchEngine; } - public void setSearchEngine(SearchEngine searchEngine) { - this.searchEngine = searchEngine; + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchEngine") + public void setSearchEngine(SearchEngine se) { + if (searchEngine == null) { + searchEngine = se; + } else { + throw new IllegalStateException( + "Configuration includes multiple SearchEngine instancess: " + + searchEngine + ", and " + se); + } } @Override @@ -54,8 +81,15 @@ public class ApplicationImpl implements Application { return imageProcessor; } - public void setImageProcessor(ImageProcessor imageProcessor) { - this.imageProcessor = imageProcessor; + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasImageProcessor") + public void setImageProcessor(ImageProcessor ip) { + if (imageProcessor == null) { + imageProcessor = ip; + } else { + throw new IllegalStateException( + "Configuration includes multiple ImageProcessor instancess: " + + imageProcessor + ", and " + ip); + } } @Override @@ -63,57 +97,151 @@ public class ApplicationImpl implements Application { return fileStorage; } - public void setFileStorage(FileStorage fileStorage) { - this.fileStorage = fileStorage; + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasFileStorage") + public void setFileStorage(FileStorage fs) { + if (fileStorage == null) { + fileStorage = fs; + } else { + throw new IllegalStateException( + "Configuration includes multiple FileStorage intances: " + + fileStorage + ", and " + fs); + } + } + + @Override + public ContentTripleSource getContentTripleSource() { + return contentTripleSource; + } + + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasContentTripleSource") + public void setContentTripleSource(ContentTripleSource source) { + if (contentTripleSource == null) { + contentTripleSource = source; + } else { + throw new IllegalStateException( + "Configuration includes multiple intances of ContentTripleSource: " + + contentTripleSource + ", and " + source); + } + } + + @Override + public ConfigurationTripleSource getConfigurationTripleSource() { + return configurationTripleSource; + } + + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource") + public void setConfigurationTripleSource(ConfigurationTripleSource source) { + if (configurationTripleSource == null) { + configurationTripleSource = source; + } else { + throw new IllegalStateException( + "Configuration includes multiple intances of ConfigurationTripleSource: " + + configurationTripleSource + ", and " + source); + } + } + + @Validation + public void validate() throws Exception { + if (searchEngine == null) { + throw new IllegalStateException( + "Configuration did not include a SearchEngine."); + } + if (imageProcessor == null) { + throw new IllegalStateException( + "Configuration did not include an ImageProcessor."); + } + if (fileStorage == null) { + throw new IllegalStateException( + "Configuration did not include a FileStorage."); + } + if (contentTripleSource == null) { + throw new IllegalStateException( + "Configuration did not include a ContentTripleSource."); + } + if (configurationTripleSource == null) { + throw new IllegalStateException( + "Configuration did not include a ConfigurationTripleSource."); + } + } + + @Override + public void shutdown() { + getFileStorage().shutdown(this); + getImageProcessor().shutdown(this); + getSearchEngine().shutdown(this); } // ---------------------------------------------------------------------- - // The Setup class. + // Setup the major components. + // + // This must happen after the ConfigurationProperties and some other stuff. // ---------------------------------------------------------------------- - public static class Setup implements ServletContextListener { - private ApplicationImpl application; - + public static class ComponentsSetup implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); + Application app = ApplicationUtils.instance(); StartupStatus ss = StartupStatus.getBean(ctx); + ComponentStartupStatus css = new ComponentStartupStatusImpl(this, + ss); - try { - application = new ApplicationImpl(ctx); - - ComponentStartupStatus css = new ComponentStartupStatusImpl( - this, ss); + SearchEngine searchEngine = app.getSearchEngine(); + searchEngine.startup(app, css); + ss.info(this, "Started the SearchEngine: " + searchEngine); - SearchEngine searchEngine = new InstrumentedSearchEngineWrapper( - new SolrSearchEngine()); - searchEngine.startup(application, css); - application.setSearchEngine(searchEngine); - ss.info(this, "Started the searchEngine: " + searchEngine); + ImageProcessor imageProcessor = app.getImageProcessor(); + imageProcessor.startup(app, css); + ss.info(this, "Started the ImageProcessor: " + imageProcessor); - ImageProcessor imageProcessor = new JaiImageProcessor(); - imageProcessor.startup(application, css); - application.setImageProcessor(imageProcessor); - ss.info(this, "Started the ImageProcessor: " + searchEngine); + FileStorage fileStorage = app.getFileStorage(); + fileStorage.startup(app, css); + ss.info(this, "Started the FileStorage system: " + fileStorage); - FileStorage fileStorage = new FileStorageImplWrapper(); - fileStorage.startup(application, css); - application.setFileStorage(fileStorage); - ss.info(this, "Started the FileStorage system: " + searchEngine); + ContentTripleSource contentTripleSource = app + .getContentTripleSource(); + contentTripleSource.startup(app, css); + ss.info(this, "Started the ContentTripleSource: " + + contentTripleSource); - ApplicationUtils.setInstance(application); - ss.info(this, "Appliation is configured."); - } catch (Exception e) { - ss.fatal(this, "Failed to initialize the Application.", e); - } + ConfigurationTripleSource configurationTripleSource = app + .getConfigurationTripleSource(); + configurationTripleSource.startup(app, css); + ss.info(this, "Started the ConfigurationTripleSource: " + + configurationTripleSource); + + configureJena(); + prepareCombinedTripleSource(app, ctx); + } + + private void configureJena() { + // we do not want to fetch imports when we wrap Models in OntModels + OntDocumentManager.getInstance().setProcessImports(false); + } + + private void prepareCombinedTripleSource(Application app, + ServletContext ctx) { + ContentTripleSource contentSource = app.getContentTripleSource(); + ConfigurationTripleSource configurationSource = app + .getConfigurationTripleSource(); + BasicCombinedTripleSource source = new BasicCombinedTripleSource( + contentSource, configurationSource); + + RDFServiceUtils.setRDFServiceFactory(ctx, + contentSource.getRDFServiceFactory()); + RDFServiceUtils.setRDFServiceFactory(ctx, + configurationSource.getRDFServiceFactory(), CONFIGURATION); + + ModelAccess.setCombinedTripleSource(source); } @Override public void contextDestroyed(ServletContextEvent sce) { - application.getFileStorage().shutdown(application); - application.getImageProcessor().shutdown(application); - application.getSearchEngine().shutdown(application); + Application app = ApplicationUtils.instance(); + app.getSearchEngine().shutdown(app); + app.getImageProcessor().shutdown(app); + app.getFileStorage().shutdown(app); } - } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationSetup.java new file mode 100644 index 000000000..21459ad3d --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationSetup.java @@ -0,0 +1,115 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.application; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; + +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoaderException; +import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel; + +/** + * Read the application setup file and create the components it describes. + */ +public class ApplicationSetup implements ServletContextListener { + private static final String APPLICATION_SETUP_PATH = "config/applicationSetup.n3"; + + private ServletContext ctx; + private StartupStatus ss; + + private ApplicationImpl app; + + private VitroHomeDirectory vitroHomeDir; + + private Path configFile; + private LockableModel configModel; + private ConfigurationBeanLoader loader; + + @Override + public void contextInitialized(ServletContextEvent sce) { + try { + this.ctx = sce.getServletContext(); + this.ss = StartupStatus.getBean(ctx); + + this.vitroHomeDir = VitroHomeDirectory.find(ctx); + ss.info(this, vitroHomeDir.getDiscoveryMessage()); + + locateApplicationConfigFile(); + loadApplicationConfigFile(); + createConfigurationBeanLoader(); + instantiateTheApplication(); + + app.setServletContext(this.ctx); + app.setHomeDirectory(this.vitroHomeDir); + + ApplicationUtils.setInstance(app); + ss.info(this, "Application is configured."); + } catch (Exception e) { + ss.fatal(this, "Failed to initialize the Application.", e); + } + } + + private void locateApplicationConfigFile() { + Path path = this.vitroHomeDir.getPath().resolve(APPLICATION_SETUP_PATH); + if (!Files.exists(path)) { + throw new IllegalStateException("'" + path + "' does not exist."); + } + if (!Files.isReadable(path)) { + throw new IllegalStateException("Can't read '" + path + "'"); + } + this.configFile = path; + } + + private void loadApplicationConfigFile() { + try (InputStream in = Files.newInputStream(this.configFile)) { + Model m = ModelFactory.createDefaultModel(); + m.read(in, null, "N3"); + this.configModel = new LockableModel(m); + } catch (Exception e) { + throw new RuntimeException("Failed to read '" + this.configFile + + "'", e); + } + } + + private void createConfigurationBeanLoader() { + this.loader = new ConfigurationBeanLoader(configModel); + } + + private void instantiateTheApplication() { + try { + Set apps = loader.loadAll(ApplicationImpl.class); + if (apps.isEmpty()) { + throw new IllegalStateException("'" + this.configFile + + "' does not define an instance of " + + ApplicationImpl.class.getName()); + } else if (apps.size() > 1) { + throw new IllegalStateException("'" + this.configFile + + "' defines " + apps.size() + " instances of " + + ApplicationImpl.class.getName()); + } else { + this.app = apps.iterator().next(); + } + } catch (ConfigurationBeanLoaderException e) { + throw new IllegalStateException("Failed to setup the application", + e); + } + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + if (app != null) { + app.shutdown(); + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationUtils.java index 01097e579..90b44f665 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationUtils.java @@ -12,7 +12,7 @@ import edu.cornell.mannlib.vitro.webapp.modules.Application; */ public class ApplicationUtils { private static final Log log = LogFactory.getLog(ApplicationUtils.class); - + private static volatile Application instance; public static Application instance() { @@ -25,9 +25,8 @@ public class ApplicationUtils { "Called for Application before it was available", e); } } - + static void setInstance(Application application) { instance = application; } - } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/BuildProperties.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/BuildProperties.java new file mode 100644 index 000000000..19438b13f --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/BuildProperties.java @@ -0,0 +1,54 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.application; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Obtains and provides the contents of the build.properties file. + */ +public class BuildProperties { + private static final Log log = LogFactory.getLog(BuildProperties.class); + + /** Path to the file of build properties baked into the webapp. */ + public static final String WEBAPP_PATH_BUILD_PROPERTIES = "/WEB-INF/resources/build.properties"; + + private final Map propertyMap; + + public BuildProperties(ServletContext ctx) { + Map map = new HashMap<>(); + + try (InputStream stream = ctx + .getResourceAsStream(WEBAPP_PATH_BUILD_PROPERTIES)) { + if (stream == null) { + log.debug("Didn't find a resource at '" + + WEBAPP_PATH_BUILD_PROPERTIES + "'."); + } else { + Properties props = new Properties(); + props.load(stream); + for (String key : props.stringPropertyNames()) { + map.put(key, props.getProperty(key)); + } + } + } catch (IOException e) { + throw new RuntimeException("Failed to load from '" + + WEBAPP_PATH_BUILD_PROPERTIES + "'.", e); + } + propertyMap = Collections.unmodifiableMap(map); + } + + public Map getMap() { + return this.propertyMap; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/VitroHomeDirectory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/VitroHomeDirectory.java new file mode 100644 index 000000000..5ddb53f54 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/VitroHomeDirectory.java @@ -0,0 +1,213 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.application; + +import static edu.cornell.mannlib.vitro.webapp.application.BuildProperties.WEBAPP_PATH_BUILD_PROPERTIES; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.naming.InitialContext; +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Encapsulates some of the info relating to the Vitro home directory. + */ +public class VitroHomeDirectory { + private static final Log log = LogFactory.getLog(VitroHomeDirectory.class); + + public static VitroHomeDirectory find(ServletContext ctx) { + HomeDirectoryFinder finder = new HomeDirectoryFinder(ctx); + return new VitroHomeDirectory(ctx, finder.getPath(), + finder.getMessage()); + } + + private final ServletContext ctx; + private final Path path; + private final String discoveryMessage; + + public VitroHomeDirectory(ServletContext ctx, Path path, + String discoveryMessage) { + this.ctx = ctx; + this.path = path; + this.discoveryMessage = discoveryMessage; + } + + public ServletContext getCtx() { + return ctx; + } + + public Path getPath() { + return path; + } + + public String getDiscoveryMessage() { + return discoveryMessage; + } + + /** + * Find something that specifies the location of the Vitro home directory. + * Look in the JDNI environment, the system properties, and the + * build.properties file. + * + * If we don't find it, fail. If we find it more than once, use the first + * one (with a warning). If it is not an existing, readable directory, fail. + */ + private static class HomeDirectoryFinder { + /** JNDI path that defines the Vitro home directory */ + private static final String VHD_JNDI_PATH = "java:comp/env/vitro/home"; + + /** System property that defines the Vitro home directory */ + private static final String VHD_SYSTEM_PROPERTY = "vitro.home"; + + /** build.properties property that defines the Vitro home directory */ + private static final String VHD_BUILD_PROPERTY = "vitro.home"; + + private final ServletContext ctx; + private final List foundLocations = new ArrayList<>(); + + public HomeDirectoryFinder(ServletContext ctx) { + this.ctx = ctx; + + getVhdFromJndi(); + getVhdFromSystemProperties(); + getVhdFromBuildProperties(); + confirmExactlyOneResult(); + confirmValidDirectory(); + } + + public String getMessage() { + return foundLocations.get(0).getMessage(); + } + + public Path getPath() { + return foundLocations.get(0).getPath(); + } + + public void getVhdFromJndi() { + try { + String vhdPath = (String) new InitialContext() + .lookup(VHD_JNDI_PATH); + if (vhdPath == null) { + log.debug("Didn't find a JNDI value at '" + VHD_JNDI_PATH + + "'."); + } else { + log.debug("'" + VHD_JNDI_PATH + "' as specified by JNDI: " + + vhdPath); + String message = String.format( + "JNDI environment '%s' was set to '%s'", + VHD_JNDI_PATH, vhdPath); + foundLocations.add(new Found(Paths.get(vhdPath), message)); + } + } catch (Exception e) { + log.debug("JNDI lookup failed. " + e); + } + } + + private void getVhdFromSystemProperties() { + String vhdPath = System.getProperty(VHD_SYSTEM_PROPERTY); + if (vhdPath == null) { + log.debug("Didn't find a system property value at '" + + VHD_SYSTEM_PROPERTY + "'."); + } else { + log.debug("'" + VHD_SYSTEM_PROPERTY + + "' as specified by system property: " + vhdPath); + String message = String.format( + "System property '%s' was set to '%s'", + VHD_SYSTEM_PROPERTY, vhdPath); + foundLocations.add(new Found(Paths.get(vhdPath), message)); + } + } + + private void getVhdFromBuildProperties() { + try { + Map buildProps = new BuildProperties(ctx) + .getMap(); + String vhdPath = buildProps.get(VHD_BUILD_PROPERTY); + if (vhdPath == null) { + log.debug("build properties doesn't contain a value for '" + + VHD_BUILD_PROPERTY + "'."); + } else { + log.debug("'" + VHD_BUILD_PROPERTY + + "' as specified by build.properties: " + vhdPath); + String message = String.format( + "In resource '%s', '%s' was set to '%s'.", + WEBAPP_PATH_BUILD_PROPERTIES, VHD_BUILD_PROPERTY, + vhdPath); + foundLocations.add(new Found(Paths.get(vhdPath), message)); + } + } catch (Exception e) { + log.warn("Reading build properties failed. " + e); + } + } + + private void confirmExactlyOneResult() { + if (foundLocations.isEmpty()) { + String message = String.format("Can't find a value " + + "for the Vitro home directory. " + + "Looked in JNDI environment at '%s'. " + + "Looked for a system property named '%s'. " + + "Looked in 'WEB-INF/resources/build.properties' " + + "for '%s'.", VHD_JNDI_PATH, VHD_SYSTEM_PROPERTY, + VHD_BUILD_PROPERTY); + throw new IllegalStateException(message); + } else if (foundLocations.size() > 1) { + String message = String.format("Found multiple values for the " + + "Vitro home directory: " + foundLocations); + log.warn(message); + } + } + + private void confirmValidDirectory() { + Path vhd = getPath(); + if (!Files.exists(vhd)) { + throw new IllegalStateException("Vitro home directory '" + vhd + + "' does not exist."); + } + if (!Files.isDirectory(vhd)) { + throw new IllegalStateException("Vitro home directory '" + vhd + + "' is not a directory."); + } + if (!Files.isReadable(vhd)) { + throw new IllegalStateException( + "Cannot read Vitro home directory '" + vhd + "'."); + } + if (!Files.isWritable(vhd)) { + throw new IllegalStateException( + "Can't write to Vitro home directory: '" + vhd + "'."); + } + } + + /** We found it: where and how. */ + private static class Found { + private final Path path; + private final String message; + + public Found(Path path, String message) { + this.path = path; + this.message = message; + } + + public Path getPath() { + return path; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "Found[path=" + path + ", message=" + message + "]"; + } + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java index 410e9e76b..3ba0cd937 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java @@ -7,12 +7,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Map; -import java.util.Properties; -import javax.naming.InitialContext; -import javax.naming.NamingException; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; @@ -20,6 +16,8 @@ import javax.servlet.ServletContextListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; +import edu.cornell.mannlib.vitro.webapp.application.BuildProperties; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** @@ -48,23 +46,11 @@ public class ConfigurationPropertiesSetup implements ServletContextListener { private static final Log log = LogFactory .getLog(ConfigurationPropertiesSetup.class); - /** JNDI path that defines the Vitro home directory */ - private static final String VHD_JNDI_PATH = "java:comp/env/vitro/home"; - - /** System property that defines the Vitro home directory */ - private static final String VHD_SYSTEM_PROPERTY = "vitro.home"; - - /** build.properties property that defines the Vitro home directory */ - private static final String VHD_BUILD_PROPERTY = "vitro.home"; - - /** Configuration property to store the Vitro home directory */ - private static final String VHD_CONFIGURATION_PROPERTY = "vitro.home"; - /** Name of the file that contains runtime properties. */ private static final String FILE_RUNTIME_PROPERTIES = "runtime.properties"; - /** Path to the file of build properties baked into the webapp. */ - private static final String PATH_BUILD_PROPERTIES = "/WEB-INF/resources/build.properties"; + /** Configuration property to store the Vitro home directory */ + private static final String VHD_CONFIGURATION_PROPERTY = "vitro.home"; @Override public void contextInitialized(ServletContextEvent sce) { @@ -74,7 +60,8 @@ public class ConfigurationPropertiesSetup implements ServletContextListener { try { InputStream stream = null; try { - File vitroHomeDir = locateVitroHomeDirectory(ctx, ss); + File vitroHomeDir = ApplicationUtils.instance() + .getHomeDirectory().getPath().toFile(); File runtimePropertiesFile = locateRuntimePropertiesFile( vitroHomeDir, ss); @@ -82,9 +69,9 @@ public class ConfigurationPropertiesSetup implements ServletContextListener { Map preempts = createPreemptiveProperties( VHD_CONFIGURATION_PROPERTY, vitroHomeDir); - + ConfigurationPropertiesImpl bean = new ConfigurationPropertiesImpl( - stream, preempts, getBuildProperties(ctx)); + stream, preempts, new BuildProperties(ctx).getMap()); ConfigurationProperties.setBean(ctx, bean); ss.info(this, "Loaded " + bean.getPropertyMap().size() @@ -103,141 +90,6 @@ public class ConfigurationPropertiesSetup implements ServletContextListener { } } - /** - * Look in the JDNI environment, the system properties, and the - * build.properties file. - * - * If we don't find it, fail. If we find it more than once, warn and use the - * first one. - * - * Confirm that it is an existing, readable directory. - */ - private File locateVitroHomeDirectory(ServletContext ctx, StartupStatus ss) { - Map whereWasIt = new LinkedHashMap(); - getVhdFromJndi(whereWasIt); - getVhdFromSystemProperties(whereWasIt); - getVhdFromBuildProperties(ctx, whereWasIt); - - if (whereWasIt.isEmpty()) { - String message = String.format("Can't find a value " - + "for the Vitro home directory. " - + "Looked in JNDI environment at '%s'. " - + "Looked for a system property named '%s'. " - + "Looked in 'WEB-INF/resources/build.properties' " - + "for '%s'.", VHD_JNDI_PATH, VHD_SYSTEM_PROPERTY, - VHD_BUILD_PROPERTY); - throw new IllegalStateException(message); - } else if (whereWasIt.size() > 1) { - String message = String.format("Found multiple values for the " - + "Vitro home directory: " + whereWasIt.keySet()); - ss.warning(this, message); - } - String message = whereWasIt.keySet().iterator().next(); - String vhdPath = whereWasIt.values().iterator().next(); - - ss.info(this, message); - - File vhd = new File(vhdPath); - if (!vhd.exists()) { - throw new IllegalStateException("Vitro home directory '" + vhdPath - + "' does not exist."); - } - if (!vhd.isDirectory()) { - throw new IllegalStateException("Vitro home directory '" + vhdPath - + "' is not a directory."); - } - if (!vhd.canRead()) { - throw new IllegalStateException("Vitro home directory '" + vhdPath - + "' cannot be read."); - } - if (!vhd.canWrite()) { - throw new IllegalStateException( - "Can't write to Vitro home directory: '" + vhdPath + "'."); - } - - return vhd; - } - - private void getVhdFromJndi(Map whereWasIt) { - try { - String vhdPath = (String) new InitialContext() - .lookup(VHD_JNDI_PATH); - - if (vhdPath == null) { - log.debug("Didn't find a JNDI value at '" + VHD_JNDI_PATH - + "'."); - return; - } - - log.debug("'" + VHD_JNDI_PATH + "' as specified by JNDI: " - + vhdPath); - String message = String.format( - "JNDI environment '%s' was set to '%s'", VHD_JNDI_PATH, - vhdPath); - whereWasIt.put(message, vhdPath); - } catch (NamingException e) { - log.debug("JNDI lookup failed. " + e); - } - } - - private void getVhdFromSystemProperties(Map whereWasIt) { - String vhdPath = System.getProperty(VHD_SYSTEM_PROPERTY); - - if (vhdPath == null) { - log.debug("Didn't find a system property value at '" - + VHD_SYSTEM_PROPERTY + "'."); - return; - } - - log.debug("'" + VHD_SYSTEM_PROPERTY - + "' as specified by system property: " + vhdPath); - String message = String.format("System property '%s' was set to '%s'", - VHD_SYSTEM_PROPERTY, vhdPath); - whereWasIt.put(message, vhdPath); - } - - private void getVhdFromBuildProperties(ServletContext ctx, - Map whereWasIt) { - Map buildProps = getBuildProperties(ctx); - String vhdPath = buildProps.get(VHD_BUILD_PROPERTY); - if (vhdPath == null) { - log.debug("'" + PATH_BUILD_PROPERTIES - + "' didn't contain a value for '" + VHD_BUILD_PROPERTY - + "'."); - return; - } - - log.debug("'" + VHD_BUILD_PROPERTY - + "' as specified by build.properties: " + vhdPath); - String message = String.format( - "In resource '%s', '%s' was set to '%s'.", - PATH_BUILD_PROPERTIES, VHD_BUILD_PROPERTY, vhdPath); - whereWasIt.put(message, vhdPath); - } - - private Map getBuildProperties(ServletContext ctx) { - Map map = new HashMap<>(); - - try (InputStream stream = ctx - .getResourceAsStream(PATH_BUILD_PROPERTIES)) { - if (stream == null) { - log.debug("Didn't find a resource at '" + PATH_BUILD_PROPERTIES - + "'."); - } else { - - Properties props = new Properties(); - props.load(stream); - for (String key : props.stringPropertyNames()) { - map.put(key, props.getProperty(key)); - } - } - } catch (IOException e) { - throw new SetupException("Failed to load from '" - + PATH_BUILD_PROPERTIES + "'.", e); - } - return map; - } - private File locateRuntimePropertiesFile(File vitroHomeDir, StartupStatus ss) { File rpf = new File(vitroHomeDir, FILE_RUNTIME_PROPERTIES); @@ -270,13 +122,4 @@ public class ConfigurationPropertiesSetup implements ServletContextListener { // No need to remove the bean. It's only a map of strings, and if we // restart the app, it will be replaced. } - - /** - * Indicates a problem setting up. Abandon ship. - */ - private static class SetupException extends RuntimeException { - public SetupException(String message, Throwable cause) { - super(message, cause); - } - } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java index 604881b2c..31e21da32 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java @@ -25,7 +25,6 @@ public class ConfigurationPropertiesSmokeTests implements private static final Log log = LogFactory .getLog(ConfigurationPropertiesSmokeTests.class); - private static final String PROPERTY_HOME_DIRECTORY = "vitro.home"; private static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace"; private static final String PROPERTY_LANGUAGE_BUILD = "languages.addToBuild"; private static final String PROPERTY_LANGUAGE_SELECTABLE = "languages.selectableLocales"; @@ -38,47 +37,10 @@ public class ConfigurationPropertiesSmokeTests implements ConfigurationProperties props = ConfigurationProperties.getBean(ctx); StartupStatus ss = StartupStatus.getBean(ctx); - checkHomeDirectory(ctx, props, ss); checkDefaultNamespace(ctx, props, ss); checkLanguages(props, ss); } - /** - * Confirm that: a home directory has been specified; it exists; it is a - * directory; it is readable and writable. - */ - private void checkHomeDirectory(ServletContext ctx, - ConfigurationProperties props, StartupStatus ss) { - String homeDirectoryPath = props.getProperty(PROPERTY_HOME_DIRECTORY); - if (homeDirectoryPath == null || homeDirectoryPath.isEmpty()) { - ss.fatal(this, "Can't find a value for the home directory: '" - + PROPERTY_HOME_DIRECTORY + "'"); - return; - } - - File homeDirectory = new File(homeDirectoryPath); - if (!homeDirectory.exists()) { - ss.fatal(this, PROPERTY_HOME_DIRECTORY + " '" + homeDirectoryPath - + "' does not exist."); - return; - } - if (!homeDirectory.isDirectory()) { - ss.fatal(this, PROPERTY_HOME_DIRECTORY + " '" + homeDirectoryPath - + "' is not a directory."); - return; - } - - if (!homeDirectory.canRead()) { - ss.fatal(this, PROPERTY_HOME_DIRECTORY + " '" + homeDirectoryPath - + "' cannot be read."); - } - if (!homeDirectory.canWrite()) { - ss.fatal(this, PROPERTY_HOME_DIRECTORY + " '" + homeDirectoryPath - + "' cannot be written to."); - } - } - - /** * Confirm that the default namespace is specified and a syntactically valid * URI. It should also end with "/individual/". diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ContactMailController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ContactMailController.java index a48d040f0..4a275a607 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ContactMailController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ContactMailController.java @@ -25,8 +25,8 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; -import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.TemplateProcessingHelper.TemplateProcessingException; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; @@ -50,7 +50,6 @@ public class ContactMailController extends FreemarkerHttpServlet { private final static String TEMPLATE_ERROR = "contactForm-error.ftl"; private final static String TEMPLATE_FORM = "contactForm-form.ftl"; - private static final String PROPERTY_VITRO_HOME_DIR = "vitro.home"; private static final String EMAIL_JOURNAL_FILE_DIR = "emailJournal"; private static final String EMAIL_JOURNAL_FILE_NAME = "contactFormEmails.html"; @@ -116,7 +115,7 @@ public class ContactMailController extends FreemarkerHttpServlet { try { // Write the message to the journal file - FileWriter fw = new FileWriter(locateTheJournalFile(vreq),true); + FileWriter fw = new FileWriter(locateTheJournalFile(), true); PrintWriter outFile = new PrintWriter(fw); writeBackupCopy(outFile, msgText, vreq); @@ -159,21 +158,8 @@ public class ContactMailController extends FreemarkerHttpServlet { * The journal file belongs in a sub-directory of the Vitro home directory. * If the sub-directory doesn't exist, create it. */ - private File locateTheJournalFile(VitroRequest vreq) { - String homeDirPath = ConfigurationProperties.getBean(vreq).getProperty( - PROPERTY_VITRO_HOME_DIR); - if (homeDirPath == null) { - throw new IllegalArgumentException( - "Configuration properties must contain a value for '" - + PROPERTY_VITRO_HOME_DIR + "'"); - } - - File homeDir = new File(homeDirPath); - if (!homeDir.exists()) { - throw new IllegalStateException("Vitro home directory '" - + homeDir.getAbsolutePath() + "' does not exist."); - } - + private File locateTheJournalFile() { + File homeDir = ApplicationUtils.instance().getHomeDirectory().getPath().toFile(); File journalDir = new File(homeDir, EMAIL_JOURNAL_FILE_DIR); if (!journalDir.exists()) { boolean created = journalDir.mkdir(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/impl/FileStorageImplWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/impl/FileStorageImplWrapper.java index e3934428a..51254f1fd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/impl/FileStorageImplWrapper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/impl/FileStorageImplWrapper.java @@ -11,6 +11,7 @@ import java.util.Collections; import javax.servlet.ServletContext; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; @@ -22,7 +23,6 @@ import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage; */ public class FileStorageImplWrapper implements FileStorage { public static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace"; - public static final String PROPERTY_VITRO_HOME_DIR = "vitro.home"; public static final String FILE_STORAGE_SUBDIRECTORY = "uploads"; private FileStorageImpl fs; @@ -35,7 +35,7 @@ public class FileStorageImplWrapper implements FileStorage { ServletContext ctx = application.getServletContext(); try { - File baseDirectory = figureBaseDir(ctx); + File baseDirectory = figureBaseDir(); Collection fileNamespace = confirmDefaultNamespace(ctx); fs = new FileStorageImpl(baseDirectory, fileNamespace); } catch (Exception e) { @@ -47,21 +47,8 @@ public class FileStorageImplWrapper implements FileStorage { * Get the configuration property for the file storage base directory, and * check that it points to an existing, writeable directory. */ - private File figureBaseDir(ServletContext ctx) throws IOException { - String homeDirPath = ConfigurationProperties.getBean(ctx).getProperty( - PROPERTY_VITRO_HOME_DIR); - if (homeDirPath == null) { - throw new IllegalArgumentException( - "Configuration properties must contain a value for '" - + PROPERTY_VITRO_HOME_DIR + "'"); - } - - File homeDir = new File(homeDirPath); - if (!homeDir.exists()) { - throw new IllegalStateException("Vitro home directory '" - + homeDir.getAbsolutePath() + "' does not exist."); - } - + private File figureBaseDir() throws IOException { + File homeDir = ApplicationUtils.instance().getHomeDirectory().getPath().toFile(); File baseDir = new File(homeDir, FILE_STORAGE_SUBDIRECTORY); if (!baseDir.exists()) { boolean created = baseDir.mkdir(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java index a03016061..2708634f3 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java @@ -4,21 +4,32 @@ package edu.cornell.mannlib.vitro.webapp.modules; import javax.servlet.ServletContext; +import edu.cornell.mannlib.vitro.webapp.application.VitroHomeDirectory; import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage; import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; /** * The interface that holds the modules and extensions together. */ public interface Application { ServletContext getServletContext(); + + VitroHomeDirectory getHomeDirectory(); SearchEngine getSearchEngine(); ImageProcessor getImageProcessor(); FileStorage getFileStorage(); + + ContentTripleSource getContentTripleSource(); + + ConfigurationTripleSource getConfigurationTripleSource(); + + void shutdown(); public interface Component { enum LifecycleState { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java index 137506630..e4e88bbed 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java @@ -18,6 +18,8 @@ import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngineExcepti import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchInputDocument; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchQuery; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResponse; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; /** * Manages the life-cycle of the SearchEngine. Adds logging, controlled by @@ -27,17 +29,30 @@ public class InstrumentedSearchEngineWrapper implements SearchEngine { private static final Log log = LogFactory .getLog(InstrumentedSearchEngineWrapper.class); - private final SearchEngine innerEngine; + private SearchEngine innerEngine; private volatile LifecycleState lifecycleState = NEW; - public InstrumentedSearchEngineWrapper(SearchEngine innerEngine) { + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#wraps") + public void setInnerEngine(SearchEngine inner) { if (innerEngine == null) { - throw new NullPointerException("innerEngine may not be null."); + innerEngine = inner; + } else { + throw new IllegalStateException( + "Configuration includes multiple SearchEngine instancess: " + + innerEngine + ", and " + inner); } - this.innerEngine = innerEngine; } + @Validation + public void validate() throws Exception { + if (innerEngine == null) { + throw new IllegalStateException( + "Configuration did not include a wrapped SearchEngine."); + } + } + + /** * Complain unless ACTIVE. */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java index b195f65eb..e728fb7c2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java @@ -52,13 +52,12 @@ public class ConfigurationModelsSetup implements ServletContextListener { private void loadFirstTimeFiles(ServletContext ctx, String modelPath, OntModel baseModel) { - RDFFilesLoader.loadFirstTimeFiles(ctx, modelPath, baseModel, - baseModel.isEmpty()); + RDFFilesLoader.loadFirstTimeFiles(modelPath, baseModel, baseModel.isEmpty()); } private void loadEveryTimeFiles(ServletContext ctx, String modelPath, OntModel memoryModel) { - RDFFilesLoader.loadEveryTimeFiles(ctx, modelPath, memoryModel); + RDFFilesLoader.loadEveryTimeFiles(modelPath, memoryModel); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java index 2f8eb399c..3919aa069 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java @@ -62,13 +62,13 @@ public class ContentModelSetup extends JenaDataSourceSetupBase if (isFirstStartup()) { initializeApplicationMetadata(ctx, applicationMetadataModel); - RDFFilesLoader.loadFirstTimeFiles(ctx, "abox", baseABoxModel, true); - RDFFilesLoader.loadFirstTimeFiles(ctx, "tbox", baseTBoxModel, true); + RDFFilesLoader.loadFirstTimeFiles("abox", baseABoxModel, true); + RDFFilesLoader.loadFirstTimeFiles("tbox", baseTBoxModel, true); } else { checkForNamespaceMismatch( applicationMetadataModel, ctx ); } - RDFFilesLoader.loadEveryTimeFiles(ctx, "abox", baseABoxModel); - RDFFilesLoader.loadEveryTimeFiles(ctx, "tbox", baseTBoxModel); + RDFFilesLoader.loadEveryTimeFiles("abox", baseABoxModel); + RDFFilesLoader.loadEveryTimeFiles("tbox", baseTBoxModel); log.info("Setting up DAO factories"); } @@ -89,7 +89,7 @@ public class ContentModelSetup extends JenaDataSourceSetupBase private void initializeApplicationMetadata(ServletContext ctx, Model applicationMetadataModel) { OntModel temporaryAMModel = VitroModelFactory.createOntologyModel(); - RDFFilesLoader.loadFirstTimeFiles(ctx, "applicationMetadata", temporaryAMModel, true); + RDFFilesLoader.loadFirstTimeFiles("applicationMetadata", temporaryAMModel, true); setPortalUriOnFirstTime(temporaryAMModel, ctx); applicationMetadataModel.add(temporaryAMModel); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java index 402804e63..555e598fe 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java @@ -33,6 +33,7 @@ import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.ModelMaker; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.dao.jena.BlankNodeFilteringModelMaker; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; @@ -49,7 +50,6 @@ public class FileGraphSetup implements ServletContextListener { private static final String ABOX = "abox"; private static final String TBOX = "tbox"; private static final String FILEGRAPH = "filegraph"; - private static final String PROPERTY_VITRO_HOME = "vitro.home"; public static final String FILEGRAPH_URI_ROOT = "http://vitro.mannlib.cornell.edu/filegraph/"; @@ -119,7 +119,7 @@ public class FileGraphSetup implements ServletContextListener { StartupStatus ss = StartupStatus.getBean(ctx); ConfigurationProperties props = ConfigurationProperties.getBean(ctx); - String homeDirProperty = props.getProperty(PROPERTY_VITRO_HOME); + String homeDirProperty = ApplicationUtils.instance().getHomeDirectory().getPath().toString(); Path filegraphDir = Paths.get(homeDirProperty, strings); Set paths = new TreeSet<>(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java index 89b6dbfe6..aa37f3e63 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java @@ -13,8 +13,6 @@ import java.nio.file.Paths; import java.util.Set; import java.util.TreeSet; -import javax.servlet.ServletContext; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,7 +21,7 @@ import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; -import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; /** * Help to load RDF files on first time and on every startup. @@ -31,7 +29,6 @@ import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; public class RDFFilesLoader { private static final Log log = LogFactory.getLog(RDFFilesLoader.class); - private static final String PROPERTY_VITRO_HOME = "vitro.home"; private static final String DEFAULT_RDF_FORMAT = "RDF/XML"; private static final String RDF = "rdf"; private static final String FIRST_TIME = "firsttime"; @@ -61,10 +58,10 @@ public class RDFFilesLoader { * * The files from the directory are added to the model. */ - public static void loadFirstTimeFiles(ServletContext ctx, String modelPath, - Model model, boolean firstTime) { + public static void loadFirstTimeFiles(String modelPath, Model model, + boolean firstTime) { if (firstTime) { - Set paths = getPaths(locateHomeDirectory(ctx), RDF, + Set paths = getPaths(locateHomeDirectory(), RDF, modelPath, FIRST_TIME); for (Path p : paths) { readOntologyFileIntoModel(p, model); @@ -83,11 +80,10 @@ public class RDFFilesLoader { * * The files from the directory become a sub-model of the model. */ - public static void loadEveryTimeFiles(ServletContext ctx, String modelPath, - OntModel model) { + public static void loadEveryTimeFiles(String modelPath, OntModel model) { OntModel everytimeModel = ModelFactory .createOntologyModel(OntModelSpec.OWL_MEM); - String home = locateHomeDirectory(ctx); + String home = locateHomeDirectory(); Set paths = getPaths(home, RDF, modelPath, EVERY_TIME); for (Path p : paths) { log.info("Loading " + relativePath(p, home)); @@ -177,9 +173,9 @@ public class RDFFilesLoader { return DEFAULT_RDF_FORMAT; } - private static String locateHomeDirectory(ServletContext ctx) { - return ConfigurationProperties.getBean(ctx).getProperty( - PROPERTY_VITRO_HOME); + private static String locateHomeDirectory() { + return ApplicationUtils.instance().getHomeDirectory().getPath() + .toString(); } /** 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 b2482eb94..d7931035e 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 @@ -13,7 +13,6 @@ 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.Arrays; @@ -44,6 +43,7 @@ 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.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; @@ -98,7 +98,7 @@ public class UpdateKnowledgeBase implements ServletContextListener { settings.setUnionOntModelSelector(ModelAccess.on(ctx).getOntModelSelector()); ConfigurationProperties props = ConfigurationProperties.getBean(ctx); - Path homeDir = Paths.get(props.getProperty("vitro.home")); + Path homeDir = ApplicationUtils.instance().getHomeDirectory().getPath(); settings.setDisplayModel(ModelAccess.on(ctx).getOntModel(DISPLAY)); OntModel oldTBoxModel = loadModelFromDirectory(ctx.getRealPath(OLD_TBOX_MODEL_DIR)); settings.setOldTBoxModel(oldTBoxModel); @@ -202,8 +202,7 @@ public class UpdateKnowledgeBase implements ServletContextListener { * 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 homeDir = ApplicationUtils.instance().getHomeDirectory().getPath(); Path dataDir = createDirectory(homeDir, "upgrade", "knowledgeBase"); settings.setDataDir(dataDir.toString()); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/rdfsetup/RDFSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/rdfsetup/RDFSetup.java deleted file mode 100644 index 00fb71fd4..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/rdfsetup/RDFSetup.java +++ /dev/null @@ -1,113 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup; - -import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService.CONFIGURATION; -import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sparql.ContentDataStructuresProviderSPARQL.PROPERTY_SPARQL_ENDPOINT_URI; -import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.tdb.ContentDataStructuresProviderTDB.PROPERTY_CONTENT_TDB_PATH; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.hp.hpl.jena.ontology.OntDocumentManager; - -import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; -import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; -import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.BasicDataStructuresProvider; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.ConfigurationDataStructuresProvider; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.ContentDataStructuresProvider; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.ContentDataStructuresProviderSDB; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sparql.ContentDataStructuresProviderSPARQL; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.tdb.ConfigurationDataStructuresProviderTDB; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.tdb.ContentDataStructuresProviderTDB; - -/** - * Create the RDFServiceFactories and ModelMakers for the application to use. - */ -public class RDFSetup implements ServletContextListener { - private static final Log log = LogFactory.getLog(RDFSetup.class); - - private ServletContext ctx; - private ConfigurationProperties configProps; - - private ContentDataStructuresProvider contentProvider; - private ConfigurationDataStructuresProvider configurationProvider; - private BasicDataStructuresProvider provider; - - @Override - public void contextInitialized(ServletContextEvent sce) { - this.ctx = sce.getServletContext(); - this.configProps = ConfigurationProperties.getBean(ctx); - - configureJena(); - - createProviders(); - - RDFServiceUtils.setRDFServiceFactory(ctx, - contentProvider.getRDFServiceFactory()); - RDFServiceUtils.setRDFServiceFactory(ctx, - configurationProvider.getRDFServiceFactory(), CONFIGURATION); - - ModelAccess.setDataStructuresProvider(provider); - } - - private void configureJena() { - // we do not want to fetch imports when we wrap Models in OntModels - OntDocumentManager.getInstance().setProcessImports(false); - } - - /** - * For now, these steps are hard-coded. They should be driven by a - * configuration file. - */ - private void createProviders() { - if (isSparqlEndpointContentConfigured()) { - contentProvider = new ContentDataStructuresProviderSPARQL(ctx, this); - } else if (isTdbConfigured()) { - contentProvider = new ContentDataStructuresProviderTDB(ctx, this); - } else { - contentProvider = new ContentDataStructuresProviderSDB(ctx, this); - } - - configurationProvider = new ConfigurationDataStructuresProviderTDB(ctx, - this); - - provider = new BasicDataStructuresProvider(contentProvider, - configurationProvider); - } - - private boolean isSparqlEndpointContentConfigured() { - return StringUtils.isNotBlank(configProps - .getProperty(PROPERTY_SPARQL_ENDPOINT_URI)); - } - - private boolean isTdbConfigured() { - return StringUtils.isNotBlank(configProps - .getProperty(PROPERTY_CONTENT_TDB_PATH)); - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - if (contentProvider != null) { - try { - contentProvider.close(); - } catch (Exception e) { - log.error("Problem when closing content provider", e); - } - } - if (configurationProvider != null) { - try { - configurationProvider.close(); - } catch (Exception e) { - log.error("Problem when closing configuration provider", e); - } - } - } - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java index e5ce43bf9..36dc530a4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java @@ -5,7 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.utils.developer; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.Arrays; import java.util.EnumMap; import java.util.HashMap; @@ -20,7 +20,7 @@ import javax.servlet.ServletContextListener; 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.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** @@ -194,12 +194,10 @@ public class DeveloperSettings { public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); StartupStatus ss = StartupStatus.getBean(ctx); - ConfigurationProperties props = ConfigurationProperties - .getBean(ctx); DeveloperSettings devSettings = DeveloperSettings.getInstance(); - String home = props.getProperty("vitro.home"); - File dsFile = Paths.get(home, "developer.properties").toFile(); + Path homeDir = ApplicationUtils.instance().getHomeDirectory().getPath(); + File dsFile = homeDir.resolve("developer.properties").toFile(); try (FileReader reader = new FileReader(dsFile)) { Properties dsProps = new Properties(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/loggers/StackTraceUtility.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/loggers/StackTraceUtility.java index 8797c9c00..747cbf772 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/loggers/StackTraceUtility.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/loggers/StackTraceUtility.java @@ -124,8 +124,9 @@ public class StackTraceUtility { StringBuilder sb = new StringBuilder(); if (requested) { for (StackTraceElement ste : stackTrace) { - sb.append(String.format(" line %4d, %s \n", - ste.getLineNumber(), ste.getClassName())); + sb.append(String.format(" %s.%s(%s:%d) \n", + ste.getClassName(), ste.getMethodName(), + ste.getFileName(), ste.getLineNumber())); } sb.append(" ...\n"); } diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java index 7ec549add..f5aeaf92f 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java @@ -7,10 +7,13 @@ import java.lang.reflect.Field; import javax.servlet.ServletContext; import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; +import edu.cornell.mannlib.vitro.webapp.application.VitroHomeDirectory; import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage; import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; /** * TODO @@ -61,6 +64,12 @@ public class ApplicationStub implements Application { // Un-implemented methods // ---------------------------------------------------------------------- + @Override + public VitroHomeDirectory getHomeDirectory() { + throw new RuntimeException( + "ApplicationStub.getHomeDirectory() not implemented."); + } + @Override public ImageProcessor getImageProcessor() { throw new RuntimeException( @@ -74,4 +83,22 @@ public class ApplicationStub implements Application { "ApplicationStub.getFileStorage() not implemented."); } + @Override + public void shutdown() { + throw new RuntimeException( + "ApplicationStub.shutdown() not implemented."); + } + + @Override + public ContentTripleSource getContentTripleSource() { + throw new RuntimeException( + "ApplicationStub.getContentTripleSource() not implemented."); + } + + @Override + public ConfigurationTripleSource getConfigurationTripleSource() { + throw new RuntimeException( + "ApplicationStub.getConfigurationTripleSource() not implemented."); + } + } diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index 94783f0ad..c5c9803eb 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -7,6 +7,8 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.JvmSmokeTests +edu.cornell.mannlib.vitro.webapp.application.ApplicationSetup + edu.cornell.mannlib.vitro.webapp.config.ConfigurationPropertiesSetup edu.cornell.mannlib.vitro.webapp.config.ConfigurationPropertiesSmokeTests @@ -16,15 +18,12 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.GuardAgainstUnmigratedRDB edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings$Setup -edu.cornell.mannlib.vitro.webapp.application.ApplicationImpl$Setup +edu.cornell.mannlib.vitro.webapp.application.ApplicationImpl$ComponentsSetup edu.cornell.mannlib.vitro.webapp.config.RevisionInfoSetup edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory$Setup -# In 1.8, this should replace JenaPersistentDataSourceSetup, RDFServiceSetup, and maybe more. -edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.RDFSetup - edu.cornell.mannlib.vitro.webapp.servlet.setup.ConfigurationModelsSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.ContentModelSetup