| /********************************************************************** |
| * Copyright (c) 2018, 2019 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| **********************************************************************/ |
| package org.eclipse.tracecompass.tmf.core.model.timegraph; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.function.Predicate; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter; |
| |
| import com.google.common.collect.HashMultimap; |
| import com.google.common.collect.ImmutableMultimap; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Multimap; |
| |
| /** |
| * Implements timegraph state filtering support. This interface provide default |
| * method to provide the inputs and do the filtering. |
| * |
| * @author Jean-Christian Kouame |
| * @since 4.0 |
| */ |
| public interface ITimeGraphStateFilter { |
| |
| /** |
| * Filter the time graph state and add it to the state list |
| * |
| * @param stateList |
| * The timegraph state list |
| * @param timeGraphState |
| * The current timegraph state |
| * @param key |
| * The timegraph entry model id |
| * @param predicates |
| * The predicates used to filter the timegraph state. It is a map of |
| * predicate by property. The value of the property is an integer |
| * representing a bitmask associated to that property. The status of |
| * each property will be set for the timegraph state according to the |
| * associated predicate test result. |
| * @param monitor |
| * The progress monitor |
| * @deprecated Use the {@link #applyFilterAndAddState(List, ITimeGraphState, Long, Multimap, Map, IProgressMonitor)} instead |
| */ |
| @Deprecated |
| default void addToStateList(List<ITimeGraphState> stateList, ITimeGraphState timeGraphState, Long key, Map<Integer, Predicate<Map<String, String>>> predicates, @Nullable IProgressMonitor monitor) { |
| |
| if (!predicates.isEmpty()) { |
| // Get the filter external input data |
| long startTime = timeGraphState.getStartTime(); |
| SelectionTimeQueryFilter filter = new SelectionTimeQueryFilter(Collections.singletonList(startTime), Collections.singleton(Objects.requireNonNull(key))); |
| Map<@NonNull String, @NonNull String> input = getFilterInput(filter, monitor); |
| input.putAll(timeGraphState.computeData()); |
| |
| // Test each predicates and set the status of the property associated to the |
| // predicate |
| for (Map.Entry<Integer, Predicate<Map<String, String>>> mapEntry : predicates.entrySet()) { |
| Predicate<Map<String, String>> value = Objects.requireNonNull(mapEntry.getValue()); |
| boolean status = value.test(input); |
| Integer property = Objects.requireNonNull(mapEntry.getKey()); |
| if (property == IFilterProperty.DIMMED || property == IFilterProperty.EXCLUDE) { |
| timeGraphState.setProperty(property, !status); |
| } else { |
| timeGraphState.setProperty(property, status); |
| } |
| } |
| } |
| |
| if (timeGraphState.isPropertyActive(IFilterProperty.EXCLUDE)) { |
| TimeGraphState timeGraphState2 = new TimeGraphState(timeGraphState.getStartTime(), timeGraphState.getDuration(), Integer.MIN_VALUE); |
| timeGraphState2.setActiveProperties(timeGraphState.getActiveProperties()); |
| stateList.add(timeGraphState2); |
| } else { |
| stateList.add(timeGraphState); |
| } |
| } |
| |
| /** |
| * Filter the time graph state and add it to the state list. |
| * |
| * @param stateList |
| * The timegraph state list |
| * @param timeGraphState |
| * The current timegraph state |
| * @param entryId |
| * The timegraph entry model id |
| * @param predicates |
| * The predicates used to filter the timegraph state. It is a map |
| * of predicate by property. The value of the property is an |
| * integer representing a bitmask associated to that property. |
| * The status of each property will be set for the timegraph |
| * state according to the associated predicate test result. |
| * @param monitor |
| * The progress monitor |
| * @since 5.0 |
| */ |
| default void applyFilterAndAddState(List<ITimeGraphState> stateList, ITimeGraphState timeGraphState, Long entryId, Map<Integer, Predicate<Multimap<String, Object>>> predicates, @Nullable IProgressMonitor monitor) { |
| applyFilterAndAddState(stateList, timeGraphState, entryId, predicates, null, monitor); |
| } |
| |
| /** |
| * Filter the time graph state and add it to the state list. |
| * <p> |
| * If a list of times is specified, all states that intersect a time in the |
| * list are included. States that do not intersect any time (e.g. in gap) |
| * are only included if they are neither dimmed nor excluded, and a maximum |
| * of one state per gap is included. The method must be called in |
| * chronological order of states, otherwise the result is unspecified. |
| * |
| * @param stateList |
| * The timegraph state list |
| * @param timeGraphState |
| * The current timegraph state |
| * @param entryId |
| * The timegraph entry model id |
| * @param predicates |
| * The predicates used to filter the timegraph state. It is a map |
| * of predicate by property. The value of the property is an |
| * integer representing a bitmask associated to that property. |
| * The status of each property will be set for the timegraph |
| * state according to the associated predicate test result. |
| * @param times |
| * The list of times that should be included in the state list. |
| * If set to <code>null</code>, all matching states should be |
| * included. |
| * @param monitor |
| * The progress monitor |
| * @since 5.2 |
| */ |
| default void applyFilterAndAddState(List<ITimeGraphState> stateList, ITimeGraphState timeGraphState, Long entryId, Map<Integer, Predicate<Multimap<String, Object>>> predicates, @Nullable List<Long> times, @Nullable IProgressMonitor monitor) { |
| |
| long startTime = timeGraphState.getStartTime(); |
| long endTime = timeGraphState.getStartTime() + timeGraphState.getDuration(); |
| |
| // Discard all additional states in same gap after first match |
| if (times != null && !stateList.isEmpty()) { |
| ITimeGraphState lastState = Iterables.getLast(stateList); |
| long lastStart = lastState.getStartTime(); |
| long lastEnd = lastStart + lastState.getDuration(); |
| int index = Collections.binarySearch(times, lastStart); |
| if (index < 0) { |
| index = -index - 1; |
| if (index >= times.size()) { |
| // Skip all after the last query time |
| return; |
| } |
| if (lastEnd < times.get(index) && endTime <= times.get(index)) { |
| // If last state was in gap, skip all others in same gap |
| return; |
| } |
| } |
| } |
| |
| if (!predicates.isEmpty()) { |
| // Get the filter external input data |
| Multimap<@NonNull String, @NonNull Object> input = HashMultimap.create(); |
| input.putAll(getFilterData(entryId, startTime, monitor)); |
| input.putAll(timeGraphState.getMetadata()); |
| |
| // Test each predicates and set the status of the property |
| // associated to the predicate |
| for (Map.Entry<Integer, Predicate<Multimap<String, Object>>> mapEntry : predicates.entrySet()) { |
| Predicate<Multimap<String, Object>> value = Objects.requireNonNull(mapEntry.getValue()); |
| boolean status = value.test(input); |
| Integer property = Objects.requireNonNull(mapEntry.getKey()); |
| if (property == IFilterProperty.DIMMED || property == IFilterProperty.EXCLUDE) { |
| timeGraphState.setProperty(property, !status); |
| } else { |
| timeGraphState.setProperty(property, status); |
| } |
| } |
| } |
| |
| if (times != null && (timeGraphState.getActiveProperties() & (IFilterProperty.DIMMED | IFilterProperty.EXCLUDE)) != 0) { |
| // Do not include state in gap if it is dimmed or excluded |
| int index = Collections.binarySearch(times, startTime); |
| if (index < 0) { |
| index = -index - 1; |
| if (index >= times.size() || (endTime < times.get(index))) { |
| return; |
| } |
| } |
| } |
| |
| if (timeGraphState.isPropertyActive(IFilterProperty.EXCLUDE)) { |
| // Replace excluded state with a null state |
| TimeGraphState timeGraphState2 = new TimeGraphState(timeGraphState.getStartTime(), timeGraphState.getDuration(), Integer.MIN_VALUE); |
| timeGraphState2.setActiveProperties(timeGraphState.getActiveProperties()); |
| stateList.add(timeGraphState2); |
| } else { |
| stateList.add(timeGraphState); |
| } |
| } |
| |
| /** |
| * Get input data used for filtering |
| * |
| * @param filter |
| * The selection time query filter |
| * @param monitor |
| * The progress monitor |
| * @return The map of input data |
| * @deprecated Use the {@link #getFilterData(long, long, IProgressMonitor)} instead |
| */ |
| @Deprecated |
| default Map<String, String> getFilterInput(SelectionTimeQueryFilter filter, @Nullable IProgressMonitor monitor) { |
| return new HashMap<>(); |
| } |
| |
| /** |
| * Get input data used for filtering |
| * |
| * @param entryId |
| * The ID of the entry |
| * @param time |
| * The time at which to get data |
| * @param monitor |
| * The progress monitor |
| * @return The map of input data |
| * @since 5.0 |
| */ |
| default Multimap<String, Object> getFilterData(long entryId, long time, @Nullable IProgressMonitor monitor) { |
| return ImmutableMultimap.of(); |
| } |
| |
| /** |
| * Merge multiple multimaps into one. The resulting map is not immutable so |
| * callers can fill it with additional data. |
| * |
| * @param maps |
| * The maps to merge |
| * @return A multimap that is the result of the merge of the maps in |
| * arguments |
| * @since 5.0 |
| */ |
| @SafeVarargs |
| static Multimap<String, Object> mergeMultimaps(Multimap<String, Object>... maps) { |
| Multimap<@NonNull String, @NonNull Object> data = HashMultimap.create(); |
| for (Multimap<String, Object> multimap : maps) { |
| data.putAll(multimap); |
| } |
| return data; |
| } |
| } |