Skip to content

Commit edf15dd

Browse files
enhance LongOperation and LongOperationMonitorWindow to support multiple exception and progress consumers; add logging feature for progress updates
1 parent a8327e3 commit edf15dd

3 files changed

Lines changed: 83 additions & 88 deletions

File tree

zk/src/main/java/tools/dynamia/zk/ui/LongOperationMonitorWindow.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@
1919
import org.zkoss.zk.ui.event.Events;
2020
import org.zkoss.zul.*;
2121
import tools.dynamia.commons.ClassMessages;
22+
import tools.dynamia.commons.DateTimeUtils;
2223
import tools.dynamia.commons.Messages;
24+
import tools.dynamia.commons.logger.LoggingService;
2325
import tools.dynamia.integration.ProgressEvent;
2426
import tools.dynamia.integration.ProgressMonitor;
2527
import tools.dynamia.ui.MessageType;
2628
import tools.dynamia.ui.UIMessages;
2729
import tools.dynamia.zk.util.LongOperation;
2830
import tools.dynamia.zk.util.ZKUtil;
2931

32+
import java.util.Date;
33+
3034
public class LongOperationMonitorWindow extends Window {
3135

3236
private static final long serialVersionUID = 1L;
@@ -40,6 +44,8 @@ public class LongOperationMonitorWindow extends Window {
4044
private Label messageLabel;
4145

4246
private String messageTemplate = messages.get("DefaultProgressMessage");
47+
private Listbox logListbox;
48+
private boolean showLog;
4349

4450
public LongOperationMonitorWindow(LongOperation longOperation, ProgressMonitor monitor) {
4551
this.longOperation = longOperation;
@@ -56,6 +62,7 @@ public static LongOperationMonitorWindow show(String title,
5662
win.setTitle(title);
5763
win.setPosition("center");
5864
win.doModal();
65+
longOperation.onException(e -> win.detach());
5966
return win;
6067
}
6168

@@ -104,6 +111,10 @@ private void updateProgress(ProgressEvent evt) {
104111
progress.setValue(evt.getPercent());
105112
progress.setTooltiptext(evt.getPercent() + "%");
106113
messageLabel.setValue(evt.getMessage());
114+
if (isShowLog()) {
115+
var item = logListbox.appendItem(DateTimeUtils.formatTime(new Date()) + " - " + evt.getMessage(), "");
116+
logListbox.scrollToIndex(item.getIndex());
117+
}
107118

108119
String title = Messages.format(messageTemplate,
109120
evt.getCurrent(), evt.getMax(), evt.getPercent());
@@ -127,6 +138,11 @@ private void initUI() {
127138
layout.setHflex("1");
128139
layout.setParent(this);
129140

141+
logListbox = new Listbox();
142+
logListbox.setVisible(false);
143+
logListbox.setHeight("150px");
144+
logListbox.setParent(layout);
145+
130146
progress = new Progressmeter();
131147
progress.setHflex("2");
132148
progress.setValue(0);
@@ -137,6 +153,43 @@ private void initUI() {
137153
messageLabel = new Label();
138154
messageLabel.setParent(msg);
139155
msg.setParent(layout);
156+
157+
Hlayout hlayout = new Hlayout();
158+
hlayout.setHflex("1");
159+
hlayout.setParent(layout);
160+
hlayout.setVisible(false);
161+
162+
Label confirmStopLabel = new Label(messages.get("ConfirmStopProcess"));
163+
confirmStopLabel.setStyle("font-weight:bold");
164+
confirmStopLabel.setParent(hlayout);
165+
166+
Button yesBtn = new Button(messages.get("yes"));
167+
yesBtn.setZclass("btn btn-success btn-sm");
168+
yesBtn.setParent(hlayout);
169+
yesBtn.addEventListener(Events.ON_CLICK, evt -> stop());
170+
171+
Button noBtn = new Button(messages.get("no"));
172+
noBtn.setZclass("btn btn-danger btn-sm");
173+
noBtn.setParent(hlayout);
174+
noBtn.addEventListener(Events.ON_CLICK, evt -> hlayout.setVisible(false));
175+
176+
addEventListener(Events.ON_CLOSE, evt -> {
177+
evt.stopPropagation();
178+
hlayout.setVisible(true);
179+
});
180+
181+
}
182+
183+
protected void stop() {
184+
try {
185+
longOperation.onFinish(null);
186+
monitor.stop();
187+
} catch (Exception e) {
188+
LoggingService.get(LongOperationMonitorWindow.class).error("Error stopping long operation", e);
189+
} finally {
190+
finish();
191+
}
192+
140193
}
141194

142195
@Override
@@ -147,4 +200,13 @@ public void setTitle(String title) {
147200
public void setMessageTemplate(String messageTemplate) {
148201
this.messageTemplate = messageTemplate;
149202
}
203+
204+
public boolean isShowLog() {
205+
return showLog;
206+
}
207+
208+
public void setShowLog(boolean showLog) {
209+
this.showLog = showLog;
210+
logListbox.setVisible(showLog);
211+
}
150212
}

zk/src/main/java/tools/dynamia/zk/util/LongOperation.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import tools.dynamia.integration.ProgressEvent;
2626
import tools.dynamia.integration.scheduling.SchedulerUtil;
2727

28+
import java.util.ArrayList;
29+
import java.util.List;
2830
import java.util.UUID;
2931
import java.util.concurrent.CompletableFuture;
3032
import java.util.concurrent.atomic.AtomicBoolean;
@@ -51,6 +53,7 @@
5153
public class LongOperation implements Runnable {
5254

5355
private static final LoggingService LOGGER = LoggingService.get(LongOperation.class);
56+
private EventQueue<LongOpEvent> opQueue;
5457

5558
/**
5659
* Types of UI events triggered by a running LongOperation.
@@ -99,8 +102,8 @@ public Exception getError() {
99102
private Callback onFinishCallback;
100103
private Callback onCancelCallback;
101104
private Callback onCleanupCallback;
102-
private Consumer<Exception> onExceptionConsumer;
103-
private Consumer<ProgressEvent> onProgressConsumer;
105+
private List<Consumer<Exception>> onExceptionConsumer;
106+
private List<Consumer<ProgressEvent>> onProgressConsumer;
104107

105108
private CompletableFuture<Void> future;
106109
private final AtomicBoolean cancelled = new AtomicBoolean(false);
@@ -153,10 +156,13 @@ public LongOperation onCancel(Callback cb) {
153156
}
154157

155158
/**
156-
* Register callback when an uncaught exception occurs.
159+
* Register callback when an uncaught exception occurs. Supports multiple consumers.
157160
*/
158161
public LongOperation onException(Consumer<Exception> cb) {
159-
this.onExceptionConsumer = cb;
162+
if (onExceptionConsumer == null) {
163+
onExceptionConsumer = new ArrayList<>();
164+
}
165+
this.onExceptionConsumer.add(cb);
160166
return this;
161167
}
162168

@@ -169,10 +175,13 @@ public LongOperation onCleanup(Callback cb) {
169175
}
170176

171177
/**
172-
* Register callback to receive UI progress reports (0-100).
178+
* Register callback to receive UI progress reports (0-100). Sopports multiple consumers.
173179
*/
174180
public LongOperation onProgress(Consumer<ProgressEvent> cb) {
175-
this.onProgressConsumer = cb;
181+
if (onProgressConsumer == null) {
182+
onProgressConsumer = new ArrayList<>();
183+
}
184+
this.onProgressConsumer.add(cb);
176185
return this;
177186
}
178187

@@ -239,7 +248,10 @@ private void safeExecute(Callback cb) {
239248
// ========================
240249

241250
private EventQueue<LongOpEvent> queue() {
242-
return EventQueues.lookup(name + "-" + taskId, EventQueues.SESSION, true);
251+
if (opQueue == null) {
252+
opQueue = EventQueues.lookup(name + "-" + taskId, EventQueues.SESSION, true);
253+
}
254+
return opQueue;
243255
}
244256

245257
private void postEvent(LongOpEventType type, ProgressEvent progress, Exception ex) {
@@ -268,12 +280,12 @@ public void onEvent(EventListener<LongOpEvent> listener) {
268280
}
269281

270282
private void safeException(Exception e) {
271-
if (onExceptionConsumer != null) onExceptionConsumer.accept(e);
283+
if (onExceptionConsumer != null) onExceptionConsumer.forEach(c -> c.accept(e));
272284
LOGGER.error("Unhandled exception in task {}", name, e);
273285
}
274286

275287
private void safeProgress(ProgressEvent p) {
276-
if (onProgressConsumer != null && p != null) onProgressConsumer.accept(p);
288+
if (onProgressConsumer != null && p != null) onProgressConsumer.forEach(c -> c.accept(p));
277289
}
278290

279291
private void cleanup() {

zk/src/main/java/tools/dynamia/zk/util/ResultLongOperation.java

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)