001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. 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: package org.apache.cocoon.caching.impl;
018:
019: import java.io.Serializable;
020: import java.util.Collection;
021: import java.util.Iterator;
022: import java.util.Set;
023:
024: import org.apache.avalon.framework.activity.Disposable;
025: import org.apache.avalon.framework.activity.Initializable;
026: import org.apache.avalon.framework.logger.AbstractLogEnabled;
027: import org.apache.avalon.framework.thread.ThreadSafe;
028: import org.apache.cocoon.caching.EventRegistry;
029: import org.apache.cocoon.caching.validity.Event;
030: import org.apache.commons.collections.MultiHashMap;
031:
032: /**
033: * This abstract base implementation of <code>EventRegistry</code> stores
034: * the event-key mappings in a simple pair of <code>MultiMap</code>s. It
035: * leaves all persistence to its concrete subclasses. To protect against
036: * future confusing inheritance trees, all internal implementation of the
037: * event-key mapping mechanism is hidden from its subclasses. If future
038: * EventRegistry implementations desire to use a different event-key mapping
039: * strategy but share persistence code, this package should probably be
040: * refactored to employ composition rather than inheritance. For now,
041: * simplicity favors inheritance.
042: *
043: * @since 2.1
044: * @author <a href="mailto:ghoward@apache.org">Geoff Howard</a>
045: * @version CVS $Id: AbstractDoubleMapEventRegistry.java 598490 2007-11-27 01:56:14Z joerg $
046: */
047:
048: public abstract class AbstractDoubleMapEventRegistry extends
049: AbstractLogEnabled implements Initializable, EventRegistry,
050: Disposable, ThreadSafe {
051:
052: private boolean m_init_success = false;
053: private MultiHashMap m_keyMMap;
054: private MultiHashMap m_eventMMap;
055:
056: /**
057: * Registers (stores) a two-way mapping between this Event and this
058: * PipelineCacheKey for later retrieval.
059: *
060: * @param e The event to
061: * @param key key
062: */
063: public void register(Event e, Serializable key) {
064: synchronized (this ) {
065: m_keyMMap.put(key, e);
066: m_eventMMap.put(e, key);
067: }
068: }
069:
070: /**
071: * Remove all registered data.
072: */
073: public void clear() {
074: synchronized (this ) {
075: m_keyMMap.clear();
076: m_eventMMap.clear();
077: }
078: }
079:
080: /**
081: * Retrieve all pipeline keys mapped to this event.
082: */
083: public Serializable[] keysForEvent(Event e) {
084: Collection coll = (Collection) m_eventMMap.get(e);
085: if (coll == null || coll.isEmpty()) {
086: if (getLogger().isDebugEnabled()) {
087: getLogger().debug("The event map returned empty");
088: }
089: return null;
090: } else {
091: return (Serializable[]) coll.toArray(new Serializable[coll
092: .size()]);
093: }
094: }
095:
096: /**
097: * Return all pipeline keys mapped to any event
098: */
099: public Serializable[] allKeys() {
100: Set keys = this .m_keyMMap.keySet();
101: return (Serializable[]) keys.toArray(new Serializable[keys
102: .size()]);
103: }
104:
105: /**
106: * When a CachedResponse is removed from the Cache, any entries
107: * in the event mapping must be cleaned up.
108: */
109: public void removeKey(Serializable key) {
110: Collection coll = (Collection) m_keyMMap.get(key);
111: if (coll == null || coll.isEmpty()) {
112: return;
113: }
114: // get the iterator over all matching PCK keyed
115: // entries in the key-indexed MMap.
116: synchronized (this ) {
117: Iterator it = coll.iterator();
118: while (it.hasNext()) {
119: /* remove all entries in the event-indexed map where this
120: * PCK key is the value.
121: */
122: Object o = it.next();
123: if (o != null) {
124: if (getLogger().isDebugEnabled()) {
125: getLogger().debug(
126: "Removing from event mapping: "
127: + o.toString());
128: }
129: m_eventMMap.remove(o, key);
130: }
131: }
132:
133: // remove all entries in the key-indexed map where this PCK key
134: // is the key -- confused yet?
135: m_keyMMap.remove(key);
136: }
137: }
138:
139: /**
140: * Recover state by de-serializing the data wrapper. If this fails
141: * a new empty mapping is initialized and the Cache is signalled of
142: * the failure so it can clean up.
143: */
144: public void initialize() throws Exception {
145: if (recover()) {
146: m_init_success = true;
147: }
148: }
149:
150: /**
151: * Delegate persistence to subclasses then clean up resources.
152: */
153: public void dispose() {
154: EventRegistryDataWrapper ecdw = wrapRegistry();
155: persist(ecdw);
156: m_keyMMap.clear();
157: m_keyMMap = null;
158: m_eventMMap.clear();
159: m_eventMMap = null;
160: }
161:
162: /**
163: * @return true if persistent state existed and was recovered successfully.
164: */
165: public boolean wasRecoverySuccessful() {
166: return m_init_success;
167: }
168:
169: protected EventRegistryDataWrapper wrapRegistry() {
170: EventRegistryDataWrapper ecdw = new EventRegistryDataWrapper();
171: ecdw.setupMaps(this .m_keyMMap, this .m_eventMMap);
172: return ecdw;
173: }
174:
175: protected void unwrapRegistry(EventRegistryDataWrapper ecdw) {
176: this .m_eventMMap = ecdw.get_eventMap();
177: this .m_keyMMap = ecdw.get_keyMap();
178: }
179:
180: protected final void createBlankCache() {
181: this .m_eventMMap = new MultiHashMap();
182: this .m_keyMMap = new MultiHashMap();
183: }
184:
185: /**
186: * An EventRegistry must recover its persisted data. Failed
187: * recovery must be signaled so that the Cache will know not to
188: * serve potentially stale content. Of course, at first start up
189: * failed recovery is a normal state.
190: *
191: * @return boolean to signal success or failure of recovery.
192: */
193: protected abstract boolean recover();
194:
195: /**
196: * An EventRegistry must persist its data.
197: */
198: protected abstract void persist(EventRegistryDataWrapper wrapper);
199:
200: }
|