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 }