VIVO-823 Replace RDFServiceSetup with RDFSetup

This introduces the RDFSource as a wrapper around an RDFServiceFactory and 2 ModelMakerFactorys.
This introduces ModelMakerUtils as a way to get the ModelMakers for context or for request.
Create implementations of RDFSource for SDB, TDB, and SPARQL.
The SDB implementation absorbs JenaPersistentDataSourceSetup and part of ConfigurationPropertiesSmokeTests,
which aren't needed unless we use SDB.

This is probably broken, without the subsequent changes.
This commit is contained in:
Jim Blake 2014-07-18 17:15:24 -04:00
parent 63ed82cef9
commit 58148630ad
25 changed files with 1352 additions and 656 deletions

View file

@ -3,16 +3,8 @@
package edu.cornell.mannlib.vitro.webapp.config;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
@ -34,19 +26,12 @@ public class ConfigurationPropertiesSmokeTests implements
.getLog(ConfigurationPropertiesSmokeTests.class);
private static final String PROPERTY_HOME_DIRECTORY = "vitro.home";
private static final String PROPERTY_DB_URL = "VitroConnection.DataSource.url";
private static final String PROPERTY_DB_USERNAME = "VitroConnection.DataSource.username";
private static final String PROPERTY_DB_PASSWORD = "VitroConnection.DataSource.password";
private static final String PROPERTY_DB_DRIVER_CLASS_NAME = "VitroConnection.DataSource.driver";
private static final String PROPERTY_DB_TYPE = "VitroConnection.DataSource.dbtype";
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";
private static final String PROPERTY_LANGUAGE_FORCE = "languages.forceLocale";
private static final String PROPERTY_LANGUAGE_FILTER = "RDFService.languageFilter";
private static final String DEFAULT_DB_DRIVER_CLASS = "com.mysql.jdbc.Driver";
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
@ -54,7 +39,6 @@ public class ConfigurationPropertiesSmokeTests implements
StartupStatus ss = StartupStatus.getBean(ctx);
checkHomeDirectory(ctx, props, ss);
checkDatabaseConnection(ctx, props, ss);
checkDefaultNamespace(ctx, props, ss);
checkLanguages(props, ss);
}
@ -94,133 +78,7 @@ public class ConfigurationPropertiesSmokeTests implements
}
}
/**
* Confirm that the URL, Username and Password have been specified for the
* Database connection. Confirm that we can load the database driver.
* Confirm that we can connect to the database using those properties.
*/
private void checkDatabaseConnection(ServletContext ctx,
ConfigurationProperties props, StartupStatus ss) {
String url = props.getProperty(PROPERTY_DB_URL);
if (url == null || url.isEmpty()) {
ss.fatal(this, "runtime.properties does not contain a value for '"
+ PROPERTY_DB_URL + "'");
return;
}
String username = props.getProperty(PROPERTY_DB_USERNAME);
if (username == null || username.isEmpty()) {
ss.fatal(this, "runtime.properties does not contain a value for '"
+ PROPERTY_DB_USERNAME + "'");
return;
}
String password = props.getProperty(PROPERTY_DB_PASSWORD);
if (password == null || password.isEmpty()) {
ss.fatal(this, "runtime.properties does not contain a value for '"
+ PROPERTY_DB_PASSWORD + "'");
return;
}
String driverClassName = props
.getProperty(PROPERTY_DB_DRIVER_CLASS_NAME);
if (driverClassName == null) {
try {
Class.forName(DEFAULT_DB_DRIVER_CLASS).newInstance();
} catch (Exception e) {
ss.fatal(this, "The default Database Driver failed to load. "
+ "The driver class is '" + DEFAULT_DB_DRIVER_CLASS
+ "'", e);
return;
}
} else {
try {
Class.forName(driverClassName).newInstance();
} catch (Exception e) {
ss.fatal(this, "The Database Driver failed to load. "
+ "The driver class was set by "
+ PROPERTY_DB_DRIVER_CLASS_NAME + " to be '"
+ driverClassName + "'", e);
return;
}
}
Properties connectionProps = new Properties();
connectionProps.put("user", username);
connectionProps.put("password", password);
try (Connection conn = DriverManager
.getConnection(url, connectionProps)) {
// Just open the connection and close it.
} catch (SQLException e) {
ss.fatal(this, "Can't connect to the database: " + PROPERTY_DB_URL
+ "='" + url + "', " + PROPERTY_DB_USERNAME + "='"
+ username + "'", e);
return;
}
String dbType = props.getProperty(PROPERTY_DB_TYPE, "MySQL");
checkForPropertHandlingOfUnicodeCharacters(url, connectionProps, ss,
dbType);
}
private void checkForPropertHandlingOfUnicodeCharacters(String url,
Properties connectionProps, StartupStatus ss, String dbType) {
String testString = "ABC\u00CE\u0123";
try (Connection conn = DriverManager
.getConnection(url, connectionProps);
Statement stmt = conn.createStatement()) {
// Create the temporary table.
stmt.executeUpdate("CREATE TEMPORARY TABLE smoke_test (contents varchar(100))");
// Write the test string, encoding in UTF-8 on the way in.
try (PreparedStatement pstmt = conn
.prepareStatement("INSERT INTO smoke_test values ( ? )")) {
pstmt.setBytes(1, testString.getBytes("UTF-8"));
pstmt.executeUpdate();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
// Read it back as a String. Does the database decode it properly?
ResultSet rs = stmt.executeQuery("SELECT * FROM smoke_test");
if (!rs.next()) {
throw new SQLException(
"Query of temporary table returned 0 rows.");
}
String storedValue = rs.getString(1);
if (!testString.equals(storedValue)) {
String message = "The database does not store Unicode "
+ "characters correctly. The test inserted \""
+ showUnicode(testString)
+ "\", but the query returned \""
+ showUnicode(storedValue)
+ "\". Is the character encoding correctly "
+ "set on the database?";
if ("MySQL".equals(dbType)) {
// For MySQL, we know that this is a configuration problem.
ss.fatal(this, message);
} else {
// For other databases, it might not be.
ss.warning(this, message);
}
}
} catch (SQLException e) {
ss.fatal(this, "Failed to check handling of Unicode characters", e);
}
}
/**
* Display the hex codes for a String.
*/
private String showUnicode(String testString) {
StringBuilder u = new StringBuilder();
for (char c : testString.toCharArray()) {
u.append(String.format("\\u%04x", c & 0x0000FFFF));
}
return u.toString();
}
/**
* Confirm that the default namespace is specified and a syntactically valid
* URI. It should also end with "/individual/".

View file

@ -0,0 +1,42 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.modelaccess;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY_DISPLAY;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY_TBOX;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.USER_ACCOUNTS;
import static edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService.CONFIGURATION;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService;
/**
* Common functionality among the Configuration-based ModelMakerFactorys
*/
public abstract class ConfigurationModelMakerFactory implements
ModelMakerFactory {
/**
* A list of all Configuration models, in case the implementation wants to
* add memory-mapping.
*/
protected static final String[] CONFIGURATION_MODELS = { DISPLAY,
DISPLAY_TBOX, DISPLAY_DISPLAY, USER_ACCOUNTS };
/**
* These decorators are added to a Configuration ModelMaker, regardless of
* the source.
*/
protected ModelMaker addConfigurationDecorators(ModelMaker sourceMM) {
// No decorators yet.
return sourceMM;
}
@Override
public WhichService whichModelMaker() {
return CONFIGURATION;
}
}

View file

@ -0,0 +1,65 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.modelaccess;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.ABOX_ASSERTIONS;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.ABOX_INFERENCES;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.ABOX_UNION;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.APPLICATION_METADATA;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.FULL_ASSERTIONS;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.FULL_INFERENCES;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.FULL_UNION;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_INFERENCES;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_UNION;
import static edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService.CONTENT;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.NamedDefaultModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.UnionModelsModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.UnionModelsModelMaker.UnionSpec;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService;
/**
* Common functionality among the Content-based ModelMakerFactorys
*/
public abstract class ContentModelMakerFactory implements ModelMakerFactory {
/**
* These are the small content models that we want to keep in memory.
*/
protected static final String[] SMALL_CONTENT_MODELS = {
APPLICATION_METADATA, TBOX_ASSERTIONS, TBOX_INFERENCES };
private static final UnionSpec[] CONTENT_UNIONS = new UnionSpec[] {
UnionSpec.base(ABOX_ASSERTIONS).plus(ABOX_INFERENCES)
.yields(ABOX_UNION),
UnionSpec.base(TBOX_ASSERTIONS).plus(TBOX_INFERENCES)
.yields(TBOX_UNION),
UnionSpec.base(ABOX_ASSERTIONS).plus(TBOX_ASSERTIONS)
.yields(FULL_ASSERTIONS),
UnionSpec.base(ABOX_INFERENCES).plus(TBOX_INFERENCES)
.yields(FULL_INFERENCES) };
private static final String CONTENT_DEFAULT_MODEL_NAME = FULL_UNION;
/**
* These decorations are added to a Content ModelMaker, regardless of the
* source.
*
* Create the union models and full models. Use the default model as the
* full union.
*/
protected ModelMaker addContentDecorators(ModelMaker sourceMM) {
ModelMaker unions = new UnionModelsModelMaker(sourceMM, CONTENT_UNIONS);
return new NamedDefaultModelMaker(unions, CONTENT_DEFAULT_MODEL_NAME);
}
@Override
public WhichService whichModelMaker() {
return CONTENT;
}
}

View file

@ -0,0 +1,34 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.modelaccess;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService;
/**
* Get model makers for long and short-term use.
*/
public interface ModelMakerFactory {
/**
* Get a model maker that is suitable for long-term use.
*/
ModelMaker getModelMaker(RDFService longTermRdfService);
/**
* Get a model maker that should not be left idle for long periods of time.
*
* Because it is based (at least in part) on a short-term RDFService, it
* should not be stored in the context or the session, but should be deleted
* at the end of the request.
*/
ModelMaker getShortTermModelMaker(RDFService shortTermRdfService);
/**
* Is this factory configured to provide CONTENT models or CONFIGURATION models?
*/
WhichService whichModelMaker();
}

View file

@ -0,0 +1,104 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.modelaccess;
import static edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService.CONFIGURATION;
import static edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService.CONTENT;
import javax.servlet.ServletContext;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService;
/**
* Convenience methods for obtaining the ModelMakerFactories.
*/
public class ModelMakerUtils {
public static final String ATTRIBUTE_BASE = ModelMakerUtils.class.getName();
public static void setContentModelMakerFactory(ServletContext ctx,
ModelMakerFactory mmFactory) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
if (mmFactory == null) {
throw new NullPointerException("mmFactory may not be null.");
}
if (mmFactory.whichModelMaker() != CONTENT) {
throw new IllegalArgumentException(
"mmFactory must be a CONTENT ModelMakerFactory");
}
ctx.setAttribute(attributeName(CONTENT), mmFactory);
}
public static void setConfigurationModelMakerFactory(ServletContext ctx,
ModelMakerFactory mmFactory) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
if (mmFactory == null) {
throw new NullPointerException("mmFactory may not be null.");
}
if (mmFactory.whichModelMaker() != CONFIGURATION) {
throw new IllegalArgumentException(
"mmFactory must be a CONFIGURATION ModelMakerFactory");
}
ctx.setAttribute(attributeName(CONFIGURATION), mmFactory);
}
public static ModelMaker getModelMaker(ServletContext ctx,
WhichService which) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
if (which == null) {
throw new NullPointerException("which may not be null.");
}
return getFactory(ctx, which).getModelMaker(
RDFServiceUtils.getRDFServiceFactory(ctx)
.getShortTermRDFService());
}
public static ModelMaker getShortTermModelMaker(ServletContext ctx,
RDFService shortTermRdfService, WhichService which) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
if (shortTermRdfService == null) {
throw new NullPointerException(
"shortTermRdfService may not be null.");
}
if (which == null) {
throw new NullPointerException("which may not be null.");
}
return getFactory(ctx, which).getShortTermModelMaker(
shortTermRdfService);
}
private static ModelMakerFactory getFactory(ServletContext ctx,
WhichService which) {
Object attribute = ctx.getAttribute(attributeName(which));
if (attribute instanceof ModelMakerFactory) {
return (ModelMakerFactory) attribute;
} else {
throw new IllegalStateException("Expected a ModelMakerFactory at '"
+ attributeName(which) + "', but found " + attribute);
}
}
private static String attributeName(WhichService which) {
return ATTRIBUTE_BASE + "-" + which;
}
/**
* No need for an instance - all methods are static.
*/
private ModelMakerUtils() {
// Nothing to instantiate.
}
}

