Package org.apache.wookie.beans.jcr

Source Code of org.apache.wookie.beans.jcr.JCRPersistenceManager

/*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

package org.apache.wookie.beans.jcr;

import java.io.InputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.nodetype.NodeTypeManager;
import javax.naming.Context;
import javax.naming.InitialContext;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
import org.apache.jackrabbit.ocm.manager.ObjectContentManager;
import org.apache.jackrabbit.ocm.manager.atomictypeconverter.impl.DefaultAtomicTypeConverterProvider;
import org.apache.jackrabbit.ocm.manager.cache.ObjectCache;
import org.apache.jackrabbit.ocm.manager.cache.impl.RequestObjectCacheImpl;
import org.apache.jackrabbit.ocm.manager.impl.ObjectContentManagerImpl;
import org.apache.jackrabbit.ocm.manager.objectconverter.impl.ObjectConverterImpl;
import org.apache.jackrabbit.ocm.manager.objectconverter.impl.ProxyManagerImpl;
import org.apache.jackrabbit.ocm.mapper.Mapper;
import org.apache.jackrabbit.ocm.mapper.impl.annotation.AnnotationMapperImpl;
import org.apache.jackrabbit.ocm.query.Filter;
import org.apache.jackrabbit.ocm.query.Query;
import org.apache.jackrabbit.ocm.query.QueryManager;
import org.apache.wookie.beans.IBean;
import org.apache.wookie.beans.IDescription;
import org.apache.wookie.beans.IFeature;
import org.apache.wookie.beans.ILicense;
import org.apache.wookie.beans.IName;
import org.apache.wookie.beans.IOAuthToken;
import org.apache.wookie.beans.IParam;
import org.apache.wookie.beans.IParticipant;
import org.apache.wookie.beans.IPreference;
import org.apache.wookie.beans.IPreferenceDefault;
import org.apache.wookie.beans.ISharedData;
import org.apache.wookie.beans.IStartFile;
import org.apache.wookie.beans.IWidget;
import org.apache.wookie.beans.IWidgetIcon;
import org.apache.wookie.beans.IWidgetInstance;
import org.apache.wookie.beans.jcr.impl.DescriptionImpl;
import org.apache.wookie.beans.jcr.impl.FeatureImpl;
import org.apache.wookie.beans.jcr.impl.LicenseImpl;
import org.apache.wookie.beans.jcr.impl.NameImpl;
import org.apache.wookie.beans.jcr.impl.ParamImpl;
import org.apache.wookie.beans.jcr.impl.ParticipantImpl;
import org.apache.wookie.beans.jcr.impl.PreferenceDefaultImpl;
import org.apache.wookie.beans.jcr.impl.PreferenceImpl;
import org.apache.wookie.beans.jcr.impl.SharedDataImpl;
import org.apache.wookie.beans.jcr.impl.StartFileImpl;
import org.apache.wookie.beans.jcr.impl.WidgetIconImpl;
import org.apache.wookie.beans.jcr.impl.WidgetImpl;
import org.apache.wookie.beans.jcr.impl.WidgetInstanceImpl;
import org.apache.wookie.beans.util.IPersistenceManager;
import org.apache.wookie.beans.util.PersistenceCommitException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* JCRPersistenceManager - JCR IPersistenceManager implementation.
*
* @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
* @version $Id$
*/
public class JCRPersistenceManager implements IPersistenceManager
{
    private static final Logger logger = LoggerFactory.getLogger(JCRPersistenceManager.class);
   
    public static final String WIDGET_REPOSITORY_JNDI_REPOSITORY_NAME = "jcr/widgetrepo";
    public static final String WIDGET_REPOSITORY_JNDI_REPOSITORY_FULL_NAME = "java:comp/env/"+WIDGET_REPOSITORY_JNDI_REPOSITORY_NAME;

    public static final String PERSISTENCE_MANAGER_USER_PROPERTY_NAME = "widget.persistence.manager.user";
    public static final String PERSISTENCE_MANAGER_PASSWORD_PROPERTY_NAME = "widget.persistence.manager.password";
    public static final String PERSISTENCE_MANAGER_ROOT_PATH_PROPERTY_NAME = "widget.persistence.manager.rootpath";
    public static final String PERSISTENCE_MANAGER_WORKSPACE_PROPERTY_NAME = "widget.persistence.manager.workspace";

