History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/management/remote/rmi/NoCallStackClassLoader.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/management/remote/rmi/NoCallStackClassLoader.java+296−0
@@ -0,0 +1,296 @@
1+/*
2+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package javax.management.remote.rmi;
27+
28+import java.security.ProtectionDomain;
29+
30+/**
31+ <p>A class loader that only knows how to define a limited number
32+ of classes, and load a limited number of other classes through
33+ delegation to another loader. It is used to get around a problem
34+ with Serialization, in particular as used by RMI (including
35+ RMI/IIOP). The JMX Remote API defines exactly what class loader
36+ must be used to deserialize arguments on the server, and return
37+ values on the client. We communicate this class loader to RMI by
38+ setting it as the context class loader. RMI uses the context
39+ class loader to load classes as it deserializes, which is what we
40+ want. However, before consulting the context class loader, it
41+ looks up the call stack for a class with a non-null class loader,
42+ and uses that if it finds one. So, in the standalone version of
43+ javax.management.remote, if the class you're looking for is known
44+ to the loader of jmxremote.jar (typically the system class loader)
45+ then that loader will load it. This contradicts the class-loading
46+ semantics required.
47+
48+ <p>We get around the problem by ensuring that the search up the
49+ call stack will find a non-null class loader that doesn't load any
50+ classes of interest, namely this one. So even though this loader
51+ is indeed consulted during deserialization, it never finds the
52+ class being deserialized. RMI then proceeds to use the context
53+ class loader, as we require.
54+
55+ <p>This loader is constructed with the name and byte-code of one
56+ or more classes that it defines, and a class-loader to which it
57+ will delegate certain other classes required by that byte-code.
58+ We construct the byte-code somewhat painstakingly, by compiling
59+ the Java code directly, converting into a string, copying that
60+ string into the class that needs this loader, and using the
61+ stringToBytes method to convert it into the byte array. We
62+ compile with -g:none because there's not much point in having
63+ line-number information and the like in these directly-encoded
64+ classes.
65+
66+ <p>The referencedClassNames should contain the names of all
67+ classes that are referenced by the classes defined by this loader.
68+ It is not necessary to include standard J2SE classes, however.
69+ Here, a class is referenced if it is the superclass or a
70+ superinterface of a defined class, or if it is the type of a
71+ field, parameter, or return value. A class is not referenced if
72+ it only appears in the throws clause of a method or constructor.
73+ Of course, referencedClassNames should not contain any classes
74+ that the user might want to deserialize, because the whole point
75+ of this loader is that it does not find such classes.
76+*/
77+
78+class NoCallStackClassLoader extends ClassLoader {
79+ /** Simplified constructor when this loader only defines one class. */
80+ public NoCallStackClassLoader(String className,
81+ byte[] byteCode,
82+ String[] referencedClassNames,
83+ ClassLoader referencedClassLoader,
84+ ProtectionDomain protectionDomain) {
85+ this(new String[] {className}, new byte[][] {byteCode},
86+ referencedClassNames, referencedClassLoader, protectionDomain);
87+ }
88+
89+ public NoCallStackClassLoader(String[] classNames,
90+ byte[][] byteCodes,
91+ String[] referencedClassNames,
92+ ClassLoader referencedClassLoader,
93+ ProtectionDomain protectionDomain) {
94+ super(null);
95+
96+ /* Validation. */
97+ if (classNames == null || classNames.length == 0
98+ || byteCodes == null || classNames.length != byteCodes.length
99+ || referencedClassNames == null || protectionDomain == null)
100+ throw new IllegalArgumentException();
101+ for (int i = 0; i < classNames.length; i++) {
102+ if (classNames[i] == null || byteCodes[i] == null)
103+ throw new IllegalArgumentException();
104+ }
105+ for (int i = 0; i < referencedClassNames.length; i++) {
106+ if (referencedClassNames[i] == null)
107+ throw new IllegalArgumentException();
108+ }
109+
110+ this.classNames = classNames;
111+ this.byteCodes = byteCodes;
112+ this.referencedClassNames = referencedClassNames;
113+ this.referencedClassLoader = referencedClassLoader;
114+ this.protectionDomain = protectionDomain;
115+ }
116+
117+ /* This method is called at most once per name. Define the name
118+ * if it is one of the classes whose byte code we have, or
119+ * delegate the load if it is one of the referenced classes.
120+ */
121+ @Override
122+ protected Class<?> findClass(String name) throws ClassNotFoundException {
123+ for (int i = 0; i < classNames.length; i++) {
124+ if (name.equals(classNames[i])) {
125+ return defineClass(classNames[i], byteCodes[i], 0,
126+ byteCodes[i].length, protectionDomain);
127+ }
128+ }
129+
130+ /* If the referencedClassLoader is null, it is the bootstrap
131+ * class loader, and there's no point in delegating to it
132+ * because it's already our parent class loader.
133+ */
134+ if (referencedClassLoader != null) {
135+ for (int i = 0; i < referencedClassNames.length; i++) {
136+ if (name.equals(referencedClassNames[i]))
137+ return referencedClassLoader.loadClass(name);
138+ }
139+ }
140+
141+ throw new ClassNotFoundException(name);
142+ }
143+
144+ private final String[] classNames;
145+ private final byte[][] byteCodes;
146+ private final String[] referencedClassNames;
147+ private final ClassLoader referencedClassLoader;
148+ private final ProtectionDomain protectionDomain;
149+
150+ /**
151+ * <p>Construct a <code>byte[]</code> using the characters of the
152+ * given <code>String</code>. Only the low-order byte of each
153+ * character is used. This method is useful to reduce the
154+ * footprint of classes that include big byte arrays (e.g. the
155+ * byte code of other classes), because a string takes up much
156+ * less space in a class file than the byte code to initialize a
157+ * <code>byte[]</code> with the same number of bytes.</p>
158+ *
159+ * <p>We use just one byte per character even though characters
160+ * contain two bytes. The resultant output length is much the
161+ * same: using one byte per character is shorter because it has
162+ * more characters in the optimal 1-127 range but longer because
163+ * it has more zero bytes (which are frequent, and are encoded as
164+ * two bytes in classfile UTF-8). But one byte per character has
165+ * two key advantages: (1) you can see the string constants, which
166+ * is reassuring, (2) you don't need to know whether the class
167+ * file length is odd.</p>
168+ *
169+ * <p>This method differs from {@link String#getBytes()} in that
170+ * it does not use any encoding. So it is guaranteed that each
171+ * byte of the result is numerically identical (mod 256) to the
172+ * corresponding character of the input.
173+ */
174+ public static byte[] stringToBytes(String s) {
175+ final int slen = s.length();
176+ byte[] bytes = new byte[slen];
177+ for (int i = 0; i < slen; i++)
178+ bytes[i] = (byte) s.charAt(i);
179+ return bytes;
180+ }
181+}
182+
183+/*
184+
185+You can use the following Emacs function to convert class files into
186+strings to be used by the stringToBytes method above. Select the
187+whole (defun...) with the mouse and type M-x eval-region, or save it
188+to a file and do M-x load-file. Then visit the *.class file and do
189+M-x class-string.
190+
191+;; class-string.el
192+;; visit the *.class file with emacs, then invoke this function
193+
194+(defun class-string ()
195+ "Construct a Java string whose bytes are the same as the current
196+buffer. The resultant string is put in a buffer called *string*,
197+possibly with a numeric suffix like <2>. From there it can be
198+insert-buffer'd into a Java program."
199+ (interactive)
200+ (let* ((s (buffer-string))
201+ (slen (length s))
202+ (i 0)
203+ (buf (generate-new-buffer "*string*")))
204+ (set-buffer buf)
205+ (insert "\"")
206+ (while (< i slen)
207+ (if (> (current-column) 61)
208+ (insert "\"+\n\""))
209+ (let ((c (aref s i)))
210+ (insert (cond
211+ ((> c 126) (format "\\%o" c))
212+ ((= c ?\") "\\\"")
213+ ((= c ?\\) "\\\\")
214+ ((< c 33)
215+ (let ((nextc (if (< (1+ i) slen)
216+ (aref s (1+ i))
217+ ?\0)))
218+ (cond
219+ ((and (<= nextc ?7) (>= nextc ?0))
220+ (format "\\%03o" c))
221+ (t
222+ (format "\\%o" c)))))
223+ (t c))))
224+ (setq i (1+ i)))
225+ (insert "\"")
226+ (switch-to-buffer buf)))
227+
228+Alternatively, the following class reads a class file and outputs a string
229+that can be used by the stringToBytes method above.
230+
231+import java.io.File;
232+import java.io.FileInputStream;
233+import java.io.IOException;
234+
235+public class BytesToString {
236+
237+ public static void main(String[] args) throws IOException {
238+ File f = new File(args[0]);
239+ int len = (int)f.length();
240+ byte[] classBytes = new byte[len];
241+
242+ FileInputStream in = new FileInputStream(args[0]);
243+ try {
244+ int pos = 0;
245+ for (;;) {
246+ int n = in.read(classBytes, pos, (len-pos));
247+ if (n < 0)
248+ throw new RuntimeException("class file changed??");
249+ pos += n;
250+ if (pos >= n)
251+ break;
252+ }
253+ } finally {
254+ in.close();
255+ }
256+
257+ int pos = 0;
258+ boolean lastWasOctal = false;
259+ for (int i=0; i<len; i++) {
260+ int value = classBytes[i];
261+ if (value < 0)
262+ value += 256;
263+ String s = null;
264+ if (value == '\\')
265+ s = "\\\\";
266+ else if (value == '\"')
267+ s = "\\\"";
268+ else {
269+ if ((value >= 32 && value < 127) && ((!lastWasOctal ||
270+ (value < '0' || value > '7')))) {
271+ s = Character.toString((char)value);
272+ }
273+ }
274+ if (s == null) {
275+ s = "\\" + Integer.toString(value, 8);
276+ lastWasOctal = true;
277+ } else {
278+ lastWasOctal = false;
279+ }
280+ if (pos > 61) {
281+ System.out.print("\"");
282+ if (i<len)
283+ System.out.print("+");
284+ System.out.println();
285+ pos = 0;
286+ }
287+ if (pos == 0)
288+ System.out.print(" \"");
289+ System.out.print(s);
290+ pos += s.length();
291+ }
292+ System.out.println("\"");
293+ }
294+}
295+
296+*/