/*
  server.cpp

  This is the mainline of a Corba server which only can say "Hallo". It uses 
  CosNaming service for presenting the reference to the server object to everybody.

  As a real server application, we need an ORB and a POA and a manager, whow!

  The used naming service is the CosNaming service, so the naming libraries has to be in
  your LD_LIBRARY_PATH, e.g.

  $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORBACUS_HOME/naming/lib

  Preparation: start the CosNaming service on host 'adrasteia' with a command line like

  adrasteia> nameserv -OAport 3674

  Start the applications as follows:

  $ server adrasteia 3674

  Author: Ingo Kloeckl
 */

#include <OB/CORBA.h>
#include <OB/CosNaming.h>
#include <Hallo_impl.h>   // header of famous server object

#include <stdlib.h>
#include <errno.h>
#include <fstream.h>

using namespace std;


int main(int argc, char* argv[], char*[]){
  int status = EXIT_SUCCESS;
  CORBA::ORB_var orb;

  if (argc != 3){
    cout << "Usage: " << argv[0] << " host port" << endl;
    cout << "(<host> and <port> for host where the NameService is running)" << endl;
    return(EXIT_FAILURE);
  }
  char* strHost = argv[1];
  char* strPort = argv[2];

  try {
    // No.1 task - get an ORB and a POA
    // we have to pass to the ORB the following data to allow the location of the CosNaming service:
    // - the port number
    // - the host where the nameserv image runs to the ORB
    // The port number of the service is given at its start time (see above)
    // We therefore create an argv-like array with these options
    char strIOR[100];
    sprintf(strIOR, "NameService=corbaloc:iiop:%s:%s/NameService", strHost, strPort);
    char* orb_options[] = { "-ORBInitRef", strIOR };
    int optc = sizeof(orb_options)/sizeof(char *);
    orb = CORBA::ORB_init(optc, orb_options);
  } catch (const CORBA::SystemException& e){
    cerr << "Error initializing ORB: " << e << endl;
    return EXIT_FAILURE;
  }

  try {
    CORBA::Object_var poaObj = orb->resolve_initial_references("RootPOA");
    if (CORBA::is_nil(poaObj)){
      cerr << "invalid reference to root POA, exiting" << endl;
      return EXIT_FAILURE;
    }
    PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(poaObj);
    if (CORBA::is_nil(rootPOA)){
      cerr << "reference is not a (root) POA, exiting" << endl;
      return EXIT_FAILURE;
    }
    PortableServer::POAManager_var manager = rootPOA->the_POAManager();
    manager->activate();
    cout << "got POA and POAManager" << endl;
  } catch (const CORBA::ORB::InvalidName&) {
    cerr << "Invalid name: RootPOA" << endl;
    return EXIT_FAILURE;
  } catch (const CORBA::SystemException& e){
    cerr << "Error initializing POA: " << e << endl;
    return EXIT_FAILURE;
  }

  CosNaming::NamingContextExt_var root_ctx;
  CosNaming::NamingContext_var my_ctx;
  try {
    // to use the CosNaming service, we have to get a reference to it
    CORBA::Object_var naming;
    naming = orb->resolve_initial_references("NameService");
    if (CORBA::is_nil(naming)){
      cerr << "invalid reference to CosNaming root ctx, exiting" << endl;
      return EXIT_FAILURE;
    }
    root_ctx = CosNaming::NamingContextExt::_narrow(naming);
    if (CORBA::is_nil(root_ctx)){
      cerr << "reference was not a root context of CosNaming, exiting" << endl;
      return EXIT_FAILURE;
    }
    cout << "got reference to NameService" << endl;

    my_ctx = root_ctx->new_context();
    CosNaming::Name_var name = root_ctx->to_name("Hallo");
    /* alternatively and the hard way:
       CosNaming::Name name;
       name.length(1);
       name[0].id = CORBA::string_dup("Hallo");
       name[0].kind = CORBA::string_dup("");
    */
    try {
      // bind my_ctx as kind to the root
      root_ctx->bind_context(name, my_ctx);
    } catch (CosNaming::NamingContext::InvalidName& e){
      cout << "CosNaming: Invalid name" << endl;
      return EXIT_FAILURE;
    } catch (CosNaming::NamingContext::AlreadyBound& e){
      cout << "CosNaming: context already bound, use rebind() instead ..." << endl;
      root_ctx->rebind_context(name, my_ctx);
    }
    cout << "bound Hallo context to NameService" << endl;
  } catch (const CORBA::ORB::InvalidName&) {
    cerr << "Invalid name: NameService " << endl;
    return EXIT_FAILURE;
  } catch (const CORBA::SystemException& e){
    cerr << "Error handling name binding: " << e << endl;
    status = EXIT_FAILURE;
  }

  try {
    // create and activate implementation object
    Hallo_impl* halloImpl = new Hallo_impl(orb, "Ingo");
    // publish reference via corbaloc naming service
    Hallo_var hallo = halloImpl->_this();
    cout << "got and activated Hallo server" << endl;

    // bind reference to naming entry
    CosNaming::Name_var implName;
    try {
      implName = root_ctx->to_name("HalloServer");
      my_ctx->bind(implName, hallo);
    } catch (const CosNaming::NamingContext::AlreadyBound& e){
      cerr << "server name already bound in CosNaming, rebinding it ..." << endl;
      my_ctx->rebind(implName, hallo);
    }
    cout << "bound service object to naming entry" << endl;
  } catch (const CORBA::SystemException& e){
    cerr << "Error activating or binding server: " << e << endl;
    return EXIT_FAILURE;
  }

  cout << "server open and ready for business ..." << endl;
  try {
    orb->run();
  } catch (const CORBA::SystemException& e){
    cerr << "Error in ORB loop: " << e << endl;
    status = EXIT_FAILURE;
  }

  // if the ORB is not fully shutdowned by the superuser, we just destroy it here
  if (!CORBA::is_nil(orb)){
    try {
      orb->destroy();
    } catch (const CORBA::SystemException& e){
      cerr << e << endl;
      status = EXIT_FAILURE;
    }
  }

  return status;
}

