001    package org.apache.ojb.broker.cache;
002    
003    /* Copyright 2003-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    import org.apache.commons.lang.builder.ToStringBuilder;
019    import org.apache.commons.lang.builder.ToStringStyle;
020    import org.apache.ojb.broker.Identity;
021    import org.apache.ojb.broker.PersistenceBroker;
022    
023    import java.lang.ref.SoftReference;
024    import java.util.HashMap;
025    import java.util.Map;
026    import java.util.Properties;
027    
028    /**
029     * Simple, flexible local {@link ObjectCache} implementation using a
030     * {@link java.util.HashMap} to cache given objects.
031     * <p>
032     * The cache uses soft-references which allows objects (softly) referenced by
033     * the cache to be reclaimed by the Java Garbage Collector when they are not
034     * longer referenced elsewhere.
035     * </p>
036     * <p>
037     * NOTE: Handle with care! If multiple PB instances are used (OJB standard behavior) you
038     * will run into synchronization problems.
039     * </p>
040     * <p>
041     * Implementation configuration properties:
042     * </p>
043     *
044     * <table cellspacing="2" cellpadding="2" border="3" frame="box">
045     * <tr>
046     *     <td><strong>Property Key</strong></td>
047     *     <td><strong>Property Values</strong></td>
048     * </tr>
049     * <tr>
050     *     <td>timeout</td>
051     *     <td>
052     *          Lifetime of the cached objects in seconds.
053     *          If expired the cached object was not returned
054     *          on lookup call (and removed from cache).
055     *    </td>
056     * </tr>
057     * </table>
058     *
059     * <br/>
060     *
061     * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
062     * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
063     * @version $Id: ObjectCacheLocalDefaultImpl.java,v 1.1 2007-08-24 22:17:29 ewestfal Exp $
064     */
065    public class ObjectCacheLocalDefaultImpl implements ObjectCache
066    {
067        private static final String TIMEOUT = "timeout";
068    
069        /**
070         * the hashtable holding all cached object
071         */
072        protected Map objectTable = new HashMap();
073    
074        /**
075         * Timeout of the cached objects.
076         */
077        private long timeout = 1000 * 60 * 15;
078    
079        /**
080         *
081         */
082        public ObjectCacheLocalDefaultImpl(PersistenceBroker broker, Properties prop)
083        {
084            timeout = prop == null ? timeout : ( Long.parseLong( prop.getProperty( TIMEOUT, "" + timeout ) ) )*1000;
085        }
086    
087        /**
088         * Clear ObjectCache. I.e. remove all entries for classes and objects.
089         */
090        public void clear()
091        {
092            objectTable.clear();
093        }
094    
095        /**
096         * Makes object persistent to the Objectcache.
097         * I'm using soft-references to allow gc reclaim unused objects
098         * even if they are still cached.
099         */
100        public void cache(Identity oid, Object obj)
101        {
102            if ((obj != null))
103            {
104                SoftReference ref = new SoftReference(new CacheEntry(obj));
105                objectTable.put(oid, ref);
106            }
107        }
108    
109        public boolean cacheIfNew(Identity oid, Object obj)
110        {
111            if(objectTable.get(oid) == null)
112            {
113                cache(oid, obj);
114                return true;
115            }
116            return false;
117        }
118    
119        /**
120         * Lookup object with Identity oid in objectTable.
121         * Returns null if no matching id is found
122         */
123        public Object lookup(Identity oid)
124        {
125            CacheEntry entry = null;
126            SoftReference ref = (SoftReference) objectTable.get(oid);
127            if (ref != null)
128            {
129                entry = (CacheEntry) ref.get();
130                if (entry == null || entry.lifetime < System.currentTimeMillis())
131                {
132                    objectTable.remove(oid);    // Soft-referenced Object reclaimed by GC
133                    // timeout, so set null
134                    entry = null;
135                }
136            }
137            return entry != null ? entry.object : null;
138        }
139    
140        /**
141         * Removes an Object from the cache.
142         */
143        public void remove(Identity oid)
144        {
145            if (oid != null)
146            {
147                objectTable.remove(oid);
148            }
149        }
150    
151        public String toString()
152        {
153            ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE);
154            buf.append("Count of cached objects", objectTable.keySet().size());
155            return buf.toString();
156        }
157    
158        //-----------------------------------------------------------
159        // inner class
160        //-----------------------------------------------------------
161        class CacheEntry
162        {
163            long lifetime;
164            Object object;
165    
166            public CacheEntry(Object object)
167            {
168                this.object = object;
169                lifetime = System.currentTimeMillis() + timeout;
170            }
171        }
172    
173    }