Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.management.rmi/share/classes/javax/management/remote/rmi/NoCallStackClassLoader.java
41162 views
1
/*
2
* Copyright (c) 2003, 2015, 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. The JMX Remote API
35
defines exactly what class loader must be used to deserialize arguments on
36
the server, and return values on the client. We communicate this class
37
loader to RMI by setting it as the context class loader. RMI uses the
38
context class loader to load classes as it deserializes, which is what we
39
want. However, before consulting the context class loader, it
40
looks up the call stack for a class with a non-null class loader,
41
and uses that if it finds one. So, in the standalone version of
42
javax.management.remote, if the class you're looking for is known
43
to the loader of jmxremote.jar (typically the system class loader)
44
then that loader will load it. This contradicts the class-loading
45
semantics required.
46
47
<p>We get around the problem by ensuring that the search up the
48
call stack will find a non-null class loader that doesn't load any
49
classes of interest, namely this one. So even though this loader
50
is indeed consulted during deserialization, it never finds the
51
class being deserialized. RMI then proceeds to use the context
52
class loader, as we require.
53
54
<p>This loader is constructed with the name and byte-code of one
55
or more classes that it defines, and a class-loader to which it
56
will delegate certain other classes required by that byte-code.
57
We construct the byte-code somewhat painstakingly, by compiling
58
the Java code directly, converting into a string, copying that
59
string into the class that needs this loader, and using the
60
stringToBytes method to convert it into the byte array. We
61
compile with -g:none because there's not much point in having
62
line-number information and the like in these directly-encoded
63
classes.
64
65
<p>The referencedClassNames should contain the names of all
66
classes that are referenced by the classes defined by this loader.
67
It is not necessary to include standard J2SE classes, however.
68
Here, a class is referenced if it is the superclass or a
69
superinterface of a defined class, or if it is the type of a
70
field, parameter, or return value. A class is not referenced if
71
it only appears in the throws clause of a method or constructor.
72
Of course, referencedClassNames should not contain any classes
73
that the user might want to deserialize, because the whole point
74
of this loader is that it does not find such classes.
75
*/
76
77
class NoCallStackClassLoader extends ClassLoader {
78
/** Simplified constructor when this loader only defines one class. */
79
public NoCallStackClassLoader(String className,
80
byte[] byteCode,
81
String[] referencedClassNames,
82
ClassLoader referencedClassLoader,
83
ProtectionDomain protectionDomain) {
84
this(new String[] {className}, new byte[][] {byteCode},
85
referencedClassNames, referencedClassLoader, protectionDomain);
86
}
87
88
public NoCallStackClassLoader(String[] classNames,
89
byte[][] byteCodes,
90
String[] referencedClassNames,
91
ClassLoader referencedClassLoader,
92
ProtectionDomain protectionDomain) {
93
super(null);
94
95
/* Validation. */
96
if (classNames == null || classNames.length == 0
97
|| byteCodes == null || classNames.length != byteCodes.length
98
|| referencedClassNames == null || protectionDomain == null)
99
throw new IllegalArgumentException();
100
for (int i = 0; i < classNames.length; i++) {
101
if (classNames[i] == null || byteCodes[i] == null)
102
throw new IllegalArgumentException();
103
}
104
for (int i = 0; i < referencedClassNames.length; i++) {
105
if (referencedClassNames[i] == null)
106
throw new IllegalArgumentException();
107
}
108
109
this.classNames = classNames;
110
this.byteCodes = byteCodes;
111
this.referencedClassNames = referencedClassNames;
112
this.referencedClassLoader = referencedClassLoader;
113
this.protectionDomain = protectionDomain;
114
}
115
116
/* This method is called at most once per name. Define the name
117
* if it is one of the classes whose byte code we have, or
118
* delegate the load if it is one of the referenced classes.
119
*/
120
@Override
121
protected Class<?> findClass(String name) throws ClassNotFoundException {
122
// Note: classNames is guaranteed by the constructor to be non-null.
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
*/
297
298