/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2012, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter.jmx.mbeanserver; import org.helios.apmrouter.OpCode; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import javax.management.Notification; import java.lang.reflect.Method; /** * <p>Title: MBeanServerConnectionInvocationResponseHandler</p> * <p>Description: Netty handler that handles a JMX request response.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.jmx.mbeanserver.MBeanServerConnectionInvocationResponseHandler</code></p> * TODO: This will work for datagrams, but for TCP we will need a ReplayDecoder */ public class MBeanServerConnectionInvocationResponseHandler extends SimpleChannelUpstreamHandler { /** The connection admin to funnel synchronous request returns through */ protected final MBeanServerConnectionAdmin connectionAdmin; /** * Creates a new MBeanServerConnectionInvocationResponseHandler * @param connectionAdmin The connection admin to funnel synchronous request returns through */ public MBeanServerConnectionInvocationResponseHandler(MBeanServerConnectionAdmin connectionAdmin) { this.connectionAdmin = connectionAdmin; } /** * Handles a JMX response. * {@inheritDoc} * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#messageReceived(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.MessageEvent) */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object message = e.getMessage(); boolean handled = false; if(message instanceof ChannelBuffer) { ChannelBuffer cb = (ChannelBuffer)message; byte op = cb.getByte(0); if(OpCode.JMX_RESPONSE.op()==op) { handled = true; int reqId=cb.getInt(1); AsynchJMXResponseListener waitingListener = AgentMBeanServerConnectionFactory.asynchTimeoutMap.remove(reqId); cb.skipBytes(5); // skipping op code and request id. final byte methodId = cb.readByte(); final int payloadSize = cb.readInt(); final byte[] bytes = new byte[payloadSize]; cb.readBytes(bytes); Object[] resp =AgentMBeanServerConnectionFactory.getInput(bytes); if(waitingListener!=null) { if(resp.length==1 && resp[0]!=null && resp[0] instanceof Throwable) { waitingListener.onException(reqId, (Throwable)resp[0]); } else { Method responseMethod = AgentMBeanServerConnectionFactory.keyToAsynchMethod.get(methodId); Object[] responseMethodParams = null; if(responseMethod.getParameterTypes().length==1) { responseMethodParams = new Object[]{reqId}; } else { responseMethodParams = new Object[]{reqId, resp[0]}; } responseMethod.invoke(waitingListener, responseMethodParams); } } else { connectionAdmin.onSynchronousResponse(reqId, resp.length==1 ? resp[0] : null); } } else if(OpCode.JMX_NOTIFICATION.op()==op) { handled = true; // Notification Write Procedure // cb.writeByte(OpCode.JMX_NOTIFICATION.op()); // cb.writeInt(requestId); // cb.writeInt(payload.length); // cb.writeBytes(payload); final int reqId=cb.readInt(); final int payloadSize = cb.readInt(); byte[] payload = new byte[payloadSize]; Object[] notifValues = AgentMBeanServerConnectionFactory.getInput(payload); connectionAdmin.onNotification(reqId, (Notification)notifValues[0], notifValues[1]); } } if(!handled) { ctx.sendUpstream(e); } } }