KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > remote > rmi > RMIConnectorServer


1 /*
2  * @(#)RMIConnectorServer.java 1.61 04/06/21
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.management.remote.rmi;
9
10 import java.io.ByteArrayOutputStream JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.io.ObjectOutputStream JavaDoc;
13 import java.net.MalformedURLException JavaDoc;
14 import java.rmi.Remote JavaDoc;
15 import java.rmi.server.RemoteObject JavaDoc;
16 import java.rmi.server.RMIClientSocketFactory JavaDoc;
17 import java.rmi.server.RMIServerSocketFactory JavaDoc;
18 import java.util.Collections JavaDoc;
19 import java.util.Hashtable JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Set JavaDoc;
23 import java.util.HashSet JavaDoc;
24
25 import javax.naming.InitialContext JavaDoc;
26 import javax.naming.NamingException JavaDoc;
27
28 import javax.management.MBeanRegistration JavaDoc;
29 import javax.management.MBeanServer JavaDoc;
30 import javax.management.ObjectName JavaDoc;
31 import javax.management.InstanceNotFoundException JavaDoc;
32
33 import javax.management.remote.JMXConnectionNotification JavaDoc;
34 import javax.management.remote.JMXConnector JavaDoc;
35 import javax.management.remote.JMXConnectorServer JavaDoc;
36 import javax.management.remote.JMXServiceURL JavaDoc;
37 import javax.management.remote.MBeanServerForwarder JavaDoc;
38
39 import com.sun.jmx.remote.security.MBeanServerFileAccessController;
40 import com.sun.jmx.remote.util.ClassLogger;
41 import com.sun.jmx.remote.util.EnvHelp;
42
43 /**
44  * <p>A JMX API connector server that creates RMI-based connections
45  * from remote clients. Usually, such connector servers are made
46  * using {@link javax.management.remote.JMXConnectorServerFactory
47  * JMXConnectorServerFactory}. However, specialized applications can
48  * use this class directly, for example with an {@link RMIServerImpl}
49  * object.</p>
50  *
51  * @since 1.5
52  * @since.unbundled 1.0
53  */

