public class

SSLContextRMIServerSocketFactory

extends SslRMIServerSocketFactory
/*
 * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.management.jmxremote;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;

/**
 * This class represents a specialized version of the
 * <code>SslRMIServerSocketFactory</code> class that
 * allows to supply an <code>SSLContext</code>.
 *
 * @see javax.rmi.ssl.SslRMIServerSocketFactory
 */
public class SSLContextRMIServerSocketFactory extends SslRMIServerSocketFactory {
    
    /**
     * <p>Creates a new <code>SSLContextRMIServerSocketFactory</code> with
     * SSL sockets created from the <code>SSLSocketFactory</code> returned
     * by the given <code>SSLContext</code> and configured with the default
     * SSL parameters.
     *
     * <p>SSL connections accepted by server sockets created by this
     * factory have the default cipher suites and protocol versions
     * enabled and do not require client authentication.</p>
     *
     * @param context the SSL context to be used for creating SSL sockets.
     * Calling this constructor with a null <code>context</code> is equivalent
     * to calling <code>SslRMIServerSocketFactory()</code>.
     */
    public SSLContextRMIServerSocketFactory(SSLContext context) {
        this(context, null, null, false);
    }
    
    /**
     * <p>Creates a new <code>SSLContextRMIServerSocketFactory</code> with
     * SSL sockets created from the <code>SSLSocketFactory</code> returned
     * by the given <code>SSLContext</code> and configured with the supplied
     * SSL parameters.
     *
     * @param context the SSL context to be used for creating SSL sockets.
     * Calling this constructor with a null <code>context</code> is equivalent
     * to calling <code>SslRMIServerSocketFactory(enabledCipherSuites,
     * enabledProtocols, needClientAuth)</code>.
     *
     * @param enabledCipherSuites names of all the cipher suites to
     * enable on SSL connections accepted by server sockets created by
     * this factory, or <code>null</code> to use the cipher suites
     * that are enabled by default
     *
     * @param enabledProtocols names of all the protocol versions to
     * enable on SSL connections accepted by server sockets created by
     * this factory, or <code>null</code> to use the protocol versions
     * that are enabled by default
     *
     * @param needClientAuth <code>true</code> to require client
     * authentication on SSL connections accepted by server sockets
     * created by this factory; <code>false</code> to not require
     * client authentication
     *
     * @exception IllegalArgumentException when one or more of the cipher
     * suites named by the <code>enabledCipherSuites</code> parameter is
     * not supported, when one or more of the protocols named by the
     * <code>enabledProtocols</code> parameter is not supported or when
     * a problem is encountered while trying to check if the supplied
     * cipher suites and protocols to be enabled are supported.
     *
     * @see SSLSocket#setEnabledCipherSuites
     * @see SSLSocket#setEnabledProtocols
     * @see SSLSocket#setNeedClientAuth
     */
    public SSLContextRMIServerSocketFactory(
            SSLContext context,
            String[] enabledCipherSuites,
            String[] enabledProtocols,
            boolean needClientAuth)
            throws IllegalArgumentException {
        super(enabledCipherSuites, enabledProtocols, needClientAuth);
        this.context = context;
        // NOTE: We should check the availability of the enabledCipherSuites
        // and enabledProtocols in the socket factory returned by the call
        // context.getSocketFactory() because it could differ from the one
        // returned by SSLSocketFactory.getDefault(), which is already
        // checked in the parent's class constructor, but we don't do it
        // because we know that although the factory the out-of-the-box
        // management agent uses might be different, they are of the same
        // type and use the same underlying SSLSocket implementation.
    }
    
    /**
     * <p>Creates a server socket that accepts SSL connections configured
     * according to this factory's SSL socket configuration parameters.
     * If a null <code>SSLContext</code> was supplied in the constructor
     * this method just calls <code>super.createServerSocket(port)</code>.
     * Otherwise, the <code>SSLSocketFactory</code> returned by the call to
     * <code>SSLContext.getSocketFactory()</code> will be used to create the
     * SSL sockets.</p>
     */
    @Override
    public ServerSocket createServerSocket(int port) throws IOException {
        if (context == null) {
            return super.createServerSocket(port);
        } else {
            final SSLSocketFactory sslSocketFactory = context.getSocketFactory();
            return new ServerSocket(port) {
                public Socket accept() throws IOException {
                    Socket socket = super.accept();
                    SSLSocket sslSocket = (SSLSocket)
                    sslSocketFactory.createSocket(
                            socket, socket.getInetAddress().getHostName(),
                            socket.getPort(), true);
                    sslSocket.setUseClientMode(false);
                    if (getEnabledCipherSuites() != null) {
                        sslSocket.setEnabledCipherSuites(getEnabledCipherSuites());
                    }
                    if (getEnabledProtocols() != null) {
                        sslSocket.setEnabledProtocols(getEnabledProtocols());
                    }
                    sslSocket.setNeedClientAuth(getNeedClientAuth());
                    return sslSocket;
                }
            };
        }
    }
    
    /**
     * <p>Indicates whether some other object is "equal to" this one.</p>
     *
     * <p>Two <code>SSLContextRMIServerSocketFactory</code> objects are
     * equal if they have been constructed with the same SSL context and
     * SSL socket configuration parameters.</p>
     *
     * <p>A subclass should override this method (as well as
     * {@link #hashCode()}) if it adds instance state that affects
     * equality.</p>
     */
    @Override
    public boolean equals(Object obj) {
        if (!super.equals(obj))
            return false;
        SSLContextRMIServerSocketFactory that = (SSLContextRMIServerSocketFactory) obj;
        return context == null ? that.context == null : context.equals(that.context);
    }
    
    /**
     * <p>Returns a hash code value for this
     * <code>SSLContextRMIServerSocketFactory</code>.</p>
     *
     * @return a hash code value for this
     * <code>SSLContextRMIServerSocketFactory</code>.
     */
    @Override
    public int hashCode() {
        return super.hashCode() + (context == null ? 0 : context.hashCode());
    }
    
    private SSLContext context;
}