/******************************************************************************* * Copyright (c) 2013 École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Geneviève Bastien - Initial implementation and API *******************************************************************************/ package fr.inria.linuxtools.tmf.core.event.matching; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import fr.inria.linuxtools.internal.tmf.core.Activator; import fr.inria.linuxtools.tmf.core.event.ITmfEvent; import fr.inria.linuxtools.tmf.core.request.ITmfEventRequest; import fr.inria.linuxtools.tmf.core.request.TmfEventRequest; import fr.inria.linuxtools.tmf.core.timestamp.TmfTimeRange; import fr.inria.linuxtools.tmf.core.trace.ITmfTrace; /** * Abstract class to extend to match certain type of events in a trace * * @author Geneviève Bastien * @since 3.0 */ public abstract class TmfEventMatching implements ITmfEventMatching { /** * The matching type * * FIXME Not the best place to put this. Have an array of match types as a * parameter of each trace? */ public enum MatchingType { /** * NETWORK, match network events */ NETWORK } /** * The array of traces to match */ private final Collection<ITmfTrace> fTraces; /** * The class to call once a match is found */ private final IMatchProcessingUnit fMatches; private static final Map<MatchingType, List<ITmfMatchEventDefinition>> fMatchDefinitions = new HashMap<>(); private final Map<ITmfTrace, ITmfMatchEventDefinition> fMatchMap = new HashMap<>(); /** * Constructor with multiple traces and a match processing object * * @param traces * The set of traces for which to match events * @param tmfEventMatches * The match processing class */ public TmfEventMatching(Collection<ITmfTrace> traces, IMatchProcessingUnit tmfEventMatches) { if (tmfEventMatches == null) { throw new IllegalArgumentException(); } fTraces = traces; fMatches = tmfEventMatches; } /** * Returns the traces to process * * @return The traces */ protected Collection<? extends ITmfTrace> getTraces() { return fTraces; } /** * Returns the match processing unit * * @return The match processing unit */ protected IMatchProcessingUnit getProcessingUnit() { return fMatches; } /** * Returns the match event definition corresponding to the trace * * @param trace * The trace * @return The match event definition object */ protected ITmfMatchEventDefinition getEventDefinition(ITmfTrace trace) { return fMatchMap.get(trace); } /** * Method that initializes any data structure for the event matching. It * also assigns to each trace an event matching definition instance that * applies to the trace */ protected void initMatching() { fMatches.init(fTraces); List<ITmfMatchEventDefinition> deflist = fMatchDefinitions.get(getMatchingType()); if (deflist == null) { return; } for (ITmfTrace trace : fTraces) { for (ITmfMatchEventDefinition def : deflist) { if (def.canMatchTrace(trace)) { fMatchMap.put(trace, def); break; } } } } /** * Calls any post matching methods of the processing class */ protected void finalizeMatching() { fMatches.matchingEnded(); } /** * Prints stats from the matching * * @return string of statistics */ @SuppressWarnings("nls") @Override public String toString() { return getClass().getSimpleName() + " [ " + fMatches + " ]"; } /** * Matches one event * * @param event * The event to match * @param trace * The trace to which this event belongs */ protected abstract void matchEvent(ITmfEvent event, ITmfTrace trace); /** * Returns the matching type this class implements * * @return A matching type */ protected abstract MatchingType getMatchingType(); /** * Method that start the process of matching events * * @return Whether the match was completed correctly or not */ @Override public boolean matchEvents() { /* Are there traces to match? If no, return false */ if (!(fTraces.size() > 0)) { return false; } // TODO Start a new thread here? initMatching(); /** * For each trace, get the events and for each event, call the * MatchEvent method * * FIXME This would use a lot of memory if the traces are big, because * all involved events from first trace will have to be kept before a * first match is possible with second trace. * * <pre> * Other possible matching strategy: * Incremental: * Sliding window: * Other strategy: start with the shortest trace, take a few events * at the beginning and at the end * Experiment strategy: have the experiment do the request, then events will * come from both traces chronologically, but then instead of ITmfTrace[], it * would be preferable to have experiment * </pre> */ for (ITmfTrace trace : fTraces) { EventMatchingBuildRequest request = new EventMatchingBuildRequest(this, trace); /* * Send the request to the trace here, since there is probably no * experiment. */ trace.sendRequest(request); try { request.waitForCompletion(); } catch (InterruptedException e) { Activator.logInfo(e.getMessage()); } } finalizeMatching(); return true; } /** * Registers an event match definition to be used for a certain match type * * @param match * The event matching definition */ public static void registerMatchObject(ITmfMatchEventDefinition match) { for (MatchingType type : match.getApplicableMatchingTypes()) { if (!fMatchDefinitions.containsKey(type)) { fMatchDefinitions.put(type, new ArrayList<ITmfMatchEventDefinition>()); } fMatchDefinitions.get(type).add(match); } } } class EventMatchingBuildRequest extends TmfEventRequest { private final TmfEventMatching matching; private final ITmfTrace trace; EventMatchingBuildRequest(TmfEventMatching matching, ITmfTrace trace) { super(ITmfEvent.class, TmfTimeRange.ETERNITY, 0, ITmfEventRequest.ALL_DATA, ITmfEventRequest.ExecutionType.FOREGROUND); this.matching = matching; this.trace = trace; } @Override public void handleData(final ITmfEvent event) { super.handleData(event); matching.matchEvent(event, trace); } @Override public void handleSuccess() { super.handleSuccess(); } @Override public void handleCancel() { super.handleCancel(); } @Override public void handleFailure() { super.handleFailure(); } }