Skip to content
This repository was archived by the owner on Sep 1, 2024. It is now read-only.

Commit 3852456

Browse files
committed
Clean shutdown implementation
Storage queue fix
1 parent 777dab6 commit 3852456

36 files changed

Lines changed: 1638 additions & 1530 deletions

eu.dariolucia.reatmetric.core/src/main/java/eu/dariolucia/reatmetric/core/impl/AcknowledgedMessageBrokerImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ private static class AcknowledgedMessageSubscriptionManager {
192192
t.setDaemon(true);
193193
return t;
194194
}); // OK to use, only 1 job, separate queue
195-
private final BlockingQueue<AcknowledgedMessage> queue = new ArrayBlockingQueue<>(1000);
195+
private final BlockingQueue<AcknowledgedMessage> queue = new LinkedBlockingQueue<>();
196196
private final IAcknowledgedMessageSubscriber subscriber;
197197
private final boolean timely;
198198
private volatile Predicate<AcknowledgedMessage> filter;
@@ -204,7 +204,7 @@ public AcknowledgedMessageSubscriptionManager(AcknowledgedMessageBrokerImpl brok
204204
this.filter = filter == null ? IDENTITY_FILTER : filter;
205205
this.timely = timely;
206206
this.queue.addAll(initialMessages);
207-
dispatcher.submit(this::processQueue);
207+
this.dispatcher.submit(this::processQueue);
208208
}
209209

210210
private void processQueue() {

eu.dariolucia.reatmetric.persist/src/main/java/eu/dariolucia/reatmetric/persist/services/AbstractDataItemArchive.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,21 @@ public void store(List<T> items) throws ArchiveException {
159159
}
160160
checkDisposed();
161161
checkStorageQueueFull(items.size());
162-
storageQueue.addAll(items);
162+
// It can happen that items has more elements than the storageQueue. So we do an incremental mass storage.
163+
if(items.size() < storageQueue.remainingCapacity()) {
164+
// Optimisation: add the items straight
165+
storageQueue.addAll(items);
166+
} else {
167+
// Start splitting
168+
int cycles = (int) Math.ceil(items.size() / (double) STORAGE_QUEUE_FLUSH_LIMIT);
169+
for(int i = 0; i < cycles; ++i) {
170+
int start = i * STORAGE_QUEUE_FLUSH_LIMIT;
171+
int end = i == (cycles - 1) ? items.size() : STORAGE_QUEUE_FLUSH_LIMIT * (i + 1);
172+
storageQueue.addAll(items.subList(start, end));
173+
// Force storage
174+
checkStorageQueueFull(MAX_STORAGE_QUEUE);
175+
}
176+
}
163177
}
164178

