blob: a11d3ba28405421bc6c394c08c7e086376c78dc9 [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.transformation.helpers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.avalon.framework.logger.Logger;
import org.apache.cocoon.caching.CachedResponse;
import org.apache.cocoon.components.sax.XMLByteStreamCompiler;
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceResolver;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.ExpiresValidity;
/**
* The preemptive loader is a singleton that runs in the background
* and loads content into the cache.
*
* @version $Id$
* @since 2.1
*/
public final class PreemptiveLoader {
private static final PreemptiveLoader instance = new PreemptiveLoader();
/** The list of proxies currently used for caching */
private Map cacheStorageProxyMap = new HashMap(20);
/** The list of URIs to load */
private List loadList = new ArrayList(50);
/** Is this thread still alive? */
boolean alive = false;
/**
* Return singleton.
* @return PreemptiveLoader
*/
static PreemptiveLoader getInstance() {
return instance;
}
/**
* Add a new task
* @param proxy The cache to store the content
* @param uri The absolute URI to load
* @param expires The expires information used for the cache
*/
public void add(IncludeCacheStorageProxy proxy, String uri, long expires) {
boolean addItem = true;
List uriList = (List)this.cacheStorageProxyMap.get(proxy);
if ( null == uriList ) {
uriList = new ArrayList(50);
this.cacheStorageProxyMap.put(proxy, uriList);
} else {
synchronized (uriList) {
// nothing to do: uri is alredy in list
if (uriList.contains(uri)) {
addItem = false;
}
}
}
if ( addItem ) {
uriList.add(uri);
this.loadList.add(new Object[] {proxy, uri, new Long(expires), uriList});
}
synchronized (this.cacheStorageProxyMap) {
this.cacheStorageProxyMap.notify();
}
}
/**
* Start the preemptive loading
* @param manager A component manager
* @param resolver A source resolver
* @param logger A logger
*/
public void process(SourceResolver resolver,
Logger logger) {
this.alive = true;
if (logger.isDebugEnabled()) {
logger.debug("PreemptiveLoader: Starting preemptive loading");
}
while (this.alive) {
while (this.loadList.size() > 0) {
Object[] object = (Object[])this.loadList.get(0);
final String uri = (String)object[1];
this.loadList.remove(0);
synchronized (object[3]) {
((List)object[3]).remove(uri);
}
Source source = null;
XMLByteStreamCompiler serializer = null;
try {
if (logger.isDebugEnabled()) {
logger.debug("PreemptiveLoader: Loading " + uri);
}
source = resolver.resolveURI(uri);
serializer = new XMLByteStreamCompiler();
SourceUtil.toSAX(source, serializer);
SourceValidity[] validities = new SourceValidity[1];
validities[0] = new ExpiresValidity(((Long)object[2]).longValue() * 1000); // milliseconds!
CachedResponse response = new CachedResponse(validities,
(byte[])serializer.getSAXFragment());
((IncludeCacheStorageProxy)object[0]).put(uri, response);
} catch (Exception ignore) {
// all exceptions are ignored!
} finally {
resolver.release( source );
}
if (logger.isDebugEnabled()) {
logger.debug("PreemptiveLoader: Finished loading " + uri);
}
}
synchronized (this.cacheStorageProxyMap) {
try {
this.cacheStorageProxyMap.wait();
} catch (InterruptedException e) {
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("PreemptiveLoader: Finished preemptive loading");
}
}
/**
* Stop the loading.
* The loader stops when all tasks from the queue are processed.
*/
synchronized public void stop() {
this.alive = false;
synchronized (this.cacheStorageProxyMap) {
this.cacheStorageProxyMap.notify();
}
}
}