// 	Copyright 10/15/01 Sun Microsystems, Inc. All Rights Reserved.

#pragma ident  "@(#)epr_main.cc	1.14 01/10/15 Sun Microsystems"

#include <em_debug_service/em_debug_service.hh>
#include <util/lockfile.hh>
#ifdef ORBACUS
#include <OB/CORBA.h>
#else
#ifdef ORBIX
#include <omg/orb.hh>
#else
#include <corba.h>
#endif
#endif
#include <cgw_utils/cgw_global.hh>
#include <cgw_utils/cgw_exception_handlers.hh>
#include <cgw_utils/cgw_utils.hh>
#include <em_c++utils/ts_shutdown_manager.hh>
#include <tspmi_scheduler/tspmi_exceptions.hh>
#include <tspmi_scheduler/tspmi_scheduler.hh>
#include "event_port_factory_impl.hh"
#include "event_port_finder_impl.hh"
#include "event_port_registry_impl.hh"
#include <util/detach_process.hh>
#include <pmi/debug.hh>


Debug_off(epr_debug)
Debug_off(epr_trace)

// epr_error will be turned off after initialization
Debug_on(epr_error)
/******************************************************************************/

/* The lock file is created by em_services before we're launched. This process 
** removes the lock file when it's done initializing.
*/
LockFile lockfile("/tmp/.em_corba_epr.lock");

/*
** As part of cleanup, unbind the EventPortRegistry, EventPortFinder and 
** EventPortFactory that were created by this process.
*/
class EPRShutdownCallback : public TSShutdownManagerCallback
{
  public:
    EPRShutdownCallback() throw() {};
    virtual ~EPRShutdownCallback() throw () {};

    void execute() throw() {
	epr_trace.print("cleanup starts\n");
	// If the root_nc_ is not initialized, there is nothing to unbind.
	
	if (CORBA::is_nil(CGWGlobal::root_nc_)) return;
	
	CosNaming::Name name;
	try {
	    name.length(1);
	    name[0].id = CORBA::string_dup("EventPortRegistry");
	    name[0].kind = CORBA::string_dup("");
	    CGWGlobal::root_nc_->unbind(name);
	    
	    name[0].id = CORBA::string_dup("EventPortFinder");
	    CGWGlobal::root_nc_->unbind(name);
	    
	    name[0].id = CORBA::string_dup("EventPortFactory");
	    CGWGlobal::root_nc_->unbind(name);
	}
	catch (const CORBA::Exception& e) {
	    epr_error.print("Unbind of % failed:\n\t", (const char* )name[0].id);
	    CGWUtils::print_corba_exception(
		epr_error,
		"Failed to unbind objects from Naming Service:\n\t",
		e);
	}

	try
	{
#if defined(ORBACUS) || defined(ORBIX)
		CGWGlobal::orb_->shutdown(true);
#else
		CGWGlobal::orb_->shutdown();
#endif
	}
	catch (...)
	{
	    epr_error.print("orb shutdown  failed:\n\t" );
	}
	epr_trace.print("cleanup ends\n");
    }
};

