236 |
{ |
{ |
237 |
Certificate[] certs = getCertificates(); |
Certificate[] certs = getCertificates(); |
238 |
if (certs == null) |
if (certs == null) |
239 |
return loader.noCertCodeSource; |
return loader.noCertCodeSource; |
240 |
else |
else |
241 |
return new CodeSource(loader.baseURL, certs); |
return new CodeSource(loader.baseURL, certs); |
242 |
} |
} |
243 |
|
|
244 |
/** |
/** |
293 |
JarFile jarfile = null; |
JarFile jarfile = null; |
294 |
try |
try |
295 |
{ |
{ |
296 |
baseJarURL = |
baseJarURL = |
297 |
new URL(null, jarURL, classloader.getURLStreamHandler("jar")); |
new URL(null, jarURL, classloader.getURLStreamHandler("jar")); |
298 |
|
|
299 |
jarfile = |
jarfile = |
300 |
((JarURLConnection) baseJarURL.openConnection()).getJarFile(); |
((JarURLConnection) baseJarURL.openConnection()).getJarFile(); |
301 |
} |
} |
302 |
catch (IOException ioe) |
catch (IOException ioe) |
303 |
{ |
{ |
304 |
/* ignored */ |
/* ignored */ |
305 |
} |
} |
306 |
|
|
307 |
this.baseJarURL = baseJarURL; |
this.baseJarURL = baseJarURL; |
312 |
Resource getResource(String name) |
Resource getResource(String name) |
313 |
{ |
{ |
314 |
if (jarfile == null) |
if (jarfile == null) |
315 |
return null; |
return null; |
316 |
|
|
317 |
if (name.startsWith("/")) |
if (name.startsWith("/")) |
318 |
name = name.substring(1); |
name = name.substring(1); |
319 |
|
|
320 |
JarEntry je = jarfile.getJarEntry(name); |
JarEntry je = jarfile.getJarEntry(name); |
321 |
if (je != null) |
if (je != null) |
322 |
return new JarURLResource(this, name, je); |
return new JarURLResource(this, name, je); |
323 |
else |
else |
324 |
return null; |
return null; |
325 |
} |
} |
326 |
|
|
327 |
Manifest getManifest() |
Manifest getManifest() |
328 |
{ |
{ |
329 |
try |
try |
330 |
{ |
{ |
331 |
return (jarfile == null) ? null : jarfile.getManifest(); |
return (jarfile == null) ? null : jarfile.getManifest(); |
332 |
} |
} |
333 |
catch (IOException ioe) |
catch (IOException ioe) |
334 |
{ |
{ |
335 |
return null; |
return null; |
336 |
} |
} |
337 |
} |
} |
338 |
} |
} |
359 |
|
|
360 |
Certificate[] getCertificates() |
Certificate[] getCertificates() |
361 |
{ |
{ |
362 |
return entry.getCertificates(); |
// We have to get the entry from the jar file again, because the |
363 |
|
// certificates will not be available until the entire entry has |
364 |
|
// been read. |
365 |
|
return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name)) |
366 |
|
.getCertificates(); |
367 |
} |
} |
368 |
|
|
369 |
URL getURL() |
URL getURL() |
370 |
{ |
{ |
371 |
try |
try |
372 |
{ |
{ |
373 |
return new URL(((JarURLLoader) loader).baseJarURL, name, |
return new URL(((JarURLLoader) loader).baseJarURL, name, |
374 |
loader.classloader.getURLStreamHandler("jar")); |
loader.classloader.getURLStreamHandler("jar")); |
375 |
} |
} |
376 |
catch (MalformedURLException e) |
catch (MalformedURLException e) |
377 |
{ |
{ |
378 |
InternalError ie = new InternalError(); |
InternalError ie = new InternalError(); |
379 |
ie.initCause(e); |
ie.initCause(e); |
380 |
throw ie; |
throw ie; |
381 |
} |
} |
382 |
} |
} |
383 |
} |
} |
403 |
{ |
{ |
404 |
try |
try |
405 |
{ |
{ |
406 |
URL url = |
URL url = |
407 |
new URL(baseURL, name, classloader.getURLStreamHandler(protocol)); |
new URL(baseURL, name, classloader.getURLStreamHandler(protocol)); |
408 |
URLConnection connection = url.openConnection(); |
URLConnection connection = url.openConnection(); |
409 |
|
|
410 |
// Open the connection and check the stream |
// Open the connection and check the stream |
411 |
// just to be sure it exists. |
// just to be sure it exists. |
412 |
int length = connection.getContentLength(); |
int length = connection.getContentLength(); |
413 |
InputStream stream = connection.getInputStream(); |
InputStream stream = connection.getInputStream(); |
414 |
|
|
415 |
// We can do some extra checking if it is a http request |
// We can do some extra checking if it is a http request |
416 |
if (connection instanceof HttpURLConnection) |
if (connection instanceof HttpURLConnection) |
417 |
{ |
{ |
418 |
int response = |
int response = |
419 |
((HttpURLConnection) connection).getResponseCode(); |
((HttpURLConnection) connection).getResponseCode(); |
420 |
if (response / 100 != 2) |
if (response / 100 != 2) |
421 |
return null; |
return null; |
422 |
} |
} |
423 |
|
|
424 |
if (stream != null) |
if (stream != null) |
425 |
return new RemoteResource(this, name, url, stream, length); |
return new RemoteResource(this, name, url, stream, length); |
426 |
else |
else |
427 |
return null; |
return null; |
428 |
} |
} |
429 |
catch (IOException ioe) |
catch (IOException ioe) |
430 |
{ |
{ |
431 |
return null; |
return null; |
432 |
} |
} |
433 |
} |
} |
434 |
} |
} |
486 |
{ |
{ |
487 |
File file = new File(dir, name); |
File file = new File(dir, name); |
488 |
if (file.exists() && ! file.isDirectory()) |
if (file.exists() && ! file.isDirectory()) |
489 |
return new FileResource(this, name, file); |
return new FileResource(this, name, file); |
490 |
return null; |
return null; |
491 |
} |
} |
492 |
} |
} |
515 |
{ |
{ |
516 |
try |
try |
517 |
{ |
{ |
518 |
return new URL(loader.baseURL, name, |
return new URL(loader.baseURL, name, |
519 |
loader.classloader.getURLStreamHandler("file")); |
loader.classloader.getURLStreamHandler("file")); |
520 |
} |
} |
521 |
catch (MalformedURLException e) |
catch (MalformedURLException e) |
522 |
{ |
{ |
523 |
InternalError ie = new InternalError(); |
InternalError ie = new InternalError(); |
524 |
ie.initCause(e); |
ie.initCause(e); |
525 |
throw ie; |
throw ie; |
526 |
} |
} |
527 |
} |
} |
528 |
} |
} |
627 |
addURLs(urls); |
addURLs(urls); |
628 |
|
|
629 |
// If this factory is still not in factoryCache, add it, |
// If this factory is still not in factoryCache, add it, |
630 |
// since we only support three protocols so far, 5 is enough |
// since we only support three protocols so far, 5 is enough |
631 |
// for cache initial size |
// for cache initial size |
632 |
synchronized (factoryCache) |
synchronized (factoryCache) |
633 |
{ |
{ |
634 |
if (factory != null && factoryCache.get(factory) == null) |
if (factory != null && factoryCache.get(factory) == null) |
635 |
factoryCache.put(factory, new HashMap(5)); |
factoryCache.put(factory, new HashMap(5)); |
636 |
} |
} |
637 |
} |
} |
638 |
|
|
651 |
{ |
{ |
652 |
synchronized (urlloaders) |
synchronized (urlloaders) |
653 |
{ |
{ |
654 |
if (newUrl == null) |
if (newUrl == null) |
655 |
return; // Silently ignore... |
return; // Silently ignore... |
656 |
|
|
657 |
// Check global cache to see if there're already url loader |
// Check global cache to see if there're already url loader |
658 |
// for this url. |
// for this url. |
659 |
URLLoader loader = (URLLoader) urlloaders.get(newUrl); |
URLLoader loader = (URLLoader) urlloaders.get(newUrl); |
660 |
if (loader == null) |
if (loader == null) |
661 |
{ |
{ |
662 |
String file = newUrl.getFile(); |
String file = newUrl.getFile(); |
663 |
String protocol = newUrl.getProtocol(); |
String protocol = newUrl.getProtocol(); |
664 |
|
|
665 |
// Check that it is not a directory |
// Check that it is not a directory |
666 |
if (! (file.endsWith("/") || file.endsWith(File.separator))) |
if (! (file.endsWith("/") || file.endsWith(File.separator))) |
667 |
loader = new JarURLLoader(this, newUrl); |
loader = new JarURLLoader(this, newUrl); |
668 |
else if ("file".equals(protocol)) |
else if ("file".equals(protocol)) |
669 |
loader = new FileURLLoader(this, newUrl); |
loader = new FileURLLoader(this, newUrl); |
670 |
else |
else |
671 |
loader = new RemoteURLLoader(this, newUrl); |
loader = new RemoteURLLoader(this, newUrl); |
672 |
|
|
673 |
// Cache it. |
// Cache it. |
674 |
urlloaders.put(newUrl, loader); |
urlloaders.put(newUrl, loader); |
675 |
} |
} |
676 |
|
|
677 |
urls.add(newUrl); |
urls.add(newUrl); |
678 |
urlinfos.add(loader); |
urlinfos.add(loader); |
679 |
} |
} |
680 |
} |
} |
681 |
|
|
751 |
// construct the class (and watch out for those nasty IOExceptions) |
// construct the class (and watch out for those nasty IOExceptions) |
752 |
try |
try |
753 |
{ |
{ |
754 |
byte[] data; |
byte[] data; |
755 |
InputStream in = resource.getInputStream(); |
InputStream in = resource.getInputStream(); |
756 |
try |
try |
757 |
{ |
{ |
758 |
int length = resource.getLength(); |
int length = resource.getLength(); |
759 |
if (length != -1) |
if (length != -1) |
760 |
{ |
{ |
761 |
// We know the length of the data. |
// We know the length of the data. |
762 |
// Just try to read it in all at once |
// Just try to read it in all at once |
763 |
data = new byte[length]; |
data = new byte[length]; |
764 |
int pos = 0; |
int pos = 0; |
765 |
while (length - pos > 0) |
while (length - pos > 0) |
766 |
{ |
{ |
767 |
int len = in.read(data, pos, length - pos); |
int len = in.read(data, pos, length - pos); |
768 |
if (len == -1) |
if (len == -1) |
769 |
throw new EOFException("Not enough data reading from: " |
throw new EOFException("Not enough data reading from: " |
770 |
+ in); |
+ in); |
771 |
pos += len; |
pos += len; |
772 |
} |
} |
773 |
} |
} |
774 |
else |
else |
775 |
{ |
{ |
776 |
// We don't know the data length. |
// We don't know the data length. |
777 |
// Have to read it in chunks. |
// Have to read it in chunks. |
778 |
ByteArrayOutputStream out = new ByteArrayOutputStream(4096); |
ByteArrayOutputStream out = new ByteArrayOutputStream(4096); |
779 |
byte[] b = new byte[4096]; |
byte[] b = new byte[4096]; |
780 |
int l = 0; |
int l = 0; |
781 |
while (l != -1) |
while (l != -1) |
782 |
{ |
{ |
783 |
l = in.read(b); |
l = in.read(b); |
784 |
if (l != -1) |
if (l != -1) |
785 |
out.write(b, 0, l); |
out.write(b, 0, l); |
786 |
} |
} |
787 |
data = out.toByteArray(); |
data = out.toByteArray(); |
788 |
} |
} |
789 |
} |
} |
790 |
finally |
finally |
791 |
{ |
{ |
792 |
in.close(); |
in.close(); |
793 |
} |
} |
794 |
final byte[] classData = data; |
final byte[] classData = data; |
795 |
|
|
796 |
// Now get the CodeSource |
// Now get the CodeSource |
797 |
final CodeSource source = resource.getCodeSource(); |
final CodeSource source = resource.getCodeSource(); |
798 |
|
|
799 |
// Find out package name |
// Find out package name |
800 |
String packageName = null; |
String packageName = null; |
801 |
int lastDot = className.lastIndexOf('.'); |
int lastDot = className.lastIndexOf('.'); |
802 |
if (lastDot != -1) |
if (lastDot != -1) |
803 |
packageName = className.substring(0, lastDot); |
packageName = className.substring(0, lastDot); |
804 |
|
|
805 |
if (packageName != null && getPackage(packageName) == null) |
if (packageName != null && getPackage(packageName) == null) |
806 |
{ |
{ |
807 |
// define the package |
// define the package |
808 |
Manifest manifest = resource.loader.getManifest(); |
Manifest manifest = resource.loader.getManifest(); |
809 |
if (manifest == null) |
if (manifest == null) |
810 |
definePackage(packageName, null, null, null, null, null, null, |
definePackage(packageName, null, null, null, null, null, null, |
811 |
null); |
null); |
812 |
else |
else |
813 |
definePackage(packageName, manifest, resource.loader.baseURL); |
definePackage(packageName, manifest, resource.loader.baseURL); |
814 |
} |
} |
815 |
|
|
816 |
// And finally construct the class! |
// And finally construct the class! |
817 |
SecurityManager sm = System.getSecurityManager(); |
SecurityManager sm = System.getSecurityManager(); |
818 |
if (sm != null && securityContext != null) |
Class result = null; |
819 |
{ |
if (sm != null && securityContext != null) |
820 |
return (Class)AccessController.doPrivileged |
{ |
821 |
(new PrivilegedAction() |
result = (Class)AccessController.doPrivileged |
822 |
{ |
(new PrivilegedAction() |
823 |
public Object run() |
{ |
824 |
{ |
public Object run() |
825 |
return defineClass(className, classData, |
{ |
826 |
0, classData.length, |
return defineClass(className, classData, |
827 |
source); |
0, classData.length, |
828 |
} |
source); |
829 |
}, securityContext); |
} |
830 |
} |
}, securityContext); |
831 |
else |
} |
832 |
return defineClass(className, classData, 0, classData.length, source); |
else |
833 |
|
result = defineClass(className, classData, 0, classData.length, source); |
834 |
|
|
835 |
|
super.setSigners(result, resource.getCertificates()); |
836 |
|
return result; |
837 |
} |
} |
838 |
catch (IOException ioe) |
catch (IOException ioe) |
839 |
{ |
{ |
840 |
throw new ClassNotFoundException(className, ioe); |
throw new ClassNotFoundException(className, ioe); |
841 |
} |
} |
842 |
} |
} |
843 |
|
|
853 |
int max = urls.size(); |
int max = urls.size(); |
854 |
for (int i = 0; i < max; i++) |
for (int i = 0; i < max; i++) |
855 |
{ |
{ |
856 |
URLLoader loader = (URLLoader) urlinfos.elementAt(i); |
URLLoader loader = (URLLoader) urlinfos.elementAt(i); |
857 |
if (loader == null) |
if (loader == null) |
858 |
continue; |
continue; |
859 |
|
|
860 |
Resource resource = loader.getResource(resourceName); |
Resource resource = loader.getResource(resourceName); |
861 |
if (resource != null) |
if (resource != null) |
862 |
return resource; |
return resource; |
863 |
} |
} |
864 |
return null; |
return null; |
865 |
} |
} |
895 |
URLStreamHandler handler; |
URLStreamHandler handler; |
896 |
synchronized (factoryCache) |
synchronized (factoryCache) |
897 |
{ |
{ |
898 |
// Check if there're handler for the same protocol in cache. |
// Check if there're handler for the same protocol in cache. |
899 |
HashMap cache = (HashMap) factoryCache.get(factory); |
HashMap cache = (HashMap) factoryCache.get(factory); |
900 |
handler = (URLStreamHandler) cache.get(protocol); |
handler = (URLStreamHandler) cache.get(protocol); |
901 |
if (handler == null) |
if (handler == null) |
902 |
{ |
{ |
903 |
// Add it to cache. |
// Add it to cache. |
904 |
handler = factory.createURLStreamHandler(protocol); |
handler = factory.createURLStreamHandler(protocol); |
905 |
cache.put(protocol, handler); |
cache.put(protocol, handler); |
906 |
} |
} |
907 |
} |
} |
908 |
return handler; |
return handler; |
909 |
} |
} |
924 |
int max = urls.size(); |
int max = urls.size(); |
925 |
for (int i = 0; i < max; i++) |
for (int i = 0; i < max; i++) |
926 |
{ |
{ |
927 |
URLLoader loader = (URLLoader) urlinfos.elementAt(i); |
URLLoader loader = (URLLoader) urlinfos.elementAt(i); |
928 |
Resource resource = loader.getResource(resourceName); |
Resource resource = loader.getResource(resourceName); |
929 |
if (resource != null) |
if (resource != null) |
930 |
resources.add(resource.getURL()); |
resources.add(resource.getURL()); |
931 |
} |
} |
932 |
return resources.elements(); |
return resources.elements(); |
933 |
} |
} |
964 |
String protocol = url.getProtocol(); |
String protocol = url.getProtocol(); |
965 |
if (protocol.equals("file")) |
if (protocol.equals("file")) |
966 |
{ |
{ |
967 |
String file = url.getFile(); |
String file = url.getFile(); |
968 |
|
|
969 |
// If the file end in / it must be an directory. |
// If the file end in / it must be an directory. |
970 |
if (file.endsWith("/") || file.endsWith(File.separator)) |
if (file.endsWith("/") || file.endsWith(File.separator)) |
971 |
{ |
{ |
972 |
// Grant permission to read everything in that directory and |
// Grant permission to read everything in that directory and |
973 |
// all subdirectories. |
// all subdirectories. |
974 |
permissions.add(new FilePermission(file + "-", "read")); |
permissions.add(new FilePermission(file + "-", "read")); |
975 |
} |
} |
976 |
else |
else |
977 |
{ |
{ |
978 |
// It is a 'normal' file. |
// It is a 'normal' file. |
979 |
// Grant permission to access that file. |
// Grant permission to access that file. |
980 |
permissions.add(new FilePermission(file, "read")); |
permissions.add(new FilePermission(file, "read")); |
981 |
} |
} |
982 |
} |
} |
983 |
else |
else |
984 |
{ |
{ |
985 |
// Grant permission to connect to and accept connections from host |
// Grant permission to connect to and accept connections from host |
986 |
String host = url.getHost(); |
String host = url.getHost(); |
987 |
if (host != null) |
if (host != null) |
988 |
permissions.add(new SocketPermission(host, "connect,accept")); |
permissions.add(new SocketPermission(host, "connect,accept")); |
989 |
} |
} |
990 |
|
|
991 |
return permissions; |
return permissions; |
1039 |
return new URLClassLoader(urls, parent); |
return new URLClassLoader(urls, parent); |
1040 |
else |
else |
1041 |
{ |
{ |
1042 |
final Object securityContext = sm.getSecurityContext(); |
final Object securityContext = sm.getSecurityContext(); |
1043 |
|
|
1044 |
// XXX - What to do with anything else then an AccessControlContext? |
// XXX - What to do with anything else then an AccessControlContext? |
1045 |
if (! (securityContext instanceof AccessControlContext)) |
if (! (securityContext instanceof AccessControlContext)) |
1046 |
throw new SecurityException("securityContext must be AccessControlContext: " |
throw new SecurityException("securityContext must be AccessControlContext: " |
1047 |
+ securityContext); |
+ securityContext); |
1048 |
|
|
1049 |
URLClassLoader loader = |
URLClassLoader loader = |
1050 |
(URLClassLoader) AccessController.doPrivileged(new PrivilegedAction() |
(URLClassLoader) AccessController.doPrivileged(new PrivilegedAction() |
1051 |
{ |
{ |
1052 |
public Object run() |
public Object run() |
1053 |
{ |
{ |
1054 |
return new URLClassLoader(parent, |
return new URLClassLoader(parent, |
1055 |
(AccessControlContext) securityContext); |
(AccessControlContext) securityContext); |
1056 |
} |
} |
1057 |
}); |
}); |
1058 |
loader.addURLs(urls); |
loader.addURLs(urls); |
1059 |
return loader; |
return loader; |
1060 |
} |
} |
1061 |
} |
} |
1062 |
} |
} |