// Filename   :	server.cpp
// Written By : Stephen Cerniglia

// Usage: server
//
//        On startup, the object reference is registered with the 
//        COS naming service. The client uses the naming service to
//        locate this object.
//
//        The name to which the object is bound is as follows:
//              root     [context]
//               |
//              test     [context] kind [my_context]
//               |
//          FrontOffice  [object]  kind [Object]
//

#include "front.h"
#include "omnithread.h"
#include <iostream.h>

#include "front_impl.cpp"

static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr,CORBA::Object_ptr);

int main(int argc, char *argv[]) {
  // These initialize the ORB required stuff

  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  cout << "Server initializing." << endl;

  // Front office as seen on page 31.
  FrontOffice_impl myFrontOffice("Royal", 25, 40, 'G', 5.00, 3.00);
  myFrontOffice._obj_is_ready(boa);

  {
    FrontOffice_var myobjRef = myFrontOffice._this();
    if (!bindObjectToName(orb,myobjRef)) {
      return 1;
    }
  }

  // Tell the BOA we are ready. The BOA's default behaviour is to block
  // on this call indefinitely.
  boa->impl_is_ready();
  
  return 0;
}


// I took this directly from the echo example that came with OmniORB
static
CORBA::Boolean
bindObjectToName(CORBA::ORB_ptr orb,CORBA::Object_ptr obj)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var initServ;
    initServ = orb->resolve_initial_references("NameService");

    // Narrow the object returned by resolve_initial_references()
    // to a CosNaming::NamingContext object:
    rootContext = CosNaming::NamingContext::_narrow(initServ);
    if (CORBA::is_nil(rootContext)) 
      {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    cerr << "Service required is invalid [does not exist]." << endl;
    return 0;
  }


  try {
    // Bind a context called "test" to the root context:

    CosNaming::Name contextName;
    contextName.length(1);
    contextName[0].id   = (const char*) "test";    // string copied
    contextName[0].kind = (const char*) "my_context"; // string copied    
    // Note on kind: The kind field is used to indicate the type
    // of the object. This is to avoid conventions such as that used
    // by files (name.type -- e.g. test.ps = postscript etc.)

    CosNaming::NamingContext_var testContext;
    try {
      // Bind the context to root, and assign testContext to it:
      testContext = rootContext->bind_new_context(contextName);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      // If the context already exists, this exception will be raised.
      // In this case, just resolve the name and assign testContext
      // to the object returned:
      CORBA::Object_var tmpobj;
      tmpobj = rootContext->resolve(contextName);
      testContext = CosNaming::NamingContext::_narrow(tmpobj);
      if (CORBA::is_nil(testContext)) {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
    } 

    // Bind the object (obj) to testContext, naming it FrontOffice;
    CosNaming::Name objectName;
    objectName.length(1);
    objectName[0].id   = (const char*) "FrontOffice";   // string copied
    objectName[0].kind = (const char*) "Object"; // string copied


    // Bind obj with name FrontOffice to the testContext:
    try {
      testContext->bind(objectName,obj);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      testContext->rebind(objectName,obj);
    }
    // Note: Using rebind() will overwrite any Object previously bound 
    //       to /test/FrontOffice with obj.
    //       Alternatively, bind() can be used, which will raise a
    //       CosNaming::NamingContext::AlreadyBound exception if the name
    //       supplied is already bound to an object.

    // Amendment: When using OrbixNames, it is necessary to first try bind
    // and then rebind, as rebind on its own will throw a NotFoundexception if
    // the Name has not already been bound. [This is incorrect behaviour -
    // it should just bind].
  }
  catch (CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "naming service." << endl;
    return 0;
  }
  catch (omniORB::fatalException& ex) {
    throw;
  }
  catch (...) {
    cerr << "Caught a system exception while using the naming service."<< endl;
    return 0;
  }
  return 1;
}