/******************************************************************************/
int
main(
    int argc,
    char* const* argv
) {
    // First setup the default exception handlers for memory allocation and
    // unexcpected exceptions.


    ExceptionHandlerManager ehm();

    // This should be the first thing after getting the lockfile.
    TSShutdownManager& shutdown_mgr = TSShutdownManager::instance();
    EPRShutdownCallback* epr_shutdown_cb = new EPRShutdownCallback();
    shutdown_mgr.add_callback(epr_shutdown_cb);
    
    // Read the configuration file
    CGWGlobal::config.load("/var/opt/SUNWconn/em/conf/em_corba_epr.conf");

    // Initialize the EM Debug service
    CGWGlobal::debug_port = 6660; 
    char *debug_port_str =
        (char *)CGWGlobal::config.fetch("EM_CORBA_EPR_DEBUG_PORT");
    if (debug_port_str != (char *)NULL)
        CGWGlobal::debug_port = atoi(debug_port_str);

    // Initialize the EM Debug service
    if (DbgProto_init(NULL) == NOT_OK) {
	epr_error.print("Failed to initialize the EM debug protocol service\n");
	exit(1);
    }
    if (DbgPort_init(&CGWGlobal::debug_port) == NOT_OK) {
	epr_error.print("Failed to initialize the EM debug port service\n");
	exit(1);
    }

    // set up the log file
    CGWGlobal::default_log_file = "em_corba_epr.log";
    CGWGlobal::log_file =  CGWGlobal::config.fetch(
	"EM_CORBA_EPR_LOG_FILE", CGWGlobal::default_log_file);
    if (CGWGlobal::log_file.length() == 0) {
        detach_process("EM_CORBA_EPR_LOG_FILE", CGWGlobal::default_log_file);
    }
    else {
        detach_process("EM_CORBA_EPR_LOG_FILE",
		       CGWGlobal::log_file);
    }

    // PMI scheduler MUST be initialized ONLY after the debug service
    // initialization above. Otherwise, debug service will not be initialized.
    // The alternative is to initialize PMI scheduler first, and then use
    // TSPMIScheduler::enqueue_cb() for initializing the debug service.
    TSPMIScheduler::instance();
    epr_debug.print("Started the thread safe PMI scheduler\n");

    // Then initialize the ORB.

    try {
	if (!CGWUtils::resolve_sem_cgw_nameservice(argc,argv)) {
                cerr << "Could not resolve Naming Service\n";
                exit(1);
        }
    }
    catch (const CORBA::Exception& e) {
	CGWUtils::print_corba_exception(
	epr_error, "Failed to init ORB/POA:\n\t", e);
	exit(1);
    }
	
    epr_debug.print("RootPOA is resolved\n");

    // Get the default naming context
    // Create an empty policy list
    CORBA::PolicyList policies;

    // Create EventPortRegistry
    EventPortRegistryImpl ep_registry;
    CosNaming::Name name;
    name.length(1);

    try {
        // Set the policy for our own child POA
        policies.length(1);
        policies[(CORBA::ULong)0] =
        CGWGlobal::root_poa_->create_lifespan_policy(PortableServer::TRANSIENT);

	// Get the POA manager
        CGWGlobal::poa_manager_ = CGWGlobal::root_poa_->the_POAManager();

	// Create the our own child POA with the right policies
        //PortableServer::POA_var myPOA =
        CGWGlobal::cgwPOA_ =
        CGWGlobal::root_poa_->create_POA("SEMCorbaEPRPOA",
        CGWGlobal::poa_manager_,policies);

	// Activate the EventPortRegistry servant with the ID on cgwPOA
        CGWGlobal::cgwPOA_->activate_object(&ep_registry);
        CORBA::Object_var reference =
        CGWGlobal::cgwPOA_->servant_to_reference(&ep_registry);

	//CGWGlobal::boa_->obj_is_ready(&ep_registry);
	name[0].id = CORBA::string_dup("EventPortRegistry");
	name[0].kind = CORBA::string_dup("");
	CGWGlobal::root_nc_->rebind(name, reference);
    }
    catch (const CORBA::Exception& e) {
	CGWUtils::print_corba_exception(
	    epr_error,
	    "Failed to register EventPortResigstry with Naming Service:\n\t",
	    e);
	exit(3);
    }

    EventPortFinderImpl ep_finder(EventPortRegistry::_duplicate(
    ep_registry._this()));

    try {
        // Activate the EventPortFinder servant with the ID on cgwPOA
        CGWGlobal::cgwPOA_->activate_object(&ep_finder);
        CORBA::Object_var reference =
        CGWGlobal::cgwPOA_->servant_to_reference(&ep_finder);


        name[0].id = CORBA::string_dup("EventPortFinder");
        name[0].kind = CORBA::string_dup("");
        CGWGlobal::root_nc_->rebind(name, reference);

    }
    catch (const CORBA::Exception& e) {
	CGWUtils::print_corba_exception(
	    epr_error,
	    "Failed to register EventPortFinder with Naming Service:\n\t", e);
	exit(4);
    }
	
    EventPortFactoryImpl
	ep_factory(EventPortRegistry::_duplicate(ep_registry._this()));

    try {

        // Activate the EventPortFactory servant with the ID on cgwPOA
        CGWGlobal::cgwPOA_->activate_object(&ep_factory);
        CORBA::Object_var reference =
        CGWGlobal::cgwPOA_->servant_to_reference(&ep_factory);

        //CGWGlobal::boa_->obj_is_ready(&ep_factory);
        name[0].id = CORBA::string_dup("EventPortFactory");
        name[0].kind = CORBA::string_dup("");
        CGWGlobal::root_nc_->rebind(name, reference);

    }
    catch (const CORBA::Exception& e) {
	CGWUtils::print_corba_exception(
	    epr_error,
	    "Failed to register EventPortFactory with Naming Service:\n\t", e);
	exit(5);
    }

    // Activate the POA manager
    CGWGlobal::poa_manager_->activate();
    epr_debug.print("The POA manager is activated\n");
	
    // Tell startup scripts to continue
    (void) lockfile.unlock();


    // Now turn off epr_error as the initialization is almost complete.
    // Hereafer, em_debug can be used to dynamically turn this on or off.
    epr_error.enabled = 0;
    epr_debug.print("Ready to accept client requests\n");

    try {
	CGWGlobal::orb_->run();
    }
    catch (const CORBA::Exception& e) {
	CGWUtils::print_corba_exception(
	    epr_error,
	    "CORBA::run() interrupted:\n\t", e);
	exit(6);
    }
}

