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