You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by co...@apache.org on 2008/02/08 10:49:00 UTC

[CONF] Apache Jackrabbit: 5' with Jackrabbit OCM (page edited)

5' with Jackrabbit OCM (JCR) edited by Christophe Lombart
      Page: http://cwiki.apache.org/confluence/display/JCR/5%27+with+Jackrabbit+OCM
   Changes: http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=75934&originalVersion=1&revisedVersion=2






Content:
---------------------------------------------------------------------

This very small tutorial describes how to create an application with Jackrabbit OCM.
In short, you have to :
* Create one or more persistent classes.
* Create the OCM node type called _ocm:discriminator_. 
* Initialize the JCR repository. 
* Instantiate an [Object Content Manager] component.
* Use the [Object Content Manager] to persist your data.

The node type creation is specific to the JCR implementation. So, the code used in this tutorial works only with Jackrabbit. 

h2. Create a persistent class

This tutorial is using the annotation support to define a persistent class. Your data objects are simple pojos with some OCM annotations. 
Here is a example of a PressRelease class. 

{code}
package org.apache.jackrabbit.ocm.model;

import java.util.Date;

import org.apache.jackrabbit.ocm.mapper.impl.annotation.Field;
import org.apache.jackrabbit.ocm.mapper.impl.annotation.Node;

@Node
public class PressRelease 
{
	@Field(path=true) String path;
	@Field String title; 
	@Field Date pubDate; 
	@Field String content;
	
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Date getPubDate() {
		return pubDate;
	}
	public void setPubDate(Date pubDate) {
		this.pubDate = pubDate;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	
	
}
{code}

The annotation {code}@Node{code} has to be added on the top of the class.
Each persistent class must have a *path field* which will be mapped into the JCR Node path. This can be specify with the annotation {code}@Field(path=true){code}.
Other persistent fields can be defined with the annotation {code}@Field{code}

That's all for the class definition. In other tutorials, we will see how to map advanced fields like collections or custom objects. 


h2. Create the node type _ocm:discriminator_
The mixin node type _ocm:discriminator_ is used internally by the [Object Content Manager] to store the classname of the object to persist. You have to create a new xml file which contains the following structure : 

{code:xml}
<?xml version="1.0" encoding="UTF-8"?>

<nodeTypes xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
       xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
       xmlns:sv="http://www.jcp.org/jcr/sv/1.0"
       xmlns:test="http://www.apache.org/jackrabbit/test"
       xmlns:mix="http://www.jcp.org/jcr/mix/1.0"
       xmlns:ocm="http://jackrabbit.apache.org/ocm">

  <nodeType name="ocm:discriminator" isMixin="true">
   <supertypes>
     <supertype>nt:base</supertype>
   </supertypes>
   <propertyDefinition name="ocm:classname" requiredType="String" autoCreated="false" mandatory="true" onParentVersion="COPY" protected="false" multiple="false" />
 </nodeType>
</nodeTypes>
{code} 

You can save this file as "custom_nodetypes.xml". You can also use the CND notation.

{info:title= When is the node type _ocm:discriminator_  used  ? }
With Jackrabbit OCM, it is possible to map different classes to the same node type. For example, it is possible to map severals java classes into the node type _nt:unstructured_. So, when the [Object Content Manager] retrieves a node based on this kind of generic type, he has to know the class to instantiate. Then, it uses the ocm:classname property stored in the _ocm:discriminator_ mixin type.
{info}


h2. Initialize the JCR repository 

You have to import the xml file created in the previous step and create the namespace _ocm_ into the JCR repository. 

You can use the following utility class : 
{code} 
package org.apache.jackrabbit.ocm.util;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;

import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Workspace;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeTypeManager;
import javax.naming.Context;
import javax.naming.InitialContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.core.jndi.RegistryHelper;
import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
import org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader;
import org.apache.jackrabbit.ocm.exception.RepositoryException;
import org.apache.jackrabbit.util.ISO9075;
import org.apache.jackrabbit.util.Text;

/**
* Utility class for managing JCR repositories.
* <b>Note</b>: most of the utility methods in this class can be used only with Jackrabbit.
*
* @author <a href="mailto:christophe.lombart@sword-technologies.com">Lombart Christophe </a>
* @version $Id: Exp $
*/
public class RepositoryUtil
{
    
