Applet Class Loader Problems

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Applet Class Loader Problems

moodycl

I am having a problem loading classes when my applet reconnects to the backup server after a network failure. My messages are taking a very long time to be processed and I think that it is because the ClassLoadingAwareObjectInputStream is still trying to connect to the original server that served up the applet.

I think that the ClassLoadingAwareObjectInputStream is still referencing the original classloader URL and has to wait for that request to timeout before it falls to the backup classloader. Another strange thing is that this appears to only be happening for the primitive types. (int, boolean, etc.) I have not yet seen it fail for any other class.

I have several threads blocked waiting for an ActiveMQ Session Task to release it's lock.
I have included the stacktrace.

Name: ActiveMQ Session Task-96
State: RUNNABLE
Total blocked: 19  Total waited: 77

Stack trace:
 java.net.TwoStacksPlainSocketImpl.socketConnect(Native Method)
java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
   - locked java.net.TwoStacksPlainSocketImpl@1dcac73
java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
java.net.AbstractPlainSocketImpl.connect(Unknown Source)
java.net.PlainSocketImpl.connect(Unknown Source)
java.net.SocksSocketImpl.connect(Unknown Source)
java.net.Socket.connect(Unknown Source)
sun.security.ssl.SSLSocketImpl.connect(Unknown Source)
sun.net.NetworkClient.doConnect(Unknown Source)
sun.net.www.http.HttpClient.openServer(Unknown Source)
sun.net.www.http.HttpClient.openServer(Unknown Source)
   - locked sun.net.www.protocol.https.HttpsClient@bdc77d
sun.net.www.protocol.https.HttpsClient.<init>(Unknown Source)
sun.net.www.protocol.https.HttpsClient.New(Unknown Source)
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
   - locked sun.net.www.protocol.https.DelegateHttpsURLConnection@1c204d7
java.net.HttpURLConnection.getResponseCode(Unknown Source)
sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
sun.plugin2.applet.Applet2ClassLoader.getBytes(Unknown Source)
sun.plugin2.applet.Applet2ClassLoader.access$000(Unknown Source)
sun.plugin2.applet.Applet2ClassLoader$1.run(Unknown Source)
java.security.AccessController.doPrivileged(Native Method)
sun.plugin2.applet.Applet2ClassLoader.findClass(Unknown Source)
sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source)
sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
   - locked sun.plugin2.applet.Applet2ClassLoader@1fe96f2
sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
   - locked sun.plugin2.applet.Applet2ClassLoader@1fe96f2
java.lang.ClassLoader.loadClass(Unknown Source)
java.lang.Class.forName0(Native Method)
java.lang.Class.forName(Unknown Source)
org.apache.activemq.util.ClassLoadingAwareObjectInputStream.load(ClassLoadingAwareObjectInputStream.java:77)
org.apache.activemq.util.ClassLoadingAwareObjectInputStream.resolveClass(ClassLoadingAwareObjectInputStream.java:46)
java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
java.io.ObjectInputStream.readClassDesc(Unknown Source)
java.io.ObjectInputStream.readClass(Unknown Source)
java.io.ObjectInputStream.readObject0(Unknown Source)
java.io.ObjectInputStream.readArray(Unknown Source)
java.io.ObjectInputStream.readObject0(Unknown Source)
java.io.ObjectInputStream.defaultReadFields(Unknown Source)
java.io.ObjectInputStream.readSerialData(Unknown Source)
java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
java.io.ObjectInputStream.readObject0(Unknown Source)
java.io.ObjectInputStream.defaultReadFields(Unknown Source)
java.io.ObjectInputStream.readSerialData(Unknown Source)
java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
java.io.ObjectInputStream.readObject0(Unknown Source)
java.io.ObjectInputStream.readObject(Unknown Source)
org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:185)
com.mypackage.MyClass$2.processObjectMessage(MyClass.java:386)
com.mypackage.JMSMessageProcessor.onMessage(JMSMessageProcessor.java:29)
   - locked com.mypackage.MyClass$2@9595d2
org.apache.activemq.ActiveMQMessageConsumer.dispatch(ActiveMQMessageConsumer.java:1321)
   - locked java.lang.Object@40c537
org.apache.activemq.ActiveMQSessionExecutor.dispatch(ActiveMQSessionExecutor.java:131)
org.apache.activemq.ActiveMQSessionExecutor.iterate(ActiveMQSessionExecutor.java:202)
org.apache.activemq.thread.PooledTaskRunner.runTask(PooledTaskRunner.java:129)
org.apache.activemq.thread.PooledTaskRunner$1.run(PooledTaskRunner.java:47)
java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
java.lang.Thread.run(Unknown Source)

