1 /*
   2  * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.management.remote.rmi;
  27 
  28 import java.io.IOException;
  29 import java.rmi.MarshalledObject;
  30 import java.rmi.UnmarshalException;
  31 import java.rmi.server.Unreferenced;
  32 import java.security.AccessControlContext;
  33 import java.security.AccessController;
  34 import java.security.Permission;
  35 import java.security.Permissions;
  36 import java.security.PrivilegedAction;
  37 import java.security.PrivilegedActionException;
  38 import java.security.PrivilegedExceptionAction;
  39 import java.security.ProtectionDomain;
  40 import java.util.Arrays;
  41 import java.util.Collections;
  42 import java.util.Map;
  43 import java.util.Set;
  44 
  45 import javax.management.*;
  46 import javax.management.remote.JMXServerErrorException;
  47 import javax.management.remote.NotificationResult;
  48 import javax.security.auth.Subject;
  49 import sun.reflect.misc.ReflectUtil;
  50 
  51 import static com.sun.jmx.mbeanserver.Util.cast;
  52 import com.sun.jmx.remote.internal.ServerCommunicatorAdmin;
  53 import com.sun.jmx.remote.internal.ServerNotifForwarder;
  54 import com.sun.jmx.remote.security.JMXSubjectDomainCombiner;
  55 import com.sun.jmx.remote.security.SubjectDelegator;
  56 import com.sun.jmx.remote.util.ClassLoaderWithRepository;
  57 import com.sun.jmx.remote.util.ClassLogger;
  58 import com.sun.jmx.remote.util.EnvHelp;
  59 import com.sun.jmx.remote.util.OrderClassLoaders;
  60 import javax.management.loading.ClassLoaderRepository;
  61 
  62 /**
  63  * <p>Implementation of the {@link RMIConnection} interface.  User
  64  * code will not usually reference this class.</p>
  65  *
  66  * @since 1.5
  67  */
  68 /*
  69  * Notice that we omit the type parameter from MarshalledObject everywhere,
  70  * even though it would add useful information to the documentation.  The
  71  * reason is that it was only added in Mustang (Java SE 6), whereas versions
  72  * 1.4 and 2.0 of the JMX API must be implementable on Tiger per our
  73  * commitments for JSR 255.
  74  */
  75 public class RMIConnectionImpl implements RMIConnection, Unreferenced {
  76 
  77     /**
  78      * Constructs a new {@link RMIConnection}. This connection can be
  79      * used with the JRMP transport. This object does
  80      * not export itself: it is the responsibility of the caller to
  81      * export it appropriately (see {@link
  82      * RMIJRMPServerImpl#makeClient(String,Subject)}).
  83      *
  84      * @param rmiServer The RMIServerImpl object for which this
  85      * connection is created.  The behavior is unspecified if this
  86      * parameter is null.
  87      * @param connectionId The ID for this connection.  The behavior
  88      * is unspecified if this parameter is null.
  89      * @param defaultClassLoader The default ClassLoader to be used
  90      * when deserializing marshalled objects.  Can be null, to signify
  91      * the bootstrap class loader.
  92      * @param subject the authenticated subject to be used for
  93      * authorization.  Can be null, to signify that no subject has
  94      * been authenticated.
  95      * @param env the environment containing attributes for the new
  96      * <code>RMIServerImpl</code>.  Can be null, equivalent to an
  97      * empty map.
  98      */
  99     public RMIConnectionImpl(RMIServerImpl rmiServer,
 100                              String connectionId,
 101                              ClassLoader defaultClassLoader,
 102                              Subject subject,
 103                              Map<String,?> env) {
 104         if (rmiServer == null || connectionId == null)
 105             throw new NullPointerException("Illegal null argument");
 106         if (env == null)
 107             env = Collections.emptyMap();
 108         this.rmiServer = rmiServer;
 109         this.connectionId = connectionId;
 110         this.defaultClassLoader = defaultClassLoader;
 111 
 112         this.subjectDelegator = new SubjectDelegator();
 113         this.subject = subject;
 114         if (subject == null) {
 115             this.acc = null;
 116             this.removeCallerContext = false;
 117         } else {
 118             this.removeCallerContext =
 119                 SubjectDelegator.checkRemoveCallerContext(subject);
 120             if (this.removeCallerContext) {
 121                 this.acc =
 122                     JMXSubjectDomainCombiner.getDomainCombinerContext(subject);
 123             } else {
 124                 this.acc =
 125                     JMXSubjectDomainCombiner.getContext(subject);
 126             }
 127         }
 128         this.mbeanServer = rmiServer.getMBeanServer();
 129 
 130         final ClassLoader dcl = defaultClassLoader;
 131 
 132         ClassLoaderRepository repository = AccessController.doPrivileged(
 133             new PrivilegedAction<ClassLoaderRepository>() {
 134                 public ClassLoaderRepository run() {
 135                     return mbeanServer.getClassLoaderRepository();
 136                 }
 137             },
 138             withPermissions(new MBeanPermission("*", "getClassLoaderRepository"))
 139         );
 140         this.classLoaderWithRepository = AccessController.doPrivileged(
 141             new PrivilegedAction<ClassLoaderWithRepository>() {
 142                 public ClassLoaderWithRepository run() {
 143                     return new ClassLoaderWithRepository(
 144                         repository,
 145                         dcl);
 146                 }
 147             },
 148             withPermissions(new RuntimePermission("createClassLoader"))
 149         );
 150 
 151         this.defaultContextClassLoader =
 152             AccessController.doPrivileged(
 153                 new PrivilegedAction<ClassLoader>() {
 154             @Override
 155                     public ClassLoader run() {
 156                         return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(),
 157                                 dcl);
 158                     }
 159                 });
 160 
 161         serverCommunicatorAdmin = new
 162           RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env));
 163 
 164         this.env = env;
 165     }
 166 
 167     private static AccessControlContext withPermissions(Permission ... perms){
 168         Permissions col = new Permissions();
 169 
 170         for (Permission thePerm : perms ) {
 171             col.add(thePerm);
 172         }
 173 
 174         final ProtectionDomain pd = new ProtectionDomain(null, col);
 175         return new AccessControlContext( new ProtectionDomain[] { pd });
 176     }
 177 
 178     private synchronized ServerNotifForwarder getServerNotifFwd() {
 179         // Lazily created when first use. Mainly when
 180         // addNotificationListener is first called.
 181         if (serverNotifForwarder == null)
 182             serverNotifForwarder =
 183                 new ServerNotifForwarder(mbeanServer,
 184                                          env,
 185                                          rmiServer.getNotifBuffer(),
 186                                          connectionId);
 187         return serverNotifForwarder;
 188     }
 189 
 190     public String getConnectionId() throws IOException {
 191         // We should call reqIncomming() here... shouldn't we?
 192         return connectionId;
 193     }
 194 
 195     public void close() throws IOException {
 196         final boolean debug = logger.debugOn();
 197         final String  idstr = (debug?"["+this.toString()+"]":null);
 198 
 199         synchronized (this) {
 200             if (terminated) {
 201                 if (debug) logger.debug("close",idstr + " already terminated.");
 202                 return;
 203             }
 204 
 205             if (debug) logger.debug("close",idstr + " closing.");
 206 
 207             terminated = true;
 208 
 209             if (serverCommunicatorAdmin != null) {
 210                 serverCommunicatorAdmin.terminate();
 211             }
 212 
 213             if (serverNotifForwarder != null) {
 214                 serverNotifForwarder.terminate();
 215             }
 216         }
 217 
 218         rmiServer.clientClosed(this);
 219 
 220         if (debug) logger.debug("close",idstr + " closed.");
 221     }
 222 
 223     public void unreferenced() {
 224         logger.debug("unreferenced", "called");
 225         try {
 226             close();
 227             logger.debug("unreferenced", "done");
 228         } catch (IOException e) {
 229             logger.fine("unreferenced", e);
 230         }
 231     }
 232 
 233     //-------------------------------------------------------------------------
 234     // MBeanServerConnection Wrapper
 235     //-------------------------------------------------------------------------
 236 
 237     public ObjectInstance createMBean(String className,
 238                                       ObjectName name,
 239                                       Subject delegationSubject)
 240         throws
 241         ReflectionException,
 242         InstanceAlreadyExistsException,
 243         MBeanRegistrationException,
 244         MBeanException,
 245         NotCompliantMBeanException,
 246         IOException {
 247         try {
 248             final Object params[] =
 249                 new Object[] { className, name };
 250 
 251             if (logger.debugOn())
 252                 logger.debug("createMBean(String,ObjectName)",
 253                              "connectionId=" + connectionId +", className=" +
 254                              className+", name=" + name);
 255 
 256             return (ObjectInstance)
 257                 doPrivilegedOperation(
 258                   CREATE_MBEAN,
 259                   params,
 260                   delegationSubject);
 261         } catch (PrivilegedActionException pe) {
 262             Exception e = extractException(pe);
 263             if (e instanceof ReflectionException)
 264                 throw (ReflectionException) e;
 265             if (e instanceof InstanceAlreadyExistsException)
 266                 throw (InstanceAlreadyExistsException) e;
 267             if (e instanceof MBeanRegistrationException)
 268                 throw (MBeanRegistrationException) e;
 269             if (e instanceof MBeanException)
 270                 throw (MBeanException) e;
 271             if (e instanceof NotCompliantMBeanException)
 272                 throw (NotCompliantMBeanException) e;
 273             if (e instanceof IOException)
 274                 throw (IOException) e;
 275             throw newIOException("Got unexpected server exception: " + e, e);
 276         }
 277     }
 278 
 279     public ObjectInstance createMBean(String className,
 280                                       ObjectName name,
 281                                       ObjectName loaderName,
 282                                       Subject delegationSubject)
 283         throws
 284         ReflectionException,
 285         InstanceAlreadyExistsException,
 286         MBeanRegistrationException,
 287         MBeanException,
 288         NotCompliantMBeanException,
 289         InstanceNotFoundException,
 290         IOException {
 291         try {
 292             final Object params[] =
 293                 new Object[] { className, name, loaderName };
 294 
 295             if (logger.debugOn())
 296                 logger.debug("createMBean(String,ObjectName,ObjectName)",
 297                       "connectionId=" + connectionId
 298                       +", className=" + className
 299                       +", name=" + name
 300                       +", loaderName=" + loaderName);
 301 
 302             return (ObjectInstance)
 303                 doPrivilegedOperation(
 304                   CREATE_MBEAN_LOADER,
 305                   params,
 306                   delegationSubject);
 307         } catch (PrivilegedActionException pe) {
 308             Exception e = extractException(pe);
 309             if (e instanceof ReflectionException)
 310                 throw (ReflectionException) e;
 311             if (e instanceof InstanceAlreadyExistsException)
 312                 throw (InstanceAlreadyExistsException) e;
 313             if (e instanceof MBeanRegistrationException)
 314                 throw (MBeanRegistrationException) e;
 315             if (e instanceof MBeanException)
 316                 throw (MBeanException) e;
 317             if (e instanceof NotCompliantMBeanException)
 318                 throw (NotCompliantMBeanException) e;
 319             if (e instanceof InstanceNotFoundException)
 320                 throw (InstanceNotFoundException) e;
 321             if (e instanceof IOException)
 322                 throw (IOException) e;
 323             throw newIOException("Got unexpected server exception: " + e, e);
 324         }
 325     }
 326 
 327     @SuppressWarnings("rawtypes")  // MarshalledObject
 328     public ObjectInstance createMBean(String className,
 329                                       ObjectName name,
 330                                       MarshalledObject params,
 331                                       String signature[],
 332                                       Subject delegationSubject)
 333         throws
 334         ReflectionException,
 335         InstanceAlreadyExistsException,
 336         MBeanRegistrationException,
 337         MBeanException,
 338         NotCompliantMBeanException,
 339         IOException {
 340 
 341         final Object[] values;
 342         final boolean debug = logger.debugOn();
 343 
 344         if (debug) logger.debug(
 345                   "createMBean(String,ObjectName,Object[],String[])",
 346                   "connectionId=" + connectionId
 347                   +", unwrapping parameters using classLoaderWithRepository.");
 348 
 349         values =
 350             nullIsEmpty(unwrap(params, classLoaderWithRepository, Object[].class,delegationSubject));
 351 
 352         try {
 353             final Object params2[] =
 354                 new Object[] { className, name, values,
 355                                nullIsEmpty(signature) };
 356 
 357             if (debug)
 358                logger.debug("createMBean(String,ObjectName,Object[],String[])",
 359                              "connectionId=" + connectionId
 360                              +", className=" + className
 361                              +", name=" + name
 362                              +", signature=" + strings(signature));
 363 
 364             return (ObjectInstance)
 365                 doPrivilegedOperation(
 366                   CREATE_MBEAN_PARAMS,
 367                   params2,
 368                   delegationSubject);
 369         } catch (PrivilegedActionException pe) {
 370             Exception e = extractException(pe);
 371             if (e instanceof ReflectionException)
 372                 throw (ReflectionException) e;
 373             if (e instanceof InstanceAlreadyExistsException)
 374                 throw (InstanceAlreadyExistsException) e;
 375             if (e instanceof MBeanRegistrationException)
 376                 throw (MBeanRegistrationException) e;
 377             if (e instanceof MBeanException)
 378                 throw (MBeanException) e;
 379             if (e instanceof NotCompliantMBeanException)
 380                 throw (NotCompliantMBeanException) e;
 381             if (e instanceof IOException)
 382                 throw (IOException) e;
 383             throw newIOException("Got unexpected server exception: " + e, e);
 384         }
 385     }
 386 
 387     @SuppressWarnings("rawtypes")  // MarshalledObject
 388     public ObjectInstance createMBean(String className,
 389                                  ObjectName name,
 390                                  ObjectName loaderName,
 391                                  MarshalledObject params,
 392                                  String signature[],
 393                                  Subject delegationSubject)
 394         throws
 395         ReflectionException,
 396         InstanceAlreadyExistsException,
 397         MBeanRegistrationException,
 398         MBeanException,
 399         NotCompliantMBeanException,
 400         InstanceNotFoundException,
 401         IOException {
 402 
 403         final Object[] values;
 404         final boolean debug = logger.debugOn();
 405 
 406         if (debug) logger.debug(
 407                  "createMBean(String,ObjectName,ObjectName,Object[],String[])",
 408                  "connectionId=" + connectionId
 409                  +", unwrapping params with MBean extended ClassLoader.");
 410 
 411         values = nullIsEmpty(unwrap(params,
 412                                     getClassLoader(loaderName),
 413                                     defaultClassLoader,
 414                                     Object[].class,delegationSubject));
 415 
 416         try {
 417             final Object params2[] =
 418                new Object[] { className, name, loaderName, values,
 419                               nullIsEmpty(signature) };
 420 
 421            if (debug) logger.debug(
 422                  "createMBean(String,ObjectName,ObjectName,Object[],String[])",
 423                  "connectionId=" + connectionId
 424                  +", className=" + className
 425                  +", name=" + name
 426                  +", loaderName=" + loaderName
 427                  +", signature=" + strings(signature));
 428 
 429             return (ObjectInstance)
 430                 doPrivilegedOperation(
 431                   CREATE_MBEAN_LOADER_PARAMS,
 432                   params2,
 433                   delegationSubject);
 434         } catch (PrivilegedActionException pe) {
 435             Exception e = extractException(pe);
 436             if (e instanceof ReflectionException)
 437                 throw (ReflectionException) e;
 438             if (e instanceof InstanceAlreadyExistsException)
 439                 throw (InstanceAlreadyExistsException) e;
 440             if (e instanceof MBeanRegistrationException)
 441                 throw (MBeanRegistrationException) e;
 442             if (e instanceof MBeanException)
 443                 throw (MBeanException) e;
 444             if (e instanceof NotCompliantMBeanException)
 445                 throw (NotCompliantMBeanException) e;
 446             if (e instanceof InstanceNotFoundException)
 447                 throw (InstanceNotFoundException) e;
 448             if (e instanceof IOException)
 449                 throw (IOException) e;
 450             throw newIOException("Got unexpected server exception: " + e, e);
 451         }
 452     }
 453 
 454     public void unregisterMBean(ObjectName name, Subject delegationSubject)
 455         throws
 456         InstanceNotFoundException,
 457         MBeanRegistrationException,
 458         IOException {
 459         try {
 460             final Object params[] = new Object[] { name };
 461 
 462             if (logger.debugOn()) logger.debug("unregisterMBean",
 463                  "connectionId=" + connectionId
 464                  +", name="+name);
 465 
 466             doPrivilegedOperation(
 467               UNREGISTER_MBEAN,
 468               params,
 469               delegationSubject);
 470         } catch (PrivilegedActionException pe) {
 471             Exception e = extractException(pe);
 472             if (e instanceof InstanceNotFoundException)
 473                 throw (InstanceNotFoundException) e;
 474             if (e instanceof MBeanRegistrationException)
 475                 throw (MBeanRegistrationException) e;
 476             if (e instanceof IOException)
 477                 throw (IOException) e;
 478             throw newIOException("Got unexpected server exception: " + e, e);
 479         }
 480     }
 481 
 482     public ObjectInstance getObjectInstance(ObjectName name,
 483                                             Subject delegationSubject)
 484         throws
 485         InstanceNotFoundException,
 486         IOException {
 487 
 488         checkNonNull("ObjectName", name);
 489 
 490         try {
 491             final Object params[] = new Object[] { name };
 492 
 493             if (logger.debugOn()) logger.debug("getObjectInstance",
 494                  "connectionId=" + connectionId
 495                  +", name="+name);
 496 
 497             return (ObjectInstance)
 498                 doPrivilegedOperation(
 499                   GET_OBJECT_INSTANCE,
 500                   params,
 501                   delegationSubject);
 502         } catch (PrivilegedActionException pe) {
 503             Exception e = extractException(pe);
 504             if (e instanceof InstanceNotFoundException)
 505                 throw (InstanceNotFoundException) e;
 506             if (e instanceof IOException)
 507                 throw (IOException) e;
 508             throw newIOException("Got unexpected server exception: " + e, e);
 509         }
 510     }
 511 
 512     @SuppressWarnings("rawtypes")  // MarshalledObject
 513     public Set<ObjectInstance>
 514         queryMBeans(ObjectName name,
 515                     MarshalledObject query,
 516                     Subject delegationSubject)
 517         throws IOException {
 518         final QueryExp queryValue;
 519         final boolean debug=logger.debugOn();
 520 
 521         if (debug) logger.debug("queryMBeans",
 522                  "connectionId=" + connectionId
 523                  +" unwrapping query with defaultClassLoader.");
 524 
 525         queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject);
 526 
 527         try {
 528             final Object params[] = new Object[] { name, queryValue };
 529 
 530             if (debug) logger.debug("queryMBeans",
 531                  "connectionId=" + connectionId
 532                  +", name="+name +", query="+query);
 533 
 534             return cast(
 535                 doPrivilegedOperation(
 536                   QUERY_MBEANS,
 537                   params,
 538                   delegationSubject));
 539         } catch (PrivilegedActionException pe) {
 540             Exception e = extractException(pe);
 541             if (e instanceof IOException)
 542                 throw (IOException) e;
 543             throw newIOException("Got unexpected server exception: " + e, e);
 544         }
 545     }
 546 
 547     @SuppressWarnings("rawtypes")  // MarshalledObject
 548     public Set<ObjectName>
 549         queryNames(ObjectName name,
 550                    MarshalledObject query,
 551                    Subject delegationSubject)
 552         throws IOException {
 553         final QueryExp queryValue;
 554         final boolean debug=logger.debugOn();
 555 
 556         if (debug) logger.debug("queryNames",
 557                  "connectionId=" + connectionId
 558                  +" unwrapping query with defaultClassLoader.");
 559 
 560         queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject);
 561 
 562         try {
 563             final Object params[] = new Object[] { name, queryValue };
 564 
 565             if (debug) logger.debug("queryNames",
 566                  "connectionId=" + connectionId
 567                  +", name="+name +", query="+query);
 568 
 569             return cast(
 570                 doPrivilegedOperation(
 571                   QUERY_NAMES,
 572                   params,
 573                   delegationSubject));
 574         } catch (PrivilegedActionException pe) {
 575             Exception e = extractException(pe);
 576             if (e instanceof IOException)
 577                 throw (IOException) e;
 578             throw newIOException("Got unexpected server exception: " + e, e);
 579         }
 580     }
 581 
 582     public boolean isRegistered(ObjectName name,
 583                                 Subject delegationSubject) throws IOException {
 584         try {
 585             final Object params[] = new Object[] { name };
 586             return ((Boolean)
 587                 doPrivilegedOperation(
 588                   IS_REGISTERED,
 589                   params,
 590                   delegationSubject)).booleanValue();
 591         } catch (PrivilegedActionException pe) {
 592             Exception e = extractException(pe);
 593             if (e instanceof IOException)
 594                 throw (IOException) e;
 595             throw newIOException("Got unexpected server exception: " + e, e);
 596         }
 597     }
 598 
 599     public Integer getMBeanCount(Subject delegationSubject)
 600         throws IOException {
 601         try {
 602             final Object params[] = new Object[] { };
 603 
 604             if (logger.debugOn()) logger.debug("getMBeanCount",
 605                  "connectionId=" + connectionId);
 606 
 607             return (Integer)
 608                 doPrivilegedOperation(
 609                   GET_MBEAN_COUNT,
 610                   params,
 611                   delegationSubject);
 612         } catch (PrivilegedActionException pe) {
 613             Exception e = extractException(pe);
 614             if (e instanceof IOException)
 615                 throw (IOException) e;
 616             throw newIOException("Got unexpected server exception: " + e, e);
 617         }
 618     }
 619 
 620     public Object getAttribute(ObjectName name,
 621                                String attribute,
 622                                Subject delegationSubject)
 623         throws
 624         MBeanException,
 625         AttributeNotFoundException,
 626         InstanceNotFoundException,
 627         ReflectionException,
 628         IOException {
 629         try {
 630             final Object params[] = new Object[] { name, attribute };
 631             if (logger.debugOn()) logger.debug("getAttribute",
 632                                    "connectionId=" + connectionId
 633                                    +", name=" + name
 634                                    +", attribute="+ attribute);
 635 
 636             return
 637                 doPrivilegedOperation(
 638                   GET_ATTRIBUTE,
 639                   params,
 640                   delegationSubject);
 641         } catch (PrivilegedActionException pe) {
 642             Exception e = extractException(pe);
 643             if (e instanceof MBeanException)
 644                 throw (MBeanException) e;
 645             if (e instanceof AttributeNotFoundException)
 646                 throw (AttributeNotFoundException) e;
 647             if (e instanceof InstanceNotFoundException)
 648                 throw (InstanceNotFoundException) e;
 649             if (e instanceof ReflectionException)
 650                 throw (ReflectionException) e;
 651             if (e instanceof IOException)
 652                 throw (IOException) e;
 653             throw newIOException("Got unexpected server exception: " + e, e);
 654         }
 655     }
 656 
 657     public AttributeList getAttributes(ObjectName name,
 658                                        String[] attributes,
 659                                        Subject delegationSubject)
 660         throws
 661         InstanceNotFoundException,
 662         ReflectionException,
 663         IOException {
 664         try {
 665             final Object params[] = new Object[] { name, attributes };
 666 
 667             if (logger.debugOn()) logger.debug("getAttributes",
 668                                    "connectionId=" + connectionId
 669                                    +", name=" + name
 670                                    +", attributes="+ strings(attributes));
 671 
 672             return (AttributeList)
 673                 doPrivilegedOperation(
 674                   GET_ATTRIBUTES,
 675                   params,
 676                   delegationSubject);
 677         } catch (PrivilegedActionException pe) {
 678             Exception e = extractException(pe);
 679             if (e instanceof InstanceNotFoundException)
 680                 throw (InstanceNotFoundException) e;
 681             if (e instanceof ReflectionException)
 682                 throw (ReflectionException) e;
 683             if (e instanceof IOException)
 684                 throw (IOException) e;
 685             throw newIOException("Got unexpected server exception: " + e, e);
 686         }
 687     }
 688 
 689     @SuppressWarnings("rawtypes")  // MarshalledObject
 690     public void setAttribute(ObjectName name,
 691                              MarshalledObject attribute,
 692                              Subject delegationSubject)
 693         throws
 694         InstanceNotFoundException,
 695         AttributeNotFoundException,
 696         InvalidAttributeValueException,
 697         MBeanException,
 698         ReflectionException,
 699         IOException {
 700         final Attribute attr;
 701         final boolean debug=logger.debugOn();
 702 
 703         if (debug) logger.debug("setAttribute",
 704                  "connectionId=" + connectionId
 705                  +" unwrapping attribute with MBean extended ClassLoader.");
 706 
 707         attr = unwrap(attribute,
 708                       getClassLoaderFor(name),
 709                       defaultClassLoader,
 710                       Attribute.class, delegationSubject);
 711 
 712         try {
 713             final Object params[] = new Object[] { name, attr };
 714 
 715             if (debug) logger.debug("setAttribute",
 716                              "connectionId=" + connectionId
 717                              +", name="+name
 718                              +", attribute name="+attr.getName());
 719 
 720             doPrivilegedOperation(
 721               SET_ATTRIBUTE,
 722               params,
 723               delegationSubject);
 724         } catch (PrivilegedActionException pe) {
 725             Exception e = extractException(pe);
 726             if (e instanceof InstanceNotFoundException)
 727                 throw (InstanceNotFoundException) e;
 728             if (e instanceof AttributeNotFoundException)
 729                 throw (AttributeNotFoundException) e;
 730             if (e instanceof InvalidAttributeValueException)
 731                 throw (InvalidAttributeValueException) e;
 732             if (e instanceof MBeanException)
 733                 throw (MBeanException) e;
 734             if (e instanceof ReflectionException)
 735                 throw (ReflectionException) e;
 736             if (e instanceof IOException)
 737                 throw (IOException) e;
 738             throw newIOException("Got unexpected server exception: " + e, e);
 739         }
 740     }
 741 
 742     @SuppressWarnings("rawtypes")  // MarshalledObject
 743     public AttributeList setAttributes(ObjectName name,
 744                          MarshalledObject attributes,
 745                          Subject delegationSubject)
 746         throws
 747         InstanceNotFoundException,
 748         ReflectionException,
 749         IOException {
 750         final AttributeList attrlist;
 751         final boolean debug=logger.debugOn();
 752 
 753         if (debug) logger.debug("setAttributes",
 754                  "connectionId=" + connectionId
 755                  +" unwrapping attributes with MBean extended ClassLoader.");
 756 
 757         attrlist =
 758             unwrap(attributes,
 759                    getClassLoaderFor(name),
 760                    defaultClassLoader,
 761                    AttributeList.class, delegationSubject);
 762 
 763         try {
 764             final Object params[] = new Object[] { name, attrlist };
 765 
 766             if (debug) logger.debug("setAttributes",
 767                              "connectionId=" + connectionId
 768                              +", name="+name
 769                              +", attribute names="+RMIConnector.getAttributesNames(attrlist));
 770 
 771             return (AttributeList)
 772                 doPrivilegedOperation(
 773                   SET_ATTRIBUTES,
 774                   params,
 775                   delegationSubject);
 776         } catch (PrivilegedActionException pe) {
 777             Exception e = extractException(pe);
 778             if (e instanceof InstanceNotFoundException)
 779                 throw (InstanceNotFoundException) e;
 780             if (e instanceof ReflectionException)
 781                 throw (ReflectionException) e;
 782             if (e instanceof IOException)
 783                 throw (IOException) e;
 784             throw newIOException("Got unexpected server exception: " + e, e);
 785         }
 786     }
 787 
 788     @SuppressWarnings("rawtypes")  // MarshalledObject
 789     public Object invoke(ObjectName name,
 790                          String operationName,
 791                          MarshalledObject params,
 792                          String signature[],
 793                          Subject delegationSubject)
 794         throws
 795         InstanceNotFoundException,
 796         MBeanException,
 797         ReflectionException,
 798         IOException {
 799 
 800         checkNonNull("ObjectName", name);
 801         checkNonNull("Operation name", operationName);
 802 
 803         final Object[] values;
 804         final boolean debug=logger.debugOn();
 805 
 806         if (debug) logger.debug("invoke",
 807                  "connectionId=" + connectionId
 808                  +" unwrapping params with MBean extended ClassLoader.");
 809 
 810         values = nullIsEmpty(unwrap(params,
 811                                     getClassLoaderFor(name),
 812                                     defaultClassLoader,
 813                                     Object[].class, delegationSubject));
 814 
 815         try {
 816             final Object params2[] =
 817                 new Object[] { name, operationName, values,
 818                                nullIsEmpty(signature) };
 819 
 820             if (debug) logger.debug("invoke",
 821                              "connectionId=" + connectionId
 822                              +", name="+name
 823                              +", operationName="+operationName
 824                              +", signature="+strings(signature));
 825 
 826             return
 827                 doPrivilegedOperation(
 828                   INVOKE,
 829                   params2,
 830                   delegationSubject);
 831         } catch (PrivilegedActionException pe) {
 832             Exception e = extractException(pe);
 833             if (e instanceof InstanceNotFoundException)
 834                 throw (InstanceNotFoundException) e;
 835             if (e instanceof MBeanException)
 836                 throw (MBeanException) e;
 837             if (e instanceof ReflectionException)
 838                 throw (ReflectionException) e;
 839             if (e instanceof IOException)
 840                 throw (IOException) e;
 841             throw newIOException("Got unexpected server exception: " + e, e);
 842         }
 843     }
 844 
 845     public String getDefaultDomain(Subject delegationSubject)
 846         throws IOException {
 847         try {
 848             final Object params[] = new Object[] { };
 849 
 850             if (logger.debugOn())  logger.debug("getDefaultDomain",
 851                                     "connectionId=" + connectionId);
 852 
 853             return (String)
 854                 doPrivilegedOperation(
 855                   GET_DEFAULT_DOMAIN,
 856                   params,
 857                   delegationSubject);
 858         } catch (PrivilegedActionException pe) {
 859             Exception e = extractException(pe);
 860             if (e instanceof IOException)
 861                 throw (IOException) e;
 862             throw newIOException("Got unexpected server exception: " + e, e);
 863         }
 864     }
 865 
 866     public String[] getDomains(Subject delegationSubject) throws IOException {
 867         try {
 868             final Object params[] = new Object[] { };
 869 
 870             if (logger.debugOn())  logger.debug("getDomains",
 871                                     "connectionId=" + connectionId);
 872 
 873             return (String[])
 874                 doPrivilegedOperation(
 875                   GET_DOMAINS,
 876                   params,
 877                   delegationSubject);
 878         } catch (PrivilegedActionException pe) {
 879             Exception e = extractException(pe);
 880             if (e instanceof IOException)
 881                 throw (IOException) e;
 882             throw newIOException("Got unexpected server exception: " + e, e);
 883         }
 884     }
 885 
 886     public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject)
 887         throws
 888         InstanceNotFoundException,
 889         IntrospectionException,
 890         ReflectionException,
 891         IOException {
 892 
 893         checkNonNull("ObjectName", name);
 894 
 895         try {
 896             final Object params[] = new Object[] { name };
 897 
 898             if (logger.debugOn())  logger.debug("getMBeanInfo",
 899                                     "connectionId=" + connectionId
 900                                     +", name="+name);
 901 
 902             return (MBeanInfo)
 903                 doPrivilegedOperation(
 904                   GET_MBEAN_INFO,
 905                   params,
 906                   delegationSubject);
 907         } catch (PrivilegedActionException pe) {
 908             Exception e = extractException(pe);
 909             if (e instanceof InstanceNotFoundException)
 910                 throw (InstanceNotFoundException) e;
 911             if (e instanceof IntrospectionException)
 912                 throw (IntrospectionException) e;
 913             if (e instanceof ReflectionException)
 914                 throw (ReflectionException) e;
 915             if (e instanceof IOException)
 916                 throw (IOException) e;
 917             throw newIOException("Got unexpected server exception: " + e, e);
 918         }
 919     }
 920 
 921     public boolean isInstanceOf(ObjectName name,
 922                                 String className,
 923                                 Subject delegationSubject)
 924         throws InstanceNotFoundException, IOException {
 925 
 926         checkNonNull("ObjectName", name);
 927 
 928         try {
 929             final Object params[] = new Object[] { name, className };
 930 
 931             if (logger.debugOn())  logger.debug("isInstanceOf",
 932                                     "connectionId=" + connectionId
 933                                     +", name="+name
 934                                     +", className="+className);
 935 
 936             return ((Boolean)
 937                 doPrivilegedOperation(
 938                   IS_INSTANCE_OF,
 939                   params,
 940                   delegationSubject)).booleanValue();
 941         } catch (PrivilegedActionException pe) {
 942             Exception e = extractException(pe);
 943             if (e instanceof InstanceNotFoundException)
 944                 throw (InstanceNotFoundException) e;
 945             if (e instanceof IOException)
 946                 throw (IOException) e;
 947             throw newIOException("Got unexpected server exception: " + e, e);
 948         }
 949     }
 950 
 951     @SuppressWarnings("rawtypes")  // MarshalledObject
 952     public Integer[] addNotificationListeners(ObjectName[] names,
 953                       MarshalledObject[] filters,
 954                       Subject[] delegationSubjects)
 955             throws InstanceNotFoundException, IOException {
 956 
 957         if (names == null || filters == null) {
 958             throw new IllegalArgumentException("Got null arguments.");
 959         }
 960 
 961         Subject[] sbjs = (delegationSubjects != null) ? delegationSubjects :
 962         new Subject[names.length];
 963         if (names.length != filters.length || filters.length != sbjs.length) {
 964             final String msg =
 965                 "The value lengths of 3 parameters are not same.";
 966             throw new IllegalArgumentException(msg);
 967         }
 968 
 969         for (int i=0; i<names.length; i++) {
 970             if (names[i] == null) {
 971                 throw new IllegalArgumentException("Null Object name.");
 972             }
 973         }
 974 
 975         int i=0;
 976         ClassLoader targetCl;
 977         NotificationFilter[] filterValues =
 978             new NotificationFilter[names.length];
 979         Integer[] ids = new Integer[names.length];
 980         final boolean debug=logger.debugOn();
 981 
 982         try {
 983             for (; i<names.length; i++) {
 984                 targetCl = getClassLoaderFor(names[i]);
 985 
 986                 if (debug) logger.debug("addNotificationListener"+
 987                                         "(ObjectName,NotificationFilter)",
 988                                         "connectionId=" + connectionId +
 989                       " unwrapping filter with target extended ClassLoader.");
 990 
 991                 filterValues[i] =
 992                     unwrap(filters[i], targetCl, defaultClassLoader,
 993                            NotificationFilter.class, sbjs[i]);
 994 
 995                 if (debug) logger.debug("addNotificationListener"+
 996                                         "(ObjectName,NotificationFilter)",
 997                                         "connectionId=" + connectionId
 998                                         +", name=" + names[i]
 999                                         +", filter=" + filterValues[i]);
1000 
1001                 ids[i] = (Integer)
1002                     doPrivilegedOperation(ADD_NOTIFICATION_LISTENERS,
1003                                           new Object[] { names[i],
1004                                                          filterValues[i] },
1005                                           sbjs[i]);
1006             }
1007 
1008             return ids;
1009         } catch (Exception e) {
1010             // remove all registered listeners
1011             for (int j=0; j<i; j++) {
1012                 try {
1013                     getServerNotifFwd().removeNotificationListener(names[j],
1014                                                                    ids[j]);
1015                 } catch (Exception eee) {
1016                     // strange
1017                 }
1018             }
1019 
1020             if (e instanceof PrivilegedActionException) {
1021                 e = extractException(e);
1022             }
1023 
1024             if (e instanceof ClassCastException) {
1025                 throw (ClassCastException) e;
1026             } else if (e instanceof IOException) {
1027                 throw (IOException)e;
1028             } else if (e instanceof InstanceNotFoundException) {
1029                 throw (InstanceNotFoundException) e;
1030             } else if (e instanceof RuntimeException) {
1031                 throw (RuntimeException) e;
1032             } else {
1033                 throw newIOException("Got unexpected server exception: "+e,e);
1034             }
1035         }
1036     }
1037 
1038     @SuppressWarnings("rawtypes")  // MarshalledObject
1039     public void addNotificationListener(ObjectName name,
1040                        ObjectName listener,
1041                        MarshalledObject filter,
1042                        MarshalledObject handback,
1043                        Subject delegationSubject)
1044         throws InstanceNotFoundException, IOException {
1045 
1046         checkNonNull("Target MBean name", name);
1047         checkNonNull("Listener MBean name", listener);
1048 
1049         final NotificationFilter filterValue;
1050         final Object handbackValue;
1051         final boolean debug=logger.debugOn();
1052 
1053         final ClassLoader targetCl = getClassLoaderFor(name);
1054 
1055         if (debug) logger.debug("addNotificationListener"+
1056                  "(ObjectName,ObjectName,NotificationFilter,Object)",
1057                  "connectionId=" + connectionId
1058                  +" unwrapping filter with target extended ClassLoader.");
1059 
1060         filterValue =
1061             unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject);
1062 
1063         if (debug) logger.debug("addNotificationListener"+
1064                  "(ObjectName,ObjectName,NotificationFilter,Object)",
1065                  "connectionId=" + connectionId
1066                  +" unwrapping handback with target extended ClassLoader.");
1067 
1068         handbackValue =
1069             unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject);
1070 
1071         try {
1072             final Object params[] =
1073                 new Object[] { name, listener, filterValue, handbackValue };
1074 
1075             if (debug) logger.debug("addNotificationListener"+
1076                  "(ObjectName,ObjectName,NotificationFilter,Object)",
1077                              "connectionId=" + connectionId
1078                              +", name=" + name
1079                              +", listenerName=" + listener
1080                              +", filter=" + filterValue
1081                              +", handback=" + handbackValue);
1082 
1083             doPrivilegedOperation(
1084               ADD_NOTIFICATION_LISTENER_OBJECTNAME,
1085               params,
1086               delegationSubject);
1087         } catch (PrivilegedActionException pe) {
1088             Exception e = extractException(pe);
1089             if (e instanceof InstanceNotFoundException)
1090                 throw (InstanceNotFoundException) e;
1091             if (e instanceof IOException)
1092                 throw (IOException) e;
1093             throw newIOException("Got unexpected server exception: " + e, e);
1094         }
1095     }
1096 
1097     public void removeNotificationListeners(ObjectName name,
1098                                             Integer[] listenerIDs,
1099                                             Subject delegationSubject)
1100         throws
1101         InstanceNotFoundException,
1102         ListenerNotFoundException,
1103         IOException {
1104 
1105         if (name == null || listenerIDs == null)
1106             throw new IllegalArgumentException("Illegal null parameter");
1107 
1108         for (int i = 0; i < listenerIDs.length; i++) {
1109             if (listenerIDs[i] == null)
1110                 throw new IllegalArgumentException("Null listener ID");
1111         }
1112 
1113         try {
1114             final Object params[] = new Object[] { name, listenerIDs };
1115 
1116             if (logger.debugOn()) logger.debug("removeNotificationListener"+
1117                                    "(ObjectName,Integer[])",
1118                                    "connectionId=" + connectionId
1119                                    +", name=" + name
1120                                    +", listenerIDs=" + objects(listenerIDs));
1121 
1122             doPrivilegedOperation(
1123               REMOVE_NOTIFICATION_LISTENER,
1124               params,
1125               delegationSubject);
1126         } catch (PrivilegedActionException pe) {
1127             Exception e = extractException(pe);
1128             if (e instanceof InstanceNotFoundException)
1129                 throw (InstanceNotFoundException) e;
1130             if (e instanceof ListenerNotFoundException)
1131                 throw (ListenerNotFoundException) e;
1132             if (e instanceof IOException)
1133                 throw (IOException) e;
1134             throw newIOException("Got unexpected server exception: " + e, e);
1135         }
1136     }
1137 
1138     public void removeNotificationListener(ObjectName name,
1139                                            ObjectName listener,
1140                                            Subject delegationSubject)
1141         throws
1142         InstanceNotFoundException,
1143         ListenerNotFoundException,
1144         IOException {
1145 
1146         checkNonNull("Target MBean name", name);
1147         checkNonNull("Listener MBean name", listener);
1148 
1149         try {
1150             final Object params[] = new Object[] { name, listener };
1151 
1152             if (logger.debugOn()) logger.debug("removeNotificationListener"+
1153                                    "(ObjectName,ObjectName)",
1154                                    "connectionId=" + connectionId
1155                                    +", name=" + name
1156                                    +", listenerName=" + listener);
1157 
1158             doPrivilegedOperation(
1159               REMOVE_NOTIFICATION_LISTENER_OBJECTNAME,
1160               params,
1161               delegationSubject);
1162         } catch (PrivilegedActionException pe) {
1163             Exception e = extractException(pe);
1164             if (e instanceof InstanceNotFoundException)
1165                 throw (InstanceNotFoundException) e;
1166             if (e instanceof ListenerNotFoundException)
1167                 throw (ListenerNotFoundException) e;
1168             if (e instanceof IOException)
1169                 throw (IOException) e;
1170             throw newIOException("Got unexpected server exception: " + e, e);
1171         }
1172     }
1173 
1174     @SuppressWarnings("rawtypes")  // MarshalledObject
1175     public void removeNotificationListener(ObjectName name,
1176                         ObjectName listener,
1177                         MarshalledObject filter,
1178                         MarshalledObject handback,
1179                         Subject delegationSubject)
1180         throws
1181         InstanceNotFoundException,
1182         ListenerNotFoundException,
1183         IOException {
1184 
1185         checkNonNull("Target MBean name", name);
1186         checkNonNull("Listener MBean name", listener);
1187 
1188         final NotificationFilter filterValue;
1189         final Object handbackValue;
1190         final boolean debug=logger.debugOn();
1191 
1192         final ClassLoader targetCl = getClassLoaderFor(name);
1193 
1194         if (debug) logger.debug("removeNotificationListener"+
1195                  "(ObjectName,ObjectName,NotificationFilter,Object)",
1196                  "connectionId=" + connectionId
1197                  +" unwrapping filter with target extended ClassLoader.");
1198 
1199         filterValue =
1200             unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject);
1201 
1202         if (debug) logger.debug("removeNotificationListener"+
1203                  "(ObjectName,ObjectName,NotificationFilter,Object)",
1204                  "connectionId=" + connectionId
1205                  +" unwrapping handback with target extended ClassLoader.");
1206 
1207         handbackValue =
1208             unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject);
1209 
1210         try {
1211             final Object params[] =
1212                 new Object[] { name, listener, filterValue, handbackValue };
1213 
1214             if (debug) logger.debug("removeNotificationListener"+
1215                  "(ObjectName,ObjectName,NotificationFilter,Object)",
1216                              "connectionId=" + connectionId
1217                              +", name=" + name
1218                              +", listenerName=" + listener
1219                              +", filter=" + filterValue
1220                              +", handback=" + handbackValue);
1221 
1222             doPrivilegedOperation(
1223               REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK,
1224               params,
1225               delegationSubject);
1226         } catch (PrivilegedActionException pe) {
1227             Exception e = extractException(pe);
1228             if (e instanceof InstanceNotFoundException)
1229                 throw (InstanceNotFoundException) e;
1230             if (e instanceof ListenerNotFoundException)
1231                 throw (ListenerNotFoundException) e;
1232             if (e instanceof IOException)
1233                 throw (IOException) e;
1234             throw newIOException("Got unexpected server exception: " + e, e);
1235         }
1236     }
1237 
1238     public NotificationResult fetchNotifications(long clientSequenceNumber,
1239                                                  int maxNotifications,
1240                                                  long timeout)
1241         throws IOException {
1242 
1243         if (logger.debugOn()) logger.debug("fetchNotifications",
1244                                "connectionId=" + connectionId
1245                                +", timeout=" + timeout);
1246 
1247         if (maxNotifications < 0 || timeout < 0)
1248             throw new IllegalArgumentException("Illegal negative argument");
1249 
1250         final boolean serverTerminated =
1251             serverCommunicatorAdmin.reqIncoming();
1252         try {
1253             if (serverTerminated) {
1254                 // we must not call fetchNotifs() if the server is
1255                 // terminated (timeout elapsed).
1256                 // returns null to force the client to stop fetching
1257                 if (logger.debugOn()) logger.debug("fetchNotifications",
1258                                "The notification server has been closed, "
1259                                        + "returns null to force the client to stop fetching");
1260                 return null;
1261             }
1262             final long csn = clientSequenceNumber;
1263             final int mn = maxNotifications;
1264             final long t = timeout;
1265             PrivilegedAction<NotificationResult> action =
1266                 new PrivilegedAction<NotificationResult>() {
1267                     public NotificationResult run() {
1268                         return getServerNotifFwd().fetchNotifs(csn, t, mn);
1269                     }
1270             };
1271             if (acc == null)
1272                 return action.run();
1273             else
1274                 return AccessController.doPrivileged(action, acc);
1275         } finally {
1276             serverCommunicatorAdmin.rspOutgoing();
1277         }
1278     }
1279 
1280     /**
1281      * <p>Returns a string representation of this object.  In general,
1282      * the <code>toString</code> method returns a string that
1283      * "textually represents" this object. The result should be a
1284      * concise but informative representation that is easy for a
1285      * person to read.</p>
1286      *
1287      * @return a String representation of this object.
1288      **/
1289     @Override
1290     public String toString() {
1291         return super.toString() + ": connectionId=" + connectionId;
1292     }
1293 
1294     //------------------------------------------------------------------------
1295     // private classes
1296     //------------------------------------------------------------------------
1297 
1298     private class PrivilegedOperation
1299             implements PrivilegedExceptionAction<Object> {
1300 
1301         public PrivilegedOperation(int operation, Object[] params) {
1302             this.operation = operation;
1303             this.params = params;
1304         }
1305 
1306         public Object run() throws Exception {
1307             return doOperation(operation, params);
1308         }
1309 
1310         private int operation;
1311         private Object[] params;
1312     }
1313 
1314     //------------------------------------------------------------------------
1315     // private classes
1316     //------------------------------------------------------------------------
1317     private class RMIServerCommunicatorAdmin extends ServerCommunicatorAdmin {
1318         public RMIServerCommunicatorAdmin(long timeout) {
1319             super(timeout);
1320         }
1321 
1322         protected void doStop() {
1323             try {
1324                 close();
1325             } catch (IOException ie) {
1326                 logger.warning("RMIServerCommunicatorAdmin-doStop",
1327                                "Failed to close: " + ie);
1328                 logger.debug("RMIServerCommunicatorAdmin-doStop",ie);
1329             }
1330         }
1331 
1332     }
1333 
1334 
1335     //------------------------------------------------------------------------
1336     // private methods
1337     //------------------------------------------------------------------------
1338 
1339     private ClassLoader getClassLoader(final ObjectName name)
1340         throws InstanceNotFoundException {
1341         try {
1342             return
1343                 AccessController.doPrivileged(
1344                     new PrivilegedExceptionAction<ClassLoader>() {
1345                         public ClassLoader run() throws InstanceNotFoundException {
1346                             return mbeanServer.getClassLoader(name);
1347                         }
1348                     },
1349                     withPermissions(new MBeanPermission("*", "getClassLoader"))
1350             );
1351         } catch (PrivilegedActionException pe) {
1352             throw (InstanceNotFoundException) extractException(pe);
1353         }
1354     }
1355 
1356     private ClassLoader getClassLoaderFor(final ObjectName name)
1357         throws InstanceNotFoundException {
1358         try {
1359             return (ClassLoader)
1360                 AccessController.doPrivileged(
1361                     new PrivilegedExceptionAction<Object>() {
1362                         public Object run() throws InstanceNotFoundException {
1363                             return mbeanServer.getClassLoaderFor(name);
1364                         }
1365                     },
1366                     withPermissions(new MBeanPermission("*", "getClassLoaderFor"))
1367             );
1368         } catch (PrivilegedActionException pe) {
1369             throw (InstanceNotFoundException) extractException(pe);
1370         }
1371     }
1372 
1373     private Object doPrivilegedOperation(final int operation,
1374                                          final Object[] params,
1375                                          final Subject delegationSubject)
1376         throws PrivilegedActionException, IOException {
1377 
1378         serverCommunicatorAdmin.reqIncoming();
1379         try {
1380 
1381             final AccessControlContext reqACC;
1382             if (delegationSubject == null)
1383                 reqACC = acc;
1384             else {
1385                 if (subject == null) {
1386                     final String msg =
1387                         "Subject delegation cannot be enabled unless " +
1388                         "an authenticated subject is put in place";
1389                     throw new SecurityException(msg);
1390                 }
1391                 reqACC = subjectDelegator.delegatedContext(
1392                     acc, delegationSubject, removeCallerContext);
1393             }
1394 
1395             PrivilegedOperation op =
1396                 new PrivilegedOperation(operation, params);
1397             if (reqACC == null) {
1398                 try {
1399                     return op.run();
1400                 } catch (Exception e) {
1401                     if (e instanceof RuntimeException)
1402                         throw (RuntimeException) e;
1403                     throw new PrivilegedActionException(e);
1404                 }
1405             } else {
1406                 return AccessController.doPrivileged(op, reqACC);
1407             }
1408         } catch (Error e) {
1409             throw new JMXServerErrorException(e.toString(),e);
1410         } finally {
1411             serverCommunicatorAdmin.rspOutgoing();
1412         }
1413     }
1414 
1415     private Object doOperation(int operation, Object[] params)
1416         throws Exception {
1417 
1418         switch (operation) {
1419 
1420         case CREATE_MBEAN:
1421             return mbeanServer.createMBean((String)params[0],
1422                                            (ObjectName)params[1]);
1423 
1424         case CREATE_MBEAN_LOADER:
1425             return mbeanServer.createMBean((String)params[0],
1426                                            (ObjectName)params[1],
1427                                            (ObjectName)params[2]);
1428 
1429         case CREATE_MBEAN_PARAMS:
1430             return mbeanServer.createMBean((String)params[0],
1431                                            (ObjectName)params[1],
1432                                            (Object[])params[2],
1433                                            (String[])params[3]);
1434 
1435         case CREATE_MBEAN_LOADER_PARAMS:
1436             return mbeanServer.createMBean((String)params[0],
1437                                            (ObjectName)params[1],
1438                                            (ObjectName)params[2],
1439                                            (Object[])params[3],
1440                                            (String[])params[4]);
1441 
1442         case GET_ATTRIBUTE:
1443             return mbeanServer.getAttribute((ObjectName)params[0],
1444                                             (String)params[1]);
1445 
1446         case GET_ATTRIBUTES:
1447             return mbeanServer.getAttributes((ObjectName)params[0],
1448                                              (String[])params[1]);
1449 
1450         case GET_DEFAULT_DOMAIN:
1451             return mbeanServer.getDefaultDomain();
1452 
1453         case GET_DOMAINS:
1454             return mbeanServer.getDomains();
1455 
1456         case GET_MBEAN_COUNT:
1457             return mbeanServer.getMBeanCount();
1458 
1459         case GET_MBEAN_INFO:
1460             return mbeanServer.getMBeanInfo((ObjectName)params[0]);
1461 
1462         case GET_OBJECT_INSTANCE:
1463             return mbeanServer.getObjectInstance((ObjectName)params[0]);
1464 
1465         case INVOKE:
1466             return mbeanServer.invoke((ObjectName)params[0],
1467                                       (String)params[1],
1468                                       (Object[])params[2],
1469                                       (String[])params[3]);
1470 
1471         case IS_INSTANCE_OF:
1472             return mbeanServer.isInstanceOf((ObjectName)params[0],
1473                                             (String)params[1])
1474                 ? Boolean.TRUE : Boolean.FALSE;
1475 
1476         case IS_REGISTERED:
1477             return mbeanServer.isRegistered((ObjectName)params[0])
1478                 ? Boolean.TRUE : Boolean.FALSE;
1479 
1480         case QUERY_MBEANS:
1481             return mbeanServer.queryMBeans((ObjectName)params[0],
1482                                            (QueryExp)params[1]);
1483 
1484         case QUERY_NAMES:
1485             return mbeanServer.queryNames((ObjectName)params[0],
1486                                           (QueryExp)params[1]);
1487 
1488         case SET_ATTRIBUTE:
1489             mbeanServer.setAttribute((ObjectName)params[0],
1490                                      (Attribute)params[1]);
1491             return null;
1492 
1493         case SET_ATTRIBUTES:
1494             return mbeanServer.setAttributes((ObjectName)params[0],
1495                                              (AttributeList)params[1]);
1496 
1497         case UNREGISTER_MBEAN:
1498             mbeanServer.unregisterMBean((ObjectName)params[0]);
1499             return null;
1500 
1501         case ADD_NOTIFICATION_LISTENERS:
1502             return getServerNotifFwd().addNotificationListener(
1503                                                 (ObjectName)params[0],
1504                                                 (NotificationFilter)params[1]);
1505 
1506         case ADD_NOTIFICATION_LISTENER_OBJECTNAME:
1507             mbeanServer.addNotificationListener((ObjectName)params[0],
1508                                                 (ObjectName)params[1],
1509                                                 (NotificationFilter)params[2],
1510                                                 params[3]);
1511             return null;
1512 
1513         case REMOVE_NOTIFICATION_LISTENER:
1514             getServerNotifFwd().removeNotificationListener(
1515                                                    (ObjectName)params[0],
1516                                                    (Integer[])params[1]);
1517             return null;
1518 
1519         case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME:
1520             mbeanServer.removeNotificationListener((ObjectName)params[0],
1521                                                    (ObjectName)params[1]);
1522             return null;
1523 
1524         case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK:
1525             mbeanServer.removeNotificationListener(
1526                                           (ObjectName)params[0],
1527                                           (ObjectName)params[1],
1528                                           (NotificationFilter)params[2],
1529                                           params[3]);
1530             return null;
1531 
1532         default:
1533             throw new IllegalArgumentException("Invalid operation");
1534         }
1535     }
1536 
1537     private static class SetCcl implements PrivilegedExceptionAction<ClassLoader> {
1538         private final ClassLoader classLoader;
1539 
1540         SetCcl(ClassLoader classLoader) {
1541             this.classLoader = classLoader;
1542         }
1543 
1544         public ClassLoader run() {
1545             Thread currentThread = Thread.currentThread();
1546             ClassLoader old = currentThread.getContextClassLoader();
1547             currentThread.setContextClassLoader(classLoader);
1548             return old;
1549         }
1550     }
1551 
1552     private <T> T unwrap(final MarshalledObject<?> mo,
1553                                 final ClassLoader cl,
1554                                 final Class<T> wrappedClass,
1555                                 Subject delegationSubject)
1556             throws IOException {
1557         if (mo == null) {
1558             return null;
1559         }
1560         try {
1561             final ClassLoader old = AccessController.doPrivileged(new SetCcl(cl));
1562             try{
1563                 final AccessControlContext reqACC;
1564                 if (delegationSubject == null)
1565                     reqACC = acc;
1566                 else {
1567                     if (subject == null) {
1568                         final String msg =
1569                             "Subject delegation cannot be enabled unless " +
1570                             "an authenticated subject is put in place";
1571                         throw new SecurityException(msg);
1572                     }
1573                     reqACC = subjectDelegator.delegatedContext(
1574                         acc, delegationSubject, removeCallerContext);
1575                 }
1576                 if(reqACC != null){
1577                     return AccessController.doPrivileged(
1578                             (PrivilegedExceptionAction<T>) () ->
1579                                     wrappedClass.cast(mo.get()), reqACC);
1580                 }else{
1581                     return wrappedClass.cast(mo.get());
1582                 }
1583             }finally{
1584                 AccessController.doPrivileged(new SetCcl(old));
1585             }
1586         } catch (PrivilegedActionException pe) {
1587             Exception e = extractException(pe);
1588             if (e instanceof IOException) {
1589                 throw (IOException) e;
1590             }
1591             if (e instanceof ClassNotFoundException) {
1592                 throw new UnmarshalException(e.toString(), e);
1593             }
1594             logger.warning("unwrap", "Failed to unmarshall object: " + e);
1595             logger.debug("unwrap", e);
1596         }catch (ClassNotFoundException ex) {
1597             logger.warning("unwrap", "Failed to unmarshall object: " + ex);
1598             logger.debug("unwrap", ex);
1599             throw new UnmarshalException(ex.toString(), ex);
1600         }
1601         return null;
1602     }
1603 
1604     private <T> T unwrap(final MarshalledObject<?> mo,
1605                                 final ClassLoader cl1,
1606                                 final ClassLoader cl2,
1607                                 final Class<T> wrappedClass,
1608                                 Subject delegationSubject)
1609         throws IOException {
1610         if (mo == null) {
1611             return null;
1612         }
1613         try {
1614             ClassLoader orderCL = AccessController.doPrivileged(
1615                 new PrivilegedExceptionAction<ClassLoader>() {
1616                     public ClassLoader run() throws Exception {
1617                         return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(),
1618                                 new OrderClassLoaders(cl1, cl2));
1619                     }
1620                 }
1621             );
1622             return unwrap(mo, orderCL, wrappedClass,delegationSubject);
1623         } catch (PrivilegedActionException pe) {
1624             Exception e = extractException(pe);
1625             if (e instanceof IOException) {
1626                 throw (IOException) e;
1627             }
1628             if (e instanceof ClassNotFoundException) {
1629                 throw new UnmarshalException(e.toString(), e);
1630             }
1631             logger.warning("unwrap", "Failed to unmarshall object: " + e);
1632             logger.debug("unwrap", e);
1633         }
1634         return null;
1635     }
1636 
1637     /**
1638      * Construct a new IOException with a nested exception.
1639      * The nested exception is set only if JDK {@literal >= 1.4}
1640      */
1641     private static IOException newIOException(String message,
1642                                               Throwable cause) {
1643         final IOException x = new IOException(message);
1644         return EnvHelp.initCause(x,cause);
1645     }
1646 
1647     /**
1648      * Iterate until we extract the real exception
1649      * from a stack of PrivilegedActionExceptions.
1650      */
1651     private static Exception extractException(Exception e) {
1652         while (e instanceof PrivilegedActionException) {
1653             e = ((PrivilegedActionException)e).getException();
1654         }
1655         return e;
1656     }
1657 
1658     private static final Object[] NO_OBJECTS = new Object[0];
1659     private static final String[] NO_STRINGS = new String[0];
1660 
1661     /*
1662      * The JMX spec doesn't explicitly say that a null Object[] or
1663      * String[] in e.g. MBeanServer.invoke is equivalent to an empty
1664      * array, but the RI behaves that way.  In the interests of
1665      * maximal interoperability, we make it so even when we're
1666      * connected to some other JMX implementation that might not do
1667      * that.  This should be clarified in the next version of JMX.
1668      */
1669     private static Object[] nullIsEmpty(Object[] array) {
1670         return (array == null) ? NO_OBJECTS : array;
1671     }
1672 
1673     private static String[] nullIsEmpty(String[] array) {
1674         return (array == null) ? NO_STRINGS : array;
1675     }
1676 
1677     /*
1678      * Similarly, the JMX spec says for some but not all methods in
1679      * MBeanServer that take an ObjectName target, that if it's null
1680      * you get this exception.  We specify it for all of them, and
1681      * make it so for the ones where it's not specified in JMX even if
1682      * the JMX implementation doesn't do so.
1683      */
1684     private static void checkNonNull(String what, Object x) {
1685         if (x == null) {
1686             RuntimeException wrapped =
1687                 new IllegalArgumentException(what + " must not be null");
1688             throw new RuntimeOperationsException(wrapped);
1689         }
1690     }
1691 
1692     //------------------------------------------------------------------------
1693     // private variables
1694     //------------------------------------------------------------------------
1695 
1696     private final Subject subject;
1697 
1698     private final SubjectDelegator subjectDelegator;
1699 
1700     private final boolean removeCallerContext;
1701 
1702     private final AccessControlContext acc;
1703 
1704     private final RMIServerImpl rmiServer;
1705 
1706     private final MBeanServer mbeanServer;
1707 
1708     private final ClassLoader defaultClassLoader;
1709 
1710     private final ClassLoader defaultContextClassLoader;
1711 
1712     private final ClassLoaderWithRepository classLoaderWithRepository;
1713 
1714     private boolean terminated = false;
1715 
1716     private final String connectionId;
1717 
1718     private final ServerCommunicatorAdmin serverCommunicatorAdmin;
1719 
1720     // Method IDs for doOperation
1721     //---------------------------
1722 
1723     private final static int
1724         ADD_NOTIFICATION_LISTENERS                              = 1;
1725     private final static int
1726         ADD_NOTIFICATION_LISTENER_OBJECTNAME                    = 2;
1727     private final static int
1728         CREATE_MBEAN                                            = 3;
1729     private final static int
1730         CREATE_MBEAN_PARAMS                                     = 4;
1731     private final static int
1732         CREATE_MBEAN_LOADER                                     = 5;
1733     private final static int
1734         CREATE_MBEAN_LOADER_PARAMS                              = 6;
1735     private final static int
1736         GET_ATTRIBUTE                                           = 7;
1737     private final static int
1738         GET_ATTRIBUTES                                          = 8;
1739     private final static int
1740         GET_DEFAULT_DOMAIN                                      = 9;
1741     private final static int
1742         GET_DOMAINS                                             = 10;
1743     private final static int
1744         GET_MBEAN_COUNT                                         = 11;
1745     private final static int
1746         GET_MBEAN_INFO                                          = 12;
1747     private final static int
1748         GET_OBJECT_INSTANCE                                     = 13;
1749     private final static int
1750         INVOKE                                                  = 14;
1751     private final static int
1752         IS_INSTANCE_OF                                          = 15;
1753     private final static int
1754         IS_REGISTERED                                           = 16;
1755     private final static int
1756         QUERY_MBEANS                                            = 17;
1757     private final static int
1758         QUERY_NAMES                                             = 18;
1759     private final static int
1760         REMOVE_NOTIFICATION_LISTENER                            = 19;
1761     private final static int
1762         REMOVE_NOTIFICATION_LISTENER_OBJECTNAME                 = 20;
1763     private final static int
1764         REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 21;
1765     private final static int
1766         SET_ATTRIBUTE                                           = 22;
1767     private final static int
1768         SET_ATTRIBUTES                                          = 23;
1769     private final static int
1770         UNREGISTER_MBEAN                                        = 24;
1771 
1772     // SERVER NOTIFICATION
1773     //--------------------
1774 
1775     private ServerNotifForwarder serverNotifForwarder;
1776     private Map<String, ?> env;
1777 
1778     // TRACES & DEBUG
1779     //---------------
1780 
1781     private static String objects(final Object[] objs) {
1782         if (objs == null)
1783             return "null";
1784         else
1785             return Arrays.asList(objs).toString();
1786     }
1787 
1788     private static String strings(final String[] strs) {
1789         return objects(strs);
1790     }
1791 
1792     private static final ClassLogger logger =
1793         new ClassLogger("javax.management.remote.rmi", "RMIConnectionImpl");
1794 
1795     private static final class CombinedClassLoader extends ClassLoader {
1796 
1797         private final static class ClassLoaderWrapper extends ClassLoader {
1798             ClassLoaderWrapper(ClassLoader cl) {
1799                 super(cl);
1800             }
1801 
1802             @Override
1803             protected Class<?> loadClass(String name, boolean resolve)
1804                     throws ClassNotFoundException {
1805                 return super.loadClass(name, resolve);
1806             }
1807         };
1808 
1809         final ClassLoaderWrapper defaultCL;
1810 
1811         private CombinedClassLoader(ClassLoader parent, ClassLoader defaultCL) {
1812             super(parent);
1813             this.defaultCL = new ClassLoaderWrapper(defaultCL);
1814         }
1815 
1816         @Override
1817         protected Class<?> loadClass(String name, boolean resolve)
1818         throws ClassNotFoundException {
1819             ReflectUtil.checkPackageAccess(name);
1820             try {
1821                 super.loadClass(name, resolve);
1822             } catch(Exception e) {
1823                 for(Throwable t = e; t != null; t = t.getCause()) {
1824                     if(t instanceof SecurityException) {
1825                         throw t==e?(SecurityException)t:new SecurityException(t.getMessage(), e);
1826                     }
1827                 }
1828             }
1829             final Class<?> cl = defaultCL.loadClass(name, resolve);
1830             return cl;
1831         }
1832 
1833     }
1834 }