Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

#!/usr/bin/env python 

 

""" 

@file ion/core/process/service_process.py 

@author Michael Meisinger 

@brief base classes for all service processes and clients. 

""" 

 

from twisted.internet import defer 

from zope.interface import implements, Interface 

 

import ion.util.ionlog 

log = ion.util.ionlog.getLogger(__name__) 

 

from ion.core import ioninit 

from ion.core.process.process import Process, ProcessClient, ProcessFactory 

from ion.core.cc.container import Container 

from ion.core.messaging.receiver import ServiceWorkerReceiver 

import ion.util.procutils as pu 

 

class IServiceProcess(Interface): 

    """ 

    Interface for all capability container service worker processes 

    """ 

 

class ServiceProcess(Process): 

    """ 

    This is the superclass for all service processes.  A service process is a 

    Capability Container process that can be spawned anywhere in the network 

    and that provides a service under a defined service name (message queue). 

    The service subclass must have declaration with defaule service name, 

    version identifier and dependencies. 

    """ 

    implements(IServiceProcess) 

 

    # Service declaration, to be set by the subclass 

    declare = {} 

 

    def __init__(self, *args, **kwargs): 

        """ 

        Initializes base service. The default service name is taken from the 

        service declaration, a different service name can be provided in the 

        spawnargs using the 'servicename' attribute. The service name, in its 

        qualified form prefixed by the system name is the public name of the 

        service inbound queue that is shared among all service processes with 

        the same name 

        """ 

        Process.__init__(self, *args, **kwargs) 

 

        # Determine public service messaging name either from spawn args or 

        # use default name from service declaration 

        #default_svcname = self.declare['name'] + '_' + self.declare['version'] 

        default_svcname = self.declare['name'] 

        self.svc_name = self.spawn_args.get('servicename', default_svcname) 

        assert self.svc_name, "Service must have a declare with a valid name" 

 

        # Create a receiver (inbound queue consumer) for service name 

        self.svc_receiver = ServiceWorkerReceiver( 

                label=self.svc_name+'.'+self.receiver.label, 

                name=self.svc_name, 

                scope='system', 

                group=self.receiver.group, 

                process=self, # David added this - is it a good idea? 

                handler=self.receive, 

                error_handler=self.receive_error) 

        self.add_receiver(self.svc_receiver) 

 

    @defer.inlineCallbacks 

    def plc_init(self): 

        # Step 1: Service init callback 

        try: 

            yield defer.maybeDeferred(self.slc_init) 

        except Exception, ex: 

            log.exception('----- Service %s process %s INIT ERROR -----' % (self.svc_name, self.id)) 

            raise ex 

 

        # Step 2: Init service name receiver (declare queue) 

        yield self.svc_receiver.initialize() 

 

    def slc_init(self): 

        """ 

        Service life cycle event: initialization of service process. This is 

        called once after the receipt of the process init message. Use this to 

        perform complex, potentially deferred initializations. 

        """ 

        #log.debug('slc_init()') 

 

    @defer.inlineCallbacks 

    def plc_activate(self): 

        # Step 1: Service activate callback 

        try: 

            yield defer.maybeDeferred(self.slc_activate) 

        except Exception, ex: 

            log.exception('----- Service %s process %s ACTIVATE ERROR -----' % (self.svc_name, self.id)) 

            raise ex 

 

        # Step 2: Activate service name receiver (activate consumer) 

        yield self.svc_receiver.activate() 

        log.info('Service process bound to name=%s' % (self.svc_receiver.xname)) 

 

    def slc_activate(self): 

        """ 

        Service life cycle event: activate service process. Will be called once 

        or many times after the slc_init of a service process. At this point, 

        all service dependencies must be present. 

        """ 

        #log.info('slc_start()') 

 

    @defer.inlineCallbacks 

    def plc_deactivate(self): 

        # Step 1: Activate service name receiver (deactivate consumer) 

        yield self.svc_receiver.deactivate() 

        log.info('Service process detached from name=%s' % (self.svc_receiver.xname)) 

 

        # Step 2: Service deactivate callback 

        try: 

            yield defer.maybeDeferred(self.slc_deactivate) 

        except Exception, ex: 

            log.exception('----- Service %s process %s DEACTIVATE ERROR -----' % (self.svc_name, self.id)) 

            raise ex 

 

    def slc_deactivate(self): 

        """ 

        Service life cycle event: deactivate service process. Will be called to 

        deactivate an activated service process, and before terminate. A 

        deactivated service can be restarted again. 

        """ 

        #log.info('slc_deactivate()') 

 

    @defer.inlineCallbacks 

    def plc_terminate(self): 

        try: 

            yield defer.maybeDeferred(self.slc_deactivate) 

            yield defer.maybeDeferred(self.slc_terminate) 

        except Exception, ex: 

            log.exception('----- Service %s process %s TERMINATE ERROR -----' % (self.svc_name, self.id)) 

            raise ex 

 

        # These appear to be left over from a previous verison of the code 

        #yield defer.maybeDeferred(self.slc_stop) 

        #yield defer.maybeDeferred(self.slc_shutdown) 

 

    def slc_terminate(self): 

        """ 

        Service life cycle event: final shutdown of service process. Will be 

        called after a slc_deactivate before the actual termination of the process. 

        No further asyncronous activities are allowed by the process after 

        reply from this function. 

        """ 

        #log.info('slc_terminate()') 

 

    @classmethod 

    def service_declare(cls, **kwargs): 

        """ 

        Helper method to create a declaration of service. 

        @param kwargs keyword attributes for service. Common ones must be present. 

        @retval a dict with service attributes 

        """ 

        log.debug("Service-declare: %s" % (kwargs)) 

        return kwargs 

 

factory = ProcessFactory(ServiceProcess) 

 

class ServiceClient(ProcessClient): 

    """ 

    This is the base class for service client libraries. Service client libraries 

    can be used from any process or standalone (in which case they spawn their 

    own client process). A service client makes accessing the service easier and 

    can perform client side optimizations (such as caching and transformation 

    of certain service results). 

    """ 

 

    def does_service_exist(self, name): 

        """The existence of a queue with the name of the service is 

        equivalent to the service existing. 

        """ 

        return self.proc.container.name_exists(name, scope='system')