001: package org.apache.ojb.broker.cache;
002:
003: /* Copyright 2004-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 java.util.HashMap;
019: import java.util.Iterator;
020: import java.util.Map;
021:
022: import org.apache.ojb.broker.Identity;
023: import org.apache.ojb.broker.util.logging.Logger;
024: import org.apache.ojb.broker.util.logging.LoggerFactory;
025:
026: /**
027: * A wrapper class for {@link ObjectCache} implementations used to materialize object graphs and
028: * push the fully materialized object to the real object cache.
029: * To avoid passing of partial materialized objects to cache this class act as a temporary storage
030: * for unmaterialized (new read or refreshed) objects.
031: *
032: * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
033: * @version $Id: MaterializationCache.java,v 1.1.2.6 2005/12/21 22:24:15 tomdz Exp $
034: */
035: public class MaterializationCache implements ObjectCacheInternal {
036: private static Logger log = LoggerFactory
037: .getLogger(MaterializationCache.class);
038:
039: private CacheDistributor cacheDistributor;
040: private HashMap objectBuffer;
041: private boolean enabledReadCache;
042: private int invokeCounter;
043:
044: MaterializationCache(CacheDistributor cache) {
045: this .cacheDistributor = cache;
046: this .objectBuffer = new HashMap();
047: enabledReadCache = false;
048: }
049:
050: /**
051: * Returns <em>true</em> if the materialisation cache is enabled, otherwise <em>false</em>.
052: */
053: public boolean isEnabledMaterialisationCache() {
054: return enabledReadCache;
055: }
056:
057: /**
058: * For internal use only! Helper method to guarantee that only full materialized objects
059: * will be pushed to the application cache regardless if an local PB transaction
060: * is running or not. When a complex object is materialized there will be
061: * nested calls to the same PB instance methods, e.g. materialization of a referenced
062: * object which itself have several references, ...
063: * <br/>
064: * This method and {@link #disableMaterializationCache()} are used to delimit nested calls
065: * and to detect the end of an object materialization and avoid endless loops on circular
066: * references.
067: * <br/>
068: * If an code block with 'enabledMaterializationCache' throws an exception, in catch-block
069: * method {@link #doLocalClear()} have to be called.
070: */
071: public void enableMaterializationCache() {
072: ++invokeCounter;
073: enabledReadCache = true;
074: }
075:
076: /**
077: * @see #enableMaterializationCache()
078: */
079: public void disableMaterializationCache() {
080: if (!enabledReadCache)
081: return;
082:
083: --invokeCounter;
084: /*
085: if materialization of the requested object was completed, the
086: counter represents '0' and we push the object
087: to the application cache
088: */
089: if (invokeCounter == 0) {
090: try {
091: if (log.isDebugEnabled()) {
092: log
093: .debug("Materialisation of object is finished, push "
094: + objectBuffer.size()
095: + "objects to cache");
096: }
097: pushObjects();
098: } finally {
099: doLocalClear();
100: }
101: }
102: }
103:
104: public void doInternalCache(Identity oid, Object obj, int type) {
105: // if OJB try to build an object graph put objects in local cache
106: // else use the application cache
107: if (enabledReadCache) {
108: doLocalCache(oid, obj, type);
109: } else {
110: cacheDistributor.doInternalCache(oid, obj, type);
111: }
112: }
113:
114: public void cache(Identity oid, Object obj) {
115: doInternalCache(oid, obj, TYPE_UNKNOWN);
116: }
117:
118: /**
119: * @see ObjectCacheInternal#cacheIfNew(org.apache.ojb.broker.Identity, Object)
120: */
121: public boolean cacheIfNew(Identity oid, Object obj) {
122: boolean result = cacheDistributor.cacheIfNew(oid, obj);
123: if (enabledReadCache) {
124: doLocalCache(oid, obj, TYPE_CACHED_READ);
125: }
126: return result;
127: }
128:
129: public Object lookup(Identity oid) {
130: Object result = null;
131: if (enabledReadCache) {
132: result = doLocalLookup(oid);
133: }
134: if (result == null) {
135: result = cacheDistributor.lookup(oid);
136: }
137: return result;
138: }
139:
140: public Object doLocalLookup(Identity oid) {
141: ObjectEntry entry = (ObjectEntry) objectBuffer.get(oid);
142: return entry != null ? entry.obj : null;
143: }
144:
145: public void remove(Identity oid) {
146: doLocalRemove(oid);
147: cacheDistributor.remove(oid);
148: }
149:
150: public void doLocalRemove(Identity oid) {
151: objectBuffer.remove(oid);
152: }
153:
154: /**
155: * Clears the internal used cache for object materialization.
156: */
157: public void doLocalClear() {
158: if (log.isDebugEnabled())
159: log.debug("Clear materialization cache");
160: invokeCounter = 0;
161: enabledReadCache = false;
162: objectBuffer.clear();
163: }
164:
165: public void clear() {
166: if (log.isDebugEnabled())
167: log.debug("Clear used caches");
168: doLocalClear();
169: cacheDistributor.clear();
170: }
171:
172: private void doLocalCache(Identity oid, Object obj, int type) {
173: objectBuffer.put(oid, new ObjectEntry(obj, type));
174: }
175:
176: private void pushObjects() {
177: Iterator it = objectBuffer.entrySet().iterator();
178: Map.Entry entry;
179: ObjectEntry oe;
180: while (it.hasNext()) {
181: entry = (Map.Entry) it.next();
182: oe = (ObjectEntry) entry.getValue();
183: /*
184: never push temporary object to a higher level cache
185: */
186: if (oe.type != TYPE_TEMP) {
187: if (log.isDebugEnabled())
188: log.debug("Push to cache: " + entry.getKey());
189: cacheDistributor.doInternalCache((Identity) entry
190: .getKey(), oe.obj, oe.type);
191: }
192: }
193: }
194:
195: //===========================================================
196: // inner class
197: //===========================================================
198:
199: static final class ObjectEntry {
200: Object obj;
201: int type;
202:
203: public ObjectEntry(Object obj, int type) {
204: this.obj = obj;
205: this.type = type;
206: }
207: }
208: }
|