package org.ovirt.engine.core.notifier.filter; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.ovirt.engine.core.common.AuditLogSeverity; import org.ovirt.engine.core.common.utils.ToStringBuilder; import org.ovirt.engine.core.notifier.transport.Transport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FirstMatchSimpleFilter { private static final Pattern PATTERN_BLANK = Pattern.compile("\\s*"); private static final Pattern PATTERN_PARSE = Pattern.compile( "\\s*" + "((?<include>include)|(?<exclude>exclude))" + ":" + "((?<anymsg>\\*)|(?<message>\\w+))" + "(" + ":" + "(?<severity>\\*|ALERT|ERROR|WARNING|NORMAL)" + ")?" + "(?<recipient>" + "\\(" + "(" + "(?<anyrecipient>\\*)|" + "(?<transport>\\w+):(?<name>[^)]*)" + ")" + "\\)" + ")?" + "\\s*" + "" ); private static final Logger log = LoggerFactory.getLogger(FirstMatchSimpleFilter.class); private Map<String, Transport> transports = new HashMap<>(); private List<FilterEntry> notify = new LinkedList<>(); private Set<Recipient> recipients = new HashSet<>(); public void registerTransport(Transport transport) { transports.put(transport.getName(), transport); } public void unregisterTransport(Transport transport) { transports.remove(transport.getName()); } private void addRecipient(Recipient recipient) { recipients.add(recipient); } public void addFilterEntries(List<FilterEntry> entries) { for (FilterEntry entry : entries) { log.debug("addFilterEntry: {}", entry); notify.add(entry); if (entry.getRecipient() != null) { addRecipient(entry.getRecipient()); } } } public void clearFilterEntries() { notify.clear(); recipients.clear(); } public void processEvent(AuditLogEvent event) { log.debug("Event: {}", event.getName()); for (Recipient recipient : recipients) { log.debug("Recipient: {}", recipient); for (FilterEntry entry : notify) { if (( entry.getEventName() == null || entry.getEventName().equals(event.getName()) ) && ( entry.getSeverity() == null || (entry.isExclude() ? -1 : 1) * event.getSeverity().compareTo(entry.getSeverity()) >= 0 ) && ( entry.getRecipient() == null || entry.getRecipient().equals(recipient) )) { log.debug("Entry match(({})): {}", entry.isExclude() ? "exclude" : "include", entry); if (!entry.isExclude()) { Transport transport = transports.get(recipient.getTransport()); if (transport == null) { log.debug("Ignoring recipient '{}' as transport not registered", recipient); } else { transport.dispatchEvent(event, recipient.getName()); } } break; } } } } public static List<FilterEntry> parse(String filters) { List<FilterEntry> ret = new LinkedList<>(); if (!PATTERN_BLANK.matcher(filters).matches()) { Matcher m = PATTERN_PARSE.matcher(filters); boolean ok = false; int expectedStart = 0; while (m.find()) { log.debug("parse: handling '{}'", m.group(0)); if (m.start() != expectedStart) { throw new RuntimeException("Cannot parse filters"); } expectedStart = m.end(); ok = m.end() == m.regionEnd(); ret.add( new FilterEntry( m.group("anymsg") != null ? null : m.group("message"), m.group("severity") == null || m.group("severity").equals("*") ? null : AuditLogSeverity.valueOf(m.group("severity")), m.group("exclude") != null, m.group("recipient") == null || m.group("anyrecipient") != null ? null : new Recipient( m.group("transport"), m.group("name") ) ) ); } if (!ok) { throw new IllegalArgumentException("Cannot parse filters"); } } return ret; } public static class Recipient { private final String transport; private final String name; public Recipient(String transport, String name) { this.transport = transport; this.name = name; } public String getTransport() { return transport; } public String getName() { return name; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Recipient)) { return false; } Recipient other = (Recipient) obj; return Objects.equals(transport, other.transport) && Objects.equals(name, other.name); } @Override public int hashCode() { return Objects.hash( transport, name ); } @Override public String toString() { return ToStringBuilder.forInstance(this) .append("transport", transport) .append("name", name) .build(); } } public static class FilterEntry { private final String eventName; private final AuditLogSeverity severity; private final boolean exclude; private final Recipient recipient; public FilterEntry(String eventName, AuditLogSeverity severity, boolean exclude, Recipient recipient) { this.eventName = eventName; this.severity = severity; this.exclude = exclude; this.recipient = recipient; } public FilterEntry(String eventName, AuditLogSeverity severity, boolean exclude, String transport, String name) { this(eventName, severity, exclude, new Recipient(transport, name)); } public String getEventName() { return eventName; } public AuditLogSeverity getSeverity() { return severity; } public boolean isExclude() { return exclude; } public Recipient getRecipient() { return recipient; } @Override public String toString() { return ToStringBuilder.forInstance(this) .append("eventName", eventName) .append("severity", severity != null ? severity.name() : "any") .append("exclude", exclude) .append("recipient", recipient) .build(); } } }