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.shared.resource;
20  
21  import java.io.File;
22  import java.io.FileFilter;
23  import java.io.InputStream;
24  import java.net.URL;
25  import java.util.Iterator;
26  import javax.faces.application.ResourceVisitOption;
27  import javax.faces.context.FacesContext;
28  
29  import org.apache.myfaces.shared.util.ClassUtils;
30  
31  /**
32   * A resource loader implementation which loads resources from the thread ClassLoader.
33   * 
34   */
35  public class ClassLoaderResourceLoader extends ResourceLoader
36  {
37      /**
38       * It checks version like this: 1, 1_0, 1_0_0, 100_100
39       * 
40       * Used on getLibraryVersion to filter resource directories
41       **/
42      //protected static Pattern VERSION_CHECKER = Pattern.compile("\\p{Digit}+(_\\p{Digit}*)*");
43  
44      /**
45       * It checks version like this: /1.js, /1_0.js, /1_0_0.js, /100_100.js
46       * 
47       * Used on getResourceVersion to filter resources
48       **/
49      //protected static Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*\\..*");
50  
51      /*
52      private FileFilter _libraryFileFilter = new FileFilter()
53      {
54          public boolean accept(File pathname)
55          {
56              if (pathname.isDirectory() && VERSION_CHECKER.matcher(pathname.getName()).matches())
57              {
58                  return true;
59              }
60              return false;
61          }
62      };*/
63  
64      /*
65      private FileFilter _resourceFileFilter = new FileFilter()
66      {
67          public boolean accept(File pathname)
68          {
69              if (pathname.isDirectory() && RESOURCE_VERSION_CHECKER.matcher(pathname.getName()).matches())
70              {
71                  return true;
72              }
73              return false;
74          }
75      };*/
76      
77      private FileFilter _resourceFileFilter = new FileFilter()
78      {
79          public boolean accept(File pathname)
80          {
81              return true;
82          }
83      };    
84      
85      public ClassLoaderResourceLoader(String prefix)
86      {
87          super(prefix);
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(String resourceId)
276     {
277         URL url = null;
278         if (getPrefix() != null && !"".equals(getPrefix()))
279         {
280             String name = getPrefix() + '/' + resourceId;
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(resourceId);
291             if (url == null)
292             {
293                 url = this.getClass().getClassLoader().getResource(resourceId);
294             }
295             return url;
296         }
297     }
298     
299     @Override
300     public URL getResourceURL(ResourceMeta resourceMeta)
301     {
302         return getResourceURL(resourceMeta.getResourceIdentifier());
303     }
304 
305     @Override
306     public String getResourceVersion(String path)
307     {
308         return null;
309         /*
310         String resourceVersion = null;
311 
312         if (getPrefix() != null)
313             path = getPrefix() + '/' + path;
314 
315         URL url = getClassLoader().getResource(path);
316 
317         if (url == null)
318         {
319             // This library does not exists for this
320             // ResourceLoader
321             return null;
322         }
323 
324         if (url.getProtocol().equals("file"))
325         {
326             try
327             {
328                 File directory = new File(url.toURI());
329                 if (directory.isDirectory())
330                 {
331                     File[] versions = directory.listFiles(_resourceFileFilter);
332                     for (int i = 0; i < versions.length; i++)
333                     {
334                         String version = versions[i].getName();
335                         if (resourceVersion == null)
336                         {
337                             resourceVersion = version;
338                         }
339                         else if (getVersionComparator().compare(resourceVersion, version) < 0)
340                         {
341                             resourceVersion = version;
342                         }
343                     }
344                     //Since it is a directory and no version found set resourceVersion as invalid
345                     if (resourceVersion == null)
346                     {
347                         resourceVersion = VERSION_INVALID;
348                     }
349                 }
350             }
351             catch (URISyntaxException e)
352             {
353                 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
354                 if (log.isLoggable(Level.WARNING))
355                 {
356                     log.log(Level.WARNING, "url "+url.toString()+" cannot be translated to uri: "+e.getMessage(), e);
357                 }
358             }
359         }
360         else if (isJarResourceProtocol(url.getProtocol()))
361         {
362             try
363             {
364                 url = getClassLoader().getResource(path + '/');
365 
366                 if (url != null)
367                 {
368                     JarURLConnection conn = (JarURLConnection)url.openConnection();
369                     // See DIGESTER-29 for related problem
370                     conn.setUseCaches(false);
371 
372                     try
373                     {
374                         if (conn.getJarEntry().isDirectory())
375                         {
376                             // Unfortunately, we have to scan all entry files
377                             JarFile file = conn.getJarFile();
378                             for (Enumeration<JarEntry> en = file.entries(); en.hasMoreElements();)
379                             {
380                                 JarEntry entry = en.nextElement();
381                                 String entryName = entry.getName();
382     
383                                 if (entryName.startsWith(path + '/'))
384                                 {
385                                     if (entryName.length() == path.length() + 1)
386                                     {
387                                         // the same string, just skip it
388                                         continue;
389                                     }
390         
391                                     entryName = entryName.substring(path.length());
392                                     if (RESOURCE_VERSION_CHECKER.matcher(entryName).matches())
393                                     {
394                                         String version = entryName.substring(1, entryName.lastIndexOf('.'));
395                                         if (resourceVersion == null)
396                                         {
397                                             resourceVersion = version;
398                                         }
399                                         else if (getVersionComparator().compare(resourceVersion, version) < 0)
400                                         {
401                                             resourceVersion = version;
402                                         }
403                                     }
404                                 }
405                             }
406                             if (resourceVersion == null)
407                             {
408                                 resourceVersion = VERSION_INVALID;
409                             }
410                         }
411                     }
412                     finally
413                     {
414                         //See TRINIDAD-73
415                         //just close the input stream again if
416                         //by inspecting the entries the stream
417                         //was let open.
418                         try
419                         {
420                             conn.getInputStream().close();
421                         }
422                         catch (Exception exception)
423                         {
424                             // Ignored
425                         }
426                     }
427 
428                 }
429             }
430             catch (IOException e)
431             {
432                 // Just return null, because library version cannot be
433                 // resolved.
434                 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
435                 if (log.isLoggable(Level.WARNING))
436                 {
437                     log.log(Level.WARNING, "IOException when scanning for resource in jar file:", e);
438                 }
439             }
440         }
441         return resourceVersion;
442         */
443     }
444 
445     @Override
446     public ResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,
447                                            String resourceName, String resourceVersion)
448     {
449         //if (_developmentStage && libraryName != null && 
450         //        ResourceUtils.JAVAX_FACES_LIBRARY_NAME.equals(libraryName) &&
451         //        ResourceUtils.JSF_JS_RESOURCE_NAME.equals(resourceName))
452         //{
453             // InternalClassLoaderResourceLoader will serve it, so return null in this case.
454         //    return null;
455         //} else if (_developmentStage && libraryName != null &&
456         //        ResourceUtils.MYFACES_LIBRARY_NAME.equals(libraryName) &&
457         //        ResourceUtils.MYFACES_JS_RESOURCE_NAME.equals(resourceName)) {
458             // InternalClassLoaderResourceLoader will serve it, so return null in this case.
459         //     return null;
460         //} else
461         //{
462             return new ResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion);
463         //}
464     }
465 
466     /**
467      * Returns the ClassLoader to use when looking up resources under the top level package. By default, this is the
468      * context class loader.
469      * 
470      * @return the ClassLoader used to lookup resources
471      */
472     protected ClassLoader getClassLoader()
473     {
474         return ClassUtils.getContextClassLoader();
475     }
476 
477     @Override
478     public boolean libraryExists(String libraryName)
479     {
480         if (getPrefix() != null && !"".equals(getPrefix()))
481         {
482             URL url = getClassLoader().getResource(getPrefix() + '/' + libraryName);
483             if (url == null)
484             {
485                 url = this.getClass().getClassLoader().getResource(getPrefix() + '/' + libraryName);
486             }
487             if (url != null)
488             {
489                 return true;
490             }
491         }
492         else
493         {
494             URL url = getClassLoader().getResource(libraryName);
495             if (url == null)
496             {
497                 url = this.getClass().getClassLoader().getResource(libraryName);
498             }
499             if (url != null)
500             {
501                 return true;
502             }
503         }
504         return false;
505     }
506     
507     @Override
508     public Iterator<String> iterator(FacesContext facesContext, String path, 
509             int maxDepth, ResourceVisitOption... options)
510     {
511         String basePath = path;
512         
513         if (getPrefix() != null)
514         {
515             basePath = getPrefix() + '/' + (path.startsWith("/") ? path.substring(1) : path);
516         }
517 
518         URL url = getClassLoader().getResource(basePath);
519 
520         return new ClassLoaderResourceLoaderIterator(url, basePath, maxDepth, options);
521     }
522     
523 }