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