View Javadoc

1   package org.jmage.filterchain;
2   
3   import org.apache.log4j.Logger;
4   import org.apache.log4j.Priority;
5   import org.jmage.ApplicationContext;
6   import org.jmage.filter.FilterException;
7   import org.jmage.resource.ResourceException;
8   import org.jmage.util.XmlUtil;
9   import org.w3c.dom.Document;
10  
11  import javax.servlet.ServletContext;
12  import java.io.File;
13  import java.io.FileInputStream;
14  import java.io.InputStream;
15  import java.net.URI;
16  import java.util.Properties;
17  
18  /***
19   * Creates a filter filterchain from serialized xml format
20   */
21  public class XmlFilterChainFactory implements FilterChainFactory {
22      protected XmlFilterChainDeserializer xmlFilterChainDeserializer;
23      protected ApplicationContext applicationContext = null;
24      protected ServletContext servletContext = null;
25  
26      protected static Logger log = Logger.getLogger(XmlFilterChainFactory.class.getName());
27  
28      private static XmlUtil xmlUtil = new XmlUtil();
29  
30      private static final String FILE_LOADED = " loaded xml filterchain from file: ";
31      private static final String FILE_LOADERROR = "unable to load xml filterchain from file: ";
32      private static final String FILTERCHAIN_ERROR = "unable to create xml filterchain: ";
33      private static final String CAUSE = ", cause: ";
34      private static final String XML_SUFFIX = ".xml";
35      private static final String REGEX_DOT = "//.";
36      private static final String SLASH = "/";
37      private static final String SERVLET_CONTEXT = "SERVLET_CONTEXT";
38      private static final String XML = "xml";
39      private static final String SERVLET_LOADERROR = "unable to load xml filterchain from servlet container";
40      private static final String SERVLET_LOADED = " loaded xml filterchain from servlet container: ";
41      private static final String CURRENT_DIR = ".";
42      private static final String resourcedir = "resourcedir";
43      private static final String REGEX_BACKSLASH = "////";
44      private static final String DOLLAR = "$";
45      private static final String DOT = ".";
46  
47  
48      public XmlFilterChainFactory() {
49          xmlFilterChainDeserializer = new XmlFilterChainDeserializer();
50      }
51  
52      public void configure(ApplicationContext context) {
53          this.applicationContext = context;
54          servletContext = (ServletContext) this.applicationContext.get(SERVLET_CONTEXT);
55      }
56  
57      /***
58       * Creates a FilterChain for a given filterChainUri by deserializing it from xml.
59       *
60       * @param filterChainUri the unique filterChainUri
61       * @return the filter filterchain
62       */
63      public FilterChain createFrom(URI filterChainUri) throws FilterChainException {
64          try {
65              Document doc = xmlUtil.read(this.getFromFile(this.mapURItoFile(filterChainUri)));
66              if (this.hasInternalChain(filterChainUri)) {
67                  return xmlFilterChainDeserializer.deserialize(doc, filterChainUri.getSchemeSpecificPart());
68              } else {
69                  return xmlFilterChainDeserializer.deserialize(doc);
70              }
71          } catch (Exception e) {
72              String message = FILTERCHAIN_ERROR + filterChainUri + CAUSE + e.getMessage();
73              if (log.isInfoEnabled()) log.info(message);
74              throw new FilterChainException(message);
75          }
76      }
77  
78      /***
79       * Creates a FilterChain for a given name by deserializing it from xml and then applying
80       * additional filter properties on top.
81       *
82       * @param name             the unique name
83       * @param filterProperties the additional filter properties
84       * @return the FilterChain
85       * @throws FilterChainException
86       */
87      public FilterChain createFrom(URI name, Properties filterProperties) throws FilterChainException {
88          try {
89              FilterChain chain = this.createFrom(name);
90              chain.updateConfigurableFilters(filterProperties);
91              return chain;
92          } catch (FilterException e) {
93              String message = FILTERCHAIN_ERROR + e.getMessage();
94              if (log.isInfoEnabled()) log.info(message);
95              throw new FilterChainException(message);
96          }
97      }
98  
99      protected File mapURItoFile(URI uri) {
100         String fileName = uri.getSchemeSpecificPart();
101         fileName = fileName.replaceAll(REGEX_DOT, SLASH);
102 
103         //scrap params for internal filters
104         if (fileName.indexOf(DOLLAR) > -1) {
105             fileName = fileName.substring(0, fileName.indexOf(DOLLAR));
106         }
107 
108         //try with ".xml"
109         if (!fileName.endsWith(XML_SUFFIX)) {
110             fileName += XML_SUFFIX;
111         }
112 
113         File file = new File(fileName);
114 
115         return file;
116     }
117 
118     protected boolean hasInternalChain(URI filterChainUri) {
119         return filterChainUri.toString().indexOf(DOLLAR) > -1;
120     }
121 
122     /***
123      * Get the image resource from a file.
124      *
125      * @param file the file
126      * @return the image
127      * @throws org.jmage.resource.ResourceException
128      *
129      */
130     protected InputStream getFromFile(File file) throws ResourceException {
131         InputStream xml = null;
132 
133         //1) try to load as resource from ServletContext
134         xml = xml == null ? this.getServletContainerResource(file) : xml;
135 
136         //2) if not try relative path beginning in JMAGE.RESOURCE.DIR system property
137         xml = xml == null ? this.getJMAGEResourceDirFile(file) : xml;
138 
139         //3) if not try on classpath as a resource
140         xml = xml == null ? this.getClassPathResource(file) : xml;
141 
142         //4) if not try relative path beginning in current dir
143         xml = xml == null ? this.getCurrentDirFile(file) : xml;
144 
145         //5) still null? throw resourceexception
146         if (xml == null) {
147 //            we shouldn't log this, the FilterChainManager should, if anyone. Failed attempts may be due to other
148 //            factories in the chain of command taking this over.
149 //            if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR + file);
150             throw new ResourceException(FILE_LOADERROR + file);
151         }
152         return xml;
153     }
154 
155     /***
156      * Get the xml file as inputstream from the ServletContainer.
157      *
158      * @param file the file
159      * @return the inputstream
160      */
161     protected InputStream getServletContainerResource(File file) {
162         InputStream inputStream = null;
163         //needs initialization if ApplicationContext hasn't been initialized by ServletMapper
164         //at the time this Factory was created. Investigate this weird shit, context is supposed to be a singleton???
165         if (servletContext == null) {
166             Object ctx = this.applicationContext.get(SERVLET_CONTEXT);
167             if (ctx == null) {
168                 ctx = ApplicationContext.getContext().get(SERVLET_CONTEXT);
169             }
170             if (ctx != null) {
171                 servletContext = (ServletContext) ctx;
172             } else {
173                 //no servlet context, return.
174                 return null;
175             }
176         }
177 
178         if (!file.isAbsolute() && servletContext != null) {
179             try {
180                 inputStream = servletContext.getResourceAsStream(file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
181                 //prefix the default resource dir with "xml" and try again. This allows
182                 //relative resources to be referred to the same way they are in resourcedir
183                 if (inputStream == null) {
184                     file = new File(XML, file.getPath());
185                     inputStream = servletContext.getResourceAsStream(file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
186                 }
187                 if (inputStream == null) {
188                     File derived = new File(SLASH + XML, file.getPath());
189                     inputStream = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
190                 }
191                 if (inputStream == null) {
192                     File derived = new File(SLASH, file.getPath());
193                     inputStream = servletContext.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
194                 }
195                 if (log.isDebugEnabled()) log.debug(SERVLET_LOADED + file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
196                 return inputStream;
197             } catch (Exception e) {
198                 if (log.isDebugEnabled()) log.debug(SERVLET_LOADERROR + file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
199             }
200         }
201         return null;
202     }
203 
204     /***
205      * Get the file from the classpath as a system resource
206      *
207      * @param file
208      * @return true | false
209      * @throws ResourceException
210      */
211     protected InputStream getClassPathResource(File file) throws ResourceException {
212         InputStream inputStream = null;
213         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
214 
215         //crop trailing slash for classloader
216         inputStream = classLoader.getResourceAsStream(file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
217         if (inputStream == null) {
218             File derived = new File(XML, file.getPath());
219             inputStream = classLoader.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
220         }
221         if (inputStream == null) {
222             File derived = new File(SLASH + XML, file.getPath());
223             inputStream = classLoader.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
224         }
225         if (inputStream == null) {
226             File derived = new File(SLASH, file.getPath());
227             inputStream = classLoader.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
228         }
229 
230         //try another classloader
231         classLoader = this.getClass().getClassLoader();
232 
233         //refactor this ugly sh**
234         if (inputStream == null) {
235             inputStream = classLoader.getResourceAsStream(file.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
236         }
237         if (inputStream == null) {
238             File derived = new File(XML, file.getPath());
239             inputStream = classLoader.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
240         }
241         if (inputStream == null) {
242             File derived = new File(SLASH + XML, file.getPath());
243             inputStream = classLoader.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
244         }
245         if (inputStream == null) {
246             File derived = new File(SLASH, file.getPath());
247             inputStream = classLoader.getResourceAsStream(derived.getPath().replaceAll(REGEX_BACKSLASH, SLASH));
248         }
249 
250         if (inputStream != null) {
251             if (log.isDebugEnabled()) log.debug(FILE_LOADED + file.getPath());
252         } else {
253             if (log.isDebugEnabled()) log.debug(FILE_LOADERROR + file.getPath());
254         }
255         return inputStream;
256     }
257 
258     /***
259      * Get the file from the current application directory.
260      *
261      * @param file the file
262      * @return the image
263      */
264     protected InputStream getCurrentDirFile(File file) {
265         InputStream inputStream = null;
266         File current = new File(CURRENT_DIR);
267         File xmlFile = new File(current, file.getPath());
268         if (xmlFile.isFile() && xmlFile.exists()) {
269             try {
270                 inputStream = new FileInputStream(file);
271                 if (log.isDebugEnabled()) log.debug(FILE_LOADED + xmlFile.getAbsolutePath());
272             } catch (Exception e) {
273                 if (log.isDebugEnabled()) log.debug(FILE_LOADERROR, e);
274             }
275         }
276         return inputStream;
277     }
278 
279     /***
280      * Get the file from the dir specified trough the resourcedir property
281      *
282      * @param file the file
283      * @return the image or null
284      */
285     protected InputStream getJMAGEResourceDirFile(File file) {
286         InputStream inputStream = null;
287         String resourceDirName = this.applicationContext.getProperty(resourcedir);
288         //gets caught by caller
289         if (resourceDirName == null) {
290             return null;
291         }
292 
293         File xmlResourceDir = new File(resourceDirName, XML);
294         if (xmlResourceDir != null && xmlResourceDir.isDirectory() && xmlResourceDir.exists()) {
295             File xmlFile = new File(xmlResourceDir, file.getPath());
296             if (xmlFile.isFile() && xmlFile.exists()) {
297                 try {
298                     inputStream = new FileInputStream(xmlFile);
299                     if (log.isDebugEnabled()) log.debug(FILE_LOADED + xmlFile.getAbsolutePath());
300                 } catch (Exception e) {
301                     if (log.isEnabledFor(Priority.ERROR)) log.error(FILE_LOADERROR, e);
302                 }
303             }
304         }
305         return inputStream;
306     }
307 
308     public String toString() {
309         return "[" + this.getClass().getName() + "#" + this.hashCode() + "]";
310     }
311 }