jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java
changeset 43662 6b16a26de895
parent 43661 c3f1a529d829
parent 43593 06bce0388880
child 43663 4416065868c1
equal deleted inserted replaced
43661:c3f1a529d829 43662:6b16a26de895
     1 /*
       
     2  * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package javax.management.remote.rmi;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.rmi.NoSuchObjectException;
       
    30 import java.rmi.Remote;
       
    31 import java.rmi.RemoteException;
       
    32 import java.rmi.server.RMIClientSocketFactory;
       
    33 import java.rmi.server.RMIServerSocketFactory;
       
    34 import java.rmi.server.UnicastRemoteObject;
       
    35 import java.rmi.server.RemoteObject;
       
    36 import java.util.Map;
       
    37 import java.util.Collections;
       
    38 import javax.security.auth.Subject;
       
    39 
       
    40 import com.sun.jmx.remote.internal.RMIExporter;
       
    41 import com.sun.jmx.remote.util.EnvHelp;
       
    42 import java.io.ObjectStreamClass;
       
    43 import java.lang.reflect.Method;
       
    44 import java.util.ArrayList;
       
    45 import java.util.Arrays;
       
    46 import java.util.List;
       
    47 import sun.reflect.misc.ReflectUtil;
       
    48 import sun.rmi.server.DeserializationChecker;
       
    49 import sun.rmi.server.UnicastServerRef;
       
    50 import sun.rmi.server.UnicastServerRef2;
       
    51 
       
    52 /**
       
    53  * <p>An {@link RMIServer} object that is exported through JRMP and that
       
    54  * creates client connections as RMI objects exported through JRMP.
       
    55  * User code does not usually reference this class directly.</p>
       
    56  *
       
    57  * @see RMIServerImpl
       
    58  *
       
    59  * @since 1.5
       
    60  */
       
    61 public class RMIJRMPServerImpl extends RMIServerImpl {
       
    62 
       
    63     private final ExportedWrapper exportedWrapper;
       
    64 
       
    65     /**
       
    66      * <p>Creates a new {@link RMIServer} object that will be exported
       
    67      * on the given port using the given socket factories.</p>
       
    68      *
       
    69      * @param port the port on which this object and the {@link
       
    70      * RMIConnectionImpl} objects it creates will be exported.  Can be
       
    71      * zero, to indicate any available port.
       
    72      *
       
    73      * @param csf the client socket factory for the created RMI
       
    74      * objects.  Can be null.
       
    75      *
       
    76      * @param ssf the server socket factory for the created RMI
       
    77      * objects.  Can be null.
       
    78      *
       
    79      * @param env the environment map.  Can be null.
       
    80      *
       
    81      * @exception IOException if the {@link RMIServer} object
       
    82      * cannot be created.
       
    83      *
       
    84      * @exception IllegalArgumentException if <code>port</code> is
       
    85      * negative.
       
    86      */
       
    87     public RMIJRMPServerImpl(int port,
       
    88                              RMIClientSocketFactory csf,
       
    89                              RMIServerSocketFactory ssf,
       
    90                              Map<String,?> env)
       
    91             throws IOException {
       
    92 
       
    93         super(env);
       
    94 
       
    95         if (port < 0)
       
    96             throw new IllegalArgumentException("Negative port: " + port);
       
    97 
       
    98         this.port = port;
       
    99         this.csf = csf;
       
   100         this.ssf = ssf;
       
   101         this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;
       
   102 
       
   103         String[] credentialsTypes
       
   104                 = (String[]) this.env.get(RMIConnectorServer.CREDENTIAL_TYPES);
       
   105         List<String> types = null;
       
   106         if (credentialsTypes != null) {
       
   107             types = new ArrayList<>();
       
   108             for (String type : credentialsTypes) {
       
   109                 if (type == null) {
       
   110                     throw new IllegalArgumentException("A credential type is null.");
       
   111                 }
       
   112                 ReflectUtil.checkPackageAccess(type);
       
   113                 types.add(type);
       
   114             }
       
   115         }
       
   116         exportedWrapper = types != null ?
       
   117                 new ExportedWrapper(this, types) :
       
   118                 null;
       
   119     }
       
   120 
       
   121     protected void export() throws IOException {
       
   122         if (exportedWrapper != null) {
       
   123             export(exportedWrapper);
       
   124         } else {
       
   125             export(this);
       
   126         }
       
   127     }
       
   128 
       
   129     private void export(Remote obj) throws RemoteException {
       
   130         final RMIExporter exporter =
       
   131             (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);
       
   132         final boolean daemon = EnvHelp.isServerDaemon(env);
       
   133 
       
   134         if (daemon && exporter != null) {
       
   135             throw new IllegalArgumentException("If "+EnvHelp.JMX_SERVER_DAEMON+
       
   136                     " is specified as true, "+RMIExporter.EXPORTER_ATTRIBUTE+
       
   137                     " cannot be used to specify an exporter!");
       
   138         }
       
   139 
       
   140         if (daemon) {
       
   141             if (csf == null && ssf == null) {
       
   142                 new UnicastServerRef(port).exportObject(obj, null, true);
       
   143             } else {
       
   144                 new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true);
       
   145             }
       
   146         } else if (exporter != null) {
       
   147             exporter.exportObject(obj, port, csf, ssf);
       
   148         } else {
       
   149             UnicastRemoteObject.exportObject(obj, port, csf, ssf);
       
   150         }
       
   151     }
       
   152 
       
   153     private void unexport(Remote obj, boolean force)
       
   154             throws NoSuchObjectException {
       
   155         RMIExporter exporter =
       
   156             (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);
       
   157         if (exporter == null)
       
   158             UnicastRemoteObject.unexportObject(obj, force);
       
   159         else
       
   160             exporter.unexportObject(obj, force);
       
   161     }
       
   162 
       
   163     protected String getProtocol() {
       
   164         return "rmi";
       
   165     }
       
   166 
       
   167     /**
       
   168      * <p>Returns a serializable stub for this {@link RMIServer} object.</p>
       
   169      *
       
   170      * @return a serializable stub.
       
   171      *
       
   172      * @exception IOException if the stub cannot be obtained - e.g the
       
   173      *            RMIJRMPServerImpl has not been exported yet.
       
   174      */
       
   175     public Remote toStub() throws IOException {
       
   176         if (exportedWrapper != null) {
       
   177             return RemoteObject.toStub(exportedWrapper);
       
   178         } else {
       
   179             return RemoteObject.toStub(this);
       
   180         }
       
   181     }
       
   182 
       
   183     /**
       
   184      * <p>Creates a new client connection as an RMI object exported
       
   185      * through JRMP. The port and socket factories for the new
       
   186      * {@link RMIConnection} object are the ones supplied
       
   187      * to the <code>RMIJRMPServerImpl</code> constructor.</p>
       
   188      *
       
   189      * @param connectionId the ID of the new connection. Every
       
   190      * connection opened by this connector server will have a
       
   191      * different id.  The behavior is unspecified if this parameter is
       
   192      * null.
       
   193      *
       
   194      * @param subject the authenticated subject.  Can be null.
       
   195      *
       
   196      * @return the newly-created <code>RMIConnection</code>.
       
   197      *
       
   198      * @exception IOException if the new {@link RMIConnection}
       
   199      * object cannot be created or exported.
       
   200      */
       
   201     protected RMIConnection makeClient(String connectionId, Subject subject)
       
   202             throws IOException {
       
   203 
       
   204         if (connectionId == null)
       
   205             throw new NullPointerException("Null connectionId");
       
   206 
       
   207         RMIConnection client =
       
   208             new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(),
       
   209                                   subject, env);
       
   210         export(client);
       
   211         return client;
       
   212     }
       
   213 
       
   214     protected void closeClient(RMIConnection client) throws IOException {
       
   215         unexport(client, true);
       
   216     }
       
   217 
       
   218     /**
       
   219      * <p>Called by {@link #close()} to close the connector server by
       
   220      * unexporting this object.  After returning from this method, the
       
   221      * connector server must not accept any new connections.</p>
       
   222      *
       
   223      * @exception IOException if the attempt to close the connector
       
   224      * server failed.
       
   225      */
       
   226     protected void closeServer() throws IOException {
       
   227         if (exportedWrapper != null) {
       
   228             unexport(exportedWrapper, true);
       
   229         } else {
       
   230             unexport(this, true);
       
   231         }
       
   232     }
       
   233 
       
   234     private final int port;
       
   235     private final RMIClientSocketFactory csf;
       
   236     private final RMIServerSocketFactory ssf;
       
   237     private final Map<String, ?> env;
       
   238 
       
   239     private static class ExportedWrapper implements RMIServer, DeserializationChecker {
       
   240         private final RMIServer impl;
       
   241         private final List<String> allowedTypes;
       
   242 
       
   243         private ExportedWrapper(RMIServer impl, List<String> credentialsTypes) {
       
   244             this.impl = impl;
       
   245             allowedTypes = credentialsTypes;
       
   246         }
       
   247 
       
   248         @Override
       
   249         public String getVersion() throws RemoteException {
       
   250             return impl.getVersion();
       
   251         }
       
   252 
       
   253         @Override
       
   254         public RMIConnection newClient(Object credentials) throws IOException {
       
   255             return impl.newClient(credentials);
       
   256         }
       
   257 
       
   258         @Override
       
   259         public void check(Method method, ObjectStreamClass descriptor,
       
   260                 int paramIndex, int callID) {
       
   261             String type = descriptor.getName();
       
   262             if (!allowedTypes.contains(type)) {
       
   263                 throw new ClassCastException("Unsupported type: " + type);
       
   264             }
       
   265         }
       
   266 
       
   267         @Override
       
   268         public void checkProxyClass(Method method, String[] ifaces,
       
   269                 int paramIndex, int callID) {
       
   270             if (ifaces != null && ifaces.length > 0) {
       
   271                 for (String iface : ifaces) {
       
   272                     if (!allowedTypes.contains(iface)) {
       
   273                         throw new ClassCastException("Unsupported type: " + iface);
       
   274                     }
       
   275                 }
       
   276             }
       
   277         }
       
   278     }
       
   279 }