View Javadoc
1   /*
2    * Prometheus: Application Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
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.GordianKeySetSpec;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataFieldValue;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
23  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
24  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
25  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedItem;
26  import io.github.tonywasher.joceanus.metis.list.MetisListKey;
27  import io.github.tonywasher.joceanus.metis.toolkit.MetisToolkit;
28  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
29  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
30  import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlData.PrometheusControlDataList;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlKey.PrometheusControlKeyList;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlKeySet.PrometheusControlKeySetList;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataKeySet.PrometheusDataKeySetList;
35  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList.PrometheusDataListSet;
36  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList.PrometheusListStyle;
37  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValidator.PrometheusDataValidatorFactory;
38  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedDataItem.PrometheusEncryptedList;
39  import io.github.tonywasher.joceanus.prometheus.preference.PrometheusPreferenceManager;
40  import io.github.tonywasher.joceanus.prometheus.preference.PrometheusPreferenceSecurity.PrometheusSecurityPreferenceKey;
41  import io.github.tonywasher.joceanus.prometheus.preference.PrometheusPreferenceSecurity.PrometheusSecurityPreferences;
42  import io.github.tonywasher.joceanus.prometheus.security.PrometheusSecurityPasswordManager;
43  import io.github.tonywasher.joceanus.prometheus.toolkit.PrometheusToolkit;
44  import io.github.tonywasher.joceanus.tethys.api.thread.TethysUIThreadStatusReport;
45  
46  import java.util.Iterator;
47  import java.util.LinkedHashMap;
48  import java.util.Map;
49  import java.util.Map.Entry;
50  
51  /**
52   * DataSet definition and list. A DataSet is a set of DataLists backed by the three security lists.
53   */
54  public abstract class PrometheusDataSet
55          implements MetisFieldItem, PrometheusDataListSet {
56      /**
57       * The Hash prime.
58       */
59      protected static final int HASH_PRIME = 19;
60  
61      /**
62       * Report fields.
63       */
64      @SuppressWarnings("rawtypes")
65      private static final MetisFieldSet<PrometheusDataSet> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusDataSet.class);
66  
67      /*
68       * Declare Fields.
69       */
70      static {
71          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATASET_VERSION, PrometheusDataSet::getVersion);
72          FIELD_DEFS.declareLocalFieldsForEnum(PrometheusCryptographyDataType.class, PrometheusDataSet::getFieldListValue);
73      }
74  
75      /**
76       * SecurityInit Task.
77       */
78      private static final String TASK_SECINIT = PrometheusDataResource.TASK_SECURITY_INIT.getValue();
79  
80      /**
81       * SecurityCheck Task.
82       */
83      private static final String TASK_SECCHECK = PrometheusDataResource.TASK_SECURITY_CHECK.getValue();
84  
85      /**
86       * SecurityUpdate Task.
87       */
88      private static final String TASK_SECUPDATE = PrometheusDataResource.TASK_SECURITY_UPDATE.getValue();
89  
90      /**
91       * SecurityReNew Task.
92       */
93      private static final String TASK_SECRENEW = PrometheusDataResource.TASK_SECURITY_RENEW.getValue();
94  
95      /**
96       * DataReBase Task.
97       */
98      private static final String TASK_DATAREBASE = PrometheusDataResource.TASK_DATA_REBASE.getValue();
99  
100     /**
101      * DataDiff Task.
102      */
103     private static final String TASK_DATADIFF = PrometheusDataResource.TASK_DATA_DIFF.getValue();
104 
105     /**
106      * Password Manager.
107      */
108     private final PrometheusSecurityPasswordManager thePasswordMgr;
109 
110     /**
111      * KeySetSpec.
112      */
113     private final GordianKeySetSpec theKeySetSpec;
114 
115     /**
116      * Number of activeKeySets.
117      */
118     private final int theNumActiveKeySets;
119 
120     /**
121      * Number of encrypted lists.
122      */
123     private int theNumEncrypted;
124 
125     /**
126      * Version of dataSet.
127      */
128     private int theVersion;
129 
130     /**
131      * The DataList Map.
132      */
133     private final Map<MetisListKey, PrometheusDataList<?>> theListMap;
134 
135     /**
136      * General formatter.
137      */
138     private final OceanusDataFormatter theFormatter;
139 
140     /**
141      * Validator factory.
142      */
143     private PrometheusDataValidatorFactory theValidatorFactory;
144 
145     /**
146      * Constructor for new empty DataSet.
147      *
148      * @param pToolkit the toolkit set
149      */
150     protected PrometheusDataSet(final PrometheusToolkit pToolkit) {
151         /* Store the password manager and Enum class */
152         thePasswordMgr = pToolkit.getPasswordManager();
153         theKeySetSpec = thePasswordMgr.getLockSpec().getKeySetSpec();
154 
155         /* Access the SecurityPreferences */
156         final PrometheusPreferenceManager myPrefMgr = pToolkit.getPreferenceManager();
157         final PrometheusSecurityPreferences mySecPreferences = myPrefMgr.getPreferenceSet(PrometheusSecurityPreferences.class);
158         theNumActiveKeySets = mySecPreferences.getIntegerValue(PrometheusSecurityPreferenceKey.ACTIVEKEYSETS);
159 
160         /* Create the map of additional DataLists */
161         theListMap = new LinkedHashMap<>();
162 
163         /* Loop through the list types */
164         for (PrometheusCryptographyDataType myType : PrometheusCryptographyDataType.values()) {
165             /* Create the empty list */
166             addList(myType, newList(myType));
167         }
168 
169         /* record formatter */
170         final MetisToolkit myToolkit = pToolkit.getToolkit();
171         theFormatter = myToolkit.getFormatter();
172     }
173 
174     /**
175      * Constructor for a cloned DataSet.
176      *
177      * @param pSource the source DataSet
178      */
179     protected PrometheusDataSet(final PrometheusDataSet pSource) {
180 
181         /* Access the #activeKeySets */
182         theNumActiveKeySets = pSource.getNumActiveKeySets();
183 
184         /* Store the password manager */
185         thePasswordMgr = pSource.getPasswordMgr();
186 
187         /* Store the keySetSpec */
188         theKeySetSpec = pSource.getKeySetSpec();
189 
190         /* Create the map of additional DataLists */
191         theListMap = new LinkedHashMap<>();
192 
193         /* Copy formatter */
194         theFormatter = pSource.getDataFormatter();
195 
196         /* Copy validator factory */
197         theValidatorFactory = pSource.theValidatorFactory;
198     }
199 
200     @Override
201     public String formatObject(final OceanusDataFormatter pFormatter) {
202         return PrometheusDataSet.class.getSimpleName();
203     }
204 
205     /**
206      * Obtain the data formatter.
207      *
208      * @return the formatter
209      */
210     public OceanusDataFormatter getDataFormatter() {
211         return theFormatter;
212     }
213 
214     /**
215      * Set the validator factory.
216      *
217      * @param pFactory the validator factory
218      */
219     public void setValidatorFactory(final PrometheusDataValidatorFactory pFactory) {
220         theValidatorFactory = pFactory;
221     }
222 
223     /**
224      * Obtain a validator fot=r the itemType.
225      *
226      * @param pItemType the itemType
227      * @return the validator.
228      */
229     PrometheusDataValidator getValidator(final MetisListKey pItemType) {
230         if (theValidatorFactory == null) {
231             throw new IllegalStateException("Validator factory not set");
232         }
233         return theValidatorFactory.newValidator(pItemType);
234     }
235 
236     /**
237      * Get Password Manager.
238      *
239      * @return the password manager
240      */
241     public PrometheusSecurityPasswordManager getPasswordMgr() {
242         return thePasswordMgr;
243     }
244 
245     /**
246      * Get ControlKeys.
247      *
248      * @return the controlKeys
249      */
250     public PrometheusControlKeyList getControlKeys() {
251         return getDataList(PrometheusCryptographyDataType.CONTROLKEY, PrometheusControlKeyList.class);
252     }
253 
254     /**
255      * Get ControlKeySets.
256      *
257      * @return the controlKeySets
258      */
259     public PrometheusControlKeySetList getControlKeySets() {
260         return getDataList(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusControlKeySetList.class);
261     }
262 
263     /**
264      * Get DataKeySets.
265      *
266      * @return the dataKeySets
267      */
268     public PrometheusDataKeySetList getDataKeySets() {
269         return getDataList(PrometheusCryptographyDataType.DATAKEYSET, PrometheusDataKeySetList.class);
270     }
271 
272     /**
273      * Get ControlData.
274      *
275      * @return the controlData
276      */
277     public PrometheusControlDataList getControlData() {
278         return getDataList(PrometheusCryptographyDataType.CONTROLDATA, PrometheusControlDataList.class);
279     }
280 
281     /**
282      * Get Version.
283      *
284      * @return the version
285      */
286     public int getVersion() {
287         return theVersion;
288     }
289 
290     /**
291      * Get Number of activeKeySets.
292      *
293      * @return the # active KeySets
294      */
295     public int getNumActiveKeySets() {
296         return theNumActiveKeySets;
297     }
298 
299     /**
300      * Get KeySetSpec.
301      *
302      * @return the keySetSpec
303      */
304     public GordianKeySetSpec getKeySetSpec() {
305         return theKeySetSpec;
306     }
307 
308     /**
309      * Get List Map.
310      *
311      * @return the list map
312      */
313     protected Map<MetisListKey, PrometheusDataList<?>> getListMap() {
314         return theListMap;
315     }
316 
317     @Override
318     public boolean hasDataType(final MetisListKey pDataType) {
319         return theListMap.containsKey(pDataType);
320     }
321 
322     /**
323      * Construct a Clone for a DataSet.
324      *
325      * @return the extract
326      * @throws OceanusException on error
327      */
328     public abstract PrometheusDataSet deriveCloneSet() throws OceanusException;
329 
330     /**
331      * Create new list of required type.
332      *
333      * @param pListType the list type
334      * @return the new list
335      */
336     private PrometheusDataList<?> newList(final PrometheusCryptographyDataType pListType) {
337         /* Switch on list Type */
338         switch (pListType) {
339             case CONTROLDATA:
340                 return new PrometheusControlDataList(this);
341             case CONTROLKEY:
342                 return new PrometheusControlKeyList(this);
343             case CONTROLKEYSET:
344                 return new PrometheusControlKeySetList(this);
345             case DATAKEYSET:
346                 return new PrometheusDataKeySetList(this);
347             default:
348                 throw new IllegalArgumentException(pListType.toString());
349         }
350     }
351 
352     /**
353      * Build an empty clone dataSet.
354      *
355      * @param pSource the source DataSet
356      * @throws OceanusException on error
357      */
358     protected void buildEmptyCloneSet(final PrometheusDataSet pSource) throws OceanusException {
359         /* Loop through the source lists */
360         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pSource.entryIterator();
361         while (myIterator.hasNext()) {
362             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
363 
364             /* Access components */
365             final MetisListKey myType = myEntry.getKey();
366             final PrometheusDataList<?> myList = myEntry.getValue();
367 
368             /* Create the empty cloned list */
369             addList(myType, myList.getEmptyList(PrometheusListStyle.CLONE));
370         }
371     }
372 
373     /**
374      * Construct a Clone for a DataSet.
375      *
376      * @param pSource the source DataSet
377      * @throws OceanusException on error
378      */
379     protected void deriveCloneSet(final PrometheusDataSet pSource) throws OceanusException {
380         /* Obtain listMaps */
381         final Map<MetisListKey, PrometheusDataList<?>> myOldMap = pSource.getListMap();
382 
383         /* Loop through the new lists */
384         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
385         while (myIterator.hasNext()) {
386             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
387 
388             /* Access components */
389             final MetisListKey myType = myEntry.getKey();
390             final PrometheusDataList<?> myNew = myEntry.getValue();
391             final PrometheusDataList<?> myOld = myOldMap.get(myType);
392 
393             /* Clone the list */
394             myNew.cloneList(this, myOld);
395         }
396     }
397 
398     /**
399      * Construct an update extract for a FinanceData Set.
400      *
401      * @return the extract
402      * @throws OceanusException on error
403      */
404     public abstract PrometheusDataSet deriveUpdateSet() throws OceanusException;
405 
406     /**
407      * Construct an update extract for a DataSet.
408      *
409      * @param pSource the source of the extract
410      * @throws OceanusException on error
411      */
412     protected void deriveUpdateSet(final PrometheusDataSet pSource) throws OceanusException {
413         /* Loop through the source lists */
414         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pSource.entryIterator();
415         while (myIterator.hasNext()) {
416             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
417 
418             /* Access components */
419             final MetisListKey myType = myEntry.getKey();
420             final PrometheusDataList<?> myList = myEntry.getValue();
421 
422             /* Create the update list */
423             addList(myType, myList.deriveList(PrometheusListStyle.UPDATE));
424         }
425 
426         /* If we have updates */
427         if (!isEmpty()) {
428             /* Update the version */
429             setVersion(1);
430         }
431     }
432 
433     /**
434      * Construct a difference extract between two DataSets. The difference extract will only contain
435      * items that differ between the two DataSets. Items that are in the new list, but not in the
436      * old list will be viewed as inserted. Items that are in the old list but not in the new list
437      * will be viewed as deleted. Items that are in both list but differ will be viewed as changed
438      *
439      * @param pReport the report
440      * @param pOld    The old list to extract from
441      * @return the difference set
442      * @throws OceanusException on error
443      */
444     public abstract PrometheusDataSet getDifferenceSet(TethysUIThreadStatusReport pReport,
445                                                        PrometheusDataSet pOld) throws OceanusException;
446 
447     /**
448      * Construct a difference extract between two DataSets. The difference extract will only contain
449      * items that differ between the two DataSets. Items that are in the new list, but not in the
450      * old list will be viewed as inserted. Items that are in the old list but not in the new list
451      * will be viewed as deleted. Items that are in both list but differ will be viewed as changed
452      *
453      * @param pReport the report
454      * @param pNew    The new list to compare
455      * @param pOld    The old list to compare
456      * @throws OceanusException on error
457      */
458     protected void deriveDifferences(final TethysUIThreadStatusReport pReport,
459                                      final PrometheusDataSet pNew,
460                                      final PrometheusDataSet pOld) throws OceanusException {
461         /* Access current profile */
462         final OceanusProfile myTask = pReport.getActiveTask();
463         final OceanusProfile myStage = myTask.startTask(TASK_DATADIFF);
464 
465         /* Obtain listMaps */
466         final Map<MetisListKey, PrometheusDataList<?>> myOldMap = pOld.getListMap();
467 
468         /* Loop through the new lists */
469         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pNew.entryIterator();
470         while (myIterator.hasNext()) {
471             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
472 
473             /* Access components */
474             final MetisListKey myType = myEntry.getKey();
475             final PrometheusDataList<?> myNew = myEntry.getValue();
476             final PrometheusDataList<?> myOld = myOldMap.get(myType);
477 
478             /* Derive Differences */
479             myStage.startTask(myNew.listName());
480             addList(myType, myNew.deriveDifferences(this, myOld));
481         }
482 
483         /* Complete task */
484         myStage.end();
485     }
486 
487     /**
488      * ReBase this data set against an earlier version.
489      *
490      * @param pReport the report
491      * @param pOld    The old data to reBase against
492      * @throws OceanusException on error
493      */
494     public void reBase(final TethysUIThreadStatusReport pReport,
495                        final PrometheusDataSet pOld) throws OceanusException {
496         /* Access current profile */
497         final OceanusProfile myTask = pReport.getActiveTask();
498         final OceanusProfile myStage = myTask.startTask(TASK_DATAREBASE);
499 
500         /* Obtain old listMap */
501         final Map<MetisListKey, PrometheusDataList<?>> myMap = pOld.getListMap();
502 
503         /* Loop through the lists */
504         boolean bUpdates = false;
505         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
506         while (myIterator.hasNext()) {
507             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
508 
509             /* Access components */
510             final MetisListKey myType = myEntry.getKey();
511             final PrometheusDataList<?> myList = myEntry.getValue();
512 
513             /* ReBase on Old dataList */
514             myStage.startTask(myList.listName());
515             bUpdates |= myList.reBase(myMap.get(myType));
516         }
517 
518         /* If we have updates */
519         if (bUpdates) {
520             /* Update the version */
521             setVersion(getVersion() + 1);
522         }
523 
524         /* Complete task */
525         myStage.end();
526     }
527 
528     /**
529      * Add DataList to list of lists.
530      *
531      * @param pListType the list type
532      * @param pList     the list to add
533      */
534     protected void addList(final MetisListKey pListType,
535                            final PrometheusDataList<?> pList) {
536         /* Add the DataList to the map */
537         theListMap.put(pListType, pList);
538 
539         /* Note if the list is an encrypted list */
540         if (pList instanceof PrometheusEncryptedList) {
541             theNumEncrypted++;
542         }
543     }
544 
545     @Override
546     public <L extends PrometheusDataList<?>> L getDataList(final MetisListKey pListType,
547                                                            final Class<L> pListClass) {
548         /* Access the list */
549         final PrometheusDataList<?> myList = theListMap.get(pListType);
550 
551         /* Cast correctly */
552         return myList == null
553                 ? null
554                 : pListClass.cast(myList);
555     }
556 
557     /**
558      * Obtain debug value for list.
559      *
560      * @param pListType the list type
561      * @return true/false
562      */
563     protected Object getFieldListValue(final MetisListKey pListType) {
564         /* Access the class */
565         final PrometheusDataList<?> myList = theListMap.get(pListType);
566 
567         /* Cast correctly */
568         return myList == null
569                 || myList.isEmpty()
570                 ? MetisDataFieldValue.SKIP
571                 : myList;
572     }
573 
574     /**
575      * Obtain DataList for an list class.
576      *
577      * @param <L>        the List type
578      * @param pListClass the class of the list
579      * @return the list of items
580      */
581     public <L extends PrometheusDataList<?>> L getDataList(final Class<L> pListClass) {
582         /* Loop through the lists */
583         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
584         while (myIterator.hasNext()) {
585             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
586 
587             /* Access components */
588             final PrometheusDataList<?> myList = myEntry.getValue();
589             if (pListClass.equals(myList.getClass())) {
590                 return pListClass.cast(myList);
591             }
592         }
593 
594         /* Not found */
595         return null;
596     }
597 
598     /**
599      * Set Version.
600      *
601      * @param pVersion the version
602      */
603     public void setVersion(final int pVersion) {
604         /* Record the version */
605         theVersion = pVersion;
606 
607         /* Loop through the List values */
608         final Iterator<PrometheusDataList<?>> myIterator = iterator();
609         while (myIterator.hasNext()) {
610             final PrometheusDataList<?> myList = myIterator.next();
611 
612             /* Set the Version */
613             myList.setVersion(pVersion);
614         }
615     }
616 
617     /**
618      * Rewind items to the required version.
619      *
620      * @param pVersion the version to rewind to
621      */
622     public void rewindToVersion(final int pVersion) {
623         /* Record the version */
624         theVersion = pVersion;
625 
626         /* Loop through the List values */
627         final Iterator<PrometheusDataList<?>> myIterator = iterator();
628         while (myIterator.hasNext()) {
629             final PrometheusDataList<?> myList = myIterator.next();
630 
631             /* Rewind the list */
632             myList.rewindToVersion(pVersion);
633         }
634     }
635 
636     @Override
637     public boolean equals(final Object pThat) {
638         /* Handle the trivial cases */
639         if (this == pThat) {
640             return true;
641         }
642         if (pThat == null) {
643             return false;
644         }
645 
646         /* Make sure that the object is a DataSet */
647         if (pThat.getClass() != this.getClass()) {
648             return false;
649         }
650 
651         /* Access the object as a DataSet */
652         final PrometheusDataSet myThat = (PrometheusDataSet) pThat;
653 
654         /* Check version and generation */
655         if (myThat.getVersion() != theVersion) {
656             return false;
657         }
658 
659         /* Compare the maps */
660         return theListMap.equals(myThat.getListMap());
661     }
662 
663     @Override
664     public int hashCode() {
665         /* Build initial hashCode */
666         int myHashCode = 0;
667 
668         /* Loop through the List values */
669         final Iterator<PrometheusDataList<?>> myIterator = iterator();
670         while (myIterator.hasNext()) {
671             final PrometheusDataList<?> myList = myIterator.next();
672 
673             /* Access equivalent list */
674             myHashCode *= HASH_PRIME;
675             myHashCode += myList.hashCode();
676         }
677 
678         /* Return the hashCode */
679         return myHashCode;
680     }
681 
682     /**
683      * Determine whether a DataSet has entries.
684      *
685      * @return <code>true</code> if the DataSet has entries
686      */
687     public boolean isEmpty() {
688         /* Loop through the List values */
689         final Iterator<PrometheusDataList<?>> myIterator = iterator();
690         while (myIterator.hasNext()) {
691             final PrometheusDataList<?> myList = myIterator.next();
692 
693             /* Determine whether the list is empty */
694             if (!myList.isEmpty()) {
695                 return false;
696             }
697         }
698 
699         /* Return the indication */
700         return true;
701     }
702 
703     /**
704      * Determine whether the Data-set has updates.
705      *
706      * @return <code>true</code> if the Data-set has updates, <code>false</code> if not
707      */
708     public boolean hasUpdates() {
709         /* Loop through the List values */
710         final Iterator<PrometheusDataList<?>> myIterator = iterator();
711         while (myIterator.hasNext()) {
712             final PrometheusDataList<?> myList = myIterator.next();
713 
714             /* Determine whether the list has updates */
715             if (myList.hasUpdates()) {
716                 return true;
717             }
718         }
719 
720         /* We have no updates */
721         return false;
722     }
723 
724     /**
725      * Get the control record.
726      *
727      * @return the control record
728      */
729     public PrometheusControlData getControl() {
730         /* Set the control */
731         return getControlData().getControl();
732     }
733 
734     /**
735      * Get the active control key.
736      *
737      * @return the control key
738      */
739     public PrometheusControlKey getControlKey() {
740         /* Access the control element from the database */
741         final PrometheusControlData myControl = getControl();
742 
743         /* Return the key */
744         return myControl == null ? null : myControl.getControlKey();
745     }
746 
747     /**
748      * Initialise Security from database (if present).
749      *
750      * @param pReport the report
751      * @param pBase   the database data
752      * @throws OceanusException on error
753      */
754     public void initialiseSecurity(final TethysUIThreadStatusReport pReport,
755                                    final PrometheusDataSet pBase) throws OceanusException {
756         /* Access current profile */
757         final OceanusProfile myTask = pReport.getActiveTask();
758         final OceanusProfile myStage = myTask.startTask(TASK_SECINIT);
759 
760         /* Set the number of stages */
761         pReport.initTask(TASK_SECINIT);
762         pReport.setNumStages(theNumEncrypted);
763 
764         /* Initialise Security */
765         getControlKeys().initialiseSecurity(pBase);
766 
767         /* Obtain base listMap */
768         final Map<MetisListKey, PrometheusDataList<?>> myMap = pBase.getListMap();
769 
770         /* Loop through the List values */
771         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
772         while (myIterator.hasNext()) {
773             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
774 
775             /* Access the two lists */
776             final PrometheusDataList<?> myList = myEntry.getValue();
777             final PrometheusDataList<?> myBase = myMap.get(myEntry.getKey());
778 
779             /* If the list is an encrypted list */
780             if (myList instanceof PrometheusEncryptedList) {
781                 /* Adopt the security */
782                 myStage.startTask(myList.listName());
783                 final PrometheusEncryptedList<?> myEncrypted = (PrometheusEncryptedList<?>) myList;
784                 myEncrypted.adoptSecurity(pReport, (PrometheusEncryptedList<?>) myBase);
785             }
786         }
787 
788         /* Complete the task */
789         myStage.end();
790     }
791 
792     /**
793      * Renew Security.
794      *
795      * @param pReport the report
796      * @throws OceanusException on error
797      */
798     public void renewSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
799         /* Access current profile */
800         final OceanusProfile myTask = pReport.getActiveTask();
801         final OceanusProfile myStage = myTask.startTask(TASK_SECRENEW);
802 
803         /* Access ControlData */
804         final PrometheusControlData myControl = getControl();
805 
806         /* Clone the control key */
807         final PrometheusControlKey myKey = getControlKeys().cloneItem(myControl.getControlKey());
808 
809         /* Declare the New Control Key */
810         myControl.setControlKey(myKey);
811 
812         /* Update Security */
813         updateSecurity(pReport);
814 
815         /* Complete task */
816         myStage.end();
817     }
818 
819     /**
820      * Check Security for incomplete security operations.
821      *
822      * @param pReport the report
823      * @throws OceanusException on error
824      */
825     public void checkSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
826         /* Access current profile */
827         final OceanusProfile myTask = pReport.getActiveTask();
828         final OceanusProfile myStage = myTask.startTask(TASK_SECCHECK);
829 
830         /* If there is more than one controlKey */
831         if (getControlKeys().size() > 1) {
832             /* Update to the selected controlKey */
833             updateSecurity(pReport);
834         }
835 
836         /* Complete task */
837         myStage.end();
838     }
839 
840     /**
841      * Update Security.
842      *
843      * @param pReport the report
844      * @throws OceanusException on error
845      */
846     public void updateSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
847         /* Access the control key */
848         final PrometheusControlKey myControl = getControlKey();
849 
850         /* Set the number of stages */
851         pReport.initTask(TASK_SECUPDATE);
852         pReport.setNumStages(theNumEncrypted);
853 
854         /* Loop through the List values */
855         final Iterator<PrometheusDataList<?>> myIterator = iterator();
856         while (myIterator.hasNext()) {
857             final PrometheusDataList<?> myList = myIterator.next();
858 
859             /* If the list is an encrypted list */
860             if (myList instanceof PrometheusEncryptedList) {
861                 /* Update the security */
862                 final PrometheusEncryptedList<?> myEncrypted = (PrometheusEncryptedList<?>) myList;
863                 myEncrypted.updateSecurity(pReport, myControl);
864             }
865         }
866 
867         /* Delete old ControlSets */
868         getControlKeys().purgeOldControlKeys();
869         setVersion(1);
870     }
871 
872     /**
873      * Get the Password Hash.
874      *
875      * @return the password hash
876      * @throws OceanusException on error
877      */
878     public GordianFactoryLock getFactoryLock() throws OceanusException {
879         /* Access the active control key */
880         final PrometheusControlKey myKey = getControlKey();
881 
882         /* Set the control */
883         return myKey == null
884                 ? null
885                 : myKey.getFactoryLock();
886     }
887 
888     /**
889      * Update data with a new password.
890      *
891      * @param pReport the report
892      * @param pSource the source of the data
893      * @throws OceanusException on error
894      */
895     public void updateFactoryLock(final TethysUIThreadStatusReport pReport,
896                                   final String pSource) throws OceanusException {
897         /* Update the control details */
898         getControlKey().updateFactoryLock(pSource);
899     }
900 
901     /**
902      * Undo changes in a dataSet.
903      */
904     public void undoLastChange() {
905         /* Ignore if we have no changes */
906         if (theVersion == 0) {
907             return;
908         }
909 
910         /* Decrement version */
911         theVersion--;
912 
913         /* Rewind to the version */
914         rewindToVersion(theVersion);
915     }
916 
917     /**
918      * Reset changes in a dataSet.
919      */
920     public void resetChanges() {
921         /* Ignore if we have no changes */
922         if (theVersion == 0) {
923             return;
924         }
925 
926         /* Decrement version */
927         theVersion = 0;
928 
929         /* Rewind to the version */
930         rewindToVersion(theVersion);
931     }
932 
933     /**
934      * Obtain list iterator.
935      *
936      * @return the iterator
937      */
938     public Iterator<PrometheusDataList<?>> iterator() {
939         return theListMap.values().iterator();
940     }
941 
942     /**
943      * Obtain list iterator.
944      *
945      * @return the iterator
946      */
947     public Iterator<Entry<MetisListKey, PrometheusDataList<?>>> entryIterator() {
948         return theListMap.entrySet().iterator();
949     }
950 
951     /**
952      * Obtain listKey iterator.
953      *
954      * @return the iterator
955      */
956     public Iterator<MetisListKey> keyIterator() {
957         return theListMap.keySet().iterator();
958     }
959 
960     /**
961      * Cryptography Data Enum Types.
962      */
963     public enum PrometheusCryptographyDataType
964             implements MetisListKey, MetisDataFieldId {
965         /**
966          * ControlKey.
967          */
968         CONTROLKEY(1),
969 
970         /**
971          * ControlKeySet.
972          */
973         CONTROLKEYSET(2),
974 
975         /**
976          * DataKeySet.
977          */
978         DATAKEYSET(3),
979 
980         /**
981          * ControlData.
982          */
983         CONTROLDATA(4);
984 
985         /**
986          * Maximum keyId.
987          */
988         public static final Integer MAXKEYID = CONTROLDATA.getItemKey();
989 
990         /**
991          * The list key.
992          */
993         private final Integer theKey;
994 
995         /**
996          * The String name.
997          */
998         private String theName;
999 
1000         /**
1001          * The list name.
1002          */
1003         private String theListName;
1004 
1005         /**
1006          * Constructor.
1007          *
1008          * @param pKey the key
1009          */
1010         PrometheusCryptographyDataType(final Integer pKey) {
1011             theKey = pKey;
1012         }
1013 
1014         @Override
1015         public String toString() {
1016             /* If we have not yet loaded the name */
1017             if (theName == null) {
1018                 /* Load the name */
1019                 theName = PrometheusDataResource.getKeyForCryptoItem(this).getValue();
1020             }
1021 
1022             /* return the name */
1023             return theName;
1024         }
1025 
1026         @Override
1027         public String getItemName() {
1028             return toString();
1029         }
1030 
1031         @Override
1032         public Class<? extends MetisFieldVersionedItem> getClazz() {
1033             switch (this) {
1034                 case CONTROLDATA:
1035                     return PrometheusControlData.class;
1036                 case CONTROLKEY:
1037                     return PrometheusControlKey.class;
1038                 case CONTROLKEYSET:
1039                     return PrometheusControlKeySet.class;
1040                 case DATAKEYSET:
1041                     return PrometheusDataKeySet.class;
1042                 default:
1043                     return null;
1044             }
1045         }
1046 
1047         @Override
1048         public String getListName() {
1049             /* If we have not yet loaded the name */
1050             if (theListName == null) {
1051                 /* Load the name */
1052                 theListName = PrometheusDataResource.getKeyForCryptoList(this).getValue();
1053             }
1054 
1055             /* return the list name */
1056             return theListName;
1057         }
1058 
1059         @Override
1060         public Integer getItemKey() {
1061             return theKey;
1062         }
1063 
1064         @Override
1065         public String getId() {
1066             return toString();
1067         }
1068     }
1069 }