/* * Emitter.java * Copyright (C) 2011,2012 Wannes De Smet * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.xenmaster.monitoring; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.wgr.core.ReflectionUtils; import net.wgr.lang.I18N; import net.wgr.wcp.Commander; import net.wgr.wcp.Scope; import net.wgr.wcp.command.Command; import org.apache.log4j.Logger; import org.xenmaster.api.entity.Event; import org.xenmaster.api.entity.NamedEntity; import org.xenmaster.api.entity.Task; import org.xenmaster.api.util.CachingFacility; import org.xenmaster.monitoring.LogEntry.Level; /** * Issues requested monitoring data "formally and with authority" * @created Oct 30, 2011 * @author double-u */ public class Emitter { protected List<EventDescriptor> descriptors; public Emitter() { descriptors = new ArrayList<>(); buildDescriptors(); } protected final void buildDescriptors() { try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/trans_" + I18N.instance().getDefaultLocale().getLanguage() + ".events")))) { String line; while ((line = br.readLine()) != null) { if (line.startsWith("#")) { continue; } descriptors.add(EventDescriptor.fromString(line)); } } catch (IOException ex) { Logger.getLogger(getClass()).error("Failed to read event file", ex); } } public void listenToEvents(EventHandler eh) { eh.addListener(new EventHandler.EventListener() { @Override public void eventOcurred(Event event) { if (event.getSnapshot() == null) { return; } // Task come and go too quickly, they are mostly already gone before we can get their reference boolean hasValidReference = event.getOperation() == Event.Operation.MOD && !(event.getSnapshot() instanceof Task); String reference = event.getSnapshot().getReference(hasValidReference); Object cachedObject = CachingFacility.get(reference, event.getSnapshot().getClass()); Map<String, Object> diff = ReflectionUtils.diff(cachedObject, event.getSnapshot()); if (diff.size() < 1) { // Nothing was changed? return; } String title = event.getOperation().name(); String message = ""; ApiEventEntry.Level level = LogEntry.Level.INFORMATION; if (hasValidReference) { diffIt: for (Map.Entry<String, Object> d : diff.entrySet()) { for (EventDescriptor ed : descriptors) { if (event.getSnapshot() == null || d.getValue() == null) { continue; } if (ed.match(event.getSnapshot().getClass().getSimpleName(), d.getKey(), d.getValue().toString())) { title = ed.getTitle(); message = ed.getDescription(); if (NamedEntity.class.isAssignableFrom(event.getSnapshot().getClass())) { NamedEntity ne = (NamedEntity) event.getSnapshot(); title = String.format(title, ne.getName(), ne.getDescription()); message = String.format(message, ne.getName(), ne.getDescription()); level = ed.getLevel(); } break diffIt; } } } } ApiEventEntry le = new ApiEventEntry(event.getSnapshot().getReference(hasValidReference), event.getEventClass(), title, message, diff, event.getOperation().name(), level); emit(le); } }, 0); } public static void emit(LogEntry le) { LogEntry filledIn = le; filledIn.doLocalization(); Commander.get().commandeer(new Command("log", "event", le), new Scope(Scope.Target.ALL)); } protected static final class EventDescriptor { protected String className; protected String field; protected String newValue; protected String title, description; protected ApiEventEntry.Level level; protected final static Pattern EVENT_DESCRIPTOR_LINE = Pattern.compile("([^\\.]+)\\.([^:]+):([^=]+)=([^;]+);([^;]+);(.+)"); public EventDescriptor(String className, String field, String newValue, ApiEventEntry.Level level, String title, String description) { this.className = className; this.field = field; this.newValue = newValue; this.title = title; this.description = description; this.level = level; } public boolean match(String className, String fieldName, String newValue) { return this.className.equals(className) && this.field.equals(fieldName) && this.newValue.equals(newValue); } public static EventDescriptor fromString(String string) { Matcher m = EVENT_DESCRIPTOR_LINE.matcher(string); if (!m.find()) { throw new IllegalArgumentException("Event descriptor line is not valid"); } return new EventDescriptor(m.group(1).trim(), m.group(2).trim(), m.group(3).trim(), ApiEventEntry.Level.valueOf(m.group(4).trim()), m.group(5).trim(), m.group(6).trim()); } public String getClassName() { return className; } public String getField() { return field; } public String getNewValue() { return newValue; } public String getTitle() { return title; } public String getDescription() { return description; } public Level getLevel() { return level; } } }