42
42
import org .graalvm .visualvm .core .options .GlobalPreferences ;
43
43
import org .graalvm .visualvm .jmx .JmxApplicationException ;
44
44
import org .graalvm .visualvm .jmx .JmxApplicationsSupport ;
45
- import org .graalvm .visualvm .tools .jmx .JmxModel ;
46
45
import org .graalvm .visualvm .tools .jmx .JmxModel .ConnectionState ;
47
46
import org .graalvm .visualvm .tools .jmx .JmxModelFactory ;
48
47
import java .awt .BorderLayout ;
54
53
import java .net .InetAddress ;
55
54
import java .net .MalformedURLException ;
56
55
import java .net .NetworkInterface ;
56
+ import java .util .ArrayList ;
57
+ import java .util .Collection ;
57
58
import java .util .Collections ;
58
59
import java .util .Enumeration ;
59
60
import java .util .HashMap ;
60
61
import java .util .HashSet ;
61
- import java .util .Iterator ;
62
62
import java .util .Map ;
63
63
import java .util .Set ;
64
64
import java .util .concurrent .atomic .AtomicInteger ;
@@ -350,127 +350,49 @@ private JmxApplication addLazyJmxApplication(boolean newApp, JMXServiceURL servi
350
350
// // If everything succeeded, add datasource to application tree
351
351
host .getRepository ().addDataSource (application );
352
352
353
- // if (model == null || model.getConnectionState() != ConnectionState.CONNECTED) {
354
- synchronized (unavailableApps ) { unavailableApps .add (application ); }
355
- if (scheduleHeartbeat ) scheduleHeartbeat ();
356
- // }
353
+ if (scheduleHeartbeat ) JmxHeartbeat .scheduleImmediately (application );
357
354
358
355
return application ;
359
356
}
360
357
361
358
362
- private static final int HEARTBEAT_DELAY = 100 ;
363
- private static final int HEARTBEAT_POLL_DELAY = 5000 ;
364
- private static final int HEARTBEAT_MAX_THREADS = 10 ;
365
- private final Set <JmxApplication > unavailableApps = new HashSet ();
366
-
367
- private volatile boolean heartbeatRunning ;
368
- private volatile boolean anotherHeartbeatPending ;
369
-
370
- private void scheduleHeartbeat () {
371
- scheduleHeartbeatImpl (true );
372
- }
373
-
374
- private void scheduleHeartbeatImpl (boolean immediately ) {
375
- if (heartbeatRunning ) {
376
- anotherHeartbeatPending = true ;
377
- return ;
378
- } else {
379
- heartbeatRunning = true ;
380
- }
381
-
382
- Set <JmxApplication > apps = new HashSet ();
383
- synchronized (unavailableApps ) {
384
- apps .addAll (unavailableApps );
385
- unavailableApps .clear ();
386
- }
387
-
388
- cleanupUnavailableApps (apps );
389
- if (apps .isEmpty ()) {
390
- heartbeatRunning = false ;
391
- if (anotherHeartbeatPending ) { // just a safe fallback, likely not needed at all
392
- anotherHeartbeatPending = false ;
393
- scheduleHeartbeatImpl (false );
394
- } else {
395
- return ;
396
- }
397
- }
398
-
399
- final AtomicInteger counter = new AtomicInteger (apps .size ());
400
- RequestProcessor processor = new RequestProcessor ("JMX Heartbeat Processor" , Math .min (counter .intValue (), HEARTBEAT_MAX_THREADS )); // NOI18N
401
- // System.err.println(">>> Heartbeat for " + counter + " targets at " + java.time.LocalTime.now());
402
- for (final JmxApplication app : apps ) {
403
- processor .post (new Runnable () {
404
- @ Override
405
- public void run () {
406
- try {
407
- boolean connected = false ;
408
- try {
409
- ProxyClient client = new ProxyClient (app );
410
- client .connect ();
411
- if (client .getConnectionState () == ConnectionState .CONNECTED ) {
412
- app .setClient (client );
413
- connected = true ;
414
- }
415
- } catch (IOException ex ) {
416
- LOGGER .log (Level .FINE , "ProxyClient.connect" , ex );
417
- }
418
- if (!connected ) {
419
- synchronized (unavailableApps ) { unavailableApps .add (app ); }
420
- } else {
421
- app .setStateImpl (Stateful .STATE_AVAILABLE );
422
-
423
- app .jmxModel = JmxModelFactory .getJmxModelFor (app );
424
- app .jvm = JvmFactory .getJVMFor (app );
359
+ // TODO: move to JmxApplication implementation
360
+ // PropertyChangeListener will be per JmxApplication instance - easy unregistering
361
+ // introduce JmxApplication.disconnect()
362
+ static boolean tryConnect (JmxApplication app ) {
363
+ try {
364
+ ProxyClient client = new ProxyClient (app );
365
+ client .connect ();
366
+ if (client .getConnectionState () == ConnectionState .CONNECTED ) {
367
+ app .setClient (client );
368
+
369
+ app .setStateImpl (Stateful .STATE_AVAILABLE );
425
370
426
- app .jmxModel .addPropertyChangeListener (new PropertyChangeListener () {
427
- public void propertyChange (PropertyChangeEvent evt ) {
428
- if (evt .getNewValue () == ConnectionState .CONNECTED ) {
429
- app .setStateImpl (Stateful .STATE_AVAILABLE );
430
- } else {
431
- app .setStateImpl (Stateful .STATE_UNAVAILABLE );
432
- if (!app .isRemoved ()) {
433
- synchronized (unavailableApps ) { unavailableApps .add (app ); }
434
- scheduleHeartbeatImpl (true );
435
- }
436
- // TODO: remove listener from model once not needed!
437
- }
438
- }
439
- });
440
- }
441
- } finally {
442
- if (counter .decrementAndGet () == 0 ) {
443
- boolean pendingApps ;
444
-
445
- synchronized (unavailableApps ) {
446
- cleanupUnavailableApps (unavailableApps );
447
- pendingApps = !unavailableApps .isEmpty ();
448
- heartbeatRunning = false ;
449
- }
371
+ app .jmxModel = JmxModelFactory .getJmxModelFor (app );
372
+ app .jvm = JvmFactory .getJVMFor (app );
450
373
451
- if (anotherHeartbeatPending || pendingApps ) {
452
- anotherHeartbeatPending = false ;
453
- scheduleHeartbeatImpl (false );
454
- }
374
+ app .jmxModel .addPropertyChangeListener (new PropertyChangeListener () {
375
+ public void propertyChange (PropertyChangeEvent evt ) {
376
+ if (evt .getNewValue () == ConnectionState .CONNECTED ) {
377
+ app .setStateImpl (Stateful .STATE_AVAILABLE );
378
+ } else {
379
+ app .setStateImpl (Stateful .STATE_UNAVAILABLE );
380
+ if (!app .isRemoved ()) JmxHeartbeat .scheduleLazily (app );
381
+ // TODO: remove listener from model once not needed!
455
382
}
456
383
}
457
- }
458
- }, immediately ? HEARTBEAT_DELAY : HEARTBEAT_POLL_DELAY );
384
+ });
385
+
386
+ return true ;
387
+ }
388
+ } catch (IOException ex ) {
389
+ LOGGER .log (Level .FINE , "ProxyClient.connect" , ex ); // NOI18N
459
390
}
391
+
392
+ return false ;
460
393
}
461
394
462
395
463
- private void cleanupUnavailableApps (Set <JmxApplication > apps ) {
464
- String trueS = Boolean .TRUE .toString ();
465
- Iterator <JmxApplication > appsI = apps .iterator ();
466
- while (appsI .hasNext ()) {
467
- JmxApplication app = appsI .next ();
468
- if (app .isRemoved () || trueS .equals (app .getStorage ().getCustomProperty (PROPERTY_DISABLE_HEARTBEAT )))
469
- appsI .remove ();
470
- }
471
- }
472
-
473
-
474
396
private void cleanupCreatedHost (Set <Host > hosts , Host host ) {
475
397
// NOTE: this is not absolutely failsafe, if resolving the JMX application
476
398
// took a long time and its host has been added by the user/plugin, it may
@@ -573,8 +495,9 @@ public synchronized void dataChanged(DataChangeEvent<Host> event) {
573
495
};
574
496
575
497
final AtomicInteger counter = new AtomicInteger (storageSetSize );
576
- RequestProcessor processor = new RequestProcessor ("JMX Persistence Processor" , Math .min (counter .intValue (), HEARTBEAT_MAX_THREADS )); // NOI18N
577
-
498
+ final Collection <JmxApplication > persistentApps = Collections .synchronizedList (new ArrayList ());
499
+ RequestProcessor processor = new RequestProcessor ("JMX Persistence Processor" , Math .min (storageSetSize , 10 )); // NOI18N
500
+
578
501
for (final Storage storage : storageSet ) {
579
502
final String [] values = storage .getCustomProperties (keys );
580
503
processor .post (new Runnable () {
@@ -589,8 +512,8 @@ public void run() {
589
512
EnvironmentProvider ep = epid == null ? null :
590
513
JmxConnectionSupportImpl .
591
514
getProvider (epid );
592
- addLazyJmxApplication (false , null , values [0 ], values [2 ], values [3 ],
593
- values [1 ], ep , storage , values [5 ], false );
515
+ persistentApps . add ( addLazyJmxApplication (false , null , values [0 ], values [2 ], values [3 ],
516
+ values [1 ], ep , storage , values [5 ], false ) );
594
517
} catch (final JMXException e ) {
595
518
if (e .isConfig ()) {
596
519
DialogDisplayer .getDefault ().notifyLater (
@@ -604,7 +527,8 @@ public void run() {
604
527
failedAppsS .add (storage );
605
528
}
606
529
} finally {
607
- if (counter .decrementAndGet () == 0 ) scheduleHeartbeat ();
530
+ if (counter .decrementAndGet () == 0 )
531
+ JmxHeartbeat .scheduleImmediately (persistentApps .toArray (new JmxApplication [0 ]));
608
532
}
609
533
synchronized (persistedAppsCount ) {
610
534
persistedAppsCount [0 ]--;
@@ -686,10 +610,11 @@ public void run() {
686
610
}
687
611
688
612
689
- private static class JMXException extends Exception {
613
+ private static class JMXException extends Exception {
690
614
private final boolean isConfig ;
691
615
public JMXException (boolean config , String message ) { super (message ); isConfig = config ; }
692
616
public JMXException (boolean config , String message , Throwable cause ) { super (message ,cause ); isConfig = config ; }
693
617
public boolean isConfig () { return isConfig ; }
694
618
}
619
+
695
620
}
0 commit comments