Recovered from the Wayback Machine.
(Note: all examples are compiled and run on a Windows 2000 box, MySql 4.x, Java 1.4.1_01)
I downloaded and unzipped the Jena2 from the SourceForge project and first thing I noticed is that there is a lot of material with this download. With the classes for the ontology support as well as RDF, this is a large Java framework, providing support for all aspects of RDF and OWL, including an inferential engine, the ‘reasoner’.
The second thing I noticed is that the documentation for Jena2 is sketchy at best, with the tutorial still set for Jena 1.4, some migration guides, and the ubiquitous Javadocs. But hey! We all know that Java is self-documenting with Javadocs, so we don’t need to stinkin’ tutorials and user manuals. Besides, tutorials are for babies.
Seriously, the generated Java documentation, installation and migration guides, and the essential Jena Mini I/O are enough if you’ve worked with Jena previously. If not, hopefully the essays this week, migrating the Jena applications in the book to Jena2 will provide a good start in your efforts.
(If all goes well, next week we’ll work with the ontology classes and all of the other new Jena2 goodes. )
Once installed, I added all of the Jena jar files to my classpath, per the README document in the root directory. I then tested the installation using the test.bat file, but I could have used Ant, or used test.sh within a Unix environment. Once tested, second step was to start porting the first example Java application, reproduced here as a guide:
import com.hp.hpl.mesa.rdf.jena.mem.ModelMem; import com.hp.hpl.mesa.rdf.jena.model.*; import com.hp.hpl.mesa.rdf.jena.common.PropertyImpl; import java.io.PrintWriter;
public class pracRDFFirst extends Object {
public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://www.burningbird.net/bbd/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = new ModelMem();
// create the resource Resource postcon = model.createResource(sURI);
// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);
// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);
// Print RDF/XML of model to system output model.write(new PrintWriter(System.out));
} catch (Exception e) { System.out.println(“Failed: ” + e); } } }
This example is pretty simple: create an in-memory model, a new resource, and add two properties to that resource, both with the predicate “related”. Absolute URIs are used, and once the model is built, it’s printed out to the system. General exceptions are captured and the error message is printed. No other error checking and management is done.
The first step in migrating this example is to change the existing class structure to the new refactored one:
* com.hp.hpl.mesa.rdf.jena.model -> com.hp.hpl.jena.rdf.model
* com.hp.hpl.mesa.rdf.jena.vocabulary -> com.hp.hpl.jena.vocabulary
This is a bit tricky at first because not only is ‘mesa’ removed, the jena.rdf reference is reversed. Another change is the fact that there no longer is a specific ModelMem class or a specific PropertyImpl implementation class. This simplifies the number of Java classes that are included:
import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;
The actual code of the application doesn’t change drastically. We’re using a class factor rather than new, but creating the resource and adding the properties doesn’t change:
import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class pracRDFFirst extends Object {
public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://burningbird.net/postcon/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = ModelFactory.createDefaultModel();
// create the resource Resource postcon = model.createResource(sURI);
// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);
// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);
Once the model is built, to print it out with Jena, I used to use Jena’s Writer. In Jena2, this is replaced with InputStream and OutputStreams, a change significant enough for the Jena team to put out wht they call a “Rush Guide – Jena 1 Migration (Must Read)”.
According to the guide:
The Jena1 developer will note that all but one of these methods are new in Jena2. Jena1 mistakenly required the use of java.io.Reader and java.io.Writer. While these classes work well on a single machine, the way they address character encoding problems differs significantly from the solution offered by XML. A typical use of the Jena1 input interface such as mdl.read(new FileReader(fName)); is incorrect, and will give the wrong results if the file contains non-ASCII data. Also, in Jena1, mdl.write(new FileWriter(fName)); wrote incorrect XML for non-ASCII data (now fixed). However, these two bugs in Jena1 canceled each other out, as long as the system doing the reading had the same default character encoding as the one doing the writing, which is why it did not bite in a typical development environment. There is the substantial migration task when porting Jena1 code to Jena2 code of reviewing all the I/O calls and changing them to use InputStream’s and OutputStream’s.
Now, this is my kind of technical description, …which is why it did not bite in a typical development environment…. According to the guide, the old methods are still supported, and can still be useful and I found this so when I compiled the application without making the I/O change. However, Jena now traps for the bugs mentioned in the description and issues errors – errors that are almost guaranteed to occur.
You can still use Reader and Writer, but do so when you’re working with StringBuffer in memory, or when you specifically control the string encoding. Otherwise – go with the new OutputStream/InputStream objects. Only problem is, according to the Rush I/O guide example, to access the new OutputStream class, RDFWriter, use getRDFWriter. This was a typographical error, and to get RDFWriter, use getWriter on the model object, passing in an optional string with the serialization language. The default serialization language, RDF/XML, works so we don’t need to pass in the string.
The change to the code to use RDFWriter in the updated application is (outputting to System.out):
// Print RDF/XML of model to system output
RDFWriter writer = model.getWriter();
writer.write(model, System.out, null);
Easy enough to change. The complete new tiny application that creates an RDF model with one resource and a repeating property, printed out to system is:
import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class pracRDFFirst extends Object {
public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://burningbird.net/postcon/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = ModelFactory.createDefaultModel();
// create the resource Resource postcon = model.createResource(sURI);
// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);
// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);
// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.write(model, System.out, null);
} catch (Exception e) { System.out.println(“Failed: ” + e); } } }
Compiling the application and running it gives us the following serialized RDF/XML:
<rdf:RDF
xmlns:j.0="http://burningbird.net/postcon/elements/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
<rdf:Description rdf:about="http://burningbird.net/articles/monsters1.htm">
<j.0:related>http://burningbird.net/articles/monster3.htm</j.0:related>
<j.0:related>http://burningbird.net/articles/monster2.htm</j.0:related>
</rdf:Description>
</rdf:RDF>
That’s it, an application that compiles and runs within Jena2, and a remarkably pain free migration. Of course, this was a small application. Next essay in this series, we’ll start looking at slightly more complicated applications. I’m sure the headache factor of the migration will increase as the complications in the applications increase. Isn’t there a law saying this is so?