View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.commons.resourcehandler.resource;
20  
21  import java.io.InputStream;
22  import java.net.URL;
23  
24  import javax.faces.application.ProjectStage;
25  import javax.faces.context.FacesContext;
26  
27  import org.apache.myfaces.commons.util.ClassUtils;
28  
29  /**
30   * A resource loader implementation which loads resources from the thread ClassLoader.
31   * 
32   */
33  public class ClassLoaderResourceLoader extends ResourceLoader
34  {
35      //public final static String JAVAX_FACES_LIBRARY_NAME = "javax.faces";
36      //public final static String JSF_JS_RESOURCE_NAME = "jsf.js";
37  
38      //public final static String MYFACES_JS_RESOURCE_NAME = "oamSubmit.js";
39      //public final static String MYFACES_LIBRARY_NAME = "org.apache.myfaces";
40  
41      
42      /**
43       * It checks version like this: 1, 1_0, 1_0_0, 100_100
44       * 
45       * Used on getLibraryVersion to filter resource directories
46       **/
47      //protected static Pattern VERSION_CHECKER = Pattern.compile("\\p{Digit}+(_\\p{Digit}*)*");
48  
49      /**
50       * It checks version like this: /1.js, /1_0.js, /1_0_0.js, /100_100.js
51       * 
52       * Used on getResourceVersion to filter resources
53       **/
54      //protected static Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*\\..*");
55  
56      /*
57      private FileFilter _libraryFileFilter = new FileFilter()
58      {
59          public boolean accept(File pathname)
60          {
61              if (pathname.isDirectory() && VERSION_CHECKER.matcher(pathname.getName()).matches())
62              {
63                  return true;
64              }
65              return false;
66          }
67      };*/
68  
69      /*
70      private FileFilter _resourceFileFilter = new FileFilter()
71      {
72          public boolean accept(File pathname)
73          {
74              if (pathname.isDirectory() && RESOURCE_VERSION_CHECKER.matcher(pathname.getName()).matches())
75              {
76                  return true;
77              }
78              return false;
79          }
80      };*/
81      
82      private final boolean _developmentStage;
83  
84      public ClassLoaderResourceLoader(String prefix)
85      {
86          super(prefix);
87          _developmentStage = FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Development);
88      }
89  
90      @Override
91      public String getLibraryVersion(String path)
92      {
93          return null;
94          /*
95          String libraryVersion = null;
96          if (getPrefix() != null)
97              path = getPrefix() + '/' + path;
98  
99          URL url = getClassLoader().getResource(path);
100 
101         if (url == null)
102         {
103             // This library does not exists for this
104             // ResourceLoader
105             return null;
106         }
107 
108         // The problem here is how to scan the directory. When a ClassLoader
109         // is used two cases could occur
110         // 1. The files are unpacked so we can use Url.toURI and crawl
111         // the directory using the api for files.
112         // 2. The files are packed in a jar. This case is more tricky,
113         // because we only have a URL. Checking the jar api we can use
114         // JarURLConnection (Sounds strange, but the api of
115         // URL.openConnection says that for a jar connection a
116         // JarURLConnection is returned). From this point we can access
117         // to the jar api and solve the algoritm.
118         if (url.getProtocol().equals("file"))
119         {
120             try
121             {
122                 File directory = new File(url.toURI());
123                 if (directory.isDirectory())
124                 {
125                     File[] versions = directory.listFiles(_libraryFileFilter);
126                     for (int i = 0; i < versions.length; i++)
127                     {
128                         String version = versions[i].getName();
129                         if (VERSION_CHECKER.matcher(version).matches())
130                         {
131                             if (libraryVersion == null)
132                             {
133                                 libraryVersion = version;
134                             }
135                             else if (getVersionComparator().compare(libraryVersion, version) < 0)
136                             {
137                                 libraryVersion = version;
138                             }
139                         }
140                     }
141                 }
142             }
143             catch (URISyntaxException e)
144             {
145                 // Just return null, because library version cannot be
146                 // resolved.
147                 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
148                 if (log.isLoggable(Level.WARNING))
149                 {
150                     log.log(Level.WARNING, "url "+url.toString()+" cannot be translated to uri: "+e.getMessage(), e);
151                 }
152             }
153         }
154         else if (isJarResourceProtocol(url.getProtocol()))
155         {
156             try
157             {
158                 url = getClassLoader().getResource(path + '/');
159 
160                 if (url != null)
161                 {
162                     JarURLConnection conn = (JarURLConnection)url.openConnection();
163                     // See DIGESTER-29 for related problem
164                     conn.setUseCaches(false);
165 
166                     try
167                     {
168                         if (conn.getJarEntry().isDirectory())
169                         {
170                             // Unfortunately, we have to scan all entry files
171                             // because there is no proper api to scan it as a
172                             // directory tree.
173                             JarFile file = conn.getJarFile();
174                             for (Enumeration<JarEntry> en = file.entries(); en.hasMoreElements();)
175                             {
176                                 JarEntry entry = en.nextElement();
177                                 String entryName = entry.getName();
178     
179                                 if (entryName.startsWith(path + '/'))
180                                 {
181                                     if (entryName.length() == path.length() + 1)
182                                     {
183                                         // the same string, just skip it
184                                         continue;
185                                     }
186     
187                                     if (entryName.charAt(entryName.length() - 1) != '/')
188                                     {
189                                         // Skip files
190                                         continue;
191                                     }
192     
193                                     entryName = entryName.substring(path.length() + 1, entryName.length() - 1);
194     
195                                     if (entryName.indexOf('/') >= 0)
196                                     {
197                                         // Inner Directory
198                                         continue;
199                                     }
200     
201                                     String version = entryName;
202                                     if (VERSION_CHECKER.matcher(version).matches())
203                                     {
204                                         if (libraryVersion == null)
205                                         {
206                                             libraryVersion = version;
207                                         }
208                                         else if (getVersionComparator().compare(libraryVersion, version) < 0)
209                                         {
210                                             libraryVersion = version;
211                                         }
212                                     }
213                                 }
214                             }
215                         }
216                     }
217                     finally
218                     {
219                         //See TRINIDAD-73
220                         //just close the input stream again if
221                         //by inspecting the entries the stream
222                         //was let open.
223                         try
224                         {
225                             conn.getInputStream().close();
226                         }
227                         catch (Exception exception)
228                         {
229                             // Ignored
230                         }
231                     }
232                 }
233             }
234             catch (IOException e)
235             {
236                 // Just return null, because library version cannot be
237                 // resolved.
238                 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
239                 if (log.isLoggable(Level.WARNING))
240                 {
241                     log.log(Level.WARNING, "IOException when scanning for resource in jar file:", e);
242                 }
243             }
244         }
245         return libraryVersion;
246         */
247     }
248 
249     @Override
250     public InputStream getResourceInputStream(ResourceMeta resourceMeta)
251     {
252         InputStream is = null;
253         if (getPrefix() != null && !"".equals(getPrefix()))
254         {
255             String name = getPrefix() + '/' + resourceMeta.getResourceIdentifier();
256             is = getClassLoader().getResourceAsStream(name);
257             if (is == null)
258             {
259                 is = this.getClass().getClassLoader().getResourceAsStream(name);
260             }
261             return is;
262         }
263         else
264         {
265             is = getClassLoader().getResourceAsStream(resourceMeta.getResourceIdentifier());
266             if (is == null)
267             {
268                 is = this.getClass().getClassLoader().getResourceAsStream(resourceMeta.getResourceIdentifier());
269             }
270             return is;
271         }
272     }
273 
274     @Override
275     public URL getResourceURL(ResourceMeta resourceMeta)
276     {
277         URL url = null;
278         if (getPrefix() != null && !"".equals(getPrefix()))
279         {
280             String name = getPrefix() + '/' + resourceMeta.getResourceIdentifier();
281             url = getClassLoader().getResource(name);
282             if (url == null)
283             {
284                 url = this.getClass().getClassLoader().getResource(name);
285             }
286             return url;
287         }
288         else
289         {
290             url = getClassLoader().getResource(resourceMeta.getResourceIdentifier());
291             if (url == null)
292             {
293                 url = this.getClass().getClassLoader().getResource(resourceMeta.getResourceIdentifier());
294             }
295             return url;
296         }
297     }
298 
299     @Override
300     public String getResourceVersion(String path)
301     {
302         return null;
303         /*
304         String resourceVersion = null;
305 
306         if (getPrefix() != null)
307             path = getPrefix() + '/' + path;
308 
309         URL url = getClassLoader().getResource(path);
310 
311         if (url == null)
312         {
313             // This library does not exists for this
314             // ResourceLoader
315             return null;
316         }
317 
318         if (url.getProtocol().equals("file"))
319         {
320             try
321             {
322                 File directory = new File(url.toURI());
323                 if (directory.isDirectory())
324                 {
325                     File[] versions = directory.listFiles(_resourceFileFilter);
326                     for (int i = 0; i < versions.length; i++)
327                     {
328                         String version = versions[i].getName();
329                         if (resourceVersion == null)
330                         {
331                             resourceVersion = version;
332                         }
333                         else if (getVersionComparator().compare(resourceVersion, version) < 0)
334                         {
335                             resourceVersion = version;
336                         }
337                     }
338                     //Since it is a directory and no version found set resourceVersion as invalid
339                     if (resourceVersion == null)
340                     {
341                         resourceVersion = VERSION_INVALID;
342                     }
343                 }
344             }
345             catch (URISyntaxException e)
346             {
347                 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
348                 if (log.isLoggable(Level.WARNING))
349                 {
350                     log.log(Level.WARNING, "url "+url.toString()+" cannot be translated to uri: "+e.getMessage(), e);
351                 }
352             }
353         }
354         else if (isJarResourceProtocol(url.getProtocol()))
355         {
356             try
357             {
358                 url = getClassLoader().getResource(path + '/');
359 
360                 if (url != null)
361                 {
362                     JarURLConnection conn = (JarURLConnection)url.openConnection();
363                     // See DIGESTER-29 for related problem
364                     conn.setUseCaches(false);
365 
366                     try
367                     {
368                         if (conn.getJarEntry().isDirectory())
369                         {
370                             // Unfortunately, we have to scan all entry files
371                             JarFile file = conn.getJarFile();
372                             for (Enumeration<JarEntry> en = file.entries(); en.hasMoreElements();)
373                             {
374                                 JarEntry entry = en.nextElement();
375                                 String entryName = entry.getName();
376     
377                                 if (entryName.startsWith(path + '/'))
378                                 {
379                                     if (entryName.length() == path.length() + 1)
380                                     {
381                                         // the same string, just skip it
382                                         continue;
383                                     }
384         
385                                     entryName = entryName.substring(path.length());
386                                     if (RESOURCE_VERSION_CHECKER.matcher(entryName).matches())
387                                     {
388                                         String version = entryName.substring(1, entryName.lastIndexOf('.'));
389                                         if (resourceVersion == null)
390                                         {
391                                             resourceVersion = version;
392                                         }
393                                         else if (getVersionComparator().compare(resourceVersion, version) < 0)
394                                         {
395                                             resourceVersion = version;
396                                         }
397                                     }
398                                 }
399                             }
400                             if (resourceVersion == null)
401                             {
402                                 resourceVersion = VERSION_INVALID;
403                             }
404                         }
405                     }
406                     finally
407                     {
408                         //See TRINIDAD-73
409                         //just close the input stream again if
410                         //by inspecting the entries the stream
411                         //was let open.
412                         try
413                         {
414                             conn.getInputStream().close();
415                         }
416                         catch (Exception exception)
417                         {
418                             // Ignored
419                         }
420                     }
421 
422                 }
423             }
424             catch (IOException e)
425             {
426                 // Just return null, because library version cannot be
427                 // resolved.
428                 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
429                 if (log.isLoggable(Level.WARNING))
430                 {
431                     log.log(Level.WARNING, "IOException when scanning for resource in jar file:", e);
432                 }
433             }
434         }
435         return resourceVersion;
436         */
437     }
438 
439     @Override
440     public ResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,
441                                            String resourceName, String resourceVersion)
442     {
443         //if (_developmentStage && libraryName != null && 
444         //        JAVAX_FACES_LIBRARY_NAME.equals(libraryName) &&
445         //        JSF_JS_RESOURCE_NAME.equals(resourceName))
446         //{
447             // InternalClassLoaderResourceLoader will serve it, so return null in this case.
448         //    return null;
449         //} else if (_developmentStage && libraryName != null &&
450         //        MYFACES_LIBRARY_NAME.equals(libraryName) &&
451         //        MYFACES_JS_RESOURCE_NAME.equals(resourceName)) {
452             // InternalClassLoaderResourceLoader will serve it, so return null in this case.
453         //     return null;
454         //} else
455         //{
456             return new ResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion);
457         //}
458     }
459 
460     /**
461      * Returns the ClassLoader to use when looking up resources under the top level package. By default, this is the
462      * context class loader.
463      * 
464      * @return the ClassLoader used to lookup resources
465      */
466     protected ClassLoader getClassLoader()
467     {
468         return ClassUtils.getContextClassLoader();
469     }
470 
471     @Override
472     public boolean libraryExists(String libraryName)
473     {
474         if (getPrefix() != null && !"".equals(getPrefix()))
475         {
476             URL url = getClassLoader().getResource(getPrefix() + '/' + libraryName);
477             if (url == null)
478             {
479                 url = this.getClass().getClassLoader().getResource(getPrefix() + '/' + libraryName);
480             }
481             if (url != null)
482             {
483                 return true;
484             }
485         }
486         else
487         {
488             URL url = getClassLoader().getResource(libraryName);
489             if (url == null)
490             {
491                 url = this.getClass().getClassLoader().getResource(libraryName);
492             }
493             if (url != null)
494             {
495                 return true;
496             }
497         }
498         return false;
499     }
500 
501     /**
502      * <p>Determines whether the given URL resource protocol refers to a JAR file. Note that
503      * BEA WebLogic and IBM WebSphere don't use the "jar://" protocol for some reason even
504      * though you can treat these resources just like normal JAR files, i.e. you can ignore
505      * the difference between these protocols after this method has returned.</p>
506      *
507      * @param protocol the URL resource protocol you want to check
508      *
509      * @return <code>true</code> if the given URL resource protocol refers to a JAR file,
510      *          <code>false</code> otherwise
511      */
512     /*
513     private static boolean isJarResourceProtocol(String protocol)
514     {
515         // Websphere uses the protocol "wsjar://" and Weblogic uses the protocol "zip://".
516         return "jar".equals(protocol) || "wsjar".equals(protocol) || "zip".equals(protocol); 
517     }*/
518 
519 }