package jacorb.orb.domain;

import java.util.Hashtable;
import java.util.Enumeration;
import jacorb.util.Debug;
/**
 * The implementation of the IDL interface ORBDomain.
 * ORBDomainImpl.java *
 * Created: Sun Aug 13 11:10:27 2000
 *
 * @author Herbert Kiefer
 * @version $Revision: 1.7 $
 */

public class ORBDomainImpl extends DomainImpl 
                           implements ORBDomainOperations
{
  /** the tie servant for an instance of this class */
  private ORBDomainPOATie theTie= null;

  /** a cache for ODM entries. */
  private ODMCache theCache;
  
  /** the set of local domains */
  private Hashtable theLocalDomains;

  /** creates an orb domain.
   *  The domain is initially empty, contains no policies
   *  and its name is the empty 
   *  string.
   */
  public ORBDomainImpl()
  {
    this(null, null, "");
  }

  /** creates an orb domain.
   *  The domain gets the specified list as initial members, contains no policies
   *  and its name is the empty 
   *  string.
   *  @param initialMembers a list of objects which shall become 
   *                        members of the domain
   */
  public ORBDomainImpl(org.omg.CORBA.Object[] initialMembers)
  {
    this(initialMembers, null, "");
  }
 
 
  
  /** creates an orb domain.
   *  The newly created domain contains the list of initial members,
   *  has the policies from the list of initial policies set and the
   *  the parameter mainPolicyType specifies the default policy type.
   *  string.
   */
  public ORBDomainImpl(org.omg.CORBA.Object[] initialMembers, 
		       org.omg.CORBA.Policy[] initialPolicies)
  { 
    this(initialMembers, initialPolicies, "");
  }

  /** Creates an orb domain. 
   *  A set of initial members, a default policy type, a set of initial 
   * minor policies and the name of the domain are specified by the parameters.
   */
  public ORBDomainImpl(org.omg.CORBA.Object[] initialMembers, 
		       org.omg.CORBA.Policy[] initialPolicies,
		       String                 name) 
  {
    super(initialMembers, initialPolicies, name);
    theLocalDomains= new Hashtable(30);
    theCache= new ODMCache();
  }


  /** registers a domain as a local domain to this orb domain.
   * Post: isLocalTo(aDomain)
   */
  public void insertLocalDomain(jacorb.orb.domain.Domain aDomain)
  {
    theLocalDomains.put(aDomain, aDomain);
  }

  /** checks whether a domain is registered as local at this orb domain. */
  public boolean isLocalTo(jacorb.orb.domain.Domain aDomain)
  {
    return theLocalDomains.contains(aDomain);
  }
  
  /** deregisters a domain as a local domain from this orb domain. 
   * Post: NOT isLocalTo(aDomain)
   */
  public void removeLocalDomain(jacorb.orb.domain.Domain aDomain)
  {
    theLocalDomains.remove(aDomain);
  }

  /** sets the tie for the orb domain. Necessary to delegate the _this() call */
  public void setTie(ORBDomainPOATie tie)
  {
    theTie= tie;
  }

  // tie stuff

  /** overwrites jacorb.orb.domain.DomainPOA._this(). delegates the call
   *  to the tie which must have been set before.
   *  @see jacorb.orb.domain.ORBDomainImpl#setTie
   *  @see jacorb.orb.domain.ORBDomainPOATie
   */
   public jacorb.orb.domain.Domain _this()
  {
    Debug.output(Debug.DOMAIN | Debug.DEBUG1, "ORBDomainImpl._this()");
    Debug.assert(1, theTie != null, "ORBDomainPOATie._this: the tie has not been set (is null)");
    return theTie._this();
  }
  
  /** gets the poa via the tie servant. 
   *  @see jacorb.orb.domain.DomainImpl#_getPOA
   */
  public org.omg.PortableServer.POA _getPOA()
  {   
    Debug.assert(1, theTie != null, "ORBDomainPOATie._getPOA: the tie has not been set (is null)");
    return theTie._poa();
  }
  /** gets the orb. */
  public org.omg.CORBA.ORB _getORB()
  {
    Debug.assert(1, theTie != null, "ORBDomainPOATie._getORB: the tie has not been set (is null)");
    return theTie._orb();
  }


  /** returns the domains the object is associated with. The orb domain has its own optimized
   *  algorithm for the search: Firstly, all domains, wich are registered as local at the
   *  orb domain are searched for a valid odm entry. If none of them provides one, the 
   *  searches starts at the root domain and traverses the underlying domain graph until
   *  a valid odm entry is found. Normally all calls to obtain the doamins of an object are
   *  delegeted to this function. For example a normal domain delegates the getDomains call
   *  to its orb domain and the ServantDelegate also delegates to its orb domain.
   *  @see jacorb.orb.domain.DomainImpl#traverseDownwards
   *  @see jacorb.orb.domain.DomainImpl#getDomains
   *  @see jacorb.orb.ServantDelegate#_domainService
   *  @see jacorb.orb.ServantDelegate#_get_domain_managers
   */
  public Domain[] getDomains(org.omg.CORBA.Object obj)
  { 
    // synchronized (_memberLock)
      {
    
    Domain domain;
    Domain result[];
    // check cache
    result= theCache.read(obj);
    if (result != null)
      {
	Debug.output(Debug.DOMAIN | Debug.DEBUG1," ORBDomainImpl<" + name() 
		     + ">.getDomains: cache hit");
	return result;
      }

    // else
    Debug.output(Debug.DOMAIN | Debug.DEBUG1," ORBDomainImpl<" + name() 
		     + ">.getDomains: cache miss");
    // firstly, try all local domains
    Enumeration resultEnum =  theLocalDomains.keys();
    while ( resultEnum.hasMoreElements() ) 
      {
	domain= (Domain) resultEnum.nextElement() ;
	if ( domain.hasMember(obj) ) 
	  {
	    Debug.output(Debug.DOMAIN | Debug.DEBUG1," ORBDomainImpl<" + name() 
			 + ">.getDomains: found mapping for an obj in " + domain.name() );
	    result= domain.getMapping(obj); 
	    theCache.write(obj, result);
	    return result;
	  }
      }

    // mapping for obj not found
    // secondly, traverse from root domain
    Debug.output(Debug.DOMAIN | Debug.DEBUG1," ORBDomainImpl<" + name() 
			 + ">.getDomains: mapping not found in local domains, searching root");

    DomainListHolder holder= new DomainListHolder();
    if ( super.traverseDownwards(obj, getRootDomain(), holder, new Hashtable() ) )
      { // found
	theCache.write(obj, holder.value);
	return holder.value; 
      }
    else 
      {
	Debug.output(Debug.DOMAIN | Debug.DEBUG1," ORBDomainImpl<" + name() 
			 + ">.getDomains: nothing found, returning empty list");
	return new Domain[0];     // not found, return empty list
      }
      }

    // if not found in some local domains, delegate call to the root domain
  //    if ( isRoot() )
//        { // ops, we are not mounted so some domain
//  	return new Domain[0];
//        }
//      else return getRootDomain().getDomains(obj);

//      // finally, return the empty list
//      //     return new Domain[0];
//      try
//        {
//  	domain= DomainHelper.narrow(_getORB().resolve_initial_references
//  				    ("DomainService"));
//  	if ( domain == null )
//  	  {
//  	    Debug.output(Debug.DOMAIN | Debug.IMPORTANT, "ORBDomainImpl.getDoamins: "
//  +" could not get reference to domain server, returning empty domain list");
//  	    return new Domain[0];
//  	  }
//  	if ( domain._non_existent() ) 
//  	  return new Domain[0];
//  	else return domain.getDomains(obj);
//        }
//      catch (org.omg.CORBA.ORBPackage.InvalidName invalid)
//        {
//  	Debug.output(Debug.DOMAIN | Debug.IMPORTANT, invalid);
//  	return new Domain[0];
//        }
//      catch (org.omg.CORBA.COMM_FAILURE failure)
//        {
//  	Debug.output(Debug.DOMAIN | Debug.IMPORTANT,failure );
//  	return new Domain[0];
//        }
  } // getDomains


  public void updateODMCache(org.omg.CORBA.Object obj, jacorb.orb.domain.Domain[] group)
  {
    theCache.write(obj, group);
  }

  public void invalidateODMCache(org.omg.CORBA.Object obj)
  {
    theCache.remove(obj);
  }

  /** adds the domain aDomain to the list of domains in the cache. */
  public void addToODMCache(org.omg.CORBA.Object obj, jacorb.orb.domain.Domain aDomain)
  {
    theCache.writeAddDomain(obj, aDomain);
  }
  
  /** removes the domain aDomain from the list of domains of obj in the cache. */
  public void removeFromODMCache(org.omg.CORBA.Object obj, jacorb.orb.domain.Domain aDomain)
  {
    theCache.writeRemoveDomain(obj, aDomain);
  }

} // ORBDomainImpl