    private static final Map<Class<?>,Class<?>> INTERFACE_TO_CLASS_MAP = new HashMap<Class<?>,Class<?>>();
    private static final Map<Class<? extends IBean>,Class<? extends IBean>> BEAN_INTERFACE_TO_CLASS_MAP = new HashMap<Class<? extends IBean>,Class<? extends IBean>>();
    private static final Map<String,String> IMPLEMENTATION_FIELD_MAP = new HashMap<String,String>();
    static
    {
        INTERFACE_TO_CLASS_MAP.put(IDescription.class, DescriptionImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IFeature.class, FeatureImpl.class);
        INTERFACE_TO_CLASS_MAP.put(ILicense.class, LicenseImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IName.class, NameImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IParam.class, ParamImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IParticipant.class, ParticipantImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IPreference.class, PreferenceImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IPreferenceDefault.class, PreferenceDefaultImpl.class);
        INTERFACE_TO_CLASS_MAP.put(ISharedData.class, SharedDataImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IStartFile.class, StartFileImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IWidget.class, WidgetImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IWidgetIcon.class, WidgetIconImpl.class);
        INTERFACE_TO_CLASS_MAP.put(IWidgetInstance.class, WidgetInstanceImpl.class);

        BEAN_INTERFACE_TO_CLASS_MAP.put(IParticipant.class, ParticipantImpl.class);
        BEAN_INTERFACE_TO_CLASS_MAP.put(IWidget.class, WidgetImpl.class);
        BEAN_INTERFACE_TO_CLASS_MAP.put(IWidgetInstance.class, WidgetInstanceImpl.class);
       
        IMPLEMENTATION_FIELD_MAP.put("widget", "widgetImpl");
    }

    private static final List<Class> CLASS_LIST = new ArrayList<Class>(INTERFACE_TO_CLASS_MAP.values());

    private static String repositoryUser;
    private static String repositoryPassword;
    private static String repositoryWorkspace;
    private static String rootPath;
    private static String repositoryRootPath;
   
    private static Map<Class<? extends IBean>,String> beanClassNodeRootPaths = new HashMap<Class<? extends IBean>,String>();
    private static GenericObjectPool ocmPool;
   
    public static final String REPOSITORY_USER_PROPERTY_NAME = "wookie.repository.user";
    public static final String REPOSITORY_PASSWORD_PROPERTY_NAME = "wookie.repository.password";
    public static final String REPOSITORY_ROOT_PATH_PROPERTY_NAME = "wookie.repository.rootpath";
    public static final String REPOSITORY_WORKSPACE_PROPERTY_NAME = "wookie.repository.workspace";