View file

@ -2,8 +2,6 @@
package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.sdb;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;

View file

@ -1,51 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.tdb;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
/**
* TODO
*/
public class RDFServiceFactoryTDB implements RDFServiceFactory {
private static final Log log = LogFactory
.getLog(RDFServiceFactoryTDB.class);
private final RDFServiceTDB service;
public RDFServiceFactoryTDB(String directoryPath) throws IOException {
this.service = new RDFServiceTDB(directoryPath);
}
@Override
public RDFService getRDFService() {
return service;
}
@Override
public RDFService getShortTermRDFService() {
return service;
}
@Override
public void registerListener(ChangeListener changeListener)
throws RDFServiceException {
service.registerListener(changeListener);
}
@Override
public void unregisterListener(ChangeListener changeListener)
throws RDFServiceException {
service.unregisterListener(changeListener);
}
}

View file

@ -20,7 +20,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.RDFServiceJena;
/**
* TODO
* An implementation that is based on Jena TDB.
*/
public class RDFServiceTDB extends RDFServiceJena {
private static final Log log = LogFactory.getLog(RDFServiceTDB.class);
@ -79,4 +79,10 @@ public class RDFServiceTDB extends RDFServiceJena {
}
}
@Override
public void close() {
if (this.dataset != null) {
dataset.close();
}
}
}

View file

