8b2ce9b7c0a1eb1aba1965717c8b009d90448280
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / request / TmfDataRequest.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 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 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.request;
14
15 import org.eclipse.linuxtools.tmf.Tracer;
16 import org.eclipse.linuxtools.tmf.event.TmfData;
17
18 /**
19 * <b><u>TmfDataRequest</u></b>
20 * <p>
21 * TmfDataRequests are used to obtain blocks of contiguous data from a data
22 * provider. Open ranges can be used, especially for continuous streaming.
23 * <p>
24 * The request is processed asynchronously by a TmfProvider and, as blocks
25 * of data become available, handleData() is invoked synchronously for each
26 * block. Upon return, the data instances go out of scope and become eligible
27 * for gc. It is is thus the responsibility of the requester to either clone
28 * or keep a reference to the data it wishes to track specifically.
29 * <p>
30 * This data block approach is used to avoid busting the heap for very
31 * large trace files. The block size is configurable.
32 * <p>
33 * The TmfProvider indicates that the request is completed by calling done().
34 * The request can be canceled at any time with cancel().
35 * <p>
36 * Typical usage:
37 *<pre><code><i>TmfTimeWindow range = new TmfTimewindow(...);
38 *TmfDataRequest&lt;DataType[]&gt; request = new TmfDataRequest&lt;DataType[]&gt;(DataType.class, 0, NB_EVENTS, BLOCK_SIZE) {
39 * public void handleData() {
40 * DataType[] data = request.getData();
41 * for (DataType e : data) {
42 * // do something
43 * }
44 * }
45 * public void handleSuccess() {
46 * // do something
47 * }
48 * }
49 * public void handleFailure() {
50 * // do something
51 * }
52 * }
53 * public void handleCancel() {
54 * // do something
55 * }
56 * }
57 *};
58 *fProcessor.process(request, true);
59 *</i></code></pre>
60 *
61 * TODO: Consider decoupling from "time range", "rank", etc and for the more
62 * generic notion of "criteria". This would allow to extend for "time range", etc
63 * instead of providing specialized constructors. This also means removing the
64 * criteria info from the data structure (with the possible exception of fNbRequested).
65 * The nice thing about it is that it would prepare us well for the coming generation
66 * of analysis tools.
67 *
68 * TODO: Implement request failures (codes, etc...)
69 */
70 public abstract class TmfDataRequest<T extends TmfData> implements ITmfDataRequest<T> {
71
72 // ------------------------------------------------------------------------
73 // Constants
74 // ------------------------------------------------------------------------
75
76 // The default maximum number of events per chunk
77 public static final int DEFAULT_BLOCK_SIZE = 1000;
78
79 // The request count for all the events
80 public static final int ALL_DATA = Integer.MAX_VALUE;
81
82 private static int fRequestNumber = 0;
83
84 // ------------------------------------------------------------------------
85 // Attributes
86 // ------------------------------------------------------------------------
87
88 private final Class<T> fDataType;
89 private final int fRequestId; // A unique request ID
90 private final int fIndex; // The index (rank) of the requested event
91 private final int fNbRequested; // The number of requested events (ALL_DATA for all)
92 private final int fBlockSize; // The maximum number of events per chunk
93 private int fNbRead; // The number of reads so far
94
95 private final Object lock;
96 private boolean fRequestCompleted;
97 private boolean fRequestFailed;
98 private boolean fRequestCanceled;
99
100 private T[] fData; // Data object
101
102 // ------------------------------------------------------------------------
103 // Constructors
104 // ------------------------------------------------------------------------
105
106 /**
107 * Resets the request counter (used for testing)
108 */
109 public static void reset() {
110 fRequestNumber = 0;
111 }
112
113 /**
114 * Default constructor
115 *
116 * @param dataType the requested data type
117 */
118 public TmfDataRequest(Class<T> dataType) {
119 this(dataType, 0, ALL_DATA, DEFAULT_BLOCK_SIZE);
120 }
121
122 /**
123 * @param dataType the requested data type
124 * @param nbRequested the number of data items requested
125 */
126 public TmfDataRequest(Class<T> dataType, int index) {
127 this(dataType, index, ALL_DATA, DEFAULT_BLOCK_SIZE);
128 }
129
130 /**
131 * @param dataType the requested data type
132 * @param index the index (rank) of the first event requested
133 * @param blockSize the number of data items per block
134 */
135 public TmfDataRequest(Class<T> dataType, int index, int nbRequested) {
136 this(dataType, index, nbRequested, DEFAULT_BLOCK_SIZE);
137 }
138
139 /**
140 * @param dataType the requested data type
141 * @param index the index (rank) of the first event requested
142 * @param nbRequested the number of data items requested
143 * @param blockSize the number of data items per block
144 */
145 public TmfDataRequest(Class<T> dataType, int index, int nbRequested, int blockSize) {
146 fRequestId = fRequestNumber++;
147 fDataType = dataType;
148 fIndex = index;
149 fNbRequested = nbRequested;
150 fBlockSize = blockSize;
151 fNbRead = 0;
152 lock = new Object();
153
154 Tracer.trace("Request #" + fRequestId + " (" + getClass().getName() + ", " + fDataType.getName() + ") created");
155 }
156
157 /**
158 * Copy constructor
159 */
160 @SuppressWarnings("unused")
161 private TmfDataRequest(TmfDataRequest<T> other) {
162 fRequestId = 0;
163 fDataType = null;
164 fIndex = 0;
165 fNbRequested = 0;
166 fBlockSize = 0;
167 fNbRead = 0;
168 lock = new Object();
169 }
170
171 // ------------------------------------------------------------------------
172 // Accessors
173 // ------------------------------------------------------------------------
174
175 /**
176 * @return the request ID
177 */
178 public int getRequestId() {
179 return fRequestId;
180 }
181
182 /**
183 * @return the index of the first event requested
184 */
185 public int getIndex() {
186 return fIndex;
187 }
188
189 /**
190 * @return the number of requested events (ALL_DATA = all)
191 */
192 public int getNbRequested() {
193 return fNbRequested;
194 }
195
196 /**
197 * @return the block size
198 */
199 public int getBlockize() {
200 return fBlockSize;
201 }
202
203 /**
204 * @return the number of events read so far
205 */
206 public synchronized int getNbRead() {
207 return fNbRead;
208 }
209
210 /**
211 * @return indicates if the request is completed
212 */
213 public boolean isCompleted() {
214 return fRequestCompleted;
215 }
216
217 /**
218 * @return indicates if the request is canceled
219 */
220 public boolean isFailed() {
221 return fRequestFailed;
222 }
223
224 /**
225 * @return indicates if the request is canceled
226 */
227 public boolean isCancelled() {
228 return fRequestCanceled;
229 }
230
231 /**
232 * @return the requested data type
233 */
234 public Class<T> getDataType() {
235 return fDataType;
236 }
237
238 // ------------------------------------------------------------------------
239 // Operators
240 // ------------------------------------------------------------------------
241
242 /**
243 * Sets the data object to specified value. To be called by the
244 * asynchronous method implementor.
245 * @param data Data value to set.
246 */
247 public synchronized void setData(T[] data) {
248 fNbRead += data.length;
249 fData = data;
250 }
251
252 /**
253 * Returns the data value, null if not set.
254 */
255 public synchronized T[] getData() {
256 return fData;
257 }
258
259 /**
260 * Handle a block of incoming data. This method is called every time
261 * a block of data becomes available.
262 *
263 * - Data items are received in the order they appear in the stream.
264 * - Called by the request processor, in its execution thread, every time a
265 * block of data becomes available.
266 * - Request processor performs a synchronous call to handlePartialResult()
267 * i.e. its execution threads holds until handlePartialData() returns.
268 * - Original data items are disposed of on return i.e. keep a reference
269 * (or a copy) if some persistence is needed between invocations.
270 * - When there is no more data, done() is called.
271 *
272 * @param events - an array of events
273 */
274 public abstract void handleData();
275
276 /**
277 * Handle the completion of the request. It is called when there is no more
278 * data available either because:
279 * - the request completed normally
280 * - the request failed
281 * - the request was canceled
282 *
283 * As a convenience, handleXXXX methods are provided. They are meant to be
284 * overridden by the application if it needs to handle these conditions.
285 */
286 public void handleCompleted() {
287 if (fRequestFailed) {
288 Tracer.trace("Request #" + fRequestId + " failed, completed");
289 handleFailure();
290 }
291 else if (fRequestCanceled) {
292 Tracer.trace("Request #" + fRequestId + " cancelled, completed");
293 handleCancel();
294 }
295 else {
296 Tracer.trace("Request #" + fRequestId + " succeeded, completed");
297 handleSuccess();
298 }
299 }
300
301 public void handleSuccess() {
302 }
303
304 public void handleFailure() {
305 }
306
307 public void handleCancel() {
308 }
309
310 /**
311 * To suspend the client thread until the request completes (or is
312 * canceled).
313 *
314 * @throws InterruptedException
315 */
316 public void waitForCompletion() throws InterruptedException {
317 synchronized (lock) {
318 while (!fRequestCompleted)
319 lock.wait();
320 }
321 }
322
323 /**
324 * Called by the request processor upon completion.
325 */
326 public void done() {
327 synchronized(lock) {
328 fRequestCompleted = true;
329 lock.notify();
330 }
331 handleCompleted();
332 }
333
334 /**
335 * Called by the request processor upon failure.
336 */
337 public void fail() {
338 synchronized(lock) {
339 fRequestFailed = true;
340 done();
341 }
342 }
343
344 /**
345 * Called by the request processor upon cancellation.
346 */
347 public void cancel() {
348 synchronized(lock) {
349 fRequestCanceled = true;
350 done();
351 }
352 }
353
354 // ------------------------------------------------------------------------
355 // Object
356 // ------------------------------------------------------------------------
357
358 @Override
359 // All requests have a unique id
360 public int hashCode() {
361 return getRequestId();
362 }
363
364 @Override
365 public boolean equals(Object other) {
366 if (other instanceof TmfDataRequest<?>) {
367 TmfDataRequest<?> request = (TmfDataRequest<?>) other;
368 return (request.fDataType == fDataType) &&
369 (request.fIndex == fIndex) &&
370 (request.fNbRequested == fNbRequested);
371 }
372 return false;
373 }
374
375 @Override
376 public String toString() {
377 return "[TmfDataRequest(" + fRequestId + "," + fDataType.getSimpleName()
378 + "," + fIndex + "," + fNbRequested + "," + fBlockSize + ")]";
379 }
380
381 }
This page took 0.037565 seconds and 4 git commands to generate.