View Javadoc

1   // ========================================================================
2   // Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.jmx;
15  
16  import java.lang.management.ManagementFactory;
17  import java.net.InetAddress;
18  import java.net.ServerSocket;
19  import java.rmi.registry.LocateRegistry;
20  import java.rmi.registry.Registry;
21  import java.rmi.server.UnicastRemoteObject;
22  import java.util.Map;
23  
24  import javax.management.MBeanServer;
25  import javax.management.ObjectName;
26  import javax.management.remote.JMXConnectorServer;
27  import javax.management.remote.JMXConnectorServerFactory;
28  import javax.management.remote.JMXServiceURL;
29  
30  import org.eclipse.jetty.util.component.AbstractLifeCycle;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.thread.ShutdownThread;
33  
34  
35  /* ------------------------------------------------------------ */
36  /**
37   * AbstractLifeCycle wrapper for JMXConnector Server
38   */
39  public class ConnectorServer extends AbstractLifeCycle
40  {
41      JMXConnectorServer _connectorServer;
42      Registry _registry;
43      
44      /* ------------------------------------------------------------ */
45      /**
46       * Constructs connector server
47       * 
48       * @param serviceURL the address of the new connector server.
49       * The actual address of the new connector server, as returned 
50       * by its getAddress method, will not necessarily be exactly the same.
51       * @param name object name string to be assigned to connector server bean
52       * @throws Exception
53       */
54      public ConnectorServer(JMXServiceURL serviceURL, String name)
55          throws Exception
56      {
57          this(serviceURL, null, name);
58      }
59      
60      /* ------------------------------------------------------------ */
61      /**
62       * Constructs connector server
63       * 
64       * @param svcUrl the address of the new connector server.
65       * The actual address of the new connector server, as returned 
66       * by its getAddress method, will not necessarily be exactly the same.
67       * @param environment  a set of attributes to control the new connector
68       * server's behavior. This parameter can be null. Keys in this map must
69       * be Strings. The appropriate type of each associated value depends on
70       * the attribute. The contents of environment are not changed by this call. 
71       * @param name object name string to be assigned to connector server bean
72       * @throws Exception
73       */
74      public ConnectorServer(JMXServiceURL svcUrl, Map<String,?> environment, String name)
75           throws Exception
76      {
77      	String urlPath = svcUrl.getURLPath();
78      	int idx = urlPath.indexOf("rmi://");
79      	if (idx > 0)
80      	{
81      	    String hostPort = urlPath.substring(idx+6, urlPath.indexOf('/', idx+6));
82      	    String regHostPort = startRegistry(hostPort);
83      	    if (regHostPort != null) {
84      	        urlPath = urlPath.replace(hostPort,regHostPort);
85      	        svcUrl = new JMXServiceURL(svcUrl.getProtocol(), svcUrl.getHost(), svcUrl.getPort(), urlPath);
86      	    }
87      	}
88          MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
89          _connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(svcUrl, environment, mbeanServer);
90          mbeanServer.registerMBean(_connectorServer,new ObjectName(name));
91      }
92  
93  	/* ------------------------------------------------------------ */
94      /**
95       * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
96       */
97      @Override
98      public void doStart()
99          throws Exception
100     {
101         _connectorServer.start();
102         ShutdownThread.register(0, this);       
103         
104         Log.info("JMX Remote URL: {}", _connectorServer.getAddress().toString());
105     }
106     
107     /* ------------------------------------------------------------ */
108     /**
109      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
110      */
111     @Override
112     public void doStop()
113         throws Exception
114     {
115         ShutdownThread.deregister(this);
116         _connectorServer.stop();
117         stopRegistry();
118     }
119 
120     /**
121      * Check that local RMI registry is used, and ensure it is started. If local RMI registry is being used and not started, start it.
122      * 
123      * @param hostPath
124      *            hostname and port number of RMI registry
125      * @throws Exception
126      */
127     private String startRegistry(String hostPath) throws Exception
128     {
129         int rmiPort = 1099; // default RMI registry port
130         String rmiHost = hostPath;
131 
132         int idx = hostPath.indexOf(':');
133         if (idx > 0)
134         {
135             rmiPort = Integer.parseInt(hostPath.substring(idx + 1));
136             rmiHost = hostPath.substring(0,idx);
137         }
138 
139         // Verify that local registry is being used
140         InetAddress hostAddress = InetAddress.getByName(rmiHost);
141         if(hostAddress.isLoopbackAddress())
142         {
143             if (rmiPort == 0)
144             {
145                 ServerSocket socket = new ServerSocket(0);
146                 rmiPort = socket.getLocalPort();
147                 socket.close();
148             }
149             else
150             {
151                 try
152                 {
153                     // Check if a local registry is already running
154                     LocateRegistry.getRegistry(rmiPort).list();
155                     return null;
156                 }
157                 catch (Exception ex)
158                 {
159                     Log.ignore(ex);
160                 }
161             }
162 
163             _registry = LocateRegistry.createRegistry(rmiPort);
164             Thread.sleep(1000);
165             
166             rmiHost = InetAddress.getLocalHost().getCanonicalHostName();
167             return rmiHost + ':' + Integer.toString(rmiPort);
168         }
169         
170         return null;
171     }
172 
173     private void stopRegistry()
174     {
175         if (_registry != null)
176         {
177             try
178             {
179                 UnicastRemoteObject.unexportObject(_registry,true);
180             }
181             catch (Exception ex)
182             {
183                 Log.ignore(ex);
184             }
185         }
186     }
187 }