/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*/
package com.sun.sgs.impl.util;
import com.sun.sgs.impl.sharedutil.LoggerWrapper;
import java.io.IOException;
import java.net.ServerSocket;
import java.rmi.NoSuchObjectException;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Provides for making the server available on the network, and removing it
* from the network during shutdown.
*
* @param <T> the remote interface type
*/
public class Exporter<T extends Remote> {
/** The name of this class. */
private static final String CLASSNAME = Exporter.class.getName();
/** The logger for this class. */
private static final LoggerWrapper logger =
new LoggerWrapper(Logger.getLogger(CLASSNAME));
/** The type of the server. */
private final Class<T> type;
/** The server for handling inbound requests. */
private T server;
/** The Java(TM) RMI registry for advertising the server. */
private Registry registry;
/** The server proxy. */
private T proxy;
/** Creates an instance for exporting a remote object of the given
* {@code type}.
*
* @param type the remote object type
*/
public Exporter(Class<T> type) {
this.type = type;
}
/**
* Makes the server available on the network on the specified
* port, and binds the server's proxy in a registry on the same
* port with the specified name. If the port is 0, chooses an
* anonymous port. Returns the actual port on which the server is
* available.
*
* @param server the server
* @param name the name of the server's proxy in the registry
* @param port the network port for the server
*
* @return the port on which the server is available
*
* @throws IOException if there is a problem exporting the server
*/
public synchronized int export(T server, String name, int port)
throws IOException
{
if (server == null) {
throw new NullPointerException("null server");
} else if (name == null) {
throw new NullPointerException("null name");
}
this.server = server;
ServerSocketFactory ssf = new ServerSocketFactory();
registry = LocateRegistry.createRegistry(port, null, ssf);
proxy = type.cast(
UnicastRemoteObject.exportObject(server, port, null, ssf));
registry.rebind(name, proxy);
return ssf.getLocalPort();
}
/**
* Makes the server available on the network on the specified port. If
* the port is 0, chooses an anonymous port. Returns the actual port
* on which the server is available.
*
* @param server the server
* @param port the network port for the server
*
* @return the port on which the server is available
*
* @throws IOException if there is a problem exporting the server
*/
public synchronized int export(T server, int port) throws IOException {
if (server == null) {
throw new NullPointerException("null server");
}
this.server = server;
ServerSocketFactory ssf = new ServerSocketFactory();
proxy = type.cast(
UnicastRemoteObject.exportObject(server, port, null, ssf));
return ssf.getLocalPort();
}
/**
* Returns the exported server's proxy which is available after
* {@code export} is invoked successfully. Before the server is
* exported, this method returns {@code null}.
*
* @return the server's proxy, or {@code null}
*/
public synchronized T getProxy() {
return proxy;
}
/**
* Removes the server from the network. This method will return immediately
* if called a second time.
*/
public synchronized void unexport() {
if (server == null) {
return; // return silently
}
if (registry != null) {
try {
UnicastRemoteObject.unexportObject(registry, true);
registry = null;
} catch (NoSuchObjectException e) {
logger.logThrow(
Level.FINE, e, "Problem unexporting registry");
return;
}
}
try {
UnicastRemoteObject.unexportObject(server, true);
server = null;
} catch (NoSuchObjectException e) {
logger.logThrow(
Level.FINE, e, "Problem unexporting server");
return;
}
}
/**
* Defines a server socket factory that provides access to the server
* socket's local port.
*/
private static class ServerSocketFactory
implements RMIServerSocketFactory
{
/** The last server socket created. */
private ServerSocket serverSocket;
/** Creates an instance. */
ServerSocketFactory() { }
/** {@inheritDoc} */
public ServerSocket createServerSocket(int port) throws IOException {
serverSocket = new ServerSocket(port);
return serverSocket;
}
/** Returns the local port of the last server socket created. */
int getLocalPort() {
return (serverSocket == null) ? -1 : serverSocket.getLocalPort();
}
}
}