Anzo Java client 3.0 Migration Guide
The Anzo Java client API has undergone a significant redesign for the release of Open Anzo 3.0. This migration guide is intended to aid users of of the Open Anzo 2.5 Java client in updating their code to version 3.0.
Major changes
- Terminology Changes
- API Simplifications
- Anzo Node API
- The Anzo Graph API
- The Anzo Client Dataset API
- Replication and Replication Modes
- Notification and Events API
- Command API and the Transacion Context
- Anzo Client Configuration and Embedded Mode
Terminology Changes
- "Dataset Service" is replaced by "Anzo Client"
- "Local Model" is replaced by "Replica Graph"
- "Server Model" is replaced by "Server Graph"
Major class replacements
| Anzo Java client 2.5 | Anzo Java client 3.0 |
DatasetService |
AnzoClient |
DatasetServiceProperties |
No replacement, configuration is performed via RDF |
INamedGraphWithMetaData |
IAnzoGraph, ClientGraph |
ModelServiceProperties |
No replacement, configuration is performed via RDF |
INamedGraphListener |
IStatementListener |
CommandImpl |
Command |
.
API Simplifications
DatasetService is replaced by a simpler AnzoClient class. AnzoClient provides the same basic functionality that DatasetService did, but in a simpler and cleaner way.
Many of the objects contained in the DatasetService such as the NotificationService, EventManager, TransactionManager, DatasetServiceReplicator, ModelApi, ResetApi, UpdateApi, ReplicationApi, RulesApi, QueryApi, and IndexApi are not included in AnzoClient. The useful methods from these classes are now provided directly by the AnzoClient class. This makes it easier for developers to find the methods they are looking for. We begin with a few important simplifications before delving into each API component in detail.
API simplifications:
| Anzo Java client 2.5 | Anzo Java client 3.0 |
DatasetService datasetService =
new DatasetService(properties);
|
// slightly more code, but no configuration properties required!
INamedGraph configGraph = AnzoClientConfigurationFactory.createJMSConfiguration(user, password, host, port);
AnzoClient client = new AnzoClient(configGraph);
|
datasetService
.getNotificationService()
.isNotificationEnabled();
|
// Notification, now split into three
// distinct client components,
// is always enabled, and used by the
// three components independently.
|
datasetService
.getDatasetReplicator
.replicate(true);
|
// to send local changes to server
client.updateRepository();
// because notification is always on,
// the local replica is maintained automatically
// and so client initiated replicaion is not required.
// In extreme cases, the application
// may require replication so to
// retrieve changes made by other
// users from server.
client.replicate();
|
datasetService.getNotificationService()
.setUsingNotification(true);
|
// see above
|
datasetService.getModelService()
.setServiceUser("username");
|
client.setServiceUser("username");
|
INamedGraphWithMetaData graphCurrent =
datasetService.getModelService()
.getCurrentNamedGraphRevision(graphUri);
|
IAnzoGraph graphCurrent =
client.getCurrentNamedGraphRevision(graphUri);
|
INamedGraphWithMetaData graphVersion2 =
datasetService.getModelService()
.getNamedGraphRevision(graphUri, 2);
|
IAnzoGraph graphVersion2 =
client.getNamedGraphRevision(graphUri, 2);
|
datasetService
.getTransactionManager().begin();
|
client.begin();
|
datasetService
.getTransactionManager().commit();
|
client.commit();
|
datasetService
.getTransactionManager().abort();
|
client.abort();
|
INamedGraphWithMetaData systemGraph =
getLocalSystemGraph(true);
|
ClientGraph systemGraph =
getReplicaGraph(
Constants.defaultSystemGraphURI);
|
INamedGraphWithMetaData systemGraph =
getRemoteSystemGraph(true);
|
ClientGraph systemGraph =
getServerGraph(
Constants.defaultSystemGraphURI);
|
datasetService.execQuery(...);
|
client.replicaQuery(...);
|
datasetService
.getModelService().execQuery(...);
|
client.serverQuery(...);
|
datasetService.getModelService().reset(stmts);
|
client.reset(stmts);
|
Anzo Node API
Anzo no longer depends on OpenRDF's Node API. Instead it now provides it's own RDF Node API. org.openanzo.rdf.Constants.valueFactory is an instance of org.openanzo.rdf.ValueFactory that may be used to instantiate instances of Node API objects. Alternatively, Mem* implementations of the various node objects each provide a create method. Either approach works, but using the ValueFactory is good practice in case the implementing classes change.
| 2.5 - OpenRDF's Node API | 3.0 - Anzo Node API |
import org.openrdf.model.URI;
import org.openrdf.model.BNode;
import org.openrdf.model.Resource;
import org.openrdf.model.Literal;
|
import org.openanzo.rdf.URI;
import org.openanzo.rdf.BlankNode;
import org.openanzo.rdf.Resource;
import org.openanzo.rdf.Literal;
|
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.model.vocabulary.OWL;
import org.openrdf.model.vocabulary.XMLSchema;
...
|
import org.openanzo.rdf.vocabulary.RDF;
import org.openanzo.rdf.vocabulary.RDFS;
import org.openanzo.rdf.vocabulary.OWL;
import org.openanzo.rdf.vocabulary.XMLSchema;
...
|
new MemURI(...);
new MemBNode(...);
new MemLiteral(...);
...
|
Constants.valueFactory.createURI(...);
Constants.valueFactory.createBnode(...);
Constants.vlaueFactory.createPlainLiteral(...);
// or
MemURI.create(...);
MemBlankNode.create(...);
MemPlainLiteral.create(...);
...
|
new BooleanMemLiteral(true);
new IntegerMemLiteral(1);
...
|
Constants.valueFactory.createTypedLiteral(true);
Constants.valueFactory.createTypedLiteral(1);
// or
MemTypedLiteral.create(true);
MemTypedLiteral.create(1);
...
|
new StatementImpl(s,p,o,g);
|
Constants.valueFactory.createStatement(s,p,o,g);
// or
new Statement(s,p,o,g);
|
new ContextStatementImpl(s,p,o,g);
|
Constants.valueFactory.createStatement(s,p,o,g);
// or
new Statement(s,p,o,g);
|
if(literal.isTypedLiteral()) {
String datatype = literal.getDatatype();
}
|
if (literal instanceof TypedLiteral) {
URI datatype = ((TypedLiteral)literal).getDatatype();
}
|
if(literal.isPlainLiteral()) {
String lang literal.getLanguage();
}
|
if (literal instanceof PlainLiteral) {
String lang = ((PlainLiteral)literal).getLanguage();
}
|
lang = literal.getLanguage();
if(lang != null) {
foo(lang);
}
|
if (literal instanceof PlainLiteral) {
PlainLiteral plain = ((PlainLiteral)literal);
if(plain.hasLiteral()) {
foo(lang);
}
}
|
QueryResult results
= anzoClient.executeServerQuery(...);
TupleQueryResult tupleResult
= results.getSelectResult();
while (tupleResult.hasNext()) {
BindingSet solution = result.next();
solution.getValue("s");
}
|
QueryResults results
= anzoClient.executeServerQuery(...);
for(PatternSolution solution : results.getSelectResults()) {
Value value = solution.getBinding("s");
...
}
|
.
The Anzo Graph API
The Anzo named graph API, located in org.openanzo.rdf and anchored by org.openanzo.rdf.INamedGraph, completely defines the operations on named graphs issued by AnzoClient operations. This represents a bit of a change from Anzo 2.5 where various named graph interfaces and implementations were spread out over various packages. The full named graph API is specified in [AnzoClientDesign].
AnzoClient operations such as getReplicaGraph and getServerGraph return instances of IAnzoGraph a subclass of NamedGraph that exposes a metadata graph. This interface replaces NamedGraphWithMeta. The particular implementation of IAnzoGraph is ClientGraph. This class is part of the public API because it provides a shortcut and more efficient way to get the revision of the graph, but in most cases developers can program against IAnzoGraph.
Note that replica and server graphs are both implemented using ClientGraph. The naming may seem a bit confusing. A replica graph is maintained in the local replica and find calls are all local finds. Whereas, all read on server graphs go against the server. All reads to both types of graphs are proxied through the set of committed transactions, and all writes are queued up as transactions to be sent to the server via updateRepository(). ClientGraph was chosen as a name for the implementation of INamedGraph because they are graphs managed by the AnzoClient.
| Anzo Java client 2.5 | Anzo Java client 3.0 |
NamedGraphWithMetaData localModel =
datasetService
.getLocalGraph(GRAPH_URI, false, true);
client.replicate();
|
// graph will automatically be replicated and up-to-date
// when this method completes
ClientGraph graph = client
.getReplicaGraph(GRAPH_URI);
|
NamedGraphWithMetaData remoteModel =
datasetService
.getRemoteGraph(GRAPH_URI, false, true);
|
ClientGraph graph = client
.getServerGraph(GRAPH_URI);
|
datasetService.isNamedGraphStored(graphUri);
|
client.namedGraphExists(graphUri);
|
datasetService.getModelService()
.findStatements(s,p,o, graphUri);
|
ClientGraph graph
= client.getServerGraph(graphUri);
graph.find(s,p,o);
// or
client.serverFind(s, p, o, graphUri);
|
datasetService
.getModelService().getSize(graphUri);
|
client.getServerGraph(graphUri).size();
|
localModel.delete(...);
|
replicaGraph.remove(...);
|
remoteModel.delete(...);
|
serverGraph.remove(...);
|
Collection<URI> uris =
datasetService.getModelService()
.getStoredNamedGraphs();
|
Collection<URI> uris =
client.getNamedGraphs();
|
client.closeLocalGraph((LocalGraph) graph);
|
graph.close();
|
client.closeRemoteGraph((RemoteGraph) graph);
|
graph.close();
|
The Anzo Client Dataset API
Much like the graph API, The base classes and interfaces for the dataset API are located in the package org.openanzo.rdf. Also like the graph API, the Anzo client package provides more advanged implementations, but maintains the same interface for easy of use.
The basic IDataset interface has been simplified in Anzo 3.0. For complete details, see [AnzoClientDesign], but the main simplification is that named and default graphs are both added to datasets by URI, and the underlying implementation is responsible for manufacturing and maintaining the lifecycles of the actual INamedGraph instances.
The nature of the IDatasets handed out by AnzoClient remains similar to their Anzo 2.5 counterparts. In particular, AnzoClient offers two kinds of datasets. The first are datasets that always reflect the current replica and server graphs managed by the client. AnzoClient.getAllServerGraphsDataset and AnzoClient.getAllReplicaGraphsDataset replace DatasetService.getCurrentRemoteDataset and DatasetService.getCurrentLocalDataset respectively. DatasetService.getCurrentDataset that maintained a dataset of all local and remote graphs in 2.5, has no replacement in Anzo 3.0.
The second IDataset implementation provided by AnzoClient.createReplicaDataset and AnzoClient.createServerDataset manages collections of replica and server graphs respectively, allowing the developer to read from and write to those graphs as a whole, using the inherited IQuadStore interface of IDataset. A new feature in Anzo 3.0 is that the developer can specify in the factory call whether or not to persist the RDF serialization of the default and named graphs in the dataset, automatically, via a replica or server graph, also maintained by the dataset. These stored datasets can be used in Sparql queries against the server. In each of the examples below, the boolean argument false indicates that the datasets are not to be stored on the server.
Dataset API changes:
| Anzo Java client 2.5 | Anzo Java client 3.0 |
IDataset localDataset =
datasetService.getLocalDataSet(
datasetUri, true, false, false,
defaultGraphs, namedGraphs);
|
IDataset replicaDataset =
client.createReplicaDataset(
false, datasetUri, defaultGraphs, namedGraphs);
|
IDataset remoteDataset =
datasetService.getRemoteDataSet(
datasetUri, true, false,
defaultGraphs, namedGraphs);
|
IDataset serverDataset =
client.createServerDataset(
false, datasetUri, defaultGraphs, namedGraphs);
|
IDataset dataset =
datasetService.getCurrentDataset();
|
// no replacement
|
IDataset localDataset =
datasetService.getCurrentLocalDataset();
|
IDataset replicaDataset =
client.getAllReplicaGraphsDataset();
|
IDataset remoteDataset =
datasetService.getCurrentRemoteDataset();
|
IDataset serverDataset =
client.getAllServerGraphsDataset();
|
Iterator<URI> graphs =
dataset.getNamedGraphs();
|
Set<URI> graphUris =
dataset.getNamedGraphUris();
|
dataset.addNamedGraphUri(graphUri);
|
dataset.addNamedGraph(graphUri);
|
dataset.removeNamedGraphUri(graphUri);
|
dataset.removeNamedGraph(graphUri);
|
dataset.getNamedGraphsSize();
|
dataset.getNamedGraphUris().size();
|
Iterable<URI> graphs =
dataset.getDefaultNamedGraphs();
|
Set<URI> graphUris =
dataset.getDefaultGraphUris();
|
dataset.find(s,p,o, graphUri);
|
dataset.find(false, s,p,o, graphUri);
|
dataset.findAll(s,p,o, graphUri);
|
dataset.find(true, s,p,o, graphUri);
|
datasetService.executeQuery(
localDataset,
"Select ?s ?p ?o FROM ...");
|
dataset.executeQuery("Select ?s ?p ?o FROM ...");
|
Replication and Replication Modes
Replication
The concept of replication, while used internally to keep the local replica updated, has been mostly removed from the Anzo API. In Anzo 2.5, replication was a two phase process of first sending all committed tranasactions to the server (update), and next bringing down any changes to graphs in the replica (replicate). Applications would invoke DatasetService.replicate when they either needed to send updates to the server, or check for updates to the local replica, or both. Automatic, or background replications were used to keep the replica as up to date as possible, and to send committed transactions to the server without the application having to do so explicitly.
In Anzo 3.0, the second phase of replication is achieved through a subtle combination of the Named Graph Update notification system (described below), and targeted calls that replicate only select graphs. Also, because JMS is the primary transport for all client-server communication, the replica is automatically kept up-to-date so there is no need for applications to call replicate.
Thus, where in Anzo 2.5, the application called DatasetService.replicate() to send updates to the server, in Anzo 3.0 we have AnzoClient.updateRepository. This call, once completed successfully, assures that all committed transactions are sent to the server, and that the contents of these transactions are also committed to the local replica. (Recall that before updateRepository all pending changes while visible to replica and server graphs, reside only in the transaction queue).
An important change worth noting as a caution, is that AnzoClient.updateRepository is a synchronized call. If an update is in progress and a second thread attempts to invoke another, that second thread will block until the first finishes. In Anzo 2.5, replications would queue up, but subsequent calls would return immediately instead of blocking. This made it difficult to track exceptions raised by update calls.
We have left AnzoClient.replicate() in the Anzo API, though developers are encouraged to rely on the updates provided automatically by Named Graph Update notification. Note that no code is needed to make this happen. Simply create a replica graph and updates will come.
Replication modes
Because of these fundamental changes, the concept of replication modes no longer makes sense. The last remnant of replication modes is AnzoClient.setUpdateOnCommit(true). This call will cause every committ to fire an updateRepository. This can be thought of as the IMMEDIATE_SYNC replication mode when enabled, and MANUAL otherwise.
We now suggest alternatives to the replication modes that have been removed.
IMMEDIATE_ASYNC
IMMEDIATE_ASNYC mode performed a replication in a seperate thread on each commit. Such background processing was deemed beyond the scope of the Anzo API. Developers are encouraged to use whichever threading approach used in the rest of their application to perform updateRepository in the background.
AUTOMATIC
Because of Named Graph Update notifications, automatic replication, for the purpose of keeping the replica up to date is no longer required. Developers that would like automatic and background updateRepository behavior should implement this simple mechamism for their applications.
Notification and Events API
The Anzo 2.5 notification and eventing model was extremely powerful, yet quite difficult to understand and make use of without intimate knowledge about the semantics and timing of all the different events it exposed. In Anzo 3.0 we have maintained, and in fact expanded, the feature set, while at the same time, significantly simplifying the API. Since the events API has changed so drastically, we provide a brief survey of the new 3.0 version, and then show how 2.5 event use cases map onto the new 3.0 API.
Anzo 3.0 provides five main types of events
* Connectivity - the connectivity status of the Anzo Client is exposed through IAnzoClientConnectionListener's
clientConnected and clientDisconnected events.
* Statement updates - IStatementListener instances may be registered in a number of places in the
Anzo Client API, providing statementAdded and statementRemoved events.
* Transactions - ITransactionListener instances may be registered in a couple spots in the Anzo Client API,
providing transactionComplete and transactionFailed events.
* Statement channels - IStatementChannelListener instances may be registered on instances of IStatementChannel
to receive messages on statement channels (this is a new feature).
* Commands - ICommandListener instance may be registered on the CommandManager to receive notifications commands
of a specific commandType, or all commands.
Anzo 3.0 provides three JMS-based notification components. All three components share the same underlying JMS connection, and coupled with the fact that JMS provides the default request-response transport for all client-server requests, the concept of notifification-enabled/disabled has been completely removed.
* Named Graph Updates - provides statement events on INamedGraph and IDataset instances handed out by such AnzoClient
methods as getReplicaGraph, getServerGraph, createReplicaDataset, etc.. Also provides transaction events on the AnzoClient for transactions involving replica and server graphs. This same mechanism is used internally to keep the local replica up to date without the application having to make replicate() calls.
* Realtime Updates - formerly known as selector trackers, realtime updates provide realtime notification of changes to arbitrary
statement patterns, completely independent of any replica or server graphs the user has created. The RealtimeUpdateManager provides methods for adding these realtime trackers, as well as subscribing to global transaction events, all independent of graphs and transactions involving the local replica and server graphs.
It's worth emphasizing how seperate these two mechanisms are. Those developers at least a little familiar with the inner workings of Anzo 2.5 will remember that tracker-based notification and tracker-based replication provided the basis for how the replica was kept up to date. In 3.0, tracker-based notifications (realtime updates) operate on seperate JMS topics from named graph updates and provides completely seperate and complimentary functionality.
* Statement channels - This feature provides JMS-based notifications from client to client, bypassing the repository to avoid storage where it isn't required. It is essentially a simple pub-sub system built atop the Anzo client and authentication mechanisms, with an appealing RDF/semantic feel to it. Since statement channels are not a replacement for any 2.5 features, we stop our discussion here. For a better description see [AnzoClientDesign].
The SelectorTracker class has been removed. Instead, Trackers are registered and unregistered by their "Quad Pattern" against the RealtimeUpdateManager. A listener must be provided.
client.getRealtimeUpdates().addTracker(subj, null, null, graphUri, listener);
Since multiple listeners can potentially be registered to track the same "Quad pattern" A single listner may be removed from a tracker by specifying it: unregister the listener.
client.getRealtimeUpdates().removeTrackerListener(subj, null, null, graphUri, listener);
To remove a tracker completely:
client.getRealtimeUpdates().removeTracker(subj, null, null, graphUri, listener);
Changes to the events API:
| Anzo Java client 2.5 | Anzo Java client 3.0 |
SelectorTracker objectTracker
= new SelectorTracker(null, null, null, object);
datasetService.getDatasetReplicator()
.addTracker(trackerGroup, objectTracker);
|
client.getRealtimeUpdates().addTracker(null, null, object, null, listener);
|
datasetService.getDatasetReplicator()
.removeTracker(trackerGroup, objectTracker);
|
client.getRealtimeUpdates().removeTrackerListener(null, null, object, null, listener);
|
datasetService
.getNotificationService()
.setUsingNotification(true);
|
// removed as per discsussion
// above.
|
// All this to receive command events in 2.5
datasetService.getEventManager()
.registerListener(new INamedGraphListener() {
public void statementsDeleted(INamedGraph source,
Statement... statements) {}
public void statementsAdded(INamedGraph source,
Statement... statements) {}
public void notifyEvent(INamedGraph source,
IEvent event) {
if (event instanceof
TransactionProcessingFinishedEvent) {
TransactionProcessingFinishedEvent e1 =
((TransactionProcessingFinishedEvent) event);
for (ITransactionCommand command
: e1.getTransaction().getCommands()) {
// do something with the commmand
}
}
}
});
|
// In 3.0, command events are isolated nicely
CommandManager = new CommandManager(client);
manager.registerCommandListener(new ICommandListener() {
public void commandCompleted(URI commandType, INamedGraph commandContext) {
// do something with the command
}
public void commandFailed(...) {
}
});
|
localModel.getEventManager().registerListener(
new INamedGraphListener() {
public void statementsDeleted(
INamedGraph source, Statement... s) {
}
public void notifyEvent(
INamedGraph source, IEvent event) {
}
public void statementsAdded(
INamedGraph source, Statement... s) {
}
});
|
replicaGraph.registerListener(
new IStatementListener<ITracker>() {
public void statementsRemoved(
INamedGraph source, Statement... s) {
}
public void statementsAdded(
INamedGraph source, Statement... s) {
}
});
|
datasetService.getDatasetReplicator()
.registerReplicationListener(
new IReplicationListener() {
public void trackerUnregistered(ITracker tracker) {
}
public void trackerRegistered(ITracker tracker) {
}
public void replicationStarted() {
}
public void replicationFailed(Throwable exception) {
}
public void replicationCompleted(Long marker) {
}
});
|
// those specific events were deemed too low level
// and have been removed.
// Instead applications should listen for actual
// transactions to complete or fail
client.addTransactionListner(
new ITransactionListener() {
transactionComplete(URI transactionURI,
long transactionTimestamp,
Set<URI> transactionGraphs,
IDataset transactionContext) {
}
transactionFailed(...) {
}
});
|
.
Command API and the Transaction Context
A CommandManager class has been added as a central point of management for command related operations to maintain and simplify the command functionality used by Anzo 2.5 applications. However, based on observed command API usage patterns, Anzo 3.0 provides a much more powerful generalization of commands, upon which the CommandManager runs. We briefly describe this now.
Users of Anzo (Boca) 2.5, found the commandType string such a useful mechanism for providing context for statement additions and deletions within a transaction, that many began to even encode RDF statements within this string. This seemed like a nice semantic generalization of the existing feature, and so Anzo 3.0 includes a better way of doing the same thing.
Transactions now have a "transaction context", a named graph whose URI is the URI of the current transaction or sub-transaction. In Anzo 3.0, nested begin() calls actually create a new sub-transaction, with a new transaction context graph and transaction URI. The server of course treates a top level transaction and its children as a single transaction, but the mechanism provides a way for the application to specify context at a more granular level. The transaction context graph is not stored anywhere, but both the Named Graph Update and Realtime Update notification systems provide the transaction context as an IDataset of context graphs to their respective transaction events on the AnzoClient and RealtimeUpdateManager.
Here is a rough outline of how it works.
anzoClient.begin();
anzoClient.getTransactionContext.add(statementAboutOuterTransaction)
// update some graphs
anzoClient.begin();
anzoClient.getTransactionContext.add(statementAboutInnerTransaction);
// update some more graphs
anzoClient.commit();
anzoClient.commit();
// on the same or on another client
anzoClient.registerTransactionListener(.......IDatset transactionContext ....) {
// search the transaction context for information about what transactions were committed
// all contexts of a top-level transaction and its children will arrive
// in a single transactionContext IDataset.
}
So given this new, more powerful mechanism, why have we maintained the Command API? Quite simply, many of our users found it a useful programming paradigm, and migrating their applications to Anzo 3.0 would be difficult without it. Furthemore, the simple commandType-based eventing is a simple way to react to transactions of certain types without having to build an additional eventing mechanism atop transaction listeners.
That said, it is recommended that users who were using the commandType to transport RDF switch to using the transaction context where appropriate.
Changes to the Command API itself are as follows:
| Anzo Java client 2.5 | Anzo Java client 3.0 |
ICommand command = new Command() {
public Object execute() {
graph.add(stmt1);
graph.add(stmt2);
return null;
}
public String getCommandType() {
return "addCommand";
}
};
|
Command command = new CommandImpl() {
public Object execute() {
localModel1.add(stmt1);
localModel1.add(stmt2);
return null;
}
public String getCommandType() {
return "addCommand";
}
};
|
datasetService.executeInTransaction(...);
|
// create one command manager for each AnzoClient
CommandManager manager = new CommandManager(client);
// use it thoroughout the code to execute transactions
manager.execute(...);
|
CommandChain chain = new CommandChain();
|
// create one command manager for each AnzoClient
CommandManager manager = new CommandManager(client);
// use it throughout the code to create command chains
CommandChain chain = manager.createCommandChain();
|
datasetService.getTransactionManager()
.executeInTransaction(chain);
|
chain.execute();
|
Not pictured here, but shown in the section on Notification and Events, is the ICommandListener mechanism for reacting to command events.
Anzo Client Configuration and Embedded Mode
In Anzo 2.5, clients (and in fact servers as well) were configured using properties files. Without getting into details beyond the scope of this document, in Anzo 3.0 clients (and servers) are primarily configured using simple RDF files that determine how the various components interact with one another. For example, a JMS Anzo Client, is simply a configuration specifying backend components that connect to the server via JMS. An Embedded Anzo Client, is simply client configured with backend components that connect directly to the Anzo repository and underlying relational database through straight Java calls.
Even thoug these RDF configuration files are relatively straight forward, they introduce complexity beyond what most users want to deal with. Fortunately, we have AnzoClientConfigurationFactory that can create Anzo Client RDF configurations for well known client types: JMS/Embedded, Persisted/Non-persisted. The user need only provide connectivity details such as username, password, host, port, and database connection information if necessary.
To configure a standard JMS-based client we have:
String user = "default"; String password = "123"; String host = "tcp://localhost"; int port = 61616; INamedGraph configGraph = AnzoClientConfigurationFactory.createJMSConfiguration(user, password, host, port); AnzoClient anzoClient = new AnzoClient(configGraph);
To configure an embedded mode client we must specify the database connection information, as well as an ldap repository for authentication.
String user = "default";
String password = "123";
String host = "tcp://localhost";
int port = 61616;
String dbType = "HSQL";
String dbUrl = "jdbc:hsqldb:mem:anzodb";
String dbUser = "sa";
String dbPassword = "";
INamedGraph configGraph = AnzoClientConfigurationFactory.createEmbeddedConfiguration(user, password,"ANZO", dbType, dbUrl, dbUser, dbPassword, true, host, port);
AnzoClientConfigurationFactory.configureNonPersistedClient(configGraph);
String ldapHost = properties.getProperty("org.openanzo.services.ldap.host");
if (ldapHost != null) {
String ldapPort = properties.getProperty("org.openanzo.services.ldap.port");
AnzoClientConfigurationFactory.configureLdapConnection(configGraph, ldapHost, Integer.valueOf(ldapPort));
}
AnzoClient anzoClient = new AnzoClient(configGraph);
Previous sections described how JMS-based notification is always enabled in the Anzo Client. This is not exactly true for embedded mode clients. The boolean parameter in createEmbeddedConfiguration determines whether or not the embedded client should use JMS. If JMS is not enabled, an embedded client will fully function except for certain notification features. However, in such cases, the Anzo Client is used primarily as a database connection-like API and so eventing is not a required feature.
Download in other formats:


