b32bc6487b60ae960ee0b7bf14a376b3533c94bf
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / trace / TmfTraceUtils.java
1 /*******************************************************************************
2 * Copyright (c) 2014 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.tmf.core.trace;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.io.BufferedInputStream;
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Optional;
24 import java.util.function.Predicate;
25
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.eclipse.tracecompass.common.core.StreamUtils;
30 import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
31 import org.eclipse.tracecompass.tmf.core.component.ITmfEventProvider;
32 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
33 import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
34 import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
35
36 import com.google.common.collect.Iterables;
37 import com.google.common.collect.Lists;
38
39 /**
40 * Utility methods for ITmfTrace's.
41 *
42 * @author Alexandre Montplaisir
43 */
44 @NonNullByDefault
45 public final class TmfTraceUtils {
46
47 private static final int MAX_NB_BINARY_BYTES = 2048;
48
49 private TmfTraceUtils() {
50 }
51
52 /**
53 * Return the first result of the first analysis module belonging to this trace or its children,
54 * with the specified ID and class.
55 *
56 * @param trace
57 * The trace for which you want the modules
58 * @param moduleClass
59 * Returned modules must extend this class
60 * @param id
61 * The ID of the analysis module
62 * @return The analysis module with specified class and ID, or null if no
63 * such module exists.
64 */
65 public static @Nullable <T extends IAnalysisModule> T getAnalysisModuleOfClass(ITmfTrace trace,
66 Class<T> moduleClass, String id) {
67 Iterable<T> modules = getAnalysisModulesOfClass(trace, moduleClass);
68 for (T module : modules) {
69 if (id.equals(module.getId())) {
70 return module;
71 }
72 }
73 return null;
74 }
75
76 /**
77 * Return the analysis modules that are of a given class. The modules will be
78 * cast to the requested class. If the trace has children, the childrens modules
79 * are also returned.
80 *
81 * @param trace
82 * The trace for which you want the modules, the children trace modules
83 * are added as well.
84 * @param moduleClass
85 * Returned modules must extend this class
86 * @return List of modules of class moduleClass
87 */
88 public static <T> Iterable<@NonNull T> getAnalysisModulesOfClass(ITmfTrace trace, Class<T> moduleClass) {
89 Iterable<IAnalysisModule> analysisModules = trace.getAnalysisModules();
90 List<@NonNull T> modules = new ArrayList<>();
91 for (IAnalysisModule module : analysisModules) {
92 if (moduleClass.isAssignableFrom(module.getClass())) {
93 modules.add(checkNotNull(moduleClass.cast(module)));
94 }
95 }
96 for (ITmfEventProvider child : trace.getChildren()) {
97 if (child instanceof ITmfTrace) {
98 ITmfTrace childTrace = (ITmfTrace) child;
99 Iterables.addAll(modules, getAnalysisModulesOfClass(childTrace, moduleClass));
100 }
101 }
102 return modules;
103 }
104
105 /**
106 * Return the first result of the first aspect that resolves as non null for
107 * the event received in parameter. If the returned value is not null, it
108 * can be safely cast to the aspect's class proper return type.
109 *
110 * @param trace
111 * The trace for which you want the event aspects
112 * @param aspectClass
113 * The class of the aspect(s) to resolve
114 * @param event
115 * The event for which to get the aspect
116 * @return The first result of the
117 * {@link ITmfEventAspect#resolve(ITmfEvent)} that returns non null
118 * for the event or {@code null} otherwise
119 */
120 public static <T extends ITmfEventAspect<?>> @Nullable Object resolveEventAspectOfClassForEvent(
121 ITmfTrace trace, Class<T> aspectClass, ITmfEvent event) {
122 return StreamUtils.getStream(trace.getEventAspects())
123 .filter(aspect -> aspectClass.isAssignableFrom(aspect.getClass()))
124 .map(aspect -> aspect.resolve(event))
125 .filter(obj -> obj != null)
126 .findFirst().orElse(null);
127 }
128
129 /**
130 * Return the first result of the first aspect that resolves as a non-null
131 * Integer for the event received in parameter. If no matching aspects are
132 * found then null is returned.
133 *
134 * @param trace
135 * The trace for which you want the event aspects
136 * @param aspectClass
137 * The class of the aspect(s) to resolve
138 * @param event
139 * The event for which to get the aspect
140 * @return Integer of the first result of the
141 * {@link ITmfEventAspect#resolve(ITmfEvent)} that returns non null
142 * for the event or {@code null} otherwise
143 * @since 2.0
144 */
145 public static <T extends ITmfEventAspect<Integer>> @Nullable Integer resolveIntEventAspectOfClassForEvent(
146 ITmfTrace trace, Class<T> aspectClass, ITmfEvent event) {
147 return StreamUtils.getStream(trace.getEventAspects())
148 .filter(aspect -> aspectClass.isAssignableFrom(aspect.getClass()))
149 /* Enforced by the T parameter bounding */
150 .map(aspect -> (Integer) aspect.resolve(event))
151 .filter(obj -> obj != null)
152 .findFirst().orElse(null);
153 }
154
155 /**
156 * Checks for text file.
157 *
158 * Note that it checks for binary value 0 in the first MAX_NB_BINARY_BYTES
159 * bytes to determine if the file is text.
160 *
161 * @param file
162 * the file to check. Caller has to make sure that file exists.
163 * @return true if it is binary else false
164 * @throws IOException
165 * if IOException occurs
166 * @since 1.2
167 */
168 public static boolean isText(File file) throws IOException {
169 try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file))) {
170 int count = 0;
171 int val = bufferedInputStream.read();
172 while ((count < MAX_NB_BINARY_BYTES) && (val >= 0)) {
173 if (val == 0) {
174 return false;
175 }
176 count++;
177 val = bufferedInputStream.read();
178 }
179 }
180 return true;
181 }
182
183 // ------------------------------------------------------------------------
184 // Event matching methods
185 // ------------------------------------------------------------------------
186
187 /**
188 * Retrieve from a trace the next event, from a starting rank, matching the
189 * given predicate.
190 *
191 * @param trace
192 * The trace
193 * @param startRank
194 * The rank of the event at which to start searching. Use
195 * <code>0</code> to search from the start of the trace.
196 * @param predicate
197 * The predicate to test events against
198 * @return The first event matching the predicate, or null if the end of the
199 * trace was reached and no event was found
200 * @since 2.1
201 */
202 public static @Nullable ITmfEvent getNextEventMatching(ITmfTrace trace, long startRank, Predicate<ITmfEvent> predicate) {
203 /* rank + 1 because we do not want to include the start event itself in the search */
204 EventMatchingRequest req = new EventMatchingRequest(startRank + 1, predicate, false);
205 trace.sendRequest(req);
206 try {
207 req.waitForCompletion();
208 } catch (InterruptedException e) {
209 return null;
210 }
211
212 return req.getFoundEvent();
213 }
214
215 /**
216 * Retrieve from a trace the previous event, from a given rank, matching the
217 * given predicate.
218 *
219 * @param trace
220 * The trace
221 * @param startRank
222 * The rank of the event at which to start searching backwards.
223 * @param predicate
224 * The predicate to test events against
225 * @return The first event found matching the predicate, or null if the
226 * beginning of the trace was reached and no event was found
227 * @since 2.1
228 */
229 public static @Nullable ITmfEvent getPreviousEventMatching(ITmfTrace trace, long startRank, Predicate<ITmfEvent> predicate) {
230 /*
231 * We are going to do a series of queries matching the trace's cache
232 * size in length (which should minimize on-disk seeks), then iterate on
233 * the found events in reverse order until we find a match.
234 */
235 int step = trace.getCacheSize();
236
237 /*
238 * If we are close to the beginning of the trace, make sure we only look
239 * for the events before the startRank.
240 */
241 if (startRank < step) {
242 step = (int) startRank;
243 }
244
245 long currentRank = startRank;
246 try {
247 while (currentRank > 0) {
248 currentRank = Math.max(currentRank - step, 0);
249
250 List<ITmfEvent> list = new ArrayList<>(step);
251 ArrayFillingRequest req = new ArrayFillingRequest(currentRank, step, list);
252 trace.sendRequest(req);
253 req.waitForCompletion();
254
255 Optional<ITmfEvent> matchingEvent = Lists.reverse(list).stream()
256 .filter(predicate)
257 .findFirst();
258
259 if (matchingEvent.isPresent()) {
260 /* We found an event matching, return it! */
261 return matchingEvent.get();
262 }
263 /* Keep searching, next loop */
264
265 }
266 } catch (InterruptedException e) {
267 return null;
268 }
269
270 /*
271 * We searched up to the beginning of the trace and didn't find
272 * anything.
273 */
274 return null;
275
276 }
277
278 /**
279 * Event request looking for an event matching a Predicate.
280 */
281 private static class EventMatchingRequest extends TmfEventRequest {
282
283 private final Predicate<ITmfEvent> fPredicate;
284 private final boolean fReturnLast;
285
286 private @Nullable ITmfEvent fFoundEvent = null;
287
288 /**
289 * Basic constructor, will query the trace until the end.
290 *
291 * @param startRank
292 * The rank at which to start, use 0 for the beginning
293 * @param predicate
294 * The predicate to test against each event
295 * @param returnLast
296 * Should we return the last or first event found. If false,
297 * the request ends as soon as a matching event is found. If
298 * false, we will go through all events to find a possible
299 * last-match.
300 */
301 public EventMatchingRequest(long startRank, Predicate<ITmfEvent> predicate, boolean returnLast) {
302 super(ITmfEvent.class, startRank, ALL_DATA, ExecutionType.FOREGROUND);
303 fPredicate = predicate;
304 fReturnLast = returnLast;
305 }
306
307 /**
308 * Basic constructor, will query the trace the limit is reached.
309 *
310 * @param startRank
311 * The rank at which to start, use 0 for the beginning
312 * @param limit
313 * The limit on the number of events
314 * @param predicate
315 * The predicate to test against each event
316 * @param returnLast
317 * Should we return the last or first event found. If false,
318 * the request ends as soon as a matching event is found. If
319 * false, we will go through all events to find a possible
320 * last-match.
321 */
322 public EventMatchingRequest(long startRank, int limit, Predicate<ITmfEvent> predicate, boolean returnLast) {
323 super(ITmfEvent.class, startRank, limit, ExecutionType.FOREGROUND);
324 fPredicate = predicate;
325 fReturnLast = returnLast;
326 }
327
328 public @Nullable ITmfEvent getFoundEvent() {
329 return fFoundEvent;
330 }
331
332 @Override
333 public void handleData(ITmfEvent event) {
334 super.handleData(event);
335
336 if (fPredicate.test(event)) {
337 fFoundEvent = event;
338 if (!fReturnLast) {
339 this.done();
340 }
341 }
342 }
343 }
344
345 /**
346 * Event request that simply puts all returned events into a list passed in
347 * parameter.
348 */
349 private static class ArrayFillingRequest extends TmfEventRequest {
350
351 private final List<ITmfEvent> fList;
352
353 public ArrayFillingRequest(long startRank, int limit, List<ITmfEvent> listToFill) {
354 super(ITmfEvent.class, startRank, limit, ExecutionType.FOREGROUND);
355 fList = listToFill;
356 }
357
358 @Override
359 public void handleData(ITmfEvent event) {
360 super.handleData(event);
361 fList.add(event);
362 }
363
364 }
365 }
This page took 0.041741 seconds and 5 git commands to generate.