// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/Basic.h>
#include <OB/Except.h>
#include <OB/Template.h>
#include <OB/TemplateI.h>
#include <OB/Declarations.h>
#include <OB/Any.h>
#include <OB/TCKind.h>
#include <OB/TypeCode.h>
#include <OB/Environment.h>
#include <OB/Context.h>
#include <OB/IOP.h>
#include <OB/Object.h>
#include <OB/Policy.h>
#include <OB/PolicyManager.h>
#include <OB/OBPolicies.h>
#include <OB/IntRepMember.h>
#include <OB/ORB.h>
#include <OB/ImplRep.h>
#include <OB/BOA.h>
#include <OB/OCI.h>
#include <OB/Util.h>
#include <OB/Net.h> // For windows sockets startup

#include <OCI_impl.h> // For new OCI_ConFactoryRegistry_impl
                      // and OCI_Current_impl

#include <ORBPolicyManager_impl.h> // For new ORBPolicyManager_impl
#include <OBPolicies_impl.h> // For new OB_ConnectionReusePolicy_impl

#include <GIOPClient.h>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>

#ifdef HAVE_NO_STRCASECMP
#   define strncasecmp strincmp
#else
#   ifdef HAVE_STRINGS_H
#       include <strings.h> // On some platforms, strncasecmp is strings.h
#   endif
#endif

//
// The ORB - only one instance is allowed
//
CORBA_ORB_ptr CORBA_ORB::orb_ = CORBA_ORB::_nil();

//
// Whether DII operations should raise system exceptions
//
CORBA_Boolean CORBA_ORB::raiseDIIExceptions_ = false;

//
// The concurrency model
//
CORBA_ORB::ConcModel CORBA_ORB::concModel_ = CORBA_ORB::ConcModelBlocking;

// ----------------------------------------------------------------------
// External, non-inline duplicate/release for templates
// ----------------------------------------------------------------------

void
OBDuplicate(CORBA_ORB_ptr p)
{
    if(p)
	p -> _OB_incRef();
}

void
OBRelease(CORBA_ORB_ptr p)
{
    if(p)
	p -> _OB_decRef();
}

// ----------------------------------------------------------------------
// Template instantiations
// ----------------------------------------------------------------------

#ifndef HAVE_NO_EXPLICIT_TEMPLATES
template class OBObjVar< CORBA_ORB >;
template class OBObjForSeq< CORBA_ORB >;
// template class OBObjSeq< CORBA_ORB >;
// template class OBSeqVar< OBObjSeq< CORBA_ORB > >;

template class OBVarSeq< CORBA_ORB::InitialService >;
#else
#ifdef HAVE_PRAGMA_DEFINE
#pragma define(OBObjVar< CORBA_ORB >)
#pragma define(OBObjForSeq< CORBA_ORB >)
// #pragma define(OBObjSeq< CORBA_ORB >)
// #pragma define(OBSeqVar< OBObjSeq< CORBA_ORB > >)

#pragma define(OBVarSeq< CORBA_ORB::InitialService >)
#endif
#endif

// ----------------------------------------------------------------------
// ORB constructor and destructor
// ----------------------------------------------------------------------

CORBA_ORB::CORBA_ORB()
#ifdef HAVE_JTC
    : dummyForJTC_(0)
