package jacorb.imr;

import java.util.*;
import jacorb.imr.RegistrationPackage.*;
import jacorb.imr.AdminPackage.*;

/**
 * This class contains the information about a logical server.
 * It has methods for managing the associated POAs, holding and
 * releasing the server, and, for the "client side", a method
 * that blocks until the server is released.
 *
 * @author Nicolas Noffke
 *
 * $Log: ImRServerInfo.java,v $
 * Revision 1.7  1999/11/25 16:04:54  brose
 * cosmetics
 *
 * Revision 1.6  1999/11/09 10:59:26  brose
 * new GUI version
 *
 * Revision 1.4  1999/10/30 16:02:58  noffke
 * Fixed bug: servers could be restarted multiple times when serveral
 * clients tried to restart them simultaneously.
 *
 * Revision 1.3  1999/10/29 19:24:29  noffke
 * Cosmetics, now fully commented , adapted to new/altered methods from the
 * interface
 *
 *
 */

public class ImRServerInfo  implements java.io.Serializable{
    protected String m_command;
    protected boolean m_holding = false;
    protected String m_host;
    protected String m_name;
    protected boolean m_active;
    protected boolean m_restarting = false;

    private Vector m_poas = null;
    private RessourceLock m_poas_lock = null;

    /**
     * The Constructor. It sets up the internal attributes.
     *
     * @param name the logical server name
     * @param host the name of the host on which the server should be restarted
     * (ignored when no startup command is specified).
     * @param command the startup command for this server, passed to the 
     * server startup daemon on <code>host</code> (in case there is one active).
     * @exception IllegalServerName thrown when <code>name</code> is 
     * <code>null</code> or of length zero.
     **/
    public ImRServerInfo(String name, String host, String command) 
	throws IllegalServerName{

	//super(name, host);

	if (name == null || name.length() == 0)
	    throw new IllegalServerName(name);
	
	m_name = name;
	m_host = host;
	m_command = command;
	m_active = false;
	m_poas = new Vector(); 
	m_poas_lock = new RessourceLock();
    }
    
    /**
     * "Converts" this Object to a <code>ServerInfo</code> instance containing
     * the same info as this object.
     *
     * @return a <code>ServerInfo</code> object.
     **/
    public ServerInfo toServerInfo(){
	m_poas_lock.gainExclusiveLock();

	// The ServerInfo class stores its POAs in an array, therefore
	// the vector has to copied. Because of backward compatibility
	// issues we decided not to use toArray() from the jdk1.2

	// build array
	POAInfo[] _poas = new POAInfo[m_poas.size()];
	Enumeration _poa_enum = m_poas.elements();

	// copy vector into array
	int _i = 0;
	while(_poa_enum.hasMoreElements())
	    _poas[_i++] = ((ImRPOAInfo) _poa_enum.nextElement()).toPOAInfo();

	m_poas_lock.releaseExclusiveLock();

	return new ServerInfo(m_name, m_command, _poas, m_host, m_active, m_holding);
    }

    /**
     * Adds a POA to this server.
     *
     * @param poa the POA to add.
     **/
    public void addPOA(ImRPOAInfo poa){
	if (! m_active)
	    m_active = true;

	m_poas_lock.gainSharedLock();
	m_poas.addElement(poa);
	m_poas_lock.releaseSharedLock();
    }

    /**
     * Builds an array of of the names of the POAs associated with this server.
     * <br> This method is needed for deleting a server since its POAs have to be
     * as well removed from the central storage.
     * @return an array of POA names
     **/
    protected String[] getPOANames(){
	// not synchronizing here since this method is only called
	// prior to destructing this object.
	String[] _poa_names = new String[m_poas.size()];
	Enumeration _poa_enum = m_poas.elements();

	int _i = 0;
	while(_poa_enum.hasMoreElements())
	    _poa_names[_i++] = ((ImRPOAInfo) _poa_enum.nextElement()).m_name;
	
	return _poa_names;
    }

    /**
     * Sets the server down, i.e. not active. If a request for a POA
     * of this server is received, the repository tries to restart the server.
     * <br>The server is automatically set back to active when the first of
     * its POAs gets reregistered.
     **/
    public void setDown(){
	// sets all associated to not active.
	for (int _i = 0; _i < m_poas.size(); _i++)
	    ((ImRPOAInfo) m_poas.elementAt(_i)).m_active = false;

	m_active = false;
    }

    /**
     * This method blocks until the server is released, i.e. set
     * to not holding. <br> This will not time out since holding a 
     * server is only done by administrators.
     * @param
     **/
    public synchronized void awaitRelease(){
	while(m_holding){
	    try{		
		wait();
	    }catch (java.lang.Exception _e){
		jacorb.util.Debug.output(2, _e);
	    }
	}	
    }

    /**
     * Release the server and unblock all waiting threads.
     **/
    public synchronized void release(){
	m_holding = false;
	notifyAll();
    }
    
    /**
     * Tests if this server should be restarted. That is the
     * case if the server is not active and nobody else is currently
     * trying to restart it. <br>
     * If true is returned the server is set to restarting. That means
     * the thread calling this method has to restart the server, 
     * otherwise it will stay down indefinetly.
     *
     * @return true, if the server should be restarted by the calling thread.
     */
    public synchronized boolean shouldBeRestarted(){
	boolean _restart = !(m_active || m_restarting);
	if (_restart)
	    m_restarting = true;
	    
	return _restart;
    }

} // ImRServerInfo


