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  }