Lines 49-60
Link Here
|
49 |
import java.io.IOException; |
49 |
import java.io.IOException; |
50 |
import java.io.InputStream; |
50 |
import java.io.InputStream; |
51 |
import java.io.OutputStream; |
51 |
import java.io.OutputStream; |
52 |
import java.lang.reflect.Field; |
52 |
import java.lang.reflect.Method; |
|
|
53 |
import java.net.JarURLConnection; |
53 |
import java.net.MalformedURLException; |
54 |
import java.net.MalformedURLException; |
54 |
import java.net.URL; |
55 |
import java.net.URL; |
55 |
import java.net.URLConnection; |
|
|
56 |
import java.net.URLStreamHandler; |
56 |
import java.net.URLStreamHandler; |
57 |
import java.net.URLStreamHandlerFactory; |
|
|
58 |
import java.security.CodeSource; |
57 |
import java.security.CodeSource; |
59 |
import java.security.PermissionCollection; |
58 |
import java.security.PermissionCollection; |
60 |
import java.security.Policy; |
59 |
import java.security.Policy; |
Lines 111-134
Link Here
|
111 |
} |
110 |
} |
112 |
|
111 |
|
113 |
static { |
112 |
static { |
114 |
ResURLStreamHandlerFactory fact = new ResURLStreamHandlerFactory(); |
113 |
ProxyURLStreamHandlerFactory.register(); |
115 |
try { |
|
|
116 |
java.net.URL.setURLStreamHandlerFactory(fact); |
117 |
} catch (Error e) { |
118 |
try { |
119 |
for (Field f : URL.class.getDeclaredFields()) { |
120 |
if (f.getType() == URLStreamHandlerFactory.class) { |
121 |
f.setAccessible(true); |
122 |
fact.del = (URLStreamHandlerFactory)f.get(null); |
123 |
f.set(null, null); |
124 |
break; |
125 |
} |
126 |
} |
127 |
URL.setURLStreamHandlerFactory(fact); |
128 |
} catch (Throwable t) { |
129 |
throw new InternalError(); // can't really continue |
130 |
} |
131 |
} |
132 |
} |
114 |
} |
133 |
|
115 |
|
134 |
private static final Logger LOGGER = Logger.getLogger(JarClassLoader.class.getName()); |
116 |
private static final Logger LOGGER = Logger.getLogger(JarClassLoader.class.getName()); |
Lines 343-348
Link Here
|
343 |
sources.put(f.toURI().toString(), src); |
325 |
sources.put(f.toURI().toString(), src); |
344 |
return src; |
326 |
return src; |
345 |
} |
327 |
} |
|
|
328 |
|
329 |
@Override |
330 |
public String toString() { |
331 |
return url.toString(); |
332 |
} |
333 |
|
346 |
} |
334 |
} |
347 |
|
335 |
|
348 |
static class JarSource extends Source { |
336 |
static class JarSource extends Source { |
Lines 356-362
Link Here
|
356 |
|
344 |
|
357 |
JarSource(File file) throws IOException { |
345 |
JarSource(File file) throws IOException { |
358 |
super(file.toURL()); |
346 |
super(file.toURL()); |
359 |
resPrefix = ResURLStreamHandler.RES_PROTO +":" + file.toURI() + "!/"; // NOI18N; |
347 |
resPrefix = "jar:" + file.toURI() + "!/"; // NOI18N; |
360 |
this.file = file; |
348 |
this.file = file; |
361 |
} |
349 |
} |
362 |
|
350 |
|
Lines 665-692
Link Here
|
665 |
return known; |
653 |
return known; |
666 |
} |
654 |
} |
667 |
|
655 |
|
668 |
private static class ResURLStreamHandlerFactory implements URLStreamHandlerFactory { |
|
|
669 |
URLStreamHandlerFactory del; |
670 |
/** |
671 |
* Creates URLStreamHandler for nbinst protocol |
672 |
* @param protocol |
673 |
* @return NbinstURLStreamHandler if the protocol is nbinst otherwise null |
674 |
*/ |
675 |
public URLStreamHandler createURLStreamHandler(String protocol) { |
676 |
if (ResURLStreamHandler.RES_PROTO.equals(protocol)) { |
677 |
return new ResURLStreamHandler (); |
678 |
} |
679 |
return del != null ? del.createURLStreamHandler(protocol): null; |
680 |
} |
681 |
} |
682 |
|
683 |
/** |
656 |
/** |
684 |
* URLStreamHandler for res protocol |
657 |
* URLStreamHandler for res protocol |
685 |
*/ |
658 |
*/ |
686 |
private static class ResURLStreamHandler extends URLStreamHandler { |
659 |
static class ResURLStreamHandler extends URLStreamHandler { |
687 |
public static final String RES_PROTO = "nbjcl"; |
|
|
688 |
|
660 |
|
689 |
ResURLStreamHandler() {} |
661 |
private final URLStreamHandler originalJarHandler; |
|
|
662 |
|
663 |
ResURLStreamHandler(URLStreamHandler originalJarHandler) { |
664 |
this.originalJarHandler = originalJarHandler; |
665 |
} |
690 |
|
666 |
|
691 |
/** |
667 |
/** |
692 |
* Creates URLConnection for URL with res protocol. |
668 |
* Creates URLConnection for URL with res protocol. |
Lines 694-825
Link Here
|
694 |
* @return URLConnection |
670 |
* @return URLConnection |
695 |
* @throws IOException |
671 |
* @throws IOException |
696 |
*/ |
672 |
*/ |
697 |
protected URLConnection openConnection(URL u) throws IOException { |
673 |
protected JarURLConnection openConnection(URL u) throws IOException { |
698 |
String url = u.getFile();//toExternalForm(); |
674 |
String url = u.getFile();//toExternalForm(); |
699 |
int bang = url.indexOf("!/"); |
675 |
int bang = url.indexOf("!/"); |
700 |
String jar = url.substring(0, bang); |
676 |
String jar = url.substring(0, bang); |
701 |
String _name = url.substring(bang+2); |
677 |
String _name = url.substring(bang+2); |
702 |
Source _src = Source.sources.get(jar); |
678 |
Source _src = Source.sources.get(jar); |
703 |
if (_src == null) { |
679 |
if (_src == null) { |
704 |
String replace = u.toExternalForm().replaceAll("nbjcl:", "jar:"); |
680 |
try { |
705 |
|
681 |
Method m = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class); |
706 |
if (archive.isActive()) { |
682 |
m.setAccessible(true); |
707 |
LOGGER.log(Level.WARNING, "Cannot find {0} in current sources", jar); |
683 |
return (JarURLConnection) m.invoke(originalJarHandler, u); |
708 |
if (LOGGER.isLoggable(Level.FINER)) { |
684 |
} catch (Exception e) { |
709 |
LOGGER.log(Level.FINER, dumpSources(Source.sources, jar)); |
685 |
throw (IOException) new IOException(e.toString()).initCause(e); |
710 |
} |
|
|
711 |
LOGGER.log(Level.WARNING, "Trying {0} instead", replace); |
712 |
LOGGER.log(Level.WARNING, "Disabling class cache"); |
713 |
archive.stopServing(); |
714 |
} |
686 |
} |
715 |
return new URL(replace).openConnection(); |
|
|
716 |
} |
687 |
} |
717 |
return new ResURLConnection (u, _src, _name); |
688 |
return new ResURLConnection (u, _src, _name); |
718 |
} |
689 |
} |
719 |
|
690 |
|
720 |
protected @Override void parseURL(URL url, String spec, |
|
|
721 |
int start, int limit) { |
722 |
String file = null; |
723 |
String ref = null; |
724 |
// first figure out if there is an anchor |
725 |
int refPos = spec.indexOf('#', limit); |
726 |
boolean refOnly = refPos == start; |
727 |
if (refPos > -1) { |
728 |
ref = spec.substring(refPos + 1, spec.length()); |
729 |
if (refOnly) { |
730 |
file = url.getFile(); |
731 |
} |
732 |
} |
733 |
// then figure out if the spec is |
734 |
// 1. absolute (res:) |
735 |
// 2. relative (i.e. url + foo/bar/baz.ext) |
736 |
// 3. anchor-only (i.e. url + #foo), which we already did (refOnly) |
737 |
boolean absoluteSpec = false; |
738 |
if (spec.length() >= RES_PROTO.length()+1) { |
739 |
absoluteSpec = spec.substring(0, RES_PROTO.length()+1).equalsIgnoreCase(RES_PROTO+":"); |
740 |
} |
741 |
spec = spec.substring(start, limit); |
742 |
|
743 |
if (absoluteSpec) { |
744 |
file = parseAbsoluteSpec(spec); |
745 |
} else if (!refOnly) { |
746 |
file = parseContextSpec(url, spec); |
747 |
|
748 |
// Canonize the result after the bangslash |
749 |
int bangSlash = file.lastIndexOf("!/") + 1; |
750 |
String toBangSlash = file.substring(0, bangSlash); |
751 |
String afterBangSlash = file.substring(bangSlash); |
752 |
sun.net.www.ParseUtil canonizer = new sun.net.www.ParseUtil(); // XXX |
753 |
afterBangSlash = canonizer.canonizeString(afterBangSlash); |
754 |
file = toBangSlash + afterBangSlash; |
755 |
} |
756 |
setURLOK(url, file, ref); |
757 |
} |
758 |
|
759 |
private static String dumpSources(Map<String, Source> sources, String jar) { |
760 |
StringBuilder sb = new StringBuilder(); |
761 |
sb.append("Searching for ").append(jar).append("\nwhile available:\n"); |
762 |
for (Map.Entry<String, Source> entry : sources.entrySet()) { |
763 |
sb.append(entry.getKey()).append('\n'); |
764 |
} |
765 |
|
766 |
return sb.toString(); |
767 |
} |
768 |
|
769 |
@SuppressWarnings("deprecation") |
770 |
private void setURLOK(URL url, String file, String ref) { |
771 |
super.setURL(url, RES_PROTO, "", -1, file, ref); |
772 |
} |
773 |
|
774 |
private String parseAbsoluteSpec(String spec) { |
775 |
URL url = null; |
776 |
int index = -1; |
777 |
// check for !/ |
778 |
if ((index = spec.lastIndexOf("!/") + 1) == -1) { |
779 |
throw new NullPointerException("no !/ in spec"); |
780 |
} |
781 |
// test the inner URL |
782 |
try { |
783 |
String innerSpec = spec.substring(0, index - 1); |
784 |
url = new URL(innerSpec); |
785 |
} catch (MalformedURLException e) { |
786 |
throw new NullPointerException("invalid url: " + |
787 |
spec + " (" + e + ")"); |
788 |
} |
789 |
return spec; |
790 |
} |
791 |
|
792 |
private String parseContextSpec(URL url, String spec) { |
793 |
String ctxFile = url.getFile(); |
794 |
// if the spec begins with /, chop up the jar back !/ |
795 |
if (spec.startsWith("/")) { |
796 |
int bangSlash = ctxFile.lastIndexOf("!/"); |
797 |
if (bangSlash == -1) { |
798 |
throw new NullPointerException("malformed " + |
799 |
"context url:" + |
800 |
url + |
801 |
": no !/"); |
802 |
} |
803 |
ctxFile = ctxFile.substring(0, bangSlash+1); |
804 |
} |
805 |
if (!ctxFile.endsWith("/") && (!spec.startsWith("/"))){ |
806 |
// chop up the last component |
807 |
int lastSlash = ctxFile.lastIndexOf('/'); |
808 |
if (lastSlash == -1) { |
809 |
throw new NullPointerException("malformed " + |
810 |
"context url:" + |
811 |
url); |
812 |
} |
813 |
ctxFile = ctxFile.substring(0, lastSlash + 1); |
814 |
} |
815 |
return (ctxFile + spec); |
816 |
} |
817 |
} |
691 |
} |
818 |
|
692 |
|
819 |
/** URLConnection for URL with res protocol. |
693 |
/** URLConnection for URL with res protocol. |
820 |
* |
694 |
* |
821 |
*/ |
695 |
*/ |
822 |
private static class ResURLConnection extends URLConnection { |
696 |
private static class ResURLConnection extends JarURLConnection { |
823 |
private JarSource src; |
697 |
private JarSource src; |
824 |
private String name; |
698 |
private String name; |
825 |
private byte[] data; |
699 |
private byte[] data; |
Lines 830-836
Link Here
|
830 |
* @param url the parameter for which the connection should be |
704 |
* @param url the parameter for which the connection should be |
831 |
* created |
705 |
* created |
832 |
*/ |
706 |
*/ |
833 |
private ResURLConnection(URL url, Source src, String name) { |
707 |
private ResURLConnection(URL url, Source src, String name) throws MalformedURLException { |
834 |
super(url); |
708 |
super(url); |
835 |
this.src = (JarSource)src; |
709 |
this.src = (JarSource)src; |
836 |
this.name = name; |
710 |
this.name = name; |
Lines 870-874
Link Here
|
870 |
if (iStream == null) iStream = new ByteArrayInputStream(data); |
744 |
if (iStream == null) iStream = new ByteArrayInputStream(data); |
871 |
return iStream; |
745 |
return iStream; |
872 |
} |
746 |
} |
|
|
747 |
|
748 |
@Override |
749 |
public JarFile getJarFile() throws IOException { |
750 |
return src.jar; |
751 |
} |
873 |
} |
752 |
} |
874 |
} |
753 |
} |