package jacorb.orb;

/*
 *        JacORB  - a free Java ORB
 *
 *   Copyright (C) 1997-2000  Gerald Brose.
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library 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
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

import java.util.*;
import java.io.*;  
import java.applet.Applet;
import java.lang.reflect.Constructor;

import jacorb.imr.*;
import jacorb.util.*;
import jacorb.orb.domain.DomainFactory;
import jacorb.orb.portableInterceptor.*;

import org.omg.CORBA.TypeCode;
import org.omg.CORBA.BooleanHolder;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.PortableInterceptor.*;
import org.omg.IOP.*;

/**
 * @author Gerald Brose, FU Berlin
 * @version $Id: ORB.java,v 1.121 2000/11/04 12:55:52 brose Exp $
 */

public final class ORB
    extends ORBSingleton
    implements jacorb.poa.POAListener
{
    /** "initial" references */
    private Hashtable initial_references = new Hashtable();

    private jacorb.poa.POA rootpoa;
    private jacorb.poa.Current poaCurrent;
    private BasicAdapter basicAdapter;
    private Current current;
    private org.omg.SecurityLevel2.Current securityCurrent = null;

    /** interceptor handling */
    private InterceptorManager interceptor_manager = null;
  
    /** reference caching */
    private Hashtable knownReferences = null;

    /** connection mgmt. */
    private ConnectionManager connectionManager;

    /** buffer mgmt. */
    private BufferManager bufferManager = new BufferManager();

    /** properties */ 
    private java.util.Properties _props;

    /** command like args */
    public String[] _args;
        
    // devik: default IIOP version used to generate IORs
    protected org.omg.IIOP.Version IIOPVersion = 
        new org.omg.IIOP.Version((byte)1,(byte)1);

    public  java.applet.Applet applet;

    /* for run() and shutdown()  */
    private Object orb_synch = new java.lang.Object();
    private boolean run = true;
    private boolean wait = true;
    private boolean shutdown_in_progress = false;
    private boolean destroyed = false;
    private Object shutdown_synch = new Object();

    /** synchroniziation for orb domain creation */ 
    private static boolean ORBDomainCreationInProgress = false;
  
    /* for registering POAs with the ImR */
    private Registration imr = null;
    private ImRInfo imr_info = null;
    private int persistentPOACount;

    public static String orb_id = "jacorb:1.0";

    /* policy factories, from portable interceptor spec */
    private Hashtable policy_factories = null;

    private static org.omg.CORBA.TCKind kind;

    public ORB()
    {
       connectionManager  = new ConnectionManager(this);
       
       try
       {
           knownReferences = (Hashtable) Class.forName( Environment.getProperty( "jacorb.hashtable_class" )).newInstance();
       }
       catch( Exception e )
       {
           Debug.output( Debug.INFORMATION | Debug.ORB_MISC, e );
           knownReferences = new Hashtable();
       }
    }


    /** this version of _getObject is used for references that have arrived over the
        network and is called from CDRInputStream. It removes stale cache entries */

    synchronized org.omg.CORBA.Object _getObject(ParsedIOR pior)
    {
        String key = pior.getIORString();
        org.omg.CORBA.portable.ObjectImpl o = 
            (org.omg.CORBA.portable.ObjectImpl)knownReferences.get( key );

        if( o != null )
        {
            Debug.output(5,"Found a reference for key " + key + " in cache ");
            jacorb.orb.Delegate del = (jacorb.orb.Delegate) o._get_delegate();
            if (del != null)
            {
                ParsedIOR delpior= del.getParsedIOR();
                if (delpior == null)
                {
                    knownReferences.remove(key);
                    Debug.output(4,"Removing an invalid reference from cache.");
                }
                else if( pior.getAddress().equals(delpior.getAddress()))
                {
                    return o._duplicate();
                }
            }
            else
            {           
                Debug.output(3,"remove stale reference for key " + 
                                         key + " from cache ");
                knownReferences.remove( key );
            }
        }
        
        jacorb.orb.Delegate d = new Delegate(this, pior );
        o = d.getReference(null);
        if( Environment.cacheReferences() )
        {
            Debug.output(5,"Caching reference for key " + key);
            knownReferences.put( key, o );
        }
        return o;
    }

    public BufferManager getBufferManager()
    {
        return bufferManager;
    }

    public ConnectionManager getConnectionManager()
    {
        return connectionManager;
    }
    

//      void _release( org.omg.CORBA.Object o )
//      {
//          String key = ((jacorb.orb.Delegate)((org.omg.CORBA.portable.ObjectImpl)o)._get_delegate()).pior.getIORString() ;
//          knownReferences.remove( key );
//      }

    synchronized void _release( jacorb.orb.Delegate delegate )
    {
        knownReferences.remove( delegate.pior.getIORString() );
    }


    /**
     * This method creates a policy with the given type
     * and the given value. A PolicyFactory for the type
     * has to be present. PolicyFactories can be registered using
     * the ORBInitializer mechanism.
     *
     * @param type The policies type.
     * @param value The policies value.
     * @exception org.omg.CORBA.PolicyError There is no PolicyFactory for the 
     * given type or the policy creation failed.
     */
    public org.omg.CORBA.Policy create_policy(int type, org.omg.CORBA.Any value)
        throws org.omg.CORBA.PolicyError
    {
        Integer key = new Integer(type);
        if ((policy_factories == null) || (! policy_factories.containsKey(key)))
            throw new org.omg.CORBA.PolicyError();

        PolicyFactory factory = (PolicyFactory) policy_factories.get(key);
    
        return factory.create_policy(type, value);
    }
    

    /**
     * Tests, if a policy factory is present for the given type.
     * This method is (right now) only called by the Info-Objects
     * of the portableInterceptor implementation to avoid running
     * into exceptions.
     */

    public boolean hasPolicyFactoryForType(int type)
    {
        return (policy_factories != null) && 
            policy_factories.containsKey(new Integer(type));
    }

    public  org.omg.CORBA.ContextList create_context_list()
    {
        return null;
    }

    public  org.omg.CORBA.Environment create_environment()
    {
        return null;
    }

    public org.omg.CORBA.portable.OutputStream create_output_stream()
    {
        return new CDROutputStream(this);
    }

    public TypeCode create_struct_tc(String id, 
                                     String name, org.omg.CORBA.StructMember[] members)
    {
        jacorb.orb.TypeCode tc = new jacorb.orb.TypeCode(org.omg.CORBA.TCKind._tk_struct,id,name,members);
        tc.resolve_recursion(0, tc);
        return tc;
    }

    public TypeCode create_union_tc(String id, 
                                    String name, TypeCode discriminator_type, 
                                    org.omg.CORBA.UnionMember[] members)
    {
        return new
            jacorb.orb.TypeCode(org.omg.CORBA.TCKind._tk_union,id,name,discriminator_type,members);
    }

    public TypeCode create_wstring_tc(int bound)
    {
        return new jacorb.orb.TypeCode(org.omg.CORBA.TCKind._tk_wstring,bound);
    }



    /**
     * Called by the POA. 
     * Generates IOR 1.0 and 1.1, 1.1 contains also 1.0 profile. Only 1.1 and 
     * greater profiles contain codeset information about this server. <br>
     * If present, IORInterceptors will be invoked.
     */

    protected org.omg.IOP.IOR createIOR( String repId, 
                                         byte[] key, 
                                         boolean _transient, 
                                         jacorb.poa.POA poa )
    {
        boolean endianness = false;
        jacorb.orb.CDROutputStream profileDataStream;
        
        // up to two profiles will be written
        TaggedProfile[] tps = null;
        String address = basicAdapter.getAddress();
        int port = basicAdapter.getPort();

        if( !_transient && Environment.useImR() )
        {
            try
            {
                if (imr == null)
                {
                    // we're first to consult ImR
                    ImplementationRepository _imr_impl = ImplementationRepositoryImpl.getImR(this);
                    imr = RegistrationHelper.narrow(_imr_impl);
                }

                if (imr_info == null)
                {
                    // we're first to get ImRInfo
                    imr_info = imr.get_imr_info();
                }
                
                // set host and port to ImR's values
                address = imr_info.host;
                port =  imr_info.port;
                Debug.output(2,"New persistent IOR created with ImR at " + 
                                         address + ":" + port );
                
            }
            catch (Exception _e)
            {
                Debug.output(6, _e);
                // sth went wrong,  host and port values of this ORB as set above are use
            }
        }

        // additional multiple tagged components profile, used often for codeset
        // information ( bnv plus the SSL tagged component.)
        boolean useMulti = Environment.charsetUpdateMulti();

        TaggedComponent[] components = null;

        Vector components_iiop_profile = new Vector();
        Vector components_multi_profile = new Vector();

        //if IORInterceptors are present, invoke them
        if ((interceptor_manager != null) &&
            interceptor_manager.hasIORInterceptors()){

            IORInfoImpl info = new IORInfoImpl(this, poa, components_iiop_profile,
                                               components_multi_profile);
            try{
                interceptor_manager.getIORIterator().iterate(info);
            }catch (Exception e){
                Debug.output(2, e);
            }
        }

        //all components for the profiles have to be present by now.
        switch( IIOPVersion.minor )
        {
        case 1: // create 1.1 profile  
            components = new TaggedComponent[components_iiop_profile.size()];
            for( int i = 0; i < components_iiop_profile.size(); i++)
                components[i] = (TaggedComponent)components_iiop_profile.elementAt(i);
              
            org.omg.IIOP.ProfileBody_1_1 pb1 = 
                new org.omg.IIOP.ProfileBody_1_1(IIOPVersion, address, (short)port, 
                                                 key, components);
                
            // serialize the profile id 1, leave idx 0 for v.1.0 profile
            profileDataStream = new jacorb.orb.CDROutputStream(this);
            profileDataStream.write_boolean(endianness);
            org.omg.IIOP.ProfileBody_1_1Helper.write( profileDataStream, pb1);
            tps = new TaggedProfile[useMulti ? 3:2];
            tps[1] = new TaggedProfile(TAG_INTERNET_IOP.value, 
                                       profileDataStream.getBufferCopy());
            // fall thru
        case 0: // create 1.0 profile
            org.omg.IIOP.ProfileBody_1_0 pb0;
            pb0 = new org.omg.IIOP.ProfileBody_1_0(new org.omg.IIOP.Version((byte)1,(byte)0),
                                                   address,(short)port,key);

            // serialize the profile id 1, leave idx 0 for v.1.0 profile
            profileDataStream = new jacorb.orb.CDROutputStream(this);
            profileDataStream.write_boolean(endianness);
            org.omg.IIOP.ProfileBody_1_0Helper.write( profileDataStream, pb0);
            if (tps == null) 
                tps = new TaggedProfile[useMulti ? 2:1];

            tps[0] = new TaggedProfile(TAG_INTERNET_IOP.value, 
                                       profileDataStream.getBufferCopy());

            // now optionally fill the last IOR profile with multicomponent
            if(useMulti)
            {
                components = new TaggedComponent[components_multi_profile.size()];
                for( int i = 0; i < components_multi_profile.size(); i++)
                    components[i] = (TaggedComponent)components_multi_profile.elementAt(i);

                profileDataStream = new jacorb.orb.CDROutputStream(this);
                profileDataStream.write_boolean(endianness);
                MultipleComponentProfileHelper.write(profileDataStream, components);
                tps[tps.length-1] = new TaggedProfile(TAG_MULTIPLE_COMPONENTS.value,
                                                      profileDataStream.getBufferCopy());
            }      
        }
        
        IOR _ior = new IOR( repId, tps);

        if ( isApplet() ) 
        {
            try
            {
                jacorb.orb.CDROutputStream out = 
                    new jacorb.orb.CDROutputStream(this);

                out.write_boolean(endianness);
                org.omg.IOP.IORHelper.write(out, _ior);
                byte bytes[] = out.getBufferCopy();

                StringBuffer sb = new StringBuffer("IOR:");
                for ( int i=0; i<bytes.length; i++ )
                {
                    int b = bytes[i];
                    if( b<0 ) b+= 256;
                    int n1 = (b & 0xff) / 16;
                    int n2 = (b & 0xff) % 16;
                    int c1 = (n1 < 10) ? ('0' + n1) : ('a' + (n1 - 10));
                    int c2 = (n2 < 10) ? ('0' + n2) : ('a' + (n2 - 10));
                    sb.append((char)c1);
                    sb.append((char)c2);
                }
                String ior_str = sb.toString();

                // if applet, return proxified IOR
        
                Debug.output(4,"ORB.createIOR, proxifying original ior " +
                                         _ior.hashCode());

//                  org.omg.CORBA.StringHolder proxyEntryId = 
//                      new org.omg.CORBA.StringHolder();

//                  org.omg.IOP.IOR proxy_ior = 
//                      new ParsedIOR( proxyObj.forward(ior_str,proxyEntryId)).getIOR();

//                  String proxy_ior_str = 
//                      new ParsedIOR( proxyObj.forward(ior_str,proxyEntryId)).getIORString();

//                  proxyEntries.addElement(proxyEntryId.value);
//                  unproxyTable.put( proxy_ior_str, (new ParsedIOR(_ior)).getIORString() );

//                  Debug.output(4,"ORB.createIOR, returning proxifyed ior " + 
//                                           proxy_ior.hashCode());

//                  return proxy_ior;

                org.omg.IOP.IOR proxyfied_ior = getConnectionManager().proxyfy(ior_str);

            } 
            catch ( Exception e ) 
            {
                e.printStackTrace(); return null;
            }


        }
        return _ior;
    }

    /** 
     *  called by Delegate to retrieve an unproxyified, local IOR 
     */

    org.omg.IOP.IOR unproxyfy(org.omg.IOP.IOR proxy_ior)
    {
        return getConnectionManager().unproxyfy(proxy_ior);
    }

    public org.omg.CORBA.Current get_current()
    {
        return current;
    }

    public  org.omg.CORBA.Context get_default_context()
    {
        return null;
    }

    public org.omg.CORBA.Request get_next_response()
    {
        return null;
    }

    /**
     * used from the POA
     * @returns the basic adapter used by this ORB instance
     */

    public jacorb.orb.BasicAdapter getBasicAdapter()
    {
        if( basicAdapter == null )
            throw new RuntimeException("Adapters not initialized, call POA.init() first");
        return basicAdapter;
    }

    public String getDefaultContextURLString()
    {
        if( applet == null )
            return Environment.rootNsURL();
        else
            return applet.getCodeBase().toString() + "_JacORB_NS";
    }

    /** 
     * getPOACurrent
     */

    public jacorb.poa.Current getPOACurrent()
    {
        if (poaCurrent == null)
        {
            poaCurrent = jacorb.poa.Current._Current_init();
        }
        return poaCurrent;
    }

    /** 
     * getReference
     * called by POA 
     */

    public org.omg.CORBA.Object getReference(jacorb.poa.POA poa, 
                                             byte[] object_key, 
                                             String rep_id, 
                                             boolean _transient,
					     BooleanHolder wasCached) // out parameter
    {
        try 
        {
            if( rep_id == null )
                rep_id = "IDL:org.omg/CORBA/Object:1.0";

            org.omg.IOP.IOR ior = createIOR( rep_id, object_key, _transient, poa );
            Delegate d = new Delegate(this, ior);
            org.omg.CORBA.Object o = d.getReference(poa);

            ParsedIOR pior = new ParsedIOR( ior );
        
            org.omg.CORBA.Object cachedReference= 
                (org.omg.CORBA.Object) knownReferences.get(pior.getIORString());
            if ( cachedReference != null ) 
            {
                Debug.output(Debug.ORB_MISC | 5, "ORB.getReference: returning cashed reference");
                wasCached.value= true;
                return cachedReference._duplicate();
            }
            // else cachedReference == null
            if( Environment.cacheReferences() )
            {   
                knownReferences.put( pior.getIORString(), o );
            }
	    wasCached.value= false;
            return o;
        } 
        catch ( Exception e )
        {
            e.printStackTrace();
        }
        return null;
    }

    public jacorb.poa.POA getRootPOA()
    {
        if (rootpoa == null) 
        {
            rootpoa = jacorb.poa.POA._POA_init(this);
            rootpoa._addPOAEventListener( this );
            basicAdapter = new BasicAdapter( this, rootpoa );
        }
        return rootpoa;
    }


    /** 
     * @returns - true if ORB is initialized by an applet and 
     * apopligator use is switched on
     */

    public boolean isApplet()
    {
        return applet != null;
        //        return applet != null && Environment.useAppligator();
    }


    Applet getApplet()
    {
        return applet;
    }

    public String[] list_initial_services()
    {
        String s[] = {"NameService", "TradingService","RootPOA","POACurrent",
                      "DynAnyFactory", "DomainService", "LocalDomainService", 
                      "PICurrent", "CodecFactory", "TransactionCurrent"};
        return s;
    }

    /** 
     * An operation from the POAListener interface. Whenever a new POA is
     * created, the ORB is notified. 
     */

    public void poaCreated(jacorb.poa.POA poa)
    {
        /* 
         * Add this orb as the child poa's event listener. This means that the
         * ORB is always a listener to all poa events!
         */
        poa._addPOAEventListener(this);


        /* If the new POA has a persistent lifetime policy, it is registered
         * with the implementation repository if there is one and the 
         * use_imr policy is set via the "jacorb.orb.use_imr" property
         */

        if( poa.isPersistent())
        {
            persistentPOACount++;

            /* Lookup the implementation repository */

            if (imr == null && Environment.useImR() )
            {
                ImplementationRepository _imr_impl = ImplementationRepositoryImpl.getImR(this);
                imr = RegistrationHelper.narrow(_imr_impl);
                if (imr == null || imr._non_existent())
                {
                    Debug.output(3, "No connection to ImplementationRepository");
                    return;
                }
            }

            if( imr != null )
            {
                try
                {
                    /* Register the POA  */
                    String server_name = new String(Environment.implName());
                    imr.register_poa(server_name + "/" + poa._getQualifiedName(), 
                                     server_name, // logical server name
                                     basicAdapter.getAddress(),
                                     basicAdapter.getPort());
                }
                catch (org.omg.CORBA.UserException user_ex){
                    Debug.output(1, user_ex);
                }           
                catch (Exception _e)
                {
                    Debug.output(4, _e);
                }
            }
        }
    }



    public void poaStateChanged(jacorb.poa.POA poa, int new_state)
    {
        if( ( new_state == jacorb.poa.POAConstants.DESTROYED ||
              new_state == jacorb.poa.POAConstants.INACTIVE )  && 
            poa.isPersistent() && imr != null
            )
        {
            /* if all persistent POAs in this server have gone down, unregister
               the server */
            if( --persistentPOACount == 0 )
            {
                try
                {
                    imr.set_server_down(new String(Environment.implName()));
                }
                catch (Exception _e)
                {
                    Debug.output(2, _e);
                }
            }
        }
    }

    public  boolean poll_next_response()
    {
        return false;
    }


    public void referenceCreated(org.omg.CORBA.Object o)
    {}

    public boolean get_service_information(short service_type,
                                           org.omg.CORBA.ServiceInformationHolder service_information) 
    {
//          if (( service_type == org.omg.CORBA.Security.value ) && Environment.supportSSL ())
//          {
//              byte options[] = new byte [5]; // ServiceOption[]
//              options[0] = (byte)org.omg.Security.SecurityLevel1.value;
//              options[1] = (byte)org.omg.Security.SecurityLevel2.value;
//              options[2] = (byte)org.omg.Security.ReplaceORBServices.value;
//              options[3] = (byte)org.omg.Security.ReplaceSecurityServices.value;
//              options[4] = (byte)org.omg.Security.CommonInteroperabilityLevel0.value;
//              org.omg.CORBA.ServiceDetail details[] = new org.omg.CORBA.ServiceDetail [2];
//              details[0].service_detail_type = org.omg.Security.SecureTransportType.value;
//              details[0].service_detail = jacorb.security.ssl.SSLSetup.getMechanismType().getBytes();
//              details[1].service_detail_type = org.omg.Security.SecureTransportType.value;
//              details[1].service_detail = "001010011".getBytes(); // AuditId, _PublicId, AccessId
//              return true;
//          }
//          else return false;
        return false;
    }
    
    /**
     * resolve_initial_references
     */

    public org.omg.CORBA.Object resolve_initial_references(String identifier) 
        throws org.omg.CORBA.ORBPackage.InvalidName 
    {
        if ( isApplet() )
        {
            getConnectionManager().initProxy();         
        }

        if ( initial_references.containsKey(identifier) )
        {
            return (org.omg.CORBA.Object) initial_references.get(identifier);
        }
        else
        {
            //Debug.output(2, ">>" + identifier + "<< not set yet");
            org.omg.CORBA.Object obj = null;

            //        if( identifier.equals("InterfaceRepository") )
            //          obj = jacorb.orb.ir.Repository.getRepository();      
            //        else 
            if( identifier.equals("NameService") )
            {
                String ior_str = null;
                String nsURL   = jacorb.util.Environment.rootNsURL();

                if (nsURL == null) 
                {
                    // try to get location of URL with ns's IOR from a file
                    //     called NameService.ior at the applet's host
                    ior_str = jacorb.util.ObjectUtil.readURL("http://"
                                                             + applet.getCodeBase().getHost()
                                                             + "/"
                                                             + "NameService.ior");
                }
                else if (nsURL.indexOf(":",4) < 0) 
                {
                    // no http: nor file:
                    // try to get location of URL with proxy's IOR from a file
                    // at applet's host
                    ior_str = jacorb.util.ObjectUtil.readURL("http://"
                                  + applet.getCodeBase().getHost()
                                  + "/"
                                  + nsURL);
                }
                else 
                {
                    // use defined nsURL
                    ior_str = jacorb.util.ObjectUtil.readURL(nsURL);
                }
                obj = org.omg.CosNaming.NamingContextHelper.narrow(this.string_to_object(ior_str));
            }
            else if( identifier.equals("TradingService") )
            {
                String trader_ior = ObjectUtil.
                    readURL(Environment.tradingServiceURL());
                obj = org.omg.CosTrading.TraderComponentsHelper.
                    narrow(this.string_to_object(trader_ior));
            } 
            else if( identifier.equals("RootPOA") )
                return (org.omg.CORBA.Object)getRootPOA();

            else if( identifier.equals("POACurrent") )
                return (org.omg.CORBA.Object)getPOACurrent();
      
            else if( identifier.equals("DomainService") )
            { 
                if ( ! Environment.useDomain() ) 
                    throw new org.omg.CORBA.ORBPackage.InvalidName
                        ("domain service is not configured for usage. To configure domain service"
                         +" set property \"jacorb.use_domain\" to \"on\".");

                // retrieve reference to global domain server
                String ds_ior = ObjectUtil.readURL
                    (Environment.DomainServiceURL());

                obj = jacorb.orb.domain.DomainHelper.narrow
                    (this.string_to_object(ds_ior));

            }
            else if( identifier.equals("LocalDomainService") )
            { 
                if ( ! Environment.useDomain() ) 
                    throw new org.omg.CORBA.ORBPackage.InvalidName(
                                                                   "domain service is not configured for usage."
                                                                   +" To configure domain service set property \"jacorb.use_domain\" to \"on\".");
          
                // make a new orb specific and therefore local instance of a domain called "orb domain"
                jacorb.orb.domain.ORBDomain orb_domain= null;

		// recursion end: at orb domain creation the orb domain itself wants to be mapped
		// by the poa to some domain(s). The poa calls this part of resolve_initial_references
		// again to obtain the orb domain. The dilemma is, that the orb domain is going to
		// be created and the reference to it will not be available until poa.servant_to_ref
		// returns. The choosen solution to this problem is to return a null refence on the
		// second call. The POA.doInitialMapping knows how to handle this.
		if (ORBDomainCreationInProgress) 
                    throw new  org.omg.CORBA.ORBPackage.InvalidName("second call");

		ORBDomainCreationInProgress= true;
                try 
                {               
                    // policy factory
                    jacorb.orb.domain.PolicyFactoryImpl polFactoryImpl =
                        new jacorb.orb.domain.PolicyFactoryImpl();

                    try 
                    { 
                        getRootPOA().the_POAManager().activate(); 
                    } 
                    catch (org.omg.PortableServer.POAManagerPackage.AdapterInactive e) 
                    { 
                        Debug.output(1, e); 
                    }

                    jacorb.orb.domain.PolicyFactory polFactory =
                        jacorb.orb.domain.PolicyFactoryHelper.narrow(
                                                                     getRootPOA().servant_to_reference(polFactoryImpl));

                    // create policies by the help of the policy factory
                    org.omg.CORBA.Policy policies[]= new org.omg.CORBA.Policy[1];
                    policies[0]= polFactory.createConflictResolutionPolicy
                        (jacorb.orb.domain.ConflictResolutionPolicy.PARENT_RULES);
              

                    // create domain with the above policies
		    jacorb.orb.domain.ORBDomainImpl impl= 
                        new jacorb.orb.domain.ORBDomainImpl(null, policies, "orb domain");
		    
		    jacorb.orb.domain.ORBDomainPOATie tie= new jacorb.orb.domain.ORBDomainPOATie(impl);
		    impl.setTie(tie);

                    orb_domain = jacorb.orb.domain.ORBDomainHelper.narrow
                        (getRootPOA().servant_to_reference(tie));

                    obj = orb_domain;

		    ORBDomainCreationInProgress= false;
				
		    orb_domain.insertLocalDomain(orb_domain);

                } 
                catch (org.omg.PortableServer.POAPackage.WrongPolicy wp) 
                {
                    Debug.output(1, "the root poa of this orb has the wrong"
                                             +" policies for \"servant_to_reference\".");
                }
                catch (org.omg.PortableServer.POAPackage.ServantNotActive na) 
                {
                    Debug.output(1, na);
                }

                if (Environment.mountORBDomain() )
                { 
                    initial_references.put(identifier, obj); // to avoid recursive calls
                    this.mountORBDomain();
                }

                String filename= Environment.ORBDomainFilename();

                if ( filename!= null && !filename.equals("") )
                {
                    Debug.output(Debug.DOMAIN | Debug.INFORMATION, 
					     "writing IOR of local domain service to file "+ filename);
                    try 
                    {
                        FileOutputStream out = new FileOutputStream(filename);
                        PrintWriter pw = new PrintWriter(out);
                        pw.println(this.object_to_string(orb_domain));
                        pw.flush();
                        out.close();
                    }
                    catch (IOException e) 
                    {
                        Debug.output(1, "Unable to write IOR to file " + filename);
                    }
                }
            }
            else if( identifier.equals("SecurityCurrent") ) {
                if( securityCurrent == null )
                {
                    try
                    {
                        Class ssl = Class.forName( "jacorb.security.level2.CurrentImpl" );

                        Constructor constr = ssl.getConstructor( new Class[]{
                            org.omg.CORBA.ORB.class });

                        securityCurrent = (org.omg.SecurityLevel2.Current)
                            constr.newInstance( new Object[]{ this });
                    }
                    catch (Exception e)
                    {
                        Debug.output( Debug.IMPORTANT | Debug.ORB_MISC,
                                      e );
                    }

                    obj = securityCurrent;
                }
            }
            else if( identifier.equals("DynAnyFactory") )
            {
                obj = (new jacorb.orb.dynany.DynAnyFactoryImpl( this ))._this();
            }
            else if( identifier.equals("PICurrent") )
            {
                if (interceptor_manager == null)
                    return InterceptorManager.EMPTY_CURRENT;
                else
                    return interceptor_manager.getCurrent();
            }
            else if( identifier.equals("CodecFactory") )
            {
                obj = new CodecFactoryImpl(this);
            }
            else if( identifier.equals("TransactionCurrent") )
                obj = new jacorb.transaction.TransactionCurrentImpl();
            else
                throw new org.omg.CORBA.ORBPackage.InvalidName();
    
            if (obj != null)
            {
                initial_references.put(identifier, obj);
                return obj;
            }
            else
                return null;
        }
    }

    private void initialReferencesInit()
    {
        try
        {
            if( !isApplet() && _args != null )
            {
                for( int i = 0; i < _args.length; i++ )
                {
                    if( _args[i].equals("-ORBInitRef"))
                    {                
                        if( _args[i+1].indexOf("=") == -1 )
                        {
                            throw new InvalidName();
                        }
                        String refName = _args[i+1].substring(0,_args[i+1].indexOf("="));
                        String ior = _args[i+1].substring(_args[i+1].indexOf("=")+1);
                        org.omg.CORBA.Object obj = string_to_object(ior);
                        if( obj != null )
                            register_initial_reference( refName, obj );
                        else
                            Debug.output(1,"Illegal URL : " + ior );
                        i++;
                    }
                }
            }
            Hashtable props = Environment.getProperties( "ORBInitRef." );
            
            for( Enumeration names = props.keys(); names.hasMoreElements(); )
            {
                String name = (String) names.nextElement();
                String key = name.substring( name.indexOf('.')+1);
                register_initial_reference( key, string_to_object( (String)props.get(name) ) );
                Debug.output(3, "ORBInitRef " + key + " string: " + (String)props.get(name));
            }                
        }
        catch( InvalidName in )
        {        
            System.err.println("usage: -ORBInitRef <name>=<Object_URL>");
            System.exit(1);
        }
        catch( Exception e )
        {
            Debug.output( 3, e );
            // System.exit(1);
        }
    }


    /**
     * Register a reference, that will be returned on subsequent calls
     * to resove_initial_references(id). <br>
     * The references "RootPOA", "POACurrent" and "PICurrent" can be set,
     * but will not be resolved with the passed in references.
     *
     * @param id The references human-readable id, e.g. "MyService".
     * @param obj The objects reference.
     * @exception InvalidName A reference with id has already been registered.
     */

    public void register_initial_reference(String id, org.omg.CORBA.Object obj) 
        throws InvalidName 
    {
        if (id == null || id.length() == 0 || initial_references.containsKey(id) )
        {
            throw new InvalidName();
        }
        else
        {
            initial_references.put(id, obj);
        }
    }

    public void run() 
    {   
        Debug.output(4,"ORB run");
        try 
        {
            synchronized( orb_synch )
            {
                while( run  )
                {
                    orb_synch.wait();
                }
            }
        } 
        catch( java.lang.InterruptedException iex )
        {
            iex.printStackTrace();
        }                 
        Debug.output(4,"ORB run, exit");
    }

    public  void send_multiple_requests_deferred(org.omg.CORBA.Request[] req)
    {
    }

    public  void send_multiple_requests_oneway(org.omg.CORBA.Request[] req)
    {
    }

    protected void set_parameters(String[] args, java.util.Properties props)
    {      
        _args = args;
        _props = props;
        Environment.addProperties( props );

        initialReferencesInit();
        interceptorInit();
    }

    protected void set_parameters(java.applet.Applet app, java.util.Properties  props)
    {
        applet = app;
        _props = props;
        Environment.addProperties( props );
        // unproxyTable = new Hashtable();

        initialReferencesInit();
        interceptorInit();
    }

    /**
     * This method retrieves the ORBInitializer-Names from the Environment,
     * and runs them.
     */ 

    private void interceptorInit()
    {
        // get instances from Environment
        Vector orb_initializers = Environment.getORBInitializers();

        if (orb_initializers.size() > 0)
        {
            ORBInitInfoImpl info = new ORBInitInfoImpl(this);

            // call pre_init in ORBInitializers
            for (int i = 0; i < orb_initializers.size(); i++)
            {
                try
                {
                    ORBInitializer init = (ORBInitializer) orb_initializers.elementAt(i);
                    init.pre_init(info);
                }
                catch (Exception e)
                {
                    Debug.output(0, e);
                }
            }
     
            //call post_init on ORBInitializers
            for (int i = 0; i < orb_initializers.size(); i++)
            {
                try
                {
                    ORBInitializer init = (ORBInitializer) orb_initializers.elementAt(i);
                    init.post_init(info);
                }
                catch (Exception e){
                    Debug.output(0, e);
                } 
            }

            //allow no more access to ORBInitInfo from ORBInitializers
            info.setInvalid();

            Vector client_interceptors = info.getClientInterceptors();
            Vector server_interceptors = info.getServerInterceptors();
            Vector ior_intercept = info.getIORInterceptors();

            if ((server_interceptors.size() > 0) || 
                (client_interceptors.size() > 0) ||
                (ior_intercept.size() > 0))
            {
                interceptor_manager = new InterceptorManager(client_interceptors,
                                                             server_interceptors,
                                                             ior_intercept,
                                                             info.getSlotCount(),
                                                             this);

                /**
                 * reinitialize cached references. This is needed
                 * since references that have been created in an
                 * ORBInitializer will have no interceptors called 
                 * on invocation.
                 */
                Enumeration e = knownReferences.elements();

                while(e.hasMoreElements())
                {
                    Reference r = (Reference) e.nextElement();
                    if( r != null )
                        ((Delegate) r._get_delegate()).initInterceptors();
                }
            }
      
            // add PolicyFactories to ORB
            policy_factories = info.getPolicyFactories();     
        }
    }

    public void shutdown( boolean wait_for_completion ) 
    {    
        Debug.output(2,"prepare ORB for going down...");

        synchronized( shutdown_synch )
        {
            Debug.output(2,"ORB going down...");
            if( shutdown_in_progress && wait_for_completion )
            {
                synchronized( shutdown_synch )
                {
                    try
                    {
                        shutdown_synch.wait();
                    }
                    catch( InterruptedException ie )
                    {}
                    Debug.output(2,"ORB shutdown complete (1)");
                    return;
                }
            }   
            else if( shutdown_in_progress && !wait_for_completion )
            {
                Debug.output(2,"ORB shutdown complete (2)");
                return;
            }
            
            shutdown_in_progress = true;
        }

        if( rootpoa != null )
            rootpoa.destroy(true, wait_for_completion); 

        Debug.output(3,"ORB shutdown (cleaning up ORB...)");

        connectionManager.shutdown();
        knownReferences.clear();
        bufferManager.release();

        Debug.output(3,"ORB shutdown (all tables cleared)");

        /* notify all threads waiting for shutdown to complete */

        synchronized( shutdown_synch )
        {
            shutdown_synch.notifyAll();
        }
        Debug.output(3,"ORB shutdown (threads notified)");

        /* notify all threads waiting in orb.run() */
        synchronized( orb_synch )
        {              
            run = false;
            orb_synch.notifyAll();
        }
        Debug.output(2,"ORB shutdown complete");
    }

    public void destroy()
    {
        if( destroyed )
            throw new org.omg.CORBA.OBJECT_NOT_EXIST();

        if( run )
        {
            shutdown( true );
        }
        
        // other clean up possible here ?
        destroyed = true;
    }

    public org.omg.CORBA.Object string_to_object(String str) 
    {
        if( str == null )
            return null;

        ParsedIOR pior = new ParsedIOR( str );
        if( pior.isNull() )
            return null;
        else
        {
            return _getObject(pior);
        }
    }

    public void set_delegate(java.lang.Object wrapper) 
    {
        if( ! (wrapper instanceof org.omg.PortableServer.Servant) )
            throw new org.omg.CORBA.BAD_PARAM("Argument must be of type org.omg.PortableServer.Servant");
        else
        {
            jacorb.orb.ServantDelegate delegate = new jacorb.orb.ServantDelegate(this);
            ((org.omg.PortableServer.Servant)wrapper)._set_delegate(delegate);
        }
    }

    /** 
     * forces the use of a proxy (by using a dummy applet)
     */

    public void useProxy()
    {
        applet = new java.applet.Applet();
    }

    public String object_to_string( org.omg.CORBA.Object obj)
    {
        return obj.toString();
    }

    public void perform_work() 
    {     
    }

    public boolean work_pending() 
    {     
        return false;
    }

    /**
     * Test, if the ORB has ClientRequestInterceptors <br>
     * Called by Delegate.
     */

    public boolean hasClientRequestInterceptors()
    {
        return (interceptor_manager != null) &&
            interceptor_manager.hasClientRequestInterceptors();
    }

    /**
     * Test, if the ORB has ServerRequestInterceptors <br>
     * Called by poa.RequestProcessor.
     */

    public boolean hasServerRequestInterceptors()
    {
        return (interceptor_manager != null) &&
            interceptor_manager.hasServerRequestInterceptors();
    }
  
    /**
     * Get the InterceptorManager, if present.
     *
     * @return the InterceptorManager, or null, if none is present.
     */

    public jacorb.orb.portableInterceptor.InterceptorManager getInterceptorManager()
    {
        return interceptor_manager;
    }

   
    public void mountORBDomain()
    {
        mountORBDomain("orb domain");
    }

    /** inserts the orb domain into the domain server as child domain. 
     *  The orb domain is the domain  returned by 
     *  this.resolve_initial_references("LocalDomainService"). The domain server is the domain 
     *  returned by this.resolve_initial_references("DomainService").
     *  @param orbDomainNameif not null and not empty the orb domain name is set
     *                              to this value
     */
    public void mountORBDomain(String orbDomainName)
    {
        jacorb.orb.domain.Domain domainServer= null;
        jacorb.orb.domain.Domain orb_domain  = null;

        try 
        {   
            domainServer= jacorb.orb.domain.DomainHelper.narrow
                (resolve_initial_references("DomainService"));
        
            orb_domain= jacorb.orb.domain.DomainHelper.narrow
                (resolve_initial_references("LocalDomainService"));

	    // set name of orb domain
	    if (orbDomainName == null || orbDomainName.equals(""))
                orbDomainName= "orb domain";

	    if ( domainServer.hasChild(orb_domain) )
            { 
                // do not insert if already a child of domain server
		// just change name
		Debug.output(2, "ORB.mountORBDomain: rename from \"" + orb_domain.name() 
			     +"\" to \"" + orbDomainName +"\".");
		domainServer.renameChildDomain(orb_domain.name(), orbDomainName);
		orb_domain.name(orbDomainName);
		return;
            }
	    // else first insert: set name of orb domain
	    orb_domain.name(orbDomainName);

            
        }
        catch (org.omg.CORBA.ORBPackage.InvalidName inv) 
        {
            Debug.output(1, inv);
        }
	catch (jacorb.orb.domain.NameAlreadyDefined def)
        { 
            return; 
        }
	catch (jacorb.orb.domain.InvalidName invalid)
        { 
            return; 
        }
	
	int tries= 0;
	while (true) // try until suceeded
        {
	    try 
            { 
		domainServer.insertChild(orb_domain);
		return;
            } 
	    catch (jacorb.orb.domain.GraphNodePackage.ClosesCycle cc) 
            {
		Debug.output(1, cc);
		return;
            }
	    catch (jacorb.orb.domain.NameAlreadyDefined already)
            {
		Debug.output(1, "ORB.mountORBDomain: name "
					 + already.name +  " already used in domain server scope");
		tries++;
		orb_domain.name(orbDomainName + "#"+ Integer.toString(tries) );
            }
        }
    }

}


