/*
  server.cpp

  This is the mainline of a Corba server which only can say "Hallo". It is a
  simple server, using no naming services, but a file-based IOR for presenting
  the reference to the server object to everybody.

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

  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();

    // save reference to server by poor man's means (writing the IOR of the
    // server to a file).
    CORBA::String_var str = orb->object_to_string(servant);
    cout << "save IOR " << str << " to file HAL.ref" << endl;
    const char* refFile = "HAL.ref";
    ofstream out(refFile);
    if (out.fail()){
      cerr << argv[0] << ": can not open " << refFile << ": " << strerror(errno) << endl;
      return EXIT_FAILURE;
    }
    out << str << endl;
    out.close();
  } 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;
  }

  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;
}

