001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2006 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: JMXProxy.java 9871 2006-11-27 09:55:29Z danesa $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.management.monitoring;
025:
026: import java.io.IOException;
027: import java.net.MalformedURLException;
028: import java.util.ArrayList;
029: import java.util.Collection;
030: import java.util.HashMap;
031: import java.util.Map;
032: import java.util.Set;
033:
034: import javax.management.AttributeList;
035: import javax.management.MBeanServerConnection;
036: import javax.management.ObjectName;
037: import javax.management.remote.JMXConnector;
038: import javax.management.remote.JMXConnectorFactory;
039: import javax.management.remote.JMXServiceURL;
040: import javax.naming.Context;
041: import javax.naming.InitialContext;
042: import javax.naming.NamingException;
043:
044: import org.objectweb.carol.util.configuration.ConfigurationRepository;
045: import org.objectweb.carol.util.configuration.Protocol;
046:
047: import org.objectweb.jonas.common.Log;
048: import org.objectweb.jonas.jmx.J2eeObjectName;
049: import org.objectweb.jonas.jmx.JmxServiceImpl;
050: import org.objectweb.jonas.jmx.JonasObjectName;
051: import org.objectweb.jonas.service.ServiceManager;
052:
053: import org.objectweb.util.monolog.api.BasicLevel;
054: import org.objectweb.util.monolog.api.Logger;
055:
056: /**
057: * Abstract class acting as a JMXConnector client
058: * It is implemented by ServerProxy or ClusterDaemonProxy
059: * @author durieuxp
060: */
061: public abstract class JMXProxy {
062:
063: /**
064: * logger for traces.
065: */
066: protected static Logger logger = Log
067: .getLogger("org.objectweb.jonas.domain.management");
068:
069: /**
070: * Unique name of the remote object
071: */
072: protected String name = null;
073:
074: /**
075: * Domain Name
076: */
077: private String domain;
078:
079: /**
080: * The OBJECT_NAME of this Proxy MBean
081: * Must be initialized before checking connection.
082: */
083: protected String objectName = null;
084:
085: /**
086: * List of urls that can be used for connection
087: */
088: private ArrayList urls = null;
089: /**
090: * URL of the current connection
091: */
092: private String connectionUrl = null;
093:
094: /**
095: * JMX connection
096: */
097: protected MBeanServerConnection connection = null;
098:
099: /**
100: * JMX Connector
101: */
102: protected JMXConnector connector = null;
103:
104: /**
105: * Environment used to get the connection
106: */
107: protected Map env = new HashMap();
108:
109: protected JmxServiceImpl jmx = null;
110:
111: /**
112: * The server's ObjectName (this corresponds to the J2EEServer MBean registered
113: * in the represented server's MBean server)
114: */
115: protected ObjectName serverOn = null;
116:
117: /**
118: * ref on the DomainMonitor
119: */
120: DomainMonitor dm;
121:
122: /**
123: * State of the remote object (as seen from the proxy)
124: */
125: protected int state = INITIAL;
126:
127: /**
128: * This is the initial state
129: */
130: public static final int INITIAL = 0;
131:
132: /**
133: * This state is corresponding to the situation when the
134: * JMX connection is broken - maybe temporary.
135: */
136: public static final int UNREACHABLE = 1;
137:
138: /**
139: * Server is RUNNING and its reacheable
140: */
141: public static final int RUNNING = 2;
142:
143: /**
144: * Server is stopped
145: */
146: public static final int STOPPED = 3;
147:
148: /**
149: * Server which can't be reached after a several number
150: * of retries
151: */
152: public static final int FAILED = 4;
153:
154: /**
155: * Server which started without the discovery and can't be reached after
156: * a several number of retries
157: */
158: public static final int UNKNOWN = 5;
159:
160: /**
161: * Server is starting (temporary state)
162: */
163: public static final int STARTING = 6;
164:
165: /**
166: * Server is stopping (temporary state)
167: */
168: public static final int STOPPING = 7;
169:
170: /**
171: * Constructor
172: * @param name the proxy name
173: * @param urls the urls that can be used to establish connection
174: * @param dm reference to the domain monitor
175: */
176: public JMXProxy(DomainMonitor dm, String name, Collection urls) {
177: this .dm = dm;
178: this .name = name;
179: logger.log(BasicLevel.DEBUG, name);
180:
181: // Useful for registering mbeans
182: jmx = (JmxServiceImpl) ServiceManager.getInstance()
183: .getJmxService();
184: domain = JonasObjectName.getDomain();
185: serverOn = J2eeObjectName.J2EEServer(domain, name);
186: logger.log(BasicLevel.DEBUG, serverOn);
187:
188: // Connection may be done later or now
189: if (urls != null) {
190: if (connect(urls)) {
191: // If connection was established, set state to "RUNNING".
192: state = RUNNING;
193: }
194: }
195: }
196:
197: /**
198: * Return the int giving the server state
199: * @return the state value as an int
200: */
201: public int getServerState() {
202: return state;
203: }
204:
205: /**
206: * MBean method returning the state as a String
207: * Return the String form of the server state
208: * @return the state value
209: */
210: public String getState() {
211: switch (state) {
212: case INITIAL:
213: return "INIT";
214: case UNREACHABLE:
215: return "UNREACHABLE";
216: case RUNNING:
217: return "RUNNING";
218: case STOPPED:
219: return "STOPPED";
220: case FAILED:
221: return "FAILED";
222: case STARTING:
223: return "STARTING";
224: case STOPPING:
225: return "STOPPING";
226: default:
227: return "UNKNOWN";
228: }
229: }
230:
231: /**
232: * Disconnect the proxy
233: */
234: public void disconnect() {
235: if (connector != null) {
236: connection = null;
237: try {
238: connector.close();
239: } catch (IOException e) {
240: }
241: }
242: }
243:
244: /**
245: * Try to connect this Proxy to its Server
246: * @param urls the urls that can be used to establish connection
247: * @return True if connected
248: */
249: public boolean connect(Collection urls) {
250: logger.log(BasicLevel.DEBUG, name);
251:
252: this .urls = new ArrayList(urls);
253:
254: // For now, just use the first url
255: // Later: try all urls until connection is OK.
256: String urlstr = (String) urls.iterator().next();
257:
258: JMXServiceURL url = null;
259:
260: // Create the JMXConnector client
261: try {
262: url = new JMXServiceURL(urlstr);
263: } catch (MalformedURLException e) {
264: logger.log(BasicLevel.ERROR, "Malformed URL:" + urlstr);
265: return false;
266: }
267: if (url.getProtocol().equals("iiop")) {
268: try {
269: env.put("java.naming.corba.orb", new InitialContext()
270: .lookup("java:comp/ORB"));
271: } catch (NamingException e) {
272: logger.log(BasicLevel.ERROR,
273: "Cannot get InitialContext: " + e);
274: }
275: }
276:
277: String initCtxClass = null;
278: String providerUrl = null;
279: try {
280: String urlPath = url.getURLPath();
281: String protocol = JmxServiceImpl
282: .getProtocolFromJmxConnectorUrl(urlPath);
283: Protocol p = ConfigurationRepository.getProtocol(protocol);
284: initCtxClass = p.getInitialContextFactoryClassName();
285: providerUrl = JmxServiceImpl
286: .getProviderUrlFromJmxConnectorUrl(urlPath);
287: } catch (Exception e) {
288: logger.log(BasicLevel.WARN,
289: "Unable to get the InitialContext from the protocol '"
290: + url.getProtocol() + "'");
291: }
292: if (initCtxClass != null) {
293: env.put(Context.INITIAL_CONTEXT_FACTORY, initCtxClass);
294: env.put(Context.PROVIDER_URL, providerUrl);
295: if (logger.isLoggable(BasicLevel.DEBUG)) {
296: logger
297: .log(BasicLevel.DEBUG,
298: "Setting the InitialContext to "
299: + initCtxClass);
300: }
301: }
302:
303: // First close old connections
304: disconnect();
305:
306: // Get the Connection to the JMXConnector
307: try {
308: connector = JMXConnectorFactory.connect(url, env);
309: connection = connector.getMBeanServerConnection();
310: } catch (IOException e) {
311: logger.log(BasicLevel.DEBUG, "JMXConnectorFactory error: "
312: + e);
313: }
314:
315: if (connection == null) {
316: connectionUrl = null;
317: return false;
318: } else {
319: if (checkConnection(connection)) {
320: if (logger.isLoggable(BasicLevel.DEBUG)) {
321: logger.log(BasicLevel.DEBUG, "connected to server "
322: + name + " using URL: " + urlstr);
323: }
324: connectionUrl = urlstr;
325: return true;
326: } else {
327: connectionUrl = null;
328: return false;
329: }
330: }
331: }
332:
333: /**
334: * Used by the connect method to check that the newlly created connection works
335: * @param connection connection to check
336: * @return true if access to the MBean server does not generate an exception,
337: * false otherwise
338: */
339: private boolean checkConnection(MBeanServerConnection connection) {
340: try {
341: int nb = connection.getMBeanCount().intValue();
342: return true;
343: } catch (IOException e) {
344: logger.log(BasicLevel.DEBUG, name + " : IOException");
345: }
346: return false;
347: }
348:
349: /**
350: * Check the established connection to the remote object, or try to establish
351: * a connection if the connection object is null.
352: * @return true if connection is ok.
353: */
354: protected boolean checkConnection() {
355: if (connection == null) {
356: logger.log(BasicLevel.DEBUG, name + " : null connection");
357: return connect(this .urls);
358: }
359: try {
360: int nb = connection.getMBeanCount().intValue();
361: if (logger.isLoggable(BasicLevel.DEBUG)) {
362: logger.log(BasicLevel.DEBUG, name + ": mbeans nb ="
363: + nb);
364: }
365: return true;
366: } catch (IOException e) {
367: logger.log(BasicLevel.DEBUG, name + " : IOException");
368: }
369: return false;
370: }
371:
372: /**
373: * @return The name of the remote object
374: */
375: public String getName() {
376: return name;
377: }
378:
379: /**
380: * Return this MBean's name
381: * @return The name of the MBean (see OBJECT_NAME in the JSR77)
382: */
383: public String getObjectName() {
384: return objectName;
385: }
386:
387: /**
388: * Set its OBJECT_NAME and register the MBean
389: * @param on OBJECT_NAME
390: */
391: public void setObjectName(String on) {
392: objectName = on;
393: jmx.registerMBean(this , on);
394: }
395:
396: /**
397: * @return the connection to the remote MBean server
398: */
399: public MBeanServerConnection getConnection() {
400: return connection;
401: }
402:
403: // ---------------------------------------------------------------------------
404: // Methods to access the remote mbean server
405: // All this replace the corresponding ManagementReprImpl methods, i.e. :
406: // ManagementReprLoader.loadServerReprForCluster(name, connection);
407: // return JonasManagementRepr.isRegistered(on, name);
408: // See jonas.jmx.ManagementReprImpl
409: // ---------------------------------------------------------------------------
410:
411: /**
412: * Check if an ObjectName is registered on the remote server
413: * @param on the ObjectName to be checked
414: * @return true if registered
415: */
416: public boolean isRegistered(ObjectName on) {
417: if (!checkConnection()) {
418: logger.log(BasicLevel.ERROR, "Not yet connected!");
419: return false;
420: }
421: try {
422: return connection.isRegistered(on);
423: } catch (IOException e) {
424: logger.log(BasicLevel.ERROR, "IO ERROR", e);
425: return false;
426: }
427: }
428:
429: /**
430: * Get an MBean Attribute on the remote server
431: * @param on the MBean's ObjectName
432: * @param attribute the attribute name
433: * @return the attribute value
434: */
435: public Object getAttribute(ObjectName on, String attribute) {
436: if (!checkConnection()) {
437: logger.log(BasicLevel.ERROR, "Not yet connected!");
438: return null;
439: }
440: try {
441: return connection.getAttribute(on, attribute);
442: } catch (Exception e) {
443: logger.log(BasicLevel.ERROR, "Cannot get attribute", e);
444: return null;
445: }
446: }
447:
448: /**
449: * Get a group of MBean Attributes on the remote server
450: * @param on the MBean's ObjectName
451: * @param attributes the attributes names
452: * @return a list of Attribute objects containing for each attribute
453: * its name and value
454: */
455: public AttributeList getAttributes(ObjectName on,
456: String[] attributes) {
457: if (!checkConnection()) {
458: logger.log(BasicLevel.ERROR, "Not yet connected!");
459: return null;
460: }
461: try {
462: return connection.getAttributes(on, attributes);
463: } catch (Exception e) {
464: logger.log(BasicLevel.ERROR, "Cannot get attribute", e);
465: return null;
466: }
467: }
468:
469: /**
470: * @param on the MBean's ObjectName
471: * @return A set containing the ObjectNames for the MBeans selected.
472: */
473: public Set queryNames(ObjectName on) {
474: if (!checkConnection()) {
475: logger.log(BasicLevel.ERROR, "Not yet connected!");
476: return null;
477: }
478: try {
479: return connection.queryNames(on, null);
480: } catch (Exception e) {
481: logger.log(BasicLevel.ERROR, "Cannot get attribute", e);
482: return null;
483: }
484: }
485:
486: /**
487: * @return the current domain name
488: */
489: public String getDomain() {
490: return domain;
491: }
492:
493: /**
494: * @return the URL of the current connection
495: */
496: public String getConnectionUrl() {
497: return connectionUrl;
498: }
499:
500: /**
501: * @return the list of urls that can be used for connection
502: */
503: public ArrayList getUrls() {
504: return urls;
505: }
506: /**
507: * @param urls the list of urls that can be used for connection
508: */
509: /*
510: public void setUrls(ArrayList urls) {
511: this.urls = urls;
512: }*/
513: }
|