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.Iterator;
021:
022: import org.apache.avalon.framework.activity.Initializable;
023: import org.apache.avalon.framework.service.ServiceException;
024: import org.apache.avalon.framework.service.ServiceManager;
025: import org.apache.cocoon.ProcessingException;
026: import org.apache.cocoon.caching.CachedResponse;
027: import org.apache.cocoon.caching.EventAware;
028: import org.apache.cocoon.caching.EventRegistry;
029: import org.apache.cocoon.caching.validity.Event;
030: import org.apache.cocoon.caching.validity.EventValidity;
031: import org.apache.cocoon.components.source.impl.SitemapSource;
032: import org.apache.excalibur.source.SourceValidity;
033: import org.apache.excalibur.source.impl.validity.AbstractAggregatedValidity;
034:
035: /**
036: * This implementation holds all mappings between Events and PipelineCacheKeys
037: * in two MultiHashMap to facilitate efficient lookup by either as Key.
038: *
039: * @author Geoff Howard (ghoward@apache.org)
040: * @version $Id: EventAwareCacheImpl.java 433543 2006-08-22 06:22:54Z crossley $
041: */
042: public class EventAwareCacheImpl extends CacheImpl implements
043: Initializable, EventAware {
044:
045: private ServiceManager m_manager;
046:
047: private EventRegistry m_eventRegistry;
048:
049: /**
050: * Clears the entire Cache, including all registered event-pipeline key
051: * mappings..
052: */
053: public void clear() {
054: super .clear();
055: m_eventRegistry.clear();
056: }
057:
058: /**
059: * When a new Pipeline key is stored, it needs to be have its
060: * <code>SourceValidity</code> objects examined. For every
061: * <code>EventValidity</code> found, its <code>Event</code> will be
062: * registered with this key in the <code>EventRegistry</code>.
063: *
064: * <code>AggregatedValidity</code> is handled recursively.
065: */
066: public void store(Serializable key, CachedResponse response)
067: throws ProcessingException {
068: SourceValidity[] validities = response.getValidityObjects();
069: for (int i = 0; i < validities.length; i++) {
070: SourceValidity val = validities[i];
071: examineValidity(val, key);
072: }
073: super .store(key, response);
074: }
075:
076: /* (non-Javadoc)
077: * @see org.apache.cocoon.caching.Cache#store(java.io.Serializable, org.apache.cocoon.caching.CachedResponse)
078:
079: public void store(Serializable key, CachedResponse response)
080: throws ProcessingException {
081: // TODO Auto-generated method stub
082: super.store(key, response);
083: }*/
084:
085: /**
086: * Look up the EventRegistry
087: */
088: public void service(ServiceManager manager) throws ServiceException {
089: this .m_manager = manager;
090: super .service(manager);
091: this .m_eventRegistry = (EventRegistry) manager
092: .lookup(EventRegistry.ROLE);
093: }
094:
095: /**
096: * Un-register this key in the EventRegistry in addition to
097: * removing it from the Store
098: */
099: public void remove(Serializable key) {
100: super .remove(key);
101: m_eventRegistry.removeKey(key);
102: }
103:
104: /**
105: * Receive notification about the occurrence of an Event.
106: * If this event has registered pipeline keys, remove them
107: * from the Store and unregister them
108: * @param e The Event to be processed.
109: */
110: public void processEvent(Event e) {
111: if (e == null)
112: return;
113: Serializable[] keys = m_eventRegistry.keysForEvent(e);
114: if (keys == null)
115: return;
116: for (int i = 0; i < keys.length; i++) {
117: if (keys[i] != null) {
118: if (getLogger().isDebugEnabled()) {
119: getLogger().debug(
120: "Processing cache event, found Pipeline key: "
121: + keys[i].toString());
122: }
123: /* every pck associated with this event needs to be
124: * removed -- regardless of event mapping. and every
125: * event mapped to those keys needs to be removed
126: * recursively.
127: */
128: remove(keys[i]);
129: }
130: }
131: }
132:
133: /**
134: * Get the EventRegistry ready, and make sure it does not contain
135: * orphaned Event/PipelineKey mappings.
136: */
137: public void initialize() throws Exception {
138: if (!m_eventRegistry.wasRecoverySuccessful()) {
139: super .clear();
140: } else {
141: // Not sure if we want this overhead here, but where else?
142: veryifyEventCache();
143: }
144: }
145:
146: /**
147: * Ensure that all PipelineCacheKeys registered to events still
148: * point to valid cache entries. Having an isTotallyEmpty() on
149: * Store might make this less necessary, as the most likely time
150: * to discover orphaned entries is at startup. This is because
151: * stray events could hang around indefinitely if the cache is
152: * removed abnormally or is not configured with persistence.
153: */
154: public void veryifyEventCache() {
155: Serializable[] keys = m_eventRegistry.allKeys();
156: if (keys == null)
157: return;
158: for (int i = 0; i < keys.length; i++) {
159: if (!this .containsKey(keys[i])) {
160: m_eventRegistry.removeKey(keys[i]);
161: if (getLogger().isDebugEnabled()) {
162: getLogger().debug(
163: "Cache key no longer valid: " + keys[i]);
164: }
165: }
166: }
167: }
168:
169: /**
170: * Release resources
171: */
172: public void dispose() {
173: m_manager.release(m_eventRegistry);
174: super .dispose();
175: m_manager = null;
176: m_eventRegistry = null;
177: }
178:
179: private void examineValidity(SourceValidity val, Serializable key) {
180: if (val instanceof AbstractAggregatedValidity) {
181: handleAggregatedValidity((AbstractAggregatedValidity) val,
182: key);
183: } else if (val instanceof EventValidity) {
184: handleEventValidity((EventValidity) val, key);
185: } else if (val instanceof SitemapSource.SitemapSourceValidity) {
186: examineValidity(((SitemapSource.SitemapSourceValidity) val)
187: .getNestedValidity(), key);
188: }
189: }
190:
191: private void handleAggregatedValidity(
192: AbstractAggregatedValidity val, Serializable key) {
193: // AggregatedValidity must be investigated further.
194: Iterator it = val.getValidities().iterator();
195: while (it.hasNext()) {
196: SourceValidity this Val = (SourceValidity) it.next();
197: // Allow recursion
198: examineValidity(this Val, key);
199: }
200: }
201:
202: private void handleEventValidity(EventValidity val, Serializable key) {
203: if (getLogger().isDebugEnabled()) {
204: getLogger().debug("Found EventValidity: " + val.toString());
205: }
206: m_eventRegistry.register(val.getEvent(), key);
207: }
208:
209: }
|