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.transformation.helpers;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.apache.avalon.framework.logger.Logger;
025: import org.apache.avalon.framework.service.ServiceManager;
026: import org.apache.cocoon.caching.CachedResponse;
027: import org.apache.cocoon.components.sax.XMLSerializer;
028: import org.apache.cocoon.components.source.SourceUtil;
029: import org.apache.excalibur.source.Source;
030: import org.apache.excalibur.source.SourceResolver;
031: import org.apache.excalibur.source.SourceValidity;
032: import org.apache.excalibur.source.impl.validity.ExpiresValidity;
033:
034: /**
035: * The preemptive loader is a singleton that runs in the background
036: * and loads content into the cache.
037: *
038: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
039: * @version CVS $Id: PreemptiveLoader.java 433543 2006-08-22 06:22:54Z crossley $
040: * @since 2.1
041: */
042: public final class PreemptiveLoader {
043:
044: private static final PreemptiveLoader instance = new PreemptiveLoader();
045:
046: /** The list of proxies currently used for caching */
047: private Map cacheStorageProxyMap = new HashMap(20);
048: /** The list of URIs to load */
049: private List loadList = new ArrayList(50);
050: /** Is this thread still alive? */
051: boolean alive = false;
052:
053: /**
054: * Return singleton.
055: * @return PreemptiveLoader
056: */
057: static PreemptiveLoader getInstance() {
058: return instance;
059: }
060:
061: /**
062: * Add a new task
063: * @param proxy The cache to store the content
064: * @param uri The absolute URI to load
065: * @param expires The expires information used for the cache
066: */
067: public void add(IncludeCacheStorageProxy proxy, String uri,
068: long expires) {
069: boolean addItem = true;
070: List uriList = (List) this .cacheStorageProxyMap.get(proxy);
071: if (null == uriList) {
072: uriList = new ArrayList(50);
073: this .cacheStorageProxyMap.put(proxy, uriList);
074: } else {
075: synchronized (uriList) {
076: // nothing to do: uri is alredy in list
077: if (uriList.contains(uri)) {
078: addItem = false;
079: }
080: }
081: }
082: if (addItem) {
083: uriList.add(uri);
084: this .loadList.add(new Object[] { proxy, uri,
085: new Long(expires), uriList });
086: }
087:
088: synchronized (this .cacheStorageProxyMap) {
089: this .cacheStorageProxyMap.notify();
090: }
091: }
092:
093: /**
094: * Start the preemptive loading
095: * @param manager A component manager
096: * @param resolver A source resolver
097: * @param logger A logger
098: */
099: public void process(ServiceManager manager,
100: SourceResolver resolver, Logger logger) {
101: this .alive = true;
102: if (logger.isDebugEnabled()) {
103: logger
104: .debug("PreemptiveLoader: Starting preemptive loading");
105: }
106:
107: while (this .alive) {
108: while (this .loadList.size() > 0) {
109: Object[] object = (Object[]) this .loadList.get(0);
110: final String uri = (String) object[1];
111: this .loadList.remove(0);
112: synchronized (object[3]) {
113: ((List) object[3]).remove(uri);
114: }
115:
116: Source source = null;
117: XMLSerializer serializer = null;
118:
119: try {
120: if (logger.isDebugEnabled()) {
121: logger
122: .debug("PreemptiveLoader: Loading "
123: + uri);
124: }
125:
126: source = resolver.resolveURI(uri);
127: serializer = (XMLSerializer) manager
128: .lookup(XMLSerializer.ROLE);
129:
130: SourceUtil.toSAX(source, serializer);
131:
132: SourceValidity[] validities = new SourceValidity[1];
133: validities[0] = new ExpiresValidity(
134: ((Long) object[2]).longValue() * 1000); // milliseconds!
135: CachedResponse response = new CachedResponse(
136: validities, (byte[]) serializer
137: .getSAXFragment());
138: ((IncludeCacheStorageProxy) object[0]).put(uri,
139: response);
140:
141: } catch (Exception ignore) {
142: // all exceptions are ignored!
143: } finally {
144: resolver.release(source);
145: manager.release(serializer);
146: }
147: if (logger.isDebugEnabled()) {
148: logger.debug("PreemptiveLoader: Finished loading "
149: + uri);
150: }
151: }
152: synchronized (this .cacheStorageProxyMap) {
153: try {
154: this .cacheStorageProxyMap.wait();
155: } catch (InterruptedException e) {
156: }
157: }
158: }
159: if (logger.isDebugEnabled()) {
160: logger
161: .debug("PreemptiveLoader: Finished preemptive loading");
162: }
163: }
164:
165: /**
166: * Stop the loading.
167: * The loader stops when all tasks from the queue are processed.
168: */
169: synchronized public void stop() {
170: this .alive = false;
171: synchronized (this.cacheStorageProxyMap) {
172: this.cacheStorageProxyMap.notify();
173: }
174: }
175: }
|