0N/A/*
2362N/A * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
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
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
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 *
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,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.jndi.ldap;
0N/A
0N/Aimport javax.naming.*;
0N/Aimport javax.naming.directory.*;
0N/Aimport javax.naming.spi.DirectoryManager;
0N/Aimport javax.naming.spi.DirStateFactory;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.io.ByteArrayInputStream;
0N/Aimport java.io.ByteArrayOutputStream;
0N/Aimport java.io.ObjectInputStream;
0N/Aimport java.io.ObjectOutputStream;
0N/Aimport java.io.ObjectStreamClass;
0N/Aimport java.io.InputStream;
0N/A
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.Vector;
0N/Aimport java.util.StringTokenizer;
0N/A
0N/Aimport sun.misc.BASE64Encoder;
0N/Aimport sun.misc.BASE64Decoder;
0N/A
0N/Aimport java.lang.reflect.Proxy;
0N/Aimport java.lang.reflect.Modifier;
0N/A
0N/A/**
0N/A * Class containing static methods and constants for dealing with
0N/A * encoding/decoding JNDI References and Serialized Objects
0N/A * in LDAP.
0N/A * @author Vincent Ryan
0N/A * @author Rosanna Lee
0N/A */
0N/Afinal class Obj {
0N/A
0N/A private Obj () {}; // Make sure no one can create one
0N/A
0N/A // package private; used by Connection
0N/A static VersionHelper helper = VersionHelper.getVersionHelper();
0N/A
0N/A // LDAP attributes used to support Java objects.
0N/A static final String[] JAVA_ATTRIBUTES = {
0N/A "objectClass",
0N/A "javaSerializedData",
0N/A "javaClassName",
0N/A "javaFactory",
0N/A "javaCodeBase",
0N/A "javaReferenceAddress",
0N/A "javaClassNames",
0N/A "javaRemoteLocation" // Deprecated
0N/A };
0N/A
0N/A static final int OBJECT_CLASS = 0;
0N/A static final int SERIALIZED_DATA = 1;
0N/A static final int CLASSNAME = 2;
0N/A static final int FACTORY = 3;
0N/A static final int CODEBASE = 4;
0N/A static final int REF_ADDR = 5;
0N/A static final int TYPENAME = 6;
0N/A /**
0N/A * @deprecated
0N/A */
0N/A private static final int REMOTE_LOC = 7;
0N/A
0N/A // LDAP object classes to support Java objects
0N/A static final String[] JAVA_OBJECT_CLASSES = {
0N/A "javaContainer",
0N/A "javaObject",
0N/A "javaNamingReference",
0N/A "javaSerializedObject",
0N/A "javaMarshalledObject",
0N/A };
0N/A
0N/A static final String[] JAVA_OBJECT_CLASSES_LOWER = {
0N/A "javacontainer",
0N/A "javaobject",
0N/A "javanamingreference",
0N/A "javaserializedobject",
0N/A "javamarshalledobject",
0N/A };
0N/A
0N/A static final int STRUCTURAL = 0; // structural object class
0N/A static final int BASE_OBJECT = 1; // auxiliary java object class
0N/A static final int REF_OBJECT = 2; // auxiliary reference object class
0N/A static final int SER_OBJECT = 3; // auxiliary serialized object class
0N/A static final int MAR_OBJECT = 4; // auxiliary marshalled object class
0N/A
0N/A /**
0N/A * Encode an object in LDAP attributes.
0N/A * Supports binding Referenceable or Reference, Serializable,
0N/A * and DirContext.
0N/A *
0N/A * If the object supports the Referenceable interface then encode
0N/A * the reference to the object. See encodeReference() for details.
0N/A *<p>
0N/A * If the object is serializable, it is stored as follows:
0N/A * javaClassName
0N/A * value: Object.getClass();
0N/A * javaSerializedData
0N/A * value: serialized form of Object (in binary form).
0N/A * javaTypeName
0N/A * value: getTypeNames(Object.getClass());
0N/A */
0N/A private static Attributes encodeObject(char separator,
0N/A Object obj, Attributes attrs,
0N/A Attribute objectClass, boolean cloned)
0N/A throws NamingException {
0N/A boolean structural =
0N/A (objectClass.size() == 0 ||
0N/A (objectClass.size() == 1 && objectClass.contains("top")));
0N/A
0N/A if (structural) {
0N/A objectClass.add(JAVA_OBJECT_CLASSES[STRUCTURAL]);
0N/A }
0N/A
0N/A // References
0N/A if (obj instanceof Referenceable) {
0N/A objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
0N/A objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
0N/A if (!cloned) {
0N/A attrs = (Attributes)attrs.clone();
0N/A }
0N/A attrs.put(objectClass);
0N/A return (encodeReference(separator,
0N/A ((Referenceable)obj).getReference(),
0N/A attrs, obj));
0N/A
0N/A } else if (obj instanceof Reference) {
0N/A objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
0N/A objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
0N/A if (!cloned) {
0N/A attrs = (Attributes)attrs.clone();
0N/A }
0N/A attrs.put(objectClass);
0N/A return (encodeReference(separator, (Reference)obj, attrs, null));
0N/A
0N/A // Serializable Object
0N/A } else if (obj instanceof java.io.Serializable) {
0N/A objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
0N/A if (!(objectClass.contains(JAVA_OBJECT_CLASSES[MAR_OBJECT]) ||
0N/A objectClass.contains(JAVA_OBJECT_CLASSES_LOWER[MAR_OBJECT]))) {
0N/A objectClass.add(JAVA_OBJECT_CLASSES[SER_OBJECT]);
0N/A }
0N/A if (!cloned) {
0N/A attrs = (Attributes)attrs.clone();
0N/A }
0N/A attrs.put(objectClass);
0N/A attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[SERIALIZED_DATA],
0N/A serializeObject(obj)));
0N/A if (attrs.get(JAVA_ATTRIBUTES[CLASSNAME]) == null) {
0N/A attrs.put(JAVA_ATTRIBUTES[CLASSNAME],
0N/A obj.getClass().getName());
0N/A }
0N/A if (attrs.get(JAVA_ATTRIBUTES[TYPENAME]) == null) {
0N/A Attribute tAttr =
0N/A LdapCtxFactory.createTypeNameAttr(obj.getClass());
0N/A if (tAttr != null) {
0N/A attrs.put(tAttr);
0N/A }
0N/A }
0N/A // DirContext Object
0N/A } else if (obj instanceof DirContext) {
0N/A // do nothing
0N/A } else {
0N/A throw new IllegalArgumentException(
0N/A "can only bind Referenceable, Serializable, DirContext");
0N/A }
0N/A // System.err.println(attrs);
0N/A return attrs;
0N/A }
0N/A
0N/A /**
0N/A * Each value in javaCodebase contains a list of space-separated
0N/A * URLs. Each value is independent; we can pick any of the values
0N/A * so we just use the first one.
0N/A * @return an array of URL strings for the codebase
0N/A */
0N/A private static String[] getCodebases(Attribute codebaseAttr) throws
0N/A NamingException {
0N/A if (codebaseAttr == null) {
0N/A return null;
0N/A } else {
0N/A StringTokenizer parser =
0N/A new StringTokenizer((String)codebaseAttr.get());
0N/A Vector vec = new Vector(10);
0N/A while (parser.hasMoreTokens()) {
0N/A vec.addElement(parser.nextToken());
0N/A }
0N/A String[] answer = new String[vec.size()];
0N/A for (int i = 0; i < answer.length; i++) {
0N/A answer[i] = (String)vec.elementAt(i);
0N/A }
0N/A return answer;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Decode an object from LDAP attribute(s).
0N/A * The object may be a Reference, or a Serialized object.
0N/A *
0N/A * See encodeObject() and encodeReference() for details on formats
0N/A * expected.
0N/A */
0N/A static Object decodeObject(Attributes attrs)
0N/A throws NamingException {
0N/A
0N/A Attribute attr;
0N/A
0N/A // Get codebase, which is used in all 3 cases.
0N/A String[] codebases = getCodebases(attrs.get(JAVA_ATTRIBUTES[CODEBASE]));
0N/A try {
0N/A if ((attr = attrs.get(JAVA_ATTRIBUTES[SERIALIZED_DATA])) != null) {
0N/A ClassLoader cl = helper.getURLClassLoader(codebases);
0N/A return deserializeObject((byte[])attr.get(), cl);
0N/A } else if ((attr = attrs.get(JAVA_ATTRIBUTES[REMOTE_LOC])) != null) {
0N/A // For backward compatibility only
0N/A return decodeRmiObject(
0N/A (String)attrs.get(JAVA_ATTRIBUTES[CLASSNAME]).get(),
0N/A (String)attr.get(), codebases);
0N/A }
0N/A
0N/A attr = attrs.get(JAVA_ATTRIBUTES[OBJECT_CLASS]);
0N/A if (attr != null &&
0N/A (attr.contains(JAVA_OBJECT_CLASSES[REF_OBJECT]) ||
0N/A attr.contains(JAVA_OBJECT_CLASSES_LOWER[REF_OBJECT]))) {
0N/A return decodeReference(attrs, codebases);
0N/A }
0N/A return null;
0N/A } catch (IOException e) {
0N/A NamingException ne = new NamingException();
0N/A ne.setRootCause(e);
0N/A throw ne;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Convert a Reference object into several LDAP attributes.
0N/A *
0N/A * A Reference is stored as into the following attributes:
0N/A * javaClassName
0N/A * value: Reference.getClassName();
0N/A * javaFactory
0N/A * value: Reference.getFactoryClassName();
0N/A * javaCodeBase
0N/A * value: Reference.getFactoryClassLocation();
0N/A * javaReferenceAddress
0N/A * value: #0#typeA#valA
0N/A * value: #1#typeB#valB
0N/A * value: #2#typeC##[serialized RefAddr C]
0N/A * value: #3#typeD#valD
0N/A *
0N/A * where
0N/A * - the first character denotes the separator
0N/A * - the number following the first separator denotes the position
0N/A * of the RefAddr within the Reference
0N/A * - "typeA" is RefAddr.getType()
0N/A * - ## denotes that the Base64-encoded form of the non-StringRefAddr
0N/A * is to follow; otherwise the value that follows is
0N/A * StringRefAddr.getContents()
0N/A *
0N/A * The default separator is the hash character (#).
0N/A * May provide property for this in future.
0N/A */
0N/A
0N/A private static Attributes encodeReference(char separator,
0N/A Reference ref, Attributes attrs, Object orig)
0N/A throws NamingException {
0N/A
0N/A if (ref == null)
0N/A return attrs;
0N/A
0N/A String s;
0N/A
0N/A if ((s = ref.getClassName()) != null) {
0N/A attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CLASSNAME], s));
0N/A }
0N/A
0N/A if ((s = ref.getFactoryClassName()) != null) {
0N/A attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[FACTORY], s));
0N/A }
0N/A
0N/A if ((s = ref.getFactoryClassLocation()) != null) {
0N/A attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CODEBASE], s));
0N/A }
0N/A
0N/A // Get original object's types if caller has not explicitly
0N/A // specified other type names
0N/A if (orig != null && attrs.get(JAVA_ATTRIBUTES[TYPENAME]) != null) {
0N/A Attribute tAttr =
0N/A LdapCtxFactory.createTypeNameAttr(orig.getClass());
0N/A if (tAttr != null) {
0N/A attrs.put(tAttr);
0N/A }
0N/A }
0N/A
0N/A int count = ref.size();
0N/A
0N/A if (count > 0) {
0N/A
0N/A Attribute refAttr = new BasicAttribute(JAVA_ATTRIBUTES[REF_ADDR]);
0N/A RefAddr refAddr;
0N/A BASE64Encoder encoder = null;
0N/A
0N/A for (int i = 0; i < count; i++) {
0N/A refAddr = ref.get(i);
0N/A
0N/A if (refAddr instanceof StringRefAddr) {
0N/A refAttr.add(""+ separator + i +
0N/A separator + refAddr.getType() +
0N/A separator + refAddr.getContent());
0N/A } else {
0N/A if (encoder == null)
0N/A encoder = new BASE64Encoder();
0N/A
0N/A refAttr.add(""+ separator + i +
0N/A separator + refAddr.getType() +
0N/A separator + separator +
0N/A encoder.encodeBuffer(serializeObject(refAddr)));
0N/A }
0N/A }
0N/A attrs.put(refAttr);
0N/A }
0N/A return attrs;
0N/A }
0N/A
0N/A /*
0N/A * A RMI object is stored in the directory as
0N/A * javaClassName
0N/A * value: Object.getClass();
0N/A * javaRemoteLocation
0N/A * value: URL of RMI object (accessed through the RMI Registry)
0N/A * javaCodebase:
0N/A * value: URL of codebase of where to find classes for object
0N/A *
0N/A * Return the RMI Location URL itself. This will be turned into
0N/A * an RMI object when getObjectInstance() is called on it.
0N/A * %%% Ignore codebase for now. Depend on RMI registry to send code.-RL
0N/A * @deprecated For backward compatibility only
0N/A */
0N/A private static Object decodeRmiObject(String className,
0N/A String rmiName, String[] codebases) throws NamingException {
0N/A return new Reference(className, new StringRefAddr("URL", rmiName));
0N/A }
0N/A
0N/A /*
0N/A * Restore a Reference object from several LDAP attributes
0N/A */
0N/A private static Reference decodeReference(Attributes attrs,
0N/A String[] codebases) throws NamingException, IOException {
0N/A
0N/A Attribute attr;
0N/A String className;
0N/A String factory = null;
0N/A
0N/A if ((attr = attrs.get(JAVA_ATTRIBUTES[CLASSNAME])) != null) {
0N/A className = (String)attr.get();
0N/A } else {
0N/A throw new InvalidAttributesException(JAVA_ATTRIBUTES[CLASSNAME] +
0N/A " attribute is required");
0N/A }
0N/A
0N/A if ((attr = attrs.get(JAVA_ATTRIBUTES[FACTORY])) != null) {
0N/A factory = (String)attr.get();
0N/A }
0N/A
0N/A Reference ref = new Reference(className, factory,
0N/A (codebases != null? codebases[0] : null));
0N/A
0N/A /*
0N/A * string encoding of a RefAddr is either:
0N/A *
0N/A * #posn#<type>#<address>
0N/A * or
0N/A * #posn#<type>##<base64-encoded address>
0N/A */
0N/A if ((attr = attrs.get(JAVA_ATTRIBUTES[REF_ADDR])) != null) {
0N/A
0N/A String val, posnStr, type;
0N/A char separator;
0N/A int start, sep, posn;
0N/A BASE64Decoder decoder = null;
0N/A
0N/A ClassLoader cl = helper.getURLClassLoader(codebases);
0N/A
0N/A /*
0N/A * Temporary Vector for decoded RefAddr addresses - used to ensure
0N/A * unordered addresses are correctly re-ordered.
0N/A */
0N/A Vector refAddrList = new Vector();
0N/A refAddrList.setSize(attr.size());
0N/A
0N/A for (NamingEnumeration vals = attr.getAll(); vals.hasMore(); ) {
0N/A
0N/A val = (String)vals.next();
0N/A
0N/A if (val.length() == 0) {
0N/A throw new InvalidAttributeValueException(
0N/A "malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - "+
0N/A "empty attribute value");
0N/A }
0N/A // first character denotes encoding separator
0N/A separator = val.charAt(0);
0N/A start = 1; // skip over separator
0N/A
0N/A // extract position within Reference
0N/A if ((sep = val.indexOf(separator, start)) < 0) {
0N/A throw new InvalidAttributeValueException(
0N/A "malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
0N/A "separator '" + separator + "'" + "not found");
0N/A }
0N/A if ((posnStr = val.substring(start, sep)) == null) {
0N/A throw new InvalidAttributeValueException(
0N/A "malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
0N/A "empty RefAddr position");
0N/A }
0N/A try {
0N/A posn = Integer.parseInt(posnStr);
0N/A } catch (NumberFormatException nfe) {
0N/A throw new InvalidAttributeValueException(
0N/A "malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
0N/A "RefAddr position not an integer");
0N/A }
0N/A start = sep + 1; // skip over position and trailing separator
0N/A
0N/A // extract type
0N/A if ((sep = val.indexOf(separator, start)) < 0) {
0N/A throw new InvalidAttributeValueException(
0N/A "malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
0N/A "RefAddr type not found");
0N/A }
0N/A if ((type = val.substring(start, sep)) == null) {
0N/A throw new InvalidAttributeValueException(
0N/A "malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
0N/A "empty RefAddr type");
0N/A }
0N/A start = sep + 1; // skip over type and trailing separator
0N/A
0N/A // extract content
0N/A if (start == val.length()) {
0N/A // Empty content
0N/A refAddrList.setElementAt(new StringRefAddr(type, null), posn);
0N/A } else if (val.charAt(start) == separator) {
0N/A // Double separators indicate a non-StringRefAddr
0N/A // Content is a Base64-encoded serialized RefAddr
0N/A
0N/A ++start; // skip over consecutive separator
0N/A // %%% RL: exception if empty after double separator
0N/A
0N/A if (decoder == null)
0N/A decoder = new BASE64Decoder();
0N/A
0N/A RefAddr ra = (RefAddr)
0N/A deserializeObject(
0N/A decoder.decodeBuffer(val.substring(start)),
0N/A cl);
0N/A
0N/A refAddrList.setElementAt(ra, posn);
0N/A } else {
0N/A // Single separator indicates a StringRefAddr
0N/A refAddrList.setElementAt(new StringRefAddr(type,
0N/A val.substring(start)), posn);
0N/A }
0N/A }
0N/A
0N/A // Copy to real reference
0N/A for (int i = 0; i < refAddrList.size(); i++) {
0N/A ref.add((RefAddr)refAddrList.elementAt(i));
0N/A }
0N/A }
0N/A
0N/A return (ref);
0N/A }
0N/A
0N/A /*
0N/A * Serialize an object into a byte array
0N/A */
0N/A private static byte[] serializeObject(Object obj) throws NamingException {
0N/A
0N/A try {
0N/A ByteArrayOutputStream bytes = new ByteArrayOutputStream();
0N/A ObjectOutputStream serial = new ObjectOutputStream(bytes);
0N/A serial.writeObject(obj);
0N/A serial.close();
0N/A
0N/A return (bytes.toByteArray());
0N/A
0N/A } catch (IOException e) {
0N/A NamingException ne = new NamingException();
0N/A ne.setRootCause(e);
0N/A throw ne;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Deserializes a byte array into an object.
0N/A */
0N/A private static Object deserializeObject(byte[] obj, ClassLoader cl)
0N/A throws NamingException {
0N/A
0N/A try {
0N/A // Create ObjectInputStream for deserialization
0N/A ByteArrayInputStream bytes = new ByteArrayInputStream(obj);
0N/A ObjectInputStream deserial = (cl == null ?
0N/A new ObjectInputStream(bytes) :
0N/A new LoaderInputStream(bytes, cl));
0N/A
0N/A try {
0N/A return deserial.readObject();
0N/A } catch (ClassNotFoundException e) {
0N/A NamingException ne = new NamingException();
0N/A ne.setRootCause(e);
0N/A throw ne;
0N/A } finally {
0N/A deserial.close();
0N/A }
0N/A } catch (IOException e) {
0N/A NamingException ne = new NamingException();
0N/A ne.setRootCause(e);
0N/A throw ne;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the attributes to bind given an object and its attributes.
0N/A */
0N/A static Attributes determineBindAttrs(
0N/A char separator, Object obj, Attributes attrs, boolean cloned,
0N/A Name name, Context ctx, Hashtable env)
0N/A throws NamingException {
0N/A
0N/A // Call state factories to convert object and attrs
0N/A DirStateFactory.Result res =
0N/A DirectoryManager.getStateToBind(obj, name, ctx, env, attrs);
0N/A obj = res.getObject();
0N/A attrs = res.getAttributes();
0N/A
0N/A // We're only storing attributes; no further processing required
0N/A if (obj == null) {
0N/A return attrs;
0N/A }
0N/A
0N/A //if object to be bound is a DirContext extract its attributes
0N/A if ((attrs == null) && (obj instanceof DirContext)) {
0N/A cloned = true;
0N/A attrs = ((DirContext)obj).getAttributes("");
0N/A }
0N/A
0N/A boolean ocNeedsCloning = false;
0N/A
0N/A // Create "objectClass" attribute
0N/A Attribute objectClass;
0N/A if (attrs == null || attrs.size() == 0) {
0N/A attrs = new BasicAttributes(LdapClient.caseIgnore);
0N/A cloned = true;
0N/A
0N/A // No objectclasses supplied, use "top" to start
0N/A objectClass = new BasicAttribute("objectClass", "top");
0N/A
0N/A } else {
0N/A // Get existing objectclass attribute
0N/A objectClass = (Attribute)attrs.get("objectClass");
0N/A if (objectClass == null && !attrs.isCaseIgnored()) {
0N/A // %%% workaround
0N/A objectClass = (Attribute)attrs.get("objectclass");
0N/A }
0N/A
0N/A // No objectclasses supplied, use "top" to start
0N/A if (objectClass == null) {
0N/A objectClass = new BasicAttribute("objectClass", "top");
0N/A } else if (ocNeedsCloning || !cloned) {
0N/A objectClass = (Attribute)objectClass.clone();
0N/A }
0N/A }
0N/A
0N/A // convert the supplied object into LDAP attributes
0N/A attrs = encodeObject(separator, obj, attrs, objectClass, cloned);
0N/A
0N/A // System.err.println("Determined: " + attrs);
0N/A return attrs;
0N/A }
0N/A
0N/A /**
0N/A * An ObjectInputStream that uses a class loader to find classes.
0N/A */
0N/A private static final class LoaderInputStream extends ObjectInputStream {
0N/A private ClassLoader classLoader;
0N/A
0N/A LoaderInputStream(InputStream in, ClassLoader cl) throws IOException {
0N/A super(in);
0N/A classLoader = cl;
0N/A }
0N/A
0N/A protected Class resolveClass(ObjectStreamClass desc) throws IOException,
0N/A ClassNotFoundException {
0N/A try {
0N/A // %%% Should use Class.forName(desc.getName(), false, classLoader);
0N/A // except we can't because that is only available on JDK1.2
0N/A return classLoader.loadClass(desc.getName());
0N/A } catch (ClassNotFoundException e) {
0N/A return super.resolveClass(desc);
0N/A }
0N/A }
0N/A
0N/A protected Class resolveProxyClass(String[] interfaces) throws
0N/A IOException, ClassNotFoundException {
0N/A ClassLoader nonPublicLoader = null;
0N/A boolean hasNonPublicInterface = false;
0N/A
0N/A // define proxy in class loader of non-public interface(s), if any
0N/A Class[] classObjs = new Class[interfaces.length];
0N/A for (int i = 0; i < interfaces.length; i++) {
0N/A Class cl = Class.forName(interfaces[i], false, classLoader);
0N/A if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
0N/A if (hasNonPublicInterface) {
0N/A if (nonPublicLoader != cl.getClassLoader()) {
0N/A throw new IllegalAccessError(
0N/A "conflicting non-public interface class loaders");
0N/A }
0N/A } else {
0N/A nonPublicLoader = cl.getClassLoader();
0N/A hasNonPublicInterface = true;
0N/A }
0N/A }
0N/A classObjs[i] = cl;
0N/A }
0N/A try {
0N/A return Proxy.getProxyClass(hasNonPublicInterface ?
0N/A nonPublicLoader : classLoader, classObjs);
0N/A } catch (IllegalArgumentException e) {
0N/A throw new ClassNotFoundException(null, e);
0N/A }
0N/A }
0N/A
0N/A }
0N/A}