Commit | Line | Data |
---|---|---|
8c8bf09f | 1 | /******************************************************************************* |
8967c8c0 | 2 | * Copyright (c) 2009, 2014 Ericsson |
0283f7ff | 3 | * |
8c8bf09f ASL |
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 | |
0283f7ff | 8 | * |
8c8bf09f | 9 | * Contributors: |
fd3f1eff AM |
10 | * Francois Chouinard - Initial API and implementation, replace background |
11 | * requests by preemptable requests | |
12 | * Alexandre Montplaisir - Merge with TmfDataProvider | |
8967c8c0 | 13 | * Bernd Hufmann - Add timer based coalescing for background requests |
8c8bf09f ASL |
14 | *******************************************************************************/ |
15 | ||
2bdf0193 | 16 | package org.eclipse.tracecompass.tmf.core.component; |
8c8bf09f | 17 | |
d77f31da BH |
18 | import java.util.ArrayList; |
19 | import java.util.Collections; | |
8967c8c0 | 20 | import java.util.Iterator; |
f45257df | 21 | import java.util.LinkedList; |
fd3f1eff | 22 | import java.util.List; |
8967c8c0 BH |
23 | import java.util.Timer; |
24 | import java.util.TimerTask; | |
fd3f1eff | 25 | |
6ae0ee68 | 26 | import org.eclipse.jdt.annotation.NonNull; |
5db5a3a4 | 27 | import org.eclipse.tracecompass.common.core.NonNullUtils; |
2bdf0193 AM |
28 | import org.eclipse.tracecompass.internal.tmf.core.TmfCoreTracer; |
29 | import org.eclipse.tracecompass.internal.tmf.core.component.TmfEventThread; | |
30 | import org.eclipse.tracecompass.internal.tmf.core.component.TmfProviderManager; | |
31 | import org.eclipse.tracecompass.internal.tmf.core.request.TmfCoalescedEventRequest; | |
32 | import org.eclipse.tracecompass.internal.tmf.core.request.TmfRequestExecutor; | |
33 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; | |
8a580390 | 34 | import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter; |
2bdf0193 AM |
35 | import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest; |
36 | import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest.ExecutionType; | |
37 | import org.eclipse.tracecompass.tmf.core.signal.TmfEndSynchSignal; | |
38 | import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; | |
39 | import org.eclipse.tracecompass.tmf.core.signal.TmfStartSynchSignal; | |
40 | import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; | |
41 | import org.eclipse.tracecompass.tmf.core.trace.ITmfContext; | |
8c8bf09f ASL |
42 | |
43 | /** | |
fd3f1eff AM |
44 | * An abstract base class that implements ITmfEventProvider. |
45 | * <p> | |
46 | * This abstract class implements the housekeeping methods to register/ | |
47 | * de-register the event provider and to handle generically the event requests. | |
48 | * </p> | |
0283f7ff | 49 | * |
8fd82db5 | 50 | * @author Francois Chouinard |
c4767854 | 51 | * @since 3.0 |
8c8bf09f | 52 | */ |
8a580390 | 53 | public abstract class TmfEventProvider extends TmfComponent implements ITmfEventProvider, ITmfFilter { |
fd3f1eff AM |
54 | |
55 | // ------------------------------------------------------------------------ | |
56 | // Constants | |
57 | // ------------------------------------------------------------------------ | |
58 | ||
c4767854 AM |
59 | /** Default amount of events per request "chunk" |
60 | * @since 3.0 */ | |
fd3f1eff AM |
61 | public static final int DEFAULT_BLOCK_SIZE = 50000; |
62 | ||
8967c8c0 BH |
63 | /** Delay for coalescing background requests (in milli-seconds) */ |
64 | private static final long DELAY = 1000; | |
65 | ||
fd3f1eff AM |
66 | // ------------------------------------------------------------------------ |
67 | // Attributes | |
68 | // ------------------------------------------------------------------------ | |
69 | ||
f45257df AM |
70 | /** List of coalesced requests */ |
71 | private final List<TmfCoalescedEventRequest> fPendingCoalescedRequests = new LinkedList<>(); | |
fd3f1eff | 72 | |
f45257df AM |
73 | /** The type of event handled by this provider */ |
74 | private Class<? extends ITmfEvent> fType; | |
fd3f1eff AM |
75 | |
76 | private final TmfRequestExecutor fExecutor; | |
77 | ||
78 | private final Object fLock = new Object(); | |
79 | ||
80 | private int fSignalDepth = 0; | |
81 | ||
82 | private int fRequestPendingCounter = 0; | |
8c8bf09f | 83 | |
506219d0 | 84 | private Timer fTimer; |
8967c8c0 | 85 | |
6ae0ee68 BH |
86 | /** Current timer task */ |
87 | @NonNull private TimerTask fCurrentTask = new TimerTask() { @Override public void run() {} }; | |
88 | ||
2b5c3b7e | 89 | private boolean fIsTimerEnabled; |
8967c8c0 | 90 | |
d77f31da BH |
91 | /** |
92 | * The parent event provider. | |
93 | */ | |
94 | private TmfEventProvider fParent = null; | |
95 | /** | |
96 | * The list if children event provider. | |
97 | */ | |
98 | private final List<TmfEventProvider> fChildren = Collections.synchronizedList(new ArrayList<TmfEventProvider>()); | |
99 | ||
00641a97 FC |
100 | // ------------------------------------------------------------------------ |
101 | // Constructors | |
102 | // ------------------------------------------------------------------------ | |
103 | ||
063f0d27 AM |
104 | /** |
105 | * Default constructor | |
106 | */ | |
12c155f5 | 107 | public TmfEventProvider() { |
00641a97 | 108 | super(); |
2b5c3b7e | 109 | setTimerEnabled(true); |
fd3f1eff | 110 | fExecutor = new TmfRequestExecutor(); |
12c155f5 | 111 | } |
8c8bf09f | 112 | |
063f0d27 | 113 | /** |
f45257df | 114 | * Standard constructor. Instantiate and initialize at the same time. |
063f0d27 AM |
115 | * |
116 | * @param name | |
fd3f1eff | 117 | * Name of the provider |
063f0d27 | 118 | * @param type |
fd3f1eff | 119 | * The type of events that will be handled |
063f0d27 | 120 | */ |
f45257df | 121 | public TmfEventProvider(String name, Class<? extends ITmfEvent> type) { |
fd3f1eff | 122 | this(); |
fd3f1eff | 123 | init(name, type); |
12c155f5 FC |
124 | } |
125 | ||
063f0d27 | 126 | /** |
f45257df | 127 | * Initialize this data provider |
fd3f1eff AM |
128 | * |
129 | * @param name | |
130 | * Name of the provider | |
131 | * @param type | |
132 | * The type of events that will be handled | |
133 | */ | |
f45257df AM |
134 | public void init(String name, Class<? extends ITmfEvent> type) { |
135 | super.init(name); | |
136 | fType = type; | |
137 | fExecutor.init(); | |
138 | ||
139 | fSignalDepth = 0; | |
506219d0 BH |
140 | |
141 | synchronized (fLock) { | |
142 | fTimer = new Timer(); | |
143 | } | |
144 | ||
f45257df | 145 | TmfProviderManager.register(fType, this); |
fd3f1eff AM |
146 | } |
147 | ||
148 | @Override | |
149 | public void dispose() { | |
150 | TmfProviderManager.deregister(fType, this); | |
151 | fExecutor.stop(); | |
506219d0 BH |
152 | synchronized (fLock) { |
153 | if (fTimer != null) { | |
154 | fTimer.cancel(); | |
155 | } | |
156 | fTimer = null; | |
157 | } | |
d77f31da BH |
158 | |
159 | synchronized (fChildren) { | |
160 | for (TmfEventProvider child : fChildren) { | |
161 | child.dispose(); | |
162 | } | |
163 | fChildren.clear(); | |
164 | } | |
2b5c3b7e | 165 | clearPendingRequests(); |
fd3f1eff | 166 | super.dispose(); |
12c155f5 FC |
167 | } |
168 | ||
00641a97 | 169 | // ------------------------------------------------------------------------ |
fd3f1eff AM |
170 | // Accessors |
171 | // ------------------------------------------------------------------------ | |
172 | ||
fd3f1eff AM |
173 | /** |
174 | * Get the event type this provider handles | |
175 | * | |
176 | * @return The type of ITmfEvent | |
177 | */ | |
0f89d4ba | 178 | public Class<? extends ITmfEvent> getType() { |
fd3f1eff AM |
179 | return fType; |
180 | } | |
181 | ||
182 | // ------------------------------------------------------------------------ | |
183 | // ITmfRequestHandler | |
00641a97 FC |
184 | // ------------------------------------------------------------------------ |
185 | ||
c4767854 AM |
186 | /** |
187 | * @since 3.0 | |
188 | */ | |
5419a136 | 189 | @Override |
fd3f1eff AM |
190 | public void sendRequest(final ITmfEventRequest request) { |
191 | synchronized (fLock) { | |
5a597798 GB |
192 | |
193 | if (TmfCoreTracer.isRequestTraced()) { | |
194 | TmfCoreTracer.traceRequest(request.getRequestId(), "SENT to provider " + getName()); //$NON-NLS-1$ | |
195 | } | |
196 | ||
8a580390 BH |
197 | if (request.getProviderFilter() == null) { |
198 | request.setProviderFilter(this); | |
6badfac0 BH |
199 | } |
200 | ||
6ae0ee68 BH |
201 | if (sendWithParent(request)) { |
202 | return; | |
203 | } | |
204 | ||
8967c8c0 BH |
205 | if (request.getExecType() == ExecutionType.FOREGROUND) { |
206 | if ((fSignalDepth > 0) || (fRequestPendingCounter > 0)) { | |
207 | coalesceEventRequest(request); | |
208 | } else { | |
f45257df | 209 | queueRequest(request); |
8967c8c0 BH |
210 | } |
211 | return; | |
212 | } | |
213 | ||
506219d0 BH |
214 | /* |
215 | * Dispatch request in case timer is not running. | |
216 | */ | |
217 | if (fTimer == null) { | |
218 | queueRequest(request); | |
219 | return; | |
220 | } | |
221 | ||
8967c8c0 | 222 | coalesceEventRequest(request); |
6ae0ee68 | 223 | |
2b5c3b7e BH |
224 | if (fIsTimerEnabled) { |
225 | fCurrentTask.cancel(); | |
226 | fCurrentTask = new TimerTask() { | |
227 | @Override | |
228 | public void run() { | |
229 | synchronized (fLock) { | |
230 | fireRequest(true); | |
231 | } | |
8967c8c0 | 232 | } |
2b5c3b7e BH |
233 | }; |
234 | fTimer.schedule(fCurrentTask, DELAY); | |
235 | } | |
fd3f1eff AM |
236 | } |
237 | } | |
238 | ||
2b5c3b7e | 239 | private void fireRequest(boolean isTimeout) { |
fd3f1eff AM |
240 | synchronized (fLock) { |
241 | if (fRequestPendingCounter > 0) { | |
242 | return; | |
243 | } | |
8967c8c0 | 244 | |
fd3f1eff | 245 | if (fPendingCoalescedRequests.size() > 0) { |
8967c8c0 BH |
246 | Iterator<TmfCoalescedEventRequest> iter = fPendingCoalescedRequests.iterator(); |
247 | while (iter.hasNext()) { | |
2b5c3b7e | 248 | ExecutionType type = (isTimeout ? ExecutionType.BACKGROUND : ExecutionType.FOREGROUND); |
8967c8c0 BH |
249 | ITmfEventRequest request = iter.next(); |
250 | if (type == request.getExecType()) { | |
f45257df | 251 | queueRequest(request); |
8967c8c0 BH |
252 | iter.remove(); |
253 | } | |
fd3f1eff | 254 | } |
fd3f1eff | 255 | } |
5419a136 | 256 | } |
5419a136 AM |
257 | } |
258 | ||
fd3f1eff AM |
259 | /** |
260 | * Increments/decrements the pending requests counters and fires the request | |
261 | * if necessary (counter == 0). Used for coalescing requests across multiple | |
262 | * TmfDataProvider's. | |
263 | * | |
264 | * @param isIncrement | |
265 | * Should we increment (true) or decrement (false) the pending | |
266 | * counter | |
267 | */ | |
5419a136 | 268 | @Override |
fd3f1eff AM |
269 | public void notifyPendingRequest(boolean isIncrement) { |
270 | synchronized (fLock) { | |
271 | if (isIncrement) { | |
8967c8c0 | 272 | fRequestPendingCounter++; |
fd3f1eff AM |
273 | } else { |
274 | if (fRequestPendingCounter > 0) { | |
275 | fRequestPendingCounter--; | |
276 | } | |
277 | ||
278 | // fire request if all pending requests are received | |
279 | if (fRequestPendingCounter == 0) { | |
2b5c3b7e | 280 | fireRequest(false); |
6badfac0 | 281 | fireRequest(true); |
fd3f1eff AM |
282 | } |
283 | } | |
284 | } | |
285 | } | |
286 | ||
287 | // ------------------------------------------------------------------------ | |
288 | // Coalescing | |
289 | // ------------------------------------------------------------------------ | |
290 | ||
291 | /** | |
292 | * Create a new request from an existing one, and add it to the coalesced | |
293 | * requests | |
294 | * | |
295 | * @param request | |
296 | * The request to copy | |
c4767854 | 297 | * @since 3.0 |
fd3f1eff | 298 | */ |
8967c8c0 BH |
299 | protected void newCoalescedEventRequest(ITmfEventRequest request) { |
300 | synchronized (fLock) { | |
672a642a | 301 | TmfCoalescedEventRequest coalescedRequest = new TmfCoalescedEventRequest( |
fd3f1eff AM |
302 | request.getDataType(), |
303 | request.getRange(), | |
304 | request.getIndex(), | |
305 | request.getNbRequested(), | |
306 | request.getExecType()); | |
307 | coalescedRequest.addRequest(request); | |
8a580390 | 308 | coalescedRequest.setProviderFilter(this); |
5419a136 | 309 | if (TmfCoreTracer.isRequestTraced()) { |
8b56808c GB |
310 | TmfCoreTracer.traceRequest(request.getRequestId(), "COALESCED with " + coalescedRequest.getRequestId()); //$NON-NLS-1$ |
311 | TmfCoreTracer.traceRequest(coalescedRequest.getRequestId(), "now contains " + coalescedRequest.getSubRequestIds()); //$NON-NLS-1$ | |
5419a136 | 312 | } |
6ae0ee68 | 313 | coalesceChildrenRequests(coalescedRequest); |
5419a136 | 314 | fPendingCoalescedRequests.add(coalescedRequest); |
8967c8c0 | 315 | } |
fd3f1eff AM |
316 | } |
317 | ||
318 | /** | |
319 | * Add an existing requests to the list of coalesced ones | |
320 | * | |
321 | * @param request | |
322 | * The request to add to the list | |
c4767854 | 323 | * @since 3.0 |
fd3f1eff AM |
324 | */ |
325 | protected void coalesceEventRequest(ITmfEventRequest request) { | |
326 | synchronized (fLock) { | |
2b5c3b7e | 327 | for (TmfCoalescedEventRequest coalescedRequest : getPendingRequests()) { |
fd3f1eff AM |
328 | if (coalescedRequest.isCompatible(request)) { |
329 | coalescedRequest.addRequest(request); | |
330 | if (TmfCoreTracer.isRequestTraced()) { | |
8b56808c GB |
331 | TmfCoreTracer.traceRequest(request.getRequestId(), "COALESCED with " + coalescedRequest.getRequestId()); //$NON-NLS-1$ |
332 | TmfCoreTracer.traceRequest(coalescedRequest.getRequestId(), "now contains " + coalescedRequest.getSubRequestIds()); //$NON-NLS-1$ | |
fd3f1eff | 333 | } |
6ae0ee68 | 334 | coalesceChildrenRequests(coalescedRequest); |
fd3f1eff AM |
335 | return; |
336 | } | |
337 | } | |
338 | newCoalescedEventRequest(request); | |
339 | } | |
340 | } | |
341 | ||
6ae0ee68 BH |
342 | /* |
343 | * Sends a request with the parent if compatible. | |
344 | */ | |
345 | private boolean sendWithParent(final ITmfEventRequest request) { | |
346 | ITmfEventProvider parent = getParent(); | |
347 | if (parent instanceof TmfEventProvider) { | |
348 | return ((TmfEventProvider) parent).sendIfCompatible(request); | |
349 | } | |
350 | return false; | |
351 | } | |
352 | ||
353 | /* | |
354 | * Sends a request if compatible with a pending coalesced request. | |
8967c8c0 | 355 | */ |
6ae0ee68 | 356 | private boolean sendIfCompatible(ITmfEventRequest request) { |
8967c8c0 | 357 | synchronized (fLock) { |
2b5c3b7e | 358 | for (TmfCoalescedEventRequest coalescedRequest : getPendingRequests()) { |
6ae0ee68 BH |
359 | if (coalescedRequest.isCompatible(request)) { |
360 | // Send so it can be coalesced with the parent(s) | |
361 | sendRequest(request); | |
362 | return true; | |
363 | } | |
364 | } | |
365 | } | |
366 | return sendWithParent(request); | |
367 | } | |
368 | ||
369 | /* | |
370 | * Coalesces children requests with given request if compatible. | |
371 | */ | |
372 | private void coalesceChildrenRequests(final TmfCoalescedEventRequest request) { | |
373 | synchronized (fChildren) { | |
374 | for (TmfEventProvider child : fChildren) { | |
375 | child.coalesceCompatibleRequests(request); | |
376 | } | |
377 | } | |
378 | } | |
379 | ||
380 | ||
381 | /* | |
382 | * Coalesces all pending requests that are compatible with coalesced request. | |
383 | */ | |
384 | private void coalesceCompatibleRequests(TmfCoalescedEventRequest request) { | |
2b5c3b7e | 385 | Iterator<TmfCoalescedEventRequest> iter = getPendingRequests().iterator(); |
6ae0ee68 BH |
386 | while (iter.hasNext()) { |
387 | TmfCoalescedEventRequest pendingRequest = iter.next(); | |
388 | if (request.isCompatible(pendingRequest)) { | |
389 | request.addRequest(pendingRequest); | |
390 | if (TmfCoreTracer.isRequestTraced()) { | |
391 | TmfCoreTracer.traceRequest(pendingRequest.getRequestId(), "COALESCED with " + request.getRequestId()); //$NON-NLS-1$ | |
392 | TmfCoreTracer.traceRequest(request.getRequestId(), "now contains " + request.getSubRequestIds()); //$NON-NLS-1$ | |
8967c8c0 | 393 | } |
6ae0ee68 | 394 | iter.remove(); |
8967c8c0 BH |
395 | } |
396 | } | |
8967c8c0 BH |
397 | } |
398 | ||
fd3f1eff AM |
399 | // ------------------------------------------------------------------------ |
400 | // Request processing | |
401 | // ------------------------------------------------------------------------ | |
402 | ||
fd3f1eff AM |
403 | /** |
404 | * Queue a request. | |
405 | * | |
406 | * @param request | |
407 | * The data request | |
c4767854 | 408 | * @since 3.0 |
fd3f1eff AM |
409 | */ |
410 | protected void queueRequest(final ITmfEventRequest request) { | |
411 | ||
412 | if (fExecutor.isShutdown()) { | |
413 | request.cancel(); | |
414 | return; | |
415 | } | |
416 | ||
417 | TmfEventThread thread = new TmfEventThread(this, request); | |
418 | ||
419 | if (TmfCoreTracer.isRequestTraced()) { | |
8b56808c | 420 | TmfCoreTracer.traceRequest(request.getRequestId(), "QUEUED"); //$NON-NLS-1$ |
fd3f1eff AM |
421 | } |
422 | ||
423 | fExecutor.execute(thread); | |
424 | } | |
425 | ||
fd3f1eff AM |
426 | /** |
427 | * Initialize the provider based on the request. The context is provider | |
428 | * specific and will be updated by getNext(). | |
429 | * | |
430 | * @param request | |
431 | * The request | |
432 | * @return An application specific context; null if request can't be | |
433 | * serviced | |
c4767854 | 434 | * @since 3.0 |
fd3f1eff AM |
435 | */ |
436 | public abstract ITmfContext armRequest(ITmfEventRequest request); | |
437 | ||
438 | /** | |
439 | * Checks if the data meets the request completion criteria. | |
440 | * | |
441 | * @param request | |
442 | * The request | |
443 | * @param event | |
444 | * The data to verify | |
445 | * @param nbRead | |
446 | * The number of events read so far | |
447 | * @return true if completion criteria is met | |
c4767854 | 448 | * @since 3.0 |
fd3f1eff AM |
449 | */ |
450 | public boolean isCompleted(ITmfEventRequest request, ITmfEvent event, int nbRead) { | |
451 | boolean requestCompleted = isCompleted2(request, nbRead); | |
452 | if (!requestCompleted) { | |
453 | ITmfTimestamp endTime = request.getRange().getEndTime(); | |
065cc19b | 454 | return event.getTimestamp().compareTo(endTime) > 0; |
fd3f1eff AM |
455 | } |
456 | return requestCompleted; | |
457 | } | |
458 | ||
459 | private static boolean isCompleted2(ITmfEventRequest request,int nbRead) { | |
460 | return request.isCompleted() || nbRead >= request.getNbRequested(); | |
461 | } | |
462 | ||
463 | // ------------------------------------------------------------------------ | |
464 | // Pass-through's to the request executor | |
465 | // ------------------------------------------------------------------------ | |
466 | ||
467 | /** | |
468 | * @return the shutdown state (i.e. if it is accepting new requests) | |
469 | * @since 2.0 | |
470 | */ | |
471 | protected boolean executorIsShutdown() { | |
472 | return fExecutor.isShutdown(); | |
473 | } | |
474 | ||
475 | /** | |
476 | * @return the termination state | |
477 | * @since 2.0 | |
478 | */ | |
479 | protected boolean executorIsTerminated() { | |
480 | return fExecutor.isTerminated(); | |
481 | } | |
482 | ||
483 | // ------------------------------------------------------------------------ | |
484 | // Signal handlers | |
485 | // ------------------------------------------------------------------------ | |
486 | ||
487 | /** | |
488 | * Handler for the start synch signal | |
489 | * | |
490 | * @param signal | |
491 | * Incoming signal | |
492 | */ | |
493 | @TmfSignalHandler | |
494 | public void startSynch(TmfStartSynchSignal signal) { | |
495 | synchronized (fLock) { | |
496 | fSignalDepth++; | |
497 | } | |
498 | } | |
499 | ||
500 | /** | |
501 | * Handler for the end synch signal | |
502 | * | |
503 | * @param signal | |
504 | * Incoming signal | |
505 | */ | |
506 | @TmfSignalHandler | |
507 | public void endSynch(TmfEndSynchSignal signal) { | |
508 | synchronized (fLock) { | |
509 | fSignalDepth--; | |
510 | if (fSignalDepth == 0) { | |
2b5c3b7e | 511 | fireRequest(false); |
fd3f1eff | 512 | } |
5419a136 AM |
513 | } |
514 | } | |
951d134a | 515 | |
d77f31da BH |
516 | @Override |
517 | public ITmfEventProvider getParent() { | |
518 | synchronized (fLock) { | |
519 | return fParent; | |
520 | } | |
521 | } | |
522 | ||
523 | @Override | |
524 | public void setParent(ITmfEventProvider parent) { | |
525 | if (!(parent instanceof TmfEventProvider)) { | |
526 | throw new IllegalArgumentException(); | |
527 | } | |
528 | ||
529 | synchronized (fLock) { | |
530 | fParent = (TmfEventProvider) parent; | |
531 | } | |
532 | } | |
533 | ||
534 | @Override | |
535 | public List<ITmfEventProvider> getChildren() { | |
536 | synchronized (fChildren) { | |
537 | List<ITmfEventProvider> list = new ArrayList<>(); | |
538 | list.addAll(fChildren); | |
539 | return list; | |
540 | } | |
541 | } | |
542 | ||
543 | @Override | |
544 | public <T extends ITmfEventProvider> List<T> getChildren(Class<T> clazz) { | |
545 | List<T> list = new ArrayList<>(); | |
546 | synchronized (fChildren) { | |
547 | for (TmfEventProvider child : fChildren) { | |
548 | if (clazz.isAssignableFrom(child.getClass())) { | |
549 | list.add(clazz.cast(child)); | |
550 | } | |
551 | } | |
552 | } | |
553 | return list; | |
554 | } | |
555 | ||
556 | @Override | |
557 | public ITmfEventProvider getChild(String name) { | |
558 | synchronized (fChildren) { | |
559 | for (TmfEventProvider child : fChildren) { | |
560 | if (child.getName().equals(name)) { | |
561 | return child; | |
562 | } | |
563 | } | |
564 | } | |
565 | return null; | |
566 | } | |
567 | ||
d77f31da BH |
568 | @Override |
569 | public ITmfEventProvider getChild(int index) { | |
5db5a3a4 | 570 | return NonNullUtils.checkNotNull(fChildren.get(index)); |
d77f31da BH |
571 | } |
572 | ||
573 | @Override | |
574 | public void addChild(ITmfEventProvider child) { | |
575 | if (!(child instanceof TmfEventProvider)) { | |
576 | throw new IllegalArgumentException(); | |
577 | } | |
fa62dc1d | 578 | child.setParent(this); |
d77f31da BH |
579 | fChildren.add((TmfEventProvider)child); |
580 | } | |
581 | ||
582 | @Override | |
583 | public int getNbChildren() { | |
584 | return fChildren.size(); | |
585 | } | |
2b5c3b7e | 586 | |
8a580390 BH |
587 | /** |
588 | * Returns true if an event was provided by this event provider or one of | |
589 | * its children event providers else false. | |
590 | * | |
591 | * @param event | |
592 | * the event to check | |
593 | * @return <code>true</code> if event was provided by this provider or one | |
594 | * of its children else <code>false</code> | |
595 | */ | |
6badfac0 | 596 | @Override |
8a580390 | 597 | public boolean matches(ITmfEvent event) { |
6badfac0 BH |
598 | if ((event.getTrace() == this)) { |
599 | return true; | |
600 | } | |
601 | if (fChildren.size() > 0) { | |
602 | synchronized (fLock) { | |
603 | List <TmfEventProvider> children = getChildren(TmfEventProvider.class); | |
604 | for (TmfEventProvider child : children) { | |
8a580390 | 605 | if (child.matches(event)) { |
6badfac0 BH |
606 | return true; |
607 | } | |
608 | } | |
609 | } | |
610 | } | |
611 | return false; | |
612 | } | |
613 | ||
2b5c3b7e BH |
614 | // ------------------------------------------------------------------------ |
615 | // Debug code (will also used in tests using reflection) | |
616 | // ------------------------------------------------------------------------ | |
617 | ||
618 | /** | |
619 | * Gets a list of all pending requests. Debug code. | |
620 | * | |
621 | * @return a list of all pending requests | |
622 | */ | |
623 | private List<TmfCoalescedEventRequest> getPendingRequests() { | |
624 | return fPendingCoalescedRequests; | |
625 | } | |
626 | ||
627 | /** | |
628 | * Clears all pending requests. Debug code. | |
629 | */ | |
630 | private void clearPendingRequests() { | |
631 | fPendingCoalescedRequests.clear(); | |
632 | } | |
633 | ||
634 | /** | |
635 | * Enables/disables the timer. Debug code. | |
636 | * | |
637 | * @param enabled | |
638 | * the enable flag to set | |
639 | */ | |
640 | private void setTimerEnabled(Boolean enabled) { | |
641 | fIsTimerEnabled = enabled; | |
642 | } | |
8c8bf09f | 643 | } |