1 17 package org.apache.geronimo.kernel.classloader; 18 19 import java.io.File ; 20 import java.io.IOException ; 21 import java.io.FileNotFoundException ; 22 import java.net.MalformedURLException ; 23 import java.net.URL ; 24 import java.util.ArrayList ; 25 import java.util.Arrays ; 26 import java.util.Collections ; 27 import java.util.Enumeration ; 28 import java.util.Iterator ; 29 import java.util.LinkedHashMap ; 30 import java.util.LinkedHashSet ; 31 import java.util.LinkedList ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.StringTokenizer ; 35 import java.util.jar.Attributes ; 36 import java.util.jar.Manifest ; 37 import java.util.jar.JarFile ; 38 39 42 public class UrlResourceFinder implements ResourceFinder { 43 private final Object lock = new Object (); 44 45 private final LinkedHashSet urls = new LinkedHashSet (); 46 private final LinkedHashMap classPath = new LinkedHashMap (); 47 private final LinkedHashSet watchedFiles = new LinkedHashSet (); 48 49 private boolean destroyed = false; 50 51 public UrlResourceFinder() { 52 } 53 54 public UrlResourceFinder(URL [] urls) { 55 addUrls(urls); 56 } 57 58 public void destroy() { 59 synchronized (lock) { 60 if (destroyed) { 61 return; 62 } 63 destroyed = true; 64 urls.clear(); 65 for (Iterator iterator = classPath.values().iterator(); iterator.hasNext();) { 66 ResourceLocation resourceLocation = (ResourceLocation) iterator.next(); 67 resourceLocation.close(); 68 } 69 classPath.clear(); 70 } 71 } 72 73 public ResourceHandle getResource(String resourceName) { 74 synchronized (lock) { 75 if (destroyed) { 76 return null; 77 } 78 for (Iterator iterator = getClassPath().entrySet().iterator(); iterator.hasNext();) { 79 Map.Entry entry = (Map.Entry ) iterator.next(); 80 ResourceLocation resourceLocation = (ResourceLocation) entry.getValue(); 81 ResourceHandle resourceHandle = resourceLocation.getResourceHandle(resourceName); 82 if (resourceHandle != null && !resourceHandle.isDirectory()) { 83 return resourceHandle; 84 } 85 } 86 } 87 return null; 88 } 89 90 public URL findResource(String resourceName) { 91 synchronized (lock) { 92 if (destroyed) { 93 return null; 94 } 95 for (Iterator iterator = getClassPath().entrySet().iterator(); iterator.hasNext();) { 96 Map.Entry entry = (Map.Entry ) iterator.next(); 97 ResourceLocation resourceLocation = (ResourceLocation) entry.getValue(); 98 ResourceHandle resourceHandle = resourceLocation.getResourceHandle(resourceName); 99 if (resourceHandle != null) { 100 return resourceHandle.getUrl(); 101 } 102 } 103 } 104 return null; 105 } 106 107 public Enumeration findResources(String resourceName) { 108 synchronized (lock) { 109 return new ResourceEnumeration(new ArrayList (getClassPath().values()), resourceName); 110 } 111 } 112 113 public void addUrl(URL url) { 114 addUrls(Collections.singletonList(url)); 115 } 116 117 public URL [] getUrls() { 118 synchronized (lock) { 119 return (URL []) urls.toArray(new URL [urls.size()]); 120 } 121 } 122 123 127 protected void addUrls(URL [] urls) { 128 addUrls(Arrays.asList(urls)); 129 } 130 131 135 protected void addUrls(List urls) { 136 synchronized (lock) { 137 if (destroyed) { 138 throw new IllegalStateException ("UrlResourceFinder has been destroyed"); 139 } 140 141 boolean shouldRebuild = this.urls.addAll(urls); 142 if (shouldRebuild) { 143 rebuildClassPath(); 144 } 145 } 146 } 147 148 private LinkedHashMap getClassPath() { 149 assert Thread.holdsLock(lock): "This method can only be called while holding the lock"; 150 151 for (Iterator iterator = watchedFiles.iterator(); iterator.hasNext();) { 152 File file = (File ) iterator.next(); 153 if (file.canRead()) { 154 rebuildClassPath(); 155 break; 156 } 157 } 158 159 return classPath; 160 } 161 162 167 private void rebuildClassPath() { 168 assert Thread.holdsLock(lock): "This method can only be called while holding the lock"; 169 170 Map existingJarFiles = new LinkedHashMap (classPath); 172 classPath.clear(); 173 174 LinkedList locationStack = new LinkedList (urls); 175 try { 176 while (!locationStack.isEmpty()) { 177 URL url = (URL ) locationStack.removeFirst(); 178 179 if (classPath.containsKey(url)) { 181 continue; 182 } 183 184 ResourceLocation resourceLocation = (ResourceLocation) existingJarFiles.remove(url); 186 187 if (resourceLocation == null) { 189 try { 190 File file = cacheUrl(url); 191 resourceLocation = createResourceLocation(url, file); 192 } catch (FileNotFoundException e) { 193 if ("file".equals(url.getProtocol())) { 195 File file = new File (url.getPath()); 196 watchedFiles.add(file); 197 continue; 198 199 } 200 } catch (IOException ignored) { 201 continue; 205 } 206 } 207 208 classPath.put(resourceLocation.getCodeSource(), resourceLocation); 210 211 List manifestClassPath = getManifestClassPath(resourceLocation); 213 locationStack.addAll(0, manifestClassPath); 214 } 215 } catch (Error e) { 216 destroy(); 217 throw e; 218 } 219 220 for (Iterator iterator = existingJarFiles.values().iterator(); iterator.hasNext();) { 221 ResourceLocation resourceLocation = (ResourceLocation) iterator.next(); 222 resourceLocation.close(); 223 } 224 } 225 226 protected File cacheUrl(URL url) throws IOException { 227 if (!"file".equals(url.getProtocol())) { 228 throw new Error ("Only local file jars are supported " + url); 230 } 231 232 File file = new File (url.getPath()); 233 if (!file.exists()) { 234 throw new FileNotFoundException (file.getAbsolutePath()); 235 } 236 if (!file.canRead()) { 237 throw new IOException ("File is not readable: " + file.getAbsolutePath()); 238 } 239 return file; 240 } 241 242 protected ResourceLocation createResourceLocation(URL codeSource, File cacheFile) throws IOException { 243 if (!cacheFile.exists()) { 244 throw new FileNotFoundException (cacheFile.getAbsolutePath()); 245 } 246 if (!cacheFile.canRead()) { 247 throw new IOException ("File is not readable: " + cacheFile.getAbsolutePath()); 248 } 249 250 ResourceLocation resourceLocation = null; 251 if (cacheFile.isDirectory()) { 252 resourceLocation = new DirectoryResourceLocation(cacheFile); 255 } else { 256 resourceLocation = new JarResourceLocation(codeSource, new JarFile (cacheFile)); 257 } 258 return resourceLocation; 259 } 260 261 private List getManifestClassPath(ResourceLocation resourceLocation) { 262 try { 263 Manifest manifest = resourceLocation.getManifest(); 265 if (manifest == null) { 266 return Collections.EMPTY_LIST; 268 } 269 270 String manifestClassPath = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH); 272 if (manifestClassPath == null) { 273 return Collections.EMPTY_LIST; 274 } 275 276 URL codeSource = resourceLocation.getCodeSource(); 279 LinkedList classPathUrls = new LinkedList (); 280 for (StringTokenizer tokenizer = new StringTokenizer (manifestClassPath, " "); tokenizer.hasMoreTokens();) { 281 String entry = tokenizer.nextToken(); 282 try { 283 URL entryUrl = new URL (codeSource, entry); 285 classPathUrls.addLast(entryUrl); 286 } catch (MalformedURLException ignored) { 287 } 289 } 290 return classPathUrls; 291 } catch (IOException ignored) { 292 return Collections.EMPTY_LIST; 294 } 295 } 296 } 297 | Popular Tags |