Reputation: 972
Hello recently I started working on a JMX bean implementation.
I then publish the below bean, run JConsole, connect to the bean, register for notification. However when the notification is sent i get the following error:
Apr 13, 2012 5:31:26 PM ClientNotifForwarder NotifFetcher.fetchOneNotif WARNING: Failed to deserialize a notification: java.io.NotSerializableException: com.*.jmx.TaskMergeMBean
Any help will be most welcome, I've spent the better part of a day trying to figure this one out.
Thanks, Jonathan
public class TaskMBean extends NotificationBroadcasterSupport implements DynamicMBean {
private final TaskStateChangedEventListener taskChangedListener;
public TaskMBean (DriverIf driver) {
taskChangedListener= new TaskStateChangedEventListener (this);
driver.registerMergeTaskStateChangedListener(mergeTaskChangedListener);
}
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE };
String name = AttributeChangeNotification.class.getName();
String description = "An attribute of this MBean has changed";
MBeanNotificationInfo info = new MBeanNotificationInfo(types, name,description);
return new MBeanNotificationInfo[] { info };
}
@Override
public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException,
ReflectionException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, ReflectionException {
// TODO Auto-generated method stub
}
@Override
public AttributeList getAttributes(String[] attributes) {
// TODO Auto-generated method stub
return null;
}
@Override
public AttributeList setAttributes(AttributeList attributes) {
// TODO Auto-generated method stub
return null;
}
@Override
public Object invoke(String actionName, Object[] params, String[] signature)
throws MBeanException, ReflectionException {
// TODO Auto-generated method stub
return null;
}
@Override
public MBeanInfo getMBeanInfo() {
MBeanNotificationInfo haltInfo =
new MBeanNotificationInfo(
new String[] { "NOTIFICATION_TYPE_MERGE_STATE_CHANGE" },
Notification.class.getName(), "server halt on fatal error");
MBeanNotificationInfo[] notifications = new MBeanNotificationInfo[] { haltInfo };
return new OpenMBeanInfoSupport(XhiveMergeMBean.class.getName(), "", null, null, null,
notifications);
}
}
public class TaskStateChangedEventListener implements Serializable {
static final String NOTIFICATION_TYPE_MERGE_STATE_CHANGE = "com.xhive.lucene.merge";
private final NotificationBroadcasterSupport broadcaster;
private int notificationSequence = 1;
public TaskStateChangedEventListener (NotificationBroadcasterSupport broadcaster) {
this.broadcaster = broadcaster;
}
@Override
public void notify(Object source) {
Notification n =
new AttributeChangeNotification(this, notificationSequence++, System.currentTimeMillis(), "", "", "int", 1, 2);
broadcaster.sendNotification(n);
}
}
Upvotes: 0
Views: 1565
Reputation: 16056
What Peter said. But also.....
Notifications usually (but not always) have to be serialized, so using this as the notification source tends to put a dent in that. (pun intended)
So you need to make completely sure that the the instance of this is serializable (and preferably usefully so) or better yet, send a simpler representation of what this is, like the ObjectName of the MBean. The intent is for the receiver (or the filter) to be able to determine the source of the notification, so I find that consistent use of informative ObjectNames really helps.
And lastly, JConsole tends to be a bit thin on business classes (by default I mean) so if you're relying on JConsole a lot and you want to be able to view all your notifications cleanly, you need to make sure you only use core JDK types in your payload.
(Or use OpenTypes (same thing) or enable remote class loading (not worth the hassle)).
//Nicholas
Upvotes: 2