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 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.
A Connection
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 a new Connection
.
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 a Connection
to the same database, the Connection
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
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:
// define the server we want to connect to
URI serverURI = new URI("rmi://localhost/server1");
// 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("test:data");
// 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:
// define the server we want to connect to
URI serverURI = new URI("rmi://localhost/server1");
// 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:
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.
// define the server we want to connect to
URI serverURI = new URI("rmi://localhost/server1");
// 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 Paula Gearon over 11 years ago ยท 9 revisions