blob: b0bed00c4586a145cd8aab924429596c959ea030 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.caching.impl;
import java.io.Serializable;
import java.util.Iterator;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.caching.CachedResponse;
import org.apache.cocoon.caching.EventAware;
import org.apache.cocoon.caching.EventRegistry;
import org.apache.cocoon.caching.PipelineCacheKey;
import org.apache.cocoon.caching.validity.Event;
import org.apache.cocoon.caching.validity.EventValidity;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.AbstractAggregatedValidity;
/**
* This implementation holds all mappings between Events and PipelineCacheKeys
* in two MultiHashMap to facilitate efficient lookup by either as Key.
*
* @author Geoff Howard (ghoward@apache.org)
* @version $Id: EventAwareCacheImpl.java,v 1.9 2004/03/05 13:01:56 bdelacretaz Exp $
*/
public class EventAwareCacheImpl extends CacheImpl implements Initializable,
EventAware {
private ServiceManager m_manager;
private EventRegistry m_eventRegistry;
/**
* Clears the entire Cache, including all registered event-pipeline key
* mappings..
*/
public void clear() {
super.clear();
m_eventRegistry.clear();
}
/**
* When a new Pipeline key is stored, it needs to be have its
* <code>SourceValidity</code> objects examined. For every
* <code>EventValidity</code> found, its <code>Event</code> will be
* registered with this key in the <code>EventRegistry</code>.
*
* <code>AggregatedValidity</code> is handled recursively.
*/
public void store(Serializable key,
CachedResponse response)
throws ProcessingException {
SourceValidity[] validities = response.getValidityObjects();
for (int i=0; i< validities.length;i++) {
SourceValidity val = validities[i];
examineValidity(val, key);
}
super.store(key, response);
}
/* (non-Javadoc)
* @see org.apache.cocoon.caching.Cache#store(java.io.Serializable, org.apache.cocoon.caching.CachedResponse)
public void store(Serializable key, CachedResponse response)
throws ProcessingException {
// TODO Auto-generated method stub
super.store(key, response);
}*/
/**
* Look up the EventRegistry
*/
public void service(ServiceManager manager) throws ServiceException {
this.m_manager = manager;
super.service(manager);
this.m_eventRegistry = (EventRegistry)manager.lookup(EventRegistry.ROLE);
}
/**
* Un-register this key in the EventRegistry in addition to
* removing it from the Store
*/
public void remove(PipelineCacheKey key) {
super.remove(key);
m_eventRegistry.removeKey(key);
}
/**
* Receive notification about the occurrence of an Event.
* If this event has registered pipeline keys, remove them
* from the Store and unregister them
* @param e The Event to be processed.
*/
public void processEvent(Event e) {
if (e == null) return;
Serializable[] keys = m_eventRegistry.keysForEvent(e);
if (keys == null) return;
for (int i=0;i<keys.length; i++) {
if (keys[i] != null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Processing cache event, found Pipeline key: " + keys[i].toString());
}
/* every pck associated with this event needs to be
* removed -- regardless of event mapping. and every
* event mapped to those keys needs to be removed
* recursively.
*/
remove(keys[i]);
}
}
}
/**
* Get the EventRegistry ready, and make sure it does not contain
* orphaned Event/PipelineKey mappings.
*/
public void initialize() throws Exception {
if (!m_eventRegistry.wasRecoverySuccessful()) {
super.clear();
} else {
// Not sure if we want this overhead here, but where else?
veryifyEventCache();
}
}
/**
* Ensure that all PipelineCacheKeys registered to events still
* point to valid cache entries. Having an isTotallyEmpty() on
* Store might make this less necessary, as the most likely time
* to discover orphaned entries is at startup. This is because
* stray events could hang around indefinitely if the cache is
* removed abnormally or is not configured with persistence.
*/
public void veryifyEventCache() {
Serializable[] keys = m_eventRegistry.allKeys();
if (keys == null) return;
for (int i=0; i<keys.length; i++) {
if (!this.containsKey(keys[i])) {
m_eventRegistry.removeKey(keys[i]);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Cache key no longer valid: " +
keys[i]);
}
}
}
}
/**
* Release resources
*/
public void dispose() {
m_manager.release(m_eventRegistry);
super.dispose();
m_manager = null;
m_eventRegistry = null;
}
private void examineValidity(SourceValidity val, Serializable key) {
if (val instanceof AbstractAggregatedValidity) {
handleAggregatedValidity((AbstractAggregatedValidity)val, key);
} else if (val instanceof EventValidity) {
handleEventValidity((EventValidity)val, key);
}
}
private void handleAggregatedValidity(
AbstractAggregatedValidity val,
Serializable key) {
// AggregatedValidity must be investigated further.
Iterator it = val.getValidities().iterator();
while (it.hasNext()) {
SourceValidity thisVal = (SourceValidity)it.next();
// Allow recursion
examineValidity(thisVal, key);
}
}
private void handleEventValidity(EventValidity val, Serializable key) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Found EventValidity: " + val.toString());
}
m_eventRegistry.register(val.getEvent(),key);
}
}