@ -1,163 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup;
import java.beans.PropertyVetoException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.sql.DataSource;
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 com.mchange.v2.c3p0.ComboPooledDataSource;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
/**
* Create connection to DB and DataSource, put them in the context.
*/
public class JenaPersistentDataSourceSetup implements ServletContextListener {
private static final Log log = LogFactory
.getLog(JenaPersistentDataSourceSetup.class.getName());
private static final String PROPERTY_DBTYPE = "VitroConnection.DataSource.dbtype";
private static final String PROPERTY_JDBC_URL = "VitroConnection.DataSource.url";
private static final String PROPERTY_DRIVER_CLASS = "VitroConnection.DataSource.driver";
private static final String PROPERTY_PASSWORD = "VitroConnection.DataSource.password";
private static final String PROPERTY_USERNAME = "VitroConnection.DataSource.username";
private static final String PROPERTY_MAX_ACTIVE = "VitroConnection.DataSource.pool.maxActive";
private static final String PROPERTY_MAX_IDLE = "VitroConnection.DataSource.pool.maxIdle";
private static final String PROPERTY_VALIDATION_QUERY = "VitroConnection.DataSource.validationQuery";
private static final String DEFAULT_DBTYPE = "MySQL";
private static final String DEFAULT_DRIVER_CLASS = "com.mysql.jdbc.Driver";
private static final String DEFAULT_VALIDATION_QUERY = "SELECT 1";
private static final int DEFAULT_MAXACTIVE = 40; //ms
private static final int MINIMUM_MAXACTIVE = 20; //ms
private static final int DEFAULT_MAXIDLE = 10; //ms
private static final boolean DEFAULT_TESTONBORROW = true;
private static final boolean DEFAULT_TESTONRETURN = true;
private ConfigurationProperties configProps;
private static ComboPooledDataSource ds;
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
configProps = ConfigurationProperties.getBean(ctx);
// we do not want to fetch imports when we wrap Models in OntModels
OntDocumentManager.getInstance().setProcessImports(false);
JenaPersistentDataSourceSetup.ds = makeC3poDataSource();
}
private ComboPooledDataSource makeC3poDataSource() {
try {
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(getDbDriverClassName());
cpds.setJdbcUrl(getJdbcUrl());
cpds.setUser(configProps.getProperty(PROPERTY_USERNAME));
cpds.setPassword(configProps.getProperty(PROPERTY_PASSWORD));
cpds.setMaxPoolSize(getMaxActive());
cpds.setMinPoolSize(getMaxIdle());
cpds.setMaxIdleTime(43200); // s
cpds.setMaxIdleTimeExcessConnections(300);
cpds.setAcquireIncrement(5);
cpds.setNumHelperThreads(6);
cpds.setTestConnectionOnCheckout(DEFAULT_TESTONBORROW);
cpds.setTestConnectionOnCheckin(DEFAULT_TESTONRETURN);
cpds.setPreferredTestQuery(getValidationQuery());
return cpds;
} catch (PropertyVetoException pve) {
throw new RuntimeException(pve);
}
}
private String getDbDriverClassName() {
return configProps.getProperty(PROPERTY_DRIVER_CLASS,
DEFAULT_DRIVER_CLASS);
}
private String getDbType() {
return configProps.getProperty(PROPERTY_DBTYPE, DEFAULT_DBTYPE);
}
private String getJdbcUrl() {
String url = configProps.getProperty(PROPERTY_JDBC_URL);
// Ensure that MySQL handles unicode properly, else all kinds of
// horrible nastiness ensues.
if (DEFAULT_DBTYPE.equals(getDbType()) && !url.contains("?")) {
url += "?useUnicode=yes&characterEncoding=utf8";
}
return url;
}
private String getValidationQuery() {
return configProps.getProperty(PROPERTY_VALIDATION_QUERY,
DEFAULT_VALIDATION_QUERY);
}
private int getMaxActive() {
String maxActiveStr = configProps.getProperty(PROPERTY_MAX_ACTIVE);
if (StringUtils.isEmpty(maxActiveStr)) {
return DEFAULT_MAXACTIVE;
}
int maxActive = DEFAULT_MAXACTIVE;
try {
maxActive = Integer.parseInt(maxActiveStr);
} catch (NumberFormatException nfe) {
log.error("Unable to parse connection pool maxActive setting "
+ maxActiveStr + " as an integer");
return DEFAULT_MAXACTIVE;
}
if (maxActive >= MINIMUM_MAXACTIVE) {
return maxActive;
}
log.warn("Specified value for " + PROPERTY_MAX_ACTIVE
+ " is too low. Using minimum value of " + MINIMUM_MAXACTIVE);
return MINIMUM_MAXACTIVE;
}
private int getMaxIdle() {
int maxIdleInt = Math.max(getMaxActive() / 4, DEFAULT_MAXIDLE);
String maxIdleStr = configProps.getProperty(PROPERTY_MAX_IDLE);
if (StringUtils.isEmpty(maxIdleStr)) {
return maxIdleInt;
}
try {
return Integer.parseInt(maxIdleStr);
} catch (NumberFormatException nfe) {
log.error("Unable to parse connection pool maxIdle setting "
+ maxIdleStr + " as an integer");
return maxIdleInt;
}
}
public static DataSource getApplicationDataSource() {
return JenaPersistentDataSourceSetup.ds;
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (JenaPersistentDataSourceSetup.ds != null) {
JenaPersistentDataSourceSetup.ds.close();
}
}
}

View file

@ -1,115 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.APPLICATION_METADATA;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.BASE_FULL;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.BASE_TBOX;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.DISPLAY;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.DISPLAY_DISPLAY;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.DISPLAY_TBOX;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.INFERRED_FULL;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.INFERRED_TBOX;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.UNION_FULL;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID.USER_ACCOUNTS;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelMakerID.CONFIGURATION;
import static edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelMakerID.CONTENT;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.rdf.model.Model;
import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker;
import edu.cornell.mannlib.vitro.webapp.dao.jena.VitroInterceptingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Sets up the content models, OntModelSelectors and webapp DAO factories.
*/
public class ModelMakerSetup implements javax.servlet.ServletContextListener {
private static final Log log = LogFactory.getLog(ModelMakerSetup.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
StartupStatus ss = StartupStatus.getBean(ctx);
createConfigurationModelMaker(ctx);
createContentModelMaker(ctx);
ss.info(this, "Created model makers.");
}
private void createConfigurationModelMaker(ServletContext ctx) {
RDFServiceFactory rdfServiceFactory = RDFServiceUtils
.getRDFServiceFactory(ctx, WhichService.CONFIGURATION);
RDFServiceModelMaker configMM = new RDFServiceModelMaker(
rdfServiceFactory);
Map<String, Model> specials = populateConfigurationSpecialMap(ctx);
VitroInterceptingModelMaker viMM = new VitroInterceptingModelMaker(
configMM, specials);
ModelAccess.on(ctx).setModelMaker(CONFIGURATION, viMM);
}
private void createContentModelMaker(ServletContext ctx) {
RDFServiceFactory rdfServiceFactory = RDFServiceUtils
.getRDFServiceFactory(ctx);
RDFServiceModelMaker contentMM = new RDFServiceModelMaker(
rdfServiceFactory);
Map<String, Model> specials = populateContentSpecialMap(ctx);
VitroInterceptingModelMaker viMM = new VitroInterceptingModelMaker(
contentMM, specials);
ModelAccess.on(ctx).setModelMaker(CONTENT, viMM);
}
private Map<String, Model> populateConfigurationSpecialMap(
ServletContext ctx) {
Map<String, Model> map = new HashMap<>();
map.put(ModelNames.DISPLAY,
ModelAccess.on(ctx).getOntModel(DISPLAY));
map.put(ModelNames.DISPLAY_TBOX,
ModelAccess.on(ctx).getOntModel(DISPLAY_TBOX));
map.put(ModelNames.DISPLAY_DISPLAY,
ModelAccess.on(ctx).getOntModel(DISPLAY_DISPLAY));
map.put(ModelNames.USER_ACCOUNTS,
ModelAccess.on(ctx).getOntModel(USER_ACCOUNTS));
return map;
}
private Map<String, Model> populateContentSpecialMap(ServletContext ctx) {
Map<String, Model> map = new HashMap<>();
map.put("vitro:jenaOntModel",
ModelAccess.on(ctx).getOntModel(UNION_FULL));
map.put("vitro:baseOntModel", ModelAccess.on(ctx)
.getOntModel(BASE_FULL));
map.put("vitro:inferenceOntModel",
ModelAccess.on(ctx).getOntModel(INFERRED_FULL));
map.put(ModelNames.TBOX_ASSERTIONS,
ModelAccess.on(ctx).getOntModel(BASE_TBOX));
map.put(ModelNames.TBOX_INFERENCES,
ModelAccess.on(ctx).getOntModel(INFERRED_TBOX));
map.put(ModelNames.APPLICATION_METADATA, ModelAccess.on(ctx)
.getOntModel(APPLICATION_METADATA));
return map;
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// Nothing to do.
}
}