    /**
     * Initialize implementation with configuration.
     *
     * @param configuration configuration properties
     * @param initializeStore truncate and initialize persistent store
     */
    public static void initialize(Configuration configuration, boolean initializeStore)
    {
        try
        {
            // configuration
            repositoryUser = configuration.getString(PERSISTENCE_MANAGER_USER_PROPERTY_NAME);
            repositoryPassword = configuration.getString(PERSISTENCE_MANAGER_PASSWORD_PROPERTY_NAME);
            repositoryWorkspace = configuration.getString(PERSISTENCE_MANAGER_WORKSPACE_PROPERTY_NAME);
            rootPath = configuration.getString(PERSISTENCE_MANAGER_ROOT_PATH_PROPERTY_NAME);
            for (Map.Entry<Class<? extends IBean>,Class<? extends IBean>> mapping : BEAN_INTERFACE_TO_CLASS_MAP.entrySet())
            {
                Class<? extends IBean> beanClass = mapping.getValue();
                Class<? extends IBean> beanInterface = mapping.getKey();
                String name = beanInterface.getSimpleName();
                if (name.startsWith("I"))
                {
                    name = name.substring(1);
                }
                if (!name.endsWith("s"))
                {
                    name = name+"s";
                }
                String nodeRootPath = rootPath+"/"+name;
                beanClassNodeRootPaths.put(beanClass, nodeRootPath);
            }
           
            // create JCR credentials session pool
            PoolableObjectFactory sessionFactory = new BasePoolableObjectFactory()
            {
                /* (non-Javadoc)
                 * @see org.apache.commons.pool.BasePoolableObjectFactory#passivateObject(java.lang.Object)
                 */
                public void passivateObject(Object obj) throws Exception
                {
                    // clear OCM object cache
                    ((ObjectContentManagerImpl)obj).setRequestObjectCache(new RequestObjectCacheImpl());
                }

                /* (non-Javadoc)
                 * @see org.apache.commons.pool.BasePoolableObjectFactory#makeObject()
                 */
                public Object makeObject() throws Exception
                {
                    // lookup JCR repository from context
                    Context initialContext = new InitialContext();
                    Repository repository = (Repository)initialContext.lookup(WIDGET_REPOSITORY_JNDI_REPOSITORY_FULL_NAME);
                   
                    // create and login JCR session
                    Credentials credentials = new SimpleCredentials(repositoryUser, repositoryPassword.toCharArray());
                    Session session = ((repositoryWorkspace != null) ? repository.login(credentials, repositoryWorkspace) : repository.login(credentials));
                   
                    // return session object content manager for session
                    return new SessionObjectContentManagerImpl(session, new AnnotationMapperImpl(CLASS_LIST));
                }

                /* (non-Javadoc)
                 * @see org.apache.commons.pool.BasePoolableObjectFactory#destroyObject(java.lang.Object)
                 */
                public void destroyObject(Object obj) throws Exception
                {
                    // logout and close object content manager and session
                    ((ObjectContentManagerImpl)obj).logout();
                }
            };
            ocmPool = new GenericObjectPool(sessionFactory, 0, GenericObjectPool.WHEN_EXHAUSTED_GROW, 0, 5);
            ocmPool.setTimeBetweenEvictionRunsMillis(60000);
            ocmPool.setMinEvictableIdleTimeMillis(300000);
           
            // initialize persistent store
            if (initializeStore)
            {
                // borrow object content manager and initialization session from pool
                ObjectContentManager ocm = (ObjectContentManager)ocmPool.borrowObject();
                Session session = ocm.getSession();
               
                // initialize root path in repository
               
                // Jackrabbit/JCR 2.X
                //boolean rootPathNodeExists = session.nodeExists(rootPath);

                // Jackrabbit/JCR 1.X
                boolean rootPathNodeExists = session.itemExists(rootPath);
               
                if (rootPathNodeExists)
                {
                    // delete nodes of root path node

                    // Jackrabbit/JCR 2.X
                    //Node rootNode = session.getNode(rootPath);

                    // Jackrabbit/JCR 1.X
                    Node rootNode = (Node)session.getItem(rootPath);
                   
                    NodeIterator nodesIter = rootNode.getNodes();
                    while (nodesIter.hasNext())
                    {
                        nodesIter.nextNode().remove();
                    }
                }
                else
                {
                    // create unstructured node hierarchy
                    int rootPathParentIndex = -1;
                    int rootPathIndex = rootPath.indexOf('/', 1);
                    while (rootPathIndex != -1)
                    {
                        // Jackrabbit/JCR 2.X
                        //Node parentNode = session.getNode(rootPath.substring(0, ((rootPathParentIndex != -1) ? rootPathParentIndex : 1)));

                        // Jackrabbit/JCR 1.X
                        Node parentNode = (Node)session.getItem(rootPath.substring(0, ((rootPathParentIndex != -1) ? rootPathParentIndex : 1)));

                        String nodeName = rootPath.substring(((rootPathParentIndex != -1) ? rootPathParentIndex+1 : 1), rootPathIndex);
                        parentNode.addNode(nodeName, "nt:unstructured");                       
                        rootPathParentIndex = rootPathIndex;
                        rootPathIndex = rootPath.indexOf('/', rootPathIndex+1);
                    }

                    // Jackrabbit/JCR 2.X
                    //Node parentNode = session.getNode(rootPath.substring(0, ((rootPathParentIndex != -1) ? rootPathParentIndex : 1)));

                    // Jackrabbit/JCR 1.X
                    Node parentNode = (Node)session.getItem(rootPath.substring(0, ((rootPathParentIndex != -1) ? rootPathParentIndex : 1)));

                    String nodeName = rootPath.substring(((rootPathParentIndex != -1) ? rootPathParentIndex+1 : 1));
                    parentNode.addNode(nodeName, "nt:unstructured");
                }
                // create bean class node root paths

                // Jackrabbit/JCR 2.X
                //Node rootNode = session.getNode(rootPath);

                // Jackrabbit/JCR 1.X
                Node rootNode = (Node)session.getItem(rootPath);

                for (String nodeRootPath : beanClassNodeRootPaths.values())
                {
                    String nodeName = nodeRootPath.substring(rootPath.length()+1);
                    rootNode.addNode(nodeName, "nt:unstructured");
                }
                session.save();

                // register/reregister repository node types
                NodeTypeManager nodeTypeManager = session.getWorkspace().getNodeTypeManager();
                InputStream nodeTypesCNDStream = JCRPersistenceManager.class.getResourceAsStream("wookie-schema.cnd");
                if (nodeTypesCNDStream == null)
                {
                    throw new IllegalArgumentException("Unable to load node types configuration: wookie-schema.cnd");                   
                }
               
                // Jackrabbit/JCR 2.X
                //Reader nodeTypesCNDReader = new InputStreamReader(nodeTypesCNDStream);
                //NamespaceRegistry namespaceRegistry = session.getWorkspace().getNamespaceRegistry();
                //ValueFactory valueFactory = session.getValueFactory();
                //CndImporter.registerNodeTypes(nodeTypesCNDReader, "wookie-schema.cnd", nodeTypeManager, namespaceRegistry, valueFactory, true);

                // Jackrabbit/JCR 1.X
                ((NodeTypeManagerImpl)nodeTypeManager).registerNodeTypes(nodeTypesCNDStream, NodeTypeManagerImpl.TEXT_X_JCR_CND, true);

                // save session used to load node types
                session.save();
                logger.info("Persistent store initialized at "+rootPath);

                // return object content manager and initialization session to pool
                ocmPool.returnObject(ocm);
            }
           
            logger.info("Initialized");
        }
        catch (Exception e)
        {
            throw new RuntimeException("Unable to initialize: "+e, e);
        }
    }

