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