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 }