View file

@ -1,176 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup;
import static edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService.CONFIGURATION;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.sdb.SDB;
import com.hp.hpl.jena.sdb.SDBFactory;
import com.hp.hpl.jena.sdb.Store;
import com.hp.hpl.jena.sdb.StoreDesc;
import com.hp.hpl.jena.sdb.sql.SDBConnection;
import com.hp.hpl.jena.sdb.store.DatabaseType;
import com.hp.hpl.jena.sdb.store.LayoutType;
import com.hp.hpl.jena.sdb.util.StoreUtils;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceFactorySingle;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.sdb.RDFServiceFactorySDB;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.tdb.RDFServiceFactoryTDB;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql.RDFServiceSparql;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
public class RDFServiceSetup extends JenaDataSourceSetupBase
implements javax.servlet.ServletContextListener {
private static final Log log = LogFactory.getLog(RDFServiceSetup.class);
private static final String DIRECTORY_TDB = "tdbModels";
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// nothing to do
}
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
StartupStatus ss = StartupStatus.getBean(ctx);
try {
String endpointURI = ConfigurationProperties.getBean(sce).getProperty(
"VitroConnection.DataSource.endpointURI");
String updateEndpointURI = ConfigurationProperties.getBean(sce).getProperty(
"VitroConnection.DataSource.updateEndpointURI");
if (endpointURI != null) {
useEndpoint(endpointURI, updateEndpointURI, ctx);
} else {
useSDB(ctx, ss);
}
//experimental
//RDFServiceFactory factory = RDFServiceUtils.getRDFServiceFactory(ctx);
//RDFServiceUtils.setRDFServiceFactory(ctx, new SameAsFilteringRDFServiceFactory(factory));
useTDBForConfigurationModels(ctx);
} catch (Exception e) {
ss.fatal(this, "Exception in RDFServiceSetup", e);
}
}
private void useTDBForConfigurationModels(ServletContext ctx) throws IOException {
String vitroHome = ConfigurationProperties.getBean(ctx).getProperty(
"vitro.home") ;
String directoryPath = vitroHome + File.separatorChar + DIRECTORY_TDB;
RDFServiceFactory factory = new RDFServiceFactoryTDB(directoryPath);
RDFServiceUtils.setRDFServiceFactory(ctx, factory, CONFIGURATION);
}
private void useEndpoint(String endpointURI, String updateEndpointURI, ServletContext ctx) {
RDFService rdfService = null;
if (updateEndpointURI == null) {
rdfService = new RDFServiceSparql(endpointURI);
} else {
rdfService = new RDFServiceSparql(endpointURI, updateEndpointURI);
}
RDFServiceFactory rdfServiceFactory = new RDFServiceFactorySingle(rdfService);
RDFServiceUtils.setRDFServiceFactory(ctx, rdfServiceFactory);
if (updateEndpointURI != null) {
log.info("Using read endpoint at " + endpointURI);
log.info("Using update endpoint at " + updateEndpointURI);
} else {
log.info("Using endpoint at " + endpointURI);
}
}
private void useSDB(ServletContext ctx, StartupStatus ss) throws SQLException {
DataSource ds = JenaPersistentDataSourceSetup.getApplicationDataSource();
if( ds == null ){
ss.fatal(this, "A DataSource must be setup before SDBSetup "+
"is run. Make sure that JenaPersistentDataSourceSetup runs before "+
"SDBSetup.");
return;
}
// union default graph
SDB.getContext().set(SDB.unionDefaultGraph, true) ;
StoreDesc storeDesc = makeStoreDesc(ctx);
Store store = connectStore(ds, storeDesc);
if (!isSetUp(store)) {
JenaDataSourceSetupBase.thisIsFirstStartup();
setupSDB(ctx, store);
}
//RDFService rdfService = new RDFServiceSDB(ds, storeDesc);
//RDFServiceFactory rdfServiceFactory = new RDFServiceFactorySingle(rdfService);
RDFServiceFactory rdfServiceFactory = new RDFServiceFactorySDB(ds, storeDesc);
RDFServiceUtils.setRDFServiceFactory(ctx, rdfServiceFactory);
log.info("SDB store ready for use");
}
/**
* Tests whether an SDB store has been formatted and populated for use.
* @param store
* @return
*/
private boolean isSetUp(Store store) throws SQLException {
if (!(StoreUtils.isFormatted(store))) {
return false;
}
// even if the store exists, it may be empty
try {
return (SDBFactory.connectNamedModel(
store,
ModelNames.TBOX_ASSERTIONS))
.size() > 0;
} catch (Exception e) {
return false;
}
}
public static StoreDesc makeStoreDesc(ServletContext ctx) {
String layoutStr = ConfigurationProperties.getBean(ctx).getProperty(
"VitroConnection.DataSource.sdb.layout", "layout2/hash");
String dbtypeStr = ConfigurationProperties.getBean(ctx).getProperty(
"VitroConnection.DataSource.dbtype", "MySQL");
return new StoreDesc(
LayoutType.fetch(layoutStr),
DatabaseType.fetch(dbtypeStr) );
}
public static Store connectStore(DataSource bds, StoreDesc storeDesc)
throws SQLException {
SDBConnection conn = new SDBConnection(bds.getConnection());
return SDBFactory.connectStore(conn, storeDesc);
}
protected static void setupSDB(ServletContext ctx, Store store) {
log.info("Initializing SDB store");
store.getTableFormatter().create();
store.getTableFormatter().truncate();
}
}

View file

