/*
  server.cpp

  This is the mainline of a Corba server which only can say "Hallo". It uses 
  a naming 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!
  Besides this, to use the naming service, we have to create a POA of our own
  to set some policies like PERSISTENT and USER_ID.

  The used naming service is a corbaloc name resolution, meaning that this server
  has to speficy a well-known port number. The client uses this port and host name
  to resolve a symbolic server name, here 'Hallo'.
  Instead of a real nameservice, the boot manager binding is used, so no external
  name resolution service must be started.

  Author: Ingo Kloeckl
 */

#include <OB/CORBA.h>
#include <OB/BootManager.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;

  char* port;
  if (argc==1){
    cout << "using default port 5555" << endl;
    port = "5555";
  } else {
    port = argv[1];
  }

  try {
    // No.1 task - get an ORB and a POA
    // we have to pass the port number of this server to the ORB, so create
    // a argv-like array
    char* orb_options[] = { "-OAport", port };
    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;
  }

  PortableServer::POAManager_var manager;
  PortableServer::POA_var poa;
  try {
    CORBA::Object_var poaObj = orb->resolve_initial_references("RootPOA");
    if (CORBA::is_nil(poaObj)){
      cerr << "error resolving RootPOA, exiting" << endl;
      return EXIT_FAILURE;
    }
    PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(poaObj);
    if (CORBA::is_nil(rootPOA)){
      cerr << "RootPOA is not a POA reference, exiting" << endl;
      return EXIT_FAILURE;
    }
    manager = rootPOA->the_POAManager();
    cout << "got POA and POAManager" << endl;

    // to use activation with user-defined objectID, we have to create a
    // persistent POA with userID policy
    CORBA::PolicyList policies;
    policies.length(2);
    policies[0] = rootPOA->create_id_assignment_policy(PortableServer::USER_ID);
    policies[1] = rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
    try {
      poa = rootPOA->create_POA("halloPOA", manager, policies);
    } catch (const PortableServer::POA::AdapterAlreadyExists&){
      // if POA already exists, we have nothing to do
    } catch (const PortableServer::POA::InvalidPolicy&){
      cerr << "invalid policy while creating POA, exiting" << endl;
      return EXIT_FAILURE;
    }
    if (CORBA::is_nil(poa)){
      cerr << "got nil reference for POA, exiting" << endl;
      return EXIT_FAILURE;
    }
    cout << "created own POA" << endl;
  } catch (const CORBA::ORB::InvalidName& e){
    cerr << "Invalid name passed: " << e << endl;
    return EXIT_FAILURE;
  } catch (const CORBA::SystemException& e){
    cerr << "Error handling POA: " << e << endl;
    return EXIT_FAILURE;
  }

  try {
    // create implementation object
    Hallo_impl* halloImpl = new Hallo_impl(orb, "Ingo");
    PortableServer::ObjectId_var oid = PortableServer::string_to_ObjectId("Hallo");
    PortableServer::ServantBase_var servant = halloImpl;
    poa->activate_object_with_id(oid, servant);
    cout << "got and activated Hallo server" << endl;

    // resolve boot manager and register server
    CORBA::Object_var bootObj = orb->resolve_initial_references("BootManager");
    if (CORBA::is_nil(bootObj)){
      cerr << "error resolving BootManager, exiting" << endl;
      return EXIT_FAILURE;
    }
    OB::BootManager_var bootManager = OB::BootManager::_narrow(bootObj);
    if (CORBA::is_nil(bootManager)){
      cerr << "Boot object is no BootManager, exiting" << endl;
      return EXIT_FAILURE;
    }
    cout << "got bootManager" << endl;

    // publish reference via corbaloc naming service
    Hallo_var hallo = halloImpl->_this();
    bootManager->add_binding(oid, hallo);
  } catch (const CORBA::SystemException& e){
    cerr << "Error handling boot manager and servant: " << e << endl;
    status = EXIT_FAILURE;
  }

  try {
    // run POA and also the implementation server
    manager->activate();
    orb->run();
  } catch (const CORBA::SystemException& e){
    cerr << 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::Exception& e){
      cerr << e << endl;
      status = EXIT_FAILURE;
    }
  }

  return status;
}

