/*
// $Id$
// Farrago is an extensible data management system.
// Copyright (C) 2005-2005 The Eigenbase Project
// Copyright (C) 2005-2005 Disruptive Tech
// Copyright (C) 2005-2005 LucidEra, Inc.
// Portions Copyright (C) 2003-2005 John V. Sichi
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version approved by The Eigenbase Project.
//
// This program 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, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package net.sf.farrago.server;

import java.io.*;
import java.rmi.*;
import java.rmi.registry.*;
import java.util.*;

import net.sf.farrago.db.*;
import net.sf.farrago.fem.config.*;
import net.sf.farrago.jdbc.engine.*;
import net.sf.farrago.resource.*;
import net.sf.farrago.session.*;
import net.sf.farrago.util.*;

/**
 * FarragoServer is a wrapper for an RmiJdbc server.
 *
 * @author John V. Sichi
 * @version $Id$
 */
public class FarragoServer
{
    //~ Static fields/initializers --------------------------------------------

    private static Registry rmiRegistry;

    //~ Methods ---------------------------------------------------------------

    /**
     * Defines the main entry point for the Farrago server.  Customized servers
     * can provide their own which call run() with an extended implementation
     * of {@link net.sf.farrago.jdbc.engine.FarragoJdbcServerDriver}.
     *
     * @param args ignored
     */
    public static void main(String [] args)
    {
        FarragoServer server = new FarragoServer();
        server.start(new FarragoJdbcEngineDriver());
        server.runConsole();
    }

    /**
     * Starts the server.
     *
     * @param jdbcDriver the JDBC driver which will be served
     * to remote clients
     */
    public void start(FarragoJdbcServerDriver jdbcDriver)
    {
        FarragoResource res = FarragoResource.instance();
        System.out.println(res.getServerLoadingDatabase());

        // Load the session factory
        FarragoSessionFactory sessionFactory = jdbcDriver.newSessionFactory();

        // Load the database instance
        FarragoDatabase db = FarragoDatabase.pinReference(sessionFactory);

        FemFarragoConfig config = db.getSystemRepos().getCurrentConfig();

        int rmiRegistryPort = config.getServerRmiRegistryPort();

        int singleListenerPort = config.getServerSingleListenerPort();

        System.out.println(res.getServerStartingNetwork());

        List argList = new ArrayList();

        if (rmiRegistry != null) {
            // A server instance was previously in existence, so don't
            // try to recreate the RMI registry.
            argList.add("-noreg");
        }

        argList.add("-port");
        argList.add(Integer.toString(rmiRegistryPort));

        if (singleListenerPort != -1) {
            argList.add("-lp");
            argList.add(Integer.toString(singleListenerPort));
        }

        FarragoRJJdbcServer.main((String []) argList.toArray(new String[0]));

        if (rmiRegistry == null) {
            // This is the first server instance in this JVM, so
            // look up the RMI registry which was just created by
            // RJJdbcServer.main.
            try {
                rmiRegistry = LocateRegistry.getRegistry(rmiRegistryPort);
            } catch (RemoteException ex) {
                // TODO:  handle this better
            }
        }

        System.out.println(
            res.getServerListening(new Integer(rmiRegistryPort)));
    }

    /**
     * Stops the server if there are no sessions.
     *
     * @return whether server was stopped
     */
    public boolean stopSoft()
    {
        FarragoResource res = FarragoResource.instance();
        System.out.println(res.getServerShuttingDown());

        // NOTE:  use groundReferences=1 in shutdownConditional
        // to account for our baseline reference
        if (FarragoDatabase.shutdownConditional(getGroundReferences())) {
            System.out.println(res.getServerShutdownComplete());

            // TODO: should find a way to prevent new messages BEFORE shutdown
            unbindRegistry();
            return true;
        } else {
            System.out.println(res.getServerSessionsExist());
            return false;
        }
    }

    /**
     * Returns the number of ground references for this server.  Ground
     * references are references pinned at startup time.  For the base
     * implementation of FarragoServer this is always 1.  Farrago extensions,
     * especially those that initialize resources via
     * {@link FarragoSessionFactory#specializedInitialization(
     *     FarragoAllocationOwner)}, may need to alter this value.
     *
     * @return the number of ground references for this server
     */
    protected int getGroundReferences()
    {
        return 1;
    }

    /**
     * Stops the server, killing any sessions.
     */
    public void stopHard()
    {
        unbindRegistry();
        FarragoResource res = FarragoResource.instance();
        System.out.println(res.getServerShuttingDown());
        FarragoDatabase.shutdown();
        System.out.println(res.getServerShutdownComplete());
    }

    private void unbindRegistry()
    {
        try {
            String [] names = rmiRegistry.list();
            for (int i = 0; i < names.length; ++i) {
                rmiRegistry.unbind(names[i]);
            }
        } catch (Exception ex) {
            // TODO:  handle this better
        }
    }

    /**
     * Implements console interaction from stdin after the server
     * has successfully started.
     */
    public void runConsole()
    {
        FarragoResource res = FarragoResource.instance();

        // TODO:  install signal handlers also
        InputStreamReader inReader = new InputStreamReader(System.in);
        LineNumberReader lineReader = new LineNumberReader(inReader);
        for (;;) {
            String cmd;
            try {
                cmd = lineReader.readLine();
            } catch (IOException ex) {
                break;
            }
            if (cmd == null) {
                // interpret end-of-stream as meaning we are supposed to
                // run forever as a daemon
                return;
            }
            if (cmd.equals("!quit")) {
                if (stopSoft()) {
                    break;
                }
            } else if (cmd.equals("!kill")) {
                stopHard();
                break;
            } else {
                System.out.println(res.getServerBadCommand(cmd));
            }
        }
        System.exit(0);
    }

}


// End FarragoServer.java

@@ -1532,21 +1532,23 @@
 %0A%0A    pr
-ivate
+otected
  static 
@@ -5692,43 +5692,167 @@
     
-private void unbindRegistry()%0A    %7B
+/** Unbinds all items remaining in RMI registry. */%0A    protected void unbindRegistry()%0A    %7B%0A        if (rmiRegistry == null) %7B%0A            return;%0A        %7D%0A
 %0A   
@@ -6091,32 +6091,66 @@
 dle this better%0A
+            ex.printStackTrace();%0A
         %7D%0A    %7D%0A

make FarragoServer more easily extensible; add traceback for RMI registry unbind errors