Package org.apache.torque.manager

Source Code of org.apache.torque.manager.AbstractBaseManager

package org.apache.torque.manager;

/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* 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.
*/

import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;

import org.apache.commons.collections.FastArrayList;
import org.apache.jcs.JCS;
import org.apache.jcs.access.GroupCacheAccess;
import org.apache.jcs.access.exception.CacheException;

import org.apache.torque.Torque;
import org.apache.torque.TorqueException;
import org.apache.torque.om.ObjectKey;
import org.apache.torque.om.Persistent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* This class contains common functionality of a Manager for
* instantiating OM's.
*
* @author <a href="mailto:jmcnally@collab.net">John McNally</a>
* @version $Id: AbstractBaseManager.java,v 1.16.2.3 2004/08/26 14:28:41 henning Exp $
*/
public abstract class AbstractBaseManager
    implements Serializable
{
    /** the log */
    protected static Log log = LogFactory.getLog(AbstractBaseManager.class);

    /** used to cache the om objects. cache is set by the region property */
    protected transient GroupCacheAccess cache;

    /** method results cache */
    protected MethodResultCache mrCache;

    /** the class that the service will instantiate */
    private Class omClass;

    private String className;

    private String region;

    private boolean isNew = true;

    protected Map validFields;
    protected Map listenersMap = new HashMap();

    /**
     * Get the Class instance
     *
     * @return the om class
     */
    protected Class getOMClass()
    {
        return omClass;
    }

    /**
     * Set the Class that will be instantiated by this manager
     *
     * @param omClass the om class
     */
    protected void setOMClass(Class omClass)
    {
        this.omClass = omClass;
    }

    /**
     * Get a fresh instance of an om
     *
     * @return an instance of the om class
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    protected Persistent getOMInstance()
        throws InstantiationException, IllegalAccessException
    {
        return (Persistent) omClass.newInstance();
    }

    /**
     * Get the classname to instantiate for getInstance()
     * @return value of className.
     */
    public String getClassName()
    {
        return className;
    }

    /**
     * Set the classname to instantiate for getInstance()
     * @param v  Value to assign to className.
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    public void setClassName(String  v)
        throws TorqueException
    {
        this.className = v;

        try
        {
            setOMClass(Class.forName(getClassName()));
        }
        catch (ClassNotFoundException cnfe)
        {
            throw new TorqueException("Could not load " + getClassName());
        }
    }


    /**
     * Return an instance of an om based on the id
     *
     * @param id
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected Persistent getOMInstance(ObjectKey id)
        throws TorqueException
    {
        return getOMInstance(id, true);
    }

    /**
     * Return an instance of an om based on the id
     *
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected Persistent getOMInstance(ObjectKey key, boolean fromCache)
        throws TorqueException
    {
        Persistent om = null;
        if (fromCache)
        {
            om = cacheGet(key);
        }

        if (om == null)
        {
            om = retrieveStoredOM(key);
            if (fromCache)
            {
                putInstanceImpl(om);
            }
        }

        return om;
    }

    protected Persistent cacheGet(Serializable key)
    {
        Persistent om = null;
        if (cache != null)
        {
            synchronized (this)
            {
                om = (Persistent) cache.get(key);
            }
        }
        return om;
    }

    /**
     *
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected void clearImpl()
        throws TorqueException
    {
        if (cache != null)
        {
            try
            {
                cache.remove();
            }
            catch (CacheException ce)
            {
                throw new TorqueException(
                        "Could not clear cache due to internal JCS error.", ce);
            }
        }
    }

    /**
     *
     * @param key
     * @return
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected Persistent removeInstanceImpl(Serializable key)
        throws TorqueException
    {
        Persistent oldOm = null;
        if (cache != null)
        {
            try
            {
                synchronized (this)
                {
                    oldOm = (Persistent) cache.get(key);
                    cache.remove(key);
                }
            }
            catch (CacheException ce)
            {
                throw new TorqueException
                    ("Could not remove from cache due to internal JCS error",
                     ce);
            }
        }
        return oldOm;
    }

    /**
     *
     * @param om
     * @return
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected Persistent putInstanceImpl(Persistent om)
        throws TorqueException
    {
        ObjectKey key = om.getPrimaryKey();
        return putInstanceImpl(key, om);
    }

    /**
     *
     * @param key
     * @param om
     * @return
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected Persistent putInstanceImpl(Serializable key, Persistent om)
        throws TorqueException
    {
        if (getOMClass() != null && !getOMClass().isInstance(om))
        {
            throw new TorqueException(om + "; class=" + om.getClass().getName()
                + "; id=" + om.getPrimaryKey() + " cannot be cached with "
                + getOMClass().getName() + " objects");
        }

        Persistent oldOm = null;
        if (cache != null)
        {
            try
            {
                synchronized (this)
                {
                    oldOm = (Persistent) cache.get(key);
                    cache.put(key, om);
                }
            }
            catch (CacheException ce)
            {
                throw new TorqueException
                    ("Could not cache due to internal JCS error", ce);
            }
        }
        return oldOm;
    }

    /**
     *
     * @param id
     * @return
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected abstract Persistent retrieveStoredOM(ObjectKey id)
        throws TorqueException;

    /**
     * Gets a list of om's based on id's.
     *
     * @param ids a <code>ObjectKey[]</code> value
     * @return a <code>List</code> value
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected List getOMs(ObjectKey[] ids)
        throws TorqueException
    {
        return getOMs(Arrays.asList(ids));
    }

    /**
     * Gets a list of om's based on id's.
     *
     * @param ids a <code>List</code> of <code>ObjectKey</code>'s
     * @return a <code>List</code> value
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected List getOMs(List ids)
        throws TorqueException
    {
        return getOMs(ids, true);
    }

    /**
     * Gets a list of om's based on id's.
     *
     * @param ids a <code>List</code> of <code>ObjectKey</code>'s
     * @return a <code>List</code> value
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected List getOMs(List ids, boolean fromCache)
        throws TorqueException
    {
        List oms = null;
        if (ids != null && ids.size() > 0)
        {
            // start a new list where we will replace the id's with om's
            oms = new ArrayList(ids);
            List newIds = new ArrayList(ids.size());
            for (int i = 0; i < ids.size(); i++)
            {
                ObjectKey key = (ObjectKey) ids.get(i);
                Persistent om = null;
                if (fromCache)
                {
                    om = cacheGet(key);
                }
                if (om == null)
                {
                    newIds.add(key);
                }
                else
                {
                    oms.set(i, om);
                }
            }

            if (newIds.size() > 0)
            {
                List newOms = retrieveStoredOMs(newIds);
                for (int i = 0; i < oms.size(); i++)
                {
                    if (oms.get(i) instanceof ObjectKey)
                    {
                        for (int j = newOms.size() - 1; j >= 0; j--)
                        {
                            Persistent om = (Persistent) newOms.get(j);
                            if (om.getPrimaryKey().equals(oms.get(i)))
                            {
                                // replace the id with the om and add the om
                                // to the cache
                                oms.set(i, om);
                                newOms.remove(j);
                                if (fromCache)
                                {
                                    putInstanceImpl(om);
                                }
                                break;
                            }
                        }
                    }
                }
            }
        }
        return oms;
    }

    /**
     *
     * @param ids
     * @return
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    protected abstract List retrieveStoredOMs(List ids)
        throws TorqueException;

    /**
     * Get the value of region.
     *
     * @return value of region.
     */
    public String getRegion()
    {
        return region;
    }

    /**
     * Set the value of region.
     *
     * @param v  Value to assign to region.
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    public void setRegion(String v)
        throws TorqueException
    {
        this.region = v;
        try
        {
            if (Torque.getConfiguration().getBoolean(Torque.CACHE_KEY, false))
            {
                cache = JCS.getInstance(getRegion());
                mrCache = new MethodResultCache(cache);
            }
            else
            {
                mrCache = new NoOpMethodResultCache(cache);
            }
        }
        catch (Exception e)
        {
            throw new TorqueException("Cache could not be initialized", e);
        }
        if (cache == null)
        {
            log.info("Cache could not be initialized for region: " + v);
        }
    }

    /**
     * @return The cache instance.
     */
    public MethodResultCache getMethodResultCache()
    {
        if (isNew)
        {
            synchronized (this)
            {
                if (isNew)
                {
                    registerAsListener();
                    isNew = false;
                }
            }
        }
        return mrCache;
    }

    /**
     * NoOp version.  Managers should override this method to notify other
     * managers that they are interested in CacheEvents.
     */
    protected void registerAsListener()
    {
    }

    /**
     *
     * @param listener A new listener for cache events.
     */
    public void addCacheListenerImpl(CacheListener listener)
    {
        List keys = listener.getInterestedFields();
        Iterator i = keys.iterator();
        while (i.hasNext())
        {
            String key = (String) i.next();
            // Peer.column names are the fields
            if (validFields != null && validFields.containsKey(key))
            {
                List listeners = (List) listenersMap.get(key);
                if (listeners == null)
                {
                    listeners = createSubsetList(key);
                }

                boolean isNew = true;
                Iterator j = listeners.iterator();
                while (j.hasNext())
                {
                    Object listener2 =
                        ((WeakReference) j.next()).get();
                    if (listener2 == null)
                    {
                        // do a little cleanup while checking for dupes
                        // not thread-safe, not likely to be many nulls
                        // but should revisit
                        //j.remove();
                    }
                    else if (listener2 == listener)
                    {
                        isNew = false;
                        break;
                    }
                }
                if (isNew)
                {
                    listeners.add(new WeakReference(listener));
                }
            }
        }
    }

    /**
     *
     * @param key
     * @return A subset of the list identified by <code>key</code>.
     */
    private synchronized List createSubsetList(String key)
    {
        FastArrayList list = null;
        if (listenersMap.containsKey(key))
        {
            list = (FastArrayList) listenersMap.get(key);
        }
        else
        {
            list = new FastArrayList();
            list.setFast(true);
            listenersMap.put(key, list);
        }
        return list;
    }

    /**
     *
     * @param listeners
     * @param oldOm
     * @param om
     */
    protected void notifyListeners(List listeners,
                                   Persistent oldOm, Persistent om)
    {
        if (listeners != null)
        {
            synchronized (listeners)
            {
                Iterator i = listeners.iterator();
                while (i.hasNext())
                {
                    CacheListener listener = (CacheListener)
                        ((WeakReference) i.next()).get();
                    if (listener == null)
                    {
                        // remove reference as its object was cleared
                        i.remove();
                    }
                    else
                    {
                        if (oldOm == null)
                        {
                            // object was added
                            listener.addedObject(om);
                        }
                        else
                        {
                            // object was refreshed
                            listener.refreshedObject(om);
                        }
                    }
                }
            }
        }
    }


    /**
     * helper methods for the Serializable interface
     *
     * @param out
     * @throws IOException
     */
    private void writeObject(java.io.ObjectOutputStream out)
        throws IOException
    {
        out.defaultWriteObject();
    }

    /**
     * Helper methods for the <code>Serializable</code> interface.
     *
     * @param in The stream to read a <code>Serializable</code> from.
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(ObjectInputStream in)
        throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        // initialize the cache
        try
        {
            if (region != null)
            {
                setRegion(region);
            }
        }
        catch (Exception e)
        {
            log.error("Cache could not be initialized for region '"
                      + region + "' after deserialization");
        }
    }
}
TOP

Related Classes of org.apache.torque.manager.AbstractBaseManager

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.