1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.prometheus.data;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory.GordianFactoryLock;
20 import io.github.tonywasher.joceanus.gordianknot.api.keyset.spec.GordianKeySetSpec;
21 import io.github.tonywasher.joceanus.metis.data.MetisDataFieldValue;
22 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
23 import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
24 import io.github.tonywasher.joceanus.metis.list.MetisListKey;
25 import io.github.tonywasher.joceanus.metis.toolkit.MetisToolkit;
26 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
27 import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
28 import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
29 import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlData.PrometheusControlDataList;
30 import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlKey.PrometheusControlKeyList;
31 import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlKeySet.PrometheusControlKeySetList;
32 import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyData.PrometheusCryptographicDataSet;
33 import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataListCtl;
34 import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataValidator;
35 import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataValidatorFactory;
36 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataKeySet.PrometheusDataKeySetList;
37 import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedDataItem.PrometheusEncryptedList;
38 import io.github.tonywasher.joceanus.prometheus.preference.PrometheusPreferenceManager;
39 import io.github.tonywasher.joceanus.prometheus.preference.PrometheusPreferenceSecurity.PrometheusSecurityPreferenceKey;
40 import io.github.tonywasher.joceanus.prometheus.preference.PrometheusPreferenceSecurity.PrometheusSecurityPreferences;
41 import io.github.tonywasher.joceanus.prometheus.security.PrometheusSecurityPasswordManager;
42 import io.github.tonywasher.joceanus.prometheus.toolkit.PrometheusToolkit;
43 import io.github.tonywasher.joceanus.tethys.api.thread.TethysUIThreadStatusReport;
44
45 import java.util.Iterator;
46 import java.util.LinkedHashMap;
47 import java.util.Map;
48 import java.util.Map.Entry;
49
50
51
52
53 public abstract class PrometheusDataSet
54 implements MetisFieldItem, PrometheusCryptographicDataSet {
55
56
57
58 protected static final int HASH_PRIME = 19;
59
60
61
62
63 @SuppressWarnings("rawtypes")
64 private static final MetisFieldSet<PrometheusDataSet> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusDataSet.class);
65
66
67
68
69 static {
70 FIELD_DEFS.declareLocalField(PrometheusDataResource.DATASET_VERSION, PrometheusDataSet::getVersion);
71 FIELD_DEFS.declareLocalFieldsForEnum(PrometheusCryptographyDataType.class, PrometheusDataSet::getFieldListValue);
72 }
73
74
75
76
77 private static final String TASK_SECINIT = PrometheusDataResource.TASK_SECURITY_INIT.getValue();
78
79
80
81
82 private static final String TASK_SECCHECK = PrometheusDataResource.TASK_SECURITY_CHECK.getValue();
83
84
85
86
87 private static final String TASK_SECUPDATE = PrometheusDataResource.TASK_SECURITY_UPDATE.getValue();
88
89
90
91
92 private static final String TASK_SECRENEW = PrometheusDataResource.TASK_SECURITY_RENEW.getValue();
93
94
95
96
97 private static final String TASK_DATAREBASE = PrometheusDataResource.TASK_DATA_REBASE.getValue();
98
99
100
101
102 private static final String TASK_DATADIFF = PrometheusDataResource.TASK_DATA_DIFF.getValue();
103
104
105
106
107 private final PrometheusSecurityPasswordManager thePasswordMgr;
108
109
110
111
112 private final GordianKeySetSpec theKeySetSpec;
113
114
115
116
117 private final int theNumActiveKeySets;
118
119
120
121
122 private int theNumEncrypted;
123
124
125
126
127 private int theVersion;
128
129
130
131
132 private final Map<MetisListKey, PrometheusDataList<?>> theListMap;
133
134
135
136
137 private final OceanusDataFormatter theFormatter;
138
139
140
141
142 private PrometheusDataValidatorFactory theValidatorFactory;
143
144
145
146
147
148
149 protected PrometheusDataSet(final PrometheusToolkit pToolkit) {
150
151 thePasswordMgr = pToolkit.getPasswordManager();
152 theKeySetSpec = thePasswordMgr.getLockSpec().getKeySetSpec();
153
154
155 final PrometheusPreferenceManager myPrefMgr = pToolkit.getPreferenceManager();
156 final PrometheusSecurityPreferences mySecPreferences = myPrefMgr.getPreferenceSet(PrometheusSecurityPreferences.class);
157 theNumActiveKeySets = mySecPreferences.getIntegerValue(PrometheusSecurityPreferenceKey.ACTIVEKEYSETS);
158
159
160 theListMap = new LinkedHashMap<>();
161
162
163 for (PrometheusCryptographyDataType myType : PrometheusCryptographyDataType.values()) {
164
165 addList(myType, newList(myType));
166 }
167
168
169 final MetisToolkit myToolkit = pToolkit.getToolkit();
170 theFormatter = myToolkit.getFormatter();
171 }
172
173
174
175
176
177
178 protected PrometheusDataSet(final PrometheusDataSet pSource) {
179
180
181 theNumActiveKeySets = pSource.getNumActiveKeySets();
182
183
184 thePasswordMgr = pSource.getPasswordMgr();
185
186
187 theKeySetSpec = pSource.getKeySetSpec();
188
189
190 theListMap = new LinkedHashMap<>();
191
192
193 theFormatter = pSource.getDataFormatter();
194
195
196 theValidatorFactory = pSource.theValidatorFactory;
197 }
198
199 @Override
200 public String formatObject(final OceanusDataFormatter pFormatter) {
201 return PrometheusDataSet.class.getSimpleName();
202 }
203
204 @Override
205 public OceanusDataFormatter getDataFormatter() {
206 return theFormatter;
207 }
208
209
210
211
212
213
214 public void setValidatorFactory(final PrometheusDataValidatorFactory pFactory) {
215 theValidatorFactory = pFactory;
216 }
217
218 @Override
219 public PrometheusDataValidator getValidator(final MetisListKey pItemType) {
220 if (theValidatorFactory == null) {
221 throw new IllegalStateException("Validator factory not set");
222 }
223 return theValidatorFactory.newValidator(pItemType);
224 }
225
226 @Override
227 public PrometheusSecurityPasswordManager getPasswordMgr() {
228 return thePasswordMgr;
229 }
230
231
232
233
234
235
236 public PrometheusControlKeyList getControlKeys() {
237 return getDataList(PrometheusCryptographyDataType.CONTROLKEY, PrometheusControlKeyList.class);
238 }
239
240
241
242
243
244
245 public PrometheusControlKeySetList getControlKeySets() {
246 return getDataList(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusControlKeySetList.class);
247 }
248
249
250
251
252
253
254 public PrometheusDataKeySetList getDataKeySets() {
255 return getDataList(PrometheusCryptographyDataType.DATAKEYSET, PrometheusDataKeySetList.class);
256 }
257
258
259
260
261
262
263 public PrometheusControlDataList getControlData() {
264 return getDataList(PrometheusCryptographyDataType.CONTROLDATA, PrometheusControlDataList.class);
265 }
266
267 @Override
268 public int getVersion() {
269 return theVersion;
270 }
271
272
273
274
275
276
277 public int getNumActiveKeySets() {
278 return theNumActiveKeySets;
279 }
280
281 @Override
282 public GordianKeySetSpec getKeySetSpec() {
283 return theKeySetSpec;
284 }
285
286
287
288
289
290
291 protected Map<MetisListKey, PrometheusDataList<?>> getListMap() {
292 return theListMap;
293 }
294
295 @Override
296 public boolean hasDataType(final MetisListKey pDataType) {
297 return theListMap.containsKey(pDataType);
298 }
299
300
301
302
303
304
305
306 public abstract PrometheusDataSet deriveCloneSet() throws OceanusException;
307
308
309
310
311
312
313
314 private PrometheusDataList<?> newList(final PrometheusCryptographyDataType pListType) {
315
316 return switch (pListType) {
317 case CONTROLDATA -> new PrometheusControlDataList(this);
318 case CONTROLKEY -> new PrometheusControlKeyList(this);
319 case CONTROLKEYSET -> new PrometheusControlKeySetList(this);
320 case DATAKEYSET -> new PrometheusDataKeySetList(this);
321 default -> throw new IllegalArgumentException(pListType.toString());
322 };
323 }
324
325
326
327
328
329
330
331 protected void buildEmptyCloneSet(final PrometheusDataSet pSource) throws OceanusException {
332
333 final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pSource.entryIterator();
334 while (myIterator.hasNext()) {
335 final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
336
337
338 final MetisListKey myType = myEntry.getKey();
339 final PrometheusDataList<?> myList = myEntry.getValue();
340
341
342 addList(myType, myList.getEmptyList(PrometheusListStyle.CLONE));
343 }
344 }
345
346
347
348
349
350
351
352 protected void deriveCloneSet(final PrometheusDataSet pSource) throws OceanusException {
353
354 final Map<MetisListKey, PrometheusDataList<?>> myOldMap = pSource.getListMap();
355
356
357 final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
358 while (myIterator.hasNext()) {
359 final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
360
361
362 final MetisListKey myType = myEntry.getKey();
363 final PrometheusDataList<?> myNew = myEntry.getValue();
364 final PrometheusDataList<?> myOld = myOldMap.get(myType);
365
366
367 myNew.cloneList(this, myOld);
368 }
369 }
370
371
372
373
374
375
376
377 public abstract PrometheusDataSet deriveUpdateSet() throws OceanusException;
378
379
380
381
382
383
384
385 protected void deriveUpdateSet(final PrometheusDataSet pSource) throws OceanusException {
386
387 final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pSource.entryIterator();
388 while (myIterator.hasNext()) {
389 final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
390
391
392 final MetisListKey myType = myEntry.getKey();
393 final PrometheusDataList<?> myList = myEntry.getValue();
394
395
396 addList(myType, myList.deriveList(PrometheusListStyle.UPDATE));
397 }
398
399
400 if (!isEmpty()) {
401
402 setVersion(1);
403 }
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417 public abstract PrometheusDataSet getDifferenceSet(TethysUIThreadStatusReport pReport,
418 PrometheusDataSet pOld) throws OceanusException;
419
420
421
422
423
424
425
426
427
428
429
430
431 protected void deriveDifferences(final TethysUIThreadStatusReport pReport,
432 final PrometheusDataSet pNew,
433 final PrometheusDataSet pOld) throws OceanusException {
434
435 final OceanusProfile myTask = pReport.getActiveTask();
436 final OceanusProfile myStage = myTask.startTask(TASK_DATADIFF);
437
438
439 final Map<MetisListKey, PrometheusDataList<?>> myOldMap = pOld.getListMap();
440
441
442 final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pNew.entryIterator();
443 while (myIterator.hasNext()) {
444 final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
445
446
447 final MetisListKey myType = myEntry.getKey();
448 final PrometheusDataList<?> myNew = myEntry.getValue();
449 final PrometheusDataList<?> myOld = myOldMap.get(myType);
450
451
452 myStage.startTask(myNew.listName());
453 addList(myType, myNew.deriveDifferences(this, myOld));
454 }
455
456
457 myStage.end();
458 }
459
460
461
462
463
464
465
466
467 public void reBase(final TethysUIThreadStatusReport pReport,
468 final PrometheusDataSet pOld) throws OceanusException {
469
470 final OceanusProfile myTask = pReport.getActiveTask();
471 final OceanusProfile myStage = myTask.startTask(TASK_DATAREBASE);
472
473
474 final Map<MetisListKey, PrometheusDataList<?>> myMap = pOld.getListMap();
475
476
477 boolean bUpdates = false;
478 final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
479 while (myIterator.hasNext()) {
480 final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
481
482
483 final MetisListKey myType = myEntry.getKey();
484 final PrometheusDataList<?> myList = myEntry.getValue();
485
486
487 myStage.startTask(myList.listName());
488 bUpdates |= myList.reBase(myMap.get(myType));
489 }
490
491
492 if (bUpdates) {
493
494 setVersion(getVersion() + 1);
495 }
496
497
498 myStage.end();
499 }
500
501
502
503
504
505
506
507 protected void addList(final MetisListKey pListType,
508 final PrometheusDataList<?> pList) {
509
510 theListMap.put(pListType, pList);
511
512
513 if (pList instanceof PrometheusEncryptedList) {
514 theNumEncrypted++;
515 }
516 }
517
518 @Override
519 public <L extends PrometheusDataListCtl<?>> L getDataList(final MetisListKey pListType,
520 final Class<L> pListClass) {
521
522 final PrometheusDataList<?> myList = theListMap.get(pListType);
523
524
525 return myList == null
526 ? null
527 : pListClass.cast(myList);
528 }
529
530
531
532
533
534
535
536 protected Object getFieldListValue(final MetisListKey pListType) {
537
538 final PrometheusDataList<?> myList = theListMap.get(pListType);
539
540
541 return myList == null
542 || myList.isEmpty()
543 ? MetisDataFieldValue.SKIP
544 : myList;
545 }
546
547
548
549
550
551
552
553
554 public <L extends PrometheusDataList<?>> L getDataList(final Class<L> pListClass) {
555
556 final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
557 while (myIterator.hasNext()) {
558 final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
559
560
561 final PrometheusDataList<?> myList = myEntry.getValue();
562 if (pListClass.equals(myList.getClass())) {
563 return pListClass.cast(myList);
564 }
565 }
566
567
568 return null;
569 }
570
571
572
573
574
575
576 public void setVersion(final int pVersion) {
577
578 theVersion = pVersion;
579
580
581 final Iterator<PrometheusDataList<?>> myIterator = iterator();
582 while (myIterator.hasNext()) {
583 final PrometheusDataList<?> myList = myIterator.next();
584
585
586 myList.setVersion(pVersion);
587 }
588 }
589
590
591
592
593
594
595 public void rewindToVersion(final int pVersion) {
596
597 theVersion = pVersion;
598
599
600 final Iterator<PrometheusDataList<?>> myIterator = iterator();
601 while (myIterator.hasNext()) {
602 final PrometheusDataList<?> myList = myIterator.next();
603
604
605 myList.rewindToVersion(pVersion);
606 }
607 }
608
609 @Override
610 public boolean equals(final Object pThat) {
611
612 if (this == pThat) {
613 return true;
614 }
615 if (pThat == null) {
616 return false;
617 }
618
619
620 if (pThat.getClass() != this.getClass()) {
621 return false;
622 }
623
624
625 final PrometheusDataSet myThat = (PrometheusDataSet) pThat;
626
627
628 if (myThat.getVersion() != theVersion) {
629 return false;
630 }
631
632
633 return theListMap.equals(myThat.getListMap());
634 }
635
636 @Override
637 public int hashCode() {
638
639 int myHashCode = 0;
640
641
642 final Iterator<PrometheusDataList<?>> myIterator = iterator();
643 while (myIterator.hasNext()) {
644 final PrometheusDataList<?> myList = myIterator.next();
645
646
647 myHashCode *= HASH_PRIME;
648 myHashCode += myList.hashCode();
649 }
650
651
652 return myHashCode;
653 }
654
655
656
657
658
659
660 public boolean isEmpty() {
661
662 final Iterator<PrometheusDataList<?>> myIterator = iterator();
663 while (myIterator.hasNext()) {
664 final PrometheusDataList<?> myList = myIterator.next();
665
666
667 if (!myList.isEmpty()) {
668 return false;
669 }
670 }
671
672
673 return true;
674 }
675
676
677
678
679
680
681 public boolean hasUpdates() {
682
683 final Iterator<PrometheusDataList<?>> myIterator = iterator();
684 while (myIterator.hasNext()) {
685 final PrometheusDataList<?> myList = myIterator.next();
686
687
688 if (myList.hasUpdates()) {
689 return true;
690 }
691 }
692
693
694 return false;
695 }
696
697
698
699
700
701
702 public PrometheusControlData getControl() {
703
704 return getControlData().getControl();
705 }
706
707 @Override
708 public PrometheusControlKey getControlKey() {
709
710 final PrometheusControlData myControl = getControl();
711
712
713 return myControl == null ? null : myControl.getControlKey();
714 }
715
716
717
718
719
720
721
722
723 public void initialiseSecurity(final TethysUIThreadStatusReport pReport,
724 final PrometheusDataSet pBase) throws OceanusException {
725
726 final OceanusProfile myTask = pReport.getActiveTask();
727 final OceanusProfile myStage = myTask.startTask(TASK_SECINIT);
728
729
730 pReport.initTask(TASK_SECINIT);
731 pReport.setNumStages(theNumEncrypted);
732
733
734 getControlKeys().initialiseSecurity(pBase);
735
736
737 final Map<MetisListKey, PrometheusDataList<?>> myMap = pBase.getListMap();
738
739
740 final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
741 while (myIterator.hasNext()) {
742 final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
743
744
745 final PrometheusDataList<?> myList = myEntry.getValue();
746 final PrometheusDataList<?> myBase = myMap.get(myEntry.getKey());
747
748
749 if (myList instanceof PrometheusEncryptedList) {
750
751 myStage.startTask(myList.listName());
752 final PrometheusEncryptedList<?> myEncrypted = (PrometheusEncryptedList<?>) myList;
753 myEncrypted.adoptSecurity(pReport, (PrometheusEncryptedList<?>) myBase);
754 }
755 }
756
757
758 myStage.end();
759 }
760
761
762
763
764
765
766
767 public void renewSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
768
769 final OceanusProfile myTask = pReport.getActiveTask();
770 final OceanusProfile myStage = myTask.startTask(TASK_SECRENEW);
771
772
773 final PrometheusControlData myControl = getControl();
774
775
776 final PrometheusControlKey myKey = getControlKeys().cloneItem(myControl.getControlKey());
777
778
779 myControl.setControlKey(myKey);
780
781
782 updateSecurity(pReport);
783
784
785 myStage.end();
786 }
787
788
789
790
791
792
793
794 public void checkSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
795
796 final OceanusProfile myTask = pReport.getActiveTask();
797 final OceanusProfile myStage = myTask.startTask(TASK_SECCHECK);
798
799
800 if (getControlKeys().size() > 1) {
801
802 updateSecurity(pReport);
803 }
804
805
806 myStage.end();
807 }
808
809
810
811
812
813
814
815 public void updateSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
816
817 final PrometheusControlKey myControl = getControlKey();
818
819
820 pReport.initTask(TASK_SECUPDATE);
821 pReport.setNumStages(theNumEncrypted);
822
823
824 final Iterator<PrometheusDataList<?>> myIterator = iterator();
825 while (myIterator.hasNext()) {
826 final PrometheusDataList<?> myList = myIterator.next();
827
828
829 if (myList instanceof PrometheusEncryptedList) {
830
831 final PrometheusEncryptedList<?> myEncrypted = (PrometheusEncryptedList<?>) myList;
832 myEncrypted.updateSecurity(pReport, myControl);
833 }
834 }
835
836
837 getControlKeys().purgeOldControlKeys();
838 setVersion(1);
839 }
840
841
842
843
844
845
846
847 public GordianFactoryLock getFactoryLock() throws OceanusException {
848
849 final PrometheusControlKey myKey = getControlKey();
850
851
852 return myKey == null
853 ? null
854 : myKey.getFactoryLock();
855 }
856
857
858
859
860
861
862
863
864 public void updateFactoryLock(final TethysUIThreadStatusReport pReport,
865 final String pSource) throws OceanusException {
866
867 getControlKey().updateFactoryLock(pSource);
868 }
869
870
871
872
873 public void undoLastChange() {
874
875 if (theVersion == 0) {
876 return;
877 }
878
879
880 theVersion--;
881
882
883 rewindToVersion(theVersion);
884 }
885
886
887
888
889 public void resetChanges() {
890
891 if (theVersion == 0) {
892 return;
893 }
894
895
896 theVersion = 0;
897
898
899 rewindToVersion(theVersion);
900 }
901
902
903
904
905
906
907 public Iterator<PrometheusDataList<?>> iterator() {
908 return theListMap.values().iterator();
909 }
910
911
912
913
914
915
916 public Iterator<Entry<MetisListKey, PrometheusDataList<?>>> entryIterator() {
917 return theListMap.entrySet().iterator();
918 }
919
920
921
922
923
924
925 public Iterator<MetisListKey> keyIterator() {
926 return theListMap.keySet().iterator();
927 }
928 }