@ -0,0 +1,94 @@
/* $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.servlet.setup.rdfsetup.impl.sparql.RDFSourceSPARQL.PROPERTY_SPARQL_ENDPOINT_URI;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.lang.StringUtils;
import com.hp.hpl.jena.ontology.OntDocumentManager;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelMakerID;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelMakerUtils;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils.WhichService;
import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB;
import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sparql.RDFSourceSPARQL;
import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.tdb.RDFSourceTDB;
/**
* Create the RDFServiceFactories and ModelMakers for the application to use.
*/
public class RDFSetup implements ServletContextListener {
private ServletContext ctx;
private ConfigurationProperties configProps;
private RDFSource contentRdfSource;
private RDFSource configurationRdfSource;
@Override
public void contextInitialized(ServletContextEvent sce) {
this.ctx = sce.getServletContext();
this.configProps = ConfigurationProperties.getBean(ctx);
configureJena();
createRdfSources();
RDFServiceUtils.setRDFServiceFactory(ctx,
contentRdfSource.getRDFServiceFactory(), WhichService.CONTENT);
ModelMakerUtils.setContentModelMakerFactory(ctx,
contentRdfSource.getContentModelMakerFactory());
ModelAccess.on(ctx).setModelMaker(ModelMakerID.CONTENT,
ModelMakerUtils.getModelMaker(ctx, WhichService.CONTENT));
RDFServiceUtils.setRDFServiceFactory(ctx,
configurationRdfSource.getRDFServiceFactory(),
WhichService.CONFIGURATION);
ModelMakerUtils.setConfigurationModelMakerFactory(ctx,
configurationRdfSource.getConfigurationModelMakerFactory());
ModelAccess.on(ctx).setModelMaker(ModelMakerID.CONFIGURATION,
ModelMakerUtils.getModelMaker(ctx, WhichService.CONFIGURATION));
}
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 createRdfSources() {
if (isSparqlEndpointContentConfigured()) {
contentRdfSource = new RDFSourceSPARQL(ctx, this);
} else {
contentRdfSource = new RDFSourceSDB(ctx, this);
}
configurationRdfSource = new RDFSourceTDB(ctx, this);
}
private boolean isSparqlEndpointContentConfigured() {
return StringUtils.isNotBlank(configProps
.getProperty(PROPERTY_SPARQL_ENDPOINT_URI));
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (configurationRdfSource != null) {
configurationRdfSource.close();
}
if (contentRdfSource != null) {
contentRdfSource.close();
}
}
}

View file

@ -0,0 +1,25 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
/**
* The interface for a triple-store implementation. It returns an
* RDFServiceFactory and either or both of the ModelMakerFactories.
*
* You should call close() when shutting down the triple-store.
*/
public interface RDFSource extends AutoCloseable {
RDFServiceFactory getRDFServiceFactory();
ModelMakerFactory getContentModelMakerFactory();
ModelMakerFactory getConfigurationModelMakerFactory();
@Override
void close();
}

View file

@ -0,0 +1,45 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ConfigurationModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ListCachingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.MemoryMappingModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
/**
* In SDB, Configuration models require database connections.
*
* However, they are all small enough for memory-mapping. Once memory-mapped,
* they are suitable for short-term or long-term use.
*
* RDFService doesn't support empty models, so support them with ListCaching
*/
public class ConfigurationModelMakerFactorySDB extends
ConfigurationModelMakerFactory {
private final ModelMaker longTermModelMaker;
public ConfigurationModelMakerFactorySDB(RDFService longTermRdfService) {
this.longTermModelMaker = new ListCachingModelMaker(
new MemoryMappingModelMaker(new RDFServiceModelMaker(
longTermRdfService), CONFIGURATION_MODELS));
}
@Override
public ModelMaker getModelMaker(RDFService longTermRdfService) {
return addConfigurationDecorators(longTermModelMaker);
}
/**
* The long-term models are all memory-mapped, so use them.
*/
@Override
public ModelMaker getShortTermModelMaker(RDFService shortTermRdfService) {
return addConfigurationDecorators(longTermModelMaker);
}
}

View file

@ -0,0 +1,59 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContentModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ListCachingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.MemoryMappingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ShadowingModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
/**
* In SDB, Content models require database connections.
*
* Memory-map the small models, and use a short-term connection for the others
* (when available).
*
* RDFService doesn't support empty models, so support them with ListCaching
*/
public class ContentModelMakerFactorySDB extends ContentModelMakerFactory
implements ModelMakerFactory {
private final ModelMaker longTermModelMaker;
public ContentModelMakerFactorySDB(RDFService longTermRdfService) {
this.longTermModelMaker = new ListCachingModelMaker(
new MemoryMappingModelMaker(new RDFServiceModelMaker(
longTermRdfService), SMALL_CONTENT_MODELS));
}
/**
* The small content models (tbox, app_metadata) are memory mapped, for
* speed.
*/
@Override
public ModelMaker getModelMaker(RDFService longTermRdfService) {
return addContentDecorators(longTermModelMaker);
}
/**
* For short-term use, the large models (abox) will come from a short-term
* service. The small models can be the memory-mapped ones that we created
* for long-term use.
*/
@Override
public ModelMaker getShortTermModelMaker(RDFService shortTermRdfService) {
ModelMaker shortTermModelMaker = new RDFServiceModelMaker(
shortTermRdfService);
// No need to create a fresh memory map of the small models: use the
// long-term ones.
return addContentDecorators(new ShadowingModelMaker(
shortTermModelMaker, longTermModelMaker, SMALL_CONTENT_MODELS));
}
}

View file

