package server;

import client.ClientDataInterface;
import java.rmi.*;
import java.rmi.server.*;
import javax.swing.*;
import java.awt.*;

/****
 *
 * Class Server is a simple illustration of a remote server that uses RMI
 * communication.  The server provides three typical methods to a client:
 * <tt>receiveClientInput</tt>, <tt>compute</tt>, and <tt>getServerOutput</tt>.
 * These methods are described further in their respective method
 * documentation.
 *									    <p>
 * The <tt>main</tt> method of the server accepts two command-line arguments.
 * The first argument is the name of the host computer on which the server
 * runs.  The hostname may be suffixed with a colon-delimited port number.  If
 * the port number is not present, the rmiregistry on the host is assumed to be
 * running on the well-known port 1099.  So, e.g., a legal hostname could be
 * "waldorf.csc.calpoly.edu" or "waldorf.csc.calpoly.edu:1098", the latter
 * selecting alternate registry port 1098.
 *									    <p>
 * The second command-line argument is an optional flag indicating if the
 * server's GUI should be displayed when it runs.  If the argument is missing,
 * the default behavior is to display the GUI.  If the second argument is
 * "<tt>-nd</tt>", then no GUI display is shown.  Using the "-nd" argument is
 * useful when the server is run in a context where there is no support for a
 * Java GUI display, for example, running the server on a UNIX machine like
 * waldorf when logged into waldorf via telnet from a Windows PC.
 *									    <p>
 * See the example <a href= ../client/Client.html> <tt>Client</tt> </a> class
 * for a description of how a client connects to this server and uses its
 * services.
 *									    <p>
 * It is noteworthy in this example that all method calls are initiated from
 * the client.  I.e., the computation is 100% client-driven.  The server calls
 * <emphasis>no</emphasis> client methods.  Specifically, input data are
 * <emphasis>pushed</emphasis> from the client to the server by the client's
 * call to <tt>receiveClientInput</tt>.  The server computation is initiated by
 * the client's call to <tt>compute</tt>.  And then the output data are
 * <emphasis>pulled</emphasis> by the client from the server with the client's
 * call to <tt>getServerOutput</tt>.
 *									    <p>
 * This client-driven computation could be replaced with a server-driven form,
 * where the server calls client's methods.  Or there could be some combined
 * form, e.g., the client performs a push of its input data, and the server
 * responds with a push its output.  Whether to use a client- or sever-driven
 * form of computation depends on a number of factors, including where the
 * end-user fits into the computation, which side should perform input data
 * validity checking, and what security concerns there are.  Details of these
 * issues are beyond the scope of this example.

 *
 */
public class Server extends UnicastRemoteObject implements ServerInterface {

    /**
     * Construct this by calling the parent constructor.
     */
    public Server() throws RemoteException {
        super();
    }

    /*-*
     * Public client methods.
     */

    /**
     * Receive some input from the client.  Store a local copy for computation
     * use.  Also, display the data in the server's display window, or output
     * the data to stdout if no display is available.
     */
    public void receiveClientInput(ClientDataInterface clientData)
	    throws RemoteException {
        this.clientData = clientData;
	if (displayOn) {
	    textField.setText(Integer.toString(clientData.getValue()));
	}
	else {
	    System.out.println("Received Client Data: " +
		Integer.toString(clientData.getValue()));
	}
    }

    /**
     * Perform some computation using the client input.  In this case, we
     * simply add 1 to the numeric input value received by the
     * <tt>receiveClientInput</tt> method.
     */
    public void compute() throws RemoteException {
        serverOutput = clientData.getValue() + 1;
    }

    /**
     * Return computation results back to the client, when the client calls for
     * it.
     */
    public Object getServerOutput() throws RemoteException {
        return new Integer(serverOutput);
    }


    /*-*
     * Protected setup methods.
     */

    /**
     * Set up the display as a JFrame with a labeled text field.  The
     * </tt>hostname</tt> input is the command-line argument from main.
     */
    protected static void setupDisplay(String hostname) {

	/*
	 * Allocate the frame and its innards.
	 */
	JFrame frame = new JFrame();
	JPanel panel = new JPanel();
	Box box = Box.createHorizontalBox();

	/*
	 * Add the text field.
	 */
	textField = new JTextField(8);
	box.add(new JLabel("Received Client Data: "));
	box.add(textField);

	/*
	 * Add border for some spacing.
	 */
	panel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
	panel.add(box, BorderLayout.CENTER);

	/*
	 * Add to, pack, and make visible the frame.
	 */
	frame.setTitle(hostname + " server");
	frame.getContentPane().add(panel);
	frame.pack();
	frame.setVisible(true);
    }

    /**
     * Perform the necessary setup for remote execution.  The <tt>hostname</tt>
     * input is a server name with optional port number, e.g.,
     * "<tt>waldorf.csc.calpoly.edu</tt>" or
     * "<tt>waldorf.csc.calpoly.edu:1098</tt>".  Server setup entails the
     * following processing:
     *							      <br><br> <ol><li>
     *   Set up a Java security manager if there isn't one already running on
     *   the server machine.
     *								   <br><br><li>
     *   Create a server name with the syntax
     *   "<tt>//<em>hostname</em>/Server</tt>".  The "<tt>//</tt>" prefix is
     *   required by the <tt>Naming.rebind</tt> method.  The
     *   <tt><em>hostname</em></tt> is the given string argument.  The
     *   "<tt>/Server</tt>" suffix is the name of the server class, i.e., this
     *   class.
     *								   <br><br><li>
     *   Allocate a remote server instance and bind it in the host's rmi
     *   registry.  This makes the server available to requesting clients.
     *								   <br><br><li>
     *   Handle any exception that may occur during server binding.  The most
     *   typical problems include that the server is not running or that the
     *   security policy is not met.  The easiest way to avoid security policy
     *   problems is to use the most liberal policy possible (see the file
     *   ./java.policy.liberal).
     *									  </ol>
     */
    protected static void setupServer(String hostname) {

	/*
	 * Set up the security manager if necessary.
	 */
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }

	/*
	 * Allocate a remote server instance and bind it in the host's rmi
	 * registry.  This makes the server available to requesting clients.
	 */
        try {
            Server server = new Server();
            Naming.rebind("//" + hostname + "/Server", server);
            System.out.println("Server bound");
	}
	/*
	 * Handle any remote exception that may occur during binding.
	 */
        catch (Exception e) {
            System.err.println("Server binding exception:\n" + e.getMessage());
            e.printStackTrace();
        }

    }

    /**
     * Get the hostname from the command-line argument, exiting if there is
     * none.  Then call the display and server setup methods and we're ready to
     * accept client requests.
     */
    public static void main(String[] args) {

	/*
	 * Make sure there's a hostname given on the command line.
	 */
	if (args.length == 0) {
	    System.out.println(
		"First command-line argument must be a host name.");
	    System.exit(0);
	}

	/*
	 * Set up the display if the second command-line arg is != "-nd".
	 */	
	if ((args.length > 1) && (args[1].equals("-nd"))) {
	    displayOn = false;
	}
	else {
	    displayOn = true;
	    setupDisplay(args[0]);
	}

	/*
	 * Set up the server.
	 */
	setupServer(args[0]);

    }


    /** Local copy of client input for computing with */
    protected ClientDataInterface clientData;

    /** Value computed by the server */
    protected int serverOutput;

    /** The text field that displays the received client data; received client
        data are printed to stdout instead of this text field if the GUI
        display is not active */
    protected static JTextField textField;

    /** True if the display is on, i.e., the 2nd command-line arg != "-nd" */
    protected static boolean displayOn;

}