/* * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * -Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Oracle nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF * THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that Software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility. */ package example.inetd; import java.io.IOException; import java.io.InterruptedIOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.Channel; import java.nio.channels.ServerSocketChannel; import java.rmi.AlreadyBoundException; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.RMIServerSocketFactory; /** * A utility to export a registry (using an inherited channel if launched * from inetd) and to bind a remote service's proxy in that * registry for clients to look up. **/ public class InitializeRegistry { private static final Object lock = new Object(); private static boolean serviceAvailable = false; private static boolean initialized = false; /** * Prevents instantiation. */ private InitializeRegistry() { throw new AssertionError(); } /** * Creates and exports a registry (using an inherited channel, if any, * as specified below), and binds the specified name to the specified * proxy in that registry. * * First, the registry is exported as follows: * * *

Once the registry is exported, the registry's bind * method is invoked with the specified name and proxy as arguments. * * @param obj the proxy for a remote object * @param name the name for the remote object in the registry * @param port a port to export the registry on if there is no * inherited channel * @throws IllegalArgumentException if the inherited channel is * null and the port is 0 * @throws IllegalStateException if this method was called previously * @throws IOException if the inherited channel is not an instance * of ServerSocketChannel or null * @throws RemoteException if the registry could not be exported **/ public static void initializeWithInheritedChannel(Remote proxy, String name, int port) throws IOException { /* * Only allow this method to be invoked once. */ synchronized (InitializeRegistry.class) { if (initialized) { throw new IllegalStateException("already invoked"); } initialized = true; } Channel channel = System.inheritedChannel(); ServerSocket serverSocket = null; /* * Handle inherited channel, if any. */ if (channel instanceof ServerSocketChannel) { /* * Service launched from inetd. Get server socket from * inherited server socket channel. */ serverSocket = ((ServerSocketChannel) channel).socket(); } else if (channel == null) { /* * Service launched from the command line. In this case, the * port specified for the registry must be nonzero */ if (port == 0) { throw new IllegalArgumentException("port must be nonzero"); } serverSocket = new ServerSocket(port); } else { throw new IOException( "unexpected channel returned from inheritedChannel: " + channel.toString()); } /* * Create server socket factory for registry to delay accepting * calls until a service is bound in the registry. */ RMIServerSocketFactory ssf = new RegistryServerSocketFactory(serverSocket); /* * Create/export registry and bind name to proxy in registry. */ Registry registry = LocateRegistry.createRegistry(port, null, ssf); try { registry.bind(name, proxy); } catch (RemoteException impossible) { throw new AssertionError(impossible); } catch (AlreadyBoundException impossible) { throw new AssertionError(impossible); } /* * Notify registry's socket factory that the service proxy is * bound in the registry, so that the registry can accept * incoming requests to look up the service. */ synchronized (lock) { serviceAvailable = true; lock.notifyAll(); } } /** * A server socket factory to use when exporting a registry launched * from 'inetd' with 'wait' status. This socket factory's * 'createServerSocket' method returns a server socket that wraps the * server socket specified during construction and is specialized to * delay accepting requests until a remote service is bound in the * registry (when the 'serviceAvailable' flag is 'true'). The server * socket supplied to the constructor should be the server socket * obtained from the 'System.inheritedChannel' method. * * Note that only a single instance of this class should be created. **/ private static class RegistryServerSocketFactory implements RMIServerSocketFactory { private final ServerSocket serverSocket; /** * Constructs a 'RegistryServerSocketFactory' with the specified * 'serverSocket'. **/ RegistryServerSocketFactory(ServerSocket serverSocket) { this.serverSocket = serverSocket; } /** * Returns the server socket specified during construction wrapped * in a 'DelayedAcceptServerSocket'. The port argument is ignored. **/ public ServerSocket createServerSocket(int port) throws IOException { return new DelayedAcceptServerSocket(serverSocket); } } /** * A server socket that delegates all public methods to the underlying * server socket specified at construction. The accept method is * overridden to delay calling accept on the underlying server socket * until a remote service is bound in the registry (when the * 'serviceAvailable' flag is 'true'). **/ private static class DelayedAcceptServerSocket extends ServerSocket { private final ServerSocket serverSocket; /** * Constructs a 'DelayedAcceptServerSocket' with the specified * 'serverSocket'. */ DelayedAcceptServerSocket(ServerSocket serverSocket) throws IOException { this.serverSocket = serverSocket; } public void bind(SocketAddress endpoint) throws IOException { serverSocket.bind(endpoint); } public void bind(SocketAddress endpoint, int backlog) throws IOException { serverSocket.bind(endpoint, backlog); } public InetAddress getInetAddress() { return serverSocket.getInetAddress(); } public int getLocalPort() { return serverSocket.getLocalPort(); } public SocketAddress getLocalSocketAddress() { return serverSocket.getLocalSocketAddress(); } /** * Delays calling accept on the underlying server socket until the * remote service is bound in the registry. **/ public Socket accept() throws IOException { synchronized (lock) { try { while (!serviceAvailable) { lock.wait(); } } catch (InterruptedException e) { throw (IOException) (new InterruptedIOException()).initCause(e); } } return serverSocket.accept(); } public void close() throws IOException { serverSocket.close(); } public ServerSocketChannel getChannel() { return serverSocket.getChannel(); } public boolean isBound() { return serverSocket.isBound(); } public boolean isClosed() { return serverSocket.isClosed(); } public void setSoTimeout(int timeout) throws SocketException { serverSocket.setSoTimeout(timeout); } public int getSoTimeout() throws IOException { return serverSocket.getSoTimeout(); } public void setReuseAddress(boolean on) throws SocketException { serverSocket.setReuseAddress(on); } public boolean getReuseAddress() throws SocketException { return serverSocket.getReuseAddress(); } public String toString() { return serverSocket.toString(); } public void setReceiveBufferSize(int size) throws SocketException { serverSocket.setReceiveBufferSize(size); } public int getReceiveBufferSize() throws SocketException { return serverSocket.getReceiveBufferSize(); } } }