SparqlProtocolWsdl11Examples

From W3C Wiki

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:

  1. 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"/>
  1. 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 a SPARQLQueryServiceLocator instance. While our example service WSDL specifies an endpoint address for the SPARQLQueryService, 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 for null 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.

Using .Net's Web References

Using Python