1 7 8 package javax.management.remote.rmi; 9 10 import java.io.ByteArrayOutputStream ; 11 import java.io.IOException ; 12 import java.io.ObjectOutputStream ; 13 import java.net.MalformedURLException ; 14 import java.rmi.Remote ; 15 import java.rmi.server.RemoteObject ; 16 import java.rmi.server.RMIClientSocketFactory ; 17 import java.rmi.server.RMIServerSocketFactory ; 18 import java.util.Collections ; 19 import java.util.Hashtable ; 20 import java.util.Map ; 21 import java.util.HashMap ; 22 import java.util.Set ; 23 import java.util.HashSet ; 24 25 import javax.naming.InitialContext ; 26 import javax.naming.NamingException ; 27 28 import javax.management.MBeanRegistration ; 29 import javax.management.MBeanServer ; 30 import javax.management.ObjectName ; 31 import javax.management.InstanceNotFoundException ; 32 33 import javax.management.remote.JMXConnectionNotification ; 34 import javax.management.remote.JMXConnector ; 35 import javax.management.remote.JMXConnectorServer ; 36 import javax.management.remote.JMXServiceURL ; 37 import javax.management.remote.MBeanServerForwarder ; 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 54 public class RMIConnectorServer extends JMXConnectorServer { 55 63 public static final String JNDI_REBIND_ATTRIBUTE = 64 "jmx.remote.jndi.rebind"; 65 66 74 public static final String RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE = 75 "jmx.remote.rmi.client.socket.factory"; 76 77 85 public static final String RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE = 86 "jmx.remote.rmi.server.socket.factory"; 87 88 112 public RMIConnectorServer(JMXServiceURL url, Map <String ,?> environment) 113 throws IOException { 114 this(url, environment, (MBeanServer ) null); 115 } 116 117 146 public RMIConnectorServer(JMXServiceURL url, Map <String ,?> environment, 147 MBeanServer mbeanServer) 148 throws IOException { 149 this(url, environment, (RMIServerImpl ) null, mbeanServer); 150 } 151 152 186 public RMIConnectorServer(JMXServiceURL url, Map <String ,?> environment, 187 RMIServerImpl rmiServerImpl, 188 MBeanServer mbeanServer) 189 throws IOException { 190 super(mbeanServer); 191 192 if (url == null) throw new 193 IllegalArgumentException ("Null JMXServiceURL"); 194 if (rmiServerImpl == null) { 195 final String prt = url.getProtocol(); 196 if (prt == null || !(prt.equals("rmi") || prt.equals("iiop"))) { 197 final String msg = "Invalid protocol type: " + prt; 198 throw new MalformedURLException (msg); 199 } 200 final String urlPath = url.getURLPath(); 201 if (!urlPath.equals("") 202 && !urlPath.equals("/") 203 && !urlPath.startsWith("/jndi/")) { 204 final String msg = "URL path must be empty or start with " + 205 "/jndi/"; 206 throw new MalformedURLException (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 244 public JMXConnector toJMXConnector(Map <String ,?> env) throws IOException { 245 if (!isActive()) throw new 248 IllegalStateException ("Connector is not active"); 249 250 Map usemap = new 252 HashMap ((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 stub=(RMIServer )rmiServerImpl.toStub(); 263 264 return new RMIConnector (stub, usemap); 265 } 266 267 327 public synchronized void start() throws IOException { 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 ("The server has been stopped."); 336 } 337 338 MBeanServer mbs = getMBeanServer(); 339 if (mbs == null) 340 throw new IllegalStateException ("This connector server is not " + 341 "attached to an MBean server"); 342 343 if (attributes != null) { 347 String accessFile = 350 (String ) attributes.get("jmx.remote.x.access.file"); 351 if (accessFile != null) { 352 MBeanServerForwarder mbsf = null; 356 try { 357 mbsf = new MBeanServerFileAccessController(accessFile); 358 } catch (IOException e) { 359 throw (IllegalArgumentException ) 360 EnvHelp.initCause( 361 new IllegalArgumentException (e.getMessage()), e); 362 } 363 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 infc) { 374 IllegalArgumentException x = new 375 IllegalArgumentException ("ClassLoader not found: "+infc); 376 throw (IllegalArgumentException )EnvHelp.initCause(x,infc); 377 } 378 379 if (tracing) logger.trace("start", "setting RMIServer object"); 380 final RMIServerImpl 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 objref = objectToBind(rmiServer, attributes); 395 396 if (address != null && address.getURLPath().startsWith("/jndi/")) { 397 final String 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 rebindS = (String ) 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 (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 usemap = EnvHelp.mapToHashtable(attributes); 420 final boolean isIiop = isIiopURL(address, true); 421 if (isIiop) { 422 usemap.put(EnvHelp.DEFAULT_ORB, 424 RMIConnector.resolveOrb(attributes)); 425 } 426 427 bind(jndiUrl, usemap, objref, rebind); 428 boundJndiUrl = jndiUrl; 429 } catch (NamingException e) { 430 throw newIOException("Cannot bind to URL ["+jndiUrl+"]: " 432 + e, e); 433 } 434 } else { 435 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 e) { 443 try { 444 rmiServer.close(); 445 } catch (Exception x) { 446 } 448 if (e instanceof RuntimeException ) 449 throw (RuntimeException ) e; 450 else if (e instanceof IOException ) 451 throw (IOException ) 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 517 public void stop() throws IOException { 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 exception = null; 537 538 if (rmiServerImpl != null) { 540 try { 541 if (tracing) logger.trace("stop", "closing RMI server."); 542 rmiServerImpl.close(); 543 } catch (IOException 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 usemap = EnvHelp.mapToHashtable(attributes); 557 final boolean isIiop = isIiopURL(address, true); 558 if (isIiop) { 559 usemap.put(EnvHelp.DEFAULT_ORB, 561 RMIConnector.resolveOrb(attributes)); 562 } 563 InitialContext ctx = 564 new InitialContext (usemap); 565 ctx.unbind(boundJndiUrl); 566 ctx.close(); 567 } catch (NamingException e) { 568 if (tracing) logger.trace("stop", "failed to unbind RMI server: "+e); 569 if (logger.debugOn()) logger.debug("stop",e); 570 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 getAddress() { 586 if (!isActive()) 587 return null; 588 return address; 589 } 590 591 public Map <String ,?> getAttributes() { 592 Map map = EnvHelp.filterAttributes(attributes); 593 return Collections.unmodifiableMap(map); 594 } 595 596 599 600 protected void connectionOpened(String connectionId, String message, 601 Object userData) { 602 super.connectionOpened(connectionId, message, userData); 603 } 604 605 protected void connectionClosed(String connectionId, String message, 606 Object userData) { 607 super.connectionClosed(connectionId, message, userData); 608 } 609 610 protected void connectionFailed(String connectionId, String message, 611 Object userData) { 612 super.connectionFailed(connectionId, message, userData); 613 } 614 615 624 void bind(String jndiUrl, Hashtable attributes, 625 RMIServer rmiServer, boolean rebind) 626 throws NamingException , MalformedURLException { 627 InitialContext ctx = 630 new InitialContext (attributes); 631 632 if (rebind) 633 ctx.rebind(jndiUrl, rmiServer); 634 else 635 ctx.bind(jndiUrl, rmiServer); 636 ctx.close(); 637 } 638 639 642 RMIServerImpl newServer() throws IOException { 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 661 private void encodeStubInAddress(RMIServer rmiServer, Map attributes) 662 throws IOException { 663 664 final String protocol, host; 665 final int port; 666 667 if (address == null) { 668 if (rmiServer instanceof javax.rmi.CORBA.Stub ) 669 protocol = "iiop"; 670 else 671 protocol = "rmi"; 672 host = null; 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 urlPath = encodeStub(rmiServer, attributes); 681 682 address = new JMXServiceURL (protocol, host, port, urlPath); 683 } 684 685 static boolean isIiopURL(JMXServiceURL directoryURL, boolean strict) 686 throws MalformedURLException { 687 String 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 ("URL must have protocol " + 695 "\"rmi\" or \"iiop\": \"" + 696 protocol + "\""); 697 } 698 return false; 699 } 700 701 704 static String encodeStub(RMIServer rmiServer, Map env) throws IOException { 705 if (rmiServer instanceof javax.rmi.CORBA.Stub ) 706 return "/ior/" + encodeIIOPStub(rmiServer, env); 707 else 708 return "/stub/" + encodeJRMPStub(rmiServer, env); 709 } 710 711 static String encodeJRMPStub(RMIServer rmiServer, Map env) 712 throws IOException { 713 ByteArrayOutputStream bout = new ByteArrayOutputStream (); 714 ObjectOutputStream oout = new ObjectOutputStream (bout); 715 oout.writeObject(rmiServer); 716 oout.close(); 717 byte[] bytes = bout.toByteArray(); 718 return byteArrayToBase64(bytes); 719 } 720 721 static String encodeIIOPStub(RMIServer rmiServer, Map env) 722 throws IOException { 723 try { 724 javax.rmi.CORBA.Stub stub = 725 (javax.rmi.CORBA.Stub ) rmiServer; 726 return stub._orb().object_to_string(stub); 727 } catch (org.omg.CORBA.BAD_OPERATION x) { 728 throw newIOException(x.getMessage(), x); 729 } 730 } 731 732 736 private static RMIServer objectToBind(RMIServerImpl rmiServer, Map env) 737 throws IOException { 738 return RMIConnector. 739 connectStub((RMIServer )rmiServer.toStub(),env); 740 } 741 742 private static RMIServerImpl newJRMPServer(Map env, int port) 743 throws IOException { 744 RMIClientSocketFactory csf = (RMIClientSocketFactory ) 745 env.get(RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE); 746 RMIServerSocketFactory ssf = (RMIServerSocketFactory ) 747 env.get(RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE); 748 return new RMIJRMPServerImpl (port, csf, ssf, env); 749 } 750 751 private static RMIServerImpl newIIOPServer(Map env) 752 throws IOException { 753 return new RMIIIOPServerImpl (env); 754 } 755 756 private static String 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 result = new StringBuffer (resultLen); 762 763 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 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 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 return result.toString(); 793 } 794 795 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 812 private static IOException newIOException(String message, 813 Throwable cause) { 814 final IOException x = new IOException (message); 815 return (IOException )EnvHelp.initCause(x,cause); 816 } 817 818 819 822 private static ClassLogger logger = 823 new ClassLogger("javax.management.remote.rmi", "RMIConnectorServer"); 824 825 private JMXServiceURL address; 826 private RMIServerImpl rmiServerImpl; 827 private final Map attributes; 828 private ClassLoader defaultClassLoader = null; 829 830 private String boundJndiUrl; 831 832 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 openedServers = new HashSet (); 839 } 840 | Popular Tags |