package org.apache.ojb.broker.cache;

/* Copyright  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.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Properties;

import org.apache.commons.collections.LRUMap;
import org.apache.ojb.broker.Identity;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.cache.ObjectCache;
import org.apache.ojb.broker.util.configuration.Configurable;
import org.apache.ojb.broker.util.configuration.Configuration;
import org.apache.ojb.broker.util.configuration.ConfigurationException;
import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;

public class ObjectCacheSoftImpl implements ObjectCache, Configurable {

        /**
         * The static the cache map
         */
        private static SoftHashMap cache = null;

        /**
         * The size of the cache
         */
        private static int size  = 10000;

        /**
         * Constructor called by ojb
         * @param broker ignored parameter
         * @param properties ignored parameter
         */
        public ObjectCacheSoftImpl(PersistenceBroker broker, Properties properties)
{
                if (cache == null) {
                        OjbConfigurator.getInstance().configure(this);
                        cache = new SoftHashMap(size);
                }
        }

        /**
         * @see
org.apache.ojb.broker.util.configuration.Configurable#configure(org.apache.o
jb.broker.util.configuration.Configuration)
         */
        public void configure(Configuration configuration) throws
ConfigurationException {
                size = configuration.getInteger("ObjectCacheSoftImpl", size);
        }

        /**
         * @see
org.apache.ojb.broker.cache.ObjectCache#cache(org.apache.ojb.broker.Identity
, java.lang.Object)
         */
        public void cache(Identity oid, Object obj) {
                cache.put(oid, obj);
        }

        /**
         * @see
org.apache.ojb.broker.cache.ObjectCache#lookup(org.apache.ojb.broker.Identit
y)
         */
        public Object lookup(Identity oid) {
                return cache.get(oid);
        }

        /**
         * @see
org.apache.ojb.broker.cache.ObjectCache#remove(org.apache.ojb.broker.Identit
y)
         */
        public void remove(Identity oid) {
                cache.remove(oid);
        }

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

        /**
         * Kind of map using SoftReference to store values
         */
        public static final class SoftHashMap {
                /** The internal HashMap that will hold the SoftReference. */
                private HashMap hash;
                /** The FIFO list of hard references, order of last access. */
                private LRUMap hardCacheMap;
                /** Reference queue for cleared SoftReference objects. */
                private ReferenceQueue queue;

                /**
                 * Construct a new hash map with the specified size
                 * @param hardSize the maximum capacity of this map
                 */
                public SoftHashMap(final int hardSize) {
                        hash = new HashMap();
                        hardCacheMap = new LRUMap(hardSize);
                        queue = new ReferenceQueue();
                }

                /**
                 * Put the key, value pair into the HashMap using a SoftValue object
                 * @param key the key
                 * @param value the value
                 * @return the old value
                 */
                public Object put(Object key, Object value) {
                        //check null since hashtable doesn't support null key or null 
value
                        if (key == null || value == null) {
                                return null;
                        }
                        processQueue(); // throw out garbage collected values first
                        hardCacheMap.put(key, value);
                        return hash.put(key, new SoftValue(value, key, queue));
                }

                /**
                 * Retrieve the value associated to a given key
                 * @param key the key
                 * @return the value associated to this key
                 */
                public Object get(Object key) {
                        // Check null since Hashtable doesn't support null key or null 
value
                        if (key == null) {
                                return null;
                        }
                        Object result = null;
                        // We get the SoftReference represented by that key
                        SoftReference softRef = (SoftReference) hash.get(key);
                        if (softRef != null) {
                                result = softRef.get();
                                if (result == null) {
                                        // If the value has been garbage collected, 
remove the
                                        // entry from the HashMap.
                                        hash.remove(key);
                                } else {
                                        if (!hardCacheMap.containsKey(key)) {
                                                hardCacheMap.put(key, result);
                                        } else {
                                                hardCacheMap.get(key);
                                        }
                                }
                        }
                        return result;
                }

                /**
                 * Remove the entry for this key
                 * @param key the key
                 * @return the old value
                 */
                public Object remove(Object key) {
                        processQueue(); // throw out garbage collected values first
                        Object retval = null;
                        Object value = hash.remove(key);
                        if (value != null) {
                                if (value instanceof SoftValue) {
                                        retval = ((SoftValue) value).get();
                                }
                        }
                        return retval;
                }

                /**
                 * Clear the map
                 */
                public void clear() {
                        processQueue();
                        hash.clear();
                        hardCacheMap.clear();
                }

                /**
                 * Class derived from SoftReference, used to
                 * store the key of the map.
                 */
                private class SoftValue extends SoftReference {
                        /** the key */
                        private final Object key; // always make data member final
                        /**
                         * Create a SoftValue given the object, key and queue
                         * @param k the object
                         * @param key the key
                         * @param q the reference queue
                         */
                        private SoftValue(final Object k, final Object key, final 
ReferenceQueue
q) {
                                super(k, q);
                                this.key = key;
                        }
                }

                /**
                 * Removes keys and objects that have been garbaged
                 */
                private void processQueue() {
                        SoftValue sv;
                        while ((sv = (SoftValue) queue.poll()) != null) {
                                hash.remove(sv.key); // we can access private data!
                        }
                }

        }
}


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to