Example #1
0
class MessageBus:
    """
    MessageBus is the heart of the backend messaging system.

    Almost all communication between components goes through this MessageBus.
    Components communicate with Messages, which are delivered to
    MessageHandlers

    via MessageBus. MessageBus knows which MessageHandlers are interested in
    which type of Messages. MessageBus is also aware of MessageHandler
    priorities and this way can serve high priority components first.

    When MessageHandler is registered to the MessageBus there is also another
    parameter besides handler itself. Second parameter is a dictionary that
    defines MessageTypes that registered handler wants to be notified of and
    also priorities for those message types."""

    # This determines number of message types avaialble. In other words, this
    # variable tells how many variables is defined in MessageType class.
    NUMBER_OF_MESSAGE_TYPES = len(
        [k for k, v in vars(MessageType).items() if type(v) is int]
        )

    def __init__(self):
        """
        Create a new MessageBus object.
        """
        # MessageHandlers - index is MessageType and data is a list of
        # tuples (priority, MessageHandler object) that is sorted by
        # priorities.
        #XXX: rockstar - WTF?!  Why is there a list comprehension being used
        # and still only returning an empty list?
        # pylint: disable-msg=W0612
        self.message_handlers = [
            [] for i in range(self.NUMBER_OF_MESSAGE_TYPES)
            ]
        self.lock = threading.Lock()
        self.logger = Logger().getLogger('backend.core.MessageBus')

    def registerMessageHandler(self, message_handler, message_priority_list):
        """
        Register a new MessageHandler to this MessageBus
        @param message_handler: MessageHandler object
        @param message_priority_list: Priority list for this MessageHandler
        """
        if isinstance(message_handler, MessageHandler):
            for key in message_priority_list:
                rule = (message_priority_list[key], message_handler)
                self.message_handlers[key].append(rule)
                self.message_handlers[key].sort() # Keep priority order
        else:
            self.logger.critical(
                "MessageHandler registration failed. Object " +
                repr(message_handler) +" is invalid type.")
            raise TypeError("Only MessageHandlers can be registered!")
        self.logger.debug("MessageHandler '" + str(message_handler) +
                          "' registered to the message bus.")

    def unregisterMessageHandler(self, message_handler):
        """
        Unregister MessageHandler form this MessageBus.
        @param message_handler: MessageHandler object that should be removed
        from bus
        """
        if isinstance(message_handler, MessageHandler):
            for i in range(self.NUMBER_OF_MESSAGE_TYPES):
                if len(self.message_handlers[i]) != 0:
                    rules = self.message_handlers[i]
                    for element in rules:
                        if element[1] is message_handler:
                            del element
        else:
            raise TypeError("Only MessageHandlers can be unregistered!")
        self.logger.debug("MessageHandler '" + str(message_handler) +
                          "' unregistered from the message bus.")

    def notifyMessage(self, message):
        """
        Emit a new Message to this MessageBus.
        @param message: Message object
        """
        if isinstance(message, Message):
            self.lock.acquire() # Lock messagebus
            self.logger.debug("Message bus locked. Message of type '" +
                              str(message.get_type()) + "' is on the bus.")
            handler_list = self.message_handlers[message.get_type()]
            for element in handler_list:
                element[1].handleMessage(message)
            self.lock.release() # Release messagebus lock
        else:
            message = "TypeError occured when message was notified to the bus."
            self.logger.error(message)
            exmessage = "Notified message must be instances of 'Message' type"
            raise TypeError(exmessage)
