How should you use Thing? How does this compare with using a bean and Bean Session? This small tutorial gives a basic comparison. It is intended both as a small first tutorial and as a way to evaluate which approach might better serve your needs.

The important part: A vocabulary

The first part of all design is to decide upon a vocabulary, i.e., the terms and properties you will use to describe your information. While you can use virtually any terms you wish, the practical issue is deciding on a set of them that allow others to discover what information you have. If at all possible, you should reuse an existing vocabulary that meets your needs. Our simple example is going to be managing a foaf person which has a pre-defined vocabulary. Since this is a small example, we will just stick to a partial version. A foaf person (for us)

* has a name
* knows other foaf persons.

The vocabulary

There is a built-in vocabulary in Tupelo already (Tupelo thoughtfully includes several standard ones). This is located in org.tupeloproject.rdf.terms.Foaf. We will use two predicates that correspond to our properties above:

* org.tupeloproject.rdf.terms.Foaf.NAME
* org.tupeloproject.rdf.terms.Foaf.KNOWS

How does bean session work?

We want to be very clear on what bean session will do. Bean session will take a java bean and associate a subject with it and at least one mapping. The mapping tells the session how the properties relate to the vocabulary and the particulars of how to convert them all to RDF. A reminder that every thing in RDF has a unique subject. When we refer to a subject we mean exactly this.

Creating a bean

To create a bean that models a foaf person, all that is needed are accessors for the information. A typical one might be

public class FoafPerson {
        public FoafPerson(){
            super();
        }
        public FoafPerson(String name){
            super();
            setName(name);
        }
 
        String name;
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
 
        Collection<FoafPerson> friends;
        public Collection<FoafPerson> getFriends() {
            if (friends == null) {
                friends = new LinkedList<FoafPerson>();
            }
            return friends;
        }
 
        public void setFriends(Collection<FoafPerson> friends) {this.friends = friends;}
        public void addFriend(FoafPerson friend){getFriends().add(friend);}
        public boolean knows(FoafPerson person) {return getFriends().contains(person);}
 
        // other methods, such for adding or removing friends
    }

Note especially that there are no external references or structures imposed on this bean by the session. Any plain old java bean will work.

To use this with a bean session requires that we create a bean mapping. This is a description of how the properties of the bean are to be converted to or from RDF. The following method would be often created as a static call in a utility class:

public class PersonUtility{
  public static  BeanMapping getPersonMapping() {
        BeanMapping beanMapping = new BeanMapping();
        // set the class. This tells the session which java class this refers to.
        beanMapping.setJavaClass(FoafPerson.class);
        // This is a unique identifier for this mapping. It is used internally to find the mapping.
        beanMapping.setSubject(Resource.uriRef("urn:mappings:/org/foo/foafPerson"));
        // This associates the RDF type of a foaf person with instances of this class. Every
        // instance of FoafPerson that is saved will be given this type so other applications
        // can use it.
        beanMapping.setRdfType(Foaf.PERSON);
        // this tells the session that the property called "name" corresponds to
        // the RDF predicate for the foaf name
        beanMapping.addProperty(Foaf.NAME, "name", String.class);
        // This tells the session that the property called "friends" corresponds to
        // the RDF predicate for foaf knows.
        // Notice that this is being stored as a list and that each element of the list will be a FoafPerson.
        beanMapping.addListProperty(Foaf.KNOWS, "friends", FoafPerson.class);
        return beanMapping;
    }
}

Working with your bean

Bean session tries very hard to be unobtrusive. How do you get bean session to manage your beans? You must register them with a subject. Below is a complete if small program to use the person bean we have made. It sets up the mapping in a specific mapping context (this is a good practice, hence it is illustrated here). It then creates a thing and reads out the information from the context. In the normal lifecycle of a bean, you only need to set up the mappings once and then every bean may use it.

public static void main(String[] args){
        Context mappings = new MemoryContext(); // a place to store mappings
        Context data = new MemoryContext(); // where the actual data goes
        BeanSession beanSession = new BeanSession(data, mappings); // create the session
        beanSession.addBeanMapping(getPersonMapping()); // stick in the mapping
        beanSession.saveMappings(); // save it.
        // if you really want to see all the triples created for the mapping,
        // uncomment the next line
        // RdfXml.write(mappings.getTriples(), System.out);
 
        // here are our two people
        FoafPerson bob = new FoafPerson("bob"); // our first bean
        FoafPerson ted = new FoafPerson("ted"); // our second bean
 
        // Create subjects for them:
        Resource bobSubject = Resource.uriRef("urn:people:/bob");
        Resource tedSubject = Resource.uriRef("urn:people:/ted");
 
        // register them with the session. Any time before saving will do.
        beanSession.register(bobSubject, bob);
        beanSession.register(tedSubject, ted);
 
        // now we can just do whatever we need to with the beans,
        bob.addFriend(ted);
        // etc. etc.
        beanSession.save();
        // if you really wish to see the raw triples, uncomment the next line
        // RdfXml.write(data.getTriples(), System.out);
 
        // a check to show that the correct information landed in the context.
        ThingSession ts = new ThingSession(data); // create a different session on the data
        Thing bobThing = ts.fetchThing(bobSubject); // grab the thing by subject
        System.out.println("Bob's name = " + bobThing.getString(Foaf.NAME)); // print the name
        System.out.println("Bob's knows = " + Arrays.toString(bobThing.getValues(Foaf.KNOWS).toArray()));
}

You should get output like this

Bob's name = bob
Bob's knows = [urn:people:/ted]

More advanced topics

There are several capabilities of bean session. Two of the more useful ones we wish to discuss are refetch and update Refetch will re-read a specific bean or all beans from the backing context. This is useful in those cases where some other process is updating the data. The effect will be that all of the current values are changed if needed.

Similarly, update takes one bean and copies the values to another. Note that the beans must have a designated subject property or this will fail.

  • No labels