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.log.Logger;
33  import org.eclipse.jetty.util.thread.ShutdownThread;
34  
35  
36  /* ------------------------------------------------------------ */
37  /**
38   * AbstractLifeCycle wrapper for JMXConnector Server
39   */
40  public class ConnectorServer extends AbstractLifeCycle
41  {
42      private static final Logger LOG = Log.getLogger(ConnectorServer.class);
43  
44      JMXConnectorServer _connectorServer;
45      Registry _registry;
46      
47      /* ------------------------------------------------------------ */
48      /**
49       * Constructs connector server
50       * 
51       * @param serviceURL the address of the new connector server.
52       * The actual address of the new connector server, as returned 
53       * by its getAddress method, will not necessarily be exactly the same.
54       * @param name object name string to be assigned to connector server bean
55       * @throws Exception
56       */
57      public ConnectorServer(JMXServiceURL serviceURL, String name)
58          throws Exception
59      {
60          this(serviceURL, null, name);
61      }
62      
63      /* ------------------------------------------------------------ */
64      /**
65       * Constructs connector server
66       * 
67       * @param svcUrl the address of the new connector server.
68       * The actual address of the new connector server, as returned 
69       * by its getAddress method, will not necessarily be exactly the same.
70       * @param environment  a set of attributes to control the new connector
71       * server's behavior. This parameter can be null. Keys in this map must
72       * be Strings. The appropriate type of each associated value depends on
73       * the attribute. The contents of environment are not changed by this call. 
74       * @param name object name string to be assigned to connector server bean
75       * @throws Exception
76       */
77      public ConnectorServer(JMXServiceURL svcUrl, Map<String,?> environment, String name)
78           throws Exception
79      {
80      	String urlPath = svcUrl.getURLPath();
81      	int idx = urlPath.indexOf("rmi://");
82      	if (idx > 0)
83      	{
84      	    String hostPort = urlPath.substring(idx+6, urlPath.indexOf('/', idx+6));
85      	    String regHostPort = startRegistry(hostPort);
86      	    if (regHostPort != null) {
87      	        urlPath = urlPath.replace(hostPort,regHostPort);
88      	        svcUrl = new JMXServiceURL(svcUrl.getProtocol(), svcUrl.getHost(), svcUrl.getPort(), urlPath);
89      	    }
90      	}
91          MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
92          _connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(svcUrl, environment, mbeanServer);
93          mbeanServer.registerMBean(_connectorServer,new ObjectName(name));
94      }
95  
96  	/* ------------------------------------------------------------ */
97      /**
98       * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
99       */
100     @Override
101     public void doStart()
102         throws Exception
103     {
104         _connectorServer.start();
105         ShutdownThread.register(0, this);       
106         
107         LOG.info("JMX Remote URL: {}", _connectorServer.getAddress().toString());
108     }
109     
110     /* ------------------------------------------------------------ */
111     /**
112      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
113      */
114     @Override
115     public void doStop()
116         throws Exception
117     {
118         ShutdownThread.deregister(this);
119         _connectorServer.stop();
120         stopRegistry();
121     }
122 
123     /**
124      * Check that local RMI registry is used, and ensure it is started. If local RMI registry is being used and not started, start it.
125      * 
126      * @param hostPath
127      *            hostname and port number of RMI registry
128      * @throws Exception
129      */
130     private String startRegistry(String hostPath) throws Exception
131     {
132         int rmiPort = 1099; // default RMI registry port
133         String rmiHost = hostPath;
134 
135         int idx = hostPath.indexOf(':');
136         if (idx > 0)
137         {
138             rmiPort = Integer.parseInt(hostPath.substring(idx + 1));
139             rmiHost = hostPath.substring(0,idx);
140         }
141 
142         // Verify that local registry is being used
143         InetAddress hostAddress = InetAddress.getByName(rmiHost);
144         if(hostAddress.isLoopbackAddress())
145         {
146             if (rmiPort == 0)
147             {
148                 ServerSocket socket = new ServerSocket(0);
149                 rmiPort = socket.getLocalPort();
150                 socket.close();
151             }
152             else
153             {
154                 try
155                 {
156                     // Check if a local registry is already running
157                     LocateRegistry.getRegistry(rmiPort).list();
158                     return null;
159                 }
160                 catch (Exception ex)
161                 {
162                     LOG.ignore(ex);
163                 }
164             }
165 
166             _registry = LocateRegistry.createRegistry(rmiPort);
167             Thread.sleep(1000);
168             
169             rmiHost = InetAddress.getLocalHost().getCanonicalHostName();
170             return rmiHost + ':' + Integer.toString(rmiPort);
171         }
172         
173         return null;
174     }
175 
176     private void stopRegistry()
177     {
178         if (_registry != null)
179         {
180             try
181             {
182                 UnicastRemoteObject.unexportObject(_registry,true);
183             }
184             catch (Exception ex)
185             {
186                 LOG.ignore(ex);
187             }
188         }
189     }
190 }