1 5 package com.tc.management.remote.connect; 6 7 import com.tc.async.api.AbstractEventHandler; 8 import com.tc.async.api.EventContext; 9 import com.tc.async.api.EventHandlerException; 10 import com.tc.logging.TCLogger; 11 import com.tc.logging.TCLogging; 12 import com.tc.management.TerracottaMBean; 13 import com.tc.management.TerracottaManagement; 14 import com.tc.management.remote.protocol.ProtocolProvider; 15 import com.tc.management.remote.protocol.terracotta.ClientProvider; 16 import com.tc.management.remote.protocol.terracotta.TunnelingMessageConnection; 17 import com.tc.management.remote.protocol.terracotta.ClientTunnelingEventHandler.L1ConnectionMessage; 18 import com.tc.net.TCSocketAddress; 19 import com.tc.net.protocol.tcm.MessageChannel; 20 21 import java.io.IOException ; 22 import java.net.MalformedURLException ; 23 import java.util.ArrayList ; 24 import java.util.HashMap ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Map ; 28 import java.util.Set ; 29 30 import javax.management.MBeanServer ; 31 import javax.management.MBeanServerConnection ; 32 import javax.management.MBeanServerInvocationHandler ; 33 import javax.management.Notification ; 34 import javax.management.NotificationFilter ; 35 import javax.management.NotificationListener ; 36 import javax.management.ObjectName ; 37 import javax.management.StandardMBean ; 38 import javax.management.remote.JMXConnectionNotification ; 39 import javax.management.remote.JMXConnector ; 40 import javax.management.remote.JMXConnectorFactory ; 41 import javax.management.remote.JMXServiceURL ; 42 43 public class ClientConnectEventHandler extends AbstractEventHandler { 44 45 private static final class ConnectorClosedFilter implements NotificationFilter { 46 47 public boolean isNotificationEnabled(final Notification notification) { 48 boolean enabled = false; 49 if (notification instanceof JMXConnectionNotification ) { 50 final JMXConnectionNotification jmxcn = (JMXConnectionNotification ) notification; 51 enabled = jmxcn.getType().equals(JMXConnectionNotification.CLOSED); 52 } 53 return enabled; 54 } 55 56 } 57 58 private static final class ConnectorClosedListener implements NotificationListener { 59 60 private static final TCLogger logger = TCLogging.getLogger(ConnectorClosedListener.class); 61 62 private final MBeanServerConnection mBeanServerConnection; 63 64 ConnectorClosedListener(final MBeanServerConnection mBeanServerConnection) { 65 this.mBeanServerConnection = mBeanServerConnection; 66 } 67 68 final public void handleNotification(final Notification notification, final Object context) { 69 for (Iterator beanNames = ((List ) context).iterator(); beanNames.hasNext();) { 70 final ObjectName dsoClientBeanName = (ObjectName ) beanNames.next(); 71 try { 72 mBeanServerConnection.unregisterMBean(dsoClientBeanName); 73 } catch (Exception e) { 74 logger.warn("Unable to unregister DSO client bean[" + dsoClientBeanName + "]", e); 75 } 76 } 77 } 78 } 79 80 private static final TCLogger logger = TCLogging.getLogger(ClientConnectEventHandler.class); 81 82 public void handleEvent(EventContext context) throws EventHandlerException { 83 L1ConnectionMessage msg = (L1ConnectionMessage) context; 84 if (msg.isConnectingMsg()) { 85 addJmxConnection(msg); 86 } else { 87 removeJmxConnection(msg); 88 } 89 } 90 91 private void addJmxConnection(final L1ConnectionMessage msg) { 92 final MessageChannel channel = msg.getChannel(); 93 final TCSocketAddress remoteAddress = channel != null ? channel.getRemoteAddress() : null; 94 if (remoteAddress == null) { return; } 95 96 final MBeanServer l2MBeanServer = msg.getMBeanServer(); 97 final Map channelIdToJmxConnector = msg.getChannelIdToJmxConnector(); 98 final Map channelIdToMsgConnection = msg.getChannelIdToMsgConnector(); 99 synchronized (channelIdToJmxConnector) { 100 if (!channelIdToJmxConnector.containsKey(channel.getChannelID())) { 101 JMXServiceURL serviceURL; 102 try { 103 serviceURL = new JMXServiceURL ("terracotta", remoteAddress.getAddress().getHostName(), remoteAddress 104 .getPort()); 105 } catch (MalformedURLException murle) { 106 logger.error("Unable to construct a JMX service URL using DSO client channel from host[" 107 + channel.getRemoteAddress() + "]; tunneled JMX connection will not be established", murle); 108 return; 109 } 110 Map environment = new HashMap (); 111 ProtocolProvider.addTerracottaJmxProvider(environment); 112 environment.put(ClientProvider.JMX_MESSAGE_CHANNEL, channel); 113 environment.put(ClientProvider.CONNECTION_LIST, channelIdToMsgConnection); 114 final JMXConnector jmxConnector; 115 try { 116 jmxConnector = JMXConnectorFactory.connect(serviceURL, environment); 117 118 final MBeanServerConnection l1MBeanServerConnection = jmxConnector.getMBeanServerConnection(); 119 Set mBeans = l1MBeanServerConnection.queryNames(null, TerracottaManagement.matchAllTerracottaMBeans()); 120 List modifiedObjectNames = new ArrayList (); 121 for (Iterator iter = mBeans.iterator(); iter.hasNext();) { 122 ObjectName objName = (ObjectName ) iter.next(); 123 try { 124 TerracottaMBean mBeanProxy = (TerracottaMBean) MBeanServerInvocationHandler.newProxyInstance( 125 l1MBeanServerConnection, objName, TerracottaMBean.class, false); 126 ObjectName modifiedObjName = TerracottaManagement.addNodeInfo(objName, channel.getRemoteAddress()); 127 Class interfaceClass = Class.forName(mBeanProxy.getInterfaceClassName()); 128 Object obj = MBeanServerInvocationHandler.newProxyInstance(l1MBeanServerConnection, objName, 129 interfaceClass, mBeanProxy.isNotificationBroadcaster()); 130 l2MBeanServer.registerMBean(new StandardMBean (obj, interfaceClass), modifiedObjName); 131 modifiedObjectNames.add(modifiedObjName); 132 } catch (Exception e) { 133 logger.error("Unable to register remote DSO client MBean[" + objName.getCanonicalName() + "] for host[" 134 + channel.getRemoteAddress() + "], this bean will not show up in monitoring tools!!", e); 135 } 136 } 137 try { 138 jmxConnector.addConnectionNotificationListener(new ConnectorClosedListener(l2MBeanServer), 139 new ConnectorClosedFilter(), modifiedObjectNames); 140 } catch (Exception e) { 141 logger.error("Unable to register a JMX connection listener for the DSO client[" 142 + channel.getRemoteAddress() 143 + "], if the DSO client disconnects the then its (dead) beans will not be unregistered", e); 144 } 145 } catch (IOException ioe) { 146 logger.error("Unable to create tunneled JMX connection to the DSO client on host[" 147 + channel.getRemoteAddress() + "], this DSO client will not show up in monitoring tools!!", ioe); 148 return; 149 } 150 channelIdToJmxConnector.put(channel.getChannelID(), jmxConnector); 151 } else { 152 logger.warn("We are trying to create a new tunneled JMX connection but already have one for channel[" 153 + channel.getRemoteAddress() + "], ignoring new connection message"); 154 } 155 } 156 } 157 158 private void removeJmxConnection(final L1ConnectionMessage msg) { 159 final MessageChannel channel = msg.getChannel(); 160 final Map channelIdToJmxConnector = msg.getChannelIdToJmxConnector(); 161 final Map channelIdToMsgConnection = msg.getChannelIdToMsgConnector(); 162 163 synchronized (channelIdToMsgConnection) { 164 final TunnelingMessageConnection tmc = (TunnelingMessageConnection) channelIdToMsgConnection.remove(channel 165 .getChannelID()); 166 if (tmc != null) { 167 try { 168 tmc.close(); 169 } catch (IOException ioe) { 170 logger.warn("Unable to close JMX tunneling message connection to DSO client[" + channel + "]", ioe); 171 } 172 } 173 } 174 175 synchronized (channelIdToJmxConnector) { 176 if (channelIdToJmxConnector.containsKey(channel.getChannelID())) { 177 final JMXConnector jmxConnector = (JMXConnector ) channelIdToJmxConnector.remove(channel.getChannelID()); 178 if (jmxConnector != null) { 179 try { 180 jmxConnector.close(); 181 } catch (IOException ioe) { 182 logger.debug("Unable to close JMX connector to DSO client[" + channel + "]", ioe); 183 } 184 } 185 } else { 186 logger.warn("DSO client channel closed without a corresponding tunneled JMX connection"); 187 } 188 } 189 } 190 191 } 192 | Popular Tags |