Example #2
0
class LogViewer:
    """
    Implements dialog that allows user to see logged events.

    This dialog is used to check Entertainer logfiles. It reads all data from
    selected file and saves rows to self.log_rows. Then it filters unwanted
    rows away by calling self.filterMessages(). This method adds rows to
    ListStore, which is the model of TreeView object.

    Combobox and refresh -button actions read files again
    Checkbox actions just filter current rows again
    """

    UI_DIR = os.path.join(os.path.dirname(__file__), "uis")

    # Is this dialog running as a stand alone process
    __STAND_ALONE = None

    widgets = None
    dialog = None
    log_store = None
    log_rows = []

    def __init__(self, stand_alone):
        self.logfile_entertainer = Configuration().LOG
        self.logger = Logger().getLogger('utils.log_viewer')

        self.__STAND_ALONE = stand_alone
        try:
            uifile = os.path.join(self.UI_DIR, "log_dialog.ui")
            self.builder = gtk.Builder()
            self.builder.set_translation_domain('entertainer')
            self.builder.add_from_file(uifile)
        except RuntimeError:
            self.logger.critical("Couldn't open ui file: " + uifile)
            sys.exit(1)
        callback_dic = {
            "on_close_log_button_clicked" : self.on_close_log_button_clicked,
            "on_log_refresh_button_clicked" : self.update_log_rows,
            "on_checkbutton_debug_toggled" : self.filter_messages,
            "on_checkbutton_critical_toggled" : self.filter_messages,
            "on_checkbutton_error_toggled" : self.filter_messages,
            "on_checkbutton_warning_toggled" : self.filter_messages,
            "on_checkbutton_info_toggled" : self.filter_messages }

        self.builder.connect_signals(callback_dic)

        # Create log treeview
        treeview = self.builder.get_object("treeview_log")
        cell_renderer1 = gtk.CellRendererText()
        cell_renderer2 = gtk.CellRendererText()
        cell_renderer3 = gtk.CellRendererText()
        cell_renderer4 = gtk.CellRendererText()

        column1 = gtk.TreeViewColumn("Date")
        column1.pack_start(cell_renderer1, True)
        column1.set_attributes(cell_renderer1, text = 0)

        column2 = gtk.TreeViewColumn("Time")
        column2.pack_start(cell_renderer2, True)
        column2.set_attributes(cell_renderer2, text = 1)

        column3 = gtk.TreeViewColumn("Type")
        column3.pack_start(cell_renderer3, True)
        column3.set_attributes(cell_renderer3, text = 2)

        column4 = gtk.TreeViewColumn("Message")
        column4.pack_end(cell_renderer4, True)
        column4.set_attributes(cell_renderer4, text = 3)

        treeview.append_column(column1)
        treeview.append_column(column2)
        treeview.append_column(column3)
        treeview.append_column(column4)
        treeview.set_headers_visible(True)

        # Set model to view and read data from logfile
        self.log_store = gtk.ListStore(str, str, str, str)
        treeview.set_model(self.log_store)
        self.update_log_rows()

        # Show Log viewer dialog
        self.dialog = self.builder.get_object("LogDialog")
        self.dialog.resize(750, 500)
        self.dialog.connect("destroy", self.on_close_log_button_clicked)
        self.dialog.show()

    def update_log_rows(self, widget=None):
        """Read logfile and udpate treeview"""
        self.log_rows[:] = []

        try:
            for line in open(self.logfile_entertainer, 'r'):
                try:
                    line_table = line.split()
                    message = ' '.join(line_table[3:])
                    row = line_table[:3] + [message]
                    parsed_row = parse_row(row)
                    self.log_rows.append(parsed_row)
                except IndexError:
                    print "Cannot parse log line: ", line
        except IOError:
            print "Cannot find logfile: ", self.logfile_entertainer

        # Reverse so that the latest message is at top
        self.log_rows.reverse()
        # Filter unwated message types
        self.filter_messages()

    def filter_messages(self, widget = None):
        """Checks which message types should be displayed on treeview"""
        if self.log_store:
            self.log_store.clear()

        debug = self.builder.get_object("checkbutton_debug").get_active()
        critical = self.builder.get_object("checkbutton_critical").get_active()
        error = self.builder.get_object("checkbutton_error").get_active()
        warning = self.builder.get_object("checkbutton_warning").get_active()
        info = self.builder.get_object("checkbutton_info").get_active()

        for element in self.log_rows:
            if element[2] == "DEBUG" and debug:
                self.log_store.append(element)
            elif element[2] == "CRITICAL" and critical:
                self.log_store.append(element)
            elif element[2] == "ERROR" and error:
                self.log_store.append(element)
            elif element[2] == "WARNING" and warning:
                self.log_store.append(element)
            elif element[2] == "INFO" and info:
                self.log_store.append(element)

    # Signal handlers
    def on_close_log_button_clicked(self, widget):
        """
        If running as a stand alone process, quit.
        Otherwise only destroy dialog.
        """
        self.dialog.hide()
        self.dialog.destroy()
        if(self.__STAND_ALONE):
            gtk.main_quit()