@ -0,0 +1,173 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb;
import java.sql.SQLException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.sdb.SDB;
import com.hp.hpl.jena.sdb.SDBFactory;
import com.hp.hpl.jena.sdb.Store;
import com.hp.hpl.jena.sdb.StoreDesc;
import com.hp.hpl.jena.sdb.sql.SDBConnection;
import com.hp.hpl.jena.sdb.store.DatabaseType;
import com.hp.hpl.jena.sdb.store.LayoutType;
import com.hp.hpl.jena.sdb.util.StoreUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.sdb.RDFServiceFactorySDB;
import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase;
import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.RDFSource;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Create the connection to the SDB triple-store.
*
* Do some smoke-tests on the parameters, create the connection pool, and create
* the RDFServiceFactory.
*
* Create the ModelMakerFactories only if requested.
*/
public class RDFSourceSDB implements RDFSource {
private static final Log log = LogFactory.getLog(RDFSourceSDB.class);
static final String PROPERTY_DB_URL = "VitroConnection.DataSource.url";
static final String PROPERTY_DB_USERNAME = "VitroConnection.DataSource.username";
static final String PROPERTY_DB_PASSWORD = "VitroConnection.DataSource.password";
static final String PROPERTY_DB_DRIVER_CLASS_NAME = "VitroConnection.DataSource.driver";
static final String PROPERTY_DB_TYPE = "VitroConnection.DataSource.dbtype";
static final String PROPERTY_DB_MAX_ACTIVE = "VitroConnection.DataSource.pool.maxActive";
static final String PROPERTY_DB_MAX_IDLE = "VitroConnection.DataSource.pool.maxIdle";
static final String PROPERTY_DB_VALIDATION_QUERY = "VitroConnection.DataSource.validationQuery";
static final String PROPERTY_DB_SDB_LAYOUT = "VitroConnection.DataSource.sdb.layout";
static final String DEFAULT_TYPE = "MySQL";
static final String DEFAULT_DRIVER_CLASS = "com.mysql.jdbc.Driver";
static final String DEFAULT_LAYOUT = "layout2/hash";
static final String DEFAULT_VALIDATION_QUERY = "SELECT 1";
static final int DEFAULT_MAXACTIVE = 40; // ms
static final int MINIMUM_MAXACTIVE = 20; // ms
static final int DEFAULT_MAXIDLE = 10; // ms
static final boolean DEFAULT_TESTONBORROW = true;
static final boolean DEFAULT_TESTONRETURN = true;
private final ServletContext ctx;
private final StartupStatus ss;
private final ComboPooledDataSource ds;
private final RDFServiceFactory rdfServiceFactory;
private final RDFService rdfService;
public RDFSourceSDB(ServletContext ctx, ServletContextListener parent) {
try {
this.ctx = ctx;
this.ss = StartupStatus.getBean(ctx);
configureSDBContext();
new SDBConnectionSmokeTests(ctx, parent)
.checkDatabaseConnection();
this.ds = new SDBDataSource(ctx).getDataSource();
this.rdfServiceFactory = createRdfServiceFactory();
this.rdfService = rdfServiceFactory.getRDFService();
ss.info(parent, "Initialized the RDF source for SDB");
} catch (SQLException e) {
throw new RuntimeException(
"Failed to set up the RDF source for SDB", e);
}
}
private void configureSDBContext() {
SDB.getContext().set(SDB.unionDefaultGraph, true);
}
private RDFServiceFactory createRdfServiceFactory() throws SQLException {
StoreDesc storeDesc = makeStoreDesc();
Store store = connectStore(ds, storeDesc);
if (!isSetUp(store)) {
JenaDataSourceSetupBase.thisIsFirstStartup();
setupSDB(store);
}
return new RDFServiceFactorySDB(ds, storeDesc);
}
/**
* Tests whether an SDB store has been formatted and populated for use.
*
* @param store
* @return
*/
private boolean isSetUp(Store store) throws SQLException {
if (!(StoreUtils.isFormatted(store))) {
return false;
}
// even if the store exists, it may be empty
try {
return (SDBFactory.connectNamedModel(store,
ModelNames.TBOX_ASSERTIONS)).size() > 0;
} catch (Exception e) {
return false;
}
}
private StoreDesc makeStoreDesc() {
ConfigurationProperties props = ConfigurationProperties.getBean(ctx);
String layoutStr = props.getProperty(PROPERTY_DB_SDB_LAYOUT,
DEFAULT_LAYOUT);
String dbtypeStr = props.getProperty(PROPERTY_DB_TYPE, DEFAULT_TYPE);
return new StoreDesc(LayoutType.fetch(layoutStr),
DatabaseType.fetch(dbtypeStr));
}
private Store connectStore(DataSource bds, StoreDesc storeDesc)
throws SQLException {
SDBConnection conn = new SDBConnection(bds.getConnection());
return SDBFactory.connectStore(conn, storeDesc);
}
private void setupSDB(Store store) {
log.info("Initializing SDB store");
store.getTableFormatter().create();
store.getTableFormatter().truncate();
}
@Override
public RDFServiceFactory getRDFServiceFactory() {
return this.rdfServiceFactory;
}
@Override
public ModelMakerFactory getContentModelMakerFactory() {
return new ContentModelMakerFactorySDB(this.rdfService);
}
@Override
public ModelMakerFactory getConfigurationModelMakerFactory() {
return new ConfigurationModelMakerFactorySDB(this.rdfService);
}
@Override
public void close() {
if (ds != null) {
ds.close();
}
}
}

View file