    /**
     * Terminate implementation.
     */
    public static void terminate()
    {
        try
        {
            // close JCR credentials session pool
            ocmPool.close();
           
            logger.info("Terminated");
        }
        catch (Exception e)
        {           
            throw new RuntimeException("Unable to terminate: "+e, e);
        }
    }
   
    public SessionObjectContentManagerImpl ocm;
    public SessionObjectCacheImpl ocmCache;
    public boolean ocmWrite;

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#begin()
     */
    public void begin()
    {
        // validate object content manager transaction
        if (ocm != null)
        {
            throw new IllegalStateException("Transaction already initiated");
        }

        // create object content manager session and start transaction
        try
        {
            // borrow session object content manager from pool
            ocm = (SessionObjectContentManagerImpl)ocmPool.borrowObject();
            ocmCache = new SessionObjectCacheImpl();
            ocm.setRequestObjectCache(ocmCache);
            ocmWrite = false;
        }
        catch (Exception e)
        {
            throw new RuntimeException("Unexpected exception: "+e, e);
        }
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#close()
     */
    public void close()
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }       

        // rollback transaction and close object content manager session
        try
        {
            if (!ocmWrite)
            {
                // return session object content manager to pool
                ocmCache.reset();
                ocmPool.returnObject(ocm);
            }
            else
            {
                // logout and close object content manager: do not return to pool
                ocmCache.reset();
                ocm.logout();
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException("Unexpected exception: "+e, e);
        }
        finally
        {
            ocm = null;
            ocmCache = null;
            ocmWrite = false;
        }
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#commit()
     */
    public void commit() throws PersistenceCommitException
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }       

        // commit object content manager session transaction
        try
        {
            // save object content manager writes to repository
            ocm.save();
            ocmWrite = false;
        }
        catch (Exception e)
        {
            throw new PersistenceCommitException("Object content manager write exception: "+e, e);
        }
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#delete(org.apache.wookie.beans.IBean)
     */
    public boolean delete(IBean bean)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // track object content manager write
        ocmWrite = true;
       
