View Javadoc

1   package org.jmage.resource;
2   
3   import org.apache.log4j.Logger;
4   import org.apache.log4j.Priority;
5   import org.jmage.ApplicationContext;
6   
7   import javax.servlet.ServletContext;
8   import java.awt.*;
9   import java.io.*;
10  import java.net.MalformedURLException;
11  import java.net.URI;
12  import java.net.URL;
13  import java.net.URLConnection;
14  import java.util.ArrayList;
15  import java.util.List;
16  import java.util.Properties;
17  
18  /***
19   * FontFactory loads and creates fonts as resources from system environment.
20   */
21  public class FontFactory implements ResourceFactory {
22      protected static FontFactory fontFactory;
23  
24      private final static String TTF = "ttf";
25  
26      private final static String HTTP = "http";
27      private final static String FILE = "file";
28  
29      private static final char SUFFIX_SEPARATOR = '.';
30  
31      protected static Logger log = Logger.getLogger(FontFactory.class.getName());
32      protected List fontTypes;
33      protected List schemeTypes;
34      protected ApplicationContext applicationContext;
35      protected ServletContext servletContext;
36  
37      private static final String resourcedir = "resourcedir";
38      private static final String FONTS = "fonts";
39      private static final String SERVLET_CONTEXT = "SERVLET_CONTEXT";
40      private static final String URI_HANDLINGERROR = "unable to handle URI resource, cause: ";
41      private static final String FILE_RESOURCE_RETRIEVED = " retrieved file resource: ";
42      private static final String URL_RESOURCE_RETRIEVED = " retrieved URL resource: ";
43      private static final String SCHEME_ERROR = "unable to retrieve resource, could not handle scheme: ";
44      private static final String FILE_LOADED = " loaded font from file: ";
45      private static final String FILE_LOADERROR = "unable to load font from file: ";
46      private static final String SERVLET_LOAD = " loaded font from servlet container: ";
47      private static final String SERVLET_LOADERROR = "unable to load font from servlet container: ";
48      private static final String URL_LOADERROR = "unable to load font from URL: ";
49      private static final String URL_LOADED = " loaded font from url: ";
50      private static final String CAUSE = ", cause: ";
51      private static final String SLASH = "/";
52      private static final String REGEX_BACKSLASH = "////";
53      private static final String CLASSPATH_LOADERROR = "unable to retrieve font from classpath, cause: ";
54  
55      public FontFactory() {
56          fontTypes = new ArrayList();
57          fontTypes.add(TTF);
58  
59          schemeTypes = new ArrayList();
60          schemeTypes.add(HTTP);
61          schemeTypes.add(FILE);
62      }
63  
64      public void configureRequestProperties(Properties properties) {
65          //nothing to do
66      }
67  
68      public void removeRequestProperties(Properties properties) {
69          //nothing to do
70      }
71  
72      public void configure(ApplicationContext context) {
73          this.applicationContext = context;
74          this.servletContext = (ServletContext) this.applicationContext.get(SERVLET_CONTEXT);
75      }
76  
77      public boolean canHandle(URI resource) {
78          try {
79              String suffix = resource.getPath().substring(resource.getPath().lastIndexOf(SUFFIX_SEPARATOR) + 1).toLowerCase();
80              String scheme = resource.getScheme();
81              return fontTypes.contains(suffix) && schemeTypes.contains(scheme);
82          } catch (Exception e) {
83              if (log.isInfoEnabled()) log.info(URI_HANDLINGERROR + e.getMessage());
84              return false;
85          }
86      }
87  
88      public Object createFrom(URI resource) throws ResourceException {
89          String scheme = resource.getScheme().toLowerCase();
90          if (FILE.equals(scheme)) {
91              File file = new File(resource);
92              Font font = this.getFile(file);
93              if (log.isInfoEnabled()) log.info(FILE_RESOURCE_RETRIEVED + file.getPath());
94              return font;
95          }
96          if (HTTP.equals(scheme)) {
97              URL url = null;
98              try {
99                  url = resource.toURL();
100             } catch (MalformedURLException e) {
101                 throw new ResourceException(e.getMessage());
102             }
103             Font font = this.getURL(url);
104             if (log.isInfoEnabled()) log.info(URL_RESOURCE_RETRIEVED + url.toString());
105             return font;
106         }
107         throw new ResourceException(SCHEME_ERROR + scheme);
108     }
109 
110     protected Font getFile(File file) throws ResourceException {
111         Font font = null;
112 
113         //1) try load absolute font
114         font = font == null ? this.getAbsoluteFile(file) : font;
115 
116         //2) get as Resource from ServletContainer if present
117         font = font == null ? this.getServletContainerResource(file) : font;
118 
119         //3) if not try relative path beginning in JMAGE.RESOURCE.DIR system property
120         font = font == null ? this.getJMAGEResourceDirFile(file) : font;
121 
122         //4) if not try on classpath as a resource
123         font = font == null ? this.getClassPathResource(file) : font;
124 
125         //5) if not try relative path beginning in current dir
126         font = font == null ? this.getCurrentDirFile(file) : font;
127 
128         //6) still null? throw resourceexception
129         if (font == null) {
130             if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR + file);
131             throw new ResourceException(FILE_LOADERROR + file);
132         }
133         return font;
134     }
135 
136     protected Font getClassPathResource(File file) throws ResourceException {
137         Font font = null;
138         String fontPath = file.getPath();
139         //crop trailing slash for classloader
140         if (fontPath.indexOf(File.separator) == 0) {
141             fontPath = fontPath.substring(1);
142         }
143 
144         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
145         URL fontURL = classLoader.getResource(fontPath);
146         if (fontURL == null) {
147             fontURL = classLoader.getResource(SLASH + fontPath);
148             if (fontURL != null) {
149                 fontPath = (SLASH + fontPath);
150             }
151         }
152         if (fontURL == null) {
153             fontURL = classLoader.getResource(FONTS + SLASH + fontPath);
154             if (fontURL != null) {
155                 fontPath = (FONTS + SLASH + fontPath);
156             }
157         }
158         if (fontURL == null) {
159             fontURL = classLoader.getResource(SLASH + FONTS + SLASH + fontPath);
160             if (fontURL != null) {
161                 fontPath = (SLASH + FONTS + SLASH + fontPath);
162             }
163         }
164 
165         if (fontURL == null) {
166             classLoader = this.getClass().getClassLoader();
167             fontURL = classLoader.getResource(SLASH + fontPath);
168             if (fontURL != null) {
169                 fontPath = (SLASH + fontPath);
170             }
171         }
172         if (fontURL == null) {
173             classLoader = this.getClass().getClassLoader();
174             fontURL = classLoader.getResource(FONTS + SLASH + fontPath);
175             if (fontURL != null) {
176                 fontPath = (FONTS + SLASH + fontPath);
177             }
178         }
179         if (fontURL == null) {
180             classLoader = this.getClass().getClassLoader();
181             fontURL = classLoader.getResource(SLASH + FONTS + SLASH + fontPath);
182             if (fontURL != null) {
183                 fontPath = (SLASH + FONTS + SLASH + fontPath);
184             }
185         }
186 
187         if (fontURL != null) {
188             try {
189                 font = Font.createFont(Font.TRUETYPE_FONT, classLoader.getResourceAsStream(fontPath));
190             } catch (Exception e) {
191                 if (log.isEnabledFor(Priority.INFO)) log.info(CLASSPATH_LOADERROR + e.getMessage());
192             }
193         }
194         return font;
195     }
196 
197     protected Font getCurrentDirFile(File file) {
198         Font font = null;
199         if (font == null) {
200             File current = new File(".");
201             File fontFile = new File(current, file.getPath());
202             if (fontFile.isFile() && fontFile.exists()) {
203                 try {
204                     font = Font.createFont(Font.TRUETYPE_FONT, this.loadFile(fontFile));
205                     if (log.isDebugEnabled()) log.debug(FILE_LOADED + file.getPath());
206                 } catch (Exception e) {
207                     if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR, e);
208                 }
209             }
210         }
211         return font;
212     }
213 
214     protected Font getJMAGEResourceDirFile(File file) {
215         Font font = null;
216         String resourceDirName = this.applicationContext.getProperty(resourcedir);
217         //caught in calling method;
218         if (resourceDirName == null) {
219             return null;
220         }
221         File fontResourceDir = new File(resourceDirName, FONTS);
222         if (fontResourceDir != null && fontResourceDir.isDirectory() && fontResourceDir.exists()) {
223             File fontFile = new File(fontResourceDir, file.getPath());
224             if (fontFile.isFile() && fontFile.exists()) {
225                 try {
226                     font = Font.createFont(Font.TRUETYPE_FONT, this.loadFile(fontFile));
227                     if (log.isDebugEnabled()) log.debug(FILE_LOADED + file.getPath());
228                 } catch (Exception e) {
229                     if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR + file.getAbsolutePath(), e);
230                 }
231             }
232         }
233         return font;
234     }
235 
236     protected Font getAbsoluteFile(File file) {
237         Font font = null;
238         if (font == null && file.isAbsolute() && file.exists()) {
239             try {
240                 font = Font.createFont(Font.TRUETYPE_FONT, this.loadFile(file));
241                 if (log.isDebugEnabled()) log.debug(FILE_LOADED + file.getAbsolutePath());
242             } catch (Exception e) {
243                 if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR, e);
244             }
245         }
246         return font;
247     }
248 
249     protected Font getURL(URL url) throws ResourceException {
250         Font font = null;
251         String errorMessage = URL_LOADERROR + url.toString();
252         try {
253             font = Font.createFont(Font.TRUETYPE_FONT, this.loadUrl(url));
254             if (log.isDebugEnabled()) log.debug(URL_LOADED + url.toString());
255         } catch (Exception e) {
256             if (log.isEnabledFor(Priority.ERROR)) log.error(errorMessage + CAUSE + e.getMessage());
257             throw new ResourceException(errorMessage + CAUSE + e.getMessage());
258         }
259 
260         // null? throw resourceexception
261         if (font == null) {
262             if (log.isEnabledFor(Priority.ERROR)) log.error(errorMessage);
263             throw new ResourceException(errorMessage);
264         }
265         return font;
266     }
267 
268     /***
269      * Get the file from the ServletContainer as a system resource.
270      *
271      * @param file the file
272      * @return the image
273      */
274     protected Font getServletContainerResource(File file) {
275         Font font = null;
276         //needs initialization if ApplicationContext hasn't been initialized by ServletMapper
277         //at the time this Factory was created.
278         if (servletContext == null) {
279             servletContext = (ServletContext) this.applicationContext.get(SERVLET_CONTEXT);
280         }
281 
282         if(servletContext != null) {
283             try {
284                 InputStream is = servletContext.getResourceAsStream(file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
285                 //prefix with "fonts" the default resource dir and try again. This allows
286                 //relative resources to be referred to the same way they are in resourcedir
287                 if (is == null) {
288                     File derived = new File(SLASH + FONTS, file.getPath());
289                     is = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
290                 }
291                 if (is == null) {
292                     File derived = new File(FONTS, file.getPath());
293                     is = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
294                 }
295                 if (is == null) {
296                     File derived = new File(SLASH, file.getPath());
297                     is = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
298                 }
299                 font = Font.createFont(Font.TRUETYPE_FONT, is);
300                 if (log.isInfoEnabled()) log.info(SERVLET_LOAD + file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
301             } catch (Exception e) {
302                 if (log.isEnabledFor(Priority.INFO))
303                     log.info(SERVLET_LOADERROR + file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
304             }
305         }
306         return font;
307     }
308 
309     protected InputStream loadFile(File file) throws IOException {
310         if (!file.isFile() && !file.exists()) {
311             throw new IOException(FILE_LOADERROR);
312         }
313         FileInputStream fis = new FileInputStream(file);
314         return fis;
315     }
316 
317     protected InputStream loadUrl(URL url) throws IOException {
318         URLConnection connection = url.openConnection();
319         connection.connect();
320         DataInputStream remoteObj = new DataInputStream(connection.getInputStream());
321         return remoteObj;
322     }
323 
324     public String toString() {
325         return "[" + this.getClass().getName() + "#" + this.hashCode() + "]";
326     }
327 }