package org.yamcs.ui.eventviewer; import java.util.Observable; import java.util.Observer; import java.util.Vector; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.table.AbstractTableModel; import org.yamcs.protobuf.Yamcs.Event; import org.yamcs.ui.eventviewer.FilteringRule.FilteringRuleFactory; /** * Table with filtering rules. The rules are matched from top to bottom, there * is always default rule. If none of the rules does apply for the event, then * the default rule is used. All rules are stored in the Preferences backing * store. */ public class FilteringRulesTable extends AbstractTableModel { /** Raw list of filtering rules */ private Vector<FilteringRule> rules = null; /** Storage of application preferences */ private Preferences prefs = null; /** Key into the storage - number of saved filtering rules */ private static final String FILTERING_RULES_NUM_KEY = "/Filtering/NoOfRules"; /** Table columns */ static final String[] columnNames = { "Active", "Rule name", "Source", "Event Type", "Event Message", "Severity", "Alert", "Show" }; /** Observable implementation */ class TheObservable extends Observable { /** * Signal change. */ public void forceChanged() { setChanged(); } /** * Notify all observers. */ public void doNotifyAllObservers() { notifyObservers(); } } /** * Observable - I have to use aggregation because no multiply inheritance is * possible */ private TheObservable theObservable = null; /** Table column indices */ public static final int ACTIVE_COL = 0; public static final int RULE_NAME_COL = 1; public static final int SOURCE_COL = 2; public static final int EVENT_TYPE_COL = 3; public static final int EVENT_MESSAGE_COL = 4; public static final int SEVERITY_COL = 5; public static final int ALERT_COL = 6; public static final int SHOW_COL = 7; /** * Constructor. */ public FilteringRulesTable() { prefs = Preferences.userNodeForPackage(this.getClass()); theObservable = new TheObservable(); readFilteringRules(); } /** * Add observers. * @param observer Observer to be added. */ public void registerObserver(Observer observer) { theObservable.addObserver(observer); } /** * Notify all observers */ public void doNotifyAllObservers() { theObservable.doNotifyAllObservers(); } /** * Add rule into the list of rules. New rule is added on the beginning of * the list. * * @param rule Rule to be added */ public void addRule(FilteringRule rule, int index) { rules.insertElementAt(rule, index); fireTableRowsInserted(index, index); theObservable.forceChanged(); writeFilteringRules(); } /** * Access to rule on the specified index. * @param index Index of the rule * @return Rule at the index. */ public FilteringRule getRule(int index) { return rules.elementAt(index); } /** * Switch active status of the rule * @param index Index of the rule * @param active Status to be set. */ public void switchRuleActivation(int index, boolean active) { getRule(index).setActive(active); theObservable.forceChanged(); doNotifyAllObservers(); writeFilteringRules(); } /** * Number of rules in the table. * @return Number of rules in the table. */ public int getSize() { return rules.size(); } /** * Remove rule on the index. * @param index Index of the rule to be removed */ public void removeRule(int index) { rules.remove(index); fireTableRowsDeleted(index, index); theObservable.forceChanged(); writeFilteringRules(); } /** * Access to the raw filtering table. * @return Vector with rules. */ public Vector<FilteringRule> getRules() { // this method should create deep copy somewhere in the future return rules; } /** * Switch rules on the specified positions. * @param xpos Position of the first rule * @param ypos Position of the second rule */ public void switchRules(int xpos, int ypos) { FilteringRule tempRule = rules.set(xpos, rules.elementAt(ypos)); rules.set(ypos, tempRule); // order so we can notify the table with valid range [xpos, ypos] if (xpos > ypos) { int temp = xpos; xpos = ypos; ypos = temp; } fireTableRowsUpdated(xpos, ypos); theObservable.forceChanged(); writeFilteringRules(); } /** * Obtain names of all filtering rules. * @return Vector containing names of all filtering rules in the same order * as the rules are applied. */ public Vector<String> getNames() { Vector<String> names = new Vector<String>(); for (FilteringRule rule : rules) { names.add(rule.getName()); } return names; } /** * Match event against the filtering table and find the rule which matches * that event. No other action is done, only the rule is determined. The * application of the rule is on the caller. * @param event Event matched against the filtering table * @return Rule matched by the event. Not null, always a rule is returned. */ private FilteringRule matchFilteringRule(Event event) { for (FilteringRule rule : rules) { if (rule.isActive()) { if (GlobUtils.isMatchGlob(rule.getSource(), event.getSource()) && GlobUtils.isMatchGlob(rule.getEventType(), event.getType()) && GlobUtils.isMatchGlob(rule.getEventText(), event.getMessage()) && rule.matchSeverity(event.getSeverity())) { return rule; } } } // otherwise super default filtering rule return FilteringRuleFactory.createDefaultFilteringRule(); } /** * Access to filtering rule on the specified index. * @param index Index of the rule * @return Rule on the specified index. */ public FilteringRule getFilteringRule(int index) { return rules.elementAt(index); } /** * Query about the event visibility * @param event Event to be queried * @return True if event has to be shown */ public boolean isEventVisible(Event event) { FilteringRule rule = matchFilteringRule(event); return rule.isShowOn(); } /** * Store all filtering rules to storage. */ public void writeFilteringRules() { try { // remove all old rules if (Preferences.userRoot().nodeExists("/Filtering")) { Preferences.userRoot().node("/Filtering").removeNode(); } prefs.putInt(FILTERING_RULES_NUM_KEY, rules.size()); for (int i = 0; i < rules.size(); ++i) { String ruleNoKey = "/Filtering/Rule" + i; prefs.put(ruleNoKey + "/Name", rules.elementAt(i).getName()); prefs.put(ruleNoKey + "/Source", rules.elementAt(i).getSource()); prefs.put(ruleNoKey + "/EventType", rules.elementAt(i).getEventType()); prefs.put(ruleNoKey + "/EventText", rules.elementAt(i).getEventText()); prefs.put(ruleNoKey + "/AlertType", rules.elementAt(i).getAlertType().toString()); prefs.putBoolean(ruleNoKey + "/IsShowOn", rules.elementAt(i).isShowOn()); prefs.putBoolean(ruleNoKey + "/IsActive", rules.elementAt(i).isActive()); prefs.put(ruleNoKey + "/Severity", rules.elementAt(i).getSeverityAsText()); } } catch (BackingStoreException e) { prefs.putInt(FILTERING_RULES_NUM_KEY, 0); } } /** * Read particular filtering rule from storage * @param ruleNo Number of the rule * @return Filtering rule stored under the concrete number */ private FilteringRule readFilteringRule(int ruleNo) { FilteringRule rule = new FilteringRule(); String ruleNoKey = "/Filtering/Rule" + ruleNo; rule.setName(prefs.get(ruleNoKey + "/Name", "")); rule.setSource(prefs.get(ruleNoKey + "/Source", "")); rule.setEventType(prefs.get(ruleNoKey + "/EventType", "")); rule.setEventText(prefs.get(ruleNoKey + "/EventText", "")); rule.setAlertType(AlertSetting.valueOf(prefs.get(ruleNoKey + "/AlertType", "None"))); rule.setShowOn(prefs.getBoolean(ruleNoKey + "/IsShowOn", false)); rule.setActive(prefs.getBoolean(ruleNoKey + "/IsActive", false)); rule.setSeverityFromText(prefs.get(ruleNoKey + "/Severity", "All")); return rule; } /** * Retrieve all filtering rules from storage. */ private void readFilteringRules() { rules = new Vector<FilteringRule>(); int rulesNo = getNumOfFilteringRules(); for (int i = 0; i < rulesNo; ++i) { rules.add(readFilteringRule(i)); } if (rules.size() == 0) { // add default rules rules.add(FilteringRuleFactory.createWarningAndErrorsFilteringRule()); rules.add(FilteringRuleFactory.createDefaultFilteringRule()); } theObservable.forceChanged(); } /** * Number of event filtering rules in storage. * @return Number of stored event filtering rules. */ private int getNumOfFilteringRules() { return prefs.getInt(FILTERING_RULES_NUM_KEY, 0); } /** * * @param event * @return */ public AlertType getAlertType(Event event) { AlertType alert = new AlertType(); FilteringRule rule = matchFilteringRule(event); switch (rule.getAlertType()) { case AlertNone: alert.alertPopup = false; alert.alertSound = false; break; case AlertPopUp: alert.alertPopup = true; alert.alertSound = false; break; case AlertSound: alert.alertPopup = false; alert.alertSound = true; break; default: alert.alertPopup = false; alert.alertSound = false; break; } return alert; } @Override public String getColumnName(int col) { return columnNames[col]; } @Override public Class getColumnClass(int col) { if (col == FilteringRulesTable.ACTIVE_COL) { return Boolean.class; } return getValueAt(0, col).getClass(); } @Override public int getRowCount() { return getSize(); } @Override public int getColumnCount() { return columnNames.length; } @Override public Object getValueAt(int rowIndex, int columnIndex) { FilteringRule rule = getFilteringRule(rowIndex); Object value = null; switch (columnIndex) { case FilteringRulesTable.ACTIVE_COL: value = rule.isActive(); break; case FilteringRulesTable.RULE_NAME_COL: value = rule.getName(); break; case FilteringRulesTable.SOURCE_COL: value = rule.getSource(); break; case FilteringRulesTable.EVENT_TYPE_COL: value = rule.getEventType(); break; case FilteringRulesTable.EVENT_MESSAGE_COL: value = rule.getEventText(); break; case FilteringRulesTable.SEVERITY_COL: value = rule.getSeverityAsText(); break; case FilteringRulesTable.ALERT_COL: value = rule.getAlertAsText(); break; case FilteringRulesTable.SHOW_COL: value = rule.getShowAsText(); break; default: break; } return value; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { FilteringRule rule = getFilteringRule(rowIndex); switch (columnIndex) { case FilteringRulesTable.ACTIVE_COL: rule.setActive((Boolean) aValue); break; case FilteringRulesTable.RULE_NAME_COL: rule.setName((String) aValue); break; case FilteringRulesTable.SOURCE_COL: rule.setSource((String) aValue); break; case FilteringRulesTable.EVENT_TYPE_COL: rule.setEventType((String) aValue); break; case FilteringRulesTable.EVENT_MESSAGE_COL: rule.setEventText((String) aValue); break; case FilteringRulesTable.SEVERITY_COL: rule.setSeverityFromText((String) aValue); break; case FilteringRulesTable.ALERT_COL: rule.setAlertFromText((String) aValue); break; case FilteringRulesTable.SHOW_COL: rule.setShowOn(((String) aValue).equalsIgnoreCase("Yes")); break; default: break; } writeFilteringRules(); theObservable.forceChanged(); } }