        // delete bean
        try
        {
            String nodePath = ((IPathBean)bean).getNodePath();
            if (nodePath != null)
            {
                // notify pre-delete listener
                if (bean instanceof IPersistenceListener)
                {
                    if (!((IPersistenceListener)bean).preDelete(this))
                    {
                        throw new RuntimeException("Pre-delete listener invocation failed");
                    }
                }
               
                // delete node
                ocm.remove(nodePath);
                ocmCache.removeObject(nodePath);

                // notify post-delete listener
                if (bean instanceof IPersistenceListener)
                {
                    if (!((IPersistenceListener)bean).postDelete(this))
                    {
                        throw new RuntimeException("Post-delete listener invocation failed");
                    }
                }               
                return true;
            }
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#delete(org.apache.wookie.beans.IBean[])
     */
    public boolean delete(IBean[] beans)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // track object content manager write
        ocmWrite = true;
       
        // remove beans
        try
        {
            for (IBean bean : beans)
            {
                String nodePath = ((IPathBean)bean).getNodePath();
                if (nodePath != null)
                {
                    // notify pre-delete listener
                    if (bean instanceof IPersistenceListener)
                    {
                        if (!((IPersistenceListener)bean).preDelete(this))
                        {
                            throw new RuntimeException("Pre-delete listener invocation failed");
                        }
                    }
                   
                    // delete node
                    ocm.remove(nodePath);
                    ocmCache.removeObject(nodePath);

                    // notify post-delete listener
                    if (bean instanceof IPersistenceListener)
                    {
                        if (!((IPersistenceListener)bean).postDelete(this))
                        {
                            throw new RuntimeException("Post-delete listener invocation failed");
                        }
                    }               
                }
            }
            return true;
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findAll(java.lang.Class)
     */
    @SuppressWarnings("unchecked")
    public <T extends IBean> T[] findAll(Class<T> beansInterface)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // validate bean interface
        Class<? extends IBean> beanClass = BEAN_INTERFACE_TO_CLASS_MAP.get(beansInterface);
        if (beanClass == null)
        {
            throw new IllegalArgumentException("Invalid bean interface specified");           
        }

        // get persistent bean extent by root path
        try
        {
            // construct query filter
            QueryManager queryManager = ocm.getQueryManager();
            Filter filter = queryManager.createFilter(beanClass);
            filter.setScope(beanClassNodeRootPaths.get(beanClass)+"//");
            Query query = queryManager.createQuery(filter);
           
            // invoke query
            Collection<? extends IBean> beansExtentList = ocm.getObjects(query);
            if ((beansExtentList != null) && !beansExtentList.isEmpty())
            {
                return beansExtentList.toArray((T [])Array.newInstance(beansInterface, beansExtentList.size()));
            }
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
        }
        return (T [])Array.newInstance(beansInterface, 0);
    }
  

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findById(java.lang.Class, java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    public <T extends IBean> T findById(Class<T> beanInterface, Object id)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // validate bean interface
        Class<? extends IBean> beanClass = BEAN_INTERFACE_TO_CLASS_MAP.get(beanInterface);
        if (beanClass == null)
        {
            throw new IllegalArgumentException("Invalid bean interface specified");           
        }

        // get persistent bean by primary id path
        try
        {
            if (!(id instanceof String) && (id != null))
            {
                id = id.toString();
            }
            return (T)ocm.getObject((String)id);
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
            return null;
        }
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findByValue(java.lang.Class, java.lang.String, java.lang.Object, java.lang.String, boolean)
     */
    @SuppressWarnings("unchecked")
    public <T extends IBean> T[] findByValue(Class<T> beansInterface, String name, Object value, String orderBy, boolean ascending)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // validate bean interface
        Class<? extends IBean> beanClass = BEAN_INTERFACE_TO_CLASS_MAP.get(beansInterface);
        if (beanClass == null)
        {
            throw new IllegalArgumentException("Invalid bean interface specified");           
        }

        // get persistent beans by root path and filter
        try
        {
            // construct query filter
            QueryManager queryManager = ocm.getQueryManager();
            Filter filter = queryManager.createFilter(beanClass);
            filter.setScope(beanClassNodeRootPaths.get(beanClass)+"//");
            if (name != null)
            {
                String mappedName = IMPLEMENTATION_FIELD_MAP.get(name);
                name = ((mappedName != null) ? mappedName : name);
                if (value instanceof IUuidBean)
                {
                    value = ((IUuidBean)value).getUuid();
                }
                filter = ((value != null) ? filter.addEqualTo(name, value) : filter.addIsNull(name));
            }           
            Query query = queryManager.createQuery(filter);
            if (orderBy != null)
            {
                String mappedOrderBy = IMPLEMENTATION_FIELD_MAP.get(orderBy);
                orderBy = ((mappedOrderBy != null) ? mappedOrderBy : orderBy);
                if (ascending)
                {
                    query.addOrderByAscending(orderBy);
                }
                else
                {
                    query.addOrderByDescending(orderBy);
                }
            }

            // invoke query
            Collection<? extends IBean> beansExtentList = ocm.getObjects(query);
            if ((beansExtentList != null) && !beansExtentList.isEmpty())
            {
                return beansExtentList.toArray((T [])Array.newInstance(beansInterface, beansExtentList.size()));
            }
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
        }
        return (T [])Array.newInstance(beansInterface, 0);
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findByValue(java.lang.Class, java.lang.String, java.lang.Object)
     */
    public <T extends IBean> T[] findByValue(Class<T> beansInterface, String name, Object value)
    {
        return findByValue(beansInterface, name, value, null, true);
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findByValues(java.lang.Class, java.util.Map, java.lang.String, boolean)
     */
    @SuppressWarnings("unchecked")
    public <T extends IBean> T[] findByValues(Class<T> beansInterface, Map<String, Object> values, String orderBy, boolean ascending)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // validate bean interface
        Class<? extends IBean> beanClass = BEAN_INTERFACE_TO_CLASS_MAP.get(beansInterface);
        if (beanClass == null)
        {
            throw new IllegalArgumentException("Invalid bean interface specified");           
        }

        // get persistent beans by root path and filter
        try
        {
            // construct query filter
            QueryManager queryManager = ocm.getQueryManager();
            Filter filter = queryManager.createFilter(beanClass);
            filter.setScope(beanClassNodeRootPaths.get(beanClass)+"//");
            if ((values != null) && !values.isEmpty())
            {
                for (Map.Entry<String,Object> value : values.entrySet())
                {
                    String valueName = value.getKey();
                    String mappedValueName = IMPLEMENTATION_FIELD_MAP.get(valueName);
                    valueName = ((mappedValueName != null) ? mappedValueName : valueName);
                    Object valueValue = value.getValue();
                    if (valueValue instanceof IUuidBean)
                    {
                        valueValue = ((IUuidBean)valueValue).getUuid();
                    }
                    filter = ((valueValue != null) ? filter.addEqualTo(valueName, valueValue) : filter.addIsNull(valueName));
                }
            }
            Query query = queryManager.createQuery(filter);
            if (orderBy != null)
            {
                String mappedOrderBy = IMPLEMENTATION_FIELD_MAP.get(orderBy);
                orderBy = ((mappedOrderBy != null) ? mappedOrderBy : orderBy);
                if (ascending)
                {
                    query.addOrderByAscending(orderBy);
                }
                else
                {
                    query.addOrderByDescending(orderBy);
                }
            }

            // invoke query
            Collection<? extends IBean> beansExtentList = ocm.getObjects(query);
            if ((beansExtentList != null) && !beansExtentList.isEmpty())
            {
                return beansExtentList.toArray((T [])Array.newInstance(beansInterface, beansExtentList.size()));
            }
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
        }
        return (T [])Array.newInstance(beansInterface, 0);
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findByValues(java.lang.Class, java.util.Map)
     */
    public <T extends IBean> T[] findByValues(Class<T> beansInterface, Map<String, Object> values)
    {
        return findByValues(beansInterface, values, null, true);
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findWidgetByGuid(java.lang.String)
     */
    public IWidget findWidgetByGuid(String guid)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // get widget by GUID
        if (guid != null)
        {
            try
            {
                IWidget [] widget = findByValue(IWidget.class, "guid", guid);
                if (widget.length == 1)
                {
                    return widget[0];
                }
            }
            catch (Exception e)
            {
                logger.error("Unexpected exception: "+e, e);
            }
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findWidgetInstanceByGuid(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
     */
    public IWidgetInstance findWidgetInstanceByGuid(String apiKey, String userId, String sharedDataKey, String widgetGuid)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // get widget instance
        if ((apiKey != null) && (userId != null) && (sharedDataKey != null) && (widgetGuid != null))
        {
            try
            {
                // find widget by GUID
                IWidget widget = findWidgetByGuid(widgetGuid);
                if (widget != null)
                {
                    // get matching widget instance for widget
                    Map<String, Object> values = new HashMap<String, Object>();
                    values.put("apiKey", apiKey);
                    values.put("userId", userId);
                    values.put("sharedDataKey", sharedDataKey);
                    values.put("widget", widget);
                    IWidgetInstance [] widgetInstance = findByValues(IWidgetInstance.class, values);
                    if (widgetInstance.length == 1)
                    {
                        return widgetInstance[0];
                    }               
                }
            }
            catch (Exception e)
            {
                logger.error("Unexpected exception: "+e, e);
            }
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#findWidgetInstanceByIdKey(java.lang.String)
     */
    public IWidgetInstance findWidgetInstanceByIdKey(String idKey)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // get widget instance
        if (idKey != null)
        {
            try
            {
                IWidgetInstance [] widgetInstance = findByValue(IWidgetInstance.class, "idKey", idKey);
                if (widgetInstance.length == 1)
                {
                    return widgetInstance[0];
                }
            }
            catch (Exception e)
            {
                logger.error("Unexpected exception: "+e, e);
            }
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#newInstance(java.lang.Class)
     */
    @SuppressWarnings("unchecked")
    public <T> T newInstance(Class<T> instanceInterface)
    {
        // validate instance interface
        Class<?> instanceClass = INTERFACE_TO_CLASS_MAP.get(instanceInterface);
        if (instanceClass == null)
        {
            throw new IllegalArgumentException("Invalid instance interface specified");           
        }

        // create new instance of persistent class
        try
        {
            return (T)instanceClass.newInstance();
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
            return null;
        }
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#rollback()
     */
    public void rollback()
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }       

        // rollback object content manager session transaction
        try
        {
            if (ocmWrite)
            {
                // logout and close object content manager: do not return to pool
                ocmCache.reset();
                ocm.logout();
            }
            // borrow session object content manager from pool
            ocm = (SessionObjectContentManagerImpl)ocmPool.borrowObject();
            ocmCache = new SessionObjectCacheImpl();
            ocm.setRequestObjectCache(ocmCache);
            ocmWrite = false;
        }
        catch (Exception e)
        {
            throw new RuntimeException("Unexpected exception: "+e, e);
        }
    }

    /* (non-Javadoc)
     * @see org.apache.wookie.beans.util.IPersistenceManager#save(org.apache.wookie.beans.IBean)
     */
    public boolean save(IBean bean)
    {
        // validate object content manager transaction
        if (ocm == null)
        {
            throw new IllegalStateException("Transaction not initiated or already closed");
        }

        // track object content manager write
        ocmWrite = true;
       
        // persist new or update existing bean
        boolean newNode = false;
        IPathBean pathBean = (IPathBean)bean;
        String nodePath = pathBean.getNodePath();
        if (nodePath == null)
        {
            nodePath = pathBean.setNodePath(beanClassNodeRootPaths.get(pathBean.getClass()));
            newNode = true;
        }
        try
        {
            // notify pre-save listener
            if (bean instanceof IPersistenceListener)
            {
                if (!((IPersistenceListener)bean).preSave(this))
                {
                    throw new RuntimeException("Pre-save listener invocation failed");
                }
            }
           
            // save node
            if (newNode)
            {
                // construct parent nodes if necessary
                constructParentNodes(nodePath);
                // insert new node
                ocm.insert(pathBean);
            }
            else
            {
                // update existing node
                ocm.update(pathBean);
            }
            ocmCache.cache(pathBean.getNodePath(), pathBean);

            // notify post-save listener
            if (bean instanceof IPersistenceListener)
            {
                if (!((IPersistenceListener)bean).postSave(this))
                {
                    throw new RuntimeException("Post-save listener invocation failed");                   
                }
            }
            return true;
        }
        catch (Exception e)
        {
            logger.error("Unexpected exception: "+e, e);
            return false;
        }
    }
   
    /**
     * Create parent node hierarchy if necessary.
     *
     * @param nodePath node path
     */
    private Node constructParentNodes(String nodePath) throws RepositoryException
    {
        // recursively create parent nodes
        Session session = ocm.getSession();
        int parentNodePathEndIndex = nodePath.lastIndexOf('/');
        if (parentNodePathEndIndex > 0)
        {
            String parentNodePath = nodePath.substring(0, parentNodePathEndIndex);
            if (!parentNodePath.equals(rootPath))
            {
                // Jackrabbit/JCR 2.X
                //boolean parentNodeExists = session.nodeExists(parentNodePath);
               
                // Jackrabbit/JCR 1.X
                boolean parentNodeExists = session.itemExists(parentNodePath);

                if (!parentNodeExists)
                {
                    // create parent parent nodes
                    Node parentNode = constructParentNodes(parentNodePath);
                    // create parent node
                    String nodeName = parentNodePath.substring(parentNodePath.lastIndexOf('/')+1);
                    return parentNode.addNode(nodeName, "nt:unstructured");
                }
            }

            // Jackrabbit/JCR 2.X
            //return session.getNode(parentNodePath);

            // Jackrabbit/JCR 1.X
            return (Node)session.getItem(parentNodePath);
        }
        return session.getRootNode();
    }
   
    /**
     * Escape invalid JCR characters in name.
     *
     * @param name original name
     * @return escaped or original name
     */
    public static String escapeJCRName(String name)
    {
        StringBuilder escapedName = null;
        if (name != null)
        {
            for (int i = 0, limit = name.length(); (i < limit); i++)
            {
                char nameChar = name.charAt(i);
                switch (nameChar)
                {
                    case '%' :
                    case '/' :
                    case ':' :
                    case '[' :
                    case ']' :
                    case '|' :
                    case '*' :
                        if (escapedName == null)
                        {
                            escapedName = new StringBuilder(name.substring(0, i));
                        }
                        escapedName.append('%');
                        escapedName.append(Character.toUpperCase(Character.forDigit(nameChar/16, 16)));
                        escapedName.append(Character.toUpperCase(Character.forDigit(nameChar%16, 16)));
                        break;
                    default :
                        if (escapedName != null)
                        {
                            escapedName.append(nameChar);
                        }
                        break;
                }
            }
        }
        return ((escapedName != null) ? escapedName.toString() : name);
    }

    /**
     * Unescape invalid JCR characters in name.
     *
     * @param escapedName escaped name
     * @return original name
     */
    public static String unescapeJCRName(String escapedName)
    {
        StringBuilder unescapedName = null;
        if (escapedName != null)
        {
            for (int i = 0, limit = escapedName.length(); (i < limit); i++)
            {
                char escapedNameChar = escapedName.charAt(i);
                if (escapedNameChar == '%')
                {
                    if (unescapedName == null)
                    {
                        unescapedName = new StringBuilder(escapedName.substring(0, i));
                    }
                    int high = Character.digit(escapedName.charAt(++i), 16);
                    int low = Character.digit(escapedName.charAt(++i), 16);
                    unescapedName.append((char)(high*16+low));
                }
                else if (unescapedName != null)
                {
                    unescapedName.append(escapedNameChar);
                }
            }
        }
        return ((unescapedName != null) ? unescapedName.toString() : escapedName);       
    }

    /**
     * Extended OCM that supports setting of object cache after construction.
     */
    private static class SessionObjectContentManagerImpl extends ObjectContentManagerImpl
    {
        /**
         * Base OCM constructor with session and mapper.
         *
         * @param session session for OCM to manage
         * @param mapper object mapper component
         */
        public SessionObjectContentManagerImpl(Session session, Mapper mapper)
        {
            super(session, mapper);
        }
       
        /* (non-Javadoc)
         * @see org.apache.jackrabbit.ocm.manager.impl.ObjectContentManagerImpl#setRequestObjectCache(org.apache.jackrabbit.ocm.manager.cache.ObjectCache)
         */
        public void setRequestObjectCache(ObjectCache requestObjectCache)
        {
            super.setObjectConverter(new ObjectConverterImpl(mapper, new DefaultAtomicTypeConverterProvider(), new ProxyManagerImpl(), requestObjectCache));
            super.setRequestObjectCache(requestObjectCache);
        }
    }
   
    /**
     * Customized OCM object cache that is not cleared between requests.
     */
    private static class SessionObjectCacheImpl implements ObjectCache
    {
        private Map<String,Object> cache = new HashMap<String,Object>();
       
        /* (non-Javadoc)
         * @see org.apache.jackrabbit.ocm.manager.cache.ObjectCache#cache(java.lang.String, java.lang.Object)
         */
        public void cache(String path, Object object)
        {
            // add to cache
            cache.put(path, object);
        }

        /* (non-Javadoc)
         * @see org.apache.jackrabbit.ocm.manager.cache.ObjectCache#clear()
         */
        public void clear()
        {
            // do not clear cache on OCM request
        }

        /* (non-Javadoc)
         * @see org.apache.jackrabbit.ocm.manager.cache.ObjectCache#getObject(java.lang.String)
         */
        public Object getObject(String path)
        {
            // retrieve from cache
            return cache.get(path);
        }

        /* (non-Javadoc)
         * @see org.apache.jackrabbit.ocm.manager.cache.ObjectCache#isCached(java.lang.String)
         */
        public boolean isCached(String path)
        {
            // cache check
            return cache.containsKey(path);
        }

        /**
         * Clear cache on reset.
         */
        public void reset()
        {
            // clear cache
            cache.clear();
        }

        /**
         * Remove object from cache.
         *
         * @param path object path
         * @return removed object
         */
        public Object removeObject(String path)
        {
            // remove from cache
            return cache.remove(path);
        }
    }
   
    public IOAuthToken findOAuthToken(IWidgetInstance widgetInstance) {
       // TODO Auto-generated method stub
       return null;
    }
}
TOP

Related Classes of org.apache.wookie.beans.jcr.JCRPersistenceManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.