/*
  server.cpp

  This is the mainline of a Corba server which only can say "Hallo". It is a
  simple server, using an IMR to start the server and to deliver a persistent
  file-based IOR to clients.

  Because we want explicit object activation with object IDs, we need a new POA
  on which we can install special policies. This POA is used as POA for the
  simple server implementation.

  We now assume that the IMR runs on host 'adrasteia' on ports 3800/3801.
  This is done by starting the services:

adrasteia$ imr -ORBConfig imr.conf --administrative&
adrasteia$ imr -ORBConfig oad.conf&

  Register the server to the IMR. Assume the server runs on host 'nike':

adrasteia$ imradmin -ORBInitRef IMR=corbaloc:iiop:adrasteia:3800/IMR \
    --add-server SRV1 "/home/ingo/serverhome/server" nike
adrasteia$ imradmin -ORBInitRef IMR=corbaloc:iiop:adrasteia:3800/IMR \
    --set-server SRV1 args "-ORBInitRef IMR=corbaloc:iiop:adrasteia:3800/IMR"

  The server itself writes no IOR file, because we can generate this file once
  and re-use it later many times, because the information for this IMR-based
  persistent server never change. To create the reference file, use the command

adrasteia$ mkref -P3801 SRV1 ISrv MyPOA >HAL.ref 

  Author: Ingo Kloeckl
 */

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

  try {
    // No.1 task - get an ORB
    orb = CORBA::ORB_init(argc, argv);
  } catch (const CORBA::SystemException& e){
    cerr << "Error initializing ORB: " << e << endl;
    return EXIT_FAILURE;
  }

  // get the root POA - this is only necessary because we have to activate at
  // least this root POA
  PortableServer::POA_var rootPOA;
  try {
    CORBA::Object_var poaObj = orb->resolve_initial_references("RootPOA");
    if (CORBA::is_nil(poaObj)){
      cerr << "error resolving RootPOA, exiting" << endl;
      return EXIT_FAILURE;
    }
    rootPOA = PortableServer::POA::_narrow(poaObj);
    if (CORBA::is_nil(rootPOA)){
      cerr << "RootPOA is not a POA reference, exiting" << endl;
      return EXIT_FAILURE;
    }
    cout << "got root 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;
  }

  // for explicit object activation with objectID, we need a special POA
  // policy. To install it, we need a new POA!
  PortableServer::POA_var myPOA;
  try {
    CORBA::PolicyList policies;
    policies.length(2);
    policies[0] = rootPOA->create_id_assignment_policy(PortableServer::USER_ID);
    policies[1] = rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
    
    PortableServer::POAManager_var myPOAManager = rootPOA->the_POAManager();
    myPOA = rootPOA->create_POA("MyPOA", myPOAManager, policies);
    if (CORBA::is_nil(myPOA)){
      cerr << "MyPOA could not be created, exiting" << endl;
      return EXIT_FAILURE;
    }
    // get the POAs manager to activate. If the POA is not activated, the ORB
    // try to dispatch requests to it, but no one processes them :-(
    myPOAManager->activate();
  } catch (const PortableServer::POA::AdapterAlreadyExists& e){
    // this POA already exists
  } catch (const PortableServer::POA::InvalidPolicy& e){
    // the choosen policy combination is invalid
  }

  try {
    // create implementation object and activate it explicitly with a special
    // POA, in this case the root POA (but this could be another, newly
    // created POA).
    Hallo_impl* halloImpl = new Hallo_impl(orb, myPOA, "+Ingo+");
    // activation call
    PortableServer::ObjectId_var oid = PortableServer::string_to_ObjectId("ISrv");
    myPOA->activate_object_with_id(oid, halloImpl);
    cout << "implementation activated" << endl;

    // The activation of the implementataion does not return a reference to the
    // implementation, so we get it here. If the implementation is already
    // activated, a call to _this() only return a reference to it!
    Hallo_var servant = halloImpl->_this();

  } catch (const PortableServer::POA::WrongPolicy& e){
    cerr << "Wrong policy: " << e << endl;
    return EXIT_FAILURE;
  } catch (const PortableServer::POA::ServantAlreadyActive&){
    cerr << "servant already active" << endl;
    return EXIT_FAILURE;
  } catch (const PortableServer::POA::ObjectAlreadyActive&){
    cerr << "object already active" << endl;
    return EXIT_FAILURE;
  } catch (const CORBA::SystemException& e){
    cerr << "Error activating servant: " << e << endl;
    return EXIT_FAILURE;
  } catch (...){
    cerr << "Something was wrong" << endl;
    return EXIT_FAILURE;
  }

  cout << " server ready and open for business ... " << endl;
  try {
    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;
}

