1 16 package com.google.gwt.dev.util; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 20 import java.io.File ; 21 import java.io.IOException ; 22 import java.net.MalformedURLException ; 23 import java.net.URI ; 24 import java.net.URISyntaxException ; 25 import java.net.URL ; 26 import java.net.URLClassLoader ; 27 import java.util.ArrayList ; 28 import java.util.Arrays ; 29 import java.util.Enumeration ; 30 import java.util.HashMap ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.jar.JarEntry ; 35 import java.util.jar.JarFile ; 36 37 59 public class FileOracleFactory { 60 61 65 public interface FileFilter { 66 boolean accept(String name); 67 } 68 69 73 private static final class FileOracleImpl extends FileOracle { 74 75 private final String [] logicalNames; 76 77 private final Map logicalToPhysical; 78 79 85 public FileOracleImpl(List logicalNames, Map logicalToPhysical) { 86 this.logicalNames = (String []) logicalNames.toArray(new String [logicalNames.size()]); 87 this.logicalToPhysical = new HashMap (logicalToPhysical); 88 } 89 90 95 public URL find(String partialPath) { 96 return (URL ) logicalToPhysical.get(partialPath); 97 } 98 99 104 public String [] getAllFiles() { 105 return logicalNames; 106 } 107 108 113 public boolean isEmpty() { 114 return logicalNames.length == 0; 115 } 116 } 117 118 133 private static void addPackagesInSortedOrder(TreeLogger logger, 134 URLClassLoader cl, Map packageMap, List classPathUrlList, 135 List sortedUrls, List sortedPackages, List sortedFilters, 136 boolean recordPackages) { 137 138 List unsortedUrls = new ArrayList (); 141 List unsortedPackages = new ArrayList (); 142 List unsortedFilters = new ArrayList (); 143 for (Iterator itPkg = packageMap.keySet().iterator(); itPkg.hasNext();) { 144 String curPkg = (String ) itPkg.next(); 145 FileFilter curFilter = (FileFilter) packageMap.get(curPkg); 146 try { 147 Enumeration found = cl.findResources(curPkg); 148 if (!recordPackages) { 149 curPkg = ""; 150 } 151 while (found.hasMoreElements()) { 152 URL match = (URL ) found.nextElement(); 153 unsortedUrls.add(match); 154 unsortedPackages.add(curPkg); 155 unsortedFilters.add(curFilter); 156 } 157 } catch (IOException e) { 158 logger.log(TreeLogger.WARN, "Unexpected error searching classpath for " 159 + curPkg, e); 160 } 161 } 162 163 167 168 int c = unsortedUrls.size(); 170 String [] unsortedUrlStrings = new String [c]; 171 for (int i = 0; i < c; ++i) { 172 unsortedUrlStrings[i] = unsortedUrls.get(i).toString(); 173 if (unsortedUrlStrings[i].startsWith("jar:")) { 175 unsortedUrlStrings[i] = unsortedUrlStrings[i].substring(4); 176 } 177 } 178 179 for (Iterator itCp = classPathUrlList.iterator(); itCp.hasNext();) { 181 URL curCpUrl = (URL ) itCp.next(); 182 String curUrlString = curCpUrl.toExternalForm(); 183 for (int i = 0; i < c; ++i) { 185 if (unsortedUrlStrings[i].startsWith(curUrlString)) { 186 sortedUrls.add(unsortedUrls.get(i)); 187 sortedPackages.add(unsortedPackages.get(i)); 188 sortedFilters.add(unsortedFilters.get(i)); 189 } 190 } 191 } 192 } 193 194 206 private static void indexFolder(TreeLogger logger, FileFilter filter, 207 int stripBaseLen, File curDir, List logicalNames, Map logicalToPhysical) { 208 File [] files = curDir.listFiles(); 209 for (int i = 0; i < files.length; i++) { 210 File f = files[i]; 211 if (f.exists()) { 212 if (f.isDirectory()) { 213 indexFolder(logger, filter, stripBaseLen, f, logicalNames, 214 logicalToPhysical); 215 } else if (f.isFile()) { 216 try { 217 String logicalName = f.getAbsolutePath().substring(stripBaseLen); 218 logicalName = logicalName.replace(File.separatorChar, '/'); 219 if (logicalToPhysical.containsKey(logicalName)) { 220 logger.log(TreeLogger.DEBUG, "Ignoring already-resolved " 222 + logicalName, null); 223 continue; 224 } 225 if (filter != null && !filter.accept(logicalName)) { 226 logger.log(TreeLogger.SPAM, "Filtered out " + logicalName, null); 228 continue; 229 } 230 URL physicalUrl = f.toURL(); 231 logicalToPhysical.put(logicalName, physicalUrl); 232 logicalNames.add(logicalName); 233 logger.log(TreeLogger.TRACE, "Found " + logicalName, null); 234 } catch (IOException e) { 235 logger.log(TreeLogger.WARN, "Unexpected error resolving " + f, e); 236 } 237 } 238 } 239 } 240 } 241 242 256 private static void indexJar(TreeLogger logger, FileFilter filter, 257 String jarUrl, JarFile jarFile, String basePath, String pkgBase, 258 List logicalNames, Map logicalToPhysical) { 259 int prefixCharsToStrip = basePath.length() - pkgBase.length(); 260 for (Enumeration enumJar = jarFile.entries(); enumJar.hasMoreElements();) { 261 JarEntry jarEntry = (JarEntry ) enumJar.nextElement(); 262 String jarEntryName = jarEntry.getName(); 263 if (jarEntryName.startsWith(basePath) && !jarEntry.isDirectory()) { 264 String logicalName = jarEntryName.substring(prefixCharsToStrip); 265 String physicalUrlString = jarUrl + "!/" + jarEntryName; 266 if (logicalToPhysical.containsKey(logicalName)) { 267 logger.log(TreeLogger.DEBUG, "Ignoring already-resolved " 269 + logicalName, null); 270 continue; 271 } 272 if (filter != null && !filter.accept(logicalName)) { 273 logger.log(TreeLogger.SPAM, "Filtered out " + logicalName, null); 275 continue; 276 } 277 try { 278 URL physicalUrl = new URL (physicalUrlString); 279 logicalToPhysical.put(logicalName, physicalUrl); 280 logicalNames.add(logicalName); 281 logger.log(TreeLogger.TRACE, "Found " + logicalName, null); 282 } catch (MalformedURLException e) { 283 logger.log(TreeLogger.WARN, "Unexpected error resolving " 284 + physicalUrlString, e); 285 } 286 } 287 } 288 } 289 290 304 private static void indexURL(TreeLogger logger, FileFilter filter, URL url, 305 String pkgBase, List logicalNames, Map logicalToPhysical) 306 throws URISyntaxException , IOException { 307 308 String urlString = url.toString(); 309 if (url.getProtocol().equals("file")) { 310 URI uri = new URI (urlString); 311 File f = new File (uri); 312 if (f.isDirectory()) { 313 int prefixCharsToStrip = f.getAbsolutePath().length() + 1 314 - pkgBase.length(); 315 indexFolder(logger, filter, prefixCharsToStrip, f, logicalNames, 316 logicalToPhysical); 317 } else { 318 logger.log(TreeLogger.WARN, "Unexpected error, " + f 322 + " is neither a file nor a jar", null); 323 } 324 } else if (url.getProtocol().equals("jar")) { 325 String path = url.getPath(); 326 int pos = path.indexOf('!'); 327 if (pos >= 0) { 328 String jarPath = path.substring(0, pos); 329 String dirPath = path.substring(pos + 2); 330 URL jarURL = new URL (jarPath); 331 if (jarURL.getProtocol().equals("file")) { 332 URI jarURI = new URI (jarURL.toString()); 333 File f = new File (jarURI); 334 JarFile jarFile = new JarFile (f); 335 indexJar(logger, filter, "jar" + ":" + jarPath, jarFile, dirPath, pkgBase, 339 logicalNames, logicalToPhysical); 340 } else { 341 logger.log(TreeLogger.WARN, "Unexpected error, jar at " + jarURL 342 + " must be a file: type URL", null); 343 } 344 } else { 345 throw new URISyntaxException (path, "Cannot locate '!' separator"); 346 } 347 } else { 348 logger.log(TreeLogger.WARN, "Unknown URL type for " + urlString, null); 349 } 350 } 351 352 355 private final URLClassLoader classLoader; 356 357 361 private final Map packages = new HashMap (); 362 363 367 private final Map rootPackages = new HashMap (); 368 369 372 public FileOracleFactory() { 373 this((URLClassLoader ) FileOracleFactory.class.getClassLoader()); 374 } 375 376 381 public FileOracleFactory(URLClassLoader classLoader) { 382 this.classLoader = classLoader; 383 } 384 385 393 public void addPackage(String packageAsPath, FileFilter filter) { 394 packageAsPath = ensureTrailingBackslash(packageAsPath); 395 packages.put(packageAsPath, filter); 396 } 397 398 407 public void addRootPackage(String packageAsPath, FileFilter filter) { 408 packageAsPath = ensureTrailingBackslash(packageAsPath); 409 rootPackages.put(packageAsPath, filter); 410 } 411 412 419 public FileOracle create(TreeLogger logger) { 420 421 List classPathUrls = new ArrayList (); 424 for (ClassLoader curCL = classLoader; curCL != null; curCL = curCL.getParent()) { 425 if (curCL instanceof URLClassLoader ) { 426 URLClassLoader curURLCL = (URLClassLoader ) curCL; 427 URL [] curURLs = curURLCL.getURLs(); 428 classPathUrls.addAll(Arrays.asList(curURLs)); 429 } 430 } 431 432 436 437 List urls = new ArrayList (); 439 List pkgNames = new ArrayList (); 440 List filters = new ArrayList (); 441 442 addPackagesInSortedOrder(logger, classLoader, rootPackages, classPathUrls, 444 urls, pkgNames, filters, false); 445 addPackagesInSortedOrder(logger, classLoader, packages, classPathUrls, 447 urls, pkgNames, filters, true); 448 449 451 List logicalNames = new ArrayList (); 453 Map logicalToPhysical = new HashMap (); 454 455 for (int i = 0, c = urls.size(); i < c; ++i) { 456 try { 457 URL url = (URL ) urls.get(i); 458 String pkgName = (String ) pkgNames.get(i); 459 FileFilter filter = (FileFilter) filters.get(i); 460 TreeLogger branch = logger.branch(TreeLogger.TRACE, url.toString(), 461 null); 462 indexURL(branch, filter, url, pkgName, logicalNames, logicalToPhysical); 463 } catch (URISyntaxException e) { 464 logger.log(TreeLogger.WARN, 465 "Unexpected error searching " + urls.get(i), e); 466 } catch (IOException e) { 467 logger.log(TreeLogger.WARN, 468 "Unexpected error searching " + urls.get(i), e); 469 } 470 } 471 472 return new FileOracleImpl(logicalNames, logicalToPhysical); 473 } 474 475 481 private String ensureTrailingBackslash(String packageAsPath) { 482 if (packageAsPath.endsWith("/")) { 483 return packageAsPath; 484 } else { 485 return packageAsPath + "/"; 486 } 487 } 488 } 489 | Popular Tags |