This tutorial shows how to insert RDF from a file (joebloggs_foaf.rdf) into Construct. It then shows how to send a SPARQL query to query this data from Construct. The resulting QueryResults object is printed in N3 format.
from construct.proxyimport proxy
from construct.constructserviceimport ServiceError
_:A6a94e801X3aX118515eda06X3aXX2dX7ffc <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2001/sw/DataAccess/tests/result-set#ResultSet> .
This post is the final part of a python and Construct tutorial. Part 1 is here and part 2 is here.
<http://www.example.com/~joebloggs> <http://xmlns.com/foaf/0.1/family_name> “Bloggs”.
This post is the second part of a tutorial on construct and python. Back to Part 1 of this tutorial or on to Part 3.
This post will show how to connect to a Construct Data Port and submit RDF data.
If an instance of Construct is available, this code will insert two pieces of RDF in N3 format. The first of these is good RDF, the second of these is not. The script is below, and example output beneath that again.
#Import the python construct proxy.
from construct.proxyimport proxy
from construct.constructserviceimport ServiceError
print“Response to bad RDF: “ + str(insertBadResponse)
# response should be “None”
except ServiceError, e:
print e.value
# Close the proxy.
proxy.close()
If this code has executed correctly (i.e., if an instance of Construct is discovered) the following will be printed:
Executing Script
Response to good RDF: 1
Response to bad RDF: None
If the Construct proxy is not found the following will be printed:
Executing Script
Error - unable to contact an instance node of Construct (using address localhost:3826). Is the Construct Proxy running at that address?
and if no instance of Construct is discovered the following will be printed:
Executing Script
Error: No instance of Construct found. Please ensure you are within Zeroconf range of a running instance of Construct
This post is the first part of a tutorial on construct and python. Part 2 of this tutorial is here and part 3 is here
In Part 1 of this series of posts, I described how to add data to Construct. This post will teach you how to get data back out again using the Query Service.
The Java libraries bundled with Construct make use Jena, and the SPARQL query language in the process of querying Construct. If you’re already familiar with Jena, then there is only a couple of additional steps to learn.
To start, we need to open a connection to the Query Service. This is done in the same way as a connection to the Data Port, by creating a new instance of the appropriate class.
final QueryServiceProxy qsProxy = new QueryServiceProxy()
The next step is to create the SPARQL query. In this example, we wish to query for the name property of the subject http://example.com/people/bob that we created in Part 1.
Then we call the query() method of the proxy object, passing the query as an argument. The return value is a Jena ResultSet object corresponding to the result of the query.
What you do with the result set is obviously dependent on your need for the data. For the purposes of this example, we’ll print the result to the console.
if(resultSet.hasNext()){
final QuerySolution solution = resultSet.nextSolution();
After you install Construct, the next thing you might want to do is add some data. This post will describe the basics.
The Java libraries bundled with Construct give you a couple of ways to contribute date: You can either pass RDF triples in directly, or work with Jena and submit a model when you’re ready to publish its contents.
The first step is to create a connection to the DataPort. This is achieved by creating a new instance of the DataPortProxy class.
final DataPortProxy proxy = new DataPortProxy();
Next, we call the add() method of the proxy object, passing the RDF triple as an argument. Multiple triples can be added simultaneously by separating them with a period. The return indicates whether the add operation was successful.
When using Jena, the process is very similar. As before you should begin by creating a new instance of the DataPortProxy object. Next, a new model should be created, and populated with data.
final Model model = ModelFactory.createDefaultModel();
final Resource person = model.createResource(“http://example.com/people/bob”);
final Property name = model.createProperty(“http://example.com/terms#name”);
person.addProperty(name, “Bob Smith”);
Then, the contents of the Jena model is added to Construct through another of the proxy object’s add() methods. Remember to close the connection as before when you are finished.
finalboolean response = proxy.add(model);
That’s the basics of adding data to Construct. The next post in this series will describe how to get data from Construct using the Query Service.
This post contains a guide for building a data port and query service client proxy for Construct in a language of your choice. The purpose of proxy objects is to disguise as much as possible the distributed nature of Construct from the developer — taking care of locating and accessing Construct services over the network.
The following sections describe (at a high level) the steps involved in building proxies for the data port and query service. If you plan to implement a client proxy, take a look at the Java, Python, and Ruby code in the codebase for examples. See the Construct protocols on the tutorial page for protocol details.
Layer 1: Finding and Connecting to Services - Connect to the Construct Bonjour Proxy
The Construct Bonjour Proxy maintains a list of active Construct instances that it can see. Assuming you have set it up on your machine, it will be running on port 3826. Connect to this port to be sent a list of service descriptors.
Layer 2: Connecting to a Service
Assuming that some services are present, pseudocode for this process is a follows:
iterate through each available service instance
if the service descriptor contains the desired service, attempt to create a connection to it
if successful, return the connection. If not, continue the iteration
If no suitable services are available, you may wish to throw an exception.
Layer 3: Wrapping the socket in an appropriate client object
The final step is to provide code that can be wrapped round the socket to handle interaction with the services and client. Code is required for each Construct service that the client requires to access (the data port and the query service).
Retain a reference to the socket as it can be reused for multiple interactions. You should only need to obtain a new set of service descriptors when your connection fails.
Below are examples of the sort of functionality you may wish to provide in your proxy:
Get the response from the data port (using the correct protocol) and return true/false to indicate successful submission
add(String rdf, long expiryTime)
As above, but add the expiry time to the end of concatenated N-Triple string
add(LanguageSpecificConstruct model)
Convert the (Jena, rdflib etc.) model to N-Triples and continue as add(String rdf)
add(Model model, long expiryTime)
Convert the (Jena, rdflib etc.) model to N-Triples and continue as add(String rdf, long expiryTime)
Destructor
stop the process scanning for Construct instances
The Query Service proxy
Methods:
Constructor (boolean scan_localhost_only)
start the process to scan for Construct instances
query(String sparqlQuery)
Takes in a String containing a SPARQL query
Create a connection to the query service (see Layer 2), format the query using the correct protocol (see Construct protocols tutorial page) and send the query.
Get the response from the data port (using the correct protocol)
If an error occurred, return null
If successful, transform the RDF into the appropriate language specific construct representing a SPARQL result set (Jena, rdflib etc.)
In this post we’ll describe the construction and runtime operation of Construct Components. These are the building blocks that combine to form the Construct infrastructure. If you want to modify how Construct works internally (i.e. write a new data dissemination mechanism, change the internal data model, add a reasoner…) then this is the place to start.
The number and type of components in any given deployment is customisable. At runtime, each of the components defined in the construct.properties file is loaded and instantiated by the Component Manager. The Component Manager is also responsible for the correct shutdown of the components when the software is terminated.
In order to facilitate this process, components must implement two interfaces. The first interface is the ConstructComponent interface, which defines all the methods required for communication between a component and the Component Manager. The second interface is component specific, and is used to register the component with Construct, and allow other components to gain access to it. A default implementation of the ConstructComponent interface, the AbstractConstructComponent, is provided in order to simplify the process of creating new components. Developers may extend from this class if desired, or implement directly from the ConstructComponent interface.
The ConstructComponent Interface
The ConstructComponent interface extends the Runnable interface and defines 6 additional methods that all components must implement in order that the Component Manager can talk with them. Below is an overview of each of these methods.
shutdownComponent(): Called by the Component Manager in order to instruct the component to shutdown. Implementing components should ensure that this method performs any cleanup operations and then terminates.
getGraphicalInterface(): Gives access to the graphical interface defined by this component. The default value is null – meaning no interface provided
setGraphicalInterface(): Sets the graphical interface for this component. Null values are valid and indicate that no interface exists.
setupComponentLinks(): This template method is where the component should access the Component Registry in order to retrieve references to other components that it talks to. The Component Manager calls this method after instantiating all components, but before running their threads.
getLogger(): This method gives access to the logger for the component. Subclasses should call this method in order to report information, warnings, or errors.
Of these methods, a component should only require to call the setLogger(), getLogger() and setGraphicalInterface() methods. The rest of the methods are called by the Component Manager when required.
The AbstractConstructComponent Class
The AbstractConstructComponent class provides the expected implementation for the get/set methods defined within the ConstructComponent interface and provides a default (blank) implementation for the setupComponentLinks() method.
In order to keep the component thread alive, the run() method waits until a notification is triggered by a call to the shutdownComponent() method (which sets a flag to indicate that the component should terminate)
In addition to providing a default implementation for the methods defined in the ConstructComponent interface, the AbstractConstructComponent class defines two template methods for developer use: the onRun() method which is called when the component’s thread is started, and the onShutdown() method which is called when the component is requested to shutdown. For both methods, implementing classes should perform any necessary actions and ensure that the method returns normally.
The Component Manager
The Component Manager is responsible for loading, running, and stopping all the components in any given Construct deployment. The set of components to be started is defined in an external file (construct.properties) which is read by the Component Manager. The startup process is as follows:
Initialise all the components. For each component, this involves making a call to the Component Registry, which is responsible for ensuring that only one copy of a component exists at any given time. If the component does not exist, it is created (using reflection). If the component already exists, a reference to the existing component is returned.
Obtain and display the graphical interface for each component. This calls the getGraphicalInterface() method for each component, and adds the return value (if not null) to a tab in the main GUI.
Allow components to interact. Next, the setupComponentLinks() method of each component is called in order that they may obtain references to the other components that they interact with from the Component Registry. Should any requested component be unavailable, the initialisation process will be terminated.
Start the components. Finally, the thread for each component is started.
When shutting down a Construct deployment, the Component Manager iterates through all active components, calling their shutdownComponent() method. Once completed, the Component Manager removes the entry from the Component Registry.
The construct.properties File
The construct.properties file in the Construct root directory specifies the components they should be loaded, and the properties that should be passed to components on startup. The construct.properties file also contain properties that can be used to refine logging details. An example file construct.properties.tmp is included with the distribution. You should copy this file to construct.properties before running Construct.
Component entires in the file take one of two forms depending on whether the component requires properties on startup.
Components without properties are specified as follows:
In this post I’ll give a brief overview of the core components in a Construct node. It’ll be of interest to anyone adapting the way Construct works internally and developers of other middleware platforms. This is a good entry point into how we designed and built Construct.
If you want to build your own components I’m about to write some tutorials and blog posts so check back soon (or grab the RSS feed).
The Component Loader
The number and type of components in any given deployment of Construct is customisable. At runtime, each of the components defined in the construct.properties file is instantiated by the Component Loader, and indexed in a Component Registry to allow collaboration between components. The Component Loader is also responsible for the correct shutdown of the components when the software is terminated.
The Discovery Service
All components that interact directly with sensors or applications provide a self-describing manifest that contains information on how to interact with them. These manifests are maintained by the Discovery Service. This service provides the first point of contact for anyone that wishes to contact a Construct node. The Discovery Service advertises itself using Bonjour.
The Data Manager
The Data Manager is responsible for storing and maintaining an RDF model of all received data. It also contains a meta-data model which holds information describing the RDF statements stored in the first model. Currently this meta-model only stores information describing when the statement expires. The current implementation of this data store manager uses Jena to manage both the models.
The DataPort
The DataPort provides the gateway for adding new data to the Construct infrastructure. It takes the simple form of a TCP socket listening on a port for RDF expressed as a String in N-TRIPLE format. Multiple triples may be concatenated, and an expiry time may be appended to the end of the String if desired.
If you want to drop data directly into the DataPort go read the tutorial on our protocol format first.
The HttpPort
The HttpPort is a convenient way to query construct over HTTP. You can do this programmatically or via a web browser. If you ask the component loader to start the HTTP port (see the construct.properties file) and have Construct running try looking at http://localhost:8888/ to find a simple SPARQL query interface. This is a great way to interact with Construct from web applications.
The Query Service
The Query Service component is the interface that the framework provides to applications wishing to query the data store. It accepts a String from an application in the form of a SPARQL query and returns a String of results. The application can then decompose the returned String value into the variables that it queried for. Using the in-built Jena reasoner, the Query Service component first infers implicit triples from the data store contents (represented as RDF triples) so that it returns inferred results as well as explicit data to the application.
The Gossipping Service
The implementation of a gossiping algorithm takes the form of a protocol stack with three layers: the data-layer, which exchanges RDF with the data-manager; the gossiping layer, which drives the process; and the network layer which encapsulates the actual sending and receiving of raw packets of bytes.
The gossiping subsystem can be further decomposed into three components: the core gossiping protocol, the message buffer, and the peer membership manager. The core gossiping protocol is stateless. Gossiping is initiated periodically at each peer by sending their message buffer summary to a randomly selected peer from their contact list. When messages arrive they are identified and processed by type. The gossiping layer handles three types of messages: data messages, message buffer summaries, and individual message requests. Data messages are stored in the message buffer for future gossiping then passed up the protocol stack to the data-manager. Message buffer summaries contain a list of the message IDs present in the remote node’s buffer. On comparison with the local message buffer requests for messages that are not held locally are generated. These requests are fulfilled by return.
With the new release of Construct we’ve updated the site and moved to a wordpress blog. In the last few months the team have been really busy developing new applications, sensors and components for Construct. We’re ready to tell you all about them in the blog and will post new cool features as we add them.
Check back for updates or grab the RSS feed to stay on top of the technologies.