-
Bug
-
Resolution: Won't Fix
-
P4
-
None
-
7
-
generic
-
generic
SYNOPSIS
--------
MBean server throws unexpected exceptions when Notification is set with thread-unsafe data
OPERATING SYSTEM
----------------
All
FULL JDK VERSION
----------------
All releases of Java 6
PROBLEM DESCRIPTION from LICENSEE
---------------------------------
In an application set-up where an MBean server has 2 or more listeners, as soon as notification is fired, all the listeners will be relayed the notification object through serialization simultaneously. Because the serialization happens simultaneously, this causes problems if thread-unsafe data is used in the Notification object.
For example, if the Notification object is set with Calendar object as userData, on the MBean client side while the data is being deserialized, the following Exception can be thrown intermittently:
Exception in thread "ClientNotifForwarder-1" java.lang.ClassCastException: java.util.SimpleTimeZone incompatible with sun.util.calendar.ZoneInfo
at java.util.Calendar$1.run(Calendar.java:2665)
at java.util.Calendar$1.run(Calendar.java:2663)
at java.security.AccessController.doPrivileged(AccessController.java:284)
at java.util.Calendar.readObject(Calendar.java:2662)
at sun.reflect.GeneratedMethodAccessor60.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:986)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1865)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:493)
at javax.management.Notification.readObject(Notification.java:364)
at sun.reflect.GeneratedMethodAccessor58.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:986)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1865)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1887)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1683)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1339)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1887)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:318)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:167)
at com.sun.jmx.remote.internal.PRef.invoke(Unknown Source)
at javax.management.remote.rmi.RMIConnectionImpl_Stub.fetchNotifications(RMIConnectionImpl_Stub.java:236)
at javax.management.remote.rmi.RMIConnector$RMINotifClient.fetchNotifs(RMIConnector.java:1318)
at com.sun.jmx.remote.internal.ClientNotifForwarder$NotifFetcher.fetchNotifs(ClientNotifForwarder.java:566)
at com.sun.jmx.remote.internal.ClientNotifForwarder$NotifFetcher.doRun(ClientNotifForwarder.java:449)
at com.sun.jmx.remote.internal.ClientNotifForwarder$NotifFetcher.run(ClientNotifForwarder.java:430)
Any attempt at synchronization, for example by overriding the handleNotification method, will not help, because the Notification objects get added to ArrayQueue<NamedNotification>in ArrayNotificationBuffer.handleNotification(). From the queue, another set of threads (RMI server threads) simultaneously serialize the Notification objects.
*Licensee's proposal is that this problem is made clear in the API documentation - i.e. it should explicitly advise users to use thread-safe data in userData of Notification object.*
TESTCASE
--------
The attached testcase replicates the scenario without the JMX environment. The client has two threads that simultaneosly serialize the calendar objects (equivalent to simultaneously serializing the Notification objects containing calendar data for various Notification Listeners, in the case.) Under particular conditions, the ClasscastException happens on the client side because of thread-unsafe operations on the server side.
REPRODUCTION INSTRUCTIONS
-------------------------
- javac *.java
- rmic DeliveryServiceImpl
- rmic DeliveryServiceImpl1
- rmiregistry
- java RmiServer
- java RmiServer1
- java RmiClient
SUGGESTED FIX
-------------
Java specification for the API Notification.setUserData(Object) should be changed from
----
The user data object. It is used for whatever data the notification source wishes to communicate to its consumers.
----
to
----
The user data object. It is used for whatever thread-safe data the notification source wishes to communicate to its consumers.
----
--------
MBean server throws unexpected exceptions when Notification is set with thread-unsafe data
OPERATING SYSTEM
----------------
All
FULL JDK VERSION
----------------
All releases of Java 6
PROBLEM DESCRIPTION from LICENSEE
---------------------------------
In an application set-up where an MBean server has 2 or more listeners, as soon as notification is fired, all the listeners will be relayed the notification object through serialization simultaneously. Because the serialization happens simultaneously, this causes problems if thread-unsafe data is used in the Notification object.
For example, if the Notification object is set with Calendar object as userData, on the MBean client side while the data is being deserialized, the following Exception can be thrown intermittently:
Exception in thread "ClientNotifForwarder-1" java.lang.ClassCastException: java.util.SimpleTimeZone incompatible with sun.util.calendar.ZoneInfo
at java.util.Calendar$1.run(Calendar.java:2665)
at java.util.Calendar$1.run(Calendar.java:2663)
at java.security.AccessController.doPrivileged(AccessController.java:284)
at java.util.Calendar.readObject(Calendar.java:2662)
at sun.reflect.GeneratedMethodAccessor60.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:986)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1865)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:493)
at javax.management.Notification.readObject(Notification.java:364)
at sun.reflect.GeneratedMethodAccessor58.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:986)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1865)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1887)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1683)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1339)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1887)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:318)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:167)
at com.sun.jmx.remote.internal.PRef.invoke(Unknown Source)
at javax.management.remote.rmi.RMIConnectionImpl_Stub.fetchNotifications(RMIConnectionImpl_Stub.java:236)
at javax.management.remote.rmi.RMIConnector$RMINotifClient.fetchNotifs(RMIConnector.java:1318)
at com.sun.jmx.remote.internal.ClientNotifForwarder$NotifFetcher.fetchNotifs(ClientNotifForwarder.java:566)
at com.sun.jmx.remote.internal.ClientNotifForwarder$NotifFetcher.doRun(ClientNotifForwarder.java:449)
at com.sun.jmx.remote.internal.ClientNotifForwarder$NotifFetcher.run(ClientNotifForwarder.java:430)
Any attempt at synchronization, for example by overriding the handleNotification method, will not help, because the Notification objects get added to ArrayQueue<NamedNotification>in ArrayNotificationBuffer.handleNotification(). From the queue, another set of threads (RMI server threads) simultaneously serialize the Notification objects.
*Licensee's proposal is that this problem is made clear in the API documentation - i.e. it should explicitly advise users to use thread-safe data in userData of Notification object.*
TESTCASE
--------
The attached testcase replicates the scenario without the JMX environment. The client has two threads that simultaneosly serialize the calendar objects (equivalent to simultaneously serializing the Notification objects containing calendar data for various Notification Listeners, in the case.) Under particular conditions, the ClasscastException happens on the client side because of thread-unsafe operations on the server side.
REPRODUCTION INSTRUCTIONS
-------------------------
- javac *.java
- rmic DeliveryServiceImpl
- rmic DeliveryServiceImpl1
- rmiregistry
- java RmiServer
- java RmiServer1
- java RmiClient
SUGGESTED FIX
-------------
Java specification for the API Notification.setUserData(Object) should be changed from
----
The user data object. It is used for whatever data the notification source wishes to communicate to its consumers.
----
to
----
The user data object. It is used for whatever thread-safe data the notification source wishes to communicate to its consumers.
----