package org.oddjob.jmx.handlers; import java.lang.reflect.UndeclaredThrowableException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.MBeanOperationInfo; import javax.management.ReflectionException; import org.oddjob.jmx.RemoteOperation; import org.oddjob.jmx.SharedConstants; import org.oddjob.jmx.client.ClientHandlerResolver; import org.oddjob.jmx.client.ClientInterfaceHandlerFactory; import org.oddjob.jmx.client.ClientSideToolkit; import org.oddjob.jmx.client.HandlerVersion; import org.oddjob.jmx.client.LogPollable; import org.oddjob.jmx.client.SimpleHandlerResolver; import org.oddjob.jmx.server.JMXOperationPlus; import org.oddjob.jmx.server.LogArchiverHelper; import org.oddjob.jmx.server.ServerContext; import org.oddjob.jmx.server.ServerInterfaceHandler; import org.oddjob.jmx.server.ServerInterfaceHandlerFactory; import org.oddjob.jmx.server.ServerSideToolkit; import org.oddjob.logging.LogEvent; /** * Provide Handlers for the {@link LogPollable} interface. * <p> * This is a special handler because url and consoleId never * change on the server so we can cache the values. * * @author rob */ public class LogPollableHandlerFactory implements ServerInterfaceHandlerFactory<Object, LogPollable> { public static final HandlerVersion VERSION = new HandlerVersion(1, 0); private static final JMXOperationPlus<String> CONSOLE_ID = new JMXOperationPlus<String>( "consoleId", "Console ID", String.class, MBeanOperationInfo.INFO); private static final JMXOperationPlus<String> URL = new JMXOperationPlus<String>( "url", "Remote URL", String.class, MBeanOperationInfo.INFO); private static final JMXOperationPlus<LogEvent[]> RETRIEVE_CONSOLE_EVENTS = new JMXOperationPlus<LogEvent[]>( SharedConstants.RETRIEVE_CONSOLE_EVENTS_METHOD, "Retrieve Console Events", LogEvent[].class, MBeanOperationInfo.INFO) .addParam("seqNum", Long.TYPE, "Sequence Number") .addParam("history", Integer.TYPE, "History"); private static final JMXOperationPlus<LogEvent[]> RETRIEVE_LOG_EVENTS = new JMXOperationPlus<LogEvent[]>( SharedConstants.RETRIEVE_LOG_EVENTS_METHOD, "Retrieve Log Events", LogEvent[].class, MBeanOperationInfo.INFO) .addParam("seqNum", Long.TYPE, "Sequence Number") .addParam("history", Integer.TYPE, "History"); /* * (non-Javadoc) * @see org.oddjob.jmx.server.ServerInterfaceHandlerFactory#interfaceClass() */ public Class<Object> interfaceClass() { return Object.class; } public MBeanAttributeInfo[] getMBeanAttributeInfo() { return new MBeanAttributeInfo[0]; } public MBeanOperationInfo[] getMBeanOperationInfo() { return new MBeanOperationInfo[] { CONSOLE_ID.getOpInfo(), URL.getOpInfo(), RETRIEVE_CONSOLE_EVENTS.getOpInfo(), RETRIEVE_LOG_EVENTS.getOpInfo() }; } public MBeanNotificationInfo[] getMBeanNotificationInfo() { return new MBeanNotificationInfo[0]; } public ServerInterfaceHandler createServerHandler(Object target, ServerSideToolkit ojmb) { return new ServerLogPollableHandler(target, ojmb); } public ClientHandlerResolver<LogPollable> clientHandlerFactory() { return new SimpleHandlerResolver<LogPollable>( ClientLogPollableHandlerFactory.class.getName(), VERSION); } public static class ClientLogPollableHandlerFactory implements ClientInterfaceHandlerFactory<LogPollable> { public Class<LogPollable> interfaceClass() { return LogPollable.class; } public HandlerVersion getVersion() { return VERSION; } public LogPollable createClientHandler(LogPollable ignored, ClientSideToolkit toolkit) { return new ClientLogPollableHandler(toolkit); } } static class ClientLogPollableHandler implements LogPollable { private final String consoleId; private final String url; private final ClientSideToolkit toolkit; ClientLogPollableHandler(ClientSideToolkit toolkit) { this.toolkit = toolkit; try { consoleId = (String) toolkit.invoke( CONSOLE_ID); url = (String) toolkit.invoke( URL); } catch (Throwable t) { throw new UndeclaredThrowableException(t); } } /** * Get the consoleId which has been saved from the remote OddjobMBean. The console * identifies the console on a remote server. The console will frequently be * shared between components in a single JVM and so we don't want to get the same * messages on a component by component bases. * * @return The consoleId. */ public String consoleId() { return consoleId; } public String url() { return url; } public LogEvent[] retrieveConsoleEvents(long from, int max) { try { return toolkit.invoke( RETRIEVE_CONSOLE_EVENTS, new Object[] { new Long(from), new Integer(max) }); } catch (Throwable t) { throw new UndeclaredThrowableException(t); } } public LogEvent[] retrieveLogEvents(long from, int max) { try { return toolkit.invoke( RETRIEVE_LOG_EVENTS, new Object[] { new Long(from), new Integer(max) }); } catch (Throwable t) { throw new UndeclaredThrowableException(t); } } } class ServerLogPollableHandler implements ServerInterfaceHandler { private final Object node; private final ServerContext srvcon; ServerLogPollableHandler(Object object, ServerSideToolkit ojmb) { this.node = object; this.srvcon = ojmb.getContext(); } public Object invoke(RemoteOperation<?> operation, Object[] params) throws MBeanException, ReflectionException { if (CONSOLE_ID.equals(operation)) { return LogArchiverHelper.consoleId( node, srvcon.getConsoleArchiver()); } else if (URL.equals(operation)) { return srvcon.getServerId().toString(); } else if (RETRIEVE_LOG_EVENTS.equals(operation)) { return LogArchiverHelper.retrieveLogEvents(node, srvcon.getLogArchiver(), (Long)params[0], (Integer)params[1]); } else if (RETRIEVE_CONSOLE_EVENTS.equals(operation)) { return LogArchiverHelper.retrieveConsoleEvents(node, srvcon.getConsoleArchiver(), (Long)params[0], (Integer)params[1]); } else { throw new ReflectionException( new IllegalStateException("Invoked for an unknown method."), operation.toString()); } } public void destroy() { } } }