Hi David,

A quick test with this new fix, but hit a classloading problem like this:

Caused by: java.lang.LinkageError: loading constraint violation: loader "org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader@3b0c3b0c" previously initiated loading for a different type with name "org/omg/CORBA/ValueDefPackage/FullValueDescription" defined by loader "com/ibm/oti/vm/BootstrapClassLoader@547d547d"
    at org.apache.yoko.rmi.impl.TypeRepository.getDescriptor(TypeRepository.java:338)
    at org.apache.yoko.rmi.impl.ValueHandlerImpl.desc(ValueHandlerImpl.java:55)
    at org.apache.yoko.rmi.impl.ValueHandlerImpl.readValue0(ValueHandlerImpl.java:91)
    at org.apache.yoko.rmi.impl.ValueHandlerImpl.readValue(ValueHandlerImpl.java:76)
    at org.apache.yoko.orb.OB.ValueReader.readRMIValue(ValueReader.java:969)
    at org.apache.yoko.orb.OB.ValueReader$FactoryCreationStrategy.create(ValueReader.java:299)
    at org.apache.yoko.orb.OB.ValueReader.readValueAny(ValueReader.java:1549)
    at org.apache.yoko.orb.CORBA.InputStream.read_value(InputStream.java:1916)
    at org.apache.yoko.orb.CORBA.Any.readValue(Any.java:210)
    at org.apache.yoko.orb.CORBA.Any.read_value(Any.java:505)
    at org.apache.yoko.orb.CORBA.InputStream.read_any(InputStream.java:1806)
    at org.apache.yoko.rmi.impl.UtilImpl.readAny(UtilImpl.java:309)
    at org.apache.geronimo.corba.util.UtilDelegateImpl.readAny(UtilDelegateImpl.java:111)
    at javax.rmi.CORBA.Util.readAny(Util.java:95)
    at org.apache.yoko.rmi.impl.AnyDescriptor.read(AnyDescriptor.java:36)
    at org.apache.yoko.rmi.impl.MethodDescriptor.readResult(MethodDescriptor.java:274)
    at org.apache.yoko.rmi.impl.RMIStubHandler.invoke(RMIStubHandler.java:79)
    at org.apache.geronimo.yoko.RMIStubHandler.invoke(RMIStubHandler.java:45)
    ... 51 more

Forrest
On Wed, Aug 3, 2011 at 8:42 AM, <djencks@apache.org> wrote:
Author: djencks
Date: Wed Aug  3 00:42:03 2011
New Revision: 1153313

URL: http://svn.apache.org/viewvc?rev=1153313&view=rev
Log:
YOKO-434 better implementation of figuring out if remote objects were custom marshalled

Modified:
   geronimo/yoko/trunk/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java
   geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FVDValueDescriptor.java
   geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java
   geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java
   geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/ClassLoaderLocal.java

