UserAPI » History » Version 8
Alex Hall -, 05/23/2008 07:23 PM
1 | 1 | Paula Gearon | |
---|---|---|---|
2 | 8 | Alex Hall - | h1. Connection API = |
3 | Overview == |
||
4 | 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. |
||
5 | 1 | Paula Gearon | |
6 | 8 | Alex Hall - | 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: |
7 | 1 | Paula Gearon | |
8 | 8 | Alex Hall - | * All queries issued to this interface must contain at least one URL for a graph on the server that will handle the query. |
9 | * Arbitrary graph names are not permitted. Graph names must follow a particular format, and will include the hostname of the server containing the graph. |
||
10 | * Queries against graphs must be changed when the server hosting the graph changes. |
||
11 | * Connections to a server cannot be cached. |
||
12 | * 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. |
||
13 | * Query languages which use a default graph name (like "SPARQL":http://www.w3.org/TR/rdf-sparql-query/) cannot identify a server if no graph names are given. |
||
14 | 1 | Paula Gearon | |
15 | 8 | Alex Hall - | 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. |
16 | 1 | Paula Gearon | |
17 | 8 | Alex Hall - | The @Connection@ interface and its supporting classes are found in the @org.mulgara.connection@ package. |
18 | 1 | Paula Gearon | |
19 | |||
20 | 8 | Alex Hall - | h2. Connection Factory |
21 | 1 | Paula Gearon | |
22 | 8 | Alex Hall - | 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. |
23 | 1 | Paula Gearon | |
24 | 8 | Alex Hall - | @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. |
25 | 7 | Alex Hall - | |
26 | 8 | Alex Hall - | 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. |
27 | 1 | Paula Gearon | |
28 | 8 | Alex Hall - | 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. |
29 | |||
30 | For the moment, the only supported protocol is _rmi_. Other protocols, including _http_ are expected shortly. |
||
31 | |||
32 | |||
33 | h2. Using a Connection == |
||
34 | Commands === |
||
35 | 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. |
||
36 | |||
37 | 1 | Paula Gearon | The following is an example of using a Connection to create a graph, and load a file into that graph: |
38 | 8 | Alex Hall - | <pre> |
39 | <code class="java"> |
||
40 | 1 | Paula Gearon | // define the server we want to connect to |
41 | URI serverURI = new URI("rmi://localhost/server1"); |
||
42 | // define the file we want to load |
||
43 | URI dataFile = new File("data.rdf").toURI(); |
||
44 | // define the name of the graph to load the data into |
||
45 | URI myData = new URI("test:data"); |
||
46 | |||
47 | // Create a factory, and connect to the server |
||
48 | 8 | Alex Hall - | [[ConnectionFactory]] factory = new [[ConnectionFactory]](); |
49 | 1 | Paula Gearon | Connection connection = factory.newConnection(serverUri); |
50 | |||
51 | // execute a CREATE command |
||
52 | 8 | Alex Hall - | connection.execute(new [[CreateGraph]](myData)); |
53 | 2 | Paula Gearon | // execute a LOAD command |
54 | connection.execute(new Load(dataFile, myData, true)); |
||
55 | |||
56 | 1 | Paula Gearon | // cleaning up the connection allows the network resources to be re-used |
57 | 2 | Paula Gearon | connection.close(); |
58 | 8 | Alex Hall - | </code></pre> |
59 | 1 | Paula Gearon | |
60 | 8 | Alex Hall - | 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. |
61 | 1 | Paula Gearon | |
62 | 8 | Alex Hall - | |
63 | h3. Queries |
||
64 | |||
65 | 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: |
||
66 | <pre> |
||
67 | <code class="java"> |
||
68 | 2 | Paula Gearon | // define the server we want to connect to |
69 | URI serverURI = new URI("rmi://localhost/server1"); |
||
70 | 1 | Paula Gearon | |
71 | // Create a factory, and connect to the server |
||
72 | 8 | Alex Hall - | [[ConnectionFactory]] factory = new [[ConnectionFactory]](); |
73 | 3 | Paula Gearon | Connection connection = factory.newConnection(serverUri); |
74 | |||
75 | 2 | Paula Gearon | // Use a SPARQL query |
76 | 8 | Alex Hall - | Query query = new [[SparqlInterpreter]]().parseQuery( |
77 | 2 | Paula Gearon | "SELECT * FROM <test:data> WHERE { ?s ?p ?o }"); |
78 | Answer answer = connection.execute(query); |
||
79 | |||
80 | // display the result |
||
81 | answer.beforeFirst(); |
||
82 | while (answer.next()) { |
||
83 | System.out.print(" " + answer.getObject(0)); |
||
84 | System.out.print(" " + answer.getObject(1)); |
||
85 | 1 | Paula Gearon | System.out.println(" " + answer.getObject(2)); |
86 | } |
||
87 | 6 | Paula Gearon | answer.close(); |
88 | |||
89 | connection.close(); |
||
90 | 8 | Alex Hall - | </code></pre> |
91 | 7 | Alex Hall - | |
92 | 1 | Paula Gearon | A working example program for issuing SPARQL queries is provided with the source code. It can be found on the following path: |
93 | 8 | Alex Hall - | "tools/src/org/mulgara/tools/Sparql.java":http://mulgara.org/svn/mulgara/tags/release-2.0-alpha-final/tools/src/org/mulgara/tools/Sparql.java |
94 | 7 | Alex Hall - | |
95 | |||
96 | 8 | Alex Hall - | h3. Closing Connections |
97 | 7 | Alex Hall - | |
98 | 8 | Alex Hall - | 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. |
99 | |||
100 | 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. |
||
101 | |||
102 | <pre> |
||
103 | <code class="java"> |
||
104 | 7 | Alex Hall - | // define the server we want to connect to |
105 | URI serverURI = new URI("rmi://localhost/server1"); |
||
106 | |||
107 | // Create a SPARQL query |
||
108 | 8 | Alex Hall - | Query query = new [[SparqlInterpreter]]().parseQuery( |
109 | 7 | Alex Hall - | "SELECT * FROM <test:data> WHERE { ?s ?p ?o }"); |
110 | |||
111 | // Create a factory, and connect to the server |
||
112 | 8 | Alex Hall - | [[ConnectionFactory]] factory = new [[ConnectionFactory]](); |
113 | 7 | Alex Hall - | Connection connection1 = factory.newConnection(serverUri); |
114 | |||
115 | // This query will execute successfully. |
||
116 | connection1.execute(query); |
||
117 | |||
118 | // Return the session for this connection to the factory for re-use |
||
119 | connection1.close(); |
||
120 | |||
121 | // This call will throw an exception since the connection was closed |
||
122 | connection1.execute(query); |
||
123 | |||
124 | // The previous connection was closed, so this will re-use the cached session |
||
125 | Connection connection2 = factory.newConnection(serverUri); |
||
126 | |||
127 | // connection2 is still in use, so this will cause a new session to be created |
||
128 | Connection connection3 = factory.newConnection(serverUri); |
||
129 | |||
130 | // This will close the session for this connection; it will not be re-used |
||
131 | 1 | Paula Gearon | connection2.dispose(); |
132 | |||
133 | // Clears the cache and closes the session for connection3 |
||
134 | factory.closeAll(); |
||
135 | 8 | Alex Hall - | </code></pre> |