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 }