165179
public void store(T item) throws ArchiveException {

eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/ReatmetricUI.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import eu.dariolucia.reatmetric.ui.plugin.ReatmetricServiceHolder;
2222
import eu.dariolucia.reatmetric.ui.preferences.PreferencesManager;
2323
import eu.dariolucia.reatmetric.ui.utils.DialogUtils;
24+
import eu.dariolucia.reatmetric.ui.utils.MimicsDisplayCoordinator;
25+
import eu.dariolucia.reatmetric.ui.utils.ParameterDisplayCoordinator;
26+
import eu.dariolucia.reatmetric.ui.utils.UserDisplayCoordinator;
2427
import javafx.application.Application;
2528
import javafx.application.Platform;
2629
import javafx.fxml.FXMLLoader;
@@ -34,14 +37,19 @@
3437
import java.util.concurrent.ConcurrentHashMap;
3538
import java.util.concurrent.ExecutorService;
3639
import java.util.concurrent.Executors;
40+
import java.util.concurrent.TimeUnit;
3741
import java.util.function.Consumer;
42+
import java.util.logging.Level;
43+
import java.util.logging.Logger;
3844

3945
/**
4046
*
4147
* @author dario
4248
*/
4349
public class ReatmetricUI extends Application {
44-
50+
51+
private static final Logger LOG = Logger.getLogger(ReatmetricUI.class.getName());
52+
4553
public static final String APPLICATION_NAME = "ReatMetric UI";
4654

4755
public static final String APPLICATION_VERSION = "0.1.0";
@@ -76,7 +84,15 @@ public static ExecutorService threadPool(final Class<?> clazz) {
7684
private static void shutdownThreadPool() {
7785
synchronized (THREAD_POOL) {
7886
for(Map.Entry<Class<?>, ExecutorService> entry : THREAD_POOL.entrySet()) {
79-
entry.getValue().shutdownNow();
87+
entry.getValue().shutdown();
88+
}
89+
for(Map.Entry<Class<?>, ExecutorService> entry : THREAD_POOL.entrySet()) {
90+
try {
91+
boolean terminated = entry.getValue().awaitTermination(1, TimeUnit.SECONDS);
92+
LOG.log(Level.FINE, "ThreadPool for class " + entry.getKey().getSimpleName() + " " + (terminated ? "terminated" : "NOT terminated"));
93+
} catch (InterruptedException e) {
94+
// Ignore
95+
}
8096
}
8197
}
8298
}
@@ -139,15 +155,27 @@ public void stop() {
139155

140156
public static void shutdown() {
141157
if (DialogUtils.confirm("Exit " + APPLICATION_NAME, "Exit " + APPLICATION_NAME, "Do you want to close " + APPLICATION_NAME + "?")) {
158+
LOG.info("Reatmetric UI shutdown sequence");
159+
LOG.info("Shutting down display coordinators");
160+
UserDisplayCoordinator.instance().dispose();
161+
ParameterDisplayCoordinator.instance().dispose();
162+
MimicsDisplayCoordinator.instance().dispose();
163+
LOG.info("Disconnection from system");
142164
ReatmetricUI.selectedSystem().setSystem(null);
165+
LOG.info("System disconnection done");
143166
// Wait for completion
144167
try {
145168
Thread.sleep(1000);
146169
} catch (InterruptedException e) {
147170
e.printStackTrace();
148171
}
172+
LOG.info("Shutting down UI thread pool");
149173
ReatmetricUI.shutdownThreadPool();
174+
LOG.info("UI thread pool shut down, exiting JFX platform");
150175
Platform.exit();
176+
LOG.info("Freeing up memory");
177+
System.gc();
178+
LOG.info("Reatmetric UI shutdown sequence completed. Have a nice day.");
151179
System.exit(0);
152180
}
153181
}

eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/AbstractDisplayController.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,14 @@
2828
import javafx.fxml.Initializable;
2929
import javafx.print.*;
3030
import javafx.scene.Node;
31-
import javafx.scene.control.Control;
32-
import javafx.scene.paint.Paint;
33-
import javafx.scene.shape.Circle;
3431
import javafx.scene.transform.Scale;
3532
import javafx.stage.Stage;
3633
import javafx.stage.Window;
3734

3835
import java.net.URL;
3936
import java.time.Instant;
4037
import java.util.ResourceBundle;
38+
import java.util.logging.Logger;
4139

4240
/**
4341
* FXML Controller class
@@ -46,6 +44,8 @@
4644
*/
4745
public abstract class AbstractDisplayController implements Initializable, IReatmetricServiceListener {
4846

47+
private static final Logger LOG = Logger.getLogger(AbstractDisplayController.class.getName());
48+
4949
// Info
5050
protected IReatmetricSystem system = null;
5151
protected String user = System.getProperty("user.name");
@@ -66,16 +66,16 @@ public final void initialize(URL url, ResourceBundle rb) {
6666
@FXML
6767
protected void printButtonSelected(ActionEvent e) {
6868
final Node n = doBuildNodeForPrinting();
69-
if(n != null) {
69+
if (n != null) {
7070
ReatmetricUI.threadPool(getClass()).execute(() -> {
7171
Printer printer = Printer.getDefaultPrinter();
7272
PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.HARDWARE_MINIMUM);
7373
PrinterJob job = PrinterJob.createPrinterJob();
74-
74+
7575
double scaleX = pageLayout.getPrintableWidth() / n.getBoundsInLocal().getWidth(); // getPrefWidth();
7676
Scale scale = new Scale(scaleX, scaleX); // Homogeneus scale, assuming width larger than height ...
7777
n.getTransforms().add(scale);
78-
78+
7979
if (job != null && job.showPrintDialog(retrieveWindow())) {
8080
boolean success = job.printPage(pageLayout, n);
8181
if (success) {
@@ -92,6 +92,7 @@ protected void printButtonSelected(ActionEvent e) {
9292
}
9393

9494
public void dispose() {
95+
LOG.fine("Disposing controller " + getClass().getSimpleName() + " - " + toString());
9596
systemDisconnected(null);
9697
ReatmetricUI.selectedSystem().removeSubscriber(this);
9798
}
@@ -138,7 +139,7 @@ public void systemDisconnected(IReatmetricSystem system) {
138139
}
139140

140141
protected static String formatTime(Instant time) {
141-
if(time == null) {
142+
if (time == null) {
142143
return "---";
143144
} else {
144145
return InstantCellFactory.DATE_TIME_FORMATTER.format(time);

eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/AckAlarmStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public enum AckAlarmStatus {
3838
}
3939

4040
public static AckAlarmStatus deriveStatus(AlarmState alarmState, boolean pendingAcknowledgement) {
41-
switch(alarmState) {
41+
switch (alarmState) {
4242
case ERROR:
4343
case ALARM:
4444
return pendingAcknowledgement ? ALARM_NOT_ACKED : ALARM_ACKED;

eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/AckMessageDialogController.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class AckMessageDialogController implements Initializable, IAcknowledgedM
5858
private volatile IReatmetricSystem system;
5959
private volatile Consumer<Boolean> handler;
6060

61-
private Set<Integer> pendingAcknowledgementSet = new HashSet<>();
61+
private final Set<Integer> pendingAcknowledgementSet = new HashSet<>();
6262

6363
@Override
6464
public void initialize(URL url, ResourceBundle resourceBundle) {
@@ -99,26 +99,26 @@ protected void updateItem(Severity item, boolean empty) {
9999
public void activate(Consumer<Boolean> alarmPresentNotifier) {
100100
this.handler = alarmPresentNotifier;
101101
this.system = ReatmetricUI.selectedSystem().getSystem();
102-
if(this.system != null) {
102+
if (this.system != null) {
103103
try {
104104
this.system.getAcknowledgedMessageMonitorService().subscribe(this, new AcknowledgedMessageFilter(null, null));
105105
} catch (ReatmetricException | RemoteException e) {
106-
LOG.log(Level.SEVERE, "Subscription to AcknowledgedMessageMonitorService failed: " + e.getMessage() , e);
106+
LOG.log(Level.SEVERE, "Subscription to AcknowledgedMessageMonitorService failed: " + e.getMessage(), e);
107107
}
108108
}
109109
}
110110

111111
public void deactivate() {
112-
if(this.system != null) {
112+
if (this.system != null) {
113113
try {
114114
this.system.getAcknowledgedMessageMonitorService().unsubscribe(this);
115115
} catch (ReatmetricException | RemoteException e) {
116-
LOG.log(Level.SEVERE, "Unsubscription to AcknowledgedMessageMonitorService failed: " + e.getMessage() , e);
116+
LOG.log(Level.SEVERE, "Unsubscription to AcknowledgedMessageMonitorService failed: " + e.getMessage(), e);
117117
}
118118
}
119119
this.ackMessageTableView.getItems().clear();
120120
this.ackMessageTableView.refresh();
121-
if(this.handler != null) {
121+
if (this.handler != null) {
122122
this.handler.accept(false);
123123
}
124124
this.handler = null;
@@ -129,8 +129,8 @@ public void deactivate() {
129129
public void dataItemsReceived(List<AcknowledgedMessage> dataItems) {
130130
Set<Long> messagesToRemove = new HashSet<>();
131131
List<AcknowledgedMessage> messagesToAdd = new LinkedList<>();
132-
for(AcknowledgedMessage am : dataItems) {
133-
if(am.getState() == AcknowledgementState.ACKNOWLEDGED) {
132+
for (AcknowledgedMessage am : dataItems) {
133+
if (am.getState() == AcknowledgementState.ACKNOWLEDGED) {
134134
messagesToRemove.add(am.getInternalId().asLong());
135135
} else {
136136
// New message for acknowledgement
@@ -142,13 +142,13 @@ public void dataItemsReceived(List<AcknowledgedMessage> dataItems) {
142142
List<AcknowledgedMessage> toRemoveActuals = new LinkedList<>();
143143
// I iterate on the whole list, so here I compute the messages pending ack
144144
pendingAcknowledgementSet.clear();
145-
for(int i = 0; i < ackMessageTableView.getItems().size(); ++i) {
145+
for (int i = 0; i < ackMessageTableView.getItems().size(); ++i) {
146146
AcknowledgedMessage am = ackMessageTableView.getItems().get(i);
147-
if(messagesToRemove.contains(am.getInternalId().asLong())) {
147+
if (messagesToRemove.contains(am.getInternalId().asLong())) {
148148
toRemoveActuals.add(am);
149149
} else {
150150
// Not to be removed, remember the ID
151-
if(am.getMessage().getLinkedEntityId() != null) {
151+
if (am.getMessage().getLinkedEntityId() != null) {
152152
pendingAcknowledgementSet.add(am.getMessage().getLinkedEntityId());
153153
}
154154
}
@@ -162,7 +162,7 @@ public void dataItemsReceived(List<AcknowledgedMessage> dataItems) {
162162
// Finally update the table
163163
ackMessageTableView.getItems().removeAll(toRemoveActuals);
164164
ackMessageTableView.getItems().addAll(messagesToAdd);
165-
if(this.handler != null) {
165+
if (this.handler != null) {
166166
this.handler.accept(!ackMessageTableView.getItems().isEmpty());
167167
}
168168
});
@@ -175,12 +175,12 @@ public void ackSelectionButtonSelected(ActionEvent actionEvent) {
175175
}
176176

177177
private void ackMessages(List<AcknowledgedMessage> selected) {
178-
if(!selected.isEmpty() && this.system != null) {
178+
if (!selected.isEmpty() && this.system != null) {
179179
ReatmetricUI.threadPool(getClass()).execute(() -> {
180180
try {
181181
system.getAcknowledgementService().acknowledgeMessages(selected, ReatmetricUI.username());
182182
} catch (ReatmetricException | RemoteException e) {
183-
LOG.log(Level.SEVERE, "Acknowledgement failed: " + e.getMessage() , e);
183+
LOG.log(Level.SEVERE, "Acknowledgement failed: " + e.getMessage(), e);
184184
}
185185
});
186186
}

eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/ActivityDataFilterWidgetController.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ public class ActivityDataFilterWidgetController implements Initializable, IFilte
6363
private CheckBox typeCheckbox;
6464
@FXML
6565
private TextField typeText;
66-
66+
6767
@FXML
6868
private Button selectBtn;
69-
69+
7070
private Runnable actionAfterSelection;
71-
71+
7272
// The result of the selection
7373
private ActivityOccurrenceDataFilter selectedFilter = null;
74-
74+
7575
/**
7676
* Initializes the controller class.
7777
*/
@@ -83,24 +83,24 @@ public void initialize(URL url, ResourceBundle rb) {
8383
this.pathText.disableProperty().bind(this.pathCheckbox.selectedProperty().not());
8484
this.typeText.disableProperty().bind(this.typeCheckbox.selectedProperty().not());
8585
this.routeText.disableProperty().bind(this.routeCheckbox.selectedProperty().not());
86-
86+
8787
this.stateList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
8888
this.stateList.getItems().addAll(Arrays.asList(ActivityOccurrenceState.values()));
89-
}
90-
89+
}
90+
9191
@FXML
9292
private void selectButtonPressed(ActionEvent e) {
9393
this.selectedFilter = deriveFromWidgets();
9494
if(this.actionAfterSelection != null) {
9595
this.actionAfterSelection.run();
9696
}
9797
}
98-
98+
9999
@Override
100100
public void setActionAfterSelection(Runnable r) {
101101
this.actionAfterSelection = r;
102102
}
103-
103+
104104
@Override
105105
public void setSelectedFilter(ActivityOccurrenceDataFilter t) {
106106
this.selectedFilter = t;
@@ -111,7 +111,7 @@ public void setSelectedFilter(ActivityOccurrenceDataFilter t) {
111111
public ActivityOccurrenceDataFilter getSelectedFilter() {
112112
return this.selectedFilter;
113113
}
114-
114+
115115
private void updateWidgets() {
116116
if(this.selectedFilter == null) {
117117
this.stateCheckbox.setSelected(false);
@@ -133,7 +133,7 @@ private void updateWidgets() {
133133
this.pathCheckbox.setSelected(this.selectedFilter.getParentPath() != null);
134134
this.routeCheckbox.setSelected(this.selectedFilter.getRouteList() != null);
135135
this.typeCheckbox.setSelected(this.selectedFilter.getTypeList() != null);
136-
136+
137137
this.sourceText.setText(IFilterController.toStringList(this.selectedFilter.getSourceList()));
138138
this.activityPathText.setText(IFilterController.toStringList(this.selectedFilter.getActivityPathList()));
139139
this.routeText.setText(IFilterController.toStringList(this.selectedFilter.getRouteList()));
@@ -171,23 +171,23 @@ private List<SystemEntityPath> deriveSelectedActivityPath() {
171171
return null;
172172
}
173173
}
174-
174+
175175
private List<String> deriveSelectedType() {
176176
if(this.typeCheckbox.isSelected()) {
177177
return new LinkedList<>(Arrays.asList(this.typeText.getText().split(",")));
178178
} else {
179179
return null;
180180
}
181181
}
182-
182+
183183
private List<String> deriveSelectedRoute() {
184184
if(this.routeCheckbox.isSelected()) {
185185
return new LinkedList<>(Arrays.asList(this.routeText.getText().split(",")));
186186
} else {
187187
return null;
188188
}
189189
}
190-
190+
191191
private List<ActivityOccurrenceState> deriveSelectedState() {
192192
if(this.stateCheckbox.isSelected()) {
193193
return new LinkedList<>(this.stateList.getSelectionModel().getSelectedItems());

0 commit comments

Comments
 (0)