1
1
package fi .helsinki .cs .tmc .spyware ;
2
2
3
+ import com .google .common .base .Optional ;
3
4
import com .google .common .collect .Iterables ;
5
+ import com .google .common .util .concurrent .FutureCallback ;
6
+ import com .google .common .util .concurrent .Futures ;
7
+ import com .google .common .util .concurrent .ListenableFuture ;
4
8
import hy .tmc .core .domain .Course ;
5
9
import fi .helsinki .cs .tmc .model .CourseDb ;
10
+ import fi .helsinki .cs .tmc .model .NBTmcSettings ;
6
11
import fi .helsinki .cs .tmc .model .ServerAccess ;
7
- import fi .helsinki .cs .tmc .utilities .BgTask ;
8
- import fi .helsinki .cs .tmc .utilities .CancellableCallable ;
12
+ import fi .helsinki .cs .tmc .model .TmcCoreSingleton ;
9
13
import fi .helsinki .cs .tmc .utilities .Cooldown ;
14
+ import fi .helsinki .cs .tmc .utilities .ExceptionUtils ;
10
15
import fi .helsinki .cs .tmc .utilities .SingletonTask ;
11
16
import fi .helsinki .cs .tmc .utilities .TmcRequestProcessor ;
17
+ import hy .tmc .core .communication .HttpResult ;
18
+ import hy .tmc .core .exceptions .TmcCoreException ;
12
19
import java .io .IOException ;
13
20
import java .util .ArrayDeque ;
14
21
import java .util .ArrayList ;
15
22
import java .util .Arrays ;
16
23
import java .util .Iterator ;
17
24
import java .util .List ;
18
25
import java .util .Random ;
19
- import java .util .concurrent .ExecutionException ;
20
- import java .util .concurrent .Future ;
21
26
import java .util .concurrent .TimeoutException ;
22
27
import java .util .logging .Level ;
23
28
import java .util .logging .Logger ;
29
+ import org .netbeans .api .progress .ProgressHandle ;
30
+ import org .netbeans .api .progress .ProgressHandleFactory ;
31
+ import org .openide .util .Exceptions ;
24
32
25
33
/**
26
- * Buffers {@link LoggableEvent}s and sends them to the server and/or syncs them to the disk periodically.
34
+ * Buffers {@link LoggableEvent}s and sends them to the server and/or syncs them
35
+ * to the disk periodically.
27
36
*/
28
37
public class EventSendBuffer implements EventReceiver {
38
+
29
39
private static final Logger log = Logger .getLogger (EventSendBuffer .class .getName ());
30
40
31
- public static final long DEFAULT_SEND_INTERVAL = 3 * 60 * 1000 ;
32
- public static final long DEFAULT_SAVE_INTERVAL = 1 * 60 * 1000 ;
41
+ public static final long DEFAULT_SEND_INTERVAL = 3 * 60 * 1000 ;
42
+ public static final long DEFAULT_SAVE_INTERVAL = 3 * 60 * 1000 ;
33
43
public static final int DEFAULT_MAX_EVENTS = 64 * 1024 ;
34
44
public static final int DEFAULT_AUTOSEND_THREHSOLD = DEFAULT_MAX_EVENTS / 2 ;
35
- public static final int DEFAULT_AUTOSEND_COOLDOWN = 30 * 1000 ;
45
+ public static final int DEFAULT_AUTOSEND_COOLDOWN = 30 * 1000 ;
36
46
37
47
private Random random = new Random ();
38
48
private SpywareSettings settings ;
@@ -47,7 +57,6 @@ public class EventSendBuffer implements EventReceiver {
47
57
private int autosendThreshold = DEFAULT_AUTOSEND_THREHSOLD ;
48
58
private Cooldown autosendCooldown ;
49
59
50
-
51
60
public EventSendBuffer (SpywareSettings settings , ServerAccess serverAccess , CourseDb courseDb , EventStore eventStore ) {
52
61
this .settings = settings ;
53
62
this .serverAccess = serverAccess ;
@@ -172,7 +181,6 @@ public void close() {
172
181
}
173
182
}
174
183
175
-
176
184
private SingletonTask sendingTask = new SingletonTask (new Runnable () {
177
185
// Sending too many at once may go over the server's POST size limit.
178
186
private static final int MAX_EVENTS_PER_SEND = 500 ;
@@ -196,7 +204,7 @@ public void run() {
196
204
return ;
197
205
}
198
206
199
- log .log (Level .INFO , "Sending {0} events to {1}" , new Object [] { eventsToSend .size (), url });
207
+ log .log (Level .INFO , "Sending {0} events to {1}" , new Object []{ eventsToSend .size (), url });
200
208
201
209
doSend (eventsToSend , url );
202
210
} while (shouldSendMore );
@@ -235,32 +243,74 @@ private String pickDestinationUrl() {
235
243
return url ;
236
244
}
237
245
238
- private void doSend ( final ArrayList < LoggableEvent > eventsToSend , final String url ) {
239
- CancellableCallable < Object > task = serverAccess . getSendEventLogJob ( url , eventsToSend );
240
- Future < Object > future = BgTask . start ( "Sending stats" , task );
241
-
242
- try {
243
- future . get ();
244
- } catch ( InterruptedException ex ) {
245
- future . cancel ( true );
246
- } catch ( ExecutionException ex ) {
247
- log . log ( Level . INFO , "Sending failed" , ex );
246
+ /**
247
+ * Converts events to data[] and sends it to defined url.
248
+ *
249
+ * @param eventsToSend
250
+ * @param url
251
+ */
252
+ private void doSend ( final ArrayList < LoggableEvent > eventsToSend , final String url ) {
253
+ NBTmcSettings settings = NBTmcSettings . getDefault ( );
254
+ Optional < Course > currentCourse = settings . getCurrentCourse ();
255
+ if (! currentCourse . isPresent ()) {
248
256
return ;
249
257
}
258
+ addCorrectSpywareUrl (url , currentCourse );
259
+ final ProgressHandle progress = ProgressHandleFactory .createSystemHandle ("Sending stats" );
260
+ progress .start ();
261
+ try {
262
+ byte [] data = convertEventsToByteArray (eventsToSend );
263
+ ListenableFuture <List <HttpResult >> spywareSending = TmcCoreSingleton .getInstance ().sendSpywareDiffs (
264
+ data , settings
265
+ );
266
+ Futures .addCallback (spywareSending , new FutureCallback <List <HttpResult >>() {
267
+ @ Override
268
+ public void onSuccess (List <HttpResult > success ) {
269
+ clearAfterSend (success );
270
+ }
271
+ @ Override
272
+ public void onFailure (Throwable thrwbl ) {
273
+ clearAfterSend (new ArrayList <HttpResult >());
274
+ System .err .println (thrwbl .getMessage ());
275
+ }
276
+ private void clearAfterSend (List <HttpResult > success ) {
277
+
278
+ progress .finish ();
279
+ log .log (Level .INFO , "Sent {0} events successfully to {1}" , new Object []{eventsToSend .size (), url });
280
+ removeSentEventsFromQueue ();
281
+ // If saving fails now (or is already running and fails later)
282
+ // then we may end up sending duplicate events later.
283
+ // This will hopefully be very rare.
284
+ savingTask .start ();
285
+ }
286
+ });
287
+
288
+ } catch (TmcCoreException ex ) {
289
+ progress .finish ();
290
+ Exceptions .printStackTrace (ex );
291
+ }
292
+ }
250
293
251
- log .log (Level .INFO , "Sent {0} events successfully to {1}" , new Object [] { eventsToSend .size (), url });
252
-
253
- removeSentEventsFromQueue ();
254
-
255
- // If saving fails now (or is already running and fails later)
256
- // then we may end up sending duplicate events later.
257
- // This will hopefully be very rare.
258
- savingTask .start ();
294
+ private void addCorrectSpywareUrl (final String url , Optional <Course > currentCourse ) {
295
+ List <String > spywareUrls = new ArrayList <String >();
296
+ String finalUrl = serverAccess .addApiCallQueryParameters (url );
297
+ spywareUrls .add (finalUrl );
298
+ currentCourse .get ().setSpywareUrls (spywareUrls );
259
299
}
260
300
301
+ private byte [] convertEventsToByteArray (final ArrayList <LoggableEvent > eventsToSend ) throws RuntimeException {
302
+ byte [] data ;
303
+ try {
304
+ data = serverAccess .eventListToPostBody (eventsToSend );
305
+ } catch (IOException ex ) {
306
+ throw ExceptionUtils .toRuntimeException (ex );
307
+ }
308
+ return data ;
309
+ }
310
+
261
311
private void removeSentEventsFromQueue () {
262
312
synchronized (sendQueue ) {
263
- assert (eventsToRemoveAfterSend <= sendQueue .size ());
313
+ assert (eventsToRemoveAfterSend <= sendQueue .size ());
264
314
while (eventsToRemoveAfterSend > 0 ) {
265
315
sendQueue .pop ();
266
316
eventsToRemoveAfterSend --;
@@ -270,7 +320,6 @@ private void removeSentEventsFromQueue() {
270
320
271
321
}, TmcRequestProcessor .instance );
272
322
273
-
274
323
private SingletonTask savingTask = new SingletonTask (new Runnable () {
275
324
@ Override
276
325
public void run () {
@@ -285,5 +334,4 @@ public void run() {
285
334
}
286
335
}
287
336
}, TmcRequestProcessor .instance );
288
-
289
337
}
0 commit comments