#endif
{
#ifdef HAVE_JTC
    //
    // If JTC has not been initialized then create a JTCInitialize object
    //
    if(!JTCInitialize::initialized())
    {
	dummyForJTC_ = new JTCInitialize();
    }
#endif

#ifdef HAVE_WINSOCK_H
    //
    // Winsock startup
    //
    WORD wVersionRequested = MAKEWORD(1, 1);
    WSADATA wsaData;
    if(WSAStartup(wVersionRequested, &wsaData) != 0)
    {
	throw CORBA_COMM_FAILURE(OBLastError(), OBMinorWSAStartup,
				 CORBA_COMPLETED_NO);
    }
#endif

#ifndef WIN32
    //
    // Set SIGPIPE signal handler
    //
    struct sigaction actPIPE;
    actPIPE.sa_handler = SIG_IGN;
    sigemptyset(&actPIPE.sa_mask);
    actPIPE.sa_flags = 0;
    sigaction(SIGPIPE, &actPIPE, 0);
#endif

    //
    // Check if there is already an ORB singleton
    //
    assert(CORBA_is_nil(orb_));

    //
    // Set the ORB singleton to this instance
    //
    orb_ = this;

    //
    // Add the default policies
    //
    CORBA_Policy_var reusePolicy = new OB_ConnectionReusePolicy_impl(true);
    policies_.append(reusePolicy);
    CORBA_Policy_var retryPolicy = new OB_ReconnectPolicy_impl(false);
    policies_.append(retryPolicy);

    //
    // Create the ORBPolicyManager
    //
    CORBA_PolicyManager_var pm = new ORBPolicyManager_impl(policies_);
    _OB_addInitialService("ORBPolicyManager", pm);

    //
    // Add the OCI_Current singleton to the list of initial services
    //
    CORBA_Current_var ociCurrent = OCI_Current_impl::_OB_instance();
    _OB_addInitialService("OCICurrent", ociCurrent);

    //
    // Create the registry
    //
    registry_ = new OCI_ConFactoryRegistry_impl;

    //
    // Initialize the default initial reference "template"
    //
    defaultInitRef_ = CORBA_string_dup("");
}

CORBA_ORB::~CORBA_ORB()
{
    //
    // Destroy all clients
    //
    for(CORBA_ULong i = 0 ; i < clients_.length() ; i++)
	clients_[i] -> destroy();

    //
    // Set ORB singleton to nil
    //
    orb_ = CORBA_ORB::_nil();

#ifdef HAVE_WINSOCK_H
    //
    // Winsock shutdown
    //
    // This is a hack to fix problems with OB/MT. The client threads
    // can still be trying to run at this point, and calling winsock
    // functions after WSACleanup() has been called causes access
    // violations.
    //
    // Of course, this isn't a good fix.  A better fix would be to
    // wait for those threads to exit, via a ThreadGroup, or something
    // similar.
    //
#   ifndef HAVE_JTC
    if(WSACleanup() != 0)
    {
	throw CORBA_COMM_FAILURE(OBLastError(), OBMinorWSACleanup,
				 CORBA_COMPLETED_NO);
    }
#   endif
#endif

#ifndef WIN32
    //
    // Reset SIGPIPE signal handler
    //
    struct sigaction actPIPE;
    actPIPE.sa_handler = SIG_DFL;
    sigemptyset(&actPIPE.sa_mask);
    actPIPE.sa_flags = 0;
    sigaction(SIGPIPE, &actPIPE, 0);
#endif

#ifdef HAVE_JTC
    //
    // Delete the JTCInitialize object if it's been created
    //
    if(dummyForJTC_ != 0)
    {
	delete dummyForJTC_;
    }
#endif
}

// ----------------------------------------------------------------------
// ORB public member implementation
// ----------------------------------------------------------------------

char*
CORBA_ORB::object_to_string(CORBA_Object_ptr p)
{
    IOP_IOR ior;
    
    if(CORBA_is_nil(p))
	ior.type_id = CORBA_string_dup("");
    else
    {
	if(p -> _is_local())
	    connect(p);

	ior = p -> _OB_ior();
    }

    return _OB_IORToString(ior);
}

//
// CORBA_ORB::string_to_object is in INS.cpp
//

CORBA_Status
CORBA_ORB::get_default_context(CORBA_Context_ptr& ctx)
{
    ctx = new CORBA_Context("");
}

CORBA_Status
CORBA_ORB::create_environment(CORBA_Environment_ptr& env)
{
    env = new CORBA_Environment;
}

