Title: jena-client - A SPARQL-centric API jena-client is a library designed to interact with an RDF database using the [SPARQL 1.1 Query](http://www.w3.org/TR/sparql11-query/) and [SPARQL 1.1 Update](http://www.w3.org/TR/sparql11-update/) W3C Recommendations. The library provides an API that can be applied to local Jena databases as well as remote [SPARQL 1.1 Protocol](http://www.w3.org/TR/sparql11-protocol/) compliant databases. It can be thought of as a SPARQL version of JDBC. SPARQL 1.1 is a W3C Recommendation supported by virtually all RDF databases. Using SPARQL as a programming model makes it easy to swap your RDF database implementation to a different vendor without having to rewrite your application code. See [Fuseki](../fuseki2/index.html) for an implementation of the [SPARQL 1.1 Protocol](http://www.w3.org/TR/sparql11-protocol/) over HTTP. Fuseki uses ARQ to provide SPARQL query access to Jena models, including Jena persistent models. ## Motivation Jena's traditional [RDF API](../rdf/index.html) is not suited for a SPARQL-centric programming model, as it focus on simple graph operations. For SPARQL support, Jena does provide an [Application API](app_api.html) (including [Querying Remote SPARQL Services](sparql-remote.html)). However, there are a some issues using these APIs: * Queries against local and remote databases must be performed differently. Without a universal client container for both database types, one must decide which to program against each time a query is performed, making it difficult to write unit tests or change the database type. * Jena's `QueryExecution` class exposes non-standard/no-longer-recommended legacy features (such as initial bindings) and other features that may only apply to either a local or a remote repository but not both. * Transactions are handled separate from the API and there is no support for auto commit transactions or remote transactions. * Update operations are not streamable (either into a local or a remote database). * Update queries must be built manually, and there is no support for generating INSERT DATA and DELETE DATA queries. jena-client attempts to address these deficiencies by introducing a new SPARQL-centric API. ## Key Classes * `DatabaseClient` - Represents a database. This can either be a local in-process Jena `DatasetGraph` or a remote database accessed via [SPARQL 1.1 Protocol](http://www.w3.org/TR/sparql11-protocol/). * `DatabaseClientFactory` - A factory class to construct appropriate `DatabaseClient` instances for local and remote databases. * `Connection` - A connection to a database. Multiple transactions and queries can be performed on a database in the context of a connection. * `QueryStatement` - Represents a single SELECT/ASK/CONSTRUCT/DESCRIBE query request. Calling the appropriate `exec` method will execute the query. * `UpdateStatement` - Represents a single update request (which may consist of multiple update operations). An update request is atomic, meaning it will result in either no effect or a complete effect, regardless of the number of operations that may be present in the request. * `Updater` - An updater provides an interface for creating a single SPARQL update request that may consist of many separate update operations. The updater is designed to be fully streaming (if the underlying database supports it). This allows for an arbitrary number of inserts, deletes, and queries to be performed in a single atomic request. Additionally it has helpful convenience methods that can transform RDF files and triples in `Graph` or `DatasetGraph` objects into INSERT DATA or DELETE DATA update operations. ## Usage DatabaseClient client = DatabaseClientFactory.createLocal(TDBFactory.createDatasetGraph()); try(Connection conn = client.getConnection()) { conn.begin(ReadWrite.WRITE); try { UpdateStatement us = conn.createUpdateStatement("prefix : \n insert data { :x :y :z }"); us.execUpdate(); conn.commit(); } finally { conn.end(); } // Print out the contents of the database using an auto commit transaction try (QueryStatement qs = conn.createQueryStatement("selectwhere { ?s ?p ?o }")) { ResultSetFormatter.out(System.out, qs.execSelect()); } } // Output will be: // ---------------------------------------------------------------------------- // | s | p | o | // ============================================================================ // | | | | // ---------------------------------------------------------------------------- Important to note is that both the `Connection` object and the `QueryStatement` object are used within try-with-resources blocks. This will ensure that `close()` is called, which is critical to release any resources held by those objects. try(Connection conn = client.getConnection()) { UpdateStatement us = conn.createUpdateStatement(new Action() { @Override public void apply(Updater up) { // Insert 10 entities into the default graph for (int i=1; i<=10; i++ ) { Node s = NodeFactory.createURI("http://example.org/entity" + i); Node p = RDFS.label.asNode(); Node o = NodeFactory.createLiteral("Entity " + i); up.insert(new Triple(s, p, o)); } // Remove entity 7 up.update("delete where { ?p ?o }"); // Add some data from a Turtle file try (InputStream in = new FileInputStream("data.ttl")) { up.insert(in, Lang.TURTLE); } catch (IOException e) { throw new RuntimeException(e); } } }); us.execUpdate(); } **Note:** This code can be simplified in Java 8 by using a Lambda instead of an anonymous inner class. ## Special Note About Remote Databases Remote databases are treated the same as local databases with the following exception: there is no remote transaction support yet. There is no W3C standard for remote SPARQL transactions, so this needs to be designed and implemented in Fuseki before jena-client can add support. **Note:** Databases other than Jena Fuseki may be limited on the type and size of remote SPARQL 1.1 Update requests. ## Authentication jena-client provides a flexible API for authenticating against remote services, see the [HTTP Authentication](http-auth.html) documentation for more details. ## Firewalls and Proxies Don't forget to set the proxy for Java if you are accessing a public server from behind a blocking firewall. Most home firewalls do not block outgoing requests; many corporate firewalls do block outgoing requests. If, to use your web browser, you need to set a proxy, you need to do so for a Java program. Simple examples include: -DsocksProxyHost=YourSocksServer -DsocksProxyHost=YourSocksServer -DsocksProxyPort=port -Dhttp.proxyHost=WebProxy -Dhttp.proxyPort=Port This can be done in the application *if it is done before any network connection are made*: System.setProperty("socksProxyHost", "socks.example.org");