/*
* (c) Rob Gordon 2005
*/
package org.oddjob.jmx.handlers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.MBeanException;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import junit.framework.TestCase;
import org.oddjob.Structural;
import org.oddjob.jmx.RemoteOperation;
import org.oddjob.jmx.client.ClientInterfaceHandlerFactory;
import org.oddjob.jmx.client.ClientSession;
import org.oddjob.jmx.client.MockClientSession;
import org.oddjob.jmx.client.MockClientSideToolkit;
import org.oddjob.jmx.server.MockServerContext;
import org.oddjob.jmx.server.MockServerSession;
import org.oddjob.jmx.server.MockServerSideToolkit;
import org.oddjob.jmx.server.ServerContext;
import org.oddjob.jmx.server.ServerInterfaceHandler;
import org.oddjob.jmx.server.ServerLoopBackException;
import org.oddjob.jmx.server.ServerSession;
import org.oddjob.structural.ChildHelper;
import org.oddjob.structural.StructuralEvent;
import org.oddjob.structural.StructuralListener;
public class StructuralHandlerFactoryTest extends TestCase {
int unique;
private class OurServerSideToolkit extends MockServerSideToolkit {
List<Notification> notifications = new ArrayList<Notification>();
Map<ObjectName, Object> children = new HashMap<ObjectName, Object>();
String name = "x";
int seq = 0;
@Override
public void sendNotification(Notification notification) {
notifications.add(notification);
}
@Override
public void runSynchronized(Runnable runnable) {
runnable.run();
}
@Override
public ServerSession getServerSession() {
return new MockServerSession() {
@Override
public ObjectName createMBeanFor(Object child,
ServerContext childContext) {
try {
ObjectName on = new ObjectName("test:name=" + name);
children.put(on, child);
name = name + "x";
return on;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void destroy(ObjectName childName) {
Object child = children.remove(childName);
assertNotNull(child);
}
};
}
@Override
public ServerContext getContext() {
return new MockServerContext() {
@Override
public ServerContext addChild(Object child)
throws ServerLoopBackException {
return new MockServerContext();
}
};
}
@Override
public Notification createNotification(String type) {
return new Notification(type, new Object(), seq++);
}
}
private class MyStructural implements Structural {
ChildHelper<Object> helper = new ChildHelper<Object>(this);
public void addStructuralListener(StructuralListener listener) {
helper.addStructuralListener(listener);
}
public void removeStructuralListener(StructuralListener listener) {
helper.removeStructuralListener(listener);
}
}
public void testServerSide() throws MBeanException, ReflectionException, MalformedObjectNameException, NullPointerException {
MyStructural structural = new MyStructural();
structural.helper.insertChild(0, new Object());
OurServerSideToolkit toolkit = new OurServerSideToolkit();
StructuralHandlerFactory test = new StructuralHandlerFactory();
ServerInterfaceHandler handler = test.createServerHandler(structural, toolkit);
assertEquals(1, toolkit.notifications.size());
Notification[] last =
(Notification[]) handler.invoke(
StructuralHandlerFactory.SYNCHRONIZE,
new Object[0]);
assertEquals(1, last.length);
Notification last0 = last[0];
assertEquals(1, last0.getSequenceNumber());
StructuralHandlerFactory.ChildData lastData0 =
(StructuralHandlerFactory.ChildData) last0.getUserData();
assertEquals(1, lastData0.getChildObjectNames().length);
assertEquals(new ObjectName("test:name=x"), lastData0.getChildObjectNames()[0]);
Object child = new Object();
structural.helper.insertChild(1, child);
assertEquals(2, toolkit.notifications.size());
// first notification will be ignored.
Notification n0 = toolkit.notifications.get(0);
assertEquals(0, n0.getSequenceNumber());
StructuralHandlerFactory.ChildData childData0 =
(StructuralHandlerFactory.ChildData) n0.getUserData();
assertEquals(1, childData0.getChildObjectNames().length);
assertEquals(new ObjectName("test:name=x"), lastData0.getChildObjectNames()[0]);
Notification n1 = toolkit.notifications.get(1);
assertEquals(2, n1.getSequenceNumber());
assertEquals(StructuralHandlerFactory.STRUCTURAL_NOTIF_TYPE,
n1.getType());
structural.helper.insertChild(2, new Object());
assertEquals(3, toolkit.notifications.size());
Notification n2 = toolkit.notifications.get(2);
assertEquals(3, n2.getSequenceNumber());
StructuralHandlerFactory.ChildData childData2 =
(StructuralHandlerFactory.ChildData) n2.getUserData();
assertEquals(3, childData2.getChildObjectNames().length);
assertEquals(new ObjectName("test:name=x"), childData2.getChildObjectNames()[0]);
assertEquals(new ObjectName("test:name=xx"), childData2.getChildObjectNames()[1]);
assertEquals(new ObjectName("test:name=xxx"), childData2.getChildObjectNames()[2]);
structural.helper.removeChildAt(1);
assertEquals(4, toolkit.notifications.size());
Notification n3 = toolkit.notifications.get(3);
assertEquals(4, n3.getSequenceNumber());
StructuralHandlerFactory.ChildData childData3 =
(StructuralHandlerFactory.ChildData) n3.getUserData();
assertEquals(2, childData3.getChildObjectNames().length);
assertEquals(new ObjectName("test:name=x"), childData3.getChildObjectNames()[0]);
assertEquals(new ObjectName("test:name=xxx"), childData3.getChildObjectNames()[1]);
handler.destroy();
assertTrue(structural.helper.isNoListeners());
}
private class OurClientToolkit extends MockClientSideToolkit {
NotificationListener handler;
Map<ObjectName, Object> created =
new HashMap<ObjectName, Object>();
Map<Object, ObjectName> toNames =
new HashMap<Object, ObjectName>();
@SuppressWarnings("unchecked")
@Override
public <T> T invoke(RemoteOperation<T> remoteOperation, Object... args)
throws Throwable {
if (StructuralHandlerFactory.SYNCHRONIZE.equals(remoteOperation)) {
return (T) new Notification[0];
}
return null;
}
public void registerNotificationListener(String eventType,
NotificationListener notificationListener) {
if (StructuralHandlerFactory.STRUCTURAL_NOTIF_TYPE.equals(eventType)) {
if (handler != null) {
throw new RuntimeException("Listener not null.");
}
this.handler= notificationListener;
}
else {
throw new RuntimeException("Unexpected.");
}
}
@Override
public ClientSession getClientSession() {
return new MockClientSession() {
public Object create(ObjectName objectName) {
Object child = new Object();
created.put(objectName, child);
toNames.put(child, objectName);
return child;
}
@Override
public void destroy(Object proxy) {
ObjectName objectName = toNames.remove(proxy);
created.remove(objectName);
}
};
}
}
private class ResultListener implements StructuralListener {
List<Object> children = new ArrayList<Object>();
public void childAdded(StructuralEvent event) {
children.add(event.getIndex(), event.getChild());
}
public void childRemoved(StructuralEvent event) {
children.remove(event.getIndex());
}
}
private class OurStructural implements Structural {
public void addStructuralListener(StructuralListener listener) {
}
public void removeStructuralListener(StructuralListener listener) {
}
}
public void testClientSide() throws MalformedObjectNameException, NullPointerException {
ClientInterfaceHandlerFactory<Structural> clientFactory =
new StructuralHandlerFactory.ClientStructuralHandlerFactory();
OurClientToolkit clientToolkit = new OurClientToolkit();
OurStructural proxy = new OurStructural();
Structural handler = clientFactory.createClientHandler(
proxy, clientToolkit);
ResultListener results = new ResultListener();
((Structural) handler).addStructuralListener(results);
// First
StructuralHandlerFactory.ChildData data1 =
new StructuralHandlerFactory.ChildData(
new ObjectName[] {new ObjectName("oddjob:name=A") });
Notification n1 = new Notification("ignored", new Object(), 0);
n1.setUserData(data1);
clientToolkit.handler.handleNotification(n1, null);
assertEquals(1, results.children.size());
Object child1 = results.children.get(0);
assertEquals(clientToolkit.created.get(new ObjectName("oddjob:name=A")), child1);
// Second
StructuralHandlerFactory.ChildData data2 =
new StructuralHandlerFactory.ChildData(
new ObjectName[] { new ObjectName("oddjob:name=A"), new ObjectName("oddjob:name=B") });
Notification n2 = new Notification("ignored", new Object(), 0);
n2.setUserData(data2);
clientToolkit.handler.handleNotification(n2, null);
assertEquals(2, results.children.size());
Object child2 = results.children.get(1);
assertEquals(clientToolkit.created.get(new ObjectName("oddjob:name=B")), child2);
// Third
StructuralHandlerFactory.ChildData data3 =
new StructuralHandlerFactory.ChildData(
new ObjectName[] { new ObjectName("oddjob:name=A"),
new ObjectName("oddjob:name=B"),
new ObjectName("oddjob:name=C") });
Notification n3 = new Notification("ignored", new Object(), 0);
n3.setUserData(data3);
clientToolkit.handler.handleNotification(n3, null);
assertEquals(3, results.children.size());
Object child3 = results.children.get(2);
assertEquals(clientToolkit.created.get(
new ObjectName("oddjob:name=C")), child3);
// Fourth
StructuralHandlerFactory.ChildData data4 =
new StructuralHandlerFactory.ChildData(
new ObjectName[] { new ObjectName("oddjob:name=B"),
new ObjectName("oddjob:name=C") });
Notification n4 = new Notification("ignored", new Object(), 0);
n4.setUserData(data4);
clientToolkit.handler.handleNotification(n4, null);
assertEquals(2, results.children.size());
Object child4 = results.children.get(0);
assertEquals(clientToolkit.created.get(new ObjectName("oddjob:name=B")), child4);
}
}