#!/usr/bin/env python

# CCA - CORBA Component Architecture
# ccapyd
#
# Copyright (C) 2004 Tektronix Berlin GmbH & Co. KG
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

import sys, os

sppath = "/usr/lib/python2.7/site-packages"
if os.path.isdir(sppath):
    sys.path.append(sppath)

bindir = os.path.abspath(os.path.dirname(sys.argv[0]))
if bindir != "":
    treedir, bin = os.path.split(bindir)
    if bin == "bin":
        pylibdir = os.path.join(treedir, "lib", "python")
        if os.path.isdir(pylibdir):
            sys.path.insert(0, pylibdir)

import time, getopt, logging, signal
try:
    import win32process
except:
    pass
import omniORB
from omniORB import CORBA, PortableServer
from omniORB import BiDirPolicy
from omniORB import omniConnectionMgmt
from omniORB import sslTP
import CCAServer
import CCA

log = None
orb = None
servantCS = None

def signalHandler(signum, frame):
    """ remove assembly factory via kill signal """
    try:
        servantCS.unloadComponentHomes()
    except:
        log.error("signal handler: got exception to remove: %s, %s", \
                  sys.exc_type, sys.exc_value)
    try:
        orb.shutdown(False)
    except:
        log.error("exception when shutting down ORB: %s %s",\
                  sys.exc_type, sys.exc_value)
    else:
        log.info("ORB terminated")

def transientExceptionHandler(cookie, retries, exc):
    # FailedOnForwarded handling copied from omniORB default handler
    if exc.minor == omniORB.TRANSIENT_FailedOnForwarded:
        log.warn("invocation on a location forwarded object has failed." \
                 "%s retries." % retries)
        if retries < 30:
            secs = retries
        else:
            secs = 30
        if secs != 0:
            time.sleep(secs)
        return True
    elif exc.minor != omniORB.TRANSIENT_CallTimedout \
        and exc.completed == CORBA.COMPLETED_NO \
        and retries < 3:
        time.sleep(1)
        return True
    return False

def timeoutExceptionHandler(cookie, retries, exc):
    return False

def commFailureExceptionHandler(cookie, retries, exc):
    if exc.completed == CORBA.COMPLETED_NO \
        and retries < 3:
        time.sleep(1)
        return True
    return False

def main():
    global log, orb, servantCS
    omniConnectionMgmt.init()
    orb = CORBA.ORB_init(sys.argv)
    progName = os.path.basename(sys.argv[0])

    try:
        opts, args = getopt.getopt(sys.argv[1:],
                                   "v:V:a:e",
                                   ['verbose=', 'Verbose=', 'activatorIOR='])
    except getopt.GetoptError, exception:
        print >>sys.stderr, "%s: %s" % (progName, str(exception))
        sys.exit(1)

    logToStderr  = False
    retryExceptions = True
    activatorIOR = None
    outputLevel = logging.WARN
    for opt, val in opts:
        if   (opt == '-a') or (opt == '--activatorIOR'):
            activatorIOR = val
        elif (opt == '-v') or (opt == '--verbose') \
          or (opt == '-V') or (opt == '--Verbose'):
            logToStderr |= ((opt == '-V') or (opt == '--Verbose'))
            try:
                outputLevel = { 'debug':    logging.DEBUG,
                                'info':     logging.INFO,
                                'warn':     logging.WARN,
                                'error':    logging.ERROR,
                                'critical': logging.CRITICAL,
                                'fatal':    logging.FATAL }[val]
            except KeyError:
                print >>sys.stderr, \
                      "%s: invalid logging verbosity '%s'." % (progName, val)
                sys.exit(1)
        elif (opt == '-e'):
            retryExceptions = False
        else:
            print >>sys.stderr, \
            "%s: found option %s with value %s." % (progName, opt, val)
            sys.exit(1)

    log = CCAServer.createLogger("ccapyd", outputLevel, logToStderr)

    if retryExceptions:
        omniORB.installTransientExceptionHandler(None,
            transientExceptionHandler)
        omniORB.installTimeoutExceptionHandler(None,
            timeoutExceptionHandler)
        omniORB.installCommFailureExceptionHandler(None,
            commFailureExceptionHandler)

    # get our activator
    if activatorIOR:
        activator = orb.string_to_object(activatorIOR)
        try:
            activator = activator._narrow(CCA.ComponentServerActivator)
        except:
            log.error("Cannot narrow CCA.ComponentServerActivator")
            sys.exit(1)
        if not activator:
            log.error("No activator from narrow CCA.ComponentServerActivator")
            sys.exit(1)
    else:
        log.error("no valid activator given")
        sys.exit(1)

    # Resolve root POA first
    try:
        root_poa = orb.resolve_initial_references("RootPOA")
    except CORBA.INITIALIZE:
        log.error("cannot initialize server: configuration error or network " \
                  "resources not available")
    except:
        log.error("resolve_initial_references: got exception: %s, %s", \
                  sys.exc_type, sys.exc_value)
        sys.exit(1)

    # Activate the Root POA's manager
    root_poa._get_the_POAManager().activate()

    # Create component server POA
    pl = [BiDirPolicy.BidirectionalPolicy(BiDirPolicy.BOTH)]
    poa = root_poa.create_POA("csPOA", root_poa._get_the_POAManager(), pl)

    # Create an instance of a servant class
    servantCS  = CCAServer.ComponentServer_i(orb, poa, log)

    # Activate cs servant in the component server POA
    try:
        id = poa.activate_object(servantCS)
        obj = poa.id_to_reference(id)._narrow(CCA.ComponentServer)
    except:
        log.error("activating ComponentServer servant: got exception: %s, %s",
                  sys.exc_type, sys.exc_value)
        sys.exit(1)
    try:
        # send confirmation to our activator
        activator.addComponentServer(os.getpid(), obj)
    except:
        log.error("addComponentServer: got exception: %s, %s",
                  sys.exc_type, sys.exc_value)
        sys.exit(1)

    # set the signal handler to call unloadComponentHomes
    signal.signal(signal.SIGINT,  signalHandler)
    signal.signal(signal.SIGTERM, signalHandler)
    if os.name == "nt":
        try:
            win32process.SetProcessShutdownParameters(0x280, 1)
        except:
            pass
        signal.signal(signal.SIGBREAK, signalHandler)

    # Run the ORB, blocking this thread
    orb.run()

    logging.shutdown()
    # finally destroy the ORB
    orb.destroy()

if __name__ == "__main__":
    main()

