#Copyright (c) 2005 by Mark T. Holder, Florida State University. (see end of file) '''Convenience functions to consolidate repetitive tasks and hide cipres implementation details''' # CIPRES types are corba-enabled versions of the PIPRes datatypes. # The separation only exists so that users of PIPRes are not required # to have the corba portions of the PIPRes (and omniorbPy) installed # if they only want to use pure python portions of PIPRes. # The Cipres versions of the types have a method createCorbaVersion(self) # which returns of the corresponding CipresIDL_api1 type ready to be passed as an # argument to or a return value from a remote call. from PIPRes.wrap.idl import * from PIPRes.util.io import logException, cipresGetLogger, _loggerInitialized, _cipresInitLogger, getCipresConfigFilePath import CosNaming # We are going now using a CIPRES service to read properties propertiesServiceWorking = False #these are globals (singletons). Users should NOT need to access them directly (may be hidden in future versions). _cipresRegistry = None _cipresProperties = None _cipresORB = None cipresDefaultFakeArgs = ['', '-CipresNoNs', '-ORBgiopMaxMsgSize', '200001000'] # hidden statics _defaultRegistryWrapper = None # set by first call to cipresDefaultRegistry _LOG = cipresGetLogger('pipres.util.cipres') _serverRunCalled = False # flag so we know if we should call orb.shutdown (set in cipresServerRun) def getObjectFromIORFile(orb, pathToIOR, narrowTo = None): if not os.path.exists(pathToIOR): raise ValueError, 'The specified path to IORFile (%s) does not exist.' % pathToIOR realIORFile = open(pathToIOR, 'rU') ior = realIORFile.readline() realIORFile.close() obj = orb.string_to_object(ior) if narrowTo is not None: return obj._narrow(narrowTo.__name__) return obj def cipresDefaultRegistry(): '''Returns a reference to the RichCipresRegistry. Should be used when the registry is needed, but the program is not invoking cipres{Client|Server}Init() to initialize the registry. Calls _cipresInitFromMethod()''' global _defaultRegistryWrapper if _defaultRegistryWrapper is None: _LOG.debug('initializing cipres ') _defaultRegistryWrapper = _cipresInitFromMethod() _defaultRegistryWrapper return _defaultRegistryWrapper def cipresClientInit(argv, returnMatrix = False, returnTree = False, **kwargs): '''Should be called by programs which will function as client that responds to cipres arguments to modify its behavior. "argv" should contain all -ORB and -Cipres args. "returnMatrix" and "returnTree" can be used if the client can be launched with -filename arg to specify data and/or tree in NEXUS.''' global _cipresProperties, _cipresRegistry assert((_cipresProperties is None) and (_cipresRegistry is None)) # should only be initialized once argv.append('-CipresNoNs') # TEMPORARY kwargs['stubTranslator'] = kwargs.get('stubTranslator', 'default') reg = _commonInitCode(argv, [], **kwargs) return _clientAppWithFilenameArg(reg, argv, returnMatrix, returnTree) def cipresServerInit(argv, interfaceList, **kwargs): '''Should be called by programs which will function as client that responds to cipres arguments to modify its behavior. "argv" should contain all -ORB and -Cipres args. "interfaceList" should be empty (to allow the request of any interface) or should list interfaces that the server supplies (used soley to validate argv).''' global _cipresProperties, _cipresRegistry assert((_cipresProperties is None) and (_cipresRegistry is None)) # should only be initialized once kwargs['stubTranslator'] = kwargs.get('stubTranslator', 'default') return _commonInitCode(argv, interfaceList, **kwargs) def cipresServe(argv, interfaceDict, **kwargs): if len(interfaceDict) == 0: raise ValueError, 'interfaceDict argument cannot be empty' registry = cipresServerInit(argv, interfaceDict.keys(), **kwargs) wrapperDict = kwargs.get('wrapper', 'default') if wrapperDict == 'default': from PIPRes.wrap import debug_impl, impl wrapperDict = '-debug' in argv and debug_impl.wrapperDict or impl.wrapperDict wrapperFactory = wrapperDict.get(registry.implName) factoryFunc = interfaceDict.get(registry.implName) if factoryFunc is None: if len(registry.implName) > 0: allServantFactoryFuncs = interfaceDict.values() factoryFunc = allServantFactoryFuncs[0] if len(allServantFactoryFuncs) == 1: registry.implName = interfaceDict.keys()[0] else: for ff in allServantFactoryFuncs[1:]: # if there are multiple interfaces, they must point to the same factory function if ff != factoryFunc: factoryFunc = None break raise InvocationError, '"-CipresImpl " arguments must be used to specify an interface to launch' argToFactoryFunc = [] if kwargs.get('factoryNeedsRegistry', True): argToFactoryFunc.append(registry) if kwargs.get('factoryNeedsArgv', False): argToFactoryFunc.append(argv) factKwargs = {} regStr = kwargs.get('factoryRegistryKeyword') if regStr is not None: factKwargs[regStr] = registry argvStr = kwargs.get('factoryArgvKeyword') if regStr is not None: factKwargs[argvStr] = argv implServantInstance = factoryFunc(*argToFactoryFunc, **factKwargs) if wrapperFactory is None: servantInstance = implServantInstance else: servantInstance = wrapperFactory(argv, registry, implServantInstance) servantRef = servantInstance._this() registry.bindOrRebind(servantRef) _LOG.debug('running server') cipresServerRun() def cipresServerRun(): global _serverRunCalled orb = getCipresORB() _activatePOAManager(orb) _serverRunCalled = True orb.run() def initCipresStatics(): '''initializes logger, reads user properties and registry. Returns properties and registry.''' if not _loggerInitialized: _cipresInitLogger() cipProp = getCipresProperties() # uses default location for properites file _LOG.debug('Properties read') from PIPRes.util.cipres_registry_from_xml import CipresRegistry cipReg = CipresRegistry() return cipProp, cipReg def getCipresORB(): if _cipresORB is None: raise AssertionError, 'CIPRES initialization (cipresClientInit, cipresServerInit, cipresServe, or cipresDefaultRegistry) must be called before CIPRES functionality is used' return _cipresORB def getCipresProperties(): '''Returns cipres properties (reading them from the standard location if necessary)''' global _cipresProperties if _cipresProperties is None: from PIPRes.util._cipres_properties import * if propertiesServiceWorking: _cipresProperties = CipresProperties() else: _cipresProperties = FakeProps() _cipresProperties.set('cipres.registry.ior', 'corbaloc::127.0.0.1:5001/CipresRegistry') return _cipresProperties def getCipresProperty(s, default=None): "Acts like a call to dict.get where the CIPRES properties are the dict" p = getCipresProperties() return getattr(p, s, default) def getCipresRegistry(): '''Calls cipresDefaultRegistry() to get a reference to the registry''' if _defaultRegistryWrapper is None: _cipresRegistry = cipresDefaultRegistry() return _cipresRegistry def _activatePOAManager(orb): poa = orb.resolve_initial_references("RootPOA") poaMgr = poa._get_the_POAManager() poaMgr.activate() class SimpleServer(CipresIDL_api1__POA.Scriptable, CipresIDL_api1__POA.LifeCycle): '''Implements default behavior for the Scriptable and LifeCylce interfaces. Reserves attributes: orb = orb reference obtained from "registry" self.userConfigCmdList = all strings sent to execute.''' def __init__(self, registry): '''"registry" should be a CipresRegistryInterface instance (or None if run as local python method call).''' self.orb = registry is not None and registry.orb or None self.userConfigCmdList = [] def remove(self): '''EXTERNAL METHOD: Calls orb shutdown if needed (if this instance was launched as a CORBA service).''' global _serverRunCalled # we only call shutdown if _serverRunCalled is True (indicating that this # server started the orb. When we are working behind corba's back (python # invocation of servants) we get in trouble if all servers call orb shutdown. if self.__dict__.get('orb') is not None and _serverRunCalled: import sys _LOG.debug('calling orb shutdown (invocation = %s' % sys.argv[0]) self.orb.shutdown(0) def getUIXml(self): '''EXTERNAL METHOD: Returns an empty string.''' return '' def execute(self, command): '''EXTERNAL METHOD: Logs "command" and appends it to the self.userConfigCmdList. Returns (True, '').''' _LOG.debug('execute called with "%s"' % command) self.userConfigCmdList.append(command) # for NEXUS programs (in nexus_program_server) we concatenate strings. return (True, '') class InvocationError(ValueError): '''Exception thrown for illegal command line arguments sent to initServerOrbAndGetRegistryWrapper (via cipres initialization).''' pass def hasServerArgs(args): '''Used by programs that can be launched as server or client. Returns True is an interface was requested using -ns or -CipresImpl.''' return (args.count('-ns') + args.count('-CipresImpl')) > 0 def initServerOrbAndGetRegistryWrapper(argv, cipresRegistry, validImpl = [], **kwargs): ''' handling of arguments should be synced with CipresFacilitator::initialize() in CIPRES_LIB_ROOT/C++/CipresCommlib/CipresFacilitator.cpp.''' from PIPRes.util.rich_cipres_registry import SimpleRegistryEntry, SimpleRegistry, RichCipresRegistry orb = getCipresORB() nsRegister = nsLookup = True implName = iorFileName = '' lastArgIndex = len(argv) - 1 argIter = iter(argv[1:]) unrecArgs = [argv[0]] for arg in argIter: if arg == '-CipresIOR': try: arg = argIter.next() except StopIteration: raise InvocationError, '-CipresIOR flag should be followed by a file path' iorFileName = arg elif arg == "-CipresNoNsReg": nsRegister = False elif arg == "-CipresNoNsLookup": nsLookup = False elif arg == "-CipresNoNs": nsRegister = nsLookup = False elif arg == "-ns" or arg == "-CipresImpl": try: arg = argIter.next() except StopIteration: raise InvocationError, '%s flag should be followed by the name of the Cipres service to be advertised' % arg implName = arg if validImpl and not implName in validImpl: raise InvocationError, 'valid values for -CipresImpl are {%s}' % '|'.join(validImpl) else: unrecArgs.append(arg) del argv[:] argv.extend(unrecArgs) if not implName: if len(validImpl) == 1: implName = validImpl[0] elif not nsRegister: _LOG.debug('Neither name service registration nor file-based publishing of the IOR were specified') if nsRegister or nsLookup: obj = orb.resolve_initial_references("NameService") rootContext = None try: rootContext = obj._narrow(CosNaming.NamingContext) finally: if not rootContext: raise CorbaError, 'Failed to narrow the root naming context' return RichCipresRegistry(cipresRegistry = cipresRegistry, implName = implName, namingContextRef = rootContext, nsRegister = nsRegister, nsLookup = nsLookup, iorFileName = iorFileName, **kwargs) return RichCipresRegistry(cipresRegistry = cipresRegistry, implName = implName, iorFileName = iorFileName, nsLookup = False, **kwargs) def _clientAppWithFilenameArg(reg, argv, returnMatrix = False, returnTree = False): '''Convenience utility accepts and handles a -filename argument and uses a readnexus service to get a tree and or matrix from it''' if returnMatrix: if returnTree: from PIPRes.cipres_types import CipresTree from PIPRes.wrap.stub import matrixAndTreeFromFileOrDefault mat, tree = matrixAndTreeFromFileOrDefault(reg, argv) return reg, mat, tree is not None and CipresTree(tree.m_newick) or None from PIPRes.wrap.stub import matrixFromFileOrDefault return reg, matrixFromFileOrDefault(reg, argv) if returnTree: from PIPRes.cipres_types import CipresTree from PIPRes.wrap.stub import treeFromFileOrDefault tree = treeFromFileOrDefault(reg, argv) return reg, tree is not None and CipresTree(tree.m_newick) or No return reg def _cipresInitFromMethod(**kwargs): '''Used (internally) to initialize the orb and registry with the default (global) cipresDefaultFakeArgs instead of command line arguments. Called by cipresDefaultRegistry''' global _loggerInitialized, cipresDefaultFakeArgs if not _loggerInitialized: _cipresInitLogger() kwargs['stubTranslator'] = kwargs.get('stubTranslator', 'default') return _commonInitCode(cipresDefaultFakeArgs, [], **kwargs) def _commonInitCode(argv, interfaces, **kwargs): '''Calls initCipresStatics and initServerOrbAndGetRegistryWrapper to initialize the orb, _cipresRegistry, _cipresProperties. Returns a registryWrapper that matches the command line arguments sent in argv. "interfaces" is used to validate argv sent to the server (verify that the argv does not contain a request to supply a service that the modules does not list in interfaces). "stubTranslator" is dict used to translate object references to instances of wrapper classes if desired. Called by cipres{Client|Server}Init() and cipresDefaultRegistry (via the _cipresInitFromMethod function). ''' global _cipresProperties, _cipresRegistry, _cipresORB try: if _cipresORB is None: from omniORB import CORBA _LOG.debug('calling orb_init') _LOG.debug(' with args: %s' % ' '.join(argv)) _cipresORB = CORBA.ORB_init(argv, CORBA.ORB_ID) _LOG.debug('ORB initialized') else: raise AssertionError, 'CIPRES initialization (cipresClientInit or cipresServerInit) called twice' if (_cipresProperties is None or _cipresRegistry is None): _cipresProperties, _cipresRegistry = initCipresStatics() if kwargs.get('stubTranslator') == 'default': from PIPRes.wrap import debug_stub, stub kwargs['stubTranslator'] = '-debug' in argv and debug_stub.objRefTranslator or stub.wrapperObjRefTranslator registryWrapper = initServerOrbAndGetRegistryWrapper(argv, _cipresRegistry, interfaces, **kwargs) except: logException(_LOG) raise assert(_cipresRegistry.orb is not None) return registryWrapper # This file is part of the PIPRes library # # The PIPRes library is free software; you can redistribute it # and/or modify it under the terms of the GNU Lesser General # Public License as published by the Free Software Foundation; # either version 2.1 of the License, or (at your option) any later # version. # # This library 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA