001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.management;
006:
007: import com.tc.exception.TCRuntimeException;
008: import com.tc.logging.TCLogger;
009: import com.tc.logging.TCLogging;
010: import com.tc.management.beans.L1MBeanNames;
011: import com.tc.management.beans.MBeanNames;
012: import com.tc.management.beans.sessions.SessionMonitor;
013: import com.tc.management.beans.sessions.SessionMonitorMBean;
014: import com.tc.management.beans.tx.ClientTxMonitor;
015: import com.tc.management.beans.tx.ClientTxMonitorMBean;
016: import com.tc.management.exposed.SessionsProduct;
017: import com.tc.management.exposed.TerracottaCluster;
018: import com.tc.management.remote.protocol.ProtocolProvider;
019: import com.tc.management.remote.protocol.terracotta.TunnelingEventHandler;
020: import com.tc.management.remote.protocol.terracotta.TunnelingMessageConnectionServer;
021: import com.tc.util.concurrent.SetOnceFlag;
022: import com.tc.util.runtime.Vm;
023:
024: import java.io.IOException;
025: import java.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.util.HashMap;
028: import java.util.List;
029: import java.util.Map;
030:
031: import javax.management.InstanceAlreadyExistsException;
032: import javax.management.MBeanRegistrationException;
033: import javax.management.MBeanServer;
034: import javax.management.MBeanServerFactory;
035: import javax.management.NotCompliantMBeanException;
036: import javax.management.ObjectName;
037: import javax.management.remote.JMXConnectorServer;
038: import javax.management.remote.JMXConnectorServerFactory;
039: import javax.management.remote.JMXServiceURL;
040:
041: public final class L1Management extends TerracottaManagement {
042:
043: private static final TCLogger logger = TCLogging
044: .getLogger(L1Management.class);
045:
046: private final SetOnceFlag started;
047: private final TunnelingEventHandler tunnelingHandler;
048: private final Object mBeanServerLock;
049: private MBeanServer mBeanServer;
050:
051: private final ClientTxMonitor clientTxBean;
052: private final SessionMonitor internalSessionBean;
053: private final SessionsProduct publicSessionBean;
054: private final TerracottaCluster clusterBean;
055:
056: public L1Management(final TunnelingEventHandler tunnelingHandler) {
057: super ();
058: started = new SetOnceFlag();
059: this .tunnelingHandler = tunnelingHandler;
060: try {
061: clientTxBean = new ClientTxMonitor();
062: internalSessionBean = new SessionMonitor();
063: publicSessionBean = new SessionsProduct(
064: internalSessionBean, clientTxBean);
065: clusterBean = new TerracottaCluster();
066: } catch (NotCompliantMBeanException ncmbe) {
067: throw new TCRuntimeException(
068: "Unable to construct one of the L1 MBeans: this is a programming error in one of those beans",
069: ncmbe);
070: }
071: mBeanServerLock = new Object();
072: }
073:
074: public synchronized void start() {
075: started.set();
076: Thread registrationThread = new Thread(new Runnable() {
077:
078: private final int MAX_ATTEMPTS = 60 * 5;
079:
080: public void run() {
081: boolean registered = false;
082: int attemptCounter = 0;
083: while (!registered && attemptCounter++ < MAX_ATTEMPTS) {
084: try {
085: if (logger.isDebugEnabled()) {
086: logger
087: .debug("Attempt #"
088: + (attemptCounter + 1)
089: + " to find the MBeanServer and register the L1 MBeans");
090: }
091: attemptToRegister();
092: registered = true;
093: if (logger.isDebugEnabled()) {
094: logger
095: .debug("L1 MBeans registered with the MBeanServer successfully after "
096: + (attemptCounter + 1)
097: + " attempts");
098: }
099: } catch (Exception e) {
100: // Ignore and try again after 1 second, give the VM a chance to get started
101: if (logger.isDebugEnabled()) {
102: logger
103: .debug(
104: "Caught exception while trying to register L1 MBeans",
105: e);
106: }
107: try {
108: Thread.sleep(1000);
109: } catch (InterruptedException ie) {
110: new Exception(
111: "JMX registration thread interrupted, management beans will not be available",
112: ie).printStackTrace();
113: }
114: }
115: }
116: if (registered) {
117: tunnelingHandler.jmxIsReady();
118: } else {
119: logger
120: .error("Aborted attempts to register management"
121: + " beans after "
122: + (MAX_ATTEMPTS / 60)
123: + " min of trying.");
124: }
125: }
126: }, "L1Management JMX registration");
127: registrationThread.setDaemon(true);
128: registrationThread.start();
129: }
130:
131: public Object findMBean(final ObjectName objectName,
132: final Class mBeanInterface) throws IOException {
133: if (objectName.equals(MBeanNames.CLIENT_TX_INTERNAL))
134: return clientTxBean;
135: else if (objectName.equals(MBeanNames.SESSION_INTERNAL))
136: return internalSessionBean;
137: else if (objectName.equals(L1MBeanNames.SESSION_PRODUCT_PUBLIC))
138: return publicSessionBean;
139: else {
140: synchronized (mBeanServerLock) {
141: if (mBeanServer != null) {
142: return findMBean(objectName, mBeanInterface,
143: mBeanServer);
144: }
145: }
146: }
147: return null;
148: }
149:
150: public ClientTxMonitorMBean findClientTxMonitorMBean() {
151: return clientTxBean;
152: }
153:
154: public SessionMonitorMBean findSessionMonitorMBean() {
155: return internalSessionBean;
156: }
157:
158: public TerracottaCluster getTerracottaCluster() {
159: return clusterBean;
160: }
161:
162: private void attemptToRegister()
163: throws InstanceAlreadyExistsException,
164: MBeanRegistrationException, NotCompliantMBeanException,
165: SecurityException, IllegalArgumentException,
166: NoSuchMethodException, ClassNotFoundException,
167: IllegalAccessException, InvocationTargetException {
168: synchronized (mBeanServerLock) {
169: if (mBeanServer == null) {
170: if (Vm.isJDK14()) {
171: List mBeanServers = MBeanServerFactory
172: .findMBeanServer(null);
173: if (mBeanServers != null && !mBeanServers.isEmpty()) {
174: mBeanServer = (MBeanServer) mBeanServers.get(0);
175: } else {
176: if (logger.isDebugEnabled()) {
177: logger
178: .debug("attemptToRegister(): Inside a 1.4 runtime, try to create an MBeanServer");
179: }
180: mBeanServer = MBeanServerFactory
181: .createMBeanServer();
182: }
183: } else {
184: // CDV-260: Make sure to use java.lang.management.ManagementFactory.getPlatformMBeanServer() on JDK 1.5+
185: if (logger.isDebugEnabled()) {
186: logger
187: .debug("attemptToRegister(): Inside a 1.5+ runtime, trying to get the platform default MBeanServer");
188: }
189: mBeanServer = getPlatformDefaultMBeanServer();
190: }
191: addJMXConnectors();
192: }
193: }
194: mBeanServer.registerMBean(clientTxBean,
195: MBeanNames.CLIENT_TX_INTERNAL);
196: mBeanServer.registerMBean(internalSessionBean,
197: MBeanNames.SESSION_INTERNAL);
198: mBeanServer.registerMBean(publicSessionBean,
199: L1MBeanNames.SESSION_PRODUCT_PUBLIC);
200: mBeanServer.registerMBean(clusterBean,
201: L1MBeanNames.CLUSTER_BEAN_PUBLIC);
202: }
203:
204: private void addJMXConnectors() {
205: JMXServiceURL url = null;
206: try {
207: // LKC-2990 and LKC-3171: Remove the JMX generic optional logging
208: java.util.logging.Logger jmxLogger = java.util.logging.Logger
209: .getLogger("javax.management.remote.generic");
210: jmxLogger.setLevel(java.util.logging.Level.OFF);
211: } catch (Throwable t) {
212: logger
213: .warn("Unable to disable default logging in Sun's JMX package; when Terracotta clients go"
214: + " up/down you may see stack traces printed to the log");
215: }
216: try {
217: final Map environment = new HashMap();
218: ProtocolProvider.addTerracottaJmxProvider(environment);
219: environment.put(
220: TunnelingMessageConnectionServer.TUNNELING_HANDLER,
221: tunnelingHandler);
222: url = new JMXServiceURL("terracotta", "localhost", 0);
223: // Normally you should NOT do this in the client, but we have a modified version of jmxremote_optional.jar that
224: // uses a daemon thread to wait for connections so we don't hang the client
225: final JMXConnectorServer connServer = JMXConnectorServerFactory
226: .newJMXConnectorServer(url, environment,
227: mBeanServer);
228: connServer.start();
229: logger.info("Terracotta JMX connector available at[" + url
230: + "]");
231: } catch (Exception e) {
232: if (url != null) {
233: logger.warn(
234: "Unable to start embedded JMX connector for url["
235: + url + "]", e);
236: } else {
237: logger
238: .warn("Unable to construct embedded JMX connector URL with params (terracotta, localhost, 0)");
239: }
240: }
241: }
242:
243: private MBeanServer getPlatformDefaultMBeanServer()
244: throws SecurityException, NoSuchMethodException,
245: ClassNotFoundException, IllegalArgumentException,
246: IllegalAccessException, InvocationTargetException {
247: // 1.5+, this code is irritating since this class needs to compile against 1.4
248: Class managementFactoryClass = Class
249: .forName("java.lang.management.ManagementFactory");
250: Method getPlatformMBeanServerMethod = managementFactoryClass
251: .getDeclaredMethod("getPlatformMBeanServer",
252: new Class[0]);
253: return (MBeanServer) getPlatformMBeanServerMethod.invoke(null,
254: new Object[0]);
255: }
256:
257: }
|