Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
516 lines (472 sloc) 26.3 KB
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
Owl2Java readme
</title>
<style type="text/css">
/*<![CDATA[*/
body {
font-family: "Verdana", "Helvetica", "Arial", sans-serif;
font-size: 10pt;
padding: 0 1.5em 1.5em 1.5em;
}
p, ul, pre {
color: #000;
line-height: 1.5em;
}
p {
margin: 0 0 .75em;
padding: 0;
}
ul {
list-style-type: circle;
margin: 0 0 .75em 1.5em;
padding: 0;
}
pre {
background: #f0f0f0;
border: 1px dashed #17365d;
font-family: monospace;
margin: .75em 2em 1.25em;
overflow: auto;
padding: .5em;
}
a, a:hover, a:active, a:visited, a:focus {
border-bottom: 1px dashed #aaa;
color: #17365d;
cursor: pointer;
text-decoration: none;
}
h1, h2, h3, h4, h5 {
background: none repeat scroll 0 0 transparent;
color: #17365d;
font-weight: 400;
line-height: auto;
margin: 1em 0 .2em;
padding: 0;
width: auto;
margin: 1em 0 .2em;
}
h1 {
font-size: 1.75em;
font-weight: 700;
}
h2, h3 {
border-bottom: 1px solid #aaa;
padding-bottom: .15em;
}
h2 {
font-size: 1.4em;
font-weight: 700;
}
h3 {
font-size: 1.2em;
}
h4 {
font-size: 1em;
font-weight: 700;
}
h5 {
font-size: 1em;
font-weight: 400;
}
/*]]>*/
</style>
</head>
<body>
<h1>
Owl2Java readme
</h1>
<h3>
Summary
</h3>
<p>
Owl2Java is a Java code generator, which generates a convenient API to work with
data in an OWL ontology. It makes it possible to write expressive and
easy-to-follow code that works with RDF/OWL ontologies, hiding the peculiarities of
working with such an ontology and a library that accesses it. The code generator generates
a Java class for each OWL class in the ontology, with static methods to retrieve and iterate
over individuals, and with getters and setters for all of the class's properties
Tools to enrich the structure of an OWL ontology (i.e. class and property definitions)
are also included in the package.
</p>
<h3>
Where to get it
</h3>
<p>
Owl2Java is available at <a href="http://github.com/piscisaureus/owl2java">http://github.com/piscisaureus/owl2java</a>.
</p>
<h2>
Background
</h2>
<p>
At the TU Delft we're trying to create a simulation that uses a semantic data set developed
using SemanticMediaWiki. SemanticMediaWiki (or any other distributed ontology editor for
that matter) makes it possible to collaboratively develop a knowledge body that can be used
for many purposes. The wiki allows to export (a part of) the data in it as an OWL/RDF ontology,
which can be used by other applications.
</p>
<p>
The simulation model itself will be written in Java. However using an ontology in a
strongly typed programming language like Java isn't really straightforward;
Libraries that access instance data in an ontology do exist (like Jena), but conceptually
simple operations often require verbose code. For example, to access a property of an OWL
instance requires code to load the instance, then load the property definition, fetch
the property value and finally cast it to an appropriate type. To do this right the programmer
needs to know exactly how the property is defined within the ontology. Furthermore, the
verbosity of this code makes it difficult to follow for a human reader.
</p>
<p>
To make a developer's life a little more easy, Jena and many other libraries also provide the
possibility to create 'wrapper classes' that allow an individual of a particular OWL class to
be represented by an instance of a normal Java class, so all peculiarities of working with an
ontology can be hidden within the wrapper class. The wrapper class exposes an easy-to-use and
Java-like interface to the 'real' application. Writing these wrapper classes however can be a
lot of work by itself when there are many OWL classes in the ontology; when an ontology tends
to evolve this becomes an even bigger problem, because the wrapper classes need to be updated
manually to keep them in sync with the ontology.
</p>
<p>
This is where Owl2Java helps: Owl2Java can generate these wrapper classes automatically.
When used properly, it generates a complete and consistent interface that works for all classes
within an OWL ontology. And, provided that the user doesn't change the generated code, it can
always be re-run after the ontology has been updated. The generated code uses Jena
underneath; when desired, advanced Jena features such as performing SPARQL queries can still
be used.
</p>
<p>
The other issue that we ran into at the TU Delft is that the ontology exported by
SemanticMediaWiki isn't always complete in terms of structure. Specifically, certain aspects
of OWL properties such as range, domain and functional-ness aren't defined in the wiki
export. Therefore we included some tools to enrich an ontology's structure by examining
individuals. Imperfect as the results may be, it generally finds a structure
that's <em>almost</em> right, limiting the amount of manual editing required.
</p>
<h2>
Using Owl2Java
</h2>
<p>
Writing an application using Owl2Java generally consists of three stages. First, the
ontology's structure needs to be checked and optionally fixed. The second step is to generate
the wrapper classes, which can then be used to write an appliction.
</p>
<h3>
Structuring the ontology
</h3>
<p>
In order for the code generator to work properly you must make sure that the ontology
has a 'complete' structure:
</p>
<ul>
<li>Classes must be defined in the ontology; Owl2Java generates a java class for each of
them.
</li>
<li>Properties must be defined in the ontology; Owl2Java generates getter and setter methods
for them.
</li>
<li>Properties need to have one or multiple classes in its domain; these are the classes that
the get/setters will be added to.
</li>
<li>Properties need to have a range (a class or a data type), otherwise the getters will
return an object of type owl:Thing. Properties may have multiple ranges, but Owl2Java doesn't
support complex constructs (i.e. anonymous classes) here.
</li>
<li>If you want to have a singular getter, i.e. getSomething() instead of listSomething(),
you'll need to make the property functional or set is maximum cardinality to one.
</li>
</ul>
<p>
Not all ontologies may have a structure as complete as this. As said, at the TU Delft we work
with ontologies created with SemanticMediaWiki, which defines classes and properties but
doesn't add any information about domains, ranges and does not declare any property
functional. To help fixing this some structure-finding tools are included with Owl2Java.
These are:
</p>
<ul>
<li>
<em>PropertyDomainInferer</em><br />
Find the domain(s) for a property by looking at the
instances that use this property. Existing domains are retained, unless a superclass of the
existing domain is found. You may need to run ThingExtender (see below) first.
</li>
<li>
<em>PropertyRangeInferer</em><br />
Find the range(s) for a property by looking at what the
property refers to when used by instances. Existing ranges are kept, unless a superclass of
an existing range class is found. You may need to run ThingExtender and
PropertyRangeSimplifier first.
</li>
<li>
<em>FunctionalPropertyInferer</em><br />
Look for properties that are never used more than once
per instance, and assume these properties are functional. This may lead to false positives;
review the output ontology after running it. Existing functional properties are retained.
</li>
<li>
<em>PropertyRangeSimplifier</em><br />
Simplify range definitions so the code generator doesn't
choke on it. Some ontology editors (Prot&eacute;g&eacute; for example) use complex
structures such as anonymous intersection/union classes to denote that a class property may
have multiple ranges. This tool simply converts anything crazy to a flat list of named
classes, which the code generator can work with. Generally you'll want to use this just
before invoking the class generator to make sure it is run every time after the ontology
was edited. Also run it before invoking PropertyRangeInferer when the ontology already has
some ranges defined.
</li>
<li>
<em>ThingExtender</em><br />
Make sure all classes (indirectly) extend owl:Thing.
PropertyDomainInferer and PropertyRangeInferer require that owl:Thing is always at the top
of the inheritance chain to function properly. Use ThingExtender before running the
range/domain inferrers just to be sure.
</li>
</ul>
<p>
All these tools are used in a similar way:
</p>
<pre>
IOntologyPreprocessor structureTool = <span style="font-weight: bold;">new</span> <span style="color: rgb(54, 95, 145);">StructureTool</span>( <span style="color: gray;">[</span><span style="color: rgb(54, 95, 145);">options&hellip;</span><span style="color: gray;">]</span> )
structureTool.process( OntModel ontology );
</pre>
<p>
Suppose you have an ontology but the structure is incomplete, and you want to fix it up.
Create a small program that loads and ontology, runs some of the structure finding tools and
then writes it back to another ontology.
</p>
<pre>
<span style="color: rgb(127, 0, 85); font-weight: bold;">class</span> StructureFinder {
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> main(String[] args) {
<span style="color: rgb(127, 0, 85); font-weight: bold;">try</span> {
<span style="color: rgb(63, 127, 95);">// Load the ontology, use Jena or this shortcut</span>
OntModel ontModel = OntologyUtils.loadOntology(<span style="color: rgb(42, 0, 255);">"file:ontology-raw.owl"</span>);
<span style="color: rgb(63, 127, 95);">// These are the tools that we will use to structure the ontology</span>
IOntologyProcessor[] structurizers = {
<span style="color: rgb(127, 0, 85); font-weight: bold;">new</span> ThingExtender(),
<span style="color: rgb(127, 0, 85); font-weight: bold;">new</span> FunctionalPropertyInferer(),
<span style="color: rgb(127, 0, 85); font-weight: bold;">new</span> PropertyDomainInferer(),
<span style="color: rgb(127, 0, 85); font-weight: bold;">new</span> PropertyRangeSimplifier(),
<span style="color: rgb(127, 0, 85); font-weight: bold;">new</span> PropertyRangeInferer()
};
<span style="color: rgb(63, 127, 95);">// Run all the processors</span>
<span style="color: rgb(127, 0, 85); font-weight: bold;">for</span> (IOntologyProcessor preprocessor : structurizers) {
preprocessor.process(ontModel);
}
<span style="color: rgb(63, 127, 95);">// Now we're going to save the structured ontology for manual review</span>
OntologyUtils.saveOntologyRdf(ontModel, <span style="color: rgb(42, 0, 255);">"ontology-reviewme.owl"</span>);
} <span style="color: rgb(127, 0, 85); font-weight: bold;">catch</span> (Exception e) {
&hellip;
}
}
}
</pre>
<h3>
Generate wrapper classes
</h3>
<p>
Generating the java classes should be rather straightforward; it's as simple as loading an
ontology, choose in which package and directory the generated classes should be placed and
then call the code generator. You should run the range simplifier (see above) just
before invoking the class generator to make sure the code generator doesn't choke on
range definitions that are too complex for it to handle.
</p>
<pre>
<span style="color: rgb(127, 0, 85); font-weight: bold;">class</span> ClassGenerator {
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> main(String[] args) {
<span style="color: rgb(127, 0, 85); font-weight: bold;">try</span> {
<span style="color: rgb(63, 127, 95);">// Load ontology, use Jena or a shorcut like this</span>
OntModel ontModel = OntologyUtils.loadOntology(<span style="color: rgb(42, 0, 255);">"file:ontology.owl"</span>);
<span style="color: rgb(63, 127, 95);">// Simplify the definition of property ranges</span>
<span style="color: rgb(63, 127, 95);">// This is necessary because Owl2Java chokes on complex range</span>
<span style="color: rgb(63, 127, 95);">// definitions (i.e. those containing anonymous classes)</span>
(<span style="color: rgb(127, 0, 85); font-weight: bold;">new</span> PropertyRangeSimplifier()).process(ontModel);
<span style="color: rgb(63, 127, 95);">// Generate classes that provide access to ontology instances</span>
JenaGenerator generator = <span style="color: rgb(127, 0, 85); font-weight: bold;">new</span> JenaGenerator();
generator.generate(ontModel, <span style="color: rgb(42, 0, 255);">"src"</span>, <span style="color: rgb(42, 0, 255);">"com.yourorg.ontology"</span>);
} <span style="color: rgb(127, 0, 85); font-weight: bold;">catch</span> (Exception e) {
&hellip;
}
}
}
</pre>
<h3>
Use the generated classes in your application
</h3>
<p>
After generating code to work with the ontology, you may start building your own application.
It is recommended that you do not make any modifications to the generated code. This will
allow you to just re-run the code generator when something in the ontology changes without
losing your own code.
</p>
<h4>
Initializing the wrapper classes
</h4>
<p>
At the start of your application, you need register all generated classes with Jena. It's as
simple as:
</p>
<pre>
Factory.<span style="font-style: italic;">registerCustomClasses</span>();
</pre>
<p>
Obviously you need to load an ontology to work with. Use Jena for it. You may optionally set
a 'default' ontology that is used when creating/loading/listing ontology instances. This is
recommended; if you don't do that you need to supply the ontology every time you're
loading or creating instances.
</p>
<pre>
<span style="color: rgb(63, 127, 95);">// Load the ontology</span>
OntModel ontModel = OntologyUtils.<span style="font-style: italic;">loadOntology</span>(<span style="color: rgb(42, 0, 255);">"file:resources/demo/industries-application.owl"</span>);
<span style="color: rgb(63, 127, 95);">// Set default ontology to load instances from</span>
Factory.<span style="font-style: italic;">setDefaultModel</span>(ontModel);
</pre>
<p>
After that, you can work with ontology instances almost like normal java objects.
What you can expect the generated classes to look like will be explained next.
</p>
<h4>
Class hierarchy
</h4>
<p>
As said, Owl2Java generates a class for each class defined in the ontology.
</p>
<p>
However Java does not support multiple inheritance like Owl does, therefore generated Java
classes do not extend their OWL 'parent' - they only extend the generic IndividualImpl class
from Jena. However for each class there is also an interface generated, which <em>does</em>
reflect the OWL inheritance chain. This is what the wrapper class/interface definition
for a particular OWL will look like:
</p>
<pre>
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">interface</span> IMyClass <span style="color: rgb(127, 0, 85); font-weight: bold;">extends</span> Individual, IMyAncestor, IThing {
&hellip;
}
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">class</span> MyClass <span style="color: rgb(127, 0, 85); font-weight: bold;">extends</span> IndividualImpl <span style="color: rgb(127, 0, 85); font-weight: bold;">implements</span> IMyClass {
&hellip;
}
</pre>
<h4>
Working with instances
</h4>
<p>
Generated classes have a number of static methods to load, delete, list and iterate over
instances of a particular OWL class. The method names should be self-explaining; however some
details may require explanation:
</p>
<ul>
<li>The OntModel parameter is always optional; if not supplied, the default ontology set
with <em>Factory.setDefaultModel()</em> is used.
</li>
<li>When creating an instance, the URI parameter may be omitted; an url for the instance
will then be generated.
</li>
<li>Delete() is a static method and requires you to give it the url of the instance to be
deleted. To remove an instance that has been 'wrapped' with get(), use the non-static remove()
method.
</li>
<li>The iterate(), list() and count() methods optionally take a parameter named <em>direct</em>.
When it is set to true, these functions consider only direct instances of this class, ignoring
instances of subclasses. If <em>direct</em> is set to false or omitted, subclass instances are
listed, iterated, counted too.
</li>
</ul>
<pre>
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> <span style="color: rgb(54, 95, 145);">MyClass</span> create( <span style="color: gray;">[</span>String URI<span style="color: gray;">]</span>, <span style="color: gray;">[</span>OntModel ontology<span style="color: gray;">]</span> )
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> exists( String URI, <span style="color: gray;">[</span>OntModel ontology<span style="color: gray;">]</span> )
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> <span style="color: rgb(54, 95, 145);">MyClass</span> get( String URI, <span style="color: gray;">[</span>OntModel ontology<span style="color: gray;">]</span> )
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> delete( String URI, <span style="color: gray;">[</span>OntModel ontology<span style="color: gray;">]</span> )
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> Iterator&lt;<span style="color: rgb(54, 95, 145);">MyClass</span>&gt; iterate( <span style="color: gray;">[</span><span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> direct<span style="color: gray;">]</span>, <span style="color: gray;">[</span>OntModel ontology<span style="color: gray;">]</span> )
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> List&lt;<span style="color: rgb(54, 95, 145);">MyClass</span>&gt; list( <span style="color: gray;">[</span><span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> direct<span style="color: gray;">]</span>, <span style="color: gray;">[</span>OntModel ontology<span style="color: gray;">]</span> )
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">static</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">int</span> count( <span style="color: gray;">[</span><span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> direct<span style="color: gray;">]</span>, <span style="color: gray;">[</span>OntModel ontology<span style="color: gray;">]</span> )
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> remove()
</pre>
<h4>
Working with properties
</h4>
<p>
The generated classes have methods to work with the properties of an OWL individual. What
methods are available for a specific property depends on whether it is a single-value (defined
<em>functional</em> or with maxCardinality = 1) or a multi-value (all others) property.
Some remarks:
</p>
<ul>
<li>Replace <em>Property</em> by the name of the property. For a property named
<em>amount</em>, the methods are called <em>getAmount</em>, <em>setAmount</em>,
etc.
</li>
<li>For object properties, <em>Range</em> refers to the class of the property while
<em>IRange</em> refers to the interface that defines it;<br />
for datatype properties both <em>Range</em> and <em>IRange</em> are simply an
appropriate Java primitive type.
</li>
</ul>
<h5>
Single-value properties
</h5>
<pre>
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(54, 95, 145);">Range</span> get<span style="color: rgb(54, 95, 145);">Property</span>()
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> set<span style="color: rgb(54, 95, 145);">Property</span>(<span style="color: rgb(54, 95, 145);">IRange</span> value)
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> exists<span style="color: rgb(54, 95, 145);">Property</span>()
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> has<span style="color: rgb(54, 95, 145);">Property</span>(<span style="color: rgb(54, 95, 145);">IRange</span> value)
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> remove<span style="color: rgb(54, 95, 145);">Property</span>()
</pre>
<h5>
Multi-value properties
</h5>
<pre>
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> List&lt;<span style="color: rgb(54, 95, 145);">Range</span>&gt; list<span style="color: rgb(54, 95, 145);">Property</span>()
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> Iterator&lt;<span style="color: rgb(54, 95, 145);">Range</span>&gt; iterate<span style="color: rgb(54, 95, 145);">Property</span>()
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">boolean</span> exists<span style="color: rgb(54, 95, 145);">Property</span>();
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">int</span> count<span style="color: rgb(54, 95, 145);">Property</span>()
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> add<span style="color: rgb(54, 95, 145);">Property</span>(<span style="color: rgb(54, 95, 145);">IRange</span> value)
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> addAll<span style="color: rgb(54, 95, 145);">Property</span>(List <span style="color: rgb(127, 0, 85); font-weight: bold;">&lt;? extends</span> <span style="color: rgb(54, 95, 145);">IRange</span>&gt; values)
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> remove<span style="color: rgb(54, 95, 145);">Property</span>(<span style="color: rgb(54, 95, 145);">IRange</span> value)
<span style="color: rgb(127, 0, 85); font-weight: bold;">public</span> <span style="color: rgb(127, 0, 85); font-weight: bold;">void</span> removeAll<span style="color: rgb(54, 95, 145);">Property</span>()
</pre>
<h2>
Known issues &amp; todo
</h2>
<h3>
Owl features
</h3>
<ul>
<li>Add support for complex range definitions (so running PropertyRangeSimplifier is no longer necessary)</li>
<li>Support property characteristics like maxCardinality, transitive, inverse functional</li>
<li>Add support for primitive types like float, int, etc. (how about lists, iterators then?)</li>
<li>Add support for XsdDuration</li>
<li>XsdTypes entity is currently ignored</li>
</ul>
<h3>
Code generation
</h3>
<ul>
<li>Output path could be either absolute or relative to project root</li>
<li>When writing code to somewhere outside the owl2java folder, also copy owl2java classes that the generated code depends on</li>
<li>Use Sparql for generated count() methods</li>
</ul>
<h3>
Other
</h3>
<ul>
<li>Add JavaDoc comments</li>
<li>More examples and general documentation</li>
<li>Make the code generator use generics instead of casts internally</li>
</ul>
<h2>
Authors and license
</h2>
<p>
The original Owl2Java, of which this project is a fork, was written by Michael Zimmermann.
He should be credited for most the work. More information can be found at
<a href="http://www.incunabulum.de/projects/it/owl2java">http://www.incunabulum.de/projects/it/owl2java</a>.<br />
Modifications were made by Bert Belder at the TU Delft (the Netherlands), faculty of Systems
Engineering, Policy Analysis and Management, Energy and Industry section.
</p>
<p>
Both the original Owl2Java and this fork are licensed under the GNU General Public License
version 2;<br />
see license.txt for more information.
</p>
</body>
</html>