@ -0,0 +1,177 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_DRIVER_CLASS;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_DRIVER_CLASS_NAME;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_PASSWORD;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_TYPE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_URL;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_USERNAME;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Smoke tests for the database connection that SDB will use.
*
* Confirm that the URL, Username and Password have been specified for the
* Database connection.
*
* Confirm that we can load the database driver.
*
* Confirm that we can connect to the database using those properties.
*
* Try to confirm that the database connection is configured to use UTF-8
* encoding. Don't know how well this works.
*/
public class SDBConnectionSmokeTests {
private final ServletContextListener parent;
private final ConfigurationProperties props;
private final StartupStatus ss;
public SDBConnectionSmokeTests(ServletContext ctx,
ServletContextListener parent) {
this.parent = parent;
this.props = ConfigurationProperties.getBean(ctx);
this.ss = StartupStatus.getBean(ctx);
}
public void checkDatabaseConnection() {
String url = props.getProperty(PROPERTY_DB_URL);
if (url == null || url.isEmpty()) {
ss.fatal(parent,
"runtime.properties does not contain a value for '"
+ PROPERTY_DB_URL + "'");
return;
}
String username = props.getProperty(PROPERTY_DB_USERNAME);
if (username == null || username.isEmpty()) {
ss.fatal(parent,
"runtime.properties does not contain a value for '"
+ PROPERTY_DB_USERNAME + "'");
return;
}
String password = props.getProperty(PROPERTY_DB_PASSWORD);
if (password == null || password.isEmpty()) {
ss.fatal(parent,
"runtime.properties does not contain a value for '"
+ PROPERTY_DB_PASSWORD + "'");
return;
}
String driverClassName = props
.getProperty(PROPERTY_DB_DRIVER_CLASS_NAME);
if (driverClassName == null) {
try {
Class.forName(DEFAULT_DRIVER_CLASS).newInstance();
} catch (Exception e) {
ss.fatal(parent, "The default Database Driver failed to load. "
+ "The driver class is '" + DEFAULT_DRIVER_CLASS
+ "'", e);
return;
}
} else {
try {
Class.forName(driverClassName).newInstance();
} catch (Exception e) {
ss.fatal(parent, "The Database Driver failed to load. "
+ "The driver class was set by "
+ PROPERTY_DB_DRIVER_CLASS_NAME + " to be '"
+ driverClassName + "'", e);
return;
}
}
Properties connectionProps = new Properties();
connectionProps.put("user", username);
connectionProps.put("password", password);
try (Connection conn = DriverManager
.getConnection(url, connectionProps)) {
// Just open the connection and close it.
} catch (SQLException e) {
ss.fatal(parent, "Can't connect to the database: "
+ PROPERTY_DB_URL + "='" + url + "', "
+ PROPERTY_DB_USERNAME + "='" + username + "'", e);
return;
}
String dbType = props.getProperty(PROPERTY_DB_TYPE, "MySQL");
checkForPropertHandlingOfUnicodeCharacters(url, connectionProps, dbType);
}
private void checkForPropertHandlingOfUnicodeCharacters(String url,
Properties connectionProps, String dbType) {
String testString = "ABC\u00CE\u0123";
try (Connection conn = DriverManager
.getConnection(url, connectionProps);
Statement stmt = conn.createStatement()) {
// Create the temporary table.
stmt.executeUpdate("CREATE TEMPORARY TABLE smoke_test (contents varchar(100))");
// Write the test string, encoding in UTF-8 on the way in.
try (PreparedStatement pstmt = conn
.prepareStatement("INSERT INTO smoke_test values ( ? )")) {
pstmt.setBytes(1, testString.getBytes("UTF-8"));
pstmt.executeUpdate();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
// Read it back as a String. Does the database decode it properly?
ResultSet rs = stmt.executeQuery("SELECT * FROM smoke_test");
if (!rs.next()) {
throw new SQLException(
"Query of temporary table returned 0 rows.");
}
String storedValue = rs.getString(1);
if (!testString.equals(storedValue)) {
String message = "The database does not store Unicode "
+ "characters correctly. The test inserted \""
+ showUnicode(testString)
+ "\", but the query returned \""
+ showUnicode(storedValue)
+ "\". Is the character encoding correctly "
+ "set on the database?";
if ("MySQL".equals(dbType)) {
// For MySQL, we know that this is a configuration problem.
ss.fatal(parent, message);
} else {
// For other databases, it might not be.
ss.warning(parent, message);
}
}
} catch (SQLException e) {
ss.fatal(parent, "Failed to check handling of Unicode characters",
e);
}
}
/**
* Display the hex codes for a String.
*/
private String showUnicode(String testString) {
StringBuilder u = new StringBuilder();
for (char c : testString.toCharArray()) {
u.append(String.format("\\u%04x", c & 0x0000FFFF));
}
return u.toString();
}
}

View file

@ -0,0 +1,136 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_DRIVER_CLASS;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_MAXACTIVE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_MAXIDLE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_TESTONBORROW;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_TESTONRETURN;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_TYPE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.DEFAULT_VALIDATION_QUERY;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.MINIMUM_MAXACTIVE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_DRIVER_CLASS_NAME;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_MAX_ACTIVE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_MAX_IDLE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_PASSWORD;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_TYPE;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_URL;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_USERNAME;
import static edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sdb.RDFSourceSDB.PROPERTY_DB_VALIDATION_QUERY;
import java.beans.PropertyVetoException;
import javax.servlet.ServletContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
/**
* Create a DataSource on the SDB database.
*/
public class SDBDataSource {
private static final Log log = LogFactory.getLog(SDBDataSource.class);
private final ConfigurationProperties configProps;
public SDBDataSource(ServletContext ctx) {
this.configProps = ConfigurationProperties.getBean(ctx);
}
public ComboPooledDataSource getDataSource() {
try {
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(getDbDriverClassName());
cpds.setJdbcUrl(getJdbcUrl());
cpds.setUser(configProps.getProperty(PROPERTY_DB_USERNAME));
cpds.setPassword(configProps.getProperty(PROPERTY_DB_PASSWORD));
cpds.setMaxPoolSize(getMaxActive());
cpds.setMinPoolSize(getMaxIdle());
cpds.setMaxIdleTime(43200); // s
cpds.setMaxIdleTimeExcessConnections(300);
cpds.setAcquireIncrement(5);
cpds.setNumHelperThreads(6);
cpds.setTestConnectionOnCheckout(DEFAULT_TESTONBORROW);
cpds.setTestConnectionOnCheckin(DEFAULT_TESTONRETURN);
cpds.setPreferredTestQuery(getValidationQuery());
return cpds;
} catch (PropertyVetoException pve) {
throw new RuntimeException(pve);
}
}
private String getDbDriverClassName() {
return configProps.getProperty(PROPERTY_DB_DRIVER_CLASS_NAME,
DEFAULT_DRIVER_CLASS);
}
private String getDbType() {
return configProps.getProperty(PROPERTY_DB_TYPE, DEFAULT_TYPE);
}
private String getJdbcUrl() {
String url = configProps.getProperty(PROPERTY_DB_URL);
// Ensure that MySQL handles unicode properly, else all kinds of
// horrible nastiness ensues.
if (DEFAULT_TYPE.equals(getDbType()) && !url.contains("?")) {
url += "?useUnicode=yes&characterEncoding=utf8";
}
return url;
}
private String getValidationQuery() {
return configProps.getProperty(PROPERTY_DB_VALIDATION_QUERY,
DEFAULT_VALIDATION_QUERY);
}
private int getMaxActive() {
String maxActiveStr = configProps.getProperty(PROPERTY_DB_MAX_ACTIVE);
if (StringUtils.isEmpty(maxActiveStr)) {
return DEFAULT_MAXACTIVE;
}
int maxActive = DEFAULT_MAXACTIVE;
try {
maxActive = Integer.parseInt(maxActiveStr);
} catch (NumberFormatException nfe) {
log.error("Unable to parse connection pool maxActive setting "
+ maxActiveStr + " as an integer");
return DEFAULT_MAXACTIVE;
}
if (maxActive >= MINIMUM_MAXACTIVE) {
return maxActive;
}
log.warn("Specified value for " + PROPERTY_DB_MAX_ACTIVE
+ " is too low. Using minimum value of " + MINIMUM_MAXACTIVE);
return MINIMUM_MAXACTIVE;
}
private int getMaxIdle() {
int maxIdleInt = Math.max(getMaxActive() / 4, DEFAULT_MAXIDLE);
String maxIdleStr = configProps.getProperty(PROPERTY_DB_MAX_IDLE);
if (StringUtils.isEmpty(maxIdleStr)) {
return maxIdleInt;
}
try {
return Integer.parseInt(maxIdleStr);
} catch (NumberFormatException nfe) {
log.error("Unable to parse connection pool maxIdle setting "
+ maxIdleStr + " as an integer");
return maxIdleInt;
}
}
}

View file

@ -0,0 +1,46 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sparql;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ConfigurationModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ListCachingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.MemoryMappingModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
/**
* On a SPARQL endpoint, is there any difference between short-term and
* long-term connections?
*
* In any case, memory-map all of the Configuration models, and apply them to
* both short-term and long-term use.
*
* RDFService doesn't support empty models, so support them with ListCaching
*/
public class ConfigurationModelMakerFactorySPARQL extends
ConfigurationModelMakerFactory {
private final ModelMaker longTermModelMaker;
public ConfigurationModelMakerFactorySPARQL(RDFService longTermRdfService) {
this.longTermModelMaker = new ListCachingModelMaker(new MemoryMappingModelMaker(
new RDFServiceModelMaker(longTermRdfService),
CONFIGURATION_MODELS));
}
@Override
public ModelMaker getModelMaker(RDFService longTermRdfService) {
return addConfigurationDecorators(longTermModelMaker);
}
/**
* The long-term models are all memory-mapped, so use them.
*/
@Override
public ModelMaker getShortTermModelMaker(RDFService shortTermRdfService) {
return addConfigurationDecorators(longTermModelMaker);
}
}

View file

@ -0,0 +1,60 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sparql;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContentModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ListCachingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.MemoryMappingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ShadowingModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
/**
* On a SPARQL endpoint, is there any difference between short-term and
* long-term connections?
*
* Anyway, memory-map the small models, and use a short-term connection for the
* others (when available).
*
* RDFService doesn't support empty models, so support them with ListCaching
*/
public class ContentModelMakerFactorySPARQL extends ContentModelMakerFactory
implements ModelMakerFactory {
private final ModelMaker longTermModelMaker;
public ContentModelMakerFactorySPARQL(RDFService longTermRdfService) {
this.longTermModelMaker = new ListCachingModelMaker(new MemoryMappingModelMaker(
new RDFServiceModelMaker(longTermRdfService),
SMALL_CONTENT_MODELS));
}
/**
* The small content models (tbox, app_metadata) are memory mapped, for
* speed.
*/
@Override
public ModelMaker getModelMaker(RDFService longTermRdfService) {
return addContentDecorators(longTermModelMaker);
}
/**
* For short-term use, the large models (abox) will come from a short-term
* service. The small models can be the memory-mapped ones that we created
* for long-term use.
*/
@Override
public ModelMaker getShortTermModelMaker(RDFService shortTermRdfService) {
ModelMaker shortTermModelMaker = new RDFServiceModelMaker(
shortTermRdfService);
// No need to create a fresh memory map of the small models: use the
// long-term ones.
return addContentDecorators(new ShadowingModelMaker(
shortTermModelMaker, longTermModelMaker, SMALL_CONTENT_MODELS));
}
}

View file

@ -0,0 +1,93 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.sparql;
import javax.servlet.ServletContext;
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.modelaccess.ModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceFactorySingle;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql.RDFServiceSparql;
import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.RDFSource;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Create the connection to a SPARQL endpoint.
*
* Depending on the settings, we might use two endpoints: one for reads and one
* for updates.
*
* Create the RDFServiceFactory.
*/
public class RDFSourceSPARQL implements RDFSource {
private static final Log log = LogFactory.getLog(RDFSourceSPARQL.class);
public static final String PROPERTY_SPARQL_ENDPOINT_URI = "VitroConnection.DataSource.endpointURI";
public static final String PROPERTY_SPARQL_UPDATE_ENDPOINT_URI = "VitroConnection.DataSource.updateEndpointURI";
private final ServletContextListener parent;
private final ConfigurationProperties props;
private final StartupStatus ss;
private final String endpointURI;
private final String updateEndpointURI;
private final RDFService rdfService;
private final RDFServiceFactory rdfServiceFactory;
public RDFSourceSPARQL(ServletContext ctx, ServletContextListener parent) {
this.parent = parent;
this.props = ConfigurationProperties.getBean(ctx);
this.ss = StartupStatus.getBean(ctx);
this.endpointURI = props.getProperty(PROPERTY_SPARQL_ENDPOINT_URI);
this.updateEndpointURI = props
.getProperty(PROPERTY_SPARQL_UPDATE_ENDPOINT_URI);
this.rdfService = createRDFService();
this.rdfServiceFactory = createRDFServiceFactory();
}
private RDFService createRDFService() {
if (updateEndpointURI == null) {
ss.info(parent, "Using endpoint at " + endpointURI);
return new RDFServiceSparql(endpointURI);
} else {
ss.info(parent, "Using read endpoint at " + endpointURI
+ " and update endpoint at " + updateEndpointURI);
return new RDFServiceSparql(endpointURI, updateEndpointURI);
}
}
private RDFServiceFactory createRDFServiceFactory() {
return new RDFServiceFactorySingle(this.rdfService);
}
@Override
public RDFServiceFactory getRDFServiceFactory() {
return this.rdfServiceFactory;
}
@Override
public ModelMakerFactory getContentModelMakerFactory() {
return new ContentModelMakerFactorySPARQL(this.rdfService);
}
@Override
public ModelMakerFactory getConfigurationModelMakerFactory() {
return new ConfigurationModelMakerFactorySPARQL(this.rdfService);
}
@Override
public void close() {
if (this.rdfService != null) {
this.rdfService.close();
}
}
}

View file

@ -0,0 +1,45 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.tdb;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ConfigurationModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ListCachingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.MemoryMappingModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
/**
* In TDB, is there any difference between short-term and long-term connections?
*
* In any case, memory-map all of the Configuration models, and apply them to
* both short-term and long-term use.
*
* RDFService doesn't support empty models, so support them with ListCaching
*/
public class ConfigurationModelMakerFactoryTDB extends
ConfigurationModelMakerFactory {
private final ModelMaker longTermModelMaker;
public ConfigurationModelMakerFactoryTDB(RDFService longTermRdfService) {
this.longTermModelMaker = new ListCachingModelMaker(new MemoryMappingModelMaker(
new RDFServiceModelMaker(longTermRdfService),
CONFIGURATION_MODELS));
}
@Override
public ModelMaker getModelMaker(RDFService longTermRdfService) {
return addConfigurationDecorators(longTermModelMaker);
}
/**
* The long-term models are all memory-mapped, so use them.
*/
@Override
public ModelMaker getShortTermModelMaker(RDFService shortTermRdfService) {
return addConfigurationDecorators(longTermModelMaker);
}
}

View file

@ -0,0 +1,59 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.tdb;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContentModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ListCachingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.MemoryMappingModelMaker;
import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.ShadowingModelMaker;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
/**
* In TDB, is there any difference between short-term and long-term connections?
*
* Anyway, memory-map the small models, and use a short-term connection for the
* others (when available).
*
* RDFService doesn't support empty models, so support them with ListCaching
*/
public class ContentModelMakerFactoryTDB extends ContentModelMakerFactory
implements ModelMakerFactory {
private final ModelMaker longTermModelMaker;
public ContentModelMakerFactoryTDB(RDFService longTermRdfService) {
this.longTermModelMaker = new ListCachingModelMaker(new MemoryMappingModelMaker(
new RDFServiceModelMaker(longTermRdfService),
SMALL_CONTENT_MODELS));
}
/**
* The small content models (tbox, app_metadata) are memory mapped, for
* speed.
*/
@Override
public ModelMaker getModelMaker(RDFService longTermRdfService) {
return addContentDecorators(longTermModelMaker);
}
/**
* For short-term use, the large models (abox) will come from a short-term
* service. The small models can be the memory-mapped ones that we created
* for long-term use.
*/
@Override
public ModelMaker getShortTermModelMaker(RDFService shortTermRdfService) {
ModelMaker shortTermModelMaker = new RDFServiceModelMaker(
shortTermRdfService);
// No need to create a fresh memory map of the small models: use the
// long-term ones.
return addContentDecorators(new ShadowingModelMaker(
shortTermModelMaker, longTermModelMaker, SMALL_CONTENT_MODELS));
}
}

View file

@ -0,0 +1,85 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.impl.tdb;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletContext;
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.modelaccess.ModelMakerFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceFactorySingle;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.tdb.RDFServiceTDB;
import edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.RDFSource;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Create the connection to the TDB triple-store.
*
* Create the RDFService on the directory. Create the RDFServiceFactory.
*/
public class RDFSourceTDB implements RDFSource {
private static final Log log = LogFactory.getLog(RDFSourceTDB.class);
private static final String DIRECTORY_TDB = "tdbModels";
private final ConfigurationProperties props;
private final StartupStatus ss;
private final RDFService rdfService;
private final RDFServiceFactory rdfServiceFactory;
public RDFSourceTDB(ServletContext ctx, ServletContextListener parent) {
this.props = ConfigurationProperties.getBean(ctx);
this.ss = StartupStatus.getBean(ctx);
try {
this.rdfService = createRdfService();
this.rdfServiceFactory = createRDFServiceFactory();
ss.info(parent, "Initialized the RDF source for TDB");
} catch (IOException e) {
throw new RuntimeException(
"Failed to set up the RDF source for TDB", e);
}
}
private RDFService createRdfService() throws IOException {
String vitroHome = props.getProperty("vitro.home");
String directoryPath = vitroHome + File.separatorChar + DIRECTORY_TDB;
return new RDFServiceTDB(directoryPath);
}
private RDFServiceFactory createRDFServiceFactory() {
return new RDFServiceFactorySingle(this.rdfService);
}
@Override
public RDFServiceFactory getRDFServiceFactory() {
return this.rdfServiceFactory;
}
@Override
public ModelMakerFactory getContentModelMakerFactory() {
return new ContentModelMakerFactoryTDB(this.rdfService);
}
@Override
public ModelMakerFactory getConfigurationModelMakerFactory() {
return new ConfigurationModelMakerFactoryTDB(this.rdfService);
}
@Override
public void close() {
if (this.rdfService != null) {
this.rdfService.close();
}
}
}

View file

@ -22,14 +22,11 @@ edu.cornell.mannlib.vitro.webapp.config.RevisionInfoSetup
edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory$Setup
### this listener must be run before SDBSetup, all models setups and WebappDaoSetup ###
edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaPersistentDataSourceSetup
edu.cornell.mannlib.vitro.webapp.servlet.setup.RDFServiceSetup
# 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
edu.cornell.mannlib.vitro.webapp.servlet.setup.ModelMakerSetup
edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup