JmxServiceImpl.java

00001 
00025 package org.objectweb.jonas.jmx;
00026 
00027 import java.io.IOException;
00028 import java.lang.reflect.Method;
00029 import java.net.MalformedURLException;
00030 import java.net.URI;
00031 import java.util.ArrayList;
00032 import java.util.HashMap;
00033 import java.util.Iterator;
00034 import java.util.Map;
00035 import java.util.Properties;
00036 import java.util.StringTokenizer;
00037 
00038 import javax.management.InstanceNotFoundException;
00039 import javax.management.JMException;
00040 import javax.management.ListenerNotFoundException;
00041 import javax.management.MBeanServerConnection;
00042 import javax.management.MBeanServerNotification;
00043 import javax.management.Notification;
00044 import javax.management.NotificationListener;
00045 import javax.management.ObjectName;
00046 import javax.management.remote.JMXConnector;
00047 import javax.management.remote.JMXConnectorFactory;
00048 import javax.management.remote.JMXConnectorServer;
00049 import javax.management.remote.JMXConnectorServerFactory;
00050 import javax.management.remote.JMXServiceURL;
00051 import javax.naming.Context;
00052 import javax.naming.InitialContext;
00053 
00054 import org.objectweb.carol.util.configuration.CarolConfiguration;
00055 import org.objectweb.carol.util.configuration.CarolCurrentConfiguration;
00056 import org.objectweb.jonas.common.Log;
00057 import org.objectweb.jonas.discovery.DiscEvent;
00058 import org.objectweb.jonas.service.JonasAlreadyStartedException;
00059 import org.objectweb.jonas.service.ServiceException;
00060 import org.objectweb.util.monolog.api.BasicLevel;
00061 import org.objectweb.util.monolog.api.Logger;
00062 
00072 public class JmxServiceImpl extends AbsJmxServiceImpl implements NotificationListener {
00073 
00077     private static final String MX4J_COMMONS_LOGGER_CLASSNAME = "mx4j.log.CommonsLogger";
00078 
00082     private static final String MX4J_LOG_CLASSNAME = "mx4j.log.Log";
00083 
00087     private static final String MX4J_LOGGER_CLASS = "mx4j.log.Logger";
00088 
00094     private String rmiConnectorName = null;
00095 
00099     public String getRmiConnectorName() {
00100         return this.rmiConnectorName;
00101     }
00102 
00106     private static final String JRMP = "jrmp";
00110     private static final String IIOP = "iiop";
00114     private static final String JEREMIE = "jeremie";
00118     private static final String CMI = "cmi";
00125     private JMXConnectorServer[] connectorServers = null;
00126 
00130     private JMXServiceURL[] connectorServerURLs = null;
00131 
00132     // Domain management support
00136     private Map managedServersToUrls = null;
00140     private Map managedServersToConnectors = null;
00144     private Map managedServersToConnections = null;
00145 
00149     private static Logger logger = logger = Log.getLogger("org.objectweb.jonas.jmx");
00155     public void doInit(Context ctx) throws ServiceException {
00156         // Test if MX4J CommonsLoggger class is present.
00157         // In this case, redirect MX4J logging to Jakarta Commons Logging.
00158         Class mx4jCommonsLoggerClass = null;
00159         try {
00160             mx4jCommonsLoggerClass = Thread.currentThread().getContextClassLoader().loadClass(MX4J_COMMONS_LOGGER_CLASSNAME);
00161             if (logger.isLoggable(BasicLevel.DEBUG)) {
00162                 logger.log(BasicLevel.DEBUG, "Class " + MX4J_COMMONS_LOGGER_CLASSNAME + " founded");
00163             }
00164             Object o =  mx4jCommonsLoggerClass.newInstance();
00165 
00166 
00167 
00168             // Load Log a Logger class
00169             Class clazz = Thread.currentThread().getContextClassLoader().loadClass(MX4J_LOG_CLASSNAME);
00170             Class mx4jLoggerClass = Thread.currentThread().getContextClassLoader().loadClass(MX4J_LOGGER_CLASS);
00171 
00172 
00173             // Then get method redirectTo
00174             Method m = clazz.getMethod("redirectTo", new Class[] {mx4jLoggerClass});
00175             m.invoke(clazz, new Object[] {o});
00176             if (logger.isLoggable(BasicLevel.DEBUG)) {
00177                 logger.log(BasicLevel.DEBUG, "MX4J logging redirected to the Jakarta commons logger");
00178             }
00179         } catch (ClassNotFoundException cnfe) {
00180             if (logger.isLoggable(BasicLevel.DEBUG)) {
00181                 logger.log(BasicLevel.DEBUG, "Class " + MX4J_COMMONS_LOGGER_CLASSNAME + " not found: " + cnfe);
00182             }
00183         } catch (Exception e) {
00184             if (logger.isLoggable(BasicLevel.WARN)) {
00185                 logger.log(BasicLevel.WARN, "Problem with " + MX4J_COMMONS_LOGGER_CLASSNAME + " instance creation " + e);
00186             }
00187         }
00188         super.doInit(ctx);
00189     }
00195     public void doStart() throws ServiceException {
00196         String serverName = getJonasServerName();
00197         try {
00198             // Create a RMI Connector for the JMX agent using the JOnAS RMIConnector class
00199             // --------------------------------------------------------------------------
00200             RMIConnector rmiConnector = new RMIConnectorImpl(getJmxServer());
00201             // Register the connector in JNDI
00202             InitialContext ictx = new InitialContext();
00203             rmiConnectorName = "RMIConnector_" + serverName;
00204             ictx.bind(rmiConnectorName, rmiConnector);
00205             ictx.close();
00206 
00207             // Create one or more connector servers
00208             // (cf. JSR 160, JMX Remote 1.0)
00209             // ------------------------------------
00210             // Determine protocols used by Carol and their configuration
00211             String s = CarolConfiguration.getProtocols();
00212             StringTokenizer st = new StringTokenizer(s, ",", false);
00213             HashMap myCarolConfig = new HashMap();
00214             while (st.hasMoreElements()) {
00215                 CarolCurrentConfiguration carolConfig = CarolCurrentConfiguration.getCurrent();
00216                 String protocol = st.nextToken().trim();
00217                 //if (!protocol.equals(CMI)) {
00218                     myCarolConfig.put(protocol, carolConfig.getRMIProperties(protocol));
00219                 //}
00220             }
00221             int nbProtocols = myCarolConfig.size();
00222             // Create a JMXServiceURL and a JMXConnectorServer per protocol
00223             connectorServerURLs = new JMXServiceURL[nbProtocols];
00224             connectorServers = new JMXConnectorServer[nbProtocols];
00225             // index over connectorServerURLs
00226             int i = 0;
00227             String serviceURL = null;
00228             // arguments needed to construct a JMXServiceURL
00229             String myProtocol = null;
00230             String myHost = null;
00231             String myPort = null;
00232             String myName = null;
00233             for (Iterator it = myCarolConfig.keySet().iterator(); it.hasNext();) {
00234                 String carolProtocol = (String) it.next();
00235                 Properties props = (Properties) myCarolConfig.get(carolProtocol);
00236                 String sCarolURL = props.getProperty(Context.PROVIDER_URL);
00237                 URI carolURL = new URI(sCarolURL);
00238                 myHost = carolURL.getHost();
00239                 myPort = String.valueOf(carolURL.getPort());
00240                 if (carolProtocol.equals(JRMP)) {
00241                     // Treat JRMP case
00242                     myProtocol = "jrmp";
00243                     myName = "jrmpconnector_" + serverName;
00244                     serviceURL = "service:jmx:rmi://" + myHost + "/jndi/rmi://"
00245                         + myHost + ":" + myPort + "/"
00246                         + myName;
00247                 } else if (carolProtocol.equals(JEREMIE)) {
00248                     // Treat JEREMIE case
00249                     myProtocol = "jeremie";
00250                     myName = "jeremieconnector_" + serverName;
00251                     // PATCH for JEREMIE ONLY !!!!
00252                     //int anyNumber = 5;
00253                     //thePort = thePort + anyNumber;
00254                     serviceURL = "service:jmx:rmi://" + myHost + "/jndi/jrmi://"
00255                         + myHost + ":" + myPort + "/"
00256                         + myName;
00257                 } else if (carolProtocol.equals(IIOP)) {
00258                     // Treat IIOP case
00259                     myProtocol = "iiop";
00260                     myName = "iiopconnector_" + serverName;
00261                     serviceURL = "service:jmx:iiop://" + myHost + "/jndi/" + myName;
00262                     props.put("java.naming.corba.orb", new InitialContext().lookup("java:comp/ORB"));
00263 
00264                 } else if (carolProtocol.equals(CMI)) {
00265                     // Treat JRMP case
00266                     myProtocol = "cmi";
00267                     myName = "cmiconnector_" + serverName;
00268                     serviceURL = "service:jmx:rmi://" + myHost + "/jndi/cmi://"
00269                         + myHost + ":" + myPort + "/"
00270                         + myName;
00271                 }
00272                 JMXServiceURL url = new JMXServiceURL(serviceURL);
00273                 // Cast to Map is required for JDK 1.5
00274                 JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, (Map) props, null);
00275                 connectorServers[i] = connectorServer;
00276                 // Create the MBean associated to the connector
00277                 String connectorObjectName = "connector_" + carolProtocol;
00278                 ObjectName connectorServerName = JonasObjectName.jmxConnectorServer(myProtocol, connectorObjectName);
00279                 getJmxServer().registerMBean(connectorServer, connectorServerName);
00280                 // Start the JMXConnectorServer
00281                 try {
00282                     connectorServer.start();
00283                     connectorServerURLs[i] = connectorServer.getAddress();
00284                 } catch (IllegalArgumentException e) {
00285                     throw e;
00286                 }
00287                 i++;
00288             }
00289         } catch (javax.naming.NameAlreadyBoundException ne) {
00290             getLogger().log(BasicLevel.DEBUG, "Cannot start JMX service " + ne);
00291             throw new JonasAlreadyStartedException();
00292         } catch (Exception e) {
00293             getLogger().log(BasicLevel.DEBUG, "Cannot start JMX service " + e);
00294             throw new ServiceException("Cannot start JMX service", e);
00295         }
00296 
00297         // Registers as listener to notifications emitted by MBeanServerDelegate
00298         // MBeanServerDelegate is the MBean which sends registration/unregistration notifications
00299         try {
00300             ObjectName delegate = ObjectName.getInstance("JMImplementation:type=MBeanServerDelegate");
00301             getJmxServer().addNotificationListener(delegate, this, null, null);
00302         } catch (JMException me) {
00303             if (logger.isLoggable(BasicLevel.DEBUG)) {
00304                 logger.log(BasicLevel.DEBUG, "JMX service could not be added as notification listener for MBeanServerNotifications " +
00305                         "related to the REGISTRATION or UNREGISTRETION of JOnAS management MBeans");
00306             }
00307         }
00308         // Create data structures allowing to manage the servers in the domain
00309         managedServersToConnectors = new HashMap();
00310         managedServersToConnections = new HashMap();
00311         managedServersToUrls = new HashMap();
00312     }
00316     public void doStop() {
00317         try {
00318             InitialContext ictx = new InitialContext();
00319             ictx.unbind("RMIConnector_" + getJonasServerName());
00320             ictx.close();
00321 
00322             // Desactivates the connector server, that is, stops listening for client connections.
00323             // Calling this method will also close all client connections that were made by this server.
00324             // Being a potentialy slow operation, we keep it commented for the moment
00325             for (int i = 0; i < connectorServers.length; i++) {
00326                 connectorServers[i].stop();
00327             }
00328         } catch (Exception e) {
00329             getLogger().log(BasicLevel.ERROR, "Cannot Unbind Jmx RMI Connector" + e);
00330         }
00331         // Unregister some MBeans
00332         ObjectName domainOn = J2eeObjectName.J2EEDomain(getDomainName());
00333         try {
00334             getJmxServer().unregisterMBean(domainOn);
00335         } catch (Exception e) {
00336             getLogger().log(BasicLevel.INFO, "Cannot unregister JEEDomain MBean:" + domainOn.toString());
00337         }
00338         ObjectName serverOn = J2eeObjectName.J2EEServer(getDomainName(), getJonasServerName());
00339         try {
00340             getJmxServer().unregisterMBean(serverOn);
00341         } catch (Exception e) {
00342             getLogger().log(BasicLevel.INFO, "Cannot unregister JEEServer MBean:" + serverOn.toString());
00343         }
00344         // Remove internal references to the MBeanServer.
00345         releaseJmxServer();
00346 
00347         getLogger().log(BasicLevel.DEBUG, "JMX Service stopped");
00348     }
00349 
00350 
00355     public JMXServiceURL[] getConnectorServerURLs() {
00356         return this.connectorServerURLs;
00357     }
00358 
00365     public void handleNotification(Notification notification, Object handback) {
00366         if (notification instanceof MBeanServerNotification) {
00367             String type = notification.getType();
00368             // ObjectName of the MBean that caused the notification
00369             ObjectName registeredOn = ((MBeanServerNotification) notification).getMBeanName();
00370             String name = registeredOn.getKeyProperty("name");
00371             // The names below are defined in JonasObjectName class
00372             if ((name != null) && (name.equals("discoveryEnroller") || name.equals("discoveryClient"))) {
00373                 if (type.equals(MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
00374                     try {
00375                         // register myself as listener of notifications emitted by the Enroller or DiscoveryClient MBean
00376                         getJmxServer().addNotificationListener(registeredOn, this, null, null);
00377                         if (logger.isLoggable(BasicLevel.DEBUG)) {
00378                             logger.log(BasicLevel.DEBUG, "J2EEDomain (this) registered as listener to notifs emitted by " + registeredOn);
00379                         }
00380                     } catch (InstanceNotFoundException e) {
00381                         // TODO Auto-generated catch block
00382                         e.printStackTrace();
00383                     }
00384                 }
00385                 if (type.equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
00386                     try {
00387                         // unregister myself as listener of notifications emitted by the Enroller or DiscoveryClient MBean
00388                         getJmxServer().removeNotificationListener(registeredOn, this);
00389                         if (logger.isLoggable(BasicLevel.DEBUG)) {
00390                             logger.log(BasicLevel.DEBUG, "J2EEDomain (this) removed listener for notifs emitted by " + registeredOn);
00391                         }
00392                     } catch (InstanceNotFoundException e) {
00393                         // TODO Auto-generated catch block
00394                         e.printStackTrace();
00395                     } catch (ListenerNotFoundException e) {
00396                         // TODO Auto-generated catch block
00397                         e.printStackTrace();
00398                     }
00399                 }
00400             }
00401         } else {
00402             // Tread discovery notification
00403             String type = notification.getType();
00404             String message = notification.getMessage();
00405             DiscEvent userData = (DiscEvent) notification.getUserData();
00406             String source = ((ObjectName) notification.getSource()).toString();
00407             String state = userData.getState();
00408             if (logger.isLoggable(BasicLevel.DEBUG)) {
00409                 logger.log(BasicLevel.DEBUG, "Treat notification:");
00410                 logger.log(BasicLevel.DEBUG, "- source: " + source);
00411                 logger.log(BasicLevel.DEBUG, "- type: " + type);
00412                 logger.log(BasicLevel.DEBUG, "- data: ");
00413                 logger.log(BasicLevel.DEBUG, "--- state: " + state);
00414                 logger.log(BasicLevel.DEBUG, "--- serverName : " + userData.getServerName());
00415                 logger.log(BasicLevel.DEBUG, "--- domainName : " + userData.getDomainName());
00416                 if (userData.getConnectorURL() != null) {
00417                     String[] urls = userData.getConnectorURL();
00418                     for (int i = 0; i < urls.length; i++) {
00419                         logger.log(BasicLevel.DEBUG, "--- urls : " + urls[i]);
00420                     }
00421                 }
00422                 logger.log(BasicLevel.DEBUG, "");
00423             }
00424             if (state.equals(DiscEvent.RUNNING)) {
00425                 String[] urls = userData.getConnectorURL();
00426                 for (int i = 0; i < urls.length; i++) {
00427                     addServer(userData.getDomainName(), userData.getServerName(), urls[i]);
00428                 }
00429             } else if (state.equals(DiscEvent.STOPPING)) {
00430                 removeServer(userData.getDomainName(), userData.getServerName());
00431             }
00432         }
00433     }
00442     public void addServer(String domainName, String serverName, String connectorServerURL) {
00443         if (logger.isLoggable(BasicLevel.DEBUG)) {
00444             logger.log(BasicLevel.DEBUG, "domain name: " + domainName + ", server name: " + serverName + ", url: " + connectorServerURL);
00445         }
00446         if (domainName.equals(getDomainName())) {
00447             // Server thet belongs to the current management domain
00448             if (managedServersToUrls.containsKey(serverName)) {
00449                 // This server is already known
00450                 ArrayList urls = (ArrayList) managedServersToUrls.get(serverName);
00451                 if (!urls.contains(connectorServerURL)) {
00452                     // Add this new connectorServerURL in the connectors list
00453                     urls.add(connectorServerURL);
00454                 }
00455             } else {
00456                 // Add new server
00457                 ArrayList urls = new ArrayList();
00458                 urls.add(connectorServerURL);
00459                 managedServersToUrls.put(serverName, urls);
00460             }
00461             // try to create a connection
00462             boolean created = createConnection(serverName, connectorServerURL);
00463         } else {
00464             if (logger.isLoggable(BasicLevel.WARN)) {
00465                 logger.log(BasicLevel.WARN, "The server named " + serverName + " was not started in the management domain "
00466                         + getDomainName() + ", but in management domain " + domainName);
00467             }
00468         }
00469     }
00470 
00477     private boolean createConnection(String serverName, String connectorServerURL) {
00478         boolean created = false;
00479         MBeanServerConnection connection;
00480         // create a connector client for the connector server at the given url
00481         JMXConnector connector = null;
00482         try {
00483             JMXServiceURL url = new JMXServiceURL(connectorServerURL);
00484             connector = JMXConnectorFactory.newJMXConnector(url, null);
00485             connector.connect(null);
00486             connection = connector.getMBeanServerConnection();
00487         } catch (MalformedURLException e) {
00488             // there is no provider for the protocol in url
00489             connection = null;
00490         } catch (IOException e) {
00491             // connector client or connection cannot be made because of a communication problem.
00492             connection = null;
00493         } catch (java.lang.SecurityException e) {
00494             // connection cannot be made for security reasons
00495             connection = null;
00496         }
00497         if (connection != null) {
00498             // OK, connection was established to the connector server.
00499             testConnection(connection, serverName);
00500             if (!managedServersToConnections.containsKey(serverName)) {
00501                 // add new connection and connector to managed data structure
00502                 managedServersToConnections.put(serverName, connection);
00503                 managedServersToConnectors.put(serverName, connector);
00504                 created = true;
00505                 logger.log(BasicLevel.INFO, "First MBeanServerConnection created for connecting to server " + serverName + " using URL: " + connectorServerURL);
00506             } else {
00507                 // A connection already exists.
00508                 // We have the following possibilities:
00509                 // - ignore this connection (close it), so continue to use the old one
00510                 // - replace the old one by the new one (close the old)
00511                 // - keep several connections
00512                 //
00513                 // Currently we keep only one connection, the new one (second approach)
00514                 JMXConnector oldConnector = (JMXConnector) managedServersToConnectors.get(serverName);
00515                 try {
00516                     oldConnector.close();
00517                 } catch (IOException e1) {
00518                 }
00519                 managedServersToConnectors.put(serverName, connector);
00520                 managedServersToConnections.put(serverName, connection);
00521                 created = true;
00522                 logger.log(BasicLevel.INFO, "New MBeanServerConnection created for connecting to server " + serverName + " using URL: " + connectorServerURL + "(replaces the old connection)");
00523             }
00524         } else {
00525             if (connector != null) {
00526                 try {
00527                     connector.close();
00528                 } catch (IOException e1) {
00529                 }
00530             }
00531         }
00532         return created;
00533     }
00534 
00535     private boolean testConnection(MBeanServerConnection connection, String serverName) {
00536         boolean ok = false;
00537         try {
00538             Integer nb = connection.getMBeanCount();
00539             /*
00540             System.out.println("IN TEST connection: got " + nb.toString() + " MBeans in the JMX server of JOnAS server " + serverName);
00541             */
00542             ok = true;
00543         } catch (IOException ioe) {
00544             ioe.printStackTrace();
00545         }
00546         return ok;
00547     }
00548 
00554     public void removeServer(String domainName, String serverName) {
00555         if (domainName.equals(getDomainName())) {
00556             // Server thet belongs to the current management domain
00557             managedServersToConnections.remove(serverName);
00558             JMXConnector connector = (JMXConnector) managedServersToConnectors.remove(serverName);
00559             if (connector != null) {
00560             try {
00561                 connector.close();
00562             } catch (IOException e1) {
00563             }
00564             }
00565             managedServersToUrls.remove(serverName);
00566         } else {
00567             if (logger.isLoggable(BasicLevel.WARN)) {
00568                 logger.log(BasicLevel.WARN, "The server named " + serverName + " was not started in the management domain "
00569                         + getDomainName() + ", but in management domain " + domainName);
00570             }
00571         }
00572     }
00578     public MBeanServerConnection getServerConnection(String serverName) {
00579         return (MBeanServerConnection) managedServersToConnections.get(serverName);
00580     }
00581 }

Generated on Tue Feb 15 15:05:16 2005 for JOnAS by  doxygen 1.3.9.1