54 public class RMIConnectorServer extends JMXConnectorServer JavaDoc {
55     /**
56      * <p>Name of the attribute that specifies whether the {@link
57      * RMIServer} stub that represents an RMI connector server should
58      * override an existing stub at the same address. The value
59      * associated with this attribute, if any, should be a string that
60      * is equal, ignoring case, to <code>"true"</code> or
61      * <code>"false"</code>. The default value is false.</p>
62      */

63     public static final String JavaDoc JNDI_REBIND_ATTRIBUTE =
64         "jmx.remote.jndi.rebind";
65
66     /**
67      * <p>Name of the attribute that specifies the {@link
68      * RMIClientSocketFactory} for the RMI objects created in
69      * conjunction with this connector. The value associated with this
70      * attribute must be of type <code>RMIClientSocketFactory</code> and can
71      * only be specified in the <code>Map</code> argument supplied when
72      * creating a connector server.</p>
73      */

74     public static final String JavaDoc RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE =
75         "jmx.remote.rmi.client.socket.factory";
76
77     /**
78      * <p>Name of the attribute that specifies the {@link
79      * RMIServerSocketFactory} for the RMI objects created in
80      * conjunction with this connector. The value associated with this
81      * attribute must be of type <code>RMIServerSocketFactory</code> and can
82      * only be specified in the <code>Map</code> argument supplied when
83      * creating a connector server.</p>
84      */

85     public static final String JavaDoc RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE =
86         "jmx.remote.rmi.server.socket.factory";
87
88     /**
89      * <p>Makes an <code>RMIConnectorServer</code>.
90      * This is equivalent to calling {@link #RMIConnectorServer(
91      * JMXServiceURL,Map,RMIServerImpl,MBeanServer)
92      * RMIConnectorServer(directoryURL,environment,null,null)}</p>
93      *
94      * @param url the URL defining how to create the connector server.
95      * Cannot be null.
96      *
97      * @param environment attributes governing the creation and
98      * storing of the RMI object. Can be null, which is equivalent to
99      * an empty Map.
100      *
101      * @exception IllegalArgumentException if <code>url</code> is null.
102      *
103      * @exception MalformedURLException if <code>url</code> does not
104      * conform to the syntax for an RMI connector, or if its protocol
105      * is not recognized by this implementation. Only "rmi" and "jrmp"
106      * are valid when this constructor is used.
107      *
108      * @exception IOException if the connector server cannot be created
109      * for some reason or if it is inevitable that its {@link #start()
110      * start} method will fail.
111      */

112     public RMIConnectorServer(JMXServiceURL JavaDoc url, Map JavaDoc<String JavaDoc,?> environment)
113             throws IOException JavaDoc {
114         this(url, environment, (MBeanServer JavaDoc) null);
115     }
116
117     /**
118      * <p>Makes an <code>RMIConnectorServer</code> for the given MBean
119      * server.
120      * This is equivalent to calling {@link #RMIConnectorServer(
121      * JMXServiceURL,Map,RMIServerImpl,MBeanServer)
122      * RMIConnectorServer(directoryURL,environment,null,mbeanServer)}</p>
123      *
124      * @param url the URL defining how to create the connector server.
125      * Cannot be null.
126      *
127      * @param environment attributes governing the creation and
128      * storing of the RMI object. Can be null, which is equivalent to
129      * an empty Map.
130      *
131      * @param mbeanServer the MBean server to which the new connector
132      * server is attached, or null if it will be attached by being
133      * registered as an MBean in the MBean server.
134      *
135      * @exception IllegalArgumentException if <code>url</code> is null.
136      *
137      * @exception MalformedURLException if <code>url</code> does not
138      * conform to the syntax for an RMI connector, or if its protocol
139      * is not recognized by this implementation. Only "rmi" and "jrmp"
140      * are valid when this constructor is used.
141      *
142      * @exception IOException if the connector server cannot be created
143      * for some reason or if it is inevitable that its {@link #start()
144      * start} method will fail.
145      */

146     public RMIConnectorServer(JMXServiceURL JavaDoc url, Map JavaDoc<String JavaDoc,?> environment,
147                               MBeanServer JavaDoc mbeanServer)
148             throws IOException JavaDoc {
149         this(url, environment, (RMIServerImpl JavaDoc) null, mbeanServer);
150     }
151
152     /**
153      * <p>Makes an <code>RMIConnectorServer</code> for the given MBean
154      * server.</p>
155      *
156      * @param url the URL defining how to create the connector server.
157      * Cannot be null.
158      *
159      * @param environment attributes governing the creation and
160      * storing of the RMI object. Can be null, which is equivalent to
161      * an empty Map.
162      *
163      * @param rmiServerImpl An implementation of the RMIServer interface,
164      * consistent with the protocol type specified in <var>url</var>.
165      * If this parameter is non null, the protocol type specified by
166      * <var>url</var> is not constrained, and is assumed to be valid.
167      * Otherwise, only "rmi" and "iiop" will be recognized.
168      *
169      * @param mbeanServer the MBean server to which the new connector
170      * server is attached, or null if it will be attached by being
171      * registered as an MBean in the MBean server.
172      *
173      * @exception IllegalArgumentException if <code>url</code> is null.
174      *
175      * @exception MalformedURLException if <code>url</code> does not
176      * conform to the syntax for an RMI connector, or if its protocol
177      * is not recognized by this implementation. Only "rmi" and "jrmp"
178      * are recognized when <var>rmiServerImpl</var> is null.
179      *
180      * @exception IOException if the connector server cannot be created
181      * for some reason or if it is inevitable that its {@link #start()
182      * start} method will fail.
183      *
184      * @see #start
185      */

186     public RMIConnectorServer(JMXServiceURL JavaDoc url, Map JavaDoc<String JavaDoc,?> environment,
187                               RMIServerImpl JavaDoc rmiServerImpl,
188                               MBeanServer JavaDoc mbeanServer)
189         throws IOException JavaDoc {
190     super(mbeanServer);
191
192     if (url == null) throw new
193         IllegalArgumentException JavaDoc("Null JMXServiceURL");
194     if (rmiServerImpl == null) {
195         final String JavaDoc prt = url.getProtocol();
196         if (prt == null || !(prt.equals("rmi") || prt.equals("iiop"))) {
197         final String JavaDoc msg = "Invalid protocol type: " + prt;
198         throw new MalformedURLException JavaDoc(msg);
199         }
200         final String JavaDoc urlPath = url.getURLPath();
201         if (!urlPath.equals("")
202         && !urlPath.equals("/")
203         && !urlPath.startsWith("/jndi/")) {
204         final String JavaDoc msg = "URL path must be empty or start with " +
205             "/jndi/";
206         throw new MalformedURLException JavaDoc(msg);
207         }
208     }
209
210         if (environment == null)
211             this.attributes = Collections.EMPTY_MAP;
212         else {
213         EnvHelp.checkAttributes(environment);
214             this.attributes = Collections.unmodifiableMap(environment);
215     }
216
217         this.address = url;
218         this.rmiServerImpl = rmiServerImpl;
219     }
220
221     /**
222      * <p>Returns a client stub for this connector server. A client
223      * stub is a serializable object whose {@link
224      * JMXConnector#connect(Map) connect} method can be used to make
225      * one new connection to this connector server.</p>
226      *
227      * @param env client connection parameters of the same sort that
228      * could be provided to {@link JMXConnector#connect(Map)
229      * JMXConnector.connect(Map)}. Can be null, which is equivalent
230      * to an empty map.
231      *
232      * @return a client stub that can be used to make a new connection
233      * to this connector server.
234      *
235      * @exception UnsupportedOperationException if this connector
236      * server does not support the generation of client stubs.
237      *
238      * @exception IllegalStateException if the JMXConnectorServer is
239      * not started (see {@link #isActive()}).
240      *
241      * @exception IOException if a communications problem means that a
242      * stub cannot be created.
243      **/

244     public JMXConnector JavaDoc toJMXConnector(Map JavaDoc<String JavaDoc,?> env) throws IOException JavaDoc {
245         // The serialized for of rmiServerImpl is automagically
246
// a RMI server stub.
247
if (!isActive()) throw new
248             IllegalStateException JavaDoc("Connector is not active");
249
250         // Merge maps
251
Map JavaDoc usemap = new
252         HashMap JavaDoc((this.attributes==null)?Collections.EMPTY_MAP:
253             this.attributes);
254
255         if (env != null) {
256         EnvHelp.checkAttributes(env);
257             usemap.putAll(env);
258         }
259
260     usemap = EnvHelp.filterAttributes(usemap);
261
262         final RMIServer JavaDoc stub=(RMIServer JavaDoc)rmiServerImpl.toStub();
263
264         return new RMIConnector JavaDoc(stub, usemap);
265     }
266
267     /**
268      * <p>Activates the connector server, that is starts listening for
269      * client connections. Calling this method when the connector
270      * server is already active has no effect. Calling this method
271      * when the connector server has been stopped will generate an
272      * <code>IOException</code>.</p>
273      *
274      * <p>The behaviour of this method when called for the first time
275      * depends on the parameters that were supplied at construction,
276      * as described below.</p>
277      *
278      * <p>First, an object of a subclass of {@link RMIServerImpl} is
279      * required, to export the connector server through RMI:</p>
280      *
281      * <ul>
282      *
283      * <li>If an <code>RMIServerImpl</code> was supplied to the
284      * constructor, it is used.
285      *
286      * <li>Otherwise, if the protocol part of the
287      * <code>JMXServiceURL</code> supplied to the constructor was
288      * <code>iiop</code>, an object of type {@link RMIIIOPServerImpl}
289      * is created.
290      *
291      * <li>Otherwise, if the <code>JMXServiceURL</code>
292      * was null, or its protocol part was <code>rmi</code>, an object
293      * of type {@link RMIJRMPServerImpl} is created.
294      *
295      * <li>Otherwise, the implementation can create an
296      * implementation-specific {@link RMIServerImpl} or it can throw
297      * {@link MalformedURLException}.
298      *
299      * </ul>
300      *
301      * <p>If the given address includes a JNDI directory URL as
302      * specified in the package documentation for {@link
303      * javax.management.remote.rmi}, then this
304      * <code>RMIConnectorServer</code> will bootstrap by binding the
305      * <code>RMIServerImpl</code> to the given address.</p>
306      *
307      * <p>If the URL path part of the <code>JMXServiceURL</code> was
308      * empty or a single slash (<code>/</code>), then the RMI object
309      * will not be bound to a directory. Instead, a reference to it
310      * will be encoded in the URL path of the RMIConnectorServer
311      * address (returned by {@link #getAddress()}). The encodings for
312      * <code>rmi</code> and <code>iiop</code> are described in the
313      * package documentation for {@link
314      * javax.management.remote.rmi}.</p>
315      *
316      * <p>The behavior when the URL path is neither empty nor a JNDI
317      * directory URL, or when the protocol is neither <code>rmi</code>
318      * nor <code>iiop</code>, is implementation defined, and may
319      * include throwing {@link MalformedURLException} when the
320      * connector server is created or when it is started.</p>
321      *
322      * @exception IllegalStateException if the connector server has
323      * not been attached to an MBean server.
324      * @exception IOException if the connector server cannot be
325      * started.
326      */

327     public synchronized void start() throws IOException JavaDoc {
328     final boolean tracing = logger.traceOn();
329
330     if (state == STARTED) {
331         if (tracing) logger.trace("start", "already started");
332         return;
333     } else if (state == STOPPED) {
334         if (tracing) logger.trace("start", "already stopped");
335         throw new IOException JavaDoc("The server has been stopped.");
336     }
337
338         MBeanServer JavaDoc mbs = getMBeanServer();
339         if (mbs == null)
340         throw new IllegalStateException JavaDoc("This connector server is not " +
341                         "attached to an MBean server");
342
343     // Check the internal access file property to see
344
// if an MBeanServerForwarder is to be provided
345
//
346
if (attributes != null) {
347         // Check if access file property is specified
348
//
349
String JavaDoc accessFile =
350         (String JavaDoc) attributes.get("jmx.remote.x.access.file");
351         if (accessFile != null) {
352         // Access file property specified, create an instance
353
// of the MBeanServerFileAccessController class
354
//
355
MBeanServerForwarder JavaDoc mbsf = null;
356         try {
357             mbsf = new MBeanServerFileAccessController(accessFile);
358         } catch (IOException JavaDoc e) {
359             throw (IllegalArgumentException JavaDoc)
360             EnvHelp.initCause(
361                new IllegalArgumentException JavaDoc(e.getMessage()), e);
362         }
363         // Set the MBeanServerForwarder
364
//
365
setMBeanServerForwarder(mbsf);
366         mbs = getMBeanServer();
367         }
368     }
369
370         try {
371         if (tracing) logger.trace("start", "setting default class loader");
372             defaultClassLoader = EnvHelp.resolveServerClassLoader(attributes, mbs);
373         } catch (InstanceNotFoundException JavaDoc infc) {
374             IllegalArgumentException JavaDoc x = new
375                 IllegalArgumentException JavaDoc("ClassLoader not found: "+infc);
376             throw (IllegalArgumentException JavaDoc)EnvHelp.initCause(x,infc);
377         }
378
379     if (tracing) logger.trace("start", "setting RMIServer object");
380         final RMIServerImpl JavaDoc rmiServer;
381
382     if (rmiServerImpl != null)
383         rmiServer = rmiServerImpl;
384     else
385             rmiServer = newServer();
386
387         rmiServer.setMBeanServer(mbs);
388         rmiServer.setDefaultClassLoader(defaultClassLoader);
389     rmiServer.setRMIConnectorServer(this);
390     rmiServer.export();
391         
392         try {
393             if (tracing) logger.trace("start", "getting RMIServer object to export");
394             final RMIServer JavaDoc objref = objectToBind(rmiServer, attributes);
395
396             if (address != null && address.getURLPath().startsWith("/jndi/")) {
397                 final String JavaDoc jndiUrl = address.getURLPath().substring(6);
398
399                 if (tracing)
400                     logger.trace("start", "Using external directory: " + jndiUrl);
401
402                 final boolean rebind;
403
404                 String JavaDoc rebindS = (String JavaDoc)
405                     attributes.get(JNDI_REBIND_ATTRIBUTE);
406                 if (rebindS == null) rebind = false;
407                 else if (rebindS.equalsIgnoreCase("true")) rebind = true;
408                 else if (rebindS.equalsIgnoreCase("false")) rebind = false;
409                 else throw new
410                     IllegalArgumentException JavaDoc(JNDI_REBIND_ATTRIBUTE + "must" +
411                                              " be \"true\" or \"false\"");
412
413                 if (tracing)
414                     logger.trace("start", JNDI_REBIND_ATTRIBUTE + "=" + rebind);
415
416                 try {
417                     if (tracing) logger.trace("start", "binding to " + jndiUrl);
418
419                     final Hashtable JavaDoc usemap = EnvHelp.mapToHashtable(attributes);
420                     final boolean isIiop = isIiopURL(address, true);
421                     if (isIiop) {
422                         // Make sure java.naming.corba.orb is in the Map.
423
usemap.put(EnvHelp.DEFAULT_ORB,
424                                    RMIConnector.resolveOrb(attributes));
425                     }
426
427                     bind(jndiUrl, usemap, objref, rebind);
428                     boundJndiUrl = jndiUrl;
429                 } catch (NamingException JavaDoc e) {
430                     // fit e in the nested exception if we are on 1.4
431
throw newIOException("Cannot bind to URL ["+jndiUrl+"]: "
432                                          + e, e);
433                 }
434             } else {
435                 // if jndiURL is null, we must encode the stub into the URL.
436
if (tracing) logger.trace("start", "Encoding URL");
437
438                 encodeStubInAddress(objref, attributes);
439
440                 if (tracing) logger.trace("start", "Encoded URL: " + this.address);
441             }
442         } catch (Exception JavaDoc e) {
443         try {
444         rmiServer.close();
445         } catch (Exception JavaDoc x) {
446         // OK: we are already throwing another exception
447
}
448         if (e instanceof RuntimeException JavaDoc)
449         throw (RuntimeException JavaDoc) e;
450         else if (e instanceof IOException JavaDoc)
451         throw (IOException JavaDoc) e;
452         else
453         throw newIOException("Got unexpected exception while " +
454                      "starting the connector server: "
455                      + e, e);
456         }
457
458         rmiServerImpl = rmiServer;
459
460     synchronized(openedServers) {
461         openedServers.add(this);
462     }
463
464         state = STARTED;
465
466         if (tracing) {
467             logger.trace("start", "Connector Server Address = " + address);
468             logger.trace("start", "started.");
469         }
470     }
471
472     /**
473      * <p>Deactivates the connector server, that is, stops listening for
474      * client connections. Calling this method will also close all
475      * client connections that were made by this server. After this
476      * method returns, whether normally or with an exception, the
477      * connector server will not create any new client
478      * connections.</p>
479      *
480      * <p>Once a connector server has been stopped, it cannot be started
481      * again.</p>
482      *
483      * <p>Calling this method when the connector server has already
484      * been stopped has no effect. Calling this method when the
485      * connector server has not yet been started will disable the
486      * connector server object permanently.</p>
487      *
488      * <p>If closing a client connection produces an exception, that
489      * exception is not thrown from this method. A {@link
490      * JMXConnectionNotification} is emitted from this MBean with the
491      * connection ID of the connection that could not be closed.</p>
492      *
493      * <p>Closing a connector server is a potentially slow operation.
494      * For example, if a client machine with an open connection has
495      * crashed, the close operation might have to wait for a network
496      * protocol timeout. Callers that do not want to block in a close
497      * operation should do it in a separate thread.</p>
498      *
499      * <p>This method calls the method {@link RMIServerImpl#close()
500      * close} on the connector server's <code>RMIServerImpl</code>
501      * object.</p>
502      *
503      * <p>If the <code>RMIServerImpl</code> was bound to a JNDI
504      * directory by the {@link #start() start} method, it is unbound
505      * from the directory by this method.</p>
506      *
507      * @exception IOException if the server cannot be closed cleanly,
508      * or if the <code>RMIServerImpl</code> cannot be unbound from the
509      * directory. When this exception is thrown, the server has
510      * already attempted to close all client connections, if
511      * appropriate; to call {@link RMIServerImpl#close()}; and to
512      * unbind the <code>RMIServerImpl</code> from its directory, if
513      * appropriate. All client connections are closed except possibly
514      * those that generated exceptions when the server attempted to
515      * close them.
516      */

517     public void stop() throws IOException JavaDoc {
518     final boolean tracing = logger.traceOn();
519
520     synchronized (this) {
521         if (state == STOPPED) {
522         if (tracing) logger.trace("stop","already stopped.");
523         return;
524         } else if (state == CREATED) {
525         if (tracing) logger.trace("stop","not started yet.");
526         }
527
528         if (tracing) logger.trace("stop", "stopping.");
529         state = STOPPED;
530     }
531
532     synchronized(openedServers) {
533         openedServers.remove(this);
534     }
535
536         IOException JavaDoc exception = null;
537
538     // rmiServerImpl can be null if stop() called without start()
539
if (rmiServerImpl != null) {
540         try {
541         if (tracing) logger.trace("stop", "closing RMI server.");
542         rmiServerImpl.close();
543         } catch (IOException JavaDoc e) {
544         if (tracing) logger.trace("stop", "failed to close RMI server: " + e);
545         if (logger.debugOn()) logger.debug("stop",e);
546         exception = e;
547         }
548     }
549
550         if (boundJndiUrl != null) {
551             try {
552         if (tracing)
553             logger.trace("stop",
554               "unbind from external directory: " + boundJndiUrl);
555         
556         final Hashtable JavaDoc usemap = EnvHelp.mapToHashtable(attributes);
557         final boolean isIiop = isIiopURL(address, true);
558         if (isIiop) {
559             // Make sure java.naming.corba.orb is in the Map.
560
usemap.put(EnvHelp.DEFAULT_ORB,
561                    RMIConnector.resolveOrb(attributes));
562         }
563                 InitialContext JavaDoc ctx =
564                     new InitialContext JavaDoc(usemap);
565                 ctx.unbind(boundJndiUrl);
566                 ctx.close();
567             } catch (NamingException JavaDoc e) {
568         if (tracing) logger.trace("stop", "failed to unbind RMI server: "+e);
569         if (logger.debugOn()) logger.debug("stop",e);
570                 // fit e in as the nested exception if we are on 1.4
571
if (exception == null)
572                     exception = newIOException("Cannot bind to URL: " + e, e);
573             }
574         }
575
576         if (exception != null) throw exception;
577
578     if (tracing) logger.trace("stop", "stopped");
579     }
580
581     public synchronized boolean isActive() {
582     return (state == STARTED);
583     }
584
585     public JMXServiceURL JavaDoc getAddress() {
586         if (!isActive())
587         return null;
588         return address;
589     }
590
591     public Map JavaDoc<String JavaDoc,?> getAttributes() {
592     Map JavaDoc map = EnvHelp.filterAttributes(attributes);
593         return Collections.unmodifiableMap(map);
594     }
595
596     /* We repeat the definitions of connection{Opened,Closed,Failed}
597        here so that they are accessible to other classes in this package
598        even though they have protected access. */

599
600     protected void connectionOpened(String JavaDoc connectionId, String JavaDoc message,
601                     Object JavaDoc userData) {
602     super.connectionOpened(connectionId, message, userData);
603     }
604
605     protected void connectionClosed(String JavaDoc connectionId, String JavaDoc message,
606                     Object JavaDoc userData) {
607     super.connectionClosed(connectionId, message, userData);
608     }
609
610     protected void connectionFailed(String JavaDoc connectionId, String JavaDoc message,
611                     Object JavaDoc userData) {
612     super.connectionFailed(connectionId, message, userData);
613     }
614
615     /**
616      * Bind a stub to a registry.
617      * @param jndiUrl URL of the stub in the registry, extracted
618      * from the <code>JMXServiceURL</code>.
619      * @param attributes A Hashtable containing environment parameters,
620      * built from the Map specified at this object creation.
621      * @param rmiServer The object to bind in the registry
622      * @param rebind true if the object must be rebound.
623      **/

624     void bind(String JavaDoc jndiUrl, Hashtable JavaDoc attributes,
625               RMIServer JavaDoc rmiServer, boolean rebind)
626         throws NamingException JavaDoc, MalformedURLException JavaDoc {
627         // if jndiURL is not null, we nust bind the stub to a
628
// directory.
629
InitialContext JavaDoc ctx =
630             new InitialContext JavaDoc(attributes);
631         
632         if (rebind)
633             ctx.rebind(jndiUrl, rmiServer);
634         else
635             ctx.bind(jndiUrl, rmiServer);
636         ctx.close();
637     }
638
639     /**
640      * Creates a new RMIServerImpl.
641      **/

642     RMIServerImpl JavaDoc newServer() throws IOException JavaDoc {
643         final boolean iiop = isIiopURL(address,true);
644     final int port;
645     if (address == null)
646         port = 0;
647     else
648         port = address.getPort();
649         if (iiop)
650             return newIIOPServer(attributes);
651         else
652             return newJRMPServer(attributes, port);
653     }
654     
655     /**
656      * Encode a stub into the JMXServiceURL.
657      * @param rmiServer The stub object to encode in the URL
658      * @param attributes A Map containing environment parameters,
659      * built from the Map specified at this object creation.
660      **/

661     private void encodeStubInAddress(RMIServer JavaDoc rmiServer, Map JavaDoc attributes)
662         throws IOException JavaDoc {
663
664     final String JavaDoc protocol, host;
665     final int port;
666
667     if (address == null) {
668         if (rmiServer instanceof javax.rmi.CORBA.Stub JavaDoc)
669         protocol = "iiop";
670         else
671         protocol = "rmi";
672         host = null; // will default to local host name
673
port = 0;
674     } else {
675         protocol = address.getProtocol();
676         host = (address.getHost().equals("")) ? null : address.getHost();
677         port = address.getPort();
678     }
679
680         final String JavaDoc urlPath = encodeStub(rmiServer, attributes);
681         
682         address = new JMXServiceURL JavaDoc(protocol, host, port, urlPath);
683     }
684
685     static boolean isIiopURL(JMXServiceURL JavaDoc directoryURL, boolean strict)
686     throws MalformedURLException JavaDoc {
687         String JavaDoc protocol = directoryURL.getProtocol();
688         if (protocol.equals("rmi"))
689             return false;
690         else if (protocol.equals("iiop"))
691             return true;
692         else if (strict) {
693         
694             throw new MalformedURLException JavaDoc("URL must have protocol " +
695                                             "\"rmi\" or \"iiop\": \"" +
696                         protocol + "\"");
697         }
698     return false;
699     }
700     
701     /**
702      * Returns the IOR of the given rmiServer.
703      **/

704     static String JavaDoc encodeStub(RMIServer JavaDoc rmiServer, Map JavaDoc env) throws IOException JavaDoc {
705         if (rmiServer instanceof javax.rmi.CORBA.Stub JavaDoc)
706         return "/ior/" + encodeIIOPStub(rmiServer, env);
707     else
708         return "/stub/" + encodeJRMPStub(rmiServer, env);
709     }
710
711     static String JavaDoc encodeJRMPStub(RMIServer JavaDoc rmiServer, Map JavaDoc env)
712         throws IOException JavaDoc {
713     ByteArrayOutputStream JavaDoc bout = new ByteArrayOutputStream JavaDoc();
714     ObjectOutputStream JavaDoc oout = new ObjectOutputStream JavaDoc(bout);
715     oout.writeObject(rmiServer);
716     oout.close();
717     byte[] bytes = bout.toByteArray();
718     return byteArrayToBase64(bytes);
719     }
720
721     static String JavaDoc encodeIIOPStub(RMIServer JavaDoc rmiServer, Map JavaDoc env)
722         throws IOException JavaDoc {
723     try {
724         javax.rmi.CORBA.Stub JavaDoc stub =
725         (javax.rmi.CORBA.Stub JavaDoc) rmiServer;
726         return stub._orb().object_to_string(stub);
727     } catch (org.omg.CORBA.BAD_OPERATION JavaDoc x) {
728         throw newIOException(x.getMessage(), x);
729     }
730     }
731
732     /**
733      * Object that we will bind to the registry.
734      * This object is a stub connected to our RMIServerImpl.
735      **/

736     private static RMIServer JavaDoc objectToBind(RMIServerImpl JavaDoc rmiServer, Map JavaDoc env)
737         throws IOException JavaDoc {
738         return RMIConnector.
739             connectStub((RMIServer JavaDoc)rmiServer.toStub(),env);
740     }
741
742     private static RMIServerImpl JavaDoc newJRMPServer(Map JavaDoc env, int port)
743         throws IOException JavaDoc {
744         RMIClientSocketFactory JavaDoc csf = (RMIClientSocketFactory JavaDoc)
745             env.get(RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE);
746         RMIServerSocketFactory JavaDoc ssf = (RMIServerSocketFactory JavaDoc)
747             env.get(RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE);
748         return new RMIJRMPServerImpl JavaDoc(port, csf, ssf, env);
749     }
750
751     private static RMIServerImpl JavaDoc newIIOPServer(Map JavaDoc env)
752         throws IOException JavaDoc {
753         return new RMIIIOPServerImpl JavaDoc(env);
754     }
755
756     private static String JavaDoc byteArrayToBase64(byte[] a) {
757         int aLen = a.length;
758         int numFullGroups = aLen/3;
759         int numBytesInPartialGroup = aLen - 3*numFullGroups;
760         int resultLen = 4*((aLen + 2)/3);
761         StringBuffer JavaDoc result = new StringBuffer JavaDoc(resultLen);
762
763         // Translate all full groups from byte array elements to Base64
764
int inCursor = 0;
765         for (int i=0; i<numFullGroups; i++) {
766             int byte0 = a[inCursor++] & 0xff;
767             int byte1 = a[inCursor++] & 0xff;
768             int byte2 = a[inCursor++] & 0xff;
769             result.append(intToAlpha[byte0 >> 2]);
770             result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
771             result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]);
772             result.append(intToAlpha[byte2 & 0x3f]);
773         }
774
775         // Translate partial group if present
776
if (numBytesInPartialGroup != 0) {
777             int byte0 = a[inCursor++] & 0xff;
778             result.append(intToAlpha[byte0 >> 2]);
779             if (numBytesInPartialGroup == 1) {
780                 result.append(intToAlpha[(byte0 << 4) & 0x3f]);
781                 result.append("==");
782             } else {
783                 // assert numBytesInPartialGroup == 2;
784
int byte1 = a[inCursor++] & 0xff;
785                 result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
786                 result.append(intToAlpha[(byte1 << 2)&0x3f]);
787                 result.append('=');
788             }
789         }
790         // assert inCursor == a.length;
791
// assert result.length() == resultLen;
792
return result.toString();
793     }
794  
795     /**
796      * This array is a lookup table that translates 6-bit positive integer
797      * index values into their "Base64 Alphabet" equivalents as specified
798      * in Table 1 of RFC 2045.
799      */

800     private static final char intToAlpha[] = {
801         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
802         'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
803         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
804         'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
805         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
806     };
807
808     /**
809      * Construct a new IOException with a nested exception.
810      * The nested exception is set only if JDK >= 1.4
811      */

812     private static IOException JavaDoc newIOException(String JavaDoc message,
813                                               Throwable JavaDoc cause) {
814         final IOException JavaDoc x = new IOException JavaDoc(message);
815         return (IOException JavaDoc)EnvHelp.initCause(x,cause);
816     }
817
818
819     // Private variables
820
// -----------------
821

822     private static ClassLogger logger =
823     new ClassLogger("javax.management.remote.rmi", "RMIConnectorServer");
824
825     private JMXServiceURL JavaDoc address;
826     private RMIServerImpl JavaDoc rmiServerImpl;
827     private final Map JavaDoc attributes;
828     private ClassLoader JavaDoc defaultClassLoader = null;
829
830     private String JavaDoc boundJndiUrl;
831
832     // state
833
private static final int CREATED = 0;
834     private static final int STARTED = 1;
835     private static final int STOPPED = 2;
836
837     private int state = CREATED;
838     private final static Set JavaDoc openedServers = new HashSet JavaDoc();
839 }
840
Popular Tags