Index: nuxeo-platform-relations-api/src/main/java/org/nuxeo/ecm/platform/relations/api/Graph.java
===================================================================
--- nuxeo-platform-relations-api/src/main/java/org/nuxeo/ecm/platform/relations/api/Graph.java (revision 25385)
+++ nuxeo-platform-relations-api/src/main/java/org/nuxeo/ecm/platform/relations/api/Graph.java (working copy)
@@ -240,4 +240,14 @@
*/
boolean write(OutputStream out, String lang, String base);
+ /**
+ * Returns true if graph needs to be shared by the service.
+ *
+ * This is supposed to happen in restricted use cases, for instance when
+ * dealing with memory graphs in tests.
+ *
+ * @return true if graph is shared.
+ */
+ boolean isShared();
+
}
Index: nuxeo-platform-relations-core/src/test/java/org/nuxeo/ecm/platform/relations/DummyGraphType.java
===================================================================
--- nuxeo-platform-relations-core/src/test/java/org/nuxeo/ecm/platform/relations/DummyGraphType.java (revision 25385)
+++ nuxeo-platform-relations-core/src/test/java/org/nuxeo/ecm/platform/relations/DummyGraphType.java (working copy)
@@ -133,4 +133,8 @@
public void remove(List statements) {
}
+ public boolean isShared() {
+ return false;
+ }
+
}
Index: nuxeo-platform-relations-core/src/main/java/org/nuxeo/ecm/platform/relations/services/RelationService.java
===================================================================
--- nuxeo-platform-relations-core/src/main/java/org/nuxeo/ecm/platform/relations/services/RelationService.java (revision 25385)
+++ nuxeo-platform-relations-core/src/main/java/org/nuxeo/ecm/platform/relations/services/RelationService.java (working copy)
@@ -68,7 +68,8 @@
private final Map graphDescriptionRegistry;
- private final Map graphRegistry;
+ // registry of memory graphs
+ private transient final Map graphRegistry;
private final Map resourceAdapterRegistry;
@@ -316,9 +317,11 @@
graph.setName(name);
graph.setOptions(options);
graph.setNamespaces(namespaces);
- // put it in registry for later retrieval
- graphRegistry.put(name, graph);
-
+ // put it in registry for later retrieval if it is shared (happens for
+ // memory graphs in tests)
+ if (graph.isShared()) {
+ graphRegistry.put(name, graph);
+ }
return graph;
}
@@ -346,7 +349,7 @@
public Set getAllResources(Object object) {
// TODO OPTIM implement reverse map in registerContribution
Set res = new HashSet();
- for (String ns: resourceAdapterRegistry.keySet()) {
+ for (String ns : resourceAdapterRegistry.keySet()) {
ResourceAdapter adapter = getResourceAdapterForNamespace(ns);
if (adapter == null) {
continue;
Index: nuxeo-platform-relations-facade/src/main/java/org/nuxeo/ecm/platform/relation/ejb/RelationManagerBean.java
===================================================================
--- nuxeo-platform-relations-facade/src/main/java/org/nuxeo/ecm/platform/relation/ejb/RelationManagerBean.java (revision 25385)
+++ nuxeo-platform-relations-facade/src/main/java/org/nuxeo/ecm/platform/relation/ejb/RelationManagerBean.java (working copy)
@@ -21,7 +21,9 @@
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
@@ -60,6 +62,11 @@
private static final Log log = LogFactory.getLog(RelationManagerBean.class);
+ /**
+ * registry of graphs; session bean ensures that there is only one per user
+ */
+ private Map graphRegistry;
+
private transient RelationManager service;
@PostActivate
@@ -68,6 +75,7 @@
try {
// get Runtime service
service = Framework.getRuntime().getService(RelationManager.class);
+ graphRegistry = new Hashtable();
} catch (Exception e) {
log.error("Could not get relation service", e);
}
@@ -81,7 +89,14 @@
// TODO: maybe hack here to get graph in a cleaner way
public Graph getGraphByName(String name) throws ClientException {
try {
- Graph graph = service.getGraphByName(name);
+ Graph graph = graphRegistry.get(name);
+ if (graph == null) {
+ graph = service.getGraphByName(name);
+ }
+ if (graph != null) {
+ // store it for later retrieval
+ graphRegistry.put(name, graph);
+ }
return graph;
} catch (Throwable t) {
throw EJBExceptionHandler.wrapException(t);
Index: nuxeo-platform-relations-jena-plugin/src/main/java/org/nuxeo/ecm/platform/relations/jena/JenaGraph.java
===================================================================
--- nuxeo-platform-relations-jena-plugin/src/main/java/org/nuxeo/ecm/platform/relations/jena/JenaGraph.java (revision 25385)
+++ nuxeo-platform-relations-jena-plugin/src/main/java/org/nuxeo/ecm/platform/relations/jena/JenaGraph.java (working copy)
@@ -72,6 +72,7 @@
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.SimpleSelector;
import com.hp.hpl.jena.rdf.model.StmtIterator;
+import com.hp.hpl.jena.shared.Lock;
/**
* Jena plugin for NXRelations.
@@ -88,6 +89,8 @@
private static final Log log = LogFactory.getLog(JenaGraph.class);
+ private transient DBConnection connection;
+
private transient Model graph;
private String name;
@@ -121,6 +124,7 @@
protected RuntimeException wrapException(Exception e) {
// force reload of graph when an error occurs
+ connection = null;
graph = null;
return new RuntimeException(e);
}
@@ -144,14 +148,13 @@
* using options
* @return the Jena graph (model)
*/
- protected Model getGraph(boolean forceReload) {
- if (this.graph == null || forceReload) {
+ protected synchronized Model getGraph(boolean forceReload) {
+ if (graph == null || forceReload) {
// create model given backend
if (backend.equals("memory")) {
- this.graph = ModelFactory.createDefaultModel(ModelFactory.Convenient);
+ graph = ModelFactory.createDefaultModel(ModelFactory.Convenient);
} else if (backend.equals("sql")) {
// create a database connection
- DBConnection conn = null;
if (datasource != null) {
try {
InitialContext context = new InitialContext();
@@ -161,7 +164,7 @@
// so ask the metadata to produce the connection so that
// it is unwrapped and handles its own transaction.
DatabaseMetaData md = wrapped.getMetaData();
- conn = new DBConnection(md.getConnection(),
+ connection = new DBConnection(md.getConnection(),
databaseType);
} catch (NamingException e) {
throw new IllegalArgumentException(String.format(
@@ -180,52 +183,52 @@
"Database driver class %s not found",
databaseDriverClass));
}
- conn = new DBConnection(databaseUrl, databaseUser,
+ connection = new DBConnection(databaseUrl, databaseUser,
databasePassword, databaseType);
}
// check if named model already exists
- if (conn.containsModel(name)) {
- ModelMaker m = ModelFactory.createModelRDBMaker(conn,
+ if (connection.containsModel(name)) {
+ ModelMaker m = ModelFactory.createModelRDBMaker(connection,
ModelFactory.Convenient);
- this.graph = m.openModel(name);
+ graph = m.openModel(name);
} else {
// create it
// check if other models already exist for that connection.
- if (conn.getAllModelNames().hasNext()) {
+ if (connection.getAllModelNames().hasNext()) {
// other models already exist => do not set parameters
// on driver.
- if (databaseDoCompressUri != conn.getDriver().getDoCompressURI()) {
+ if (databaseDoCompressUri != connection.getDriver().getDoCompressURI()) {
log.warn(String.format(
"Cannot set databaseDoCompressUri attribute to %s "
+ "for model %s, other models already "
+ "exist with value %s",
databaseDoCompressUri, name,
- conn.getDriver().getDoCompressURI()));
+ connection.getDriver().getDoCompressURI()));
}
- if (databaseTransactionEnabled != conn.getDriver().getIsTransactionDb()) {
+ if (databaseTransactionEnabled != connection.getDriver().getIsTransactionDb()) {
log.warn(String.format(
"Cannot set databaseTransactionEnabled attribute to %s "
+ "for model %s, other models already "
+ "exist with value %s",
databaseTransactionEnabled, name,
- conn.getDriver().getIsTransactionDb()));
+ connection.getDriver().getIsTransactionDb()));
}
} else {
if (databaseDoCompressUri) {
- conn.getDriver().setDoCompressURI(true);
+ connection.getDriver().setDoCompressURI(true);
}
if (databaseTransactionEnabled) {
- conn.getDriver().setIsTransactionDb(true);
+ connection.getDriver().setIsTransactionDb(true);
}
}
- ModelMaker m = ModelFactory.createModelRDBMaker(conn,
+ ModelMaker m = ModelFactory.createModelRDBMaker(connection,
ModelFactory.Convenient);
- this.graph = m.createModel(name);
+ graph = m.createModel(name);
}
}
- this.graph.setNsPrefixes(this.namespaces);
+ graph.setNsPrefixes(this.namespaces);
}
- return this.graph;
+ return graph;
}
/**
@@ -335,11 +338,11 @@
/**
* Gets Jena statement selector corresponding to the NXRelations statement.
*
+ * @param graph the jena graph
* @param nuxStatement NXRelations statement
* @return jena statement selector
*/
- private SimpleSelector getJenaSelector(Statement nuxStatement) {
- Model graph = getGraph();
+ private SimpleSelector getJenaSelector(Model graph, Statement nuxStatement) {
com.hp.hpl.jena.rdf.model.Resource subjResource = null;
com.hp.hpl.jena.graph.Node subject = getJenaNode(nuxStatement.getSubject());
if (subject != null && subject.isURI()) {
@@ -364,12 +367,12 @@
* Reified statements may be retrieved from the Jena graph and set as
* properties on NXRelations statements.
*
+ * @param graph the jena graph
* @param jenaStatement jena statement
* @return NXRelations statement
*/
- private Statement getNXRelationsStatement(
+ private Statement getNXRelationsStatement(Model graph,
com.hp.hpl.jena.rdf.model.Statement jenaStatement) {
- Model graph = getGraph();
Node subject = getNXRelationsNode(jenaStatement.getSubject().asNode());
Node predicate = getNXRelationsNode(jenaStatement.getPredicate().asNode());
Node object = getNXRelationsNode(jenaStatement.getObject().asNode());
@@ -394,15 +397,16 @@
/**
* Gets NXRelations statement list corresponding to the Jena statement list.
*
+ * @param graph the jena graph
* @param jenaStatements jena statements list
* @return NXRelations statements list
*/
- private List getNXRelationsStatements(
+ private List getNXRelationsStatements(Model graph,
List jenaStatements) {
List nuxStmts = new ArrayList();
for (com.hp.hpl.jena.rdf.model.Statement jenaStmt : jenaStatements) {
if (!jenaStmt.getSubject().isAnon()) {
- nuxStmts.add(getNXRelationsStatement(jenaStmt));
+ nuxStmts.add(getNXRelationsStatement(graph, jenaStmt));
}
}
return nuxStmts;
@@ -471,8 +475,10 @@
}
public void add(List statements) {
+ Model graph = null;
try {
- Model graph = getGraph();
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.WRITE);
for (Statement nuxStmt : statements) {
com.hp.hpl.jena.graph.Node subject = getJenaNode(nuxStmt.getSubject());
com.hp.hpl.jena.graph.Node predicate = getJenaNode(nuxStmt.getPredicate());
@@ -505,12 +511,18 @@
}
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
public void remove(List statements) {
+ Model graph = null;
try {
- Model graph = getGraph();
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.WRITE);
for (Statement nuxStmt : statements) {
com.hp.hpl.jena.graph.Node subject = getJenaNode(nuxStmt.getSubject());
com.hp.hpl.jena.graph.Node predicate = getJenaNode(nuxStmt.getPredicate());
@@ -530,38 +542,56 @@
}
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
@SuppressWarnings("unchecked")
public List getStatements() {
+ Model graph = null;
try {
- Model graph = getGraph();
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
StmtIterator it = graph.listStatements();
- return getNXRelationsStatements(it.toList());
+ return getNXRelationsStatements(graph, it.toList());
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
@SuppressWarnings("unchecked")
public List getStatements(Statement statement) {
+ Model graph = null;
try {
- SimpleSelector selector = getJenaSelector(statement);
- Model graph = getGraph();
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
+ SimpleSelector selector = getJenaSelector(graph, statement);
StmtIterator it = graph.listStatements(selector);
- return getNXRelationsStatements(it.toList());
+ return getNXRelationsStatements(graph, it.toList());
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
@SuppressWarnings("unchecked")
public List getSubjects(Node predicate, Node object) {
+ Model graph = null;
try {
- Model graph = getGraph();
- SimpleSelector selector = getJenaSelector(new StatementImpl(null,
- predicate, object));
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
+ SimpleSelector selector = getJenaSelector(graph, new StatementImpl(
+ null, predicate, object));
ResIterator it = graph.listSubjectsWithProperty(
selector.getPredicate(), selector.getObject());
List res = new ArrayList();
@@ -571,17 +601,24 @@
return res;
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
@SuppressWarnings("unchecked")
public List getPredicates(Node subject, Node object) {
+ Model graph = null;
try {
- SimpleSelector selector = getJenaSelector(new StatementImpl(
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
+ SimpleSelector selector = getJenaSelector(graph, new StatementImpl(
subject, null, object));
- Model graph = getGraph();
StmtIterator it = graph.listStatements(selector);
- List statements = getNXRelationsStatements(it.toList());
+ List statements = getNXRelationsStatements(graph,
+ it.toList());
List res = new ArrayList();
for (Statement stmt : statements) {
Node predicate = stmt.getPredicate();
@@ -593,13 +630,19 @@
return res;
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
public List getObjects(Node subject, Node predicate) {
+ Model graph = null;
try {
- Model graph = getGraph();
- SimpleSelector selector = getJenaSelector(new StatementImpl(
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
+ SimpleSelector selector = getJenaSelector(graph, new StatementImpl(
subject, predicate, null));
NodeIterator it = graph.listObjectsOfProperty(
selector.getSubject(), selector.getPredicate());
@@ -610,6 +653,10 @@
return res;
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
@@ -617,27 +664,39 @@
if (statement == null) {
return false;
}
+ Model graph = null;
try {
- Model graph = getGraph();
- SimpleSelector selector = getJenaSelector(statement);
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
+ SimpleSelector selector = getJenaSelector(graph, statement);
return graph.contains(selector.getSubject(),
selector.getPredicate(), selector.getObject());
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
public boolean hasResource(Resource resource) {
+ if (resource == null) {
+ return false;
+ }
+ Model graph = null;
try {
- if (resource == null) {
- return false;
- }
- Model graph = getGraph();
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
com.hp.hpl.jena.graph.Node jenaNodeInst = getJenaNode(resource);
RDFNode jenaNode = graph.asRDFNode(jenaNodeInst);
return graph.containsResource(jenaNode);
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
@@ -650,38 +709,52 @@
* @return integer number of statements in the graph
*/
public Long size() {
+ Model graph = null;
try {
- Model jenaGraph = getGraph();
- return jenaGraph.size();
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
+ return graph.size();
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
-
}
public void clear() {
+ Model graph = null;
try {
- Model jenaGraph = getGraph();
- jenaGraph.removeAll();
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
+ graph.removeAll();
// XXX AT: remove reification quadlets explicitely
- RSIterator it = jenaGraph.listReifiedStatements();
+ RSIterator it = graph.listReifiedStatements();
List rss = new ArrayList();
while (it.hasNext()) {
rss.add(it.nextRS());
}
for (ReifiedStatement rs : rss) {
- jenaGraph.removeReification(rs);
+ graph.removeReification(rs);
}
} catch (Exception e) {
throw wrapException(e);
+ } finally {
+ if (graph != null) {
+ graph.leaveCriticalSection();
+ }
}
}
@SuppressWarnings("unchecked")
public QueryResult query(String queryString, String language, String baseURI) {
+ Model graph = null;
QueryResult res = null;
QueryExecution qe = null;
try {
+ graph = getGraph();
+ graph.enterCriticalSection(Lock.READ);
log.debug(String.format("Running query %s", queryString));
// XXX AT: ignore language for now
if (language != null && !language.equals("sparql")) {
@@ -690,7 +763,7 @@
}
Query query = QueryFactory.create(queryString);
query.setBaseURI(baseURI);
- qe = QueryExecutionFactory.create(query, getGraph());
+ qe = QueryExecutionFactory.create(query, graph);
res = new QueryResultImpl(0, new ArrayList(),
new ArrayList