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
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
00157
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
00169 Class clazz = Thread.currentThread().getContextClassLoader().loadClass(MX4J_LOG_CLASSNAME);
00170 Class mx4jLoggerClass = Thread.currentThread().getContextClassLoader().loadClass(MX4J_LOGGER_CLASS);
00171
00172
00173
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
00199
00200 RMIConnector rmiConnector = new RMIConnectorImpl(getJmxServer());
00201
00202 InitialContext ictx = new InitialContext();
00203 rmiConnectorName = "RMIConnector_" + serverName;
00204 ictx.bind(rmiConnectorName, rmiConnector);
00205 ictx.close();
00206
00207
00208
00209
00210
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
00218 myCarolConfig.put(protocol, carolConfig.getRMIProperties(protocol));
00219
00220 }
00221 int nbProtocols = myCarolConfig.size();
00222
00223 connectorServerURLs = new JMXServiceURL[nbProtocols];
00224 connectorServers = new JMXConnectorServer[nbProtocols];
00225
00226 int i = 0;
00227 String serviceURL = null;
00228
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
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
00249 myProtocol = "jeremie";
00250 myName = "jeremieconnector_" + serverName;
00251
00252
00253
00254 serviceURL = "service:jmx:rmi://" + myHost + "/jndi/jrmi://"
00255 + myHost + ":" + myPort + "/"
00256 + myName;
00257 } else if (carolProtocol.equals(IIOP)) {
00258
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
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
00274 JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, (Map) props, null);
00275 connectorServers[i] = connectorServer;
00276
00277 String connectorObjectName = "connector_" + carolProtocol;
00278 ObjectName connectorServerName = JonasObjectName.jmxConnectorServer(myProtocol, connectorObjectName);
00279 getJmxServer().registerMBean(connectorServer, connectorServerName);
00280
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
00298
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
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
00323
00324
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
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
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
00369 ObjectName registeredOn = ((MBeanServerNotification) notification).getMBeanName();
00370 String name = registeredOn.getKeyProperty("name");
00371
00372 if ((name != null) && (name.equals("discoveryEnroller") || name.equals("discoveryClient"))) {
00373 if (type.equals(MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
00374 try {
00375
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
00382 e.printStackTrace();
00383 }
00384 }
00385 if (type.equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
00386 try {
00387
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
00394 e.printStackTrace();
00395 } catch (ListenerNotFoundException e) {
00396
00397 e.printStackTrace();
00398 }
00399 }
00400 }
00401 } else {
00402
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
00448 if (managedServersToUrls.containsKey(serverName)) {
00449
00450 ArrayList urls = (ArrayList) managedServersToUrls.get(serverName);
00451 if (!urls.contains(connectorServerURL)) {
00452
00453 urls.add(connectorServerURL);
00454 }
00455 } else {
00456
00457 ArrayList urls = new ArrayList();
00458 urls.add(connectorServerURL);
00459 managedServersToUrls.put(serverName, urls);
00460 }
00461
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
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
00489 connection = null;
00490 } catch (IOException e) {
00491
00492 connection = null;
00493 } catch (java.lang.SecurityException e) {
00494
00495 connection = null;
00496 }
00497 if (connection != null) {
00498
00499 testConnection(connection, serverName);
00500 if (!managedServersToConnections.containsKey(serverName)) {
00501
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
00508
00509
00510
00511
00512
00513
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
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
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 }