Project

General

Profile

Actions

UserAPI » History » Revision 7

« Previous | Revision 7/9 (diff) | Next »
Alex Hall -, 05/23/2008 07:23 PM


= Connection API =
Overview
Mulgara now supports a new interface called a `Connection`. This will be replacing the current `ItqlInterpreterBean` interface as the full suite of utilities becomes available.

The existing `ItqlInterpreterBean` interface provides a completely automated connection mechanism, based on the URLs of graphs referenced in TQL queries. While convenient, this has several undesirable effects:

  • All queries issued to this interface must contain at least one URL for a graph on the server that will handle the query.
  • Arbitrary graph names are not permitted. Graph names must follow a particular format, and will include the hostname of the server containing the graph.
  • Queries against graphs must be changed when the server hosting the graph changes.
  • Connections to a server cannot be cached.
  • Distributed queries (queries where the requested data comes from more than one server) are sent to an arbitrary server and not necessarily the most desirable one.
  • Query languages which use a default graph name (like [http://www.w3.org/TR/rdf-sparql-query/ SPARQL]) cannot identify a server if no graph names are given.

The `Connection` interface avoids these issues by establishing a link to a specified server. This link can be to a server running in the current process, over inter-process-communication (IPC) to a server running on the same machine, or across a network. Queries and commands can be sent along this link, and all operations will be performed by the server that has been connected to.

The `Connection` interface and its supporting classes are found in the `org.mulgara.connection` package.

Connection Factory
While Connections can be created directly, the `ConnectionFactory` class attempts to manage connections to ensure that the correct type is created, and reduce network overhead. The connections returned by a `ConnectionFactory` are only managed by that factory, and will not interfere with connections from a separate factory instance.

`Connection`s can be established based on the URL of a database (in the form ''protocol''://''host''/''service'') or by wrapping a `Session` instance. The `Session` interface has existed in Mulgara for some time, and it may be more appropriate for existing code to use its internal `Session` instances to create new `Connection`s.

When the `ConnectionFactory` is used to obtain a connection based on the database URL, the factory will first check to see if it has previously established a `Connection` to that database. If it has, and the connection is no longer in use, then it will try to re-use the resources associated with that previous connection that are cached in the factory. This will avoid setting up a new remote session with the database, which in turn should reduce network overhead. The `ConnectionFactory` is designed to support concurrent access by multiple clients in different threads; if two clients simultaneously get `Connection`s to the same database, the `Connection`s they receive will be distinct and commands issued on one will not interfere with commands issued on the other. Note, however, that the `Connection` itself is not designed for concurrent access.

When the `ConnectionFactory` is used to obtain a connection based on an existing `Session` instance, no caching is performed. It is assumed that the user will take responsibility for managing their own `Session`s since they are using a lower-level API.

For the moment, the only supported protocol is ''rmi''. Other protocols, including ''http'' are expected shortly.

Using a Connection === Commands ===
Once a `Connection` has been created, commands can be sent on it using the `execute` method. Alternatively, commands also have their own `execute` method that can be applied to a connection, with the same effect.

The following is an example of using a Connection to create a graph, and load a file into that graph: {{{
#!java
// define the server we want to connect to
URI serverURI = new URI;
// define the file we want to load
URI dataFile = new File("data.rdf").toURI();
// define the name of the graph to load the data into
URI myData = new URI;

// Create a factory, and connect to the server
ConnectionFactory factory = new ConnectionFactory();
Connection connection = factory.newConnection(serverUri);
// execute a CREATE command
connection.execute(new CreateGraph(myData));
// execute a LOAD command
connection.execute(new Load(dataFile, myData, true));
// cleaning up the connection allows the network resources to be re-used
connection.close();
}}}

Executing a command returns a String containing a message related to the success of the command. If commands are kept, then it is also possible to retrieve the last message from a command with the `getResultMessage` method.

=== Queries ===
Queries are a type of command that return an `Answer` instead of a message string. Queries can be created using either the TQL or SPARQL parsers: {{{
#!java
// define the server we want to connect to
URI serverURI = new URI;

// Create a factory, and connect to the server
ConnectionFactory factory = new ConnectionFactory();
Connection connection = factory.newConnection(serverUri);
// Use a SPARQL query
Query query = new SparqlInterpreter().parseQuery(
"SELECT * FROM <test:data> WHERE { ?s ?p ?o }");
Answer answer = connection.execute(query);
// display the result
answer.beforeFirst();
while (answer.next()) {
System.out.print(" " + answer.getObject(0));
System.out.print(" " + answer.getObject(1));
System.out.println(" " + answer.getObject(2));
}
answer.close();
connection.close();
}}}

A working example program for issuing SPARQL queries is provided with the source code. It can be found on the following path:
[http://mulgara.org/svn/mulgara/tags/release-2.0-alpha-final/tools/src/org/mulgara/tools/Sparql.java tools/src/org/mulgara/tools/Sparql.java]

=== Closing Connections ===
When a `Connection` is no longer in use, it should be either closed or disposed in order to release the resources. Close a connection that was obtained from a `ConnectionFactory` using the database URL by calling the `Connection.close()` method. This will release the resources associated with the connection back to the factory, where they may be re-used for subsequent connections. If a connection was obtained based on an existing `Session` or was created directly (not using the factory) then close it by calling the `Connection.dispose()` method. This will destroy the underlying resources for that connection, both in the local process and in the remote database, including the `Session` itself. Once `close()` or `dispose()` has been called on a `Connection` and further attempts to execute commands or queries on that connection will cause an exception to be thrown. Some care should be taken when using the `Connection.close()` method; if autocommit is turned off on a connection when the connection is closed (but not disposed) then the write-lock will not be released and any modifications made on that connection will remain uncommitted. Also, authentication credentials are stored in the `Session` that backs a `Connection`, so if you are using a `ConnectionFactory` in a multi-user environment then you should use the `dispose()` method to ensure that credentials are not shared between users.

Finally, the `ConnectionFactory` provides a `closeAll()` method that disposes of all resources associated with the factory. Exercise caution when using this method, as it will dispose of both cached resources and any resources which might still be in use by active connections created by the factory. This method is intended to be used when an application is shutting down and releasing all of its resources.

{{{
#!java
// define the server we want to connect to
URI serverURI = new URI;

// Create a SPARQL query
Query query = new SparqlInterpreter().parseQuery(
"SELECT * FROM <test:data> WHERE { ?s ?p ?o }");
// Create a factory, and connect to the server
ConnectionFactory factory = new ConnectionFactory();
Connection connection1 = factory.newConnection(serverUri);
// This query will execute successfully.
connection1.execute(query);
// Return the session for this connection to the factory for re-use
connection1.close();
// This call will throw an exception since the connection was closed
connection1.execute(query);
// The previous connection was closed, so this will re-use the cached session
Connection connection2 = factory.newConnection(serverUri);
// connection2 is still in use, so this will cause a new session to be created
Connection connection3 = factory.newConnection(serverUri);
// This will close the session for this connection; it will not be re-used
connection2.dispose();
// Clears the cache and closes the session for connection3
factory.closeAll();
}}}

Updated by Alex Hall - almost 16 years ago · 7 revisions