1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.prometheus.views;
18
19 import io.github.tonywasher.joceanus.metis.data.MetisDataEditState;
20 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
21 import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
22 import io.github.tonywasher.joceanus.metis.list.MetisListKey;
23 import io.github.tonywasher.joceanus.metis.ui.MetisErrorPanel;
24 import io.github.tonywasher.joceanus.metis.viewer.MetisViewerErrorList;
25 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
26 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
27 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
28 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar.OceanusEventProvider;
29 import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
30 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogManager;
31 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogger;
32 import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
33 import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataListCtl;
34 import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataSetListCtl;
35 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
36 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList;
37 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
38 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
39
40 import java.util.Iterator;
41 import java.util.LinkedHashMap;
42 import java.util.Map;
43
44
45
46
47 public class PrometheusEditSet
48 implements MetisFieldItem, OceanusEventProvider<PrometheusDataEvent>, PrometheusDataSetListCtl {
49
50
51
52 @SuppressWarnings("rawtypes")
53 private static final MetisFieldSet<PrometheusEditSet> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusEditSet.class);
54
55
56
57
58 static {
59 FIELD_DEFS.declareLocalField(PrometheusDataResource.DATASET_VERSION, PrometheusEditSet::getVersion);
60 }
61
62
63
64
65 private static final OceanusLogger LOGGER = OceanusLogManager.getLogger(PrometheusEditSet.class);
66
67
68
69
70 private final OceanusEventManager<PrometheusDataEvent> theEventManager;
71
72
73
74
75 @SuppressWarnings("rawtypes")
76 private final MetisFieldSet<PrometheusEditSet> theLocalFields;
77
78
79
80
81 private final Map<MetisListKey, PrometheusEditEntry<?>> theMap;
82
83
84
85
86 private final PrometheusDataControl theControl;
87
88
89
90
91 private PrometheusDataSet theDataSet;
92
93
94
95
96 private int theVersion;
97
98
99
100
101 private Boolean itemEditing = Boolean.FALSE;
102
103
104
105
106
107
108 public PrometheusEditSet(final PrometheusDataControl pControl) {
109 this(pControl, pControl.getData());
110 }
111
112
113
114
115
116
117
118 public PrometheusEditSet(final PrometheusDataControl pControl,
119 final PrometheusDataSet pDataSet) {
120
121 theControl = pControl;
122 theDataSet = pDataSet;
123
124
125 theEventManager = new OceanusEventManager<>();
126
127
128 theLocalFields = MetisFieldSet.newFieldSet(this);
129
130
131 theMap = new LinkedHashMap<>();
132 }
133
134 @SuppressWarnings("rawtypes")
135 @Override
136 public MetisFieldSet<PrometheusEditSet> getDataFieldSet() {
137 return theLocalFields;
138 }
139
140 @Override
141 public String formatObject(final OceanusDataFormatter pFormatter) {
142 return getDataFieldSet().getName();
143 }
144
145 @Override
146 public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
147 return theEventManager.getEventRegistrar();
148 }
149
150
151
152
153
154
155 public void setEditing(final Boolean pFlag) {
156 itemEditing = pFlag;
157 }
158
159
160
161
162
163
164 public Boolean isEditing() {
165 return itemEditing;
166 }
167
168
169
170
171
172
173 public int getVersion() {
174 return theVersion;
175 }
176
177
178
179
180
181
182 public PrometheusDataSet getDataSet() {
183 return theDataSet;
184 }
185
186
187
188
189
190
191 public void setDataSet(final PrometheusDataSet pDataSet) {
192 theDataSet = pDataSet;
193 }
194
195
196
197
198
199
200
201
202 public <T extends PrometheusDataItem> PrometheusEditEntry<T> registerType(final MetisListKey pDataType) {
203
204 @SuppressWarnings("unchecked") final PrometheusEditEntry<T> myEntry = (PrometheusEditEntry<T>) theMap.computeIfAbsent(pDataType, t -> {
205
206 final PrometheusEditEntry<T> myNewEntry = new PrometheusEditEntry<>(t);
207 theLocalFields.declareLocalField(myNewEntry.getName(), n -> myNewEntry);
208 return myNewEntry;
209 });
210
211
212 myEntry.setDataList(null);
213 return myEntry;
214 }
215
216
217
218
219
220
221
222
223
224
225
226 @Override
227 public <L extends PrometheusDataListCtl<?>> L getDataList(final MetisListKey pDataType,
228 final Class<L> pClass) {
229
230 final PrometheusEditEntry<?> myEntry = theMap.get(pDataType);
231
232
233 return myEntry != null
234 ? pClass.cast(myEntry.getDataList())
235 : theDataSet.getDataList(pDataType, pClass);
236 }
237
238 @Override
239 public boolean hasDataType(final MetisListKey pDataType) {
240 return theMap.containsKey(pDataType);
241 }
242
243
244
245
246
247
248
249
250 public <T extends PrometheusDataItem> void setEditEntryList(final MetisListKey pDataType,
251 final PrometheusDataList<T> pList) {
252 @SuppressWarnings("unchecked") final PrometheusEditEntry<T> myEntry = (PrometheusEditEntry<T>) theMap.get(pDataType);
253 myEntry.setDataList(pList);
254 }
255
256
257
258
259
260
261 public Iterator<MetisListKey> keyIterator() {
262 return theMap.keySet().iterator();
263 }
264
265
266
267
268
269
270 public Iterator<PrometheusEditEntry<?>> listIterator() {
271 return theMap.values().iterator();
272 }
273
274
275
276
277 public void incrementVersion() {
278
279 final OceanusProfile myTask = theControl.getActiveTask();
280 final OceanusProfile mySubTask = myTask == null
281 ? theControl.getNewProfile("incrementVersion")
282 : myTask.startTask("incrementVersion");
283
284
285 theVersion++;
286
287
288 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
289
290 final PrometheusDataList<?> myDataList = myEntry.getDataList();
291
292
293 if (myDataList != null) {
294
295 mySubTask.startTask(myDataList.listName());
296
297
298 myDataList.setVersion(theVersion);
299
300
301 if (Boolean.FALSE.equals(itemEditing)) {
302 myDataList.postProcessOnUpdate();
303 }
304 }
305 }
306
307
308 mySubTask.end();
309 }
310
311
312
313
314
315
316 private void rewindToVersion(final int pVersion) {
317
318 final OceanusProfile myTask = theControl.getActiveTask();
319 OceanusProfile mySubTask = myTask.startTask("reWindToVersion");
320
321
322 theVersion = pVersion;
323
324
325 Iterator<PrometheusEditEntry<?>> myIterator = theMap.values().iterator();
326 while (myIterator.hasNext()) {
327
328 final PrometheusEditEntry<?> myEntry = myIterator.next();
329 final PrometheusDataList<?> myDataList = myEntry.getDataList();
330
331
332 if (myDataList != null) {
333
334 mySubTask.startTask(myDataList.listName());
335
336
337 myDataList.rewindToVersion(theVersion);
338 }
339 }
340
341
342 mySubTask = myTask.startTask("postProcess");
343 myIterator = theMap.values().iterator();
344 while (myIterator.hasNext()) {
345
346 final PrometheusEditEntry<?> myEntry = myIterator.next();
347 final PrometheusDataList<?> myDataList = myEntry.getDataList();
348
349
350 if (myDataList != null) {
351
352 mySubTask.startTask(myDataList.listName());
353
354
355 if (Boolean.FALSE.equals(itemEditing)) {
356 myDataList.postProcessOnUpdate();
357 }
358 }
359 }
360
361
362 mySubTask = myTask.startTask("Notify");
363
364
365 theEventManager.fireEvent(PrometheusDataEvent.DATACHANGED);
366
367
368 mySubTask.end();
369 }
370
371
372
373
374 private void undoLastChange() {
375
376 if (theVersion == 0) {
377 return;
378 }
379
380
381 theVersion--;
382
383
384 rewindToVersion(theVersion);
385 }
386
387
388
389
390 private void resetChanges() {
391
392 if (theVersion == 0) {
393 return;
394 }
395
396
397 theVersion = 0;
398
399
400 rewindToVersion(theVersion);
401 }
402
403
404
405
406 private void applyChanges() {
407
408 final OceanusProfile myTask = theControl.getActiveTask();
409 final OceanusProfile mySubTask = myTask.startTask("applyChanges");
410
411
412 validate();
413
414
415 if (hasErrors()) {
416
417 mySubTask.startTask("Notify");
418
419
420 theEventManager.fireEvent(PrometheusDataEvent.DATACHANGED);
421
422
423 mySubTask.end();
424 return;
425 }
426
427
428 boolean bSuccess = prepareChanges();
429
430
431 if (bSuccess) {
432
433 bSuccess = theControl.analyseData(false);
434 }
435
436
437 if (bSuccess) {
438
439 commitChanges();
440
441
442 theControl.refreshViews();
443
444
445 } else {
446
447 rollBackChanges();
448
449
450 theControl.analyseData(true);
451 }
452
453
454 mySubTask.end();
455 }
456
457
458
459
460
461
462 private boolean prepareChanges() {
463
464 final OceanusProfile myTask = theControl.getActiveTask();
465 final OceanusProfile mySubTask = myTask.startTask("prepareChanges");
466 boolean bSuccess = true;
467
468
469 try {
470
471 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
472
473 mySubTask.startTask(myEntry.getName());
474
475
476 myEntry.prepareChanges();
477 }
478
479 } catch (OceanusException e) {
480 LOGGER.error("Failed to prepare changes", e);
481 bSuccess = false;
482 }
483
484
485 mySubTask.end();
486 return bSuccess;
487 }
488
489
490
491
492 private void commitChanges() {
493
494 final OceanusProfile myTask = theControl.getActiveTask();
495 final OceanusProfile mySubTask = myTask.startTask("commitChanges");
496
497
498 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
499
500 mySubTask.startTask(myEntry.getName());
501
502
503 myEntry.commitChanges();
504 }
505
506
507 theControl.incrementVersion();
508 theVersion = 0;
509
510
511 mySubTask.end();
512 }
513
514
515
516
517 private void rollBackChanges() {
518
519 final OceanusProfile myTask = theControl.getActiveTask();
520 final OceanusProfile mySubTask = myTask.startTask("rollBackChanges");
521
522
523 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
524
525 mySubTask.startTask(myEntry.getName());
526
527
528 myEntry.rollBackChanges();
529 }
530
531
532 mySubTask.end();
533 }
534
535
536
537
538
539
540 public boolean hasUpdates() {
541
542 return theVersion != 0;
543 }
544
545
546
547
548
549
550 public boolean hasErrors() {
551
552 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
553
554 final PrometheusDataList<?> myDataList = myEntry.getDataList();
555
556
557 if (myDataList != null && myDataList.hasErrors()) {
558 return true;
559 }
560 }
561
562
563 return false;
564 }
565
566
567
568
569 public void validate() {
570
571 final OceanusProfile myTask = theControl.getActiveTask();
572 final OceanusProfile mySubTask = myTask.startTask("validate");
573
574
575 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
576
577 final PrometheusDataList<?> myDataList = myEntry.getDataList();
578
579
580 if (myDataList != null) {
581
582 mySubTask.startTask(myDataList.listName());
583
584
585 myDataList.validate();
586 }
587 }
588
589
590 mySubTask.end();
591 }
592
593
594
595
596
597
598 public MetisDataEditState getEditState() {
599
600 final Iterator<PrometheusEditEntry<?>> myIterator = theMap.values().iterator();
601 MetisDataEditState myState = MetisDataEditState.CLEAN;
602 while (myIterator.hasNext()) {
603
604 final PrometheusEditEntry<?> myEntry = myIterator.next();
605 final PrometheusDataList<?> myDataList = myEntry.getDataList();
606
607
608 if (myDataList != null) {
609 myState = myState.combineState(myDataList.getEditState());
610 }
611 }
612
613
614 return myState;
615 }
616
617
618
619
620
621
622
623 public void processCommand(final PrometheusUIEvent pCmd,
624 final MetisErrorPanel pError) {
625
626 final OceanusProfile myTask = theControl.getNewProfile("EditCommand");
627
628
629 switch (pCmd) {
630 case OK:
631 applyChanges();
632 break;
633 case UNDO:
634 undoLastChange();
635 break;
636 case RESET:
637 resetChanges();
638 break;
639 default:
640 break;
641 }
642
643
644 final MetisViewerErrorList myErrors = theControl.getErrors();
645
646
647 if (!myErrors.isEmpty()) {
648 pError.setErrors(myErrors);
649 }
650
651
652 myTask.end();
653 }
654
655
656
657
658
659
660
661
662 public void processEditCommand(final PrometheusUIEvent pCmd,
663 final int pVersion,
664 final MetisErrorPanel pError) {
665
666 final OceanusProfile myTask = theControl.getNewProfile("ItemCommand");
667
668
669 switch (pCmd) {
670 case OK:
671 condenseHistory(pVersion);
672 break;
673 case UNDO:
674 undoLastChange();
675 break;
676 case REWIND:
677 rewindToVersion(pVersion);
678 break;
679 default:
680 break;
681 }
682
683
684 final MetisViewerErrorList myErrors = theControl.getErrors();
685
686
687 if (!myErrors.isEmpty()) {
688 pError.setErrors(myErrors);
689 }
690
691
692 myTask.end();
693 }
694
695
696
697
698
699
700 private void condenseHistory(final int pNewVersion) {
701
702 final OceanusProfile myTask = theControl.getActiveTask();
703 final OceanusProfile mySubTask = myTask.startTask("condenseHistory");
704
705
706 for (PrometheusEditEntry<?> myEntry : theMap.values()) {
707
708 final PrometheusDataList<?> myDataList = myEntry.getDataList();
709
710
711 if (myDataList != null) {
712
713 final OceanusProfile myListTask = mySubTask.startTask(myDataList.listName());
714 myListTask.startTask("Condense");
715
716
717 myDataList.condenseHistory(pNewVersion);
718
719
720 if (Boolean.FALSE.equals(itemEditing)) {
721 myListTask.startTask("postProcess");
722 myDataList.postProcessOnUpdate();
723 }
724 }
725 }
726
727
728 theVersion = pNewVersion;
729
730
731 theEventManager.fireEvent(PrometheusDataEvent.DATACHANGED);
732
733
734 mySubTask.end();
735 }
736 }