1 package org.jmage.resource;
2
3 import com.sun.media.jai.codec.ByteArraySeekableStream;
4 import org.apache.log4j.Logger;
5 import org.apache.log4j.Priority;
6 import org.jmage.ApplicationContext;
7 import org.jmage.mapper.InterceptorMapper;
8
9 import javax.media.jai.JAI;
10 import javax.media.jai.PlanarImage;
11 import javax.servlet.ServletContext;
12 import java.io.ByteArrayOutputStream;
13 import java.io.File;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.net.MalformedURLException;
17 import java.net.URI;
18 import java.net.URL;
19 import java.net.URLConnection;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Properties;
23
24 /***
25 * DefaultImageFactory loads images as resources from system environment.
26 */
27 public class DefaultImageFactory implements ResourceFactory {
28 protected static DefaultImageFactory defaultImageFactory;
29
30 private final static String PNG = "png";
31 private final static String GIF = "gif";
32 private final static String JPG = "jpg";
33 private final static String JPEG = "jpeg";
34 private final static String TIF = "tif";
35 private final static String TIFF = "tiff";
36 private final static String BMP = "bmp";
37
38 private final static String HTTP = "http";
39 private final static String FILE = "file";
40
41 protected static Logger log = Logger.getLogger(DefaultImageFactory.class.getName());
42 protected List imageTypes;
43 protected List schemeTypes;
44 protected ApplicationContext applicationContext;
45 protected ServletContext servletContext;
46
47 private static final String resourcedir = "resourcedir";
48 private static final String IMAGES = "images";
49 private static final String SERVLET_CONTEXT = "SERVLET_CONTEXT";
50 private static final String URI_HANDLINGERROR = "unable to handle URI resource, cause: ";
51 private static final String FILE_RESOURCE_RETRIEVED = " retrieved file resource: ";
52 private static final String URL_RESOURCE_RETRIEVED = " retrieved URL resource: ";
53 private static final String SCHEME_ERROR = "unable to retrieve resource, could not handle scheme: ";
54 private static final String FILELOAD = "fileload";
55 private static final String FILE_LOADED = " loaded image from file: ";
56 private static final String FILE_LOADERROR = "unable to load image from file: ";
57 private static final String STREAM = "stream";
58 private static final String SERVLET_LOADERROR = "unable to load image from servlet container: ";
59 private static final String SERVLET_LOADED = " loaded image from servlet container: ";
60 private static final String URL_LOADERROR = "unable to load image from URL: ";
61 private static final String URL_LOADED = " loaded image from url: ";
62 private static final String CAUSE = ", cause: ";
63 private static final String TRUE = "TRUE";
64 private static final String HTTP_HEADER_ERROR = "error while retrieving http status header from server";
65 private static final String HTTP_400 = "40";
66 private static final String SLASH = "/";
67 private static final char SUFFIX_SEPARATOR = '.';
68 private static final String REGEX_BACKSLASH = "////";
69 private static final String CLASSPATH_LOADERROR = "unable to retrieve resource from classpath, cause: ";
70
71 /***
72 * Create a DefaultimageFactory
73 */
74 public DefaultImageFactory() {
75 imageTypes = new ArrayList();
76 imageTypes.add(PNG);
77 imageTypes.add(GIF);
78 imageTypes.add(JPG);
79 imageTypes.add(JPEG);
80 imageTypes.add(TIF);
81 imageTypes.add(TIFF);
82 imageTypes.add(BMP);
83
84 schemeTypes = new ArrayList();
85 schemeTypes.add(HTTP);
86 schemeTypes.add(FILE);
87 }
88
89 /***
90 * Configures the ImageFactory with ApplicationContext
91 *
92 * @param context the ApplicationContext
93 */
94 public void configure(ApplicationContext context) {
95 this.applicationContext = context;
96 this.servletContext = (ServletContext) this.applicationContext.get(SERVLET_CONTEXT);
97 }
98
99 public void configureRequestProperties(Properties properties) {
100
101 }
102
103 public void removeRequestProperties(Properties properties) {
104
105 }
106
107 /***
108 * Tests whether the ImageFactory can handle a particular resource URI.
109 *
110 * @param resource
111 * @return true | false
112 */
113 public boolean canHandle(URI resource) {
114 try {
115 String suffix = resource.getPath().substring(resource.getPath().lastIndexOf(SUFFIX_SEPARATOR) + 1).toLowerCase();
116 String scheme = resource.getScheme();
117 return imageTypes.contains(suffix) && schemeTypes.contains(scheme);
118 } catch (Exception e) {
119 if (log.isInfoEnabled()) log.info(URI_HANDLINGERROR + e.getMessage());
120 return false;
121 }
122 }
123
124 /***
125 * Create an object resource from a resource URI
126 *
127 * @param resource the resource URI
128 * @return the object
129 * @throws ResourceException
130 */
131 public Object createFrom(URI resource) throws ResourceException {
132 String scheme = resource.getScheme().toLowerCase();
133 if (FILE.equals(scheme)) {
134 File file = new File(resource);
135 PlanarImage image = this.getFile(file);
136 if (log.isInfoEnabled()) log.info(FILE_RESOURCE_RETRIEVED + file.getName());
137 return image;
138 }
139 if (HTTP.equals(scheme)) {
140 URL url = null;
141 try {
142 url = resource.toURL();
143 } catch (MalformedURLException e) {
144 throw new ResourceException(e.getMessage());
145 }
146 PlanarImage image = this.getURL(url);
147 if (log.isInfoEnabled()) log.info(URL_RESOURCE_RETRIEVED + url.toString());
148 return image;
149 }
150 throw new ResourceException(SCHEME_ERROR + scheme);
151 }
152
153 /***
154 * Get the image resource from a file.
155 *
156 * @param file the file
157 * @return the image
158 * @throws ResourceException
159 */
160 protected PlanarImage getFile(File file) throws ResourceException {
161 PlanarImage image = null;
162
163
164 image = getAbsoluteFile(file);
165
166
167 image = image == null ? this.getServletContainerResource(file) : image;
168
169
170 image = image == null ? this.getJMAGEResourceDirFile(file) : image;
171
172
173 image = image == null ? this.getClassPathResource(file) : image;
174
175
176 image = image == null ? this.getCurrentDirFile(file) : image;
177
178
179 if (image == null) {
180 if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR + file);
181 throw new ResourceException(FILE_LOADERROR + file);
182 }
183 return image;
184 }
185
186 /***
187 * Get the file from the classpath as a system resource
188 *
189 * @param file
190 * @return true | false
191 * @throws ResourceException
192 */
193 protected PlanarImage getClassPathResource(File file) throws ResourceException {
194 PlanarImage image = null;
195 String imagePath = file.getPath();
196
197 if (imagePath.indexOf(File.separator) == 0) {
198 imagePath = imagePath.substring(1);
199 }
200 imagePath = imagePath.replaceAll(REGEX_BACKSLASH, SLASH);
201
202
203 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
204 URL imageURL = this.locateOnClassPath(imagePath, classLoader);
205 if(imageURL==null) {
206 classLoader = this.getClass().getClassLoader();
207 imageURL = this.locateOnClassPath(imagePath, classLoader);
208 }
209
210 if (imageURL != null) {
211 try {
212 image = JAI.create(STREAM, new ByteArraySeekableStream(this.streamConvert(classLoader.getResourceAsStream(imagePath)).toByteArray()));
213 } catch (IOException e) {
214 if (log.isEnabledFor(Priority.INFO)) log.info(CLASSPATH_LOADERROR + e.getMessage());
215 }
216 }
217 return image;
218 }
219
220 protected URL locateOnClassPath(String path, ClassLoader classLoader) {
221 URL uRL = classLoader.getResource(path);
222 if (uRL == null) {
223 uRL = classLoader.getResource(SLASH + path);
224 if (uRL != null) {
225 path = (SLASH + path);
226 }
227 }
228 if (uRL == null) {
229 uRL = classLoader.getResource(IMAGES + SLASH + path);
230 if (uRL != null) {
231 path = (IMAGES + SLASH + path);
232 }
233 }
234 if (uRL == null) {
235 uRL = classLoader.getResource(SLASH + IMAGES + SLASH + path);
236 if (uRL != null) {
237 path = (SLASH + IMAGES + SLASH + path);
238 }
239 }
240 return uRL;
241 }
242
243 /***
244 * Get the file from the current application directory.
245 *
246 * @param file the file
247 * @return the image
248 */
249 protected PlanarImage getCurrentDirFile(File file) {
250 PlanarImage image = null;
251 if (!file.isAbsolute()) {
252 File current = new File(".");
253 File imageFile = new File(current, file.getPath());
254 if (imageFile.isFile() && imageFile.exists()) {
255 try {
256 image = JAI.create(FILELOAD, imageFile.getAbsolutePath());
257 if (log.isDebugEnabled()) log.debug(FILE_LOADED + imageFile.getAbsolutePath());
258 } catch (Exception e) {
259 if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR, e);
260 }
261 }
262 }
263 return image;
264 }
265
266 /***
267 * Get the file from the dir specified trough the resourcedir property
268 *
269 * @param file the file
270 * @return the image or null
271 */
272 protected PlanarImage getJMAGEResourceDirFile(File file) {
273 PlanarImage image = null;
274 String resourceDirName = this.applicationContext.getProperty(resourcedir);
275
276 if (resourceDirName == null) {
277 return null;
278 }
279
280 File imageResourceDir = new File(resourceDirName, IMAGES);
281 if (imageResourceDir != null && imageResourceDir.isDirectory() && imageResourceDir.exists()) {
282 File imageFile = new File(imageResourceDir, file.getPath());
283 if (imageFile.isFile() && imageFile.exists()) {
284 try {
285 image = JAI.create(FILELOAD, imageFile.getAbsolutePath());
286 if (log.isDebugEnabled()) log.debug(FILE_LOADED + imageFile.getAbsolutePath());
287 } catch (Exception e) {
288 if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR, e);
289 }
290 }
291 }
292
293 if(image!=null) return image;
294
295 imageResourceDir = new File(resourceDirName);
296 if (imageResourceDir != null && imageResourceDir.isDirectory() && imageResourceDir.exists()) {
297 File imageFile = new File(imageResourceDir, file.getPath());
298 if (imageFile.isFile() && imageFile.exists()) {
299 try {
300 image = JAI.create(FILELOAD, imageFile.getAbsolutePath());
301 if (log.isDebugEnabled()) log.debug(FILE_LOADED + imageFile.getAbsolutePath());
302 } catch (Exception e) {
303 if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR, e);
304 }
305 }
306 }
307 return image;
308 }
309
310 /***
311 * Get the file from the ServletContainer as a system resource.
312 *
313 * @param file the file
314 * @return the image
315 */
316 protected PlanarImage getServletContainerResource(File file) {
317 PlanarImage image = null;
318
319
320 if (servletContext == null) {
321 servletContext = (ServletContext) this.applicationContext.get(SERVLET_CONTEXT);
322 if (log.isEnabledFor(Priority.DEBUG)) log.debug("servletContext is " + servletContext);
323 }
324
325 if (servletContext != null) {
326 try {
327 InputStream is = servletContext.getResourceAsStream(file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
328
329
330 if (is == null) {
331 File derived = new File(SLASH + IMAGES, file.getPath());
332 is = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
333 }
334 if (is == null) {
335 File derived = new File(IMAGES, file.getPath());
336 is = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
337 }
338 if (is == null) {
339 File derived = new File(SLASH, file.getPath());
340 is = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
341 }
342
343 if (is == null) {
344 String derivedPath = file.getPath().replaceAll(REGEX_BACKSLASH, SLASH);
345 File derived = new File(derivedPath.startsWith(SLASH) ? derivedPath.substring(1) : derivedPath);
346 is = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
347 }
348
349 if (is == null) {
350 if (log.isDebugEnabled()) log.debug(SERVLET_LOADERROR + file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
351 return null;
352 }
353 image = JAI.create(STREAM, new ByteArraySeekableStream((this.streamConvert(is).toByteArray())));
354 if (log.isDebugEnabled()) log.debug(SERVLET_LOADED + file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
355 } catch (Throwable e) {
356 if (log.isDebugEnabled()) log.debug(SERVLET_LOADERROR + file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
357 }
358 }
359 return image;
360 }
361
362 /***
363 * Get the absolute file from the file system
364 *
365 * @param file the file
366 * @return the image
367 */
368 protected PlanarImage getAbsoluteFile(File file) {
369 PlanarImage image = null;
370 if (file.isAbsolute() && file.exists()) {
371 try {
372 image = JAI.create(FILELOAD, file.getAbsolutePath());
373 if (log.isDebugEnabled()) log.debug(FILE_LOADED + file.getAbsolutePath());
374 } catch (Exception e) {
375 if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR, e);
376 }
377 }
378 return image;
379 }
380
381 /***
382 * Get the image from an URL
383 *
384 * @param url the url
385 * @return the image
386 * @throws ResourceException
387 */
388 protected PlanarImage getURL(URL url) throws ResourceException {
389 PlanarImage image = null;
390 final String errorMessage = URL_LOADERROR + url.toString();
391
392 try {
393 byte[] urlBytes = this.readFromUrl(url).toByteArray();
394 image = JAI.create(STREAM, new ByteArraySeekableStream(urlBytes));
395 if (log.isDebugEnabled()) log.debug(URL_LOADED + url.toString());
396 } catch (Exception e) {
397 if (log.isEnabledFor(Priority.ERROR)) log.error(errorMessage + CAUSE + e.getMessage());
398 throw new ResourceException(errorMessage);
399 }
400
401
402 if (image == null) {
403 if (log.isEnabledFor(Priority.ERROR)) log.error(errorMessage);
404 throw new ResourceException(errorMessage);
405 }
406 return image;
407 }
408
409 /***
410 * Read an image from a URL using http
411 *
412 * @param url the url
413 * @return the image stream
414 * @throws IOException
415 */
416 protected ByteArrayOutputStream readFromUrl(URL url) throws IOException {
417 URLConnection connection = url.openConnection();
418
419
420 connection.setDoOutput(true);
421 connection.setRequestProperty(InterceptorMapper.JMAGE_INTERNAL, TRUE);
422 connection.connect();
423
424
425 String responseHeader = connection.getHeaderField(null);
426 assert(responseHeader != null) : HTTP_HEADER_ERROR;
427 if (responseHeader.indexOf(HTTP_400) > -1) {
428 throw new IOException(URL_LOADERROR + url + CAUSE + responseHeader);
429 }
430
431 InputStream is = connection.getInputStream();
432 return streamConvert(is);
433 }
434
435 private ByteArrayOutputStream streamConvert(InputStream inputStream) throws IOException {
436 ByteArrayOutputStream bos = new ByteArrayOutputStream();
437 int c = 0;
438 while ((c = inputStream.read()) > -1) {
439 bos.write(c);
440 }
441 return bos;
442 }
443
444 public String toString() {
445 return "[" + this.getClass().getName() + "#" + this.hashCode() + "]";
446 }
447 }