/* * (c) Rob Gordon 2005 */ package org.oddjob.jmx.client; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * Client side utility class for managing ClientInterfaceHandlers. * * @author Rob Gordon */ class ClientInterfaceManagerFactory { private final Set<Class<?>> interfaces = new HashSet<Class<?>>(); private final Set<ClientInterfaceHandlerFactory<?>> clientHandlerFactories = new HashSet<ClientInterfaceHandlerFactory<?>>(); public ClientInterfaceManagerFactory( ClientInterfaceHandlerFactory<?>[] clientHandlerFactories) { for (int i = 0; clientHandlerFactories != null && i < clientHandlerFactories.length; ++i) { ClientInterfaceHandlerFactory<?> handlerFactory = clientHandlerFactories[i]; addHandlerFactory(handlerFactory); } } public void addHandlerFactory(ClientInterfaceHandlerFactory<?> handlerFactory) { // add to factories. this.clientHandlerFactories.add(handlerFactory); if (handlerFactory.interfaceClass().isInterface()) { // add to interfaces supported. interfaces.add(handlerFactory.interfaceClass()); } } public Class<?>[] interfaces() { return (Class[]) interfaces.toArray(new Class[0]); } public ClientInterfaceManager create( Object source, ClientSideToolkit csToolkit) { /** Map of methods of the InterfaceHandlers. Not sure if the order * interface might be important but we are using a LinkedHashMap just * in case it is. */ final Map<Method, Operation<?>> operations = new LinkedHashMap<Method, Operation<?>>(); final List<Destroyable> destroyables = new ArrayList<Destroyable>(); // Loop over all definitions. for (ClientInterfaceHandlerFactory<?> clientHandlerFactory : clientHandlerFactories) { Object handler = createOperations(source, csToolkit, clientHandlerFactory, operations); if (handler instanceof Destroyable) { destroyables.add((Destroyable) handler); } } return new ClientInterfaceManager() { public Object invoke(Method method, Object[] args) throws Throwable { Operation<?> op = (Operation<?>) operations.get(method); if (op == null) { throw new IllegalArgumentException("No interface supports method [" + method + "]"); } Object interfaceHandler = op.getHandler(); try { return method.invoke(interfaceHandler, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } @Override public void destroy() { for (Destroyable destroyable : destroyables) { destroyable.destroy(); } } }; } /** * Purely for Template trickary. * * @param <T> * @param source * @param csToolkit * @param factory * @param operations */ private <T> T createOperations( Object source, ClientSideToolkit csToolkit, ClientInterfaceHandlerFactory<T> factory, Map<Method, Operation<?>> operations) { Class<T> cl = factory.interfaceClass(); // create the interface handler T interfaceHandler = factory.createClientHandler(cl.cast(source), csToolkit); // map operations to handler Method[] methods = cl.getMethods(); for (int j = 0; j < methods.length; ++j) { Method m = methods[j]; Operation<?> op = operations.get(m); if (op != null) { throw new IllegalArgumentException("Method [" + m + "] already registered by factory for " + op.getFactory().interfaceClass().getName()); } operations.put( m, new Operation<T>(interfaceHandler, factory)); } return interfaceHandler; } /** * Store a handler and a factory for an operation. * <p> * The factory is only stored for to create the duplicate message. Can't remember why * this the handler wasn't good enough for the message. * * * @author rob * */ class Operation<T> { private final T handler; private final ClientInterfaceHandlerFactory<T> factory; Operation(T handler, ClientInterfaceHandlerFactory<T> factory) { this.handler = handler; this.factory = factory; } T getHandler() { return handler; } ClientInterfaceHandlerFactory<T> getFactory() { return factory; } } }