001: /*
002: * Copyright (c) 2003 The Visigoth Software Society. All rights
003: * reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * 2. Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowledgement:
019: * "This product includes software developed by the
020: * Visigoth Software Society (http://www.visigoths.org/)."
021: * Alternately, this acknowledgement may appear in the software itself,
022: * if and wherever such third-party acknowledgements normally appear.
023: *
024: * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
025: * project contributors may be used to endorse or promote products derived
026: * from this software without prior written permission. For written
027: * permission, please contact visigoths@visigoths.org.
028: *
029: * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030: * nor may "FreeMarker" or "Visigoth" appear in their names
031: * without prior written permission of the Visigoth Software Society.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of the Visigoth Software Society. For more
049: * information on the Visigoth Software Society, please see
050: * http://www.visigoths.org/
051: */
052:
053: package freemarker.cache;
054:
055: import java.io.IOException;
056: import java.io.Reader;
057: import java.util.Collections;
058: import java.util.HashMap;
059: import java.util.Map;
060:
061: /**
062: * A {@link TemplateLoader} that uses a set of other loaders to load the templates.
063: * On every request, loaders are queried in the order of their appearance in the
064: * array of loaders that this Loader owns. If a request for some template name
065: * was already satisfied in the past by one of the loaders, that Loader is queried
066: * first (a soft affinity).
067: * This class is <em>NOT</em> thread-safe. If it is accessed from multiple
068: * threads concurrently, proper synchronization must be provided by the callers.
069: * Note that {@link TemplateCache}, the natural user of this class provides the
070: * necessary synchronizations when it uses the class.
071: * @author Attila Szegedi, szegedia at freemail dot hu
072: * @version $Id: MultiTemplateLoader.java,v 1.12.2.2 2007/04/04 07:51:16 szegedia Exp $
073: */
074: public class MultiTemplateLoader implements StatefulTemplateLoader {
075: private final TemplateLoader[] loaders;
076: private final Map lastLoaderForName = Collections
077: .synchronizedMap(new HashMap());
078:
079: /**
080: * Creates a new multi template Loader that will use the specified loaders.
081: * @param loaders the loaders that are used to load templates.
082: */
083: public MultiTemplateLoader(TemplateLoader[] loaders) {
084: this .loaders = (TemplateLoader[]) loaders.clone();
085: }
086:
087: public Object findTemplateSource(String name) throws IOException {
088: // Use soft affinity - give the loader that last found this
089: // resource a chance to find it again first.
090: TemplateLoader lastLoader = (TemplateLoader) lastLoaderForName
091: .get(name);
092: if (lastLoader != null) {
093: Object source = lastLoader.findTemplateSource(name);
094: if (source != null) {
095: return new MultiSource(source, lastLoader);
096: }
097: }
098:
099: // If there is no affine loader, or it could not find the resource
100: // again, try all loaders in order of appearance. If any manages
101: // to find the resource, then associate it as the new affine loader
102: // for this resource.
103: for (int i = 0; i < loaders.length; ++i) {
104: TemplateLoader loader = loaders[i];
105: Object source = loader.findTemplateSource(name);
106: if (source != null) {
107: lastLoaderForName.put(name, loader);
108: return new MultiSource(source, loader);
109: }
110: }
111:
112: lastLoaderForName.remove(name);
113: // Resource not found
114: return null;
115: }
116:
117: public long getLastModified(Object templateSource) {
118: return ((MultiSource) templateSource).getLastModified();
119: }
120:
121: public Reader getReader(Object templateSource, String encoding)
122: throws IOException {
123: return ((MultiSource) templateSource).getReader(encoding);
124: }
125:
126: public void closeTemplateSource(Object templateSource)
127: throws IOException {
128: ((MultiSource) templateSource).close();
129: }
130:
131: public void resetState() {
132: lastLoaderForName.clear();
133: for (int i = 0; i < loaders.length; i++) {
134: TemplateLoader loader = loaders[i];
135: if (loader instanceof StatefulTemplateLoader) {
136: ((StatefulTemplateLoader) loader).resetState();
137: }
138: }
139: }
140:
141: /**
142: * Represents a template source bound to a specific template loader. It
143: * serves as the complete template source descriptor used by the
144: * MultiTemplateLoader class.
145: */
146: private static final class MultiSource {
147: private final Object source;
148: private final TemplateLoader loader;
149:
150: MultiSource(Object source, TemplateLoader loader) {
151: this .source = source;
152: this .loader = loader;
153: }
154:
155: long getLastModified() {
156: return loader.getLastModified(source);
157: }
158:
159: Reader getReader(String encoding) throws IOException {
160: return loader.getReader(source, encoding);
161: }
162:
163: void close() throws IOException {
164: loader.closeTemplateSource(source);
165: }
166:
167: public boolean equals(Object o) {
168: if (o instanceof MultiSource) {
169: MultiSource m = (MultiSource) o;
170: return m.loader.equals(loader)
171: && m.source.equals(source);
172: }
173: return false;
174: }
175:
176: public int hashCode() {
177: return loader.hashCode() + 31 * source.hashCode();
178: }
179:
180: public String toString() {
181: return source.toString();
182: }
183: }
184: }
|