Modified: geronimo/yoko/trunk/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java
URL: http://svn.apache.org/viewvc/geronimo/yoko/trunk/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java?rev=1153313&r1=1153312&r2=1153313&view=diff
==============================================================================
--- geronimo/yoko/trunk/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java (original)
+++ geronimo/yoko/trunk/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java Wed Aug  3 00:42:03 2011
@@ -71,7 +71,7 @@ final public class ValueReader {

        String[] ids;

-        ChunkState state;
+        final ChunkState state;

        Header next; // Java only
        String codebase; // Java only

Modified: geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FVDValueDescriptor.java
URL: http://svn.apache.org/viewvc/geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FVDValueDescriptor.java?rev=1153313&r1=1153312&r2=1153313&view=diff
==============================================================================
--- geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FVDValueDescriptor.java (original)
+++ geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FVDValueDescriptor.java Wed Aug  3 00:42:03 2011
@@ -20,6 +20,7 @@ package org.apache.yoko.rmi.impl;
 import org.omg.CORBA.AttributeDescription;
 import org.omg.CORBA.TypeCode;
 import org.omg.CORBA.ValueDefPackage.FullValueDescription;
+import org.omg.CORBA.ValueMember;

 /**
 * @author krab
@@ -44,24 +45,24 @@ public class FVDValueDescriptor extends
    public void init() {
        super.init();

-        // iverride custom loading
-        if (!fvd.is_custom) {
-            _read_object_method = null;
-            _write_object_method = null;
-            _is_externalizable = false;
-        }
-
-        AttributeDescription[] atts = fvd.attributes;
-        FieldDescriptor[] new_fields = new FieldDescriptor[atts.length];
-        for (int i = 0; i < atts.length; i++) {
-            AttributeDescription att = atts[i];
-            new_fields[i] = findField(att);
+        // don't override custom loading. Our local version could work differently.
+//        if (!fvd.is_custom) {
+//            _read_object_method = null;
+//            _write_object_method = null;
+//            _is_externalizable = false;
+//        }
+
+        ValueMember[] members = fvd.members;
+        FieldDescriptor[] new_fields = new FieldDescriptor[members.length];
+        for (int i = 0; i < members.length; i++) {
+            ValueMember valueMember = members[i];
+            new_fields[i] = findField(valueMember);
        }

        _fields = new_fields;
    }

-    FieldDescriptor findField(AttributeDescription att) {
+    FieldDescriptor findField(ValueMember valueMember) {
        FieldDescriptor result = null;

        for (Class c = getJavaClass(); c != null; c = c.getSuperclass()) {
@@ -75,7 +76,7 @@ public class FVDValueDescriptor extends
                }

                for (int i = 0; i < fds.length; i++) {
-                    if (fds[i].getIDLName().equals(att.name)) {
+                    if (fds[i].getIDLName().equals(valueMember.name)) {
                        return fds[0];
                    }
                }
@@ -103,7 +104,7 @@ public class FVDValueDescriptor extends
     *
     * @see org.apache.yoko.rmi.impl.TypeDescriptor#getTypeCode()
     */
-    TypeCode getTypeCode() {
+    public TypeCode getTypeCode() {
        return fvd.type;
    }


Modified: geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java
URL: http://svn.apache.org/viewvc/geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java?rev=1153313&r1=1153312&r2=1153313&view=diff
==============================================================================
--- geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java (original)
+++ geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java Wed Aug  3 00:42:03 2011
@@ -18,6 +18,8 @@

 package org.apache.yoko.rmi.impl;

+import java.lang.reflect.Method;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Logger;
 import java.util.logging.Level;

@@ -37,76 +39,58 @@ public class TypeRepository {

    org.omg.CORBA.ORB orb;

-    java.util.Map classMap = new java.util.HashMap();
+    java.util.Map<Class, TypeDescriptor> classMap = new ConcurrentHashMap<Class, TypeDescriptor> ();

-    java.util.Map repidMap = new java.util.HashMap();
+    java.util.Map<String, TypeDescriptor> repidMap = new ConcurrentHashMap<String, TypeDescriptor>();

    public TypeRepository(org.omg.CORBA.ORB orb) {
        this.orb = orb;
-        init();
-    }
-
-    org.omg.CORBA.ORB getORB() {
-        return orb;
-    }
-
-    void init() {
        TypeDescriptor desc;

        desc = new AnyDescriptor(java.lang.Object.class, this);
-        synchronized (desc) {
-            classMap.put(java.lang.Object.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(java.lang.Object.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);

        desc = new AnyDescriptor(java.lang.Object.class, this);
-        synchronized (desc) {
-            classMap.put(java.lang.Object.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(java.lang.Object.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);

        desc = new StringDescriptor(this);
-        synchronized (desc) {
-            classMap.put(String.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(String.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);

        desc = new ClassDescriptor(this);
-        synchronized (desc) {
-            classMap.put(Class.class, desc);
-            classMap.put(javax.rmi.CORBA.ClassDesc.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(Class.class, desc);
+        classMap.put(javax.rmi.CORBA.ClassDesc.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);

        desc = new DateValueDescriptor(this);
-        synchronized (desc) {
-            classMap.put(java.util.Date.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(java.util.Date.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);
+
        desc = new AnyDescriptor(java.io.Externalizable.class, this);
-        synchronized (desc) {
-            classMap.put(java.io.Externalizable.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(java.io.Externalizable.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);

        desc = new AnyDescriptor(java.io.Serializable.class, this);
-        synchronized (desc) {
-            classMap.put(java.io.Serializable.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(java.io.Serializable.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);
+
        desc = new AnyDescriptor(java.rmi.Remote.class, this);
-        synchronized (desc) {
-            classMap.put(java.rmi.Remote.class, desc);
-            desc.init();
-            repidMap.put(desc.getRepositoryID(), desc);
-        }
+        classMap.put(java.rmi.Remote.class, desc);
+        desc.init();
+        repidMap.put(desc.getRepositoryID(), desc);
+    }
+
+    org.omg.CORBA.ORB getORB() {
+        return orb;
    }

    public String getRepositoryID(Class type) {
@@ -143,8 +127,8 @@ public class TypeRepository {
    }

    public TypeDescriptor getDescriptor(Class type) {
-        logger.fine("Requesting type descriptor for class " + type.getName());
-        TypeDescriptor desc = (TypeDescriptor) classMap.get(type);
+        logger.fine("Requesting type descriptor for class " + type.getName());
+        TypeDescriptor desc = classMap.get(type);

        if (desc != null) {
            return desc.getSelf();
@@ -154,33 +138,25 @@ public class TypeRepository {
                && isIDLEntity(type)) {
            IDLEntityDescriptor idlDesc = new IDLEntityDescriptor(type, this);
            desc = idlDesc;
-            synchronized (desc) {
-                classMap.put(type, desc);
-                idlDesc.initIDL();
-            }
+            classMap.put(type, desc);
+            idlDesc.initIDL();
        } else if (java.lang.Throwable.class.isAssignableFrom(type)) {
            desc = new ExceptionDescriptor(type, this);
-            synchronized (desc) {
-                classMap.put(type, desc);
-                desc.init();
-                repidMap.put(desc.getRepositoryID(), desc);
-            }
+            classMap.put(type, desc);
+            desc.init();
+            repidMap.put(desc.getRepositoryID(), desc);

        } else if (type.isArray()) {
            desc = ArrayDescriptor.get(type, this);
-            synchronized (desc) {
-                classMap.put(type, desc);
-                desc.init();
-                repidMap.put(desc.getRepositoryID(), desc);
-            }
+            classMap.put(type, desc);
+            desc.init();
+            repidMap.put(desc.getRepositoryID(), desc);
        } else if (!type.isInterface()
                && java.io.Serializable.class.isAssignableFrom(type)) {
            desc = new ValueDescriptor(type, this);
-            synchronized (desc) {
-                classMap.put(type, desc);
-                desc.init();
-                repidMap.put(desc.getRepositoryID(), desc);
-            }
+            classMap.put(type, desc);
+            desc.init();
+            repidMap.put(desc.getRepositoryID(), desc);
        } else if (java.rmi.Remote.class.isAssignableFrom(type)) {
            if (type.isInterface()) {
                desc = new RemoteInterfaceDescriptor(type, this);
@@ -188,17 +164,13 @@ public class TypeRepository {
                desc = new RemoteClassDescriptor(type, this);
            }

-            synchronized (desc) {
-                classMap.put(type, desc);
-                desc.init();
-                repidMap.put(desc.getRepositoryID(), desc);
-            }
+            classMap.put(type, desc);
+            desc.init();
+            repidMap.put(desc.getRepositoryID(), desc);
        } else if (type.isPrimitive()) {
            desc = getSimpleDescriptor(type);
-            synchronized (desc) {
-                classMap.put(type, desc);
-                repidMap.put(desc.getRepositoryID(), desc);
-            }
+            classMap.put(type, desc);
+            repidMap.put(desc.getRepositoryID(), desc);

        } else if (Object.class.isAssignableFrom(type)) {
            if (isAbstractInterface(type)) {
@@ -212,24 +184,18 @@ public class TypeRepository {
                desc = new ValueDescriptor(type, this);
            }

-            synchronized (desc) {
-                classMap.put(type, desc);
-                desc.init();
-                repidMap.put(desc.getRepositoryID(), desc);
-            }
+            classMap.put(type, desc);
+            desc.init();
+            repidMap.put(desc.getRepositoryID(), desc);

        } else {
            throw new RuntimeException("cannot handle class " + type.getName());
        }
-
-        logger.fine("Class " + type.getName() + " resolves to " + desc.getClass().getName());
+
+        logger.fine("Class " + type.getName() + " resolves to " + desc.getClass().getName());
        return desc;
    }

-    /**
-     * @param type
-     * @return
-     */
    private boolean isIDLEntity(Class type) {
        Class[] supers = type.getInterfaces();

@@ -293,14 +259,14 @@ public class TypeRepository {
            return false;

        Class[] interfaces = type.getInterfaces();
-        for (int i = 0; i < interfaces.length; i++) {
-            if (!isAbstractInterface(interfaces[i]))
+        for (Class anInterface : interfaces) {
+            if (!isAbstractInterface(anInterface))
                return false;
        }

        java.lang.reflect.Method[] methods = type.getDeclaredMethods();
-        for (int j = 0; j < methods.length; j++) {
-            if (!isRemoteMethod(methods[j]))
+        for (Method method : methods) {
+            if (!isRemoteMethod(method))
                return false;
        }

@@ -310,8 +276,8 @@ public class TypeRepository {
    boolean isRemoteMethod(java.lang.reflect.Method m) {
        Class[] ex = m.getExceptionTypes();

-        for (int i = 0; i < ex.length; i++) {
-            if (ex[i].isAssignableFrom(REMOTE_EXCEPTION))
+        for (Class anEx : ex) {
+            if (anEx.isAssignableFrom(REMOTE_EXCEPTION))
                return true;
        }

@@ -319,28 +285,32 @@ public class TypeRepository {
    }

    /**
-     * @param repid
+     * @param clz (local) class we are interested in
+     * @param repid  repository id from GIOP input for the remote class
+     * @param runtime way to look up the complete remote descriptor
     * @return ValueDescriptor
+     * @throws ClassNotFoundException  something might go wrong.
     */
    public ValueDescriptor getDescriptor(Class clz, String repid,
            RunTime runtime) throws ClassNotFoundException {
-        // ValueDescriptor desc = null;
-        ValueDescriptor clzdesc = null;
+        if (repid == null) {
+            return (ValueDescriptor) getDescriptor(clz);
+        }
+
+        ValueDescriptor clzdesc = (ValueDescriptor) repidMap.get(repid);
+        if (clzdesc != null) {
+            return clzdesc;
+        }

        if (clz != null) {
            logger.fine("Requesting type descriptor for class " + clz.getName() + " with repid " + repid);
-            ValueDescriptor desc = (ValueDescriptor)classMap.get(clz);
-            if (desc != null) {
-                return desc;
-            }
-            // special handling for array value types.
+            // special handling for array value types.
            if (clz.isArray()) {
-                desc = ArrayDescriptor.get(clz, this);
-                synchronized (desc) {
-                    classMap.put(clz, desc);
-                    desc.init();
-                    repidMap.put(desc.getRepositoryID(), desc);
-                }
+                //TODO don't we need to look up the FVD for the array element?
+                ValueDescriptor desc = ArrayDescriptor.get(clz, this);
+                classMap.put(clz, desc);
+                desc.init();
+                repidMap.put(desc.getRepositoryID(), desc);
                return desc;
            }
            clzdesc = (ValueDescriptor) getDescriptor(clz);
@@ -349,33 +319,14 @@ public class TypeRepository {
            if (repid.equals(localID)) {
                return clzdesc;
            }
-
-            // we have a mismatch.  We'll accept this if the class name and the
-            // serial version id are the same (ignoring the hash portion of the id);
-            String localClassName = localID.substring(0, localID.indexOf(':'));
-            String remoteClassName = repid.substring(0, repid.indexOf(':'));
-
-            String localSUID = localID.substring(localID.lastIndexOf(':'));
-            String remoteSUID = repid.substring(repid.lastIndexOf(':'));
-
-            // compare the CORBA hash codes, and allow this to work
-            if (localClassName.equals(remoteClassName) && localSUID.equals(remoteSUID)) {
-                logger.fine("mismatching repository ids accepted because of matching name and SUID.  local: " + clzdesc.getRepositoryID() + "; remote: " + repid);
-                return clzdesc;
-            }
-
-            logger.fine("mismatching repository ids. local: "
-                    + clzdesc.getRepositoryID() + "; remote: " + repid);
+            //One might think that java serialization compatibility (same SerialVersionUID) would mean corba
+            //serialization compatibility.  However, one implementation might have a writeObject method and the
+            //other implementation not.  This is recorded only in the isCustomMarshall of the source value
+            //descriptor, so we have to fetch it to find out.  A custom marshall value has a couple extra bytes
+            // and padding and these can't be reliably identified without this remote info.  cf YOKO-434.
        }

        logger.fine("Requesting type descriptor for repid " + repid);
-        if (repid != null) {
-            clzdesc = (ValueDescriptor) repidMap.get(repid);
-            if (clzdesc != null) {
-                return clzdesc;
-            }
-        }
-
        CodeBase codebase = CodeBaseHelper.narrow(runtime);
        if (codebase == null) {
            throw new MARSHAL("cannot locate RunTime CodeBase");
@@ -385,7 +336,7 @@ public class TypeRepository {

        ValueDescriptor super_desc = null;
        if (!"".equals(fvd.base_value)) {
-            super_desc = getDescriptor(clz.getSuperclass(), fvd.base_value,
+            super_desc = getDescriptor(clz == null? null: clz.getSuperclass(), fvd.base_value,
                    codebase);
        }

@@ -475,14 +426,14 @@ public class TypeRepository {
            int len = current.length();
            match = false;

-            for (int i = 0; i < reservedPostfixes.length; i++) {
-                if (current.endsWith(reservedPostfixes[i])) {
+            for (ByteString reservedPostfixe : reservedPostfixes) {
+                if (current.endsWith(reservedPostfixe)) {
                    ByteBuffer buf = new ByteBuffer();
                    buf.append('_');
                    buf.append(result);
                    result = buf.toByteString();

-                    int resultLen = reservedPostfixes[i].length();
+                    int resultLen = reservedPostfixe.length();
                    if (len > resultLen)
                        current = current.substring(0, len - resultLen);
                    else
@@ -498,7 +449,7 @@ public class TypeRepository {
        return name;
    }

-    static final java.util.Set keyWords = new java.util.HashSet();
+    static final java.util.Set<ByteString> keyWords = new java.util.HashSet<ByteString>();

    static final ByteString[] reservedPostfixes = new ByteString[] {
            new ByteString("Helper"), new ByteString("Holder"),
@@ -519,8 +470,8 @@ public class TypeRepository {
                "toString", "transient", "true", "try", "void", "volatile",
                "wait", "while" };

-        for (int i = 0; i < words.length; i++) {
-            keyWords.add(new ByteString(words[i]));
+        for (String word : words) {
+            keyWords.add(new ByteString(word));
        }
    }


Modified: geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java
URL: http://svn.apache.org/viewvc/geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java?rev=1153313&r1=1153312&r2=1153313&view=diff
==============================================================================
--- geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java (original)
+++ geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java Wed Aug  3 00:42:03 2011
@@ -818,7 +818,7 @@ public class ValueDescriptor extends Typ

        // System.out.println ("readValue "+getJavaClass());

-        if (_write_object_method != null) {
+        if (isCustomMarshalled()) {

            // read custom marshalling value header
            byte streamFormatVersion = reader.readByte();
@@ -967,7 +967,8 @@ public class ValueDescriptor extends Typ
                getJavaClass().getName(), getRepositoryID(), false, // is_abstract
                isCustomMarshalled(), "", "1.0",
                new org.omg.CORBA.OperationDescription[0],
-                new org.omg.CORBA.AttributeDescription[0], getValueMembers(),
+                new org.omg.CORBA.AttributeDescription[0],
+                getValueMembers(),
                new org.omg.CORBA.Initializer[0], new String[0], new String[0],
                false, // is_truncatable
                (_super_descriptor == null ? "" : _super_descriptor

Modified: geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/ClassLoaderLocal.java
URL: http://svn.apache.org/viewvc/geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/ClassLoaderLocal.java?rev=1153313&r1=1153312&r2=1153313&view=diff
==============================================================================
--- geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/ClassLoaderLocal.java (original)
+++ geronimo/yoko/trunk/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/ClassLoaderLocal.java Wed Aug  3 00:42:03 2011
@@ -86,7 +86,7 @@ public class ClassLoaderLocal {

    // table for tracking the CL to map relationships.  We're
    // using a WeakHashMap to prevent us pinning class loaders.
-    static private WeakHashMap localMaps = new WeakHashMap();
+    static final private WeakHashMap localMaps = new WeakHashMap();

    private ClassLocalMap getLoaderLocalMap() {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();