diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/TripleSource.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/TripleSource.java index d799a1bd7..67fad9e35 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/TripleSource.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/TripleSource.java @@ -24,4 +24,7 @@ public interface TripleSource extends Application.Module{ OntModelCache getShortTermOntModels(RDFService shortTermRdfService, OntModelCache longTermOntModelCache); + + /** Ways in which this TripleSource behaves oddly. */ + TripleStoreQuirks getQuirks(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/TripleStoreQuirks.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/TripleStoreQuirks.java new file mode 100644 index 000000000..19d7ad6c0 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/TripleStoreQuirks.java @@ -0,0 +1,18 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.modules.tripleSource; + +import com.hp.hpl.jena.rdf.model.Model; + +/** + * TODO + */ +public interface TripleStoreQuirks { + + /** + * Test to see whether the FileGraph must be updated to reflect the current + * state of the file. + */ + boolean hasFileGraphChanged(Model fromFile, Model previous, String graphURI); + +} 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 d98b551d2..4fbd5d8c2 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 @@ -218,12 +218,15 @@ public class FileGraphSetup implements ServletContextListener { path.getFileName(), dbModel.size(), fileModel.size())); - boolean isIsomorphic = dbModel.isIsomorphicWith(fileModel); + // Isomorphism has some quirky issues with TDB, and perhaps also with Virtuoso. + boolean isChanged = ApplicationUtils.instance() + .getContentTripleSource().getQuirks() + .hasFileGraphChanged(fileModel, dbModel, graphURI); if (dbModel.isEmpty() && !fileModel.isEmpty()) { dbModel.add(fileModel); modelChanged = true; - } else if (!isIsomorphic) { + } else if (isChanged) { log.info("Updating " + path + " because graphs are not isomorphic"); log.info("dbModel: " + dbModel.size() + " ; fileModel: " + fileModel.size()); dbModel.removeAll(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/DefaultTripleStoreQuirks.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/DefaultTripleStoreQuirks.java new file mode 100644 index 000000000..5365a8bb8 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/DefaultTripleStoreQuirks.java @@ -0,0 +1,19 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.triplesource.impl; + +import com.hp.hpl.jena.rdf.model.Model; + +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.TripleStoreQuirks; + +/** + * The behavior for non-quirky TripleSource implementations. + */ +public class DefaultTripleStoreQuirks implements TripleStoreQuirks { + + @Override + public boolean hasFileGraphChanged(Model fromFile, Model previous, String graphURI) { + return !fromFile.isIsomorphicWith(previous); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sdb/ContentTripleSourceSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sdb/ContentTripleSourceSDB.java index 9b129c0d8..33feb8a73 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sdb/ContentTripleSourceSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sdb/ContentTripleSourceSDB.java @@ -38,11 +38,13 @@ import edu.cornell.mannlib.vitro.webapp.modelaccess.ontmodels.UnionModelsOntMode import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.TripleStoreQuirks; 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.rdfservice.impl.logging.LoggingRDFServiceFactory; import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; +import edu.cornell.mannlib.vitro.webapp.triplesource.impl.DefaultTripleStoreQuirks; import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; /** @@ -76,6 +78,8 @@ public class ContentTripleSourceSDB extends ContentTripleSource { static final boolean DEFAULT_TESTONBORROW = true; static final boolean DEFAULT_TESTONRETURN = true; + + private final TripleStoreQuirks quirks = new DefaultTripleStoreQuirks(); private ServletContext ctx; private ComboPooledDataSource ds; @@ -205,6 +209,11 @@ public class ContentTripleSourceSDB extends ContentTripleSource { return new UnionModelsOntModelsCache(combinedCache, CONTENT_UNIONS); } + @Override + public TripleStoreQuirks getQuirks() { + return quirks; + } + @Override public String toString() { return "ContentTripleSourceSDB[" + ToString.hashHex(this) + "]"; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java index e2f48f3a4..70d7c2cce 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java @@ -13,11 +13,13 @@ import edu.cornell.mannlib.vitro.webapp.modelaccess.ontmodels.OntModelCache; import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.TripleStoreQuirks; 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.logging.LoggingRDFServiceFactory; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql.RDFServiceSparql; +import edu.cornell.mannlib.vitro.webapp.triplesource.impl.DefaultTripleStoreQuirks; import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; @@ -35,6 +37,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; public class ContentTripleSourceSPARQL extends ContentTripleSource { private String endpointURI; private String updateEndpointURI; // Optional + + private final TripleStoreQuirks quirks = new DefaultTripleStoreQuirks(); private RDFService rdfService; private RDFServiceFactory rdfServiceFactory; @@ -132,6 +136,11 @@ public class ContentTripleSourceSPARQL extends ContentTripleSource { return longTermOntModelCache; } + @Override + public TripleStoreQuirks getQuirks() { + return quirks; + } + @Override public String toString() { return "ContentTripleSourceSPARQL[" + ToString.hashHex(this) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ConfigurationTripleSourceTDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ConfigurationTripleSourceTDB.java index 187205daf..cecc0053d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ConfigurationTripleSourceTDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ConfigurationTripleSourceTDB.java @@ -18,6 +18,7 @@ import edu.cornell.mannlib.vitro.webapp.modelaccess.ontmodels.OntModelCache; import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.TripleStoreQuirks; 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; @@ -39,9 +40,10 @@ import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; * Memory-map all of the configuration models, and add the standard decorators. */ public class ConfigurationTripleSourceTDB extends ConfigurationTripleSource { - private static final String DIRECTORY_TDB = "tdbModels"; + private final TripleStoreQuirks quirks = new TDBTripleStoreQuirks(); + private volatile RDFService rdfService; private RDFServiceFactory rdfServiceFactory; private RDFService unclosableRdfService; @@ -112,6 +114,11 @@ public class ConfigurationTripleSourceTDB extends ConfigurationTripleSource { return longTermOntModelCache; } + @Override + public TripleStoreQuirks getQuirks() { + return quirks; + } + @Override public String toString() { return "ConfigurationTripleSourceTDB[" + ToString.hashHex(this) + "]"; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java index 439cf2a63..2fde9f53d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java @@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.modelaccess.ontmodels.OntModelCache; import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; +import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.TripleStoreQuirks; 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; @@ -39,6 +40,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; * Memory-map the small content models, and add the standard decorators. */ public class ContentTripleSourceTDB extends ContentTripleSource { + private final TripleStoreQuirks quirks = new TDBTripleStoreQuirks(); + private String tdbPath; private volatile RDFService rdfService; @@ -124,6 +127,11 @@ public class ContentTripleSourceTDB extends ContentTripleSource { return longTermOntModelCache; } + @Override + public TripleStoreQuirks getQuirks() { + return quirks; + } + @Override public String toString() { return "ContentTripleSourceTDB[" + ToString.hashHex(this) + "]"; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/TDBTripleStoreQuirks.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/TDBTripleStoreQuirks.java new file mode 100644 index 000000000..936c93f03 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/TDBTripleStoreQuirks.java @@ -0,0 +1,58 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.triplesource.impl.tdb; + +import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDinteger; +import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDnonNegativeInteger; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; + +import edu.cornell.mannlib.vitro.webapp.triplesource.impl.DefaultTripleStoreQuirks; + +/** + * TDB has some odd behaviors to deal with. + */ +public class TDBTripleStoreQuirks extends DefaultTripleStoreQuirks { + private static final Log log = LogFactory + .getLog(TDBTripleStoreQuirks.class); + + /** + * When the file graph was previously written to the TDB store, TDB mangled + * some of the literal types: any type of XMLSchema#nonNegativeInteger was + * changed to XMLSchema#integer. + * + * We need to mangle our new model in the same way before comparing to the + * previous one. + */ + @Override + public boolean hasFileGraphChanged(Model fromFile, Model previous, + String graphURI) { + try { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + fromFile.write(buffer, "N-TRIPLE"); + String fromString = buffer.toString("UTF-8"); + + String mangleString = fromString.replace( + XSDnonNegativeInteger.getURI(), XSDinteger.getURI()); + InputStream mangleStream = new ByteArrayInputStream( + mangleString.getBytes("UTF-8")); + Model mangled = ModelFactory.createDefaultModel(); + mangled.read(mangleStream, null, "N-TRIPLE"); + + return !mangled.isIsomorphicWith(previous); + } catch (Exception e) { + log.warn("Failed to test for changes in filegraph. " + + "Change assumed.", e); + return true; + } + } + +}