Reply | Threaded
Open this post in threaded view
|

Re: Applet Class Loader Problems

moodycl
This post was updated on .
I think I have found the problem. In ClassLoadingAwareObjectInputStream.java the  load() method makes a call to Class.forName().

For the primitive types (int, boolean, etc.) this would result in a call similar to:
    Class.forName("int", false, loader); //Where loader is the Applet2ClassLoader

Since Applet2ClassLoader is a URLClassLoader and "int.class" is not in the jar cache it pulled down from the server at the start of application, it is going to try and go to the server to resolve this class.
In the event of a network failure, this will result in the ClassLoader having to wait for the socket timeout. (see stacktrace in previous post) Once this socket timeout occurs, the load() method then attempts to lookup the class in the primitive HashMap that is statically initialized. This returns the class for the int and the deserialization continues on.

At first it seemed like the messages were failing to be received but it turned out they were just taking a very long time to be deserialized. This problem can be avoided by changing the order in which ClassLoadingAwareObjectInputStream tries to resolve the class. Here is the change I made to the load() method:

Please let me know how I can go about getting this incorporated into the ActiveMQ trunk. Thanks.

private Class<?> load(String className, ClassLoader... cl) throws ClassNotFoundException {
    //Check to see if this is a primitive first
    final Class<?> clazz = (Class<?>) primClasses.get(className);
    if (clazz != null) {
        return clazz; //return the primitive class found in the map
    } else {
        for (ClassLoader loader : cl) {
            try {
                return Class.forName(className, false, loader); //for applets this may be a URLClassLoader
            } catch (Exception ex) {
                // ignore
            }
        }
        //if we still haven't found the class, use the fallback
        return Class.forName(className, false, FALLBACK_CLASS_LOADER);
    }
}
Reply | Threaded
Open this post in threaded view
|

Re: Applet Class Loader Problems

tabish121@gmail.com
On 09/26/2013 10:16 AM, moodycl wrote:

> I think I have found the problem. In ClassLoadingAwareObjectInputStream.java
> the  load() method makes a call to Class.forName().
>
> For the primitive types (int, boolean, etc.) this would result in a call
> similar to:
>      Class.forName("int", false, loader); //Where loader is the
> Applet2ClassLoader
>
> Since Applet2ClassLoader is a URLClassLoader and "int.class" is not in the
> jar cache it pulled down from the server at the start of application, it is
> going to try and go to the server to resolve this class.
> In the event of a network failure, this will result in the ClassLoader
> having to wait for the socket timeout. (see stacktrace in previous post)
> Once this socket timeout occurs, the load() method then attempts to lookup
> the class in the primitive HashMap that is statically initialized. This
> returns the class for the int and the deserialization continues on.
>
> At first it seemed like the messages were failing to be received but it
> turned out they were just taking a very long time to be deserialized. This
> problem can be avoided by changing the order in which
> ClassLoadingAwareObjectInputStream tries to resolve the class. Here is the
> change I made to the load() method:
>
> Please let me know how I can o about getting this incorporated into the
> ActiveMQ trunk. Thanks.
>
> private Class<?> load(String className, ClassLoader... cl) throws
> ClassNotFoundException {
>      //Check to see if this is a primitive first
>      final Class<?> clazz = (Class<?>) primClasses.get(className);
>      if (clazz != null) {
>          return clazz; //return the primitive class found in the map
>      } else {
>          for (ClassLoader loader : cl) {
>              try {
>                  return Class.forName(className, false, loader); //for
> applets this may be a URLClassLoader
>              } catch (Exception ex) {
>                  // ignore
>              }
>          }
>          //if we still haven't found the class, use the fallback
>          return Class.forName(className, false, FALLBACK_CLASS_LOADER);
>      }
> }
>
>
>
>
> --
> View this message in context: http://activemq.2283324.n4.nabble.com/Applet-Class-Loader-Problems-tp4671835p4671856.html
> Sent from the ActiveMQ - User mailing list archive at Nabble.com.
>
To get fixes into the broker you need to create a new Jira issue
documenting the bug you think you've found and then attach a patch with
a fix along with a unit test to demonstrate the issue and show that it
is now fixed.  Once done someone from the team can review and apply the
patch once its been verified.

--
Tim Bish
Sr Software Engineer | RedHat Inc.
[hidden email] | www.fusesource.com | www.redhat.com
skype: tabish121 | twitter: @tabish121
blog: http://timbish.blogspot.com/