/*
* (c) Rob Gordon 2005
*/
package org.oddjob.jmx.server;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.ReflectionException;
import org.oddjob.jmx.RemoteOperation;
import org.oddjob.jmx.client.ClientHandlerResolver;
/**
* Simple Implementation of an InterfaceManager.
*
* @author Rob Gordon
*/
public class ServerInterfaceManagerImpl implements ServerInterfaceManager {
/** The collective mBeanInfo */
private final MBeanInfo mBeanInfo;
/** The collective interfaces. */
private final Map<ClientHandlerResolver<?>, MBeanOperationInfo[]> clientResolvers =
new LinkedHashMap<ClientHandlerResolver<?>, MBeanOperationInfo[]>();
/** Remember the handlers so they can be destroyed */
private final ServerInterfaceHandler[] handlers;
/** Map of methods to InterfaceHandlers. Not sure if the order
* interface might be important but we are using a LinkedHashMap just
* in case it is. */
private final Map<RemoteOperation<?>, ServerInterfaceHandler> operations =
new LinkedHashMap<RemoteOperation<?>, ServerInterfaceHandler>();
/** Map of remote operations. */
private final Map<RemoteOperation<?>, MBeanOperationInfo> opInfos =
new HashMap<RemoteOperation<?>, MBeanOperationInfo>();
/** Simple Security */
private final OddjobJMXAccessController accessController;
public ServerInterfaceManagerImpl(Object target,
ServerSideToolkit ojmb,
ServerInterfaceHandlerFactory<?, ?>[] serverHandlerFactories) {
this(target, ojmb, serverHandlerFactories, null);
}
/**
* Constructor.
*
* @param target. The target object the OddjobMBean is representing.
* @param ojmb The OddjobMBean.
* @param serverHandlerFactories The InterfaceInfos.
*/
public ServerInterfaceManagerImpl(Object target,
ServerSideToolkit ojmb,
ServerInterfaceHandlerFactory<?, ?>[] serverHandlerFactories,
OddjobJMXAccessController accessController) {
List<MBeanAttributeInfo> attributeInfo =
new ArrayList<MBeanAttributeInfo>();
List<MBeanOperationInfo> operationInfo =
new ArrayList<MBeanOperationInfo>();
List<MBeanNotificationInfo> notificationInfo =
new ArrayList<MBeanNotificationInfo>();
handlers = new ServerInterfaceHandler[serverHandlerFactories.length];
// Loop over all definitions.
for (int i = 0; i < serverHandlerFactories.length; ++i) {
ServerInterfaceHandlerFactory<?, ?> serverHandlerFactory = serverHandlerFactories[i];
// create the interface handler
ServerInterfaceHandler interfaceHandler
= create(target, ojmb, serverHandlerFactory);
handlers[i] = interfaceHandler;
// collate MBeanAttributeInfo.
attributeInfo.addAll(Arrays.asList(serverHandlerFactory.getMBeanAttributeInfo()));
// collate MBeanOperationInfo.
MBeanOperationInfo[] oInfo = serverHandlerFactory.getMBeanOperationInfo();
clientResolvers.put(serverHandlerFactory.clientHandlerFactory(), oInfo);
for (MBeanOperationInfo opInfo : oInfo) {
operationInfo.add(opInfo);
RemoteOperation<?> remoteOp =
new OperationInfoOperation(opInfo);
operations.put(
remoteOp,
interfaceHandler);
opInfos.put(remoteOp, opInfo);
}
// collate MBeanNotificationInfo.
notificationInfo.addAll(Arrays.asList(serverHandlerFactory.getMBeanNotificationInfo()));
}
// create an MBeanInfo from the collated informations.
mBeanInfo = new MBeanInfo(target.toString(),
"Description of " + target.toString(),
(MBeanAttributeInfo[]) attributeInfo.toArray(new MBeanAttributeInfo[0]),
new MBeanConstructorInfo[0],
(MBeanOperationInfo[]) operationInfo.toArray(new MBeanOperationInfo[0]),
(MBeanNotificationInfo[]) notificationInfo.toArray(new MBeanNotificationInfo[0]));
if (accessController == null) {
this.accessController = new OddjobJMXAccessController() {
@Override
public boolean isAccessable(MBeanOperationInfo opInfo) {
return true;
}
};
}
else {
this.accessController = accessController;
}
}
private <S> ServerInterfaceHandler create(
Object target,
ServerSideToolkit ojmb,
ServerInterfaceHandlerFactory<S, ?> factory) {
Class<S> type = factory.interfaceClass();
if (! type.isInstance(target)) {
throw new ClassCastException("" + target +
" not of type " + type.getName());
}
// create the interface handler
ServerInterfaceHandler interfaceHandler
= factory.createServerHandler(
type.cast(target), ojmb);
return interfaceHandler;
}
public ClientHandlerResolver<?>[] allClientInfo() {
List<ClientHandlerResolver<?>> resolvers =
new ArrayList<ClientHandlerResolver<?>>();
resolver:
for (Map.Entry<ClientHandlerResolver<?>, MBeanOperationInfo[]> entry
: clientResolvers.entrySet()) {
for (MBeanOperationInfo opInfo : entry.getValue()) {
if (!accessController.isAccessable(opInfo)) {
continue resolver;
}
}
resolvers.add(entry.getKey());
}
return resolvers.toArray(
new ClientHandlerResolver[resolvers.size()]);
}
/*
* (non-Javadoc)
* @see org.oddjob.jmx.server.InterfaceManager#getMBeanInfo()
*/
public MBeanInfo getMBeanInfo() {
return mBeanInfo;
}
/*
* (non-Javadoc)
* @see org.oddjob.jmx.server.InterfaceManager#invoke(java.lang.String, java.lang.Object[], java.lang.String[])
*/
public Object invoke(String actionName,
Object[] params, String[] signature)
throws MBeanException, ReflectionException {
RemoteOperation<Object> op = new MBeanOperation(actionName, signature);
ServerInterfaceHandler interfaceHandler = operations.get(op);
if (interfaceHandler == null) {
throw new IllegalArgumentException(
"No interface supports method [" + op + "]");
}
MBeanOperationInfo opInfo = this.opInfos.get(op);
if (opInfo == null) {
throw new RuntimeException(
"No OpInfo for [" + op + "] (This is a bug!)");
}
if (!accessController.isAccessable(opInfo)) {
throw new SecurityException(
"Access denied! Invalid access level for " + op);
}
return interfaceHandler.invoke(op, params);
}
/*
* (non-Javadoc)
* @see org.oddjob.jmx.server.InterfaceManager#destroy()
*/
public void destroy() {
for (int i = 0; i < handlers.length; ++i) {
handlers[i].destroy();
handlers[i] = null;
}
}
}