001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Contact: sequoia@continuent.org
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: *
019: * Initial developer(s): Marc Wick.
020: * Contributor(s): ______________________.
021: */package org.continuent.sequoia.controller.jmx;
022:
023: import java.net.InetAddress;
024: import java.net.UnknownHostException;
025: import java.rmi.Remote;
026: import java.rmi.registry.LocateRegistry;
027: import java.rmi.server.UnicastRemoteObject;
028: import java.util.ArrayList;
029: import java.util.Date;
030: import java.util.Hashtable;
031: import java.util.Iterator;
032: import java.util.List;
033:
034: import javax.management.Notification;
035: import javax.management.remote.JMXAuthenticator;
036: import javax.management.remote.JMXConnectorServer;
037: import javax.management.remote.JMXServiceURL;
038: import javax.management.remote.rmi.RMIConnectorServer;
039:
040: import org.continuent.sequoia.common.authentication.PasswordAuthenticator;
041: import org.continuent.sequoia.common.i18n.Translate;
042: import org.continuent.sequoia.common.jmx.JmxException;
043: import org.continuent.sequoia.common.jmx.notifications.JmxNotification;
044: import org.continuent.sequoia.common.log.Trace;
045: import org.continuent.sequoia.common.net.RMISSLClientSocketFactory;
046: import org.continuent.sequoia.common.net.RMISSLServerSocketFactory;
047: import org.continuent.sequoia.common.net.SSLConfiguration;
048: import org.continuent.sequoia.common.net.SocketFactoryFactory;
049:
050: /**
051: * This class defines a RmiConnector
052: *
053: * @author <a href="mailto:marc.wick@monte-bre.ch">Marc Wick </a>
054: * @version 1.0
055: */
056: public class RmiConnector {
057: static Trace logger = Trace
058: .getLogger("org.continuent.sequoia.controller.jmx");
059:
060: private String controllerName;
061: private String hostName;
062: private int port;
063: private JMXAuthenticator authenticator;
064: private SSLConfiguration sslConfig;
065:
066: /**
067: * we have to keep a reference to the server to avoid it from being garbage
068: * collected otherwise the client will throw a java.rmi.NoSuchObjectException
069: * (problem experienced with ssl connections)
070: */
071: private JMXConnectorServer connection;
072: private Remote rmiRegistry;
073:
074: private static List rmiConnectors = new ArrayList();
075:
076: /**
077: * Creates a new <code>RmiConnector.java</code> object
078: *
079: * @param controllerName for reference when sending notification
080: * @param hostName the name of the host we bind to, if null the default
081: * InetAddress.getLocalHost().getHostName() is used
082: * @param port the port the rmi registry is listening on
083: * @param authenticator the jmxauthenticator used for the connection
084: * @param sslConfig ssl configuration
085: * @throws JmxException the name of the localhost could not be determined
086: */
087: public RmiConnector(String controllerName, String hostName,
088: int port, JMXAuthenticator authenticator,
089: SSLConfiguration sslConfig) throws JmxException {
090: if (hostName != null) {
091: this .hostName = hostName;
092: } else {
093: try {
094: /** TODO: dssmith - determine applicability of getLocalHost() */
095: this .hostName = InetAddress.getLocalHost()
096: .getHostName();
097: } catch (UnknownHostException ex) {
098: throw new JmxException(ex);
099: }
100: }
101: this .controllerName = controllerName;
102: this .port = port;
103: this .authenticator = authenticator;
104: this .sslConfig = sslConfig;
105:
106: addRmiConnector(this );
107: }
108:
109: /**
110: * Returns the authenticator value.
111: *
112: * @return Returns the authenticator.
113: */
114: public JMXAuthenticator getAuthenticator() {
115: return authenticator;
116: }
117:
118: /**
119: * Sets the authenticator value.
120: *
121: * @param authenticator The authenticator to set.
122: */
123: public void setAuthenticator(JMXAuthenticator authenticator) {
124: this .authenticator = authenticator;
125: }
126:
127: /**
128: * Returns the port value.
129: *
130: * @return Returns the port.
131: */
132: public int getPort() {
133: return port;
134: }
135:
136: /**
137: * Sets the port value.
138: *
139: * @param port The port to set.
140: */
141: public void setPort(int port) {
142: this .port = port;
143: }
144:
145: /**
146: * Returns the sslConfig value.
147: *
148: * @return Returns the sslConfig.
149: */
150: public SSLConfiguration getSslConfig() {
151: return sslConfig;
152: }
153:
154: /**
155: * Sets the sslConfig value.
156: *
157: * @param sslConfig The sslConfig to set.
158: */
159: public void setSslConfig(SSLConfiguration sslConfig) {
160: this .sslConfig = sslConfig;
161: }
162:
163: /**
164: * Returns the connection value.
165: *
166: * @return Returns the connection.
167: */
168: public JMXConnectorServer getConnection() {
169: return connection;
170: }
171:
172: /**
173: * start the rmi connector and the rmi naming service
174: *
175: * @throws JmxException an exception
176: */
177: public void start() throws JmxException {
178: createNamingService();
179: createJRMPAdaptor();
180: }
181:
182: /**
183: * stop the rmi connector and the rmi registry
184: *
185: * @throws JmxException an exception
186: */
187: public synchronized void stop() throws JmxException {
188: try {
189: if (connection != null)
190: connection.stop();
191: if (rmiRegistry != null)
192: UnicastRemoteObject.unexportObject(rmiRegistry, true);
193: } catch (Exception e) {
194: throw new JmxException(e);
195: } finally {
196: connection = null;
197: rmiRegistry = null;
198: }
199: }
200:
201: /**
202: * Create naming service and starts rmi
203: *
204: * @throws JmxException if creation fails
205: */
206: private void createNamingService() throws JmxException {
207: try {
208: // create and start the naming service
209: logger.info(Translate.get("jmx.create.naming.service",
210: new String[] { "" + port }));
211: rmiRegistry = LocateRegistry.createRegistry(port);
212: } catch (Exception e) {
213: throw new JmxException(e);
214: }
215: }
216:
217: private void createJRMPAdaptor() throws JmxException {
218: try {
219: // create the JRMP adaptator
220: logger.info(Translate.get("jmx.create.jrmp.adaptor", ""
221: + port));
222:
223: // Set the jndi name with which it will be registered
224: // JNDI properties
225: logger.debug(Translate.get("jmx.prepare.jndi"));
226:
227: JMXServiceURL address = new JMXServiceURL(
228: "service:jmx:rmi:///jndi/rmi://" + hostName + ":"
229: + port + "/jmxrmi");
230:
231: java.util.Map environment = new java.util.HashMap();
232:
233: if (authenticator == null) {
234: authenticator = PasswordAuthenticator.NO_AUTHENICATION;
235: }
236:
237: if (authenticator != null) {
238: environment.put(JMXConnectorServer.AUTHENTICATOR,
239: authenticator);
240: }
241:
242: // ssl enabled ?
243: if (sslConfig != null) {
244: logger.info(Translate
245: .get("jmx.create.jrmp.ssl.enabled"));
246:
247: RMISSLClientSocketFactory csf = new RMISSLClientSocketFactory();
248: RMISSLServerSocketFactory ssf = new RMISSLServerSocketFactory(
249: SocketFactoryFactory
250: .createServerFactory(sslConfig));
251: environment
252: .put(
253: RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
254: csf);
255: environment
256: .put(
257: RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
258: ssf);
259: }
260:
261: connection = javax.management.remote.JMXConnectorServerFactory
262: .newJMXConnectorServer(address, environment,
263: MBeanServerManager.getInstance());
264:
265: connection.start();
266: } catch (Exception e) {
267: throw new JmxException(e);
268: }
269: }
270:
271: /**
272: * Returns a list of rmiConnectors .
273: *
274: * @return Returns list of RmiConnector.
275: */
276: public static List getRmiConnectors() {
277: return rmiConnectors;
278: }
279:
280: /**
281: * Adds an rmiConnector to the list.
282: *
283: * @param pRmiConnector The rmiConnector to add.
284: */
285: private static synchronized void addRmiConnector(
286: RmiConnector pRmiConnector) {
287: rmiConnectors.add(pRmiConnector);
288: }
289:
290: /**
291: * @return Returns the controllerName.
292: */
293: public String getControllerName() {
294: return controllerName;
295: }
296:
297: /**
298: * @return Returns the hostName.
299: */
300: public String getHostName() {
301: return hostName;
302: }
303:
304: private Date myDate;
305: private long time;
306: private JmxNotification sequoiaNotification;
307: private Notification notification;
308: private static long sequence = 0;
309:
310: /**
311: * This method sends notification to all client registered to an instance of
312: * the <code>RmiConnector</code> class. The <code>JmxNotification</code>
313: * class is used here to create an object with all the information gathered in
314: * parameters, and then is serialized in xml for interaction on the client
315: * side.
316: *
317: * @see JmxNotification
318: * @param mbean the mbean that is generating the notification
319: * @param type the type as seen in <code>SequoiaNotificationList</code>
320: * @param priority notification level as seen in
321: * <code>SequoiaNotificationList</code>
322: * @param description a string description of the notification
323: * @param data a hashtable of data that can be used to give more information
324: * on the notification
325: */
326: public synchronized void sendNotification(
327: AbstractStandardMBean mbean, String type, String priority,
328: String description, Hashtable data) {
329:
330: myDate = new Date();
331: time = myDate.getTime();
332:
333: sequoiaNotification = new JmxNotification(priority, ""
334: + sequence, type, description, "" + time,
335: controllerName, mbean.getClass().getName(),
336: "mbeanName", hostName, "" + port, data);
337: notification = new Notification(type, mbean, sequence, myDate
338: .getTime(), description);
339: notification.setUserData(sequoiaNotification.toString());
340: mbean.sendNotification(notification);
341: }
342:
343: /**
344: * Broadcast a jmx notification to any client connected to any RmiConnector
345: * registered in the static list. The method is static because it is sending
346: * notifications to all rmi connectors.
347: *
348: * @param mbean the mbean that is generating the notification
349: * @param type the type as seen in <code>SequoiaNotificationList</code>
350: * @param priority notification level as seen in
351: * <code>SequoiaNotificationList</code>
352: * @param description a string description of the notification
353: * @param data a hashtable of data that can be used to give more information
354: * on the notification
355: */
356: public static void broadcastNotification(
357: AbstractStandardMBean mbean, String type, String priority,
358: String description, Hashtable data) {
359: sequence++;
360: logger.info("Sending notification:" + description
361: + "(Message No:" + sequence + ")");
362: Iterator iter = rmiConnectors.iterator();
363: RmiConnector rmi;
364: while (iter.hasNext()) {
365: rmi = ((RmiConnector) iter.next());
366: rmi.sendNotification(mbean, type, priority, description,
367: data);
368: }
369: }
370: }
|