CORBA_TypeCode_ptr
CORBA_ORB::create_struct_tc(const char* id,
			    const char* name,
			    const CORBA_StructMemberSeq& members)
{
    assert_nca(id, OBNCANullString);
    assert_nca(name, OBNCANullString);

    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_struct;
    tc -> id_ = id;
    tc -> name_ = name;

    tc -> memberNames_.length(members.length());
    tc -> memberTypes_.length(members.length());

    for(CORBA_ULong i = 0 ; i < members.length() ; i++)
    {
	tc -> memberNames_[i] = members[i].name;
	tc -> memberTypes_[i] = members[i].type;
	OBFillRec(tc -> memberTypes_[i].inout(), tc, 1);
    }

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_union_tc(const char* id,
			   const char* name,
			   CORBA_TypeCode_ptr discriminator_type,
			   const CORBA_UnionMemberSeq& members)
{
    assert_nca(id, OBNCANullString);
    assert_nca(name, OBNCANullString);

    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_union;
    tc -> id_ = id;
    tc -> name_ = name;
    tc -> discriminatorType_ = CORBA_TypeCode::_duplicate(discriminator_type);

#ifndef NDEBUG
    CORBA_TypeCode_var tc1 = OBGetOrigType(discriminator_type);
    CORBA_TCKind k = tc1 -> kind();
    
    assert_nca(k == CORBA_tk_short || k == CORBA_tk_ushort ||
 	       k == CORBA_tk_long || k == CORBA_tk_ulong ||
 	       k == CORBA_tk_char || k == CORBA_tk_boolean ||
 	       k == CORBA_tk_enum, OBNCADiscType);
#endif
    
    tc -> labels_.length(members.length());
    tc -> memberNames_.length(members.length());
    tc -> memberTypes_.length(members.length());

    for(CORBA_ULong i = 0 ; i < members.length() ; i++)
    {
#ifndef NDEBUG
	CORBA_TypeCode_var tc2 = members[i].label.type();
 	if(tc2 -> kind() != CORBA_tk_octet)
 	    assert_nca(tc1 -> equal(tc2), OBNCADiscType);
#endif

	tc -> labels_[i] = members[i].label;
	tc -> memberNames_[i] = members[i].name;
	tc -> memberTypes_[i] = members[i].type;
	OBFillRec(tc -> memberTypes_[i].inout(), tc, 1);
    }

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_enum_tc(const char* id,
			  const char* name,
			  const CORBA_EnumMemberSeq& members)
{
    assert_nca(id, OBNCANullString);
    assert_nca(name, OBNCANullString);

    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_enum;
    tc -> id_ = id;
    tc -> name_ = name;

    tc -> memberNames_.length(members.length());

    for(CORBA_ULong i = 0 ; i < members.length() ; i++)
    {
	tc -> memberNames_[i] = members[i];
    }

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_alias_tc(const char* id,
			   const char* name,
			   CORBA_TypeCode_ptr original_type)
{
    assert_nca(id, OBNCANullString);
    assert_nca(name, OBNCANullString);

    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_alias;
    tc -> id_ = id;
    tc -> name_ = name;

    tc -> contentType_ = CORBA_TypeCode::_duplicate(original_type);

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_exception_tc(const char* id,
			       const char* name,
			       const CORBA_StructMemberSeq& members)
{
    assert_nca(id, OBNCANullString);
    assert_nca(name, OBNCANullString);

    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_except;
    tc -> id_ = id;
    tc -> name_ = name;

    tc -> memberNames_.length(members.length());
    tc -> memberTypes_.length(members.length());

    for(CORBA_ULong i = 0 ; i < members.length() ; i++)
    {
	tc -> memberNames_[i] = members[i].name;
	tc -> memberTypes_[i] = members[i].type;
	OBFillRec(tc -> memberTypes_[i].inout(), tc, 1);
    }

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_interface_tc(const char* id,
			       const char* name)
{
    assert_nca(id, OBNCANullString);
    assert_nca(name, OBNCANullString);

    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_objref;
    tc -> id_ = id;
    tc -> name_ = name;

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_string_tc(CORBA_ULong bound)
{
    if(bound == 0)
	return CORBA_TypeCode::_duplicate(CORBA__tc_string);

    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_string;
    tc -> length_ = bound;

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_sequence_tc(CORBA_ULong bound,
			      CORBA_TypeCode_ptr element_type)
{
    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_sequence;
    tc -> length_ = bound;
    tc -> contentType_ = CORBA_TypeCode::_duplicate(element_type);
    tc -> offset_ = 0;

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_recursive_sequence_tc(CORBA_ULong bound,
					CORBA_ULong offset)
{
    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_sequence;
    tc -> length_ = bound;
    tc -> contentType_ = CORBA_TypeCode::_nil();
    tc -> offset_ = offset;

    return tc._retn();
}

CORBA_TypeCode_ptr
CORBA_ORB::create_array_tc(CORBA_ULong length,
			   CORBA_TypeCode_ptr element_type)
{
    CORBA_TypeCode_var tc = new CORBA_TypeCode;
    
    tc -> kind_ = CORBA_tk_array;
    tc -> length_ = length;
    tc -> contentType_ = CORBA_TypeCode::_duplicate(element_type);
    
    return tc._retn();
}

CORBA_ORB::ObjectIdList*
CORBA_ORB::list_initial_services()
{
    ObjectIdList* list = new ObjectIdList;

    for(CORBA_ULong i = 0 ; i < services_.length() ; i++)
	list -> append(services_[i].name);

    return list;
}

CORBA_Object_ptr
CORBA_ORB::resolve_initial_references(const char* identifier)
{
    assert_nca(identifier, OBNCANullString);

    CORBA_Object_var obj;

    //
    // Search the list of initial references
    //
    for(CORBA_ULong i = 0 ; i < services_.length() ; i++)
	if(strcmp(identifier, services_[i].name.in()) == 0)
        {
            if(CORBA_is_nil(services_[i].obj))
            {
                assert(strlen(services_[i].ref.in()) > 0);
                obj = string_to_object(services_[i].ref.in());
                services_[i].obj = CORBA_Object::_duplicate(obj);
            }
            else
                obj = CORBA_Object::_duplicate(services_[i].obj);
            break;
        }

    //
    // If no match was found, and there's a default initial
    // reference "template", then try to compose a URL using
    // the identifier as the object-key
    //
    if(CORBA_is_nil(obj) && strlen(defaultInitRef_) > 0)
    {
        CORBA_String_var url = defaultInitRef_;
        url += '/';
        url += identifier;
        obj = string_to_object(url);
    }

    if(!CORBA_is_nil(obj))
    {
        try
        {
            //
            // If the object is not locality constrained, return a
            // new object with the current set of policies
            // applied.
            //
            return obj -> _set_policy_overrides(policies_,
                                                CORBA_SET_OVERRIDE);
        }
        catch(const CORBA_BAD_OPERATION&)
        {
            //
            // If the object is locality constrained, return the
            // object itself.
            //
            return CORBA_Object::_duplicate(obj);
        }
    }
    
    throw InvalidName();
    return CORBA_Object::_nil(); // Some compilers need this
}

OCI_ConFactoryRegistry_ptr
CORBA_ORB::get_con_factory_registry()
{
    return OCI_ConFactoryRegistry::_duplicate(registry_);
}

//
// CORBA_ORB::get_inet_object is in INS.cpp
//

CORBA_ORB::ConcModel
CORBA_ORB::conc_model()
{
    return concModel_;
}

void
CORBA_ORB::conc_model(CORBA_ORB::ConcModel model)
{
    concModel_ = model;
}

void
CORBA_ORB::connect(CORBA_Object_ptr p)
{
    CORBA_BOA_ptr boa = CORBA_BOA::_OB_instance_nodup();
    if(CORBA_is_nil(boa))
	throw CORBA_INITIALIZE("BOA not initialized");
    
    boa -> connect(p);
}

void
CORBA_ORB::connect(CORBA_Object_ptr p, const char* name)
{
    CORBA_BOA_ptr boa = CORBA_BOA::_OB_instance_nodup();
    if(CORBA_is_nil(boa))
	throw CORBA_INITIALIZE("BOA not initialized");
    
    boa -> connect(p, name);
}

void
CORBA_ORB::disconnect(CORBA_Object_ptr p)
{
    CORBA_BOA_ptr boa = CORBA_BOA::_OB_instance_nodup();
    if(CORBA_is_nil(boa))
	//
	// Calling disconnect() if there is no BOA is not considered a
	// bug, since it is possible that the BOA has already been
	// released with some servants still alive for which
	// disconnect() is called.
	//
	return;
        //throw CORBA_INITIALIZE("BOA not initialized");
    
    boa -> disconnect(p);
}

CORBA_Policy_ptr
CORBA_ORB::create_policy(CORBA_PolicyType policy_type, CORBA_Any& val)
{
    //
    // I wanted a case stmt here, but egcs complains: case label
    // `OB_CONNECTION_REUSE_POLICY' does not reduce to an integer
    // constant
    //
    if(policy_type == OB_CONNECTION_REUSE_POLICY)
    {
	CORBA_Boolean b;
	if(val >>= CORBA_Any::to_boolean(b))
	    return new OB_ConnectionReusePolicy_impl(b);
        throw CORBA_PolicyError(CORBA_BAD_TYPE);
    }
    if(policy_type == OB_PROTOCOL_POLICY)
    {
        OCI_ProfileId tag;
        if(val >>= tag)
            return new OB_ProtocolPolicy_impl(tag);
        throw CORBA_PolicyError(CORBA_BAD_TYPE);
    }
    if(policy_type == OB_RECONNECT_POLICY)
    {
        CORBA_Boolean b;
        if(val >>= CORBA_Any::to_boolean(b))
            return new OB_ReconnectPolicy_impl(b);
        throw CORBA_PolicyError(CORBA_BAD_TYPE);
    }
    if(policy_type == OB_TIMEOUT_POLICY)
    {
        CORBA_ULong t;
        if(val >>= t)
            return new OB_TimeoutPolicy_impl(t);
        throw CORBA_PolicyError(CORBA_BAD_TYPE);
    }
    throw CORBA_PolicyError(CORBA_BAD_POLICY);
    return CORBA_Policy::_nil(); // Some compilers need this.
}

void
CORBA_ORB::add_initial_reference(const char* name, CORBA_Object_ptr obj)
{
    _OB_addInitialService(name, obj);
}

CORBA_ORB_ptr
CORBA_ORB::_OB_instance()
{
    return CORBA_ORB::_duplicate(orb_);
}

CORBA_ORB_ptr
CORBA_ORB::_OB_instance_nodup()
{
    return orb_;
}

char*
CORBA_ORB::_OB_IORToString(const IOP_IOR& ior)
{
    CORBA_ULong count = 0;
    OBMarshalCount(OBEndian, count);
    OBMarshalCount(ior, count);
    
    CORBA_Octet* const buf = new CORBA_Octet[count];
    memset(buf, 0, count);
    
    CORBA_Octet* oct = buf;
    OBMarshal(OBEndian, oct);
    OBMarshal(ior, oct);
    
    CORBA_String_var s = OBOctetsToAscii(buf, count);
    
    delete [] buf;

    static const char* prefix = "IOR:";
    char* result = CORBA_string_alloc(strlen(prefix) + strlen(s));
    strcpy(result, prefix);
    strcat(result, s);

    return result;
}

CORBA_Object_ptr
CORBA_ORB::_OB_createObject(const IOP_IOR& ior)
{
    assert_nca(ior.type_id.in(), OBNCANullString);

    //
    // Check for nil object reference
    //
    if(strlen(ior.type_id) == 0 && ior.profiles.length() == 0)
	return CORBA_Object::_nil();

    //
    // If there is a BOA, try to find an implementation object
    //
    CORBA_BOA_ptr boa = CORBA_BOA::_OB_instance_nodup();
    if(!CORBA_is_nil(boa))
    {
	CORBA_Object_var impl = boa -> _OB_find(ior);

	if(!CORBA_is_nil(impl))
	    return impl._retn();
    }
    
    //
    // Create new object, set policies, change object and return
    //
    CORBA_Object_ptr p = new CORBA_Object();
    p -> _OB_policies(policies_);
    _OB_changeObject(p, ior);
    return p;
}

void
CORBA_ORB::_OB_changeObject(CORBA_Object_ptr p, const IOP_IOR& ior)
{
    assert_nca(ior.type_id.in(), OBNCANullString);

    if(strlen(ior.type_id) == 0 && ior.profiles.length() == 0)
	throw CORBA_INV_OBJREF(); // I can't change an object to a nil object

    {
#ifdef HAVE_JTC
	JTCSynchronized synchronized(clientsMutex_);
#endif

	OCI_ObjectKey_var key;
	OBClient_var clt;
	
	//
	// Find reuse policy among policies
	//
	const CORBA_PolicyList& policies = p -> _OB_policies();
	OB_ConnectionReusePolicy_var reusePolicy;
	for(CORBA_ULong i = 0; i < policies.length(); i++)
	    if(policies[i] -> policy_type() == OB_CONNECTION_REUSE_POLICY)
		reusePolicy = OB_ConnectionReusePolicy::_narrow(policies[i]);
	
	if(CORBA_is_nil(reusePolicy) || reusePolicy -> value())
	{
	    //
	    // Try to reuse clients
	    //
	    for(CORBA_ULong i = 0 ; i < clients_.length() ; i++)
	    {
		//
		// Check reuse flag
		//
		if(clients_[i] -> reuseClient())
		{
		    OCI_Connector_var connector = clients_[i] -> connector();
		    key = connector -> is_usable_with_policies(ior, policies);
		    if(key -> length() > 0)
			clt = OBClient::_duplicate(clients_[i]);
		}
	    }
	}
	
	if(CORBA_is_nil(clt))
	{
	    //
	    // Create a new connector
	    //
	    OCI_ConFactory_var factory =
		registry_ -> get_factory_with_policies(ior, policies);
	    if(CORBA_is_nil(factory))
		throw CORBA_NO_RESOURCES();
	    OCI_Connector_var connector =
		factory -> create_with_policies(ior, policies);
	    key = connector -> is_usable_with_policies(ior, policies);
	    assert(key -> length() > 0);
	    
	    //
	    // Create a new client
	    //
	    clt = new OBGIOPClient(connector);
	    clients_.append(clt);
	    if(!CORBA_is_nil(reusePolicy) && !reusePolicy -> value())
		clt -> reuseClient(false);
	}

	assert(!CORBA_is_nil(clt));
	
	//
	// Setup the object
	//
	p -> _OB_client(clt);
	p -> _OB_ior(ior);
	p -> _OB_key(key); // Must be last, as the other operations
	                   // invalidate the key
    }
}

void
CORBA_ORB::_OB_incClientUsage(OBClient_ptr client)
{
#ifdef HAVE_JTC
    JTCSynchronized synchronized(clientsMutex_);
#endif

    client -> incUsage();
}

void
CORBA_ORB::_OB_decClientUsage(OBClient_ptr client)
{
#ifdef HAVE_JTC
    JTCSynchronized synchronized(clientsMutex_);
#endif

    bool inUse = client -> decUsage();

    if(!inUse)
    {
	for(CORBA_ULong i = 0 ; i < clients_.length() ; i++)
	    if(clients_[i].in() == client)
	    {
		client -> destroy();
		clients_.remove(i);
		return;
	    }
	
	assert(false);
    }
}

CORBA_Boolean
CORBA_ORB::_OB_equivalent(const IOP_IOR& ior1, const IOP_IOR& ior2)
{
    return registry_ -> equivalent(ior1, ior2);
}

CORBA_ULong
CORBA_ORB::_OB_hash(const IOP_IOR& ior, CORBA_ULong maximum)
{
    return registry_ -> hash(ior, maximum);
}

void
CORBA_ORB::_OB_addInitialService(const char* name, const char* iorString)
{
    assert_nca(name, OBNCANullString);
    assert_nca(iorString, OBNCANullString);

    for(CORBA_ULong i = 0 ; i < services_.length() ; i++)
    {
	if(strcmp(name, services_[i].name) == 0)
	{
	    services_[i].ref = iorString;
	    services_[i].obj = CORBA_Object::_nil();

	    OBMessageViewer* viewer = OBMessageViewer::instance();
	    CORBA_String_var str =
		CORBA_string_dup("ORB_init: initial service `");
	    str += name;
	    str += "' was overridden";
	    viewer -> warning(str);

	    return;
	}
    }

    CORBA_ORB::InitialService newService;
    newService.name = name;
    newService.ref = iorString;
    services_.append(newService);
}

void
CORBA_ORB::_OB_addInitialService(const char* name, CORBA_Object_ptr p)
{
    assert_nca(name, OBNCANullString);

    for(CORBA_ULong i = 0 ; i < services_.length() ; i++)
    {
	if(strcmp(name, services_[i].name) == 0)
	{
            services_[i].ref = CORBA_string_dup("");
            services_[i].obj = CORBA_Object::_duplicate(p);

	    OBMessageViewer* viewer = OBMessageViewer::instance();
	    CORBA_String_var str =
                CORBA_string_dup("ORB_init: initial service `");
	    str += name;
	    str += "' was overridden";
	    viewer -> warning(str);

	    return;
	}
    }

    CORBA_ORB::InitialService newService;
    newService.name = name;
    newService.ref = CORBA_string_dup("");
    newService.obj = CORBA_Object::_duplicate(p);
    services_.append(newService);
}

CORBA_Boolean
CORBA_ORB::_OB_raiseDIIExceptions()
{
    return raiseDIIExceptions_;
}

// ----------------------------------------------------------------------
// ORB Initialization
// ----------------------------------------------------------------------

/* See IIOPInit.cpp */
