diff options
author | David Pursehouse <david.pursehouse@sonymobile.com> | 2012-08-02 12:38:17 +0900 |
---|---|---|
committer | David Pursehouse <david.pursehouse@sonymobile.com> | 2012-08-02 17:50:31 +0900 |
commit | 8f6f44c15a3ca3d7520b09147c8862e73ad30e11 (patch) | |
tree | eedccd4e67435211b541488f30895b5b90f44619 | |
parent | bb6cc231717ce7e77e809c9ed721e7c236bf30cb (diff) | |
download | pygerrit-8f6f44c15a3ca3d7520b09147c8862e73ad30e11.tar.gz |
Add event factory and refactor event dispatching
Add a new static class GerritEventFactory which provides:
- Decorator method to register event names to classes
- Method to instantiate an event class based on event name
The stream implementation is refactored to use the factory to
generate the events.
With this change it will be possible to add new event classes
without having to modify the stream handler implementation.
Change-Id: If1fd0b4f77ead320e98a56301d8266d66dcc8aca
-rw-r--r-- | pygerrit/events.py | 46 | ||||
-rw-r--r-- | pygerrit/stream.py | 69 |
2 files changed, 65 insertions, 50 deletions
diff --git a/pygerrit/events.py b/pygerrit/events.py index c07979a..4a7200d 100644 --- a/pygerrit/events.py +++ b/pygerrit/events.py @@ -4,6 +4,45 @@ from pygerrit.error import GerritError from pygerrit.models import Account, Approval, Change, Patchset, RefUpdate +class GerritEventFactory(object): + + """ Gerrit event factory. """ + + _events = {} + + @classmethod + def register(cls, name): + """ Decorator to register the event identified by `name`. + + Raise GerritError if the event is already registered. + + """ + + def decorate(klazz): + if name in cls._events: + raise GerritError("Duplicate event: %s" % name) + cls._events[name] = klazz.__name__ + return klazz + return decorate + + @classmethod + def create(cls, json_data): + """ Create a new event instance. + + Return an instance of the `GerritEvent` subclass from `json_data` + Raise GerritError if `json_data` does not contain a `type` key, or + no corresponding event is registered. + + """ + if not "type" in json_data: + raise GerritError("`type` not in json_data") + name = json_data["type"] + if not name in cls._events: + raise GerritError("Unknown event: %s" % name) + classname = cls._events[name] + return globals()[classname](json_data) + + class GerritEvent(object): """ Gerrit event base class. """ @@ -12,6 +51,7 @@ class GerritEvent(object): pass +@GerritEventFactory.register("patchset-created") class PatchsetCreatedEvent(GerritEvent): """ Gerrit "patchset-created" event. """ @@ -26,6 +66,7 @@ class PatchsetCreatedEvent(GerritEvent): raise GerritError("PatchsetCreatedEvent: %s" % e) +@GerritEventFactory.register("draft-published") class DraftPublishedEvent(GerritEvent): """ Gerrit "draft-published" event. """ @@ -40,6 +81,7 @@ class DraftPublishedEvent(GerritEvent): raise GerritError("DraftPublishedEvent: %s" % e) +@GerritEventFactory.register("comment-added") class CommentAddedEvent(GerritEvent): """ Gerrit "comment-added" event. """ @@ -59,6 +101,7 @@ class CommentAddedEvent(GerritEvent): raise GerritError("CommentAddedEvent: %s" % e) +@GerritEventFactory.register("change-merged") class ChangeMergedEvent(GerritEvent): """ Gerrit "change-merged" event. """ @@ -73,6 +116,7 @@ class ChangeMergedEvent(GerritEvent): raise GerritError("ChangeMergedEvent: %s" % e) +@GerritEventFactory.register("change-abandoned") class ChangeAbandonedEvent(GerritEvent): """ Gerrit "change-abandoned" event. """ @@ -88,6 +132,7 @@ class ChangeAbandonedEvent(GerritEvent): raise GerritError("ChangeAbandonedEvent: %s" % e) +@GerritEventFactory.register("change-restored") class ChangeRestoredEvent(GerritEvent): """ Gerrit "change-restored" event. """ @@ -103,6 +148,7 @@ class ChangeRestoredEvent(GerritEvent): raise GerritError("ChangeRestoredEvent: %s" % e) +@GerritEventFactory.register("ref-updated") class RefUpdatedEvent(GerritEvent): """ Gerrit "ref-updated" event. """ diff --git a/pygerrit/stream.py b/pygerrit/stream.py index d59dbb8..9a12d12 100644 --- a/pygerrit/stream.py +++ b/pygerrit/stream.py @@ -5,21 +5,10 @@ Class to listen to the Gerrit event stream and dispatch events. """ import json +import logging -from pygerrit.events import PatchsetCreatedEvent, \ - RefUpdatedEvent, ChangeMergedEvent, CommentAddedEvent, \ - ChangeAbandonedEvent, ChangeRestoredEvent, \ - DraftPublishedEvent - - -# Event types -CHANGE_MERGED = "change-merged" -PATCHSET_CREATED = "patchset-created" -DRAFT_PUBLISHED = "draft-published" -COMMENT_ADDED = "comment-added" -CHANGE_ABANDONED = "change-abandoned" -CHANGE_RESTORED = "change-restored" -REF_UPDATED = "ref-updated" +from pygerrit.error import GerritError +from pygerrit.events import GerritEventFactory class GerritStreamError(Exception): @@ -33,15 +22,6 @@ class GerritStream(object): """ Gerrit events stream handler. """ - # Map the event types to class names. - _event_dict = {CHANGE_MERGED: "ChangeMergedEvent", - PATCHSET_CREATED: "PatchsetCreatedEvent", - DRAFT_PUBLISHED: "DraftPublishedEvent", - COMMENT_ADDED: "CommentAddedEvent", - CHANGE_ABANDONED: "ChangeAbandonedEvent", - CHANGE_RESTORED: "ChangeRestoredEvent", - REF_UPDATED: "RefUpdatedEvent"} - def __init__(self): self.listeners = [] @@ -70,39 +50,28 @@ class GerritStream(object): except ValueError: pass - def _get_event(self, json_data): - """ Create a new event from `json_data`. - - Return an instance of one of the `GerritEvent` subclasses. - Raise GerritStreamError if any error occurs. - - """ - event_type = json_data["type"] - if event_type in self._event_dict: - classname = self._event_dict[event_type] - try: - return globals()[classname](json_data) - except KeyError, e: - raise GerritStreamError("Error creating event: %s" % e) + def stream(self, inputstream): + """ Read lines of JSON data from `inputstream` and dispatch events. - raise GerritStreamError("Unexpected event type `%s`" % event_type) + For each line read from `inputstream`, until EOF, parse the line as + JSON data, instantiate the corresponding GerritEvent, and dispatch it + to the listeners. - def _dispatch_event(self, event): - """ Dispatch the `event` to the listeners. """ - for listener in self.listeners: - listener.on_gerrit_event(event) + Raise GerritStreamError on any errors. - def stream(self, inputstream): - """ Listen to the `inputstream` and handle JSON objects. """ + """ try: - done = 0 - while not done: + while 1: line = inputstream.readline() - if line: - data = json.loads(line) - self._dispatch_event(self._get_event(data)) - else: + if not line: break + json_data = json.loads(line) + try: + event = GerritEventFactory.create(json_data) + for listener in self.listeners: + listener.on_gerrit_event(event) + except GerritError, e: + logging.error("Unable to dispatch event: %s", e) except IOError, e: raise GerritStreamError("Error reading event stream: %s" % e) except ValueError, e: |