- Anzo Java Programming Model
- Compiling and running examples
- The Basics: DatasetService and named graphs
-
Examples
- Example 1: Using remote graphs
- Example 2: Using local graphs
- Example 3: Embedded Mode
- Example 4: The Selector Tracker
- Example 5: Notification: receiving updates to the local graph without …
- Example 7: SPARQL query
- Example 8: Anzo named graph versioning
- Example 9: The Anzo command execution framework
- Example 10: Anzo command preconditions
- Example 11: Users and access controls
- Example 12: Resetting the database programatically
- Notes
Anzo Java Programming Model
This document will help you get started developing applications using the Anzo server.
Compiling and running examples
- Start the Anzo server by running the appropriate startup script in bin (anzo.bat/start.sh)
- In a new command window, change directory to c:\openanzo-#.#\examples. Make sure javac from a Java JDK is in your path.
- Compile the examples by calling
ant compile
- The examples can be run as ant tasks:
ant run-AccessControl ant run-CommandLinking ant run-CommandWithPrecondition ant run-GraphRevision ant run-LocalGraphNotification ant run-LocalGraphSelectorTracker ant run-LocalGraphWebService ant run-QueryDataset ant run-RemoteGraphAsyncReplication ant run-RemoteGraphWebService ant run-ResetDatabaseWebService ant run-Transactions ant run-ResetDatabaseEmbedded ant run-RemoteGraphEmbedded
Note: Examples ran in embedded mode will only work if the jdbc jar files used to connect to your database are added to the lib directory.
The Basics: DatasetService and named graphs
- DatasetService: The interface to the Anzo server.
The most atomic unit of storage in Anzo is a named graph, a collection of triples named by a URI. If a triple exists in more than one named graph, each such triple is considered to be independent. The two types of graphs we will use are:
- Local Graph: store triples locally (local caching) and performs reads against the cached data
- Remote Graph: does not store triples locally - sends all read requests to the server
Data access in Anzo comprises several variations on the following basic theme: ask for an !INamedGraph interface to a named graph, perform zero or more reads, execute zero or more transactions, and close the graph.
Examples
Sample code found in the examples directory.
The first three examples demonstrate how to connect to Anzo and gain access to named graphs via the Anzo DatasetService interface. We also briefly show the two different ways of connecting to Anzo: the Web Service client and the embedded client. The Web Service client uses Web Service calls to the server to perform all operations against the database layer, while the embedded client speaks directly to the database layer through calls in the same JVM. The two use cases differ only in configuration, not code. The Web Service client is typically used for java-based client multi-user applications while the embedded client API is used in server-side applications which themselves use Anzo in the back end but expose other interfaces to clients.
Example 1: Using remote graphs
The following example can be run by typing:
ant run-RemoteGraphWebService
- Create a remote graph.
- Add statements to the graph.
- Send the changes to the server.
(1) DatasetService datasetService = null;
(2) // use a try-finally to make sure the datasetServices are closed properly
(3) try {
(4)
(5) // Read properties file.
(6) Properties webserviceProperties = new Properties();
(7) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(8)
(9) // instantiate a dataset service
(10) datasetService = new DatasetService(webserviceProperties);
(11)
(12)
(13) // always use try-finally to make sure the graph is closed.
(14) URI namedGraphURI = datasetService.getValueFactory().createURI("http://example.org/ng1");
(15) boolean createIfNecessary = true;
(16) INamedGraph remoteGraph = null;
(17) try {
(18) remoteGraph = datasetService.getRemoteGraph(namedGraphURI, createIfNecessary);
(19) URI res1 = datasetService.getValueFactory().createURI("http://example.org/res1");
(20) URI prop1 = datasetService.getValueFactory().createURI("http://example.org/prop1");
(21)
(22) // all operations to graphs occur in transactions. If any operations are
(23) // applied outside of a begin/commit, each operation is assigned its own
(24) // transaction. Thus, it is recommended that begin/commit subsume as many operations
(25) // as possible.
(26) datasetService.begin();
(27) try {
(28) // do whatever you want to the graph, read write,etc..
(29) remoteGraph.add(res1, prop1, datasetService.getValueFactory().createLiteral("value1" ));
(30) remoteGraph.add(res1, prop1, datasetService.getValueFactory().createLiteral("value2"));
(31) datasetService.commit();
(32) } catch (Exception e) {
(33) datasetService.abort();
(34) throw e;
(35) }
(36)
(37) // Push all transaction to the server synchronously. Even before this replication
(38) // occurs, all graphs created with the given DatasetService will reflect the
(39) // committed transactions.
(40) datasetService.getDatasetReplicator().replicate(true);
(41) } finally {
(42) if (remoteGraph != null)
(43) remoteGraph.close();
(44) }
(45) } finally {
(46) if (datasetService != null) {
(47) datasetService.close();
(48) }
(49) }
(lines 6-7): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(line 10) : Create a dataset service.
(line 14) : Create a URI for the name of a named graph we are interested in.
(line 18) : Get a remote graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
A remote graph performs all transactions and reads directly against the Anzo server, regardless of whether we use a Web Service or embedded client. Statements are never cached locally by the remote graph.
(lines 26-35) : Add two statements to the remote graph in a single transaction.
(line 40) : Send the changes (transaction with two additions) to the server.
Example 2: Using local graphs
The following example can be run by typing:
ant run-LocalGraphWebService
- Create a remote graph.
- Add statements to the graph.
- Send the changes to the server.
- Get a local graph with the same URI as the remote graph.
- Replicate to download the statements from the server (the ones we added using a remote graph.
- Print the statements.
(1) DatasetService datasetService1 = null;
(2) DatasetService datasetService2 = null;
(3)
(4) // use a try-finally to make sure the datasetServices are closed properly
(5) try {
(6)
(7) // Read properties file.
(8) Properties webserviceProperties = new Properties();
(9) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(10)
(11) // instantiate a dataset service
(12) datasetService1 = new DatasetService(webserviceProperties);
(13) // for this example, we disable JMS-based notification to avoid confusion
(14) datasetService1.getNotificationService().setUsingNotification(false);
(15)
(16) // instantiate a dataset service for demonstration purposes
(17) datasetService2 = new DatasetService(webserviceProperties);
(18)
(19)
(20) // always use try-finally to make sure the graph is closed.
(21) URI namedGraphURI = datasetService1.getValueFactory().createURI("http://example.org/ng1");
(22) boolean createIfNecessary = true;
(23) INamedGraph localGraph = null;
(24) INamedGraph remoteGraph = null;
(25) try {
(26)
(27) // create a remote graph for demonstration purposes. In practice, this might be
(28) // occurring on some machine elsewhere.
(29) remoteGraph = datasetService2.getRemoteGraph(namedGraphURI, createIfNecessary);
(30)
(31) // add some properties to the remote graph so that when
(32) // we create a LocalGraph below, we have some data to replicate.
(33) URI res1 = datasetService1.getValueFactory().createURI("http://example.org/res1");
(34) URI prop1 = datasetService1.getValueFactory().createURI("http://example.org/prop1");
(35) datasetService2.begin();
(36) try {
(37) // do whatever you want to the graph, read write,etc..
(38) remoteGraph.add(res1, prop1, datasetService2.getValueFactory().createLiteral("value1" ));
(39) remoteGraph.add(res1, prop1, datasetService2.getValueFactory().createLiteral("value2"));
(40) datasetService2.commit();
(41) } catch (Exception e) {
(42) datasetService2.abort();
(43) throw e;
(44) }
(45)
(46) // Push all transaction to the server synchronously. Even before this replication occurs,
(47) // all graphs dataService2 will reflect the committed transactions. However, the LocalGraph
(48) // created with dataService1 will not contain those statemnets until we replicate it.
(49) datasetService2.getDatasetReplicator().replicate(true);
(50)
(51) // Now for the real example code we are concerned with.
(52)
(53) // create the LocalGraph...
(54) // the third argument indicates that we want to 'track' all statements
(55) // in the named graph.
(56) localGraph = datasetService1.getLocalGraph(namedGraphURI, createIfNecessary, true);
(57)
(58) // the localGraph should be initially empty.
(59) CloseableIterator<Statement> itr = localGraph.getStatements();
(60) System.err.println("Statments before replication (should empty):");
(61) while (itr.hasNext()) {
(62) System.err.println(itr.next().toString());
(63) }
(64) itr.close();
(65) // replicate datasetService1 to bring down the current state. This will grab all triples
(66) // from ng1 because we instatiated the localgraph with a tracker for the named graph. We
(67) // could add other more complicated pattern based trackers instead.
(68) datasetService1.getDatasetReplicator().replicate(true);
(69)
(70) // now we should have some statements
(71) itr = localGraph.getStatements();
(72) System.err.println("Statments after replication:");
(73) while (itr.hasNext()) {
(74) System.err.println(itr.next().toString());
(75) }
(76) itr.close();
(77) } finally {
(78) try {
(79) if (remoteGraph != null)
(80) remoteGraph.close();
(81) } finally {
(82) if (localGraph != null)
(83) localGraph.close();
(84) }
(85) }
(86) } finally {
(87) try {
(88) if (datasetService1 != null)
(89) datasetService1.close();
(90) } finally {
(91) if (datasetService2 != null)
(92) datasetService2.close();
(93) }
(94) }
(lines 8-9): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(lines 12 and 17) : Create instances of dataset services.
(line 14) : Disable notifications for first dataset service.
Notifications are messages sent from the server to update local graphs (locally cached triples) when changes occur on the server.
(line 21) : Create a URI for the name of a named graph we are interested in.
(line 29) : Get a remote graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
A remote graph performs all transactions and reads directly against the Anzo server, regardless of whether we use a Web Service or embedded client. Statements are never cached locally by the remote graph.
(lines 35-44) : Add two statements to the remote graph in a single transaction.
(line 49) : Send the changes (transaction with two additions) to the server.
(line 56) : Get a local graph with the given URI. The second argument specifies that one needs to be created if it does not already exist. Note in this case that the graph will always exist since it was created by the call to get the remote graph.
(lines 58-64) : Print all statements of the local graph (the graph is empty at this point).
(line 68) : Replicate with the server. The statements for the local graph are downloaded and cached locally.
(lines 71-76) : Print the statements in the local graph. This will print the statements that we added to the graph using the remote graph.
Example 3: Embedded Mode
We can run Example 1 using an embedded client simply by modifying just a bit of code.
(5) // Read properties file.
(6) Properties webserviceProperties = new Properties();
(7) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(8)
(9) // instantiate a dataset service
(10) datasetService = new DatasetService(webserviceProperties);
becomes...
(5) // Read properties file.
(6) Properties embeddedclient = new Properties();
(7) embeddedclient.load(new FileInputStream("embeddedclient.properties"));
(8)
(9) // instantiate a dataset service
(10) datasetService = new DatasetService(embeddedclient);
Details on configuring an embedded client can be found here.
Note: Examples ran in embedded mode will only work if the jdbc jar files used to connect to your database are added to the lib directory.
Example 4: The Selector Tracker
The following example can be run by typing:
ant run-LocalGraphSelectorTracker
- Create a remote graph.
- Add statements to the graph.
- Send the changes to the server.
- Get a local graph with the same URI as the remote graph.
- Specify a tracker with a specific pattern.
- Replicate to download the statements that match the tracker pattern.
- Print the downloaded statements.
(1) DatasetService datasetService1 = null;
(2) DatasetService datasetService2 = null;
(3)
(4) // use a try-finally to make sure the datasetServices are closed properly
(5) try {
(6) // Read properties file.
(7) Properties webserviceProperties = new Properties();
(8) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(9)
(10) // instantiate a dataset service
(11) datasetService1 = new DatasetService(webserviceProperties);
(12) // for this example, we disable JMS-based notification to avoid confusion
(13) datasetService1.getNotificationService().setUsingNotification(false);
(14)
(15) // instantiate a dataset service for demonstration purposes
(16) datasetService2 = new DatasetService(webserviceProperties);
(17)
(18)
(19) // always use try-finally to make sure the graph is closed.
(20) URI namedGraphURI = datasetService1.getValueFactory().createURI("http://example.org/ng1");
(21) boolean createIfNecessary = true;
(22) INamedGraph localGraph = null;
(23) INamedGraph remoteGraph = null;
(24) try {
(25)
(26) // create a remote graph for demonstration purposes. In practice, this might be
(27) // occurring on some machine elsewhere.
(28) remoteGraph = datasetService2.getRemoteGraph(namedGraphURI, createIfNecessary);
(29)
(30) // add some properties to the remote graph so that when
(31) // we create a localGraph below, we have some data to replicate.
(32) URI res1 = datasetService1.getValueFactory().createURI("http://example.org/res1");
(33) URI prop1 = datasetService1.getValueFactory().createURI("http://example.org/prop1");
(34) datasetService2.begin();
(35) try {
(36) // do whatever you want to the graph, read write,etc..
(37) remoteGraph.add(res1, prop1, datasetService2.getValueFactory().createLiteral("value1" ));
(38) remoteGraph.add(res1, prop1, datasetService2.getValueFactory().createLiteral("value2"));
(39) datasetService2.commit();
(40) } catch (Exception e) {
(41) datasetService2.abort();
(42) throw e;
(43) }
(44)
(45) // Push all transaction to the server synchronously. Even before this replication occurs,
(46) // all graphs dataService2 will reflect the committed transactions. However, the localGraph
(47) // created with dataService1 will not contain those statemnets until we replicate it.
(48) datasetService2.getDatasetReplicator().replicate(true);
(49)
(50) // Now for the real example code we are concerned with.
(51)
(52) // create the localGraph...
(53) // the third argument indicates that we do not want to 'track' all statements
(54) // in the named graph. We will add a separate, more specific tracker.
(55) localGraph = datasetService1.getLocalGraph(namedGraphURI, createIfNecessary, false);
(56) // this tracker means (any NG, any subject, any property, "value1")
(57) // any permutation is acceptible.
(58) SelectorTracker tracker = new SelectorTracker(null, null, null,datasetService1.getValueFactory().createLiteral("value1"));
(59) datasetService1.getDatasetReplicator().addTracker(datasetService1.getValueFactory().createURI("http://example.org#testSet"), tracker);
(60)
(61) // the localGraph should be initially empty.
(62) CloseableIterator<Statement> itr = localGraph.getStatements();
(63) System.err.println("Statments before replication (should empty):");
(64) while (itr.hasNext()) {
(65) System.err.println(itr.next().toString());
(66) }
(67) itr.close();
(68) // replicate datasetService1 to bring down the current state. This will grab all triples
(69) // from ng1 because we instatiated the localGraph with a tracker for the named graph. We
(70) // could add other more complicated pattern based trackers instead.
(71) datasetService1.getDatasetReplicator().replicate(true);
(72)
(73) // now we should have some statements
(74) itr = localGraph.getStatements();
(75) System.err.println("Statments after replication, should only be 'value1'");
(76) while (itr.hasNext()) {
(77) System.err.println(itr.next().toString());
(78) }
(79) } finally {
(80) try {
(81) if (remoteGraph != null)
(82) remoteGraph.close();
(83) } finally {
(84) if (localGraph != null)
(85) localGraph.close();
(86) }
(87) }
(88) } finally {
(89) try {
(90) if (datasetService1 != null)
(91) datasetService1.close();
(92) } finally {
(93) if (datasetService2 != null)
(94) datasetService2.close();
(95) }
(96) }
(lines 7-8): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(lines 11 and 16) : Create instances of dataset services.
(line 13) : Disable notifications for first dataset service.
(line 20) : Create a URI for the name of a named graph we are interested in.
(line 28) : Get a remote graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
A remote graph performs all transactions and reads directly against the Anzo server, regardless of whether we use a Web Service or embedded client. Statements are never cached locally by the remote graph.
(lines 32-43) : Add two statements to the remote graph in a single transaction.
(line 48) : Send the changes (transaction with two additions) to the server.
(line 55) : Get a local graph with the given URI. The second argument specifies that one needs to be created if it does not already exist. Note in this case that the graph will always exist since it was created by the call to get the remote graph.
(lines 58-59) : Add a tracker to the following pattern: ? ? ? 'value1'
(lines 62-67) : Print all statements of the local graph (the graph is empty at this point).
(line 71) : Replicate with the server. The statements for the local graph are downloaded and cached locally.
(lines 74-78) : Print the statements in the local graph. This will only print the statement added to the graph that matches the pattern specified in the tracker.
Example 5: Notification: receiving updates to the local graph without replication
The following example can be run by typing:
ant run-LocalGraphNotification
- Create a local graph.
- Register an event listener with the local graph.
- Create a remote graph with the same URI as the local graph.
- Replicate the remote graph changes to the server.
This causes the server to send a notification to the local graph to update.
- The event listener is called once the local graph updates with the new statements.
(1) DatasetService datasetService1 = null;
(2) DatasetService datasetService2 = null;
(3) // use a try-finally to make sure the datasetServices are closed properly
(4) try {
(5) // Read properties file.
(6) Properties webserviceProperties = new Properties();
(7) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(8)
(9) // instantiate a dataset service
(10) datasetService1 = new DatasetService(webserviceProperties);
(11) // for this example, we enable JMS-based notification
(12) datasetService1.getNotificationService().setUsingNotification(true);
(13)
(14) // instantiate a dataset service for demonstration purposes
(15) datasetService2 = new DatasetService(webserviceProperties);
(16)
(17)
(18) // always use try-finally to make sure the graph is closed.
(19) URI namedGraphURI = datasetService1.getValueFactory().createURI("http://example.org/ng1");
(20) boolean createIfNecessary = true;
(21) INamedGraph localGraph = null;
(22) INamedGraph remoteGraph = null;
(23) try {
(24)
(25) // create the localGraph...
(26) // the third argument indicates that we do not want to 'track' all statements
(27) // in the named graph. We will add a separate, more specific tracker.
(28) localGraph = datasetService1.getLocalGraph(namedGraphURI, createIfNecessary, false);
(29) URI res1 = datasetService1.getValueFactory().createURI("http://example.org/res1");
(30) URI prop1 = datasetService1.getValueFactory().createURI("http://example.org/prop1");
(31) datasetService1.getDatasetReplicator().replicate(true);
(32) // this tracker means (any named graph, res1, any property, any object)
(33) // any permutation is acceptible.
(34) SelectorTracker tracker = new SelectorTracker(null, res1, null, null);
(35) datasetService1.getDatasetReplicator().addTracker(datasetService1.getValueFactory().createURI("http://example.org#testSet"), tracker);
(36)
(37) // register a listener on the graph to notify us of changes
(38) localGraph.getEventManager().registerListener(new INamedGraphListener() {
(39)
(40) public void statementsDeleted(INamedGraph source, Statement... statements) {
(41) // TODO Auto-generated method stub
(42) }
(43)
(44) public void statementsAdded(INamedGraph source, Statement... statements) {
(45) for(Statement stmt:statements) {
(46) System.err.println("Added:"+stmt.toString());
(47) }
(48) }
(49)
(50) public void notifyEvent(INamedGraph source, IEvent event) {
(51) // TODO Auto-generated method stub
(52) }
(53) });
(54)
(55) // create a remote graph for demonstration purposes. In practice, this might be
(56) // occurring on some machine elsewhere.
(57) remoteGraph = datasetService2.getRemoteGraph(namedGraphURI, createIfNecessary);
(58)
(59) // add some properties to the remote graph
(60) // to be delivered to the localGraph via JMS
(61) datasetService2.begin();
(62) try {
(63) // do whatever you want to the graph, read write,etc..
(64) // we add a random string to the end of the value so each time this example is
(65) // run it adds a different statement to the named graph. Otherwise, the
(66) // additions will be correctly treated as no-ops.
(67) String rand = String.valueOf(Math.random());
(68) remoteGraph.add(res1, prop1, datasetService2.getValueFactory().createLiteral("value1" + rand));
(69) remoteGraph.add(res1, prop1, datasetService2.getValueFactory().createLiteral("value2" + rand));
(70) datasetService2.commit();
(71) } catch (Exception e) {
(72) datasetService2.abort();
(73) throw e;
(74) }
(75)
(76) // Push all transaction to the server synchronously. Even before this replication
(77) // occurs, all graphs dataService2 will reflect the committed transactions. However,
(78) // the localGraph created with dataService1 will not contain those statemnets until
(79) // we replicate it.
(80) datasetService2.getDatasetReplicator().replicate(true);
(81)
(82) // once this replication finish, the statement listener above should
(83) // print some updates.
(84) Thread.sleep(300);
(85) } finally {
(86) try {
(87) if (remoteGraph != null)
(88) remoteGraph.close();
(89) } finally {
(90) if (localGraph != null)
(91) localGraph.close();
(92) }
(93) }
(94) } finally {
(95) try {
(96) if (datasetService1 != null)
(97) datasetService1.close();
(98) } finally {
(99) if (datasetService2 != null)
(100) datasetService2.close();
(101) }
(102) }
(lines 6-7): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(lines 10 and 15) : Create instances of dataset services.
(line 12) : Enable notifications for first dataset service.
(line 19) : Create a URI for the name of a named graph we are interested in.
(line 28) : Get a local graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
(line 31) : Replicate with the server.
(lines 34-35) : Add a tracker to the following pattern: ? res1 ? ?
(lines 38-53) : Register an event listener with the local graph.
(line 57) : Get a remote graph with the same URI as the local graph.
(lines 61-74) : Add two statements to the remote graph in a single transaction.
(line 80) : Replicate the dataset service we used to get the remote graph.
(line 84) : Allow the notification some time to arrive to the client from the server.
Once the notification arrives, the local graph is updated and the event listener is called.
Example 7: SPARQL query
The following example can be run by typing:
ant run-QueryDataset
- Create a remote graph.
- Add some statements to the graph.
- Execute a SPARQL query.
(1) DatasetService datasetService = null;
(2) // use a try-finally to make sure the datasetServices are closed properly
(3) try {
(4) // Read properties file.
(5) Properties webserviceProperties = new Properties();
(6) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(7)
(8) // instantiate a dataset service
(9) datasetService = new DatasetService(webserviceProperties);
(10)
(11)
(12) // always use try-finally to make sure the graph is closed.
(13) URI namedGraphURI = datasetService.getValueFactory().createURI("http://example.org/ng1");
(14) boolean createIfNecessary = true;
(15) INamedGraph remoteGraph = null;
(16) try {
(17)
(18) // create a remote graph for demonstration purposes. In practice, this might be
(19) // occurring on some machine elsewhere.
(20) remoteGraph = datasetService.getRemoteGraph(namedGraphURI, createIfNecessary);
(21)
(22) // add some properties to the remote graph that may be queried
(23) URI res1 = datasetService.getValueFactory().createURI("http://example.org/res1");
(24) URI prop1 = datasetService.getValueFactory().createURI("http://example.org/prop1");
(25) datasetService.begin();
(26) try {
(27) // do whatever you want to the graph, read write,etc..
(28) remoteGraph.add(res1, prop1, datasetService.getValueFactory().createLiteral("value1" ));
(29) remoteGraph.add(res1, prop1, datasetService.getValueFactory().createLiteral("value2"));
(30) datasetService.commit();
(31) } catch (Exception e) {
(32) datasetService.abort();
(33) throw e;
(34) }
(35)
(36) // Push all transaction to the server synchronously.
(37) datasetService.getDatasetReplicator().replicate(true);
(38)
(39) // Now for the real example code we are concerned with.
(40)
(41) // a basic SPARQL query that executes against the remote graph.
(42) // The INamedGraphWithMetaData objects can be used as normal RDF graphs
(43) // for querying, as well as other purposes.
(44) String query = "SELECT ?s ?p ?o WHERE { ?s ?p ?o }";
(45) QueryResult result = datasetService.execQuery(Collections.singleton(remoteGraph.getNamedGraphUri()), Collections.<URI>emptySet(), query);
(46) TupleQueryResult results=result.getSelectResult();
(47) while (results.hasNext()) {
(48) BindingSet sol=results.next();
(49) URI s = (URI)sol.getValue("s");
(50) URI p = (URI)sol.getValue("p");
(51) Value o = sol.getValue("o");
(52) System.err.println(datasetService.getValueFactory().createStatement(s, p, o));
(53) }
(54) } finally {
(55) if (remoteGraph != null)
(56) remoteGraph.close();
(57) }
(58) } finally {
(59) if (datasetService != null)
(60) datasetService.close();
(61) }
(lines 5-6): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(line 9) : Create an instance of a dataset service.
(line 13) : Create a URI for the name of a named graph we are interested in.
(line 20) : Get a remote graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
A remote graph performs all transactions and reads directly against the Anzo server, regardless of whether we use a Web Service or embedded client. Statements are never cached locally by the remote graph.
(lines 23-34) : Add two statements to the remote graph in a single transaction.
(line 37) : Send the changes (transaction with two additions) to the server.
(lines 44-45) : Create and execute a SPARQL query on the server.
(lines 46-53) : Iterate through the result set and print it out.
Example 8: Anzo named graph versioning
The following example can be run by typing:
ant run-GraphRevision
- Create a local graph.
- Modify the graph (add/remove statements) and see how the revision of the graph increments.
- Get an old revision of the graph.
(1) public static void main(String[] args) throws Exception {
(2)
(3)
(4) DatasetService datasetService = null;
(5) // use a try-finally to make sure the datasetServices are closed properly
(6) try {
(7)
(8) // Read properties file.
(9) Properties webserviceProperties = new Properties();
(10) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(11)
(12) // instantiate a dataset service
(13) datasetService = new DatasetService(webserviceProperties);
(14) datasetService.getDatasetReplicator().setReplicationMode(IReplicationService.REPLICATION_IMMEDIATE_SYNC);
(15) final Statement stmt1 = datasetService.getValueFactory().createStatement(datasetService.getValueFactory().createURI("http://subject1"),datasetService.getValueFactory().createURI("http://test.anzo.org/test#property"), datasetService.getValueFactory().createURI("http://object1"));
(16) final Statement stmt2 = datasetService.getValueFactory().createStatement(datasetService.getValueFactory().createURI("http://subject2"), datasetService.getValueFactory().createURI("http://test.anzo.org/test#property"), datasetService.getValueFactory().createURI("http://object2"));
(17)
(18) final URI NAMED_GRAPH_URI = datasetService.getValueFactory().createURI("http://example.org/ng1" + Math.random());
(19) boolean createIfNecessary = true;
(20) boolean addNamedGraphTracker = true;
(21) INamedGraphWithMetaData localGraph1 = null;
(22)
(23) // always use try-finally to make sure the graph is closed.
(24) try {
(25)
(26) localGraph1 = datasetService.getLocalGraph(NAMED_GRAPH_URI, createIfNecessary, addNamedGraphTracker);
(27)
(28) // EDITING A NAMED GRAPH AND OBSERVING THE INCREMENT OF ITS VERSION
(29)
(30) long currentRevision = getNamedGraphRevision(datasetService.getModelService().getCurrentNamedGraphRevision(NAMED_GRAPH_URI));
(31) System.out.println("> Initial revision for the named graph: " + currentRevision);
(32) System.out.println("> adding: " + stmt1);
(33) localGraph1.add(stmt1);
(34)
(35) // check the revision has incremented
(36) currentRevision = getNamedGraphRevision(localGraph1);
(37) System.out.println("> Current revision for the named graph: " + currentRevision);
(38) System.out.println("> adding: " + stmt2);
(39) localGraph1.add(stmt2);
(40)
(41) // check the revision has incremented
(42) currentRevision = getNamedGraphRevision(localGraph1);
(43) System.out.println("> Current revision for the named graph: " + currentRevision);
(44) System.out.println("> removing: " + stmt2);
(45) localGraph1.delete(stmt2);
(46)
(47) // check the revision has incremented
(48) currentRevision = getNamedGraphRevision(datasetService.getModelService().getCurrentNamedGraphRevision(NAMED_GRAPH_URI));
(49) System.out.println("> Current revision for the named graph: " + currentRevision);
(50)
(51) // ACCESSING AN OLD REVISION OF A GRAPH
(52)
(53) INamedGraphWithMetaData localGraph1V2 = datasetService.getModelService().getNamedGraphRevision(NAMED_GRAPH_URI, 2);
(54)
(55) System.out.println("> Named graph revision 2 contains: ");
(56) CloseableIterator<Statement> iter = localGraph1V2.getStatements();
(57) while ( iter.hasNext()) {
(58) System.out.println(" - " + iter.next());
(59) }
(60) iter.close();
(61)
(62) } finally {
(63) if (localGraph1 != null)
(64) localGraph1.close();
(65) }
(66) } finally {
(67) if (datasetService != null)
(68) datasetService.close();
(69) }
(70) }
(71)
(72) /**
(73) * A utility method that extracts the revision number from the given graph and returns
(74) * it.
(75) *
(76) * @param graph the graph containing the revision number
(77) * @return the revision number extracted from the given graph
(78) */
(79) static long getNamedGraphRevision(INamedGraphWithMetaData graph) {
(80) NamedGraph ng = AnzoFactory.getNamedGraph(graph.getNamedGraphUri(), graph.getMetaDataGraph());
(81) return ng.getRevision();
(82) }
(lines 9-10): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(line 13) : Create an instance of a dataset service.
(line 14) : Specify replication mode as immediate synchronous.
Replication modes:
- REPLICATION_MANUAL: replicate only when called upon (when getDatasetReplicator().replicate(sync/async) is called)
- REPLICATION_IMMEDIATE_SYNC: replicate automatically after every transaction submission synchronously
- REPLICATION_IMMEDIATE_ASYNC: replicate automatically after every transaction submission asynchronously
- REPLICATION_AUTOMATIC: replicate automatically after a given time interval passes
(line 18) : Create a URI for the name of a named graph we are interested in.
(line 26) : Get a local graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
(lines 30-31) : Get current revision number of the named graph and print it.
(line 33) : Add a statement.
When begin/commit are not specified, each add/remove is treated as an individual transaction.
(lines 36-37) : Get current revision number of the named graph and print it.
(line 39) : Add a statement.
When begin/commit are not specified, each add/remove is treated as an individual transaction.
(lines 43-44) : Get current revision number of the named graph and print it.
(line 46) : Remove a statement.
When begin/commit are not specified, each add/remove is treated as an individual transaction.
(lines 49-50) : Get current revision number of the named graph and print it.
(line 54) : Get revision 2 of the named graph (this graph is read-only).
(lines 57-61) : Print the statements of the revision 2 graph.
Example 9: The Anzo command execution framework
The following example can be run by typing:
ant run-CommandLinking
- Create a remote graph and send it to the server.
- Create a command that adds a statement and returns it in its execute method.
- Create a command that removes the statement specified in the previous command.
- Chain the two commands into a single 'Chained Command'
- Wire the output of the first command into the input of the second.
- Execute the commands in a single transaction.
(1) DatasetService datasetService = null;
(2) // use a try-finally to make sure the datasetServices are closed properly
(3) try {
(4) // Read properties file.
(5) Properties webserviceProperties = new Properties();
(6) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(7)
(8) // instantiate a dataset service
(9) datasetService = new DatasetService(webserviceProperties);
(10) datasetService.getDatasetReplicator().setReplicationMode(IReplicationService.REPLICATION_MANUAL);
(11)
(12)
(13) URI namedGraphURI = datasetService.getValueFactory().createURI("http://example.org/ng1");
(14) boolean createIfNecessary = true;
(15) boolean addNamedGraphTracker = true;
(16)
(17) // create a local graph and track all of its statements
(18) final INamedGraph localGraph = datasetService.getLocalGraph(namedGraphURI, createIfNecessary, addNamedGraphTracker);
(19)
(20) // send the newly created graph to the server via replication
(21) datasetService.getDatasetReplicator().replicate(true);
(22)
(23) final String inputURI = "input";
(24) final Statement stmt = datasetService.getValueFactory().createStatement(datasetService.getValueFactory().createURI("http://res1"), datasetService.getValueFactory().createURI("http://test.anzo.org/test#property"), datasetService.getValueFactory().createURI("http://res1"));
(25)
(26) // this command adds 'stmt' to the graph
(27) Command addStmtCmd = new CommandImpl() {
(28)
(29) public Object execute() {
(30) System.out.println("> executing 'addStmtCmd'");
(31) System.out.println(" > adding: " + stmt);
(32) localGraph.add(stmt);
(33) System.out.println(" > returning: "+stmt);
(34) return stmt;
(35) }
(36) };
(37)
(38) // this command removes 'stmt' from the graph
(39) Command removeStmtCmd = new CommandImpl() {
(40)
(41) public Object execute() {
(42) System.out.println("> executing 'removeStmtCmd'");
(43) Statement resultFromPreviousCmd = (Statement) getInputProperty(inputURI);
(44) System.out.println(" > getting input: " + resultFromPreviousCmd);
(45) System.out.println(" > removing: " + resultFromPreviousCmd);
(46) localGraph.delete(resultFromPreviousCmd);
(47) System.out.println(" > returning");
(48) return null;
(49) }
(50) };
(51)
(52) // create command chain
(53) CommandChain chain = new CommandChain();
(54) chain.addCommand(addStmtCmd);
(55) chain.addCommand(removeStmtCmd);
(56)
(57) System.out.println("> Linking output of 'addStmtCmd' to the input of 'removeStmtCmd");
(58) // link commands
(59) chain.linkCommand(removeStmtCmd, inputURI, addStmtCmd);
(60)
(61) // execute chain command
(62) datasetService.executeInTransaction(chain);
(63)
(64) if (localGraph != null)
(65) localGraph.close();
(66)
(67) } finally {
(68) if (datasetService != null)
(69) datasetService.close();
(70) }
(lines 5-6): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(line 9) : Create an instance of a dataset service.
(line 10) : Specify replication mode as manual.
Replication modes:
- REPLICATION_MANUAL: replicate only when called upon (when getDatasetReplicator().replicate(sync/async) is called)
- REPLICATION_IMMEDIATE_SYNC: replicate automatically after every transaction submission synchronously
- REPLICATION_IMMEDIATE_ASYNC: replicate automatically after every transaction submission asynchronously
- REPLICATION_AUTOMATIC: replicate automatically after a given time interval passes
(line 13) : Create a URI for the name of a named graph we are interested in.
(line 18) : Get a local graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
(line 21) : Replicate with the server.
(lines 27-36) : Create a command that adds a statement and returns that statement.
(lines 39-50) : Create a command that removes the statement added by the first command.
(lines 53-55) : Create a command chain (command list) that contains the first and second command.
(line 59) : Cain the output of the first command into the input of the second.
(line 62) : Execute the command chain (the two commands) in a single transaction.
Example 10: Anzo command preconditions
The following example can be run by typing:
ant run-CommandWithPrecondition
We create a command, using a precondition that the named graph is at a particular revision. This is the most basic tool to solve multiple clients or threads concurrently modifying a named graph. Before modifying a named graph, a client might assert that the named graph should be at the revision at which they last read it; otherwise, it has been written by someone else since. This is a special case that precludes concurrent modification at the named-graph level. More granular locking can be achieved by asserting preconditions on particular triples in the graph.
(1) public static void main(String[] args) throws Exception {
(2)
(3) DatasetService datasetService = null;
(4) // use a try-finally to make sure the datasetServices are closed properly
(5) try {
(6) // Read properties file.
(7) Properties webserviceProperties = new Properties();
(8) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(9)
(10) // instantiate a dataset service
(11) datasetService = new DatasetService(webserviceProperties);
(12) datasetService.getDatasetReplicator().setReplicationMode(IReplicationService.REPLICATION_MANUAL);
(13)
(14)
(15) URI namedGraphURI = datasetService.getValueFactory().createURI("http://example.org/ng1");
(16) boolean createIfNecessary = true;
(17) boolean addNamedGraphTracker = true;
(18)
(19) // create a local graph and track all of its statements
(20) final INamedGraphWithMetaData localGraph = datasetService.getLocalGraph(namedGraphURI, createIfNecessary, addNamedGraphTracker);
(21)
(22) // send the newly created graph to the server via replication
(23) datasetService.getDatasetReplicator().replicate(true);
(24)
(25) // ------------------------------------------------------------------
(26) // EXAMPLE OF PRECONDITION THAT IS VALID WHEN THE COMMAND IS EXECUTED
(27) // ------------------------------------------------------------------
(28)
(29) // get current revision number for the local graph
(30) long currentRevision = getNamedGraphRevision(datasetService.getModelService().getCurrentNamedGraphRevision(localGraph.getNamedGraphUri()));
(31) final Statement stmt1 = datasetService.getValueFactory().createStatement(datasetService.getValueFactory().createURI("http://res1"), datasetService.getValueFactory().createURI("http://test.anzo.org/test#property"), datasetService.getValueFactory().createURI("http://res2"));
(32)
(33) Command command1 = new CommandImpl() {
(34) public Object execute() {
(35) localGraph.add(stmt1);
(36) return null;
(37) }
(38) };
(39)
(40) // Create a precondition
(41) IPrecondition entryGraphPrecondition = new Precondition();
(42)
(43) // specify the graph to query
(44) Set<URI> defaults = new HashSet<URI>();
(45) defaults.add(localGraph.getMetaDataGraph().getNamedGraphUri());
(46) entryGraphPrecondition.setDefaultGraphUris(defaults);
(47)
(48) // specify the precondition query and expected result
(49) entryGraphPrecondition.setQuery("ASK { <" + localGraph.getNamedGraphUri() + "> <" + NamedGraph.revisionProperty + "> \"" + currentRevision + "\"^^<http://www.w3.org/2001/XMLSchema#long>}");
(50) entryGraphPrecondition.setResult(AskResult.getAskResult(true));
(51)
(52) // add precondition to the command
(53) command1.addPrecondition(entryGraphPrecondition);
(54)
(55) // add the command to the transaction queue
(56) datasetService.executeInTransaction(command1);
(57)
(58) // commit the changes to the server
(59) datasetService.getDatasetReplicator().replicate(true);
(60)
(61) if (localGraph.contains(stmt1))
(62) System.err.println("> stmt1 exist in the local graph");
(63) else
(64) System.err.println("> stmt1 does NOT exist in the local graph");
(65)
(66) // --------------------------------------------------------------------
(67) // EXAMPLE OF PRECONDITION THAT IS INVALID WHEN THE COMMAND IS EXECUTED
(68) // --------------------------------------------------------------------
(69)
(70) final Statement stmt2 = datasetService.getValueFactory().createStatement(datasetService.getValueFactory().createURI("http://res2"), datasetService.getValueFactory().createURI("http://test.anzo.org/test#property"), datasetService.getValueFactory().createURI("http://res2"));
(71)
(72) Command command2 = new CommandImpl() {
(73)
(74) public Object execute() {
(75) localGraph.add(stmt2);
(76) return null;
(77) }
(78) };
(79)
(80) // Create a precondition
(81) IPrecondition entryGraphPrecondition2 = new Precondition();
(82)
(83) Set<URI> defaults2 = new HashSet<URI>();
(84) defaults2.add(localGraph.getMetaDataGraph().getNamedGraphUri());
(85) entryGraphPrecondition2.setDefaultGraphUris(defaults2);
(86)
(87) entryGraphPrecondition2.setQuery("ASK { <" + localGraph.getNamedGraphUri() + "> <" + NamedGraph.revisionProperty + "> \"" + 30 + "\"^^<http://www.w3.org/2002/XMLSchema#long>}");
(88) entryGraphPrecondition2.setResult(AskResult.getAskResult(true));
(89)
(90) command2.addPrecondition(entryGraphPrecondition2);
(91)
(92) datasetService.executeInTransaction(command2);
(93)
(94) // attempt to commit the changes to the server
(95) try {
(96) datasetService.getDatasetReplicator().replicate(true);
(97) } catch (UpdateServerException e) {
(98) System.err.println(">> The command was not committed to the server because the precondition failed.");
(99) }
(100)
(101) if (localGraph.contains(stmt2))
(102) System.err.println("> stmt2 exist in the local graph");
(103) else
(104) System.err.println("> stmt2 does NOT exist in the local graph");
(105)
(106) if (localGraph != null)
(107) localGraph.close();
(108)
(109) } finally {
(110) if (datasetService != null)
(111) datasetService.close();
(112) }
(113) }
(114)
(115) /**
(116) * A utility method that extracts the revision number from the given graph and returns
(117) * it.
(118) *
(119) * @param graph the graph containing the revision number
(120) * @return the revision number extracted from the given graph
(121) */
(122) static long getNamedGraphRevision(INamedGraphWithMetaData graph) {
(123) NamedGraph ng = AnzoFactory.getNamedGraph(graph.getNamedGraphUri(), graph.getMetaDataGraph());
(124) return ng.getRevision();
(125) }
(lines 7-8): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(line 11) : Create an instance of a dataset service.
(line 12) : Specify replication mode as manual.
Replication modes:
- REPLICATION_MANUAL: replicate only when called upon (when getDatasetReplicator().replicate(sync/async) is called)
- REPLICATION_IMMEDIATE_SYNC: replicate automatically after every transaction submission synchronously
- REPLICATION_IMMEDIATE_ASYNC: replicate automatically after every transaction submission asynchronously
- REPLICATION_AUTOMATIC: replicate automatically after a given time interval passes
(line 15) : Create a URI for the name of a named graph we are interested in.
(line 20) : Get a local graph with the given URI. The second argument specifies that one needs to be created if it does not already exist.
(line 23) : Replicate with the server.
(line 30) : Get current revision of the local graph.
(line 33-38) : Create a command that adds a statement to the local graph.
(lines 41-50) : Create a pre-condition that specifies an ASK query and stores the result set of the curretn execution of that query.
(line 53) : Add the pre-condition the the command.
(line 56) : Execute the command as a transaction.
(line 59) : Replicate with the server - send the transaction to the server.
In this case, the pre-condition is valid and the transaction executes as expected.
(lines 72-78) : Create a command that adds a statement to the local graph.
(lines 81-88) : Create a pre-condition that specifies an ASK query and stores the result set of the curretn execution of that query.
(line 90) : Add the pre-condition the the command.
(line 92) : Execute the command as a transaction.
(lines 95-99) : Replicate with the server - send the transaction to the server.
In this case, the pre-condition failes and the transaction therefore fails as well.
(line 107) : Close the graph - all graphs should be closed once they are no longer needed
The close() call on the graph tells the DatasetService? that it is done with the resource. If an application does not release graph resources, it may eventually run out of memory.
(line 111) : Close the dataset service - this deallocates all resources held by this service
Most code that interacts with Anzo will not instantiate or close DatasetService objects. This will typically be handled by single points of setup and tear-down code, once per application.
Example 11: Users and access controls
The following example can be run by typing:
ant run-AccessControl
In this example we show how use the normal named graph API to add new users and roles to Anzo. We then show how to login with this new user and begin exercising their new permissions.
(1) public static void main(String[] args) throws Exception {
(2)
(3) // Here we choose the user and password of the user with access to the system graph
(4) final String sysadmin = "sysadmin";
(5) final String sysadminpw = "123";
(6)
(7) DatasetService datasetService1 = null;
(8) DatasetService datasetService2 = null;
(9)
(10) // use a try-finally to make sure the datasetServices are closed properly
(11) try {
(12) // Read properties file.
(13) Properties webserviceProperties = new Properties();
(14) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(15)
(16) // instantiate a dataset service
(17) datasetService1 = getDatasetService(webserviceProperties, sysadmin, sysadminpw, IReplicationService.REPLICATION_MANUAL);
(18)
(19) // -----------------------------------------
(20) // Create a new graph as user: http://anzo.org/users/sysadmin
(21)
(22) final URI namedGraphURI = datasetService1.getValueFactory().createURI("http://example.org/ng1");
(23) final INamedGraphWithMetaData newNamedGraph = datasetService1.getRemoteGraph(namedGraphURI, true);
(24)
(25) // add a statement to the new graph
(26) URI res1 = datasetService1.getValueFactory().createURI("http://example.org/res1");
(27) URI prop1 = datasetService1.getValueFactory().createURI("http://example.org/prop1");
(28) Literal obj1 = datasetService1.getValueFactory().createLiteral("foo");
(29) newNamedGraph.add(res1, prop1, obj1);
(30)
(31) // commit your changes to the server
(32) datasetService1.getDatasetReplicator().replicate(true);
(33)
(34) // at this point only the current user (sysadmin) has access to this new graph
(35)
(36) // ------------------------------------------
(37) // Create a new user: http://anzo.org/users/newUser
(38)
(39) URI newUser = datasetService1.getValueFactory().createURI("http://anzo.org/users/newUser");
(40) String newUserId = "newUser";
(41) String newUserPwd = "456";
(42) URI newUserDefaultRole = datasetService1.getValueFactory().createURI("http://test.anzo.org/Role/newRole");
(43)
(44) INamedGraphWithMetaData systemGraph = datasetService1.getRemoteSystemGraph();
(45)
(46) // Create a new user using jastor beans.
(47) // NOTE: Always add properties to a new user in a single transaction because each user
(48) // MUST have a username and password. Thus, if you first create a user and then later
(49) // specify her password or username, you will get exceptions.
(50) datasetService1.begin(); // beginning of transaction
(51) try {
(52) // create a new user (resource of type user)
(53) User userJastorObj = AnzoFactory.createUser(newUser,systemGraph.getMetaDataGraph());
(54) // specify the user's default role
(55) userJastorObj.setDefaultRole(newUserDefaultRole);
(56) // specify the user's password
(57) userJastorObj.setPassword(newUserPwd);
(58) // specify the user's userId
(59) userJastorObj.setUserId(newUserId);
(60)
(61) datasetService1.commit(); // end of transaction
(62) } catch (Exception e) {
(63) datasetService1.abort(); // abort the transaction
(64) }
(65)
(66) // commit your changes to the server
(67) datasetService1.getDatasetReplicator().replicate(true);
(68)
(69) // -----------------------------------------
(70) // Give the new user full access to read/edit/etc the new graph
(71)
(72) datasetService1.begin();
(73) try {
(74)
(75) ACLUtil.setPermissions(newNamedGraph, newUserDefaultRole, true, true, true, true, true, true);
(76) datasetService1.commit();
(77)
(78) } catch (Exception e) {
(79) datasetService1.abort();
(80) throw e;
(81) }
(82)
(83) datasetService1.getDatasetReplicator().replicate(true);
(84)
(85) // -----------------------------------------
(86) // Connect to server using the new user and access the newly created graph.
(87)
(88) datasetService2 = getDatasetService(webserviceProperties, newUserId, newUserPwd, IReplicationService.REPLICATION_MANUAL);
(89)
(90) final INamedGraph newGraph2 = datasetService2.getRemoteGraph(namedGraphURI, false);
(91)
(92) // the new user can now access newGraph2 (read, write, etc)
(93)
(94) newGraph2.close();
(95)
(96) datasetService2.getDatasetReplicator().replicate(true);
(97)
(98) } finally {
(99) try {
(100) if (datasetService1 != null)
(101) datasetService1.close();
(102) } finally {
(103) if (datasetService2 != null)
(104) datasetService2.close();
(105) }
(106)
(107) }
(108) }
(109)
(110) /**
(111) * This is a simple method that creates a dataset service with the specified properties,
(112) * username, password and replication mode.
(113) *
(114) * @param props
(115) * @param username
(116) * @param password
(117) * @param replicationMode
(118) * @return
(119) * @throws ReplicationException
(120) */
(121) public static DatasetService getDatasetService(Properties props, String username, String password, int replicationMode) throws ReplicationException {
(122) DatasetService datasetService;
(123) Properties properties = new Properties();
(124) properties.putAll(props);
(125) ModelServiceProperties.setUser(properties, username);
(126) ModelServiceProperties.setPassword(properties, password);
(127) datasetService = new DatasetService(properties);
(128) datasetService.getDatasetReplicator().setReplicationMode(replicationMode);
(129) return datasetService;
(130) }
(lines 13-14): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(line 17) : Create an instance of a dataset service.
(lines 22-32) : Create a named graph, add a statement to it and replicate with the server.
(lines 39-67) : Create a new user and send the changes to the server.
When creating a new user the username and password MUST be specified in a single transaction.
(line 72-83) : Using the ACLUtil, set the permissions of the new named graph to allow the following:
Grant the role in which the new user is in full access to the graph (read/write/etc).
(line 88) : Create a dataset service logged in as the new user.
(line 90) : Access the new graph to which the new user has been granted access.
(lines 98-107) : Close the graphs and dataset services.
The close() call on the graph tells the DatasetService that it is done with the resource. If an application does not release graph resources, it may eventually run out of memory. Most code that interacts with Anzo will not instantiate or close DatasetService? objects. This will typically be handled by single points of setup and tear-down code, once per application.
Example 12: Resetting the database programatically
The following example can be run by typing:
ant run-ResetDatabaseWebService
In the course of development and testing, you will probably want to clear your database several times. This can be easily done by dropping tables or deleting the database itself. However, it's a bit easier it use the built in reset operation on the model service. Before proceeding we warn that the reset call may be fairly expensive if the database is relatively full, and problems can arise if reset is called many times in rapid succession.
Reset takes as an argument, an RDF file that is used to initialize a new server with ACLs, roles, users, etc.
(1) DatasetService datasetService = null;
(2) // use a try-finally to make sure the datasetServices are closed properly
(3) try {
(4) Properties webserviceProperties = new Properties();
(5) webserviceProperties.load(new FileInputStream("webserviceclient.properties"));
(6) // instantiate a dataset service
(7) datasetService = new DatasetService(webserviceProperties);
(8)
(9) StatementCollector sc=new StatementCollector();
(10) try {
(11) RDFParser parser=Rio.createParser(RDFFormat.forFileName("initializeNew.nt"));
(12) InputStream initializationStream = new FileInputStream("initializeNew.nt");
(13) parser.setRDFHandler(sc);
(14) parser.parse(initializationStream, "");
(15) } catch (UnsupportedRDFormatException mse) {
(16) throw new RuntimeException(mse);
(17) }catch (RDFHandlerException mse) {
(18) throw new RuntimeException(mse);
(19) }catch (RDFParseException mse) {
(20) throw new RuntimeException(mse);
(21) }catch (IOException mse) {
(22) throw new RuntimeException(mse);
(23) }
(24)
(25) datasetService.getModelService().reset(sc.getStatements());
(26) } finally {
(27) if (datasetService != null)
(28) datasetService.close();
(29) }
(lines 4-5): Load the webservice.properties into memory.
The webserviceclient.properties file tells the client, among other things, to connect to an Anzo server over a web service on a particular host and port and with a particular user name and password.
(line 7) : Create an instance of a dataset service.
(lines 9-23) : Parse the initialization RDF file into memory (StatementCollector).
(line 25) : Reset the server with the loaded statements.
(lines 26-29) : Close the graphs and dataset services.
The close() call on the graph tells the DatasetService that it is done with the resource. If an application does not release graph resources, it may eventually run out of memory. Most code that interacts with Anzo will not instantiate or close DatasetService objects. This will typically be handled by single points of setup and tear-down code, once per application.
Notes
Things to keep in mind.
Replication
Replication modes:
- REPLICATION_MANUAL: replicate only when called upon (when getDatasetReplicator().replicate(sync/async) is called)
- REPLICATION_IMMEDIATE_SYNC: replicate automatically after every transaction submission synchronously
- REPLICATION_IMMEDIATE_ASYNC: replicate automatically after every transaction submission asynchronously
- REPLICATION_AUTOMATIC: replicate automatically after a given time interval passes
// note: the default mode is manual datasetService.getDatasetReplicator().setReplicationMode(IReplicationService.REPLICATION_IMMEDIATE_SYNC);
- Replication sends all changes (transactions) to the server when using either local or remote graphs.
- Replication also synchronizes the locally cached statements with the tracked statements on the server when using local graphs.
Transactions
- If no transaction boundaries are specified then every add and remove on the graph is performed in a separate transaction, and is very expensive.
- It is very important to abort a transaction should the code enter an exception state before committing. Otherwise, the transaction will remain open and will be continued by other transactions elsewhere in the code.
datasetService.begin(); // start transaction try { // adds/removes datasetService.commit(); // end transaction } catch (Exception e) { datasetService2.abort(); // abort transaction throw e; }
- When you are deep in nested methods and are unsure if you are in a transaction, do the following:
boolean isMe = !datasetService.isInTransaction(); if (isMe) datasetService.begin(); try { // <DO WHATEVER> if(isMe) datasetService.commit(); } catch(Exception e) { if(isMe) datasetService.abort(); throw e; }
Querying
- SPARQL queries can be executed on the local triples by calling:
datasetService.execQuery(...);
- SPARQL queries can be executed on the server by calling:
datasetService.getModelService().execQuery(...);
When making a SPARQL query, you typically have to specify default graphs and named graphs. If you would like to query across all of the statements in Anzo (rather than limiting yourself to enumerated named graphs), use the following URIs:
- http://openanzo.org/namedGraphs/reserved/graphs/ALL : Query all named graphs
- http://openanzo.org/metadataGraphs/reserved/graphs/ALL : Query all metadata graphs (which include user/ACL/role data)
- http://openanzo.org/graphs/reserved/graphs/ALL : Query all data, including named graphs and metadata graphs
Graphs
NamedGraph: a collection of triples named by a URI
The two types of graphs we will use are:
- Local Graph: store triples locally (local caching) and performs reads against the cached data
- Remote Graph: does not store triples locally - sends all read requests to the server
Each NamedGraph has an associated MetadataGraph that contains server provided data about a particular graph, such as its revision number, who created the graph, who last modified the graph, when it was last modified, and the ACL information about the graph. This MetadataGraph also has a server generated URI, which is provided when a NamedGraph is first committed to the server.
namedGraph.getMetadataGraph(); namedGraph.getMetadataGraphUri();
