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