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
26package javax.management.remote.rmi;
27
28import java.io.IOException;
29import java.rmi.MarshalledObject;
30import java.rmi.UnmarshalException;
31import java.rmi.server.Unreferenced;
32import java.security.AccessControlContext;
33import java.security.AccessController;
34import java.security.Permission;
35import java.security.Permissions;
36import java.security.PrivilegedAction;
37import java.security.PrivilegedActionException;
38import java.security.PrivilegedExceptionAction;
39import java.security.ProtectionDomain;
40import java.util.Arrays;
41import java.util.Collections;
42import java.util.Map;
43import java.util.Set;
44
45import javax.management.*;
46import javax.management.remote.JMXServerErrorException;
47import javax.management.remote.NotificationResult;
48import javax.security.auth.Subject;
49import sun.reflect.misc.ReflectUtil;
50
51import static javax.management.remote.rmi.RMIConnector.Util.cast;
52import com.sun.jmx.remote.internal.ServerCommunicatorAdmin;
53import com.sun.jmx.remote.internal.ServerNotifForwarder;
54import com.sun.jmx.remote.security.JMXSubjectDomainCombiner;
55import com.sun.jmx.remote.security.SubjectDelegator;
56import com.sun.jmx.remote.util.ClassLoaderWithRepository;
57import com.sun.jmx.remote.util.ClassLogger;
58import com.sun.jmx.remote.util.EnvHelp;
59import com.sun.jmx.remote.util.OrderClassLoaders;
60import 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 */
75public 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}
1835