SparqlProtocolWsdl11Examples
Introduction
The W3C's Data Access Working Group is charged with designing a query language and data-access protocol for retrieving information from RDF data stores and knowledgebases. The SPARQL Protocol is normatively described by means of a set of WSDL 2.0 definitions.
To facilitate the creation of SPARQL Protocol clients and endpoints using existing tooling, the Working Group has also published an informative Working Draft describing the SPARQL Protocol via a set of WSDL 1.1 definitions.
The Working Group intends this page to host samples of using the WSDL 1.1 document with various toolkits to generate code to implement the SPARQL Protocol.
Using Axis's WSDL2Java
SPARQLClient is an example SPARQL Protocol client that uses Apache Axis's WSDL2Java to run SPARQL queries against a (not provided) SPARQL Protocol endpoint using SOAP over HTTP.
The archive contains the following folders and files:
-
.classpath
,.project
-- This code sample was developed using Eclipse. These project files should enable anyone using Eclipse to easily build the sample client. -
src/RunClient.java
-- The main source of the sample client. See below for more details. -
SOAP/src-soap/*
-- Source code generated by WSDL2Java from the SPARQL Protocol WSDL 1.1 definitions. -
SOAP/build.xml
-- ANT build file with a task to use WSDL2Java to generate source code from the WSDL 1.1 definitions. See below for more details. -
SOAP/sparql-11-example-port.wsdl
-- This example file contains a sample WSDL 1.1 service with a single port servicing the SPARQL Protocol query interface via SOAP bindings. See below for more details.
SOAP/sparql-11-example-port.wsdl
The WSDL 1.1 provided in the Working Group Note contains the types, faults, operations, and interface (port type) that define the abstract SPARQL Protocol. For sample code to connect to a concrete endpoint implementing the main [[SparqlQueryInterface]]
port type, we need a supplementary WSDL file defining a service with a port that specifies a specific address of an endpoint. SOAP/sparql-11-example-port.wsdl
, then, performs two functions:
- Import the WSDL 1.1 defining the SOAP bindings for
[[SparqlQueryInterface]]
:
<wsdl:import namespace="http://www.w3.org/2005/08/sparql-protocol-query/#" location="http://www.w3.org/2001/sw/DataAccess/proto-wsdl11/sparql-protocol-query-11.wsdl"/>
- Define a sample service and port with binding information specifying SOAP over HTTP and pointing to the URL of our sample endpoint:
<wsdl:service name="SPARQLQueryService"> <wsdl:port binding="bindings:QuerySoapBinding" name="sparql-query"> <soap:address location="http://localhost:2525/axis/services/sparql-query"/> </wsdl:port> </wsdl:service>
SOAP/build.xml
This is an Ant build configuration file. Its default task, sparql-11-wsdl
uses the WSDL2Java Ant task to generate source code from the WSDL and imported XML Schema files. The sparql-11-wsdl
task outputs both classes to invoke the SPARL Protocol query
operation against a specific service endpoint as well as bean classes to represent the types involved as inputs to and outputs from the operation.
The source code generated from the sparql-11-wsdl
task is output in a folder hierarchy in SOAP/src-soap
.
src/RunClient.java
This stitches together the generated code to invoke the SPARQL Protocol endpoint given in SOAP/sparql-11-example-port.wsdl
and interpret the results. It issues two queries: a SELECT
query followed by a CONSTRUCT
query. Here we walkthrough the code that issues a query in it the order it executes at runtime.
- First, the
runQuery
method initializes aSPARQLQueryServiceLocator
instance. While our example service WSDL specifies an endpoint address for theSPARQLQueryService
, the sample code shows that this address can be overridden in code. Also, we retrieve a reference to this concrete service's implementation of the interface in which we are interested ([[SparqlQueryInterface]]
):
static String endpoint = "http://localhost:2525/axis/services/sparql-query" ; ... public static void runQuery(String query, String // Setup our service to point to our endpoint SPARQLQueryServiceLocator service = new SPARQLQueryServiceLocator(); service.setSparqlQueryEndpointAddress(endpoint); // Retrieve a reference to the SparqlQuery interface SparqlQueryInterface soapQuery = null; try { soapQuery = service.getSparqlQuery() ; } catch (javax.xml.rpc.ServiceException ex) { throw new RuntimeException("Query exception: " + ex.getMessage()) ; }
- We next take care of some bookkeeping. The latest SPARQL-Protocol-draft XML Schema imports a stub schema file for RDF/XML. Because this schema does not fully describe the XML that will be returned when RDF/XML is returned, we must give Axis a custom deserializer that can be invoked when RDF/XML is encountered in the response to the
query
operation. In our case, we define a trivial deserializer factory ([[SimpleDeserializerFactory]]
) and deserializer class ([[SimpleDeserializer]]
) that does nothing more than convert the root element of an RDF/XML document fragment to its string representation.
// We register a stub class to deserialize RDF/XML // so that Axis does not complain. A "real" implementation // would use a deserialization class that parses the RDF/XML // into an appropriate graph representation. Our deserializer // simply returns a string representation of the RDF/XML returned. TypeMappingRegistry reg = service.getEngine().getTypeMappingRegistry() ; TypeMapping tm = (TypeMapping)reg.getTypeMapping("") ; tm.register( String.class, // the type to deserialize to new QName("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF") , null, // SerializerFactory new SimpleDeserializerFactory() );
- The next step uses the bean classes to populate the input messages for the
query
operation:
QueryRequest q = new QueryRequest() ; q.setQuery(query) ; // Any default graphs or named graphs would be set here //q.setDefaultGraphUri(new URI[] { ... }); //q.setNamedGraphUri(new URI[] { ... });
- Now we're ready to invoke the operation via the interface reference retrieved above. The various faults defined in the WSDL are translates to appropriately named exceptions. For the purposes of this example, we simply propagate any exceptions as
[[RuntimeException]]
s.
QueryResult result = null; try { result = soapQuery.query(q) ; } catch (MalformedQuery ex) { throw new RuntimeException("Malformed query fault: " + ex.getFaultString(), ex) ; } catch (QueryRequestRefused refused) { throw new RuntimeException("Query request refused fault: " + refused.getFaultString(), refused); } catch (AxisFault axisFault) { throw new RuntimeException("Axis Fault: "+axisFault.getFaultString(), axisFault); } catch (RemoteException e) { throw new RuntimeException("Remote Exception: "+e.getMessage(), e) ; }
- Finally, we interpret the results. The SPARQL Protocol schema defines the
query-result
element as a choice between either the SPARQL Query Results XML Format or RDF/XML. WSDL2Java generates accessor's for either return type, and we simply check fornull
to differentiate the two. If RDF/XML is returned, we display the deserialized string representation, and if the Query Results XML Format is returned then we display the size of the result set. Note that because the Query Results XML Format is fully defined by an imported XML Schema, we have afull set of bean classes at our disposal to traverse a returned result set.
// Switch on the type of the result received and act accordingly. if (result.getRDF() != null) { System.out.println("RDF/XML returned:"); // In this example, the result of deserializing RDF/XML is simply a string System.out.println(result.getRDF()); } else if (result.getSparql() != null) { System.out.println("VBR returned."); // Beans are generated for the SPARQL Query Results XML Format schema, // so we can use them to walk through our resultset. Sparql sparql = result.getSparql(); if (sparql.get_boolean() == null) { Results results = sparql.getResults(); System.out.println("SELECT returned " + results.getResult().length + " rows"); } else { System.out.println("ASK result is: " + sparql.get_boolean()); } } else { System.out.println("Something else ?? returned."); }
Running the SPARQLClient Sample
To run the sample, change
static String endpoint = "http://localhost:2525/axis/services/sparql-query" ;
to point to an actual SOAP-over-HTTP endpoint. (A listing of any publically available SOAP SPARQL endpoints would be great!) Then simply compile and run the [[RunClient]]
class as a Java application to see the sample in action.