package jacorb.orb.domain;

import java.util.Hashtable;

/**
 * MapToTypeDomainsPolicy.java
 * An instance of this classs implements the IDL-interace InitialMapPolicy. The OnReference-
 * Creation operation of this class maps a newly created object reference to its type domain.
 * A type domain contains all object references of a determined idl type. New object references
 * are therefore classified by their type. 
 * <br>
 * Before using an instance of this class, its tie must be set via the "setTie" operation. This
 * is due both to the poa tie object implementation approach of this class and to the need of
 * creating object references (domains). If you don't do this, you will get an 
 * "org.omg.CORBA.BAD_INV_ORDER: The Servant has not been associated with an ORBinstance" 
 * exception.
 *
 * Created: Sat Apr 22 14:10:24 2000
 *
 * @author Herbert Kiefer
 * @version $Revision: 1.5 $
 */

public class MapToTypeDomainsPolicy extends ManagementPolicyImpl
  implements InitialMapPolicyOperations {
  
  /** type id -> domain */
  private Hashtable _typeDomains;

  /** factory to create new type domains */
  private DomainFactory _factory;

  /** the associated tie of an instance of this class */
  private InitialMapPolicyPOATie _tie;

  /** used to indicate that OnReferenceCreation itself is creating a new object and there
   *  calls itself recursively */
  boolean callMyself= false;
  
  public MapToTypeDomainsPolicy() 
  {
    super("initial map");
    String desc= "This object implements the domain initial map policy. The initial map policy"
      +" is used to map a newly created object reference to one or more domains. The strategy "
      +"of this object is to map a new object reference to its type domain. The type domain of"
      +" an object \"obj\" is the domain containing all objects which have the same most "
      +"specific type as \"obj\".";
   long_description(desc);

   // create hashtable
   _typeDomains= new Hashtable();
   
  }
  
  /** maps a newly created object reference to its type domain. */
  public Domain[] OnReferenceCreation(org.omg.CORBA.Object newReference, Domain rootDomain)
  {
    String type= Util.toID( newReference.toString() );
    jacorb.util.Debug.output(2, "type is a " + type);

   //   try { getTie()._poa(); } catch (Exception e) { 
//        jacorb.util.Debug.output(2, " call of _poa failed"); 
//        jacorb.util.Debug.output(2, e);

//      }
  

    Domain domain = (Domain) _typeDomains.get(type);
    if (domain == null) 
      { // new type, create domain for it

	// return empty list to avoid recursive hangup on second call
	if (callMyself) return new Domain[0]; 

	callMyself= true; // indicate object creation which is not mapped to any domain
	domain= _domainFactory().createDomain(null, null, type);
	callMyself= false;
	
	_typeDomains.put(type, domain);

	try 
	  { // insert new domain as child domain into root domain
	    rootDomain.insertChild(domain);
	  }
	catch (jacorb.orb.domain.GraphNodePackage.ClosesCycle cc)
	  {
	    jacorb.util.Debug.output(1, "MapToTypeDomainsPolicy.OnReferenceCreation: cannot "
				     +"insert "+Util.downcast(domain) + " as child domain to "
				     +"root domain " +Util.downcast(rootDomain));
	    jacorb.util.Debug.output(1, cc);
	  }
	catch (jacorb.orb.domain.NameAlreadyDefined already)
	  {
	    jacorb.util.Debug.output(1, "MapToTypeDomainsPolicy.OnReferenceCreation: cannot "
				     +"insert "+Util.downcast(domain) + " as child domain to "
				     +"root domain " +Util.downcast(rootDomain));
	    jacorb.util.Debug.output(1, already);
	  }

      }
    // domain != null
    Domain result[]= new Domain[1];
    result[0]= domain;
    return result;

  } // OnReferenceCreation
  

  /** returns a domain factory. */
  private DomainFactory _domainFactory()
  {
    if (_factory == null)
      { // create domain factory
	try 
	  {
	    DomainFactoryImpl factoryImpl= new DomainFactoryImpl();

	    callMyself= true;
	    _factory = DomainFactoryHelper.narrow(getTie()._poa().servant_to_reference
						  (factoryImpl));
	    callMyself= false;
	  } 
	catch (org.omg.PortableServer.POAPackage.WrongPolicy wp) 
	  {
	    jacorb.util.Debug.output(1, "the poa of this domain(" + this 
				     +") has the wrong policies for \"servant_to_reference\".");
	  }
	catch (Exception e)
	  {
	    jacorb.util.Debug.output(1, e);
	  }
      }
    // factory != null
    return _factory;

  } // _domainFactory

  // tie functions

  /** sets the tie of this object. Because this class uses the poa tie approach to
   *  implement CORBA objects and this class needs to access the poa of
   *  its tie to create new objects, it needs to know its tie. This method sets the tie. 
   *  It must be called from outside after creating the object.
   * @param tie the servant which is used as tie to connect this class to a poa
   */
  public void setTie(InitialMapPolicyPOATie tie) { _tie= tie; }

  /** gets the associated tie of this object. The tie must be set prior to this call.
   * @see jacorb.orb.domain.MapToTypeDomainsPolicy#setTie
   */
  public InitialMapPolicyPOATie getTie() 
  { 
    jacorb.util.Debug.assert(1, _tie != null,"MapToTypeDomainsPolicy.getTie: tie is not set !");
    return _tie; 
  }

  // inherited member functions

 public short strategy()
  { return InitialMapPolicy.TYPE_DOMAINS; } 

  public int policy_type()
    { return INITIAL_MAP_POLICY_ID.value; }

  public org.omg.CORBA.Policy copy() 
  { 
    return getTie()._this();
  }
} // MapToTypeDomainsPolicy











