SeamFramework.orgCommunity Documentation

Chapter 5. Seam JCR - Object Content Mapping

5.1. What is Object Content Mapping?
5.2. Mapping and Conversion Capabilities
5.3. JCR Data Access Objects

Object Content Mapping is a design paradigm, in the same light as ORM (Object Relational Mapping) frameworks such as JPA or Hibernate, where statically typed objects are bound to a storage mechanism, in this case a JCR store. Seam JCR OCM is provided as annotations only on top of entities that are discovered during the CDI Phase ProcessAnnotatedType. In addition, Seam JCR's OCM implementation provides ServiceHandlers for working with entities over JCR.

The mapping API is very simple and designed to be clean. In order to define an entity, you simply need to use the annotation org.jboss.seam.jcr.annotations.ocm.JcrNode to define that this is an entity to map. All fields by default will be mapped to their field names. You can override this behavior by using the annotation org.jboss.seam.jcr.annotations.ocm.JcrProperty which will map the property to a different property name. The JcrProperty annotation can be placed on both field and getter method. You can define a special property uuid of type String that will represent the identifier for the node. This is a sample node mapping:



        @JcrNode("nt:unstructured")
public class BasicNode implements java.io.Serializable {
    @JcrProperty("myvalue")
    private String value;
    private String uuid;
    private String lordy;
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public String getUuid() {
        return uuid;
    }
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
    @JcrProperty("notaproperty")
    public String getLordy() {
        return lordy;
    }
    public void setLordy(String lordy) {
        this.lordy = lordy;
    }   
}
        

The simplest way to convert entities is to use CDI Events. There are two event objects that can be fired to support parsing, org.jboss.seam.jcr.ocm.ConvertToNode and org.jboss.seam.jcr.ocm.ConvertToObject. By passing in a node and a pre-constructed object you can convert the full node to object or object to node depending on your need. Here is a sample parsing (from our test cases):



        @Inject Event<ConvertToObject< objectEvent;
        @Inject Event<ConvertToNode< nodeEvent;
        ....
        
        Node root = session.getRootNode();
        Node ocmnode1 = root.addNode("ocmnode1","nt:unstructured");
        BasicNode bn = new BasicNode();
        bn.setValue("Hello, World!");
        bn.setLordy("this was saved.");
        nodeEvent.fire(new ConvertToNode(bn,ocmnode1));
        
        Node hello2 = root.getNode("ocmnode1");
        BasicNode bn2 = new BasicNode();
        objectEvent.fire(new ConvertToObject(hello2,bn2));
        

If you have ever worked with entities, the term DAO should be very familiar to you. Seam JCR OCM supports DAOs in a highly automated fashion. Using annotations and interfaces only, you can automate querying, finds and saving entities into their mapped node types. There are four annotations to support DAOs:

Here is a sample definition of an interface, describing the objects that can be used:



        import static org.jboss.seam.jcr.ConfigParams.MODESHAPE_URL;
import java.util.List;
import org.jboss.seam.jcr.annotations.JcrConfiguration;
import org.jboss.seam.jcr.annotations.ocm.JcrDao;
import org.jboss.seam.jcr.annotations.ocm.JcrFind;
import org.jboss.seam.jcr.annotations.ocm.JcrQuery;
import org.jboss.seam.jcr.annotations.ocm.JcrSave;
import org.jboss.seam.jcr.test.ocm.BasicNode;
@JcrDao(
    @JcrConfiguration(name = MODESHAPE_URL, 
        value = "file:target/test-classes/modeshape.xml?repositoryName=CarRepo")
)
public interface BasicNodeDAO {
    @JcrFind
    public BasicNode findBasicNode(String uuid);
    @JcrQuery(query="select * from [nt:unstructured]",language="JCR-SQL2",resultClass=BasicNode.class)
    public List<BasicNode> findAllNodes();
    @JcrSave
    public String save(String path, BasicNode basicNode);
}
        

In this case, we are telling the JcrDao BasicNodeDAO to use the JCR Session based on the annotated JcrConfiguration noted. Since BasicNode is mapped to nt:unstructured, we can map any nt:unstructured to it by calling findAllNodes. We can save a basic node to a given path as well as find based on uuid. The best part is that there is no implementation necessary on your side. You can use this interface as is.



        @Inject
    BasicNodeDAO basicDAO;
    
    ....
        BasicNode bn = new BasicNode();
        bn.setValue("this is my node.");
        String uuid = basicDAO.save("/anypathone",bn);
        System.out.println("The UUID is: "+uuid);
        
        BasicNode bn2 = basicDAO.findBasicNode(uuid);
        System.out.printf("The original node was %s and the new node is \n",bn.getValue(), bn2.getValue());
        
        List<BasicNode> nodes = basicDAO.findAllNodes();
        System.out.println(nodes);