Package org.apache.cocoon.caching.impl

Source Code of org.apache.cocoon.caching.impl.EventAwareCacheImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 java.util.Timer;
import java.util.TimerTask;

import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.activity.Startable;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameters;
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.validity.Event;
import org.apache.cocoon.caching.validity.EventValidity;
import org.apache.cocoon.components.source.impl.SitemapSource;
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 MultiValueMaps to facilitate efficient lookup by either as Key.
*
* @version $Id: EventAwareCacheImpl.java 665950 2008-06-10 01:53:10Z joerg $
*/
public class EventAwareCacheImpl
    extends CacheImpl
    implements Initializable, Startable, EventAware {

    private ServiceManager m_manager;

    private EventRegistry m_eventRegistry;

    // clean-up thread
    private static final Timer timer = new Timer(true);
    private TimerTask timerTask;
    private long interval;

    public void parameterize(Parameters parameters) throws ParameterException {

        super.parameterize(parameters);
        this.interval = parameters.getParameterAsInteger("cleanupthreadinterval",1000*60*60); // 1 hour
        if(this.interval < 1) {
            throw new ParameterException("EventAwareCacheImpl cleanupthreadinterval parameter has to be greater then 1");
        }

        String eventRegistryName = parameters.getParameter("registry", EventRegistry.ROLE);
        try {
            this.m_eventRegistry = (EventRegistry)m_manager.lookup(eventRegistryName);
        } catch (ServiceException e) {
            throw new ParameterException("Unable to lookup registry: " + eventRegistryName, e);
        }
    }

    /**
     * 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 have it's
     * <code>SourceValidity</code> objects examined.  For every
     * <code>EventValidity</code> found, it's <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);
    }

    /**
     * Look up the EventRegistry
     */
    public void service(ServiceManager manager) throws ServiceException {
        this.m_manager = manager;
        super.service(manager);
    }

    /**
     * Un-register this key in the EventRegistry in addition to
     * removing it from the Store
     */
    public void remove(Serializable 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?
            verifyEventCache();
        }
    }

    /**
     * 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 verifyEventCache() {
        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);
        } else if (val instanceof SitemapSource.SitemapSourceValidity) {
            examineValidity(((SitemapSource.SitemapSourceValidity) val).getNestedValidity(), 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);
    }

    /**
     * starts cache-cleaner timer task scheduling
     */
    public void start() throws Exception {
        getLogger().debug("Intializing event-cache checker thread");
        timerTask = new TimerTask() { public void run() {verifyEventCache();}; };
        timer.schedule(timerTask, interval, interval);
    }

    /**
     * stops cache-cleaner timer task scheduling
     */
    public void stop() {
        timerTask.cancel();
    }
}
TOP

Related Classes of org.apache.cocoon.caching.impl.EventAwareCacheImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.