    /** namespace prefix constant */
    public static final String OCM_NAMESPACE_PREFIX   = "ocm";

    /** namespace constant */
    public static final String OCM_NAMESPACE          = "http://jackrabbit.apache.org/ocm";    
    
    /** Item path separator */
    public static final String PATH_SEPARATOR = "/";
    
    private final static Log log = LogFactory.getLog(RepositoryUtil.class);
    
    /**
     * Register a new repository 
     * 
     * @param repositoryName The repository unique name
     * @param configFile The JCR config file
     * @param homeDir The directory containing the complete repository settings (workspace, node types, ...)
     * 
     * @throws RepositoryException when it is not possible to register the repository
     */
    public static void registerRepository(String repositoryName, String configFile, String homeDir) throws RepositoryException
    {
        try
        {
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
            env.put(Context.PROVIDER_URL, "localhost");
            InitialContext ctx = new InitialContext(env);

            RegistryHelper.registerRepository(ctx, repositoryName, configFile, homeDir, true);
        }
        catch (Exception e)
        {        
            throw new RepositoryException("Impossible to register the respository : " + 
                                           repositoryName + " - config file : " + configFile, e);
        }        
        
    }
    
    
    /**
     * Unregister a repository 
     * 
     * @param repositoryName The repository unique name
     * 
     * @throws RepositoryException when it is not possible to unregister the repository
     */
    public static void unRegisterRepository(String repositoryName) throws RepositoryException
    {
        try
        {
        	Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
            env.put(Context.PROVIDER_URL, "localhost");
            InitialContext ctx = new InitialContext(env);

            RegistryHelper.unregisterRepository(ctx, repositoryName);
        }
        catch (Exception e)
        {
            throw new RepositoryException("Impossible to unregister the respository : " + 
                                           repositoryName , e);
        }        
        
    }
    
    /**
     * Get a repository
     * 
     * @param repositoryName The repository name
     * @return a JCR repository reference
     * 
     * @throws RepositoryException when it is not possible to get the repository. 
     *         Before calling this method, the repository has to be registered (@see RepositoryUtil#registerRepository(String, String, String)
     */
    public static Repository getRepository(String repositoryName) throws RepositoryException
    {
        try
        {
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
            env.put(Context.PROVIDER_URL, "localhost");
            InitialContext ctx = new InitialContext(env);
            
            Repository repository = (Repository) ctx.lookup(repositoryName);
            return repository;
        }
        catch (Exception e)
        {
            throw new RepositoryException("Impossible to get the repository : " + repositoryName, e);
        }        
    }
    
    /**
     * Connect to a JCR repository
     * 
     * @param repository The JCR repository 
     * @param user The user name
     * @param password The password
     * @return a valid JCR session 
     * 
     * @throws RepositoryException when it is not possible to connect to the JCR repository 
     */
    public static Session login(Repository repository, String user, String password) throws RepositoryException
    {
        try
        {
            Session session = repository.login(new SimpleCredentials(user, password.toCharArray()), null);
            
           
            return session; 
        }
        catch (Exception e)
        {
            throw new RepositoryException("Impossible to login ", e);
                        
        }
        
        
    }
      
    public static Session login(Repository repository, String user, String password, String workspace) throws RepositoryException
    {
        try
        {
            Session session = repository.login(new SimpleCredentials(user, password.toCharArray()), workspace);
            return session; 
        }
        catch (Exception e)
        {
            throw new RepositoryException("Impossible to login ", e);
                        
        }
        
        
    }
    
    /**
     * Create the ocm namespace
     * 
     */
    public static void createNamespace(Session session) throws RepositoryException
    {
         try
         {
        	log.info("Setup Jcr session setup ...");
        	
            String[] jcrNamespaces = session.getWorkspace().getNamespaceRegistry().getPrefixes();
            boolean createNamespace = true;
            for (int i = 0; i < jcrNamespaces.length; i++)
            {
                if (jcrNamespaces[i].equals(OCM_NAMESPACE_PREFIX))
                {
                    createNamespace = false;
                    log.debug("Jackrabbit OCM namespace exists.");
                }
            }
             
            if (createNamespace)
            {
                session.getWorkspace().getNamespaceRegistry().registerNamespace(OCM_NAMESPACE_PREFIX, OCM_NAMESPACE);
                log.info("Successfully created Jackrabbit OCM namespace.");
            }
            
            if (session.getRootNode() != null)
            {
                log.info("Jcr session setup successfull.");
            }
            

        }
        catch (Exception e)
        {
            log.error("Error while setting up the jcr session.", e);
            throw new RepositoryException(e.getMessage());
        }
    }

