Java tutorial
/* * 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 javax.persistence.EntityManager; 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.IAccessRequest; import org.apache.wookie.beans.IApiKey; 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.IParam; import org.apache.wookie.beans.IParticipant; import org.apache.wookie.beans.IPreference; import org.apache.wookie.beans.IPreferenceDefault; import org.apache.wookie.beans.IServerFeature; import org.apache.wookie.beans.ISharedData; import org.apache.wookie.beans.IStartFile; import org.apache.wookie.beans.IStoreUser; import org.apache.wookie.beans.ITags; import org.apache.wookie.beans.IToken; import org.apache.wookie.beans.IWhitelist; import org.apache.wookie.beans.IWidget; import org.apache.wookie.beans.IWidgetDefault; import org.apache.wookie.beans.IWidgetIcon; import org.apache.wookie.beans.IWidgetInstance; import org.apache.wookie.beans.IWidgetService; import org.apache.wookie.beans.IWidgetType; import org.apache.wookie.beans.IPost; import org.apache.wookie.beans.jcr.impl.AccessRequestImpl; import org.apache.wookie.beans.jcr.impl.ApiKeyImpl; 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.ServerFeatureImpl; import org.apache.wookie.beans.jcr.impl.SharedDataImpl; import org.apache.wookie.beans.jcr.impl.StartFileImpl; import org.apache.wookie.beans.jcr.impl.TokenImpl; import org.apache.wookie.beans.jcr.impl.WhitelistImpl; import org.apache.wookie.beans.jcr.impl.WidgetDefaultImpl; 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.jcr.impl.WidgetServiceImpl; import org.apache.wookie.beans.jcr.impl.WidgetTypeImpl; import org.apache.wookie.beans.jcr.impl.PostImpl; 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(IAccessRequest.class, AccessRequestImpl.class); INTERFACE_TO_CLASS_MAP.put(IApiKey.class, ApiKeyImpl.class); 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(IServerFeature.class, ServerFeatureImpl.class); INTERFACE_TO_CLASS_MAP.put(ISharedData.class, SharedDataImpl.class); INTERFACE_TO_CLASS_MAP.put(IStartFile.class, StartFileImpl.class); INTERFACE_TO_CLASS_MAP.put(IToken.class, TokenImpl.class); INTERFACE_TO_CLASS_MAP.put(IWhitelist.class, WhitelistImpl.class); INTERFACE_TO_CLASS_MAP.put(IWidget.class, WidgetImpl.class); INTERFACE_TO_CLASS_MAP.put(IWidgetDefault.class, WidgetDefaultImpl.class); INTERFACE_TO_CLASS_MAP.put(IWidgetIcon.class, WidgetIconImpl.class); INTERFACE_TO_CLASS_MAP.put(IWidgetInstance.class, WidgetInstanceImpl.class); INTERFACE_TO_CLASS_MAP.put(IWidgetService.class, WidgetServiceImpl.class); INTERFACE_TO_CLASS_MAP.put(IWidgetType.class, WidgetTypeImpl.class); //IWC INTERFACE_TO_CLASS_MAP.put(IPost.class, PostImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IAccessRequest.class, AccessRequestImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IApiKey.class, ApiKeyImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IParticipant.class, ParticipantImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IServerFeature.class, ServerFeatureImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IWhitelist.class, WhitelistImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IWidget.class, WidgetImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IWidgetDefault.class, WidgetDefaultImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IWidgetInstance.class, WidgetInstanceImpl.class); BEAN_INTERFACE_TO_CLASS_MAP.put(IWidgetService.class, WidgetServiceImpl.class); //IWC BEAN_INTERFACE_TO_CLASS_MAP.put(IPost.class, PostImpl.class); IMPLEMENTATION_FIELD_MAP.put("widget", "widgetImpl"); } @SuppressWarnings("unchecked") 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 Map<Class<? extends IBean>, String> beanClassNodeRootPaths = new HashMap<Class<? extends IBean>, String>(); private static GenericObjectPool ocmPool; /** * 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#findApplicableAccessRequests(org.apache.wookie.beans.IWidget) */ public IAccessRequest[] findApplicableAccessRequests(IWidget widget) { // validate object content manager transaction if (ocm == null) { throw new IllegalStateException("Transaction not initiated or already closed"); } // get applicable access requests for widget using custom query if (widget != null) { try { Map<String, Object> values = new HashMap<String, Object>(); values.put("widget", widget); values.put("granted", Boolean.TRUE); return findByValues(IAccessRequest.class, values); } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } } return new IAccessRequest[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#findParticipants(org.apache.wookie.beans.IWidgetInstance) */ public IParticipant[] findParticipants(IWidgetInstance widgetInstance) { // validate object content manager transaction if (ocm == null) { throw new IllegalStateException("Transaction not initiated or already closed"); } // get participants for widget instance if (widgetInstance != null) { try { Map<String, Object> values = new HashMap<String, Object>(); values.put("sharedDataKey", widgetInstance.getSharedDataKey()); values.put("widget", widgetInstance.getWidget()); return findByValues(IParticipant.class, values); } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } } return new IParticipant[0]; } /* (non-Javadoc) * @see org.apache.wookie.beans.util.IPersistenceManager#findParticipantViewer(org.apache.wookie.beans.IWidgetInstance) */ public IParticipant findParticipantViewer(IWidgetInstance widgetInstance) { // validate object content manager transaction if (ocm == null) { throw new IllegalStateException("Transaction not initiated or already closed"); } // get participant viewer for widget instance if (widgetInstance != null) { try { Map<String, Object> values = new HashMap<String, Object>(); values.put("sharedDataKey", widgetInstance.getSharedDataKey()); values.put("widget", widgetInstance.getWidget()); values.put("participantId", widgetInstance.getUserId()); IParticipant[] participantViewer = findByValues(IParticipant.class, values); if (participantViewer.length == 1) { return participantViewer[0]; } } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } } return null; } /* (non-Javadoc) * @see org.apache.wookie.beans.util.IPersistenceManager#findServerFeatureByName(java.lang.String) */ public IServerFeature findServerFeatureByName(String name) { // validate object content manager transaction if (ocm == null) { throw new IllegalStateException("Transaction not initiated or already closed"); } // get server feature by name if (name != null) { try { IServerFeature[] serverFeature = findByValue(IServerFeature.class, "featureName", name); if (serverFeature.length == 1) { return serverFeature[0]; } } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } } return null; } /* (non-Javadoc) * @see org.apache.wookie.beans.util.IPersistenceManager#findServerFeatureNames() */ public String[] findServerFeatureNames() { // validate object content manager transaction if (ocm == null) { throw new IllegalStateException("Transaction not initiated or already closed"); } // get server feature names try { IServerFeature[] serverFeatures = findAll(IServerFeature.class); if (serverFeatures.length > 0) { String[] names = new String[serverFeatures.length]; for (int i = 0; (i < serverFeatures.length); i++) { names[i] = serverFeatures[i].getFeatureName(); } return names; } } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } return new String[0]; } /* (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#findWidgetDefaultByType(java.lang.String) */ public IWidget findWidgetDefaultByType(String widgetContext) { // validate object content manager transaction if (ocm == null) { throw new IllegalStateException("Transaction not initiated or already closed"); } // get default widget by type if (widgetContext != null) { try { IWidgetDefault[] widgetDefault = findByValue(IWidgetDefault.class, "widgetContext", widgetContext); if (widgetDefault.length == 1) { return widgetDefault[0].getWidget(); } } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } } return null; } /* (non-Javadoc) * @see org.apache.wookie.beans.util.IPersistenceManager#findWidgetInstance(java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ public IWidgetInstance findWidgetInstance(String apiKey, String userId, String sharedDataKey, String serviceContext) { // 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) && (serviceContext != null)) { try { // get candidate widget instances Map<String, Object> values = new HashMap<String, Object>(); values.put("apiKey", apiKey); values.put("userId", userId); values.put("sharedDataKey", sharedDataKey); IWidgetInstance[] widgetInstances = findByValues(IWidgetInstance.class, values); // filter widget instances by widget type/context IWidgetInstance foundWidgetInstance = null; for (IWidgetInstance widgetInstance : widgetInstances) { // check widget type/context boolean hasServiceContext = false; for (IWidgetType widgetType : widgetInstance.getWidget().getWidgetTypes()) { if (widgetType.getWidgetContext().equals(serviceContext)) { hasServiceContext = true; break; } } if (hasServiceContext) { // validate search matches only one widget if (foundWidgetInstance != null) { foundWidgetInstance = null; break; } foundWidgetInstance = widgetInstance; } } // return single matching widget instance if (foundWidgetInstance != null) { return foundWidgetInstance; } } 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; } public IWidget[] findWidgetsByType(String widgetContext) { // validate object content manager transaction if (ocm == null) { throw new IllegalStateException("Transaction not initiated or already closed"); } // get widgets by type if (widgetContext != null) { try { // get candidate widgets IWidget[] widgets = findAll(IWidget.class); // filter widgets by widget type/context Collection<IWidget> foundWidgets = new ArrayList<IWidget>(); for (IWidget widget : widgets) { // check widget type/context for (IWidgetType widgetType : widget.getWidgetTypes()) { if (widgetType.getWidgetContext().equals(widgetContext)) { foundWidgets.add(widget); break; } } } return foundWidgets.toArray(new IWidget[foundWidgets.size()]); } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } } return new IWidget[0]; } /* (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); } } @Override public List<ITags> findLike(String tagText) { return null; } public IStoreUser getStoreUser(String username) { return null; } public List<IDescription> findWidgetsLike(String keyword) { return null; } public EntityManager getEntityManager() { return null; } public <T> List<T> JPQLQuery(Class<T> bean, String queryString) { return null; } }