Package org.apache.jetspeed.page.impl

Source Code of org.apache.jetspeed.page.impl.DatabasePageManagerCache

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.jetspeed.page.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.apache.jetspeed.cache.CacheElement;
import org.apache.jetspeed.cache.JetspeedCache;
import org.apache.jetspeed.cache.JetspeedCacheEventListener;
import org.apache.jetspeed.om.folder.Folder;
import org.apache.jetspeed.om.folder.impl.FolderImpl;
import org.apache.jetspeed.page.PageManager;
import org.apache.jetspeed.page.document.impl.NodeImpl;
import org.apache.ojb.broker.Identity;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.cache.ObjectCache;

/**
* DatabasePageManagerCache
*
* @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
* @version $Id: $
*/
public class DatabasePageManagerCache implements ObjectCache
{
    // Members
   
    private static JetspeedCache oidCache;
    private static JetspeedCache pathCache;
    private static boolean constraintsEnabled;
    private static boolean permissionsEnabled;
    private static PageManager pageManager;
    private static List updatePathsList = new ArrayList();
    private static ThreadLocal transactionedOperations = new ThreadLocal();

    // Implementation
   
    /**
     * cacheInit
     *
     * Initialize cache using page manager configuration.
     *
     * @param pageManager configured page manager
     */
    public synchronized static void cacheInit(final JetspeedCache oidCache, final JetspeedCache pathCache, final DatabasePageManager pageManager)
    {
        // initialize
        DatabasePageManagerCache.oidCache = oidCache;
        DatabasePageManagerCache.pathCache = pathCache;
        constraintsEnabled = pageManager.getConstraintsEnabled();
        permissionsEnabled = pageManager.getPermissionsEnabled();
       
        // setup local oid cache listener
        oidCache.addEventListener(new JetspeedCacheEventListener()
        {
            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementAdded(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementAdded(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
                final NodeImpl node = (NodeImpl)element;
                // infuse node with page manager configuration
                // or the page manager itself and add to the
                // paths cache
                node.setConstraintsEnabled(constraintsEnabled);
                node.setPermissionsEnabled(permissionsEnabled);
                if (node instanceof FolderImpl)
                {
                    ((FolderImpl)node).setPageManager(pageManager);
                }
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementChanged(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementChanged(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
                final NodeImpl node = (NodeImpl)element;
                // infuse node with page manager configuration
                // or the page manager itself and add to the
                // paths cache
                node.setConstraintsEnabled(constraintsEnabled);
                node.setPermissionsEnabled(permissionsEnabled);
                if (node instanceof FolderImpl)
                {
                    ((FolderImpl)node).setPageManager(pageManager);
                }
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementEvicted(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementEvicted(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
                final NodeImpl node = (NodeImpl)element;
                // reset internal FolderImpl caches
                if (node instanceof FolderImpl)
                {
                    ((FolderImpl)node).resetAll(false);
                }
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementExpired(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementExpired(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
                final NodeImpl node = (NodeImpl)element;
                // reset internal FolderImpl caches
                if (node instanceof FolderImpl)
                {
                    ((FolderImpl)node).resetAll(false);
                }
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementRemoved(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementRemoved(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
                final NodeImpl node = (NodeImpl)element;
                // reset internal FolderImpl caches
                if (node instanceof FolderImpl)
                {
                    ((FolderImpl)node).resetAll(false);
                }
            }
        }, true);
       
        // setup remote path cache listener
        pathCache.addEventListener(new JetspeedCacheEventListener()
        {
            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementAdded(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementAdded(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementChanged(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementChanged(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementEvicted(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementEvicted(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementExpired(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementExpired(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
            }

            /* (non-Javadoc)
             * @see org.apache.jetspeed.cache.JetspeedCacheEventListener#notifyElementRemoved(org.apache.jetspeed.cache.JetspeedCache, boolean, java.lang.Object, java.lang.Object)
             */
            public void notifyElementRemoved(final JetspeedCache cache, final boolean local, final Object key, final Object element)
            {
                final DatabasePageManagerCacheObject cacheObject = (DatabasePageManagerCacheObject)element;
                // remove cache object from local oid cache
                if (cacheObject != null)
                {
                    final Identity oid = cacheObject.getId();
                    final String path = cacheObject.getPath();
                    if ((oid != null) || (path != null))
                    {
                        synchronized (DatabasePageManagerCache.class)
                        {
                            if (oid != null)
                            {
                                // get object cached by oid
                                final NodeImpl node = (NodeImpl)cacheLookup(oid);
                                // reset internal FolderImpl caches
                                if (node instanceof FolderImpl)
                                {
                                    ((FolderImpl)node).resetAll(false);
                                }
                                // notify page manager of update
                                pageManager.notifyUpdatedNode(node);
                                // remove from cache
                                oidCache.removeQuiet(oid);
                            }
                            if (path != null)
                            {
                                // lookup parent object cached by path and oid
                                final int pathLastSeparatorIndex = path.lastIndexOf(Folder.PATH_SEPARATOR);
                                final String parentPath = ((pathLastSeparatorIndex > 0) ? path.substring(0, pathLastSeparatorIndex) : Folder.PATH_SEPARATOR);
                                final NodeImpl parentNode = cacheLookup(parentPath);
                                // reset internal FolderImpl caches in case element removed
                                if (parentNode instanceof FolderImpl)
                                {
                                    ((FolderImpl)parentNode).resetAll(false);
                                }
                                // ensure removed from cache
                                pathCache.removeQuiet(path);
                            }
                        }                       
                    }
                }
            }
        }, false);
    }

    /**
     * Override page manager specified during create with proxy.
     *
     * @param proxy proxied page manager interface used to
     *               inject into Folder instances to provide
     *               transaction/intercept
     */
    public synchronized static void setPageManagerProxy(PageManager proxy)
    {
        // set/reset page manager proxy and clear cache to
        // flush any objects referencing replaced page manager
        if (pageManager != proxy)
        {
            pageManager = proxy;
            cacheClear();
        }
    }

    /**
     * Lookup object instances by unique path.
     *
     * @param path node unique path
     * @return cached node
     */
    public synchronized static NodeImpl cacheLookup(final String path)
    {
        if (path != null)
        {
            // return valid object cached by path and oid
            final CacheElement pathElement = pathCache.get(path);
            if (pathElement != null)
            {
                final DatabasePageManagerCacheObject cacheObject = (DatabasePageManagerCacheObject)pathElement.getContent();
                return (NodeImpl)cacheLookup(cacheObject.getId());
            }
        }
        return null;
    }

    /**
     * Add path to list of updating paths; this list is used to
     * distinguish cache add operations that are probably the
     * result of writes vs. those that are associated with reads.
     *
     * @param path object path
     */
    public synchronized static void addUpdatePath(final String path)
    {
        // add path for later examination, (duplicates allowed)
        updatePathsList.add(path);
    }

    /**
     * Add object to cache and cache instances by unique path;
     * infuse nodes loaded by OJB with page manager configuration.
     *
     * @param oid object/node identity
     * @param obj object/node to cache
     */
    public synchronized static void cacheAdd(final Identity oid, final Object obj)
    {
        if (obj instanceof NodeImpl)
        {
            final NodeImpl node = (NodeImpl)obj;
            final String nodePath = node.getPath();

            // add node to caches; note that removes force notification
            // of update to distributed caches
            oidCache.remove(oid);
            final CacheElement element = oidCache.createElement(oid, node);
            oidCache.put(element);
            final boolean removed = pathCache.remove(nodePath);
            final CacheElement pathElement = pathCache.createElement(nodePath, new DatabasePageManagerCacheObject(oid, nodePath));
            pathCache.put(pathElement);
            // if a remove was not successful from the path cache, update
            // notification to distributed peers was not performed;
            // for updates of objects evicted from the cache or newly
            // created ones, this is problematic: remove and put into
            // path cache a second time to force
            if (!removed && updatePathsList.contains(nodePath))
            {
                pathCache.remove(nodePath);
                pathCache.put(pathElement);
            }
        }
    }

    /**
     * Remove path from list of updating paths.
     *
     * @param path object path
     */
    public synchronized static void removeUpdatePath(final String path)
    {
        // remove single path from list
        updatePathsList.remove(path);
    }

    /**
     * Clear object and path caches.
     */
    public synchronized static void cacheClear()
    {
        // remove all items from oid cache individually
        // to ensure notifications are run to detach
        // elements; do not invoke oidCache.clear()
        final Iterator removeOidIter = oidCache.getKeys().iterator();
        while (removeOidIter.hasNext())
        {
            oidCache.remove((Identity)removeOidIter.next());
        }
        // remove all items from path cache individually
        // to avoid potential distributed clear invocation
        // that would be performed against all peers; do
        // not invoke pathCache.clear()
        final Iterator removePathIter = pathCache.getKeys().iterator();
        while (removePathIter.hasNext())
        {
            pathCache.removeQuiet(removePathIter.next());
        }
    }

    /**
     * Lookup objects by identity.
     *
     * @param oid object identity
     * @return cached object
     */
    public synchronized static Object cacheLookup(final Identity oid)
    {
        if (oid != null)
        {
            // return valid object cached by oid
            final CacheElement element = oidCache.get(oid);
            if (element != null)
            {
                return element.getContent();
            }
        }
        return null;
    }

    /**
     * Remove identified object from object and path caches.
     *
     * @param oid object identity
     */
    public synchronized static void cacheRemove(final Identity oid)
    {
        // remove from cache by oid
        if (oid != null)
        {
            final NodeImpl node = (NodeImpl)cacheLookup(oid);
            if (node != null)
            {
                final String nodePath = node.getPath();
                // remove from caches; note that removes are
                // propagated to distributed caches
                oidCache.remove(oid);
                final boolean removed = pathCache.remove(nodePath);
                // if a remove was not successful from the path cache,
                // remove notification to distributed peers was not
                // performed; this is problematic: put into path cache
                // and remove a second time to force
                if (!removed)
                {
                    final CacheElement pathElement = pathCache.createElement(nodePath, new DatabasePageManagerCacheObject(oid, nodePath));
                    pathCache.put(pathElement);
                    pathCache.remove(nodePath);
                }
            }
        }
    }

    /**
     * Remove identified object from object and path caches.
     *
     * @param path object path
     */
    public synchronized static void cacheRemove(final String path)
    {
        // remove from cache by path
        if (path != null)
        {
            CacheElement pathElement = pathCache.get(path);
            if (pathElement != null)
            {
                final DatabasePageManagerCacheObject cacheObject = (DatabasePageManagerCacheObject)pathElement.getContent();
                // remove from caches; note that removes are
                // propagated to distributed caches
                oidCache.remove(cacheObject.getId());
                pathCache.remove(path);
            }
            else
            {
                // if an object is not found in the path cache, remove
                // notification to distributed peers will not be performed;
                // this is problematic: put into path cache and remove to
                // force
                pathElement = pathCache.createElement(path, new DatabasePageManagerCacheObject(path));
                pathCache.put(pathElement);
                pathCache.remove(path);               
            }
        }
    }
   
    /**
     * Reset cached security constraints in all cached objects.
     */
    public synchronized static void resetCachedSecurityConstraints()
    {
        // reset cached objects
        final Iterator resetIter = oidCache.getKeys().iterator();
        while (resetIter.hasNext())
        {
            final NodeImpl node = (NodeImpl)cacheLookup((Identity)resetIter.next());
            node.resetCachedSecurityConstraints();
        }
    }
   
    /**
     * Get transactions registered on current thread
     *
     * @return transactions list
     */
    public static List getTransactions()
    {
        List operations = (List)transactionedOperations.get();
        if (operations == null)
        {
            operations = new LinkedList();
            transactionedOperations.set(operations);
        }
        return operations;
    }

    /**
     * Register transactions with current thread
     *
     * @param operation transaction operation
     */
    public static void addTransaction(TransactionedOperation operation)
    {
        final List transactions = getTransactions();       
        transactions.add(operation);
    }
   
    /**
     * Rollback transactions registered with current thread.
     */
    public synchronized static void rollbackTransactions()
    {
        final Iterator transactions = getTransactions().iterator();
        while (transactions.hasNext())
        {
            final TransactionedOperation operation = (TransactionedOperation)transactions.next();
            cacheRemove(operation.getPath());
        }
    }

    /**
     * Clear transactions registered with current thread.
     */
    public static void clearTransactions()
    {
        transactionedOperations.remove();
    }

    /**
     * Returns whether this cache is currently part of a distributed cache cluster.
     *
     * @return distributed flag
     */
    public static boolean isDistributed()
    {
        return pathCache.isDistributed();
    }

    // OJB Constructor
   
    /**
     * Construct a cache instance using OJB compliant signatures.
     *
     * @param broker broker that is to own cache
     * @param props attribute properties passed to cache
     */
    public DatabasePageManagerCache(PersistenceBroker broker, Properties props)
    {
    }

    // OJB ObjectCache Implementation
   
    /* (non-Javadoc)
     * @see org.apache.ojb.broker.cache.ObjectCache#cache(org.apache.ojb.broker.Identity, java.lang.Object)
     */
    public void cache(Identity oid, Object obj)
    {
        cacheAdd(oid, obj);
    }

    /* (non-Javadoc)
     * @see org.apache.ojb.broker.cache.ObjectCache#clear()
     */
    public void clear()
    {
        cacheClear();
    }

    /* (non-Javadoc)
     * @see org.apache.ojb.broker.cache.ObjectCache#lookup(org.apache.ojb.broker.Identity)
     */
    public Object lookup(Identity oid)
    {
        return cacheLookup(oid);
    }

    /* (non-Javadoc)
     * @see org.apache.ojb.broker.cache.ObjectCache#remove(org.apache.ojb.broker.Identity)
     */
    public void remove(Identity oid)
    {
        cacheRemove(oid);
    }

    // Utilities
   
    /**
     * Dump cache paths and oids to standard out.
     */
    public synchronized static void dump()
    {
        System.out.println("--------------------------");       
        final Iterator dumpIter = oidCache.getKeys().iterator();
        while (dumpIter.hasNext())
        {
            final Identity oid = (Identity)dumpIter.next();
            final NodeImpl node = (NodeImpl)cacheLookup(oid);
            System.out.println("node="+node.getPath()+", oid="+oid);
        }
        System.out.println("--------------------------");
    }   
}
TOP

Related Classes of org.apache.jetspeed.page.impl.DatabasePageManagerCache

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.