001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package nextapp.echo2.app;
031:
032: import java.io.IOException;
033: import java.io.InputStream;
034: import java.io.OutputStream;
035: import java.util.Collections;
036: import java.util.HashMap;
037: import java.util.Map;
038:
039: /**
040: * A representation of an image that will be retrieved as a resource from
041: * the CLASSPATH.
042: */
043: public class ResourceImageReference extends StreamImageReference {
044:
045: /**
046: * Size of buffer used for reading image data from CLASSPATH and writing
047: * it to <code>OutputStream</code>s.
048: */
049: private static final int BUFFER_SIZE = 4096;
050:
051: /**
052: * Mapping of extensions to content types.
053: */
054: private static final Map extensionToContentType;
055: static {
056: Map map = new HashMap();
057: map.put("gif", "image/gif");
058: map.put("png", "image/png");
059: map.put("jpeg", "image/jpeg");
060: map.put("jpg", "image/jpg");
061: map.put("bmp", "image/bmp");
062: extensionToContentType = Collections.unmodifiableMap(map);
063: }
064:
065: /**
066: * Automatically determines the content type based on the name of a
067: * resource.
068: *
069: * @param resourceName the resource name
070: * @return the discovered content type
071: * @throws IllegalArgumentException if no content type can be determined
072: */
073: private static final String getContentType(String resourceName) {
074: String contentType;
075:
076: // Determine content type.
077: int extensionDelimiterPosition = resourceName.lastIndexOf(".");
078: if (extensionDelimiterPosition == -1) {
079: throw new IllegalArgumentException(
080: "Invalid file extension (resource has no extension: "
081: + resourceName + ")");
082: } else {
083: String extension = resourceName.substring(
084: extensionDelimiterPosition + 1).toLowerCase();
085: contentType = (String) extensionToContentType
086: .get(extension);
087: if (contentType == null) {
088: throw new IllegalArgumentException(
089: "Invalid file extension (no matching content type: "
090: + resourceName + ")");
091: }
092: }
093:
094: return contentType;
095: }
096:
097: private Extent width, height;
098: private String contentType;
099: private String resource;
100: private String id;
101:
102: /**
103: * Creates a <code>ResourceImageReference</code>.
104: * The content type will be automatically determined.
105: *
106: * @param resource the resource name containing the binary image data
107: */
108: public ResourceImageReference(String resource) {
109: this (resource, null, null, null);
110: }
111:
112: /**
113: * Creates a <code>ResourceImageReference</code>.
114: *
115: * @param resource the resource name containing the binary image data
116: * (all resource names will be treated as absolute, it is
117: * unnecessary to prepend a leading slash to the resource name)
118: * @param contentType the content type of the image (or null to
119: * automatically determine the content type based on the resource
120: * extension)
121: */
122: public ResourceImageReference(String resource, String contentType) {
123: this (resource, contentType, null, null);
124: }
125:
126: /**
127: * Creates a <code>ResourceImageReference</code>.
128: * The content type will be automatically determined.
129: *
130: * @param resource the resource name containing the binary image data
131: * (all resource names will be treated as absolute, it is
132: * unnecessary to prepend a leading slash to the resource name)
133: * @param width the width of the image
134: * @param height the height of the image
135: */
136: public ResourceImageReference(String resource, Extent width,
137: Extent height) {
138: this (resource, null, width, height);
139: }
140:
141: /**
142: * Creates a <code>ResourceImageReference</code>.
143: *
144: * @param resource the resource name containing the binary image data
145: * (all resource names will be treated as absolute, it is
146: * unnecessary to prepend a leading slash to the resource name)
147: * @param contentType the content type of the image (or null to
148: * automatically determine the content type based on the resource
149: * extension)
150: * @param width the width of the image
151: * @param height the height of the image
152: */
153: public ResourceImageReference(String resource, String contentType,
154: Extent width, Extent height) {
155: super ();
156:
157: // Drop leading slash as all resource paths are absolute.
158: if (resource.charAt(0) == '/') {
159: this .resource = resource.substring(1);
160: } else {
161: this .resource = resource;
162: }
163:
164: this .contentType = contentType == null ? getContentType(resource)
165: : contentType;
166: this .width = width;
167: this .height = height;
168: id = ApplicationInstance.generateSystemId();
169: }
170:
171: /**
172: * @see java.lang.Object#equals(java.lang.Object)
173: */
174: public boolean equals(Object o) {
175: if (!(o instanceof ResourceImageReference)) {
176: return false;
177: }
178: ResourceImageReference that = (ResourceImageReference) o;
179: if (!(this .resource == that.resource || (this .resource != null && this .resource
180: .equals(that.resource)))) {
181: return false;
182: }
183: if (!(this .contentType == that.contentType || (this .contentType != null && this .contentType
184: .equals(that.contentType)))) {
185: return false;
186: }
187: if (!(this .width == that.width || (this .width != null && this .width
188: .equals(that.width)))) {
189: return false;
190: }
191: if (!(this .height == that.height || (this .height != null && this .height
192: .equals(that.height)))) {
193: return false;
194: }
195: return true;
196: }
197:
198: /**
199: * @see nextapp.echo2.app.StreamImageReference#getContentType()
200: */
201: public String getContentType() {
202: return contentType;
203: }
204:
205: /**
206: * @see nextapp.echo2.app.ImageReference#getHeight()
207: */
208: public Extent getHeight() {
209: return height;
210: }
211:
212: /**
213: * @see nextapp.echo2.app.RenderIdSupport#getRenderId()
214: */
215: public String getRenderId() {
216: return id;
217: }
218:
219: /**
220: * Returns the name of the resource.
221: *
222: * @return the name of the resource
223: */
224: public String getResource() {
225: return resource;
226: }
227:
228: /**
229: * @see nextapp.echo2.app.ImageReference#getWidth()
230: */
231: public Extent getWidth() {
232: return width;
233: }
234:
235: /**
236: * @see java.lang.Object#hashCode()
237: */
238: public int hashCode() {
239: return resource == null ? 0 : resource.hashCode();
240: }
241:
242: /**
243: * @see nextapp.echo2.app.StreamImageReference#render(java.io.OutputStream)
244: */
245: public void render(OutputStream out) throws IOException {
246: InputStream in = null;
247: byte[] buffer = new byte[BUFFER_SIZE];
248: int bytesRead = 0;
249:
250: try {
251: in = Thread.currentThread().getContextClassLoader()
252: .getResourceAsStream(resource);
253: if (in == null) {
254: throw new IllegalArgumentException(
255: "Specified resource does not exist: "
256: + resource + ".");
257: }
258: do {
259: bytesRead = in.read(buffer);
260: if (bytesRead > 0) {
261: out.write(buffer, 0, bytesRead);
262: }
263: } while (bytesRead > 0);
264: } finally {
265: if (in != null) {
266: try {
267: in.close();
268: } catch (IOException ex) {
269: }
270: }
271: }
272: }
273: }
|