    public static void registerNodeTypes(Session session, String nodeTypeFile)
    {
        try {
			InputStream xml = new FileInputStream(nodeTypeFile);

			NodeTypeDef[] types = NodeTypeReader.read(xml);

			Workspace workspace = session.getWorkspace();
			NodeTypeManager ntMgr = workspace.getNodeTypeManager();
			NodeTypeRegistry ntReg = ((NodeTypeManagerImpl) ntMgr).getNodeTypeRegistry();

			for (int j = 0; j < types.length; j++) {
			    NodeTypeDef def = types[j];

			    try {
			        ntReg.getNodeTypeDef(def.getName());
			    }
			    catch (NoSuchNodeTypeException nsne) {
			        // HINT: if not already registered than register custom node type
			        ntReg.registerNodeType(def);
			    }

			}
		} 
        catch (Exception e) 
		{
        	throw new RepositoryException("Impossible to register node types", e);
		}
    }
    
    /**
     * Encode a path 
     * @TODO : drop Jackrabbit dependency
     * 
     * @param path the path to encode
     * @return the encoded path 
     * 
     */
    public static String encodePath(String path)
    {
    	String[] pathElements = Text.explode(path, '/');
    	for (int i=0;i<pathElements.length;i++)
    	{
    		pathElements[i] = ISO9075.encode(pathElements[i]);
    	}
    	return "/" + Text.implode(pathElements, "/");
    }
    
    }

{code} 

Now, you can use this utility class like this : 
{code}
Session session = ... // get a JCR Session
RepositoryUtil.createNamespace(session);
RepositoryUtil.registerNodeTypes(session, "[full path]/custom_nodetypes.xml");
{code}

The method call *RepositoryUtil.createNamespace(session)*  will create the _ocm_ namespace and the other one *RepositoryUtil.registerNodeTypes(...)* will import the node type ocm:descriminator (defined in the file custom_nodetypes.xml).

h2. Instantiate an Object Content Manager component
In order to save a PressRelease object, you have to instantiate an [Object Content Manager] component : 

{code}
List<Class> classes = new ArrayList<Class>();	
classes.add(PressRelease.class); // Call this method for each persistent class
		
Mapper mapper = new AnnotationMapperImpl(classes);
ObjectContentManager ocm =  new ObjectContentManagerImpl(session, mapper);	
{code}

h2. Use the Object Content Manager to persist your data

Now, you are ready to create a new PressRelease and use the [Object Content Manager] to persist it into the JCR repository. 

{code}
// Insert an object
System.out.println("Insert a press release in the repository");
PressRelease pressRelease = new PressRelease();
pressRelease.setPath("/newtutorial");
pressRelease.setTitle("This is the first tutorial on OCM");
pressRelease.setPubDate(new Date());
pressRelease.setContent("Many Jackrabbit users ask to the dev team to make a tutorial on OCM");
			
ocm.insert(pressRelease);
ocm.save();
			
// Retrieve 
System.out.println("Retrieve a press release from the repository");
pressRelease = (PressRelease) ocm.getObject("/newtutorial");
System.out.println("PressRelease title : " + pressRelease.getTitle());
			
// Delete
System.out.println("Remove a press release from the repository");
ocm.remove(pressRelease);
ocm.save();
{code}

---------------------------------------------------------------------
CONFLUENCE INFORMATION
This message is automatically generated by Confluence

Unsubscribe or edit your notifications preferences
   http://cwiki.apache.org/confluence/users/viewnotifications.action

If you think it was sent incorrectly contact one of the administrators
   http://cwiki.apache.org/confluence/administrators.action

If you want more information on Confluence, or have a bug to report see
   http://www.atlassian.com/software/confluence