github.com/TIBCOSoftware/flogo-lib@v0.5.9/core/event/events.go (about) 1 package event 2 3 import ( 4 "github.com/TIBCOSoftware/flogo-lib/logger" 5 "sync" 6 "runtime/debug" 7 "errors" 8 "strings" 9 "github.com/TIBCOSoftware/flogo-lib/config" 10 ) 11 12 type EventListener interface { 13 // Returns name of the listener 14 Name() string 15 16 // Called when matching event occurs 17 HandleEvent(*EventContext) error 18 } 19 20 var eventListeners = make(map[string][]EventListener) 21 22 // Buffered channel 23 var eventQueue = make(chan *EventContext, 100) 24 var publisherRoutineStarted = false 25 var shutdown = make(chan bool) 26 var publishEventsEnabled = config.PublishAuditEvents() 27 28 var lock = &sync.RWMutex{} 29 30 // Registers listener for given event types 31 func RegisterEventListener(evtListener EventListener, eventTypes []string) error { 32 if evtListener == nil { 33 return errors.New("Event listener must not nil") 34 } 35 36 if len(eventTypes) == 0 { 37 return errors.New("Failed register event listener. At-least one event type must be provided.") 38 } 39 40 lock.Lock() 41 for _, eType := range eventTypes { 42 eventListeners[eType] = append(eventListeners[eType], evtListener) 43 logger.Debugf("Event listener - '%s' successfully registered for event type - '%s'", evtListener.Name(), eType) 44 } 45 lock.Unlock() 46 startPublisherRoutine() 47 return nil 48 } 49 50 // Unregister event listener for given event types . 51 // To unregister from all event types, set eventTypes to nil 52 func UnRegisterEventListener(name string, eventTypes []string) { 53 54 if name == "" { 55 return 56 } 57 58 lock.Lock() 59 60 var deleteList []string 61 var index = -1 62 63 if eventTypes != nil && len(eventTypes) > 0 { 64 for _, eType := range eventTypes { 65 evtLs, ok := eventListeners[eType] 66 if ok { 67 for i, el := range evtLs { 68 if strings.EqualFold(el.Name(), name) { 69 index = i 70 break 71 } 72 } 73 if index > -1 { 74 if len(evtLs) > 1 { 75 // More than one listeners 76 copy(evtLs[index:], evtLs[index+1:]) 77 evtLs[len(evtLs)-1] = nil 78 eventListeners[eType] = evtLs[:len(evtLs)-1] 79 } else { 80 // Single listener in the map. Remove map entry 81 deleteList = append(deleteList, eType) 82 } 83 logger.Debugf("Event listener - '%s' successfully unregistered for event type - '%s'", name, eType) 84 index = -1 85 } 86 } 87 } 88 } else { 89 for eType, elList := range eventListeners { 90 for i, el := range elList { 91 if strings.EqualFold(el.Name(), name) { 92 index = i 93 break 94 } 95 } 96 if index > -1 { 97 if len(elList) > 1 { 98 // More than one listeners 99 copy(elList[index:], elList[index+1:]) 100 elList[len(elList)-1] = nil 101 eventListeners[eType] = elList[:len(elList)-1] 102 } else { 103 // Single listener in the map. Remove map entry 104 deleteList = append(deleteList, eType) 105 } 106 logger.Debugf("Event listener - '%s' successfully unregistered for event type - '%s'", name, eType) 107 index = -1 108 } 109 } 110 } 111 112 if len(deleteList) > 0 { 113 for _, evtType := range deleteList { 114 delete(eventListeners, evtType) 115 } 116 } 117 118 lock.Unlock() 119 stopPublisherRoutine() 120 } 121 122 func startPublisherRoutine() { 123 if publisherRoutineStarted == true { 124 return 125 } 126 127 if len(eventListeners) > 0 { 128 // start publisher routine 129 go publishEvents() 130 publisherRoutineStarted = true 131 } 132 } 133 134 func stopPublisherRoutine() { 135 if publisherRoutineStarted == false { 136 return 137 } 138 139 if len(eventListeners) == 0 { 140 // No more listeners. Stop go routine 141 shutdown <- true 142 publisherRoutineStarted = false 143 } 144 } 145 146 // EventContext is a wrapper over specific event 147 type EventContext struct { 148 // Type of event 149 eventType string 150 // Event data 151 event interface{} 152 } 153 154 // Returns wrapped event data 155 func (ec *EventContext) GetEvent() interface{} { 156 return ec.event 157 } 158 159 // Returns event type 160 func (ec *EventContext) GetType() string { 161 return ec.eventType 162 } 163 164 func publishEvents() { 165 defer func() { 166 publisherRoutineStarted = false 167 }() 168 169 for { 170 select { 171 case event := <-eventQueue: 172 lock.RLock() 173 publishEvent(event) 174 lock.RUnlock() 175 case <-shutdown: 176 logger.Infof("Shutting down event publisher routine") 177 return 178 } 179 } 180 } 181 182 func publishEvent(fe *EventContext) { 183 regListeners, ok := eventListeners[fe.eventType] 184 if ok { 185 for _, ls := range regListeners { 186 func() { 187 defer func() { 188 if r := recover(); r != nil { 189 logger.Errorf("Registered event listener - '%s' failed to process event due to error - '%v' ", ls.Name(), r) 190 logger.Errorf("StackTrace: %s", debug.Stack()) 191 } 192 }() 193 err := ls.HandleEvent(fe) 194 if err != nil { 195 logger.Errorf("Registered event listener - '%s' failed to process event due to error - '%s' ", ls.Name(), err.Error()) 196 } else { 197 logger.Debugf("Event - '%s' is successfully delivered to event listener - '%s'", fe.eventType, ls.Name()) 198 } 199 200 }() 201 } 202 fe = nil 203 } 204 } 205 206 func HasListener(eventType string) bool { 207 // event publishing is turned off 208 if !publishEventsEnabled { 209 return false 210 } 211 212 lock.RLock() 213 ls, ok := eventListeners[eventType] 214 lock.RUnlock() 215 return ok && len(ls) > 0 216 } 217 218 //TODO channel to be passed to actions 219 // Puts event with given type and data on the channel 220 func PostEvent(eType string, event interface{}) { 221 if publishEventsEnabled && publisherRoutineStarted && HasListener(eType) { 222 evtContext := &EventContext{event: event, eventType: eType} 223 // Put event on the queue 224 eventQueue <- evtContext 225 } 226 }