Skip to main content

"As" (when an RDF store meets NetBeans Lookup)

Posted by fabriziogiudici on November 22, 2009 at 6:46 AM PST

My latest example of an API that would benefit from support by a RDF
store was the href="http://weblogs.java.net/blog/2009/04/29/observation-api-hey-its-not-observable-pattern">“Observation
API” and focused on modeling a set of observations made by
some subjects and related to some places (I'm keeping birds and
birdwatchers in mind, but it's only a special case):


style="width: 766px; height: 368px;" alt=""
src="https://bluemarine.dev.java.net/nonav/Blog/20090429/DomainModel.png">



I recall you that a typical example of use is:



ObservationManager
observationManager =
ObservationManager.Locator.findObservationManager();
style="font-family: monospace;">
ObservationSet  style="font-family: monospace;">observationSet style="font-family: monospace;"> =
observationManager.createObservationSet(); style="font-family: monospace;">


Date when =
dateFormat.parse("29-04-2007");
style="font-family: monospace;">
Location castiglione
= observationSet.findOrCreate(Location.class, "Castiglione della
Pescaia", EmptyInitializer.instance());
style="font-family: monospace;">
Observer fabrizio =
observationSet.findOrCreate(Observer.class, "Fabrizio Giudici",
EmptyInitializer.instance());
style="font-family: monospace;">
Observable flamingo
= observationSet.findOrCreate(Observable.class, "Flamingo",
EmptyInitializer.instance());
style="font-family: monospace;">
Observable spoonbill
= observationSet.findOrCreate(Observable.class, "Spoonbill",
EmptyInitializer.instance());
style="font-family: monospace;">
  style="font-family: monospace;">
Observation
observation = observationSet.createObservation().
style="font-family: monospace;">
                                        
date(when).


                                        
location(castiglione).
style="font-family: monospace;">
                                        
item(spoonbill, Cardinality.valueOf(23)).
style="font-family: monospace;">
                                        
item(flamingo, Cardinality.rangeOf(100, 150)).
style="font-family: monospace;">
                                        
observer(fabrizio).


                                        
build();




Now that href="http://weblogs.java.net/blog/fabriziogiudici/archive/2009/10/26/elmo-semantic-entity-manager">I
have introduced Elmo, you should have a rough idea about how
this can be implemented so that a RDF store provides persistence: just
figure out classes such as ElmoObservation,
ElmoObservable
etc... which are concrete implementations of the interfaces in the API
and, by properly using @rdf
annotations, map to RDF statements. Actually, sooner or later I'll
show you the detail of this implementation, but not now.



The topic I'd like to illustrate today is how to use the great
flexibility of a RDF store in a Java API.



In my href="http://weblogs.java.net/blog/fabriziogiudici/archive/2009/10/26/elmo-semantic-entity-manager">previous
post about Elmo, I wrote:



style="font-style: italic;">“...
while a ER (Entity-Relation) database is usually less flexible than the
code managing it
(e.g. there's no inheritance, polymorphism, etc...) and there's a sort
of strong type system (one table usually matches one entity), a RDF
store is usually more flexible than the code managing it, because of
the AAA slogan (Anyone can say Anything about Any topic).”.



Thinking of a concrete example, I'm not willing to constrain myself in
having that the only property of the “fabrizio” or “flamingo” objects
is a simple label: rather, I'd like them to be full-fledged objects,
with multiple attributes and behaviours. For instance, an style="font-family: monospace;">Observer that
is a Person
could have name, first name, birth date, etc... and and style="font-family: monospace;">ObservationItem
that is a Bird
could be part of a classification scheme (taxonomy). Just imagine these
two classes (Person,
Bird)
to be part of their relative APIs, designed in a similar way as the
Observation API (or not), and possibly mapped themselves to RDF triples
(for instance, FOAF
is a standard ontology in the RDF world that has been designed to
describe people).



It's a typical extensibility problem for APIs: you have some complete
APIs that live on their own, and you want to enhance them by enabling
their cooperation, without
changing the code
, since you don't want to introduce
unneeded dependencies (the APIs could anyway be used on their own, or
composed in different ways, etc).


src="http://weblogs.java.net/sites/default/files/As.002.jpg">



How to “glue” these APIs together? Since we have got interfaces,
one might be tempted about merging them into an “uber-interface”, but
then problems arise out of the implementations. Before starting arguing
about multiple inheritance in Java, I advance the objection that even
if you were able to inherit from multiple classes, you'd get a style="font-style: italic;">static model: you
can't change it after you compiled it. I keep in my mind a style="font-style: italic;">dynamic model, such
as component programming à la OSGi, or the NetBeans Platform (or href="http://blogs.sun.com/geertjan/entry/lookup_as_osgi_service_registry">both),
where you have single component binaries (e.g. the Observable API and
the FOAF stuff), you just install them into a container (maybe at
runtime) and they start cooperating together.



This is one of the battefields or the so-called href="http://en.wikipedia.org/wiki/Mixin">“mixins”,
supported in languages such as JavaFX or Scala (where they are
called “traits”).
If you look at the Scala example (please have href="http://www.scala-lang.org/node/117">a look at it
since it's very simple), you'll see that the solution is asymmetrical:
the subclass inherits something from the “true” superclass and
additional behaviours from traits. I don't like this for three reasons:

  1. it's still static
  2. as explained it's asymmetric (you need to distinguish
    traits from regular classes)
  3. you need to declare traits in advance 
style="font-style: italic;">As a side note, I'm not saying
that Scala can't do better. It can of course. I've just borrowed an
example from Scala traits as Java doesn't have mixins.



Elmo provides a similar feature with href="http://www.openrdf.org/doc/elmo/1.5/user-guide.html#SEC.REGISTERING-ROLES-20">“behaviours”,
that also considers a synonym of “mixin” (it implements them in Java
with interfaces and some dynamic bytecode manipulation). It's much
better than traits since it is not completely static
(behaviour are searched and injected at runtime), but it requires that
all the involved classes are registered with Elmo in some way; instead
I'd like to work even with regular classes, in case I don't need that
all of them are persisted with RDF (moreover, you've surely noted that
I'm constraining myself in keeping all the Elmo stuff in
implementation details and not exposing through the public API).



The way I'm exploring to achieve those goals is very simple: the old,
plain composition. The
original classes stay as they are, but their instances get “glued”
together into aggregates. With “glue” now I mean that I have a way to
navigate from an object to any other in its aggregation, as the
animated picture below explains.


type="application/x-shockwave-flash" allowscriptaccess="always"
allowfullscreen="true" height="390" width="480">



I need a
really generic glue and the best that I know is the style="font-family: monospace;">Lookup
class / idiom from NetBeans: it's a container of services that can be
looked up by their class name and href="http://netbeans.dzone.com/articles/netbeans-platform-idioms-looku">injected
at runtime.


style="font-style: italic;">Please note that I'm not binding
to the NetBeans Platform: Lookup is a simple API that style="font-style: italic;"
href="http://blogs.sun.com/geertjan/entry/lookup_api_outside_the_netbeans">can
be used outside of it,
in any Java application, by just importing a single JAR file.



For instance, with the following code I retrieve a certain service
available in a Lookup:



Lookup lookup = ...;

MyService myService = lookup.lookup(Service.class);
style="font-family: monospace;">
myService.doSomething();



Lookup
can work with multiple implementations and in mine it style="font-style: italic;">also searches for
behaviours provided by Elmo. Now I just need to provide my classes with
an extra method, getLookup().
For instance, I can
write:



Observer observer =
...


observer.getLookup().lookup(Person.class).setEmail("fabrizio
DOT giudici AT tidalwave DOT it");
style="font-family: monospace;">


Since this is a bit verbose, I've implemented a simple shortcut such as:



observer.as(Person.class).setEmail("fabrizio
DOT giudici AT tidalwave DOT it");
style="font-family: monospace;">


Furthermore, I like the “as” word since it underlines that the object
I'm dealing with has got multiple personalities. I'd like to stress the
fact that this is not a static cast such as:



((Person)observer).setEmail( style="font-family: monospace;">"fabrizio DOT giudici AT
tidalwave DOT it");



In fact the traditional cast works only if you provide an instance of a
class that implements both  style="font-family: monospace;">Observer
and Person,
that is it has been
statically compiled in that way
, while style="font-family: monospace;">as()
dynamically searches in the aggregate, that can be modified at runtime,
at any time.



Furthermore, as()
works also in the reverse way:



Person fabrizio = ... style="font-family: monospace;">
Observation
observation = observationSet.createObservation().
style="font-family: monospace;">
                                        
date(when).


                                        
location(castiglione).
style="font-family: monospace;">
                                        
item(spoonbill, Cardinality.valueOf(23)).
style="font-family: monospace;">
                                        
item(flamingo, Cardinality.rangeOf(100, 150)).
style="font-family: monospace;">
                                        
observer(fabrizio.as(Observer.class)).
style="font-family: monospace;">
                                        
build();




Of course, to me this brings the additional advantage of providing
integration with the NetBeans Platform. For instance, the Platform
provides support for simplifying the rendering of lists and trees
containing objects by means of a delegate called style="font-family: monospace;">Node; the href="http://weblogs.java.net/blog/fabriziogiudici/archive/2007/08/creative_use_of.html">Visual
Library, which is as sort of whiteboard where you an arrange
things representing data, does the same by means of a delegate named style="font-family: monospace;">Widget. Now I
can write highly reusable code (note that “anything”):



Node node =
anything.as(NodeFactory.class).createNodeDelegate();
style="font-family: monospace;">
Widget widget =
anything.as(WidgetFactory.class).createWidgetDelegate();




BTW, this is a pretty good example about why I want to mix also
behaviours that are not backed by Elmo: style="font-family: monospace;">Node and style="font-family: monospace;">Widget are
UI-related classes that in general don't need persistence (or at least
they don't need the same persistence as the domain object they refer
to). 



What happens if the required personality can't be found? Well, as part
of the dynamicity I've injected into your application, I must check
preconditions. This means using conditionals or exception catching (for
instance, in case of failure getLookup().lookup(Something.class)
returns null,
while I choose to have as(Something.class)
to throw an exception). Alternatively you
could use the href="http://en.wikipedia.org/wiki/Null_Object_pattern">Null
Object pattern and have a dynamically generated, do-nothing
object to be
returned (this works well with methods returning a style="font-family: monospace;">void, while
it's not always easy to define a meaningful result for others, even
though zero often is good).



Last but not least, there's the readability thing. I find the above
code sketches pretty readable, but I know that not everybody will
agree. Amen to that ;-) My main priority is to have a better design,
and a dynamic one is better than a static one. There are actually cases
where this approach is not completely href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY
(Don't Repeat Yourself) - consider, for instance, a style="font-family: monospace;">Displayable
class with a getDisplayName()
method. I'm using it and it's pretty useful, for instance, to retrieve
the string to render in a ListCellRenderer
or such:



String text =
person.as(Displayable.class).getDisplayName();

// render text



This is not DRY, as the “display” english word is repeated twice. I
don't think that there's anything to do in Java if we want to keep the
dynamicity (that is, the fact that the object providing the display
name is not known at compilation time). In other languages, such as
Groovy, I could write:



var text =
person.getDisplayName();




and arrange things so that the method is properly searched for and
found.



Consider that these are corner cases; often the required
personality has got more than a single method, and the DRY violation is
less apparent or there's no violation at all (this is evident for
things rich in semantics such as style="font-family: monospace;">Person or style="font-family: monospace;">Bird, and
generically speaking, a domain model class). The Groovy example,
anyway, is less flexible as it can't deal with the (admittedly rare)
case in which multiple personalities have got methods with the same
signature.



For my personal taste, the only thing that I'd like to get rid of is
the .class
suffix. I'd like to write



observer.as(Person).setEmail("fabrizio
DOT giudici AT tidalwave DOT it");




and I wonder whether the javac compiler could just be made a bit
smarter so it can guess it when it's missing. Maybe for JDK7?



In any case, as usual I have working code showing off this design. It
still needs some polish and I'm preparing a screencast to explain how
to use it. Stay tuned.

AttachmentSize
As.002.jpg21.54 KB
Related Topics >>