80 public class URLClassPath {
81 private static final String USER_AGENT_JAVA_VERSION = "UA-Java-Version";
82 private static final String JAVA_HOME;
83 private static final String JAVA_VERSION;
84 private static final boolean DEBUG;
85 private static final boolean DISABLE_JAR_CHECKING;
86
87 static {
88 JAVA_HOME = java.security.AccessController.doPrivileged(
89 new sun.security.action.GetPropertyAction("java.home"));
90 JAVA_VERSION = java.security.AccessController.doPrivileged(
91 new sun.security.action.GetPropertyAction("java.version"));
92 DEBUG = (java.security.AccessController.doPrivileged(
93 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null);
94 String p = java.security.AccessController.doPrivileged(
95 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking"));
96 DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
97 }
98
99 /* The original search path of URLs. */
100 private ArrayList<URL> path = new ArrayList<URL>();
101
102 /* The stack of unopened URLs */
103 Stack<URL> urls = new Stack<URL>();
104
105 /* The resulting search path of Loaders */
106 ArrayList<Loader> loaders = new ArrayList<Loader>();
107
108 /* Map of each URL opened to its corresponding Loader */
109 HashMap<String, Loader> lmap = new HashMap<String, Loader>();
110
111 /* The jar protocol handler to use when creating new URLs */
112 private URLStreamHandler jarHandler;
113
114 /* Whether this URLClassLoader has been closed yet */
115 private boolean closed = false;
116
117 /**
118 * Creates a new URLClassPath for the given URLs. The URLs will be
119 * searched in the order specified for classes and resources. A URL
120 * ending with a '/' is assumed to refer to a directory. Otherwise,
121 * the URL is assumed to refer to a JAR file.
122 *
123 * @param urls the directory and JAR file URLs to search for classes
124 * and resources
125 * @param factory the URLStreamHandlerFactory to use when creating new URLs
126 */
127 public URLClassPath(URL[] urls, URLStreamHandlerFactory factory) {
128 for (int i = 0; i < urls.length; i++) {
129 path.add(urls[i]);
130 }
131 push(urls);
132 if (factory != null) {
133 jarHandler = factory.createURLStreamHandler("jar");
134 }
135 }
136
137 public URLClassPath(URL[] urls) {
138 this(urls, null);
139 }
140
141 public synchronized List<IOException> closeLoaders() {
142 if (closed) {
143 return Collections.emptyList();
144 }
145 List<IOException> result = new LinkedList<IOException>();
146 for (Loader loader : loaders) {
147 try {
148 loader.close();
149 } catch (IOException e) {
150 result.add (e);
151 }
152 }
153 closed = true;
154 return result;
155 }
156
157 /**
158 * Appends the specified URL to the search path of directory and JAR
159 * file URLs from which to load classes and resources.
160 * <p>
161 * If the URL specified is null or is already in the list of
162 * URLs, then invoking this method has no effect.
163 */
164 public synchronized void addURL(URL url) {
165 if (closed)
217
218 Loader loader;
219 for (int i = 0; (loader = getLoader(i)) != null; i++) {
220 Resource res = loader.getResource(name, check);
221 if (res != null) {
222 return res;
223 }
224 }
225 return null;
226 }
227
228 /**
229 * Finds all resources on the URL search path with the given name.
230 * Returns an enumeration of the URL objects.
231 *
232 * @param name the resource name
233 * @return an Enumeration of all the urls having the specified name
234 */
235 public Enumeration<URL> findResources(final String name,
236 final boolean check) {
237 return new Enumeration<URL>() {
238 private int index = 0;
239 private URL url = null;
240
241 private boolean next() {
242 if (url != null) {
243 return true;
244 } else {
245 Loader loader;
246 while ((loader = getLoader(index++)) != null) {
247 url = loader.findResource(name, check);
248 if (url != null) {
249 return true;
250 }
251 }
252 return false;
253 }
254 }
255
256 public boolean hasMoreElements() {
257 return next();
264 URL u = url;
265 url = null;
266 return u;
267 }
268 };
269 }
270
271 public Resource getResource(String name) {
272 return getResource(name, true);
273 }
274
275 /**
276 * Finds all resources on the URL search path with the given name.
277 * Returns an enumeration of the Resource objects.
278 *
279 * @param name the resource name
280 * @return an Enumeration of all the resources having the specified name
281 */
282 public Enumeration<Resource> getResources(final String name,
283 final boolean check) {
284 return new Enumeration<Resource>() {
285 private int index = 0;
286 private Resource res = null;
287
288 private boolean next() {
289 if (res != null) {
290 return true;
291 } else {
292 Loader loader;
293 while ((loader = getLoader(index++)) != null) {
294 res = loader.getResource(name, check);
295 if (res != null) {
296 return true;
297 }
298 }
299 return false;
300 }
301 }
302
303 public boolean hasMoreElements() {
304 return next();
357 if (urls != null) {
358 push(urls);
359 }
360 } catch (IOException e) {
361 // Silently ignore for now...
362 continue;
363 }
364 // Finally, add the Loader to the search path.
365 loaders.add(loader);
366 lmap.put(urlNoFragString, loader);
367 }
368 return loaders.get(index);
369 }
370
371 /*
372 * Returns the Loader for the specified base URL.
373 */
374 private Loader getLoader(final URL url) throws IOException {
375 try {
376 return java.security.AccessController.doPrivileged(
377 new java.security.PrivilegedExceptionAction<Loader>() {
378 public Loader run() throws IOException {
379 String file = url.getFile();
380 if (file != null && file.endsWith("/")) {
381 if ("file".equals(url.getProtocol())) {
382 return new FileLoader(url);
383 } else {
384 return new Loader(url);
385 }
386 } else {
387 if (file != null && "file".equals(url.getProtocol())) {
388 if (file.endsWith(".jimage"))
389 return new JImageLoader(url);
390 }
391 return new JarLoader(url, jarHandler, lmap);
392 }
393 }
394 });
395 } catch (java.security.PrivilegedActionException pae) {
396 throw (IOException)pae.getException();
397 }
672 if (!closed) {
673 closed = true;
674 // in case not already open.
675 ensureOpen();
676 jar.close();
677 }
678 }
679
680 JarFile getJarFile () {
681 return jar;
682 }
683
684 private boolean isOptimizable(URL url) {
685 return "file".equals(url.getProtocol());
686 }
687
688 private void ensureOpen() throws IOException {
689 if (jar == null) {
690 try {
691 java.security.AccessController.doPrivileged(
692 new java.security.PrivilegedExceptionAction<Void>() {
693 public Void run() throws IOException {
694 if (DEBUG) {
695 System.err.println("Opening " + csu);
696 Thread.dumpStack();
697 }
698
699 jar = getJarFile(csu);
700 index = JarIndex.getJarIndex(jar, metaIndex);
701 if (index != null) {
702 String[] jarfiles = index.getJarFiles();
703 // Add all the dependent URLs to the lmap so that loaders
704 // will not be created for them by URLClassPath.getLoader(int)
705 // if the same URL occurs later on the main class path. We set
706 // Loader to null here to avoid creating a Loader for each
707 // URL until we actually need to try to load something from them.
708 for(int i = 0; i < jarfiles.length; i++) {
709 try {
710 URL jarURL = new URL(csu, jarfiles[i]);
711 // If a non-null loader already exists, leave it alone.
712 String urlNoFragString = URLUtil.urlNoFragString(jarURL);
853 */
854 Resource getResource(final String name, boolean check) {
855 if (metaIndex != null) {
856 if (!metaIndex.mayContain(name)) {
857 return null;
858 }
859 }
860
861 try {
862 ensureOpen();
863 } catch (IOException e) {
864 throw new InternalError(e);
865 }
866 final JarEntry entry = jar.getJarEntry(name);
867 if (entry != null)
868 return checkResource(name, check, entry);
869
870 if (index == null)
871 return null;
872
873 HashSet<String> visited = new HashSet<String>();
874 return getResource(name, check, visited);
875 }
876
877 /*
878 * Version of getResource() that tracks the jar files that have been
879 * visited by linking through the index files. This helper method uses
880 * a HashSet to store the URLs of jar files that have been searched and
881 * uses it to avoid going into an infinite loop, looking for a
882 * non-existent resource
883 */
884 Resource getResource(final String name, boolean check,
885 Set<String> visited) {
886
887 Resource res;
888 String[] jarFiles;
889 int count = 0;
890 LinkedList<String> jarFilesList = null;
891
892 /* If there no jar files in the index that can potential contain
893 * this resource then return immediately.
895 if((jarFilesList = index.get(name)) == null)
896 return null;
897
898 do {
899 int size = jarFilesList.size();
900 jarFiles = jarFilesList.toArray(new String[size]);
901 /* loop through the mapped jar file list */
902 while(count < size) {
903 String jarName = jarFiles[count++];
904 JarLoader newLoader;
905 final URL url;
906
907 try{
908 url = new URL(csu, jarName);
909 String urlNoFragString = URLUtil.urlNoFragString(url);
910 if ((newLoader = (JarLoader)lmap.get(urlNoFragString)) == null) {
911 /* no loader has been set up for this jar file
912 * before
913 */
914 newLoader = AccessController.doPrivileged(
915 new PrivilegedExceptionAction<JarLoader>() {
916 public JarLoader run() throws IOException {
917 return new JarLoader(url, handler,
918 lmap);
919 }
920 });
921
922 /* this newly opened jar file has its own index,
923 * merge it into the parent's index, taking into
924 * account the relative path.
925 */
926 JarIndex newIndex = newLoader.getIndex();
927 if(newIndex != null) {
928 int pos = jarName.lastIndexOf('/');
929 newIndex.merge(this.index, (pos == -1 ?
930 null : jarName.substring(0, pos + 1)));
931 }
932
933 /* put it in the global hashtable */
934 lmap.put(urlNoFragString, newLoader);
935 }
|
80 public class URLClassPath {
81 private static final String USER_AGENT_JAVA_VERSION = "UA-Java-Version";
82 private static final String JAVA_HOME;
83 private static final String JAVA_VERSION;
84 private static final boolean DEBUG;
85 private static final boolean DISABLE_JAR_CHECKING;
86
87 static {
88 JAVA_HOME = java.security.AccessController.doPrivileged(
89 new sun.security.action.GetPropertyAction("java.home"));
90 JAVA_VERSION = java.security.AccessController.doPrivileged(
91 new sun.security.action.GetPropertyAction("java.version"));
92 DEBUG = (java.security.AccessController.doPrivileged(
93 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null);
94 String p = java.security.AccessController.doPrivileged(
95 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking"));
96 DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
97 }
98
99 /* The original search path of URLs. */
100 private ArrayList<URL> path = new ArrayList<>();
101
102 /* The stack of unopened URLs */
103 Stack<URL> urls = new Stack<>();
104
105 /* The resulting search path of Loaders */
106 ArrayList<Loader> loaders = new ArrayList<>();
107
108 /* Map of each URL opened to its corresponding Loader */
109 HashMap<String, Loader> lmap = new HashMap<>();
110
111 /* The jar protocol handler to use when creating new URLs */
112 private URLStreamHandler jarHandler;
113
114 /* Whether this URLClassLoader has been closed yet */
115 private boolean closed = false;
116
117 /**
118 * Creates a new URLClassPath for the given URLs. The URLs will be
119 * searched in the order specified for classes and resources. A URL
120 * ending with a '/' is assumed to refer to a directory. Otherwise,
121 * the URL is assumed to refer to a JAR file.
122 *
123 * @param urls the directory and JAR file URLs to search for classes
124 * and resources
125 * @param factory the URLStreamHandlerFactory to use when creating new URLs
126 */
127 public URLClassPath(URL[] urls, URLStreamHandlerFactory factory) {
128 for (int i = 0; i < urls.length; i++) {
129 path.add(urls[i]);
130 }
131 push(urls);
132 if (factory != null) {
133 jarHandler = factory.createURLStreamHandler("jar");
134 }
135 }
136
137 public URLClassPath(URL[] urls) {
138 this(urls, null);
139 }
140
141 public synchronized List<IOException> closeLoaders() {
142 if (closed) {
143 return Collections.emptyList();
144 }
145 List<IOException> result = new LinkedList<>();
146 for (Loader loader : loaders) {
147 try {
148 loader.close();
149 } catch (IOException e) {
150 result.add (e);
151 }
152 }
153 closed = true;
154 return result;
155 }
156
157 /**
158 * Appends the specified URL to the search path of directory and JAR
159 * file URLs from which to load classes and resources.
160 * <p>
161 * If the URL specified is null or is already in the list of
162 * URLs, then invoking this method has no effect.
163 */
164 public synchronized void addURL(URL url) {
165 if (closed)
217
218 Loader loader;
219 for (int i = 0; (loader = getLoader(i)) != null; i++) {
220 Resource res = loader.getResource(name, check);
221 if (res != null) {
222 return res;
223 }
224 }
225 return null;
226 }
227
228 /**
229 * Finds all resources on the URL search path with the given name.
230 * Returns an enumeration of the URL objects.
231 *
232 * @param name the resource name
233 * @return an Enumeration of all the urls having the specified name
234 */
235 public Enumeration<URL> findResources(final String name,
236 final boolean check) {
237 return new Enumeration<>() {
238 private int index = 0;
239 private URL url = null;
240
241 private boolean next() {
242 if (url != null) {
243 return true;
244 } else {
245 Loader loader;
246 while ((loader = getLoader(index++)) != null) {
247 url = loader.findResource(name, check);
248 if (url != null) {
249 return true;
250 }
251 }
252 return false;
253 }
254 }
255
256 public boolean hasMoreElements() {
257 return next();
264 URL u = url;
265 url = null;
266 return u;
267 }
268 };
269 }
270
271 public Resource getResource(String name) {
272 return getResource(name, true);
273 }
274
275 /**
276 * Finds all resources on the URL search path with the given name.
277 * Returns an enumeration of the Resource objects.
278 *
279 * @param name the resource name
280 * @return an Enumeration of all the resources having the specified name
281 */
282 public Enumeration<Resource> getResources(final String name,
283 final boolean check) {
284 return new Enumeration<>() {
285 private int index = 0;
286 private Resource res = null;
287
288 private boolean next() {
289 if (res != null) {
290 return true;
291 } else {
292 Loader loader;
293 while ((loader = getLoader(index++)) != null) {
294 res = loader.getResource(name, check);
295 if (res != null) {
296 return true;
297 }
298 }
299 return false;
300 }
301 }
302
303 public boolean hasMoreElements() {
304 return next();
357 if (urls != null) {
358 push(urls);
359 }
360 } catch (IOException e) {
361 // Silently ignore for now...
362 continue;
363 }
364 // Finally, add the Loader to the search path.
365 loaders.add(loader);
366 lmap.put(urlNoFragString, loader);
367 }
368 return loaders.get(index);
369 }
370
371 /*
372 * Returns the Loader for the specified base URL.
373 */
374 private Loader getLoader(final URL url) throws IOException {
375 try {
376 return java.security.AccessController.doPrivileged(
377 new java.security.PrivilegedExceptionAction<>() {
378 public Loader run() throws IOException {
379 String file = url.getFile();
380 if (file != null && file.endsWith("/")) {
381 if ("file".equals(url.getProtocol())) {
382 return new FileLoader(url);
383 } else {
384 return new Loader(url);
385 }
386 } else {
387 if (file != null && "file".equals(url.getProtocol())) {
388 if (file.endsWith(".jimage"))
389 return new JImageLoader(url);
390 }
391 return new JarLoader(url, jarHandler, lmap);
392 }
393 }
394 });
395 } catch (java.security.PrivilegedActionException pae) {
396 throw (IOException)pae.getException();
397 }
672 if (!closed) {
673 closed = true;
674 // in case not already open.
675 ensureOpen();
676 jar.close();
677 }
678 }
679
680 JarFile getJarFile () {
681 return jar;
682 }
683
684 private boolean isOptimizable(URL url) {
685 return "file".equals(url.getProtocol());
686 }
687
688 private void ensureOpen() throws IOException {
689 if (jar == null) {
690 try {
691 java.security.AccessController.doPrivileged(
692 new java.security.PrivilegedExceptionAction<>() {
693 public Void run() throws IOException {
694 if (DEBUG) {
695 System.err.println("Opening " + csu);
696 Thread.dumpStack();
697 }
698
699 jar = getJarFile(csu);
700 index = JarIndex.getJarIndex(jar, metaIndex);
701 if (index != null) {
702 String[] jarfiles = index.getJarFiles();
703 // Add all the dependent URLs to the lmap so that loaders
704 // will not be created for them by URLClassPath.getLoader(int)
705 // if the same URL occurs later on the main class path. We set
706 // Loader to null here to avoid creating a Loader for each
707 // URL until we actually need to try to load something from them.
708 for(int i = 0; i < jarfiles.length; i++) {
709 try {
710 URL jarURL = new URL(csu, jarfiles[i]);
711 // If a non-null loader already exists, leave it alone.
712 String urlNoFragString = URLUtil.urlNoFragString(jarURL);
853 */
854 Resource getResource(final String name, boolean check) {
855 if (metaIndex != null) {
856 if (!metaIndex.mayContain(name)) {
857 return null;
858 }
859 }
860
861 try {
862 ensureOpen();
863 } catch (IOException e) {
864 throw new InternalError(e);
865 }
866 final JarEntry entry = jar.getJarEntry(name);
867 if (entry != null)
868 return checkResource(name, check, entry);
869
870 if (index == null)
871 return null;
872
873 HashSet<String> visited = new HashSet<>();
874 return getResource(name, check, visited);
875 }
876
877 /*
878 * Version of getResource() that tracks the jar files that have been
879 * visited by linking through the index files. This helper method uses
880 * a HashSet to store the URLs of jar files that have been searched and
881 * uses it to avoid going into an infinite loop, looking for a
882 * non-existent resource
883 */
884 Resource getResource(final String name, boolean check,
885 Set<String> visited) {
886
887 Resource res;
888 String[] jarFiles;
889 int count = 0;
890 LinkedList<String> jarFilesList = null;
891
892 /* If there no jar files in the index that can potential contain
893 * this resource then return immediately.
895 if((jarFilesList = index.get(name)) == null)
896 return null;
897
898 do {
899 int size = jarFilesList.size();
900 jarFiles = jarFilesList.toArray(new String[size]);
901 /* loop through the mapped jar file list */
902 while(count < size) {
903 String jarName = jarFiles[count++];
904 JarLoader newLoader;
905 final URL url;
906
907 try{
908 url = new URL(csu, jarName);
909 String urlNoFragString = URLUtil.urlNoFragString(url);
910 if ((newLoader = (JarLoader)lmap.get(urlNoFragString)) == null) {
911 /* no loader has been set up for this jar file
912 * before
913 */
914 newLoader = AccessController.doPrivileged(
915 new PrivilegedExceptionAction<>() {
916 public JarLoader run() throws IOException {
917 return new JarLoader(url, handler,
918 lmap);
919 }
920 });
921
922 /* this newly opened jar file has its own index,
923 * merge it into the parent's index, taking into
924 * account the relative path.
925 */
926 JarIndex newIndex = newLoader.getIndex();
927 if(newIndex != null) {
928 int pos = jarName.lastIndexOf('/');
929 newIndex.merge(this.index, (pos == -1 ?
930 null : jarName.substring(0, pos + 1)));
931 }
932
933 /* put it in the global hashtable */
934 lmap.put(urlNoFragString, newLoader);
935 }
|