2273N/A * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 0N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 1472N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A * or visit www.oracle.com if you need additional information or have any 1879N/A <p>A class loader that only knows how to define a limited number 0N/A of classes, and load a limited number of other classes through 0N/A delegation to another loader. It is used to get around a problem 0N/A with Serialization, in particular as used by RMI (including 0N/A RMI/IIOP). The JMX Remote API defines exactly what class loader 0N/A must be used to deserialize arguments on the server, and return 0N/A values on the client. We communicate this class loader to RMI by 0N/A setting it as the context class loader. RMI uses the context 0N/A class loader to load classes as it deserializes, which is what we 0N/A want. However, before consulting the context class loader, it 0N/A looks up the call stack for a class with a non-null class loader, 0N/A and uses that if it finds one. So, in the standalone version of 0N/A javax.management.remote, if the class you're looking for is known 0N/A to the loader of jmxremote.jar (typically the system class loader) 0N/A then that loader will load it. This contradicts the class-loading 0N/A <p>We get around the problem by ensuring that the search up the 0N/A call stack will find a non-null class loader that doesn't load any 0N/A classes of interest, namely this one. So even though this loader 0N/A is indeed consulted during deserialization, it never finds the 0N/A class being deserialized. RMI then proceeds to use the context 0N/A class loader, as we require. 0N/A <p>This loader is constructed with the name and byte-code of one 0N/A or more classes that it defines, and a class-loader to which it 0N/A will delegate certain other classes required by that byte-code. 0N/A We construct the byte-code somewhat painstakingly, by compiling 0N/A the Java code directly, converting into a string, copying that 0N/A string into the class that needs this loader, and using the 0N/A stringToBytes method to convert it into the byte array. We 0N/A compile with -g:none because there's not much point in having 0N/A line-number information and the like in these directly-encoded 0N/A <p>The referencedClassNames should contain the names of all 0N/A classes that are referenced by the classes defined by this loader. 0N/A It is not necessary to include standard J2SE classes, however. 0N/A Here, a class is referenced if it is the superclass or a 0N/A superinterface of a defined class, or if it is the type of a 0N/A field, parameter, or return value. A class is not referenced if 0N/A it only appears in the throws clause of a method or constructor. 0N/A Of course, referencedClassNames should not contain any classes 0N/A that the user might want to deserialize, because the whole point 0N/A of this loader is that it does not find such classes. 0N/A /** Simplified constructor when this loader only defines one class. */ 0N/A /* This method is called at most once per name. Define the name 0N/A * if it is one of the classes whose byte code we have, or 0N/A * delegate the load if it is one of the referenced classes. 0N/A /* If the referencedClassLoader is null, it is the bootstrap 0N/A * class loader, and there's no point in delegating to it 0N/A * because it's already our parent class loader. 0N/A * <p>Construct a <code>byte[]</code> using the characters of the 0N/A * given <code>String</code>. Only the low-order byte of each 0N/A * character is used. This method is useful to reduce the 0N/A * footprint of classes that include big byte arrays (e.g. the 0N/A * byte code of other classes), because a string takes up much 0N/A * less space in a class file than the byte code to initialize a 0N/A * <code>byte[]</code> with the same number of bytes.</p> 0N/A * <p>We use just one byte per character even though characters 0N/A * contain two bytes. The resultant output length is much the 0N/A * same: using one byte per character is shorter because it has 0N/A * more characters in the optimal 1-127 range but longer because 0N/A * it has more zero bytes (which are frequent, and are encoded as 0N/A * two bytes in classfile UTF-8). But one byte per character has 0N/A * two key advantages: (1) you can see the string constants, which 0N/A * is reassuring, (2) you don't need to know whether the class 0N/A * file length is odd.</p> 0N/A * <p>This method differs from {@link String#getBytes()} in that 0N/A * it does not use any encoding. So it is guaranteed that each 0N/A * byte of the result is numerically identical (mod 256) to the 0N/A * corresponding character of the input. You can use the following Emacs function to convert class files into strings to be used by the stringToBytes method above. Select the whole (defun...) with the mouse and type M-x eval-region, or save it to a file and do M-x load-file. Then visit the *.class file and do ;; visit the *.class file with emacs, then invoke this function "Construct a Java string whose bytes are the same as the current buffer. The resultant string is put in a buffer called *string*, possibly with a numeric suffix like <2>. From there it can be insert-buffer'd into a Java program." (let* ((s (buffer-string)) (buf (generate-new-buffer "*string*"))) (if (> (current-column) 61) ((> c 126) (format "\\%o" c)) (let ((nextc (if (< (1+ i) slen) ((and (<= nextc ?7) (>= nextc ?0)) Alternatively, the following class reads a class file and outputs a string that can be used by the stringToBytes method above. import java.io.FileInputStream; import java.io.IOException; public class BytesToString { public static void main(String[] args) throws IOException { File f = new File(args[0]); int len = (int)f.length(); byte[] classBytes = new byte[len]; FileInputStream in = new FileInputStream(args[0]); int n = in.read(classBytes, pos, (len-pos)); throw new RuntimeException("class file changed??"); boolean lastWasOctal = false; for (int i=0; i<len; i++) { int value = classBytes[i]; if ((value >= 32 && value < 127) && ((!lastWasOctal || (value < '0' || value > '7')))) { s = Character.toString((char)value); s = "\\" + Integer.toString(value, 8); System.out.println("\"");