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.wicket.util.template;
018:
019: import java.io.IOException;
020: import java.io.Serializable;
021: import java.util.Map;
022:
023: import org.apache.wicket.Application;
024: import org.apache.wicket.MetaDataKey;
025: import org.apache.wicket.util.concurrent.ConcurrentHashMap;
026: import org.apache.wicket.util.io.Streams;
027: import org.apache.wicket.util.lang.Packages;
028: import org.apache.wicket.util.resource.IResourceStream;
029: import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
030: import org.apache.wicket.util.resource.locator.IResourceStreamLocator;
031: import org.apache.wicket.util.resource.locator.ResourceStreamLocator;
032: import org.apache.wicket.util.string.JavascriptStripper;
033: import org.apache.wicket.util.string.interpolator.MapVariableInterpolator;
034: import org.slf4j.Logger;
035: import org.slf4j.LoggerFactory;
036:
037: /**
038: * A string resource that can be appended to.
039: *
040: * @author Eelco Hillenius
041: */
042: // TODO cache templates application scoped with a watch
043: public class PackagedTextTemplate extends TextTemplate {
044: private static final class CachedTextTemplate implements
045: Serializable {
046: private static final long serialVersionUID = 1L;
047:
048: CachedTextTemplate(String text) {
049: }
050: }
051:
052: private static final class CachedTextTemplateKey implements
053: Serializable {
054: private static final long serialVersionUID = 1L;
055:
056: private final String className;
057:
058: CachedTextTemplateKey(Class clazz, String path) {
059: this .className = clazz.getName();
060: }
061:
062: }
063:
064: private static final class TextTemplateCache implements
065: Serializable {
066: private static final long serialVersionUID = 1L;
067:
068: private final Map cache = new ConcurrentHashMap();
069:
070: CachedTextTemplate get(CachedTextTemplateKey key) {
071: return (CachedTextTemplate) cache.get(key);
072: }
073:
074: void put(CachedTextTemplateKey key, CachedTextTemplate value) {
075: cache.put(key, value);
076: }
077: }
078:
079: /** log. */
080: private static final Logger log = LoggerFactory
081: .getLogger(PackagedTextTemplate.class);
082:
083: private static final long serialVersionUID = 1L;
084:
085: /** class loader stream locator. */
086: private static final IResourceStreamLocator streamLocator = new ResourceStreamLocator();
087:
088: private static final MetaDataKey TEXT_TEMPLATE_CACHE_KEY = new MetaDataKey(
089: TextTemplateCache.class) {
090: private static final long serialVersionUID = 1L;
091: };
092:
093: /** contents */
094: private final StringBuffer buffer = new StringBuffer();
095:
096: /**
097: * Constructor.
098: *
099: * @param clazz
100: * The class to be used for retrieving the classloader for
101: * loading the packaged template.
102: * @param fileName
103: * The name of the file, relative to the clazz position
104: */
105: public PackagedTextTemplate(final Class clazz, final String fileName) {
106: this (clazz, fileName, "text");
107: }
108:
109: /**
110: * Constructor.
111: *
112: * @param clazz
113: * The class to be used for retrieving the classloader for
114: * loading the packaged template.
115: * @param fileName
116: * the name of the file, relative to the clazz position
117: * @param contentType
118: * The mime type of this resource, such as "image/jpeg" or
119: * "text/html"
120: */
121: public PackagedTextTemplate(final Class clazz,
122: final String fileName, final String contentType) {
123: this (clazz, fileName, contentType, null);
124: }
125:
126: /**
127: * Constructor.
128: *
129: * @param clazz
130: * The class to be used for retrieving the classloader for
131: * loading the packaged template.
132: * @param fileName
133: * the name of the file, relative to the clazz position
134: * @param contentType
135: * The mime type of this resource, such as "image/jpeg" or
136: * "text/html"
137: * @param encoding
138: * The file's encoding, e.g. 'UTF-8'
139: */
140: public PackagedTextTemplate(final Class clazz,
141: final String fileName, final String contentType,
142: final String encoding) {
143: super (contentType);
144:
145: String path = Packages.absolutePath(clazz, fileName);
146:
147: Application app = Application.get();
148: TextTemplateCache cache = (TextTemplateCache) app
149: .getMetaData(TEXT_TEMPLATE_CACHE_KEY);
150: // TODO implement cache
151:
152: IResourceStream stream = streamLocator.locate(clazz, path);
153:
154: if (stream == null) {
155: throw new IllegalArgumentException("resource " + fileName
156: + " not found for scope " + clazz + " (path = "
157: + path + ")");
158: }
159:
160: try {
161: if (encoding != null) {
162: buffer.append(Streams.readString(stream
163: .getInputStream(), encoding));
164: } else {
165: buffer.append(Streams.readString(stream
166: .getInputStream()));
167: }
168: } catch (IOException e) {
169: throw new RuntimeException(e);
170: } catch (ResourceStreamNotFoundException e) {
171: throw new RuntimeException(e);
172: } finally {
173: try {
174: stream.close();
175: } catch (IOException e) {
176: log.error(e.getMessage(), e);
177: }
178: }
179: }
180:
181: /**
182: * @see org.apache.wicket.util.resource.AbstractStringResourceStream#getString()
183: */
184: public String getString() {
185: if (Application.get().getResourceSettings()
186: .getStripJavascriptCommentsAndWhitespace()) {
187: return JavascriptStripper.stripCommentsAndWhitespace(buffer
188: .toString());
189: } else {
190: // don't strip the comments
191: return buffer.toString();
192: }
193: }
194:
195: /**
196: * Interpolate the map of variables with the content and replace the content
197: * with the result. Variables are denoted in this string by the syntax
198: * ${variableName}. The contents will be altered by replacing each variable
199: * of the form ${variableName} with the value returned by
200: * variables.getValue("variableName").
201: * <p>
202: * WARNING there is no going back to the original contents after the
203: * interpolation is done. if you need to do different interpolations on the
204: * same original contents, use method {@link #asString(Map)} instead.
205: * </p>
206: *
207: * @param variables
208: * The variables to interpolate
209: * @return This for chaining
210: */
211: public final TextTemplate interpolate(Map variables) {
212: if (variables != null) {
213: String result = new MapVariableInterpolator(buffer
214: .toString(), variables).toString();
215: buffer.delete(0, buffer.length());
216: buffer.append(result);
217: }
218: return this ;
219: }
220:
221: /**
222: * @see org.apache.wicket.util.resource.IResourceStream#length()
223: */
224: public final long length() {
225: return buffer.length();
226: }
227: }
|