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.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   * DataSet definition and list. A DataSet is a set of DataLists backed by the three security lists.
52   */
53  public abstract class PrometheusDataSet
54          implements MetisFieldItem, PrometheusCryptographicDataSet {
55      /**
56       * The Hash prime.
57       */
58      protected static final int HASH_PRIME = 19;
59  
60      /**
61       * Report fields.
62       */
63      @SuppressWarnings("rawtypes")
64      private static final MetisFieldSet<PrometheusDataSet> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusDataSet.class);
65  
66      /*
67       * Declare Fields.
68       */
69      static {
70          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATASET_VERSION, PrometheusDataSet::getVersion);
71          FIELD_DEFS.declareLocalFieldsForEnum(PrometheusCryptographyDataType.class, PrometheusDataSet::getFieldListValue);
72      }
73  
74      /**
75       * SecurityInit Task.
76       */
77      private static final String TASK_SECINIT = PrometheusDataResource.TASK_SECURITY_INIT.getValue();
78  
79      /**
80       * SecurityCheck Task.
81       */
82      private static final String TASK_SECCHECK = PrometheusDataResource.TASK_SECURITY_CHECK.getValue();
83  
84      /**
85       * SecurityUpdate Task.
86       */
87      private static final String TASK_SECUPDATE = PrometheusDataResource.TASK_SECURITY_UPDATE.getValue();
88  
89      /**
90       * SecurityReNew Task.
91       */
92      private static final String TASK_SECRENEW = PrometheusDataResource.TASK_SECURITY_RENEW.getValue();
93  
94      /**
95       * DataReBase Task.
96       */
97      private static final String TASK_DATAREBASE = PrometheusDataResource.TASK_DATA_REBASE.getValue();
98  
99      /**
100      * DataDiff Task.
101      */
102     private static final String TASK_DATADIFF = PrometheusDataResource.TASK_DATA_DIFF.getValue();
103 
104     /**
105      * Password Manager.
106      */
107     private final PrometheusSecurityPasswordManager thePasswordMgr;
108 
109     /**
110      * KeySetSpec.
111      */
112     private final GordianKeySetSpec theKeySetSpec;
113 
114     /**
115      * Number of activeKeySets.
116      */
117     private final int theNumActiveKeySets;
118 
119     /**
120      * Number of encrypted lists.
121      */
122     private int theNumEncrypted;
123 
124     /**
125      * Version of dataSet.
126      */
127     private int theVersion;
128 
129     /**
130      * The DataList Map.
131      */
132     private final Map<MetisListKey, PrometheusDataList<?>> theListMap;
133 
134     /**
135      * General formatter.
136      */
137     private final OceanusDataFormatter theFormatter;
138 
139     /**
140      * Validator factory.
141      */
142     private PrometheusDataValidatorFactory theValidatorFactory;
143 
144     /**
145      * Constructor for new empty DataSet.
146      *
147      * @param pToolkit the toolkit set
148      */
149     protected PrometheusDataSet(final PrometheusToolkit pToolkit) {
150         /* Store the password manager and Enum class */
151         thePasswordMgr = pToolkit.getPasswordManager();
152         theKeySetSpec = thePasswordMgr.getLockSpec().getKeySetSpec();
153 
154         /* Access the SecurityPreferences */
155         final PrometheusPreferenceManager myPrefMgr = pToolkit.getPreferenceManager();
156         final PrometheusSecurityPreferences mySecPreferences = myPrefMgr.getPreferenceSet(PrometheusSecurityPreferences.class);
157         theNumActiveKeySets = mySecPreferences.getIntegerValue(PrometheusSecurityPreferenceKey.ACTIVEKEYSETS);
158 
159         /* Create the map of additional DataLists */
160         theListMap = new LinkedHashMap<>();
161 
162         /* Loop through the list types */
163         for (PrometheusCryptographyDataType myType : PrometheusCryptographyDataType.values()) {
164             /* Create the empty list */
165             addList(myType, newList(myType));
166         }
167 
168         /* record formatter */
169         final MetisToolkit myToolkit = pToolkit.getToolkit();
170         theFormatter = myToolkit.getFormatter();
171     }
172 
173     /**
174      * Constructor for a cloned DataSet.
175      *
176      * @param pSource the source DataSet
177      */
178     protected PrometheusDataSet(final PrometheusDataSet pSource) {
179 
180         /* Access the #activeKeySets */
181         theNumActiveKeySets = pSource.getNumActiveKeySets();
182 
183         /* Store the password manager */
184         thePasswordMgr = pSource.getPasswordMgr();
185 
186         /* Store the keySetSpec */
187         theKeySetSpec = pSource.getKeySetSpec();
188 
189         /* Create the map of additional DataLists */
190         theListMap = new LinkedHashMap<>();
191 
192         /* Copy formatter */
193         theFormatter = pSource.getDataFormatter();
194 
195         /* Copy validator factory */
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      * Set the validator factory.
211      *
212      * @param pFactory the validator factory
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      * Get ControlKeys.
233      *
234      * @return the controlKeys
235      */
236     public PrometheusControlKeyList getControlKeys() {
237         return getDataList(PrometheusCryptographyDataType.CONTROLKEY, PrometheusControlKeyList.class);
238     }
239 
240     /**
241      * Get ControlKeySets.
242      *
243      * @return the controlKeySets
244      */
245     public PrometheusControlKeySetList getControlKeySets() {
246         return getDataList(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusControlKeySetList.class);
247     }
248 
249     /**
250      * Get DataKeySets.
251      *
252      * @return the dataKeySets
253      */
254     public PrometheusDataKeySetList getDataKeySets() {
255         return getDataList(PrometheusCryptographyDataType.DATAKEYSET, PrometheusDataKeySetList.class);
256     }
257 
258     /**
259      * Get ControlData.
260      *
261      * @return the controlData
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      * Get Number of activeKeySets.
274      *
275      * @return the # active KeySets
276      */
277     public int getNumActiveKeySets() {
278         return theNumActiveKeySets;
279     }
280 
281     @Override
282     public GordianKeySetSpec getKeySetSpec() {
283         return theKeySetSpec;
284     }
285 
286     /**
287      * Get List Map.
288      *
289      * @return the list map
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      * Construct a Clone for a DataSet.
302      *
303      * @return the extract
304      * @throws OceanusException on error
305      */
306     public abstract PrometheusDataSet deriveCloneSet() throws OceanusException;
307 
308     /**
309      * Create new list of required type.
310      *
311      * @param pListType the list type
312      * @return the new list
313      */
314     private PrometheusDataList<?> newList(final PrometheusCryptographyDataType pListType) {
315         /* Switch on list Type */
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      * Build an empty clone dataSet.
327      *
328      * @param pSource the source DataSet
329      * @throws OceanusException on error
330      */
331     protected void buildEmptyCloneSet(final PrometheusDataSet pSource) throws OceanusException {
332         /* Loop through the source lists */
333         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pSource.entryIterator();
334         while (myIterator.hasNext()) {
335             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
336 
337             /* Access components */
338             final MetisListKey myType = myEntry.getKey();
339             final PrometheusDataList<?> myList = myEntry.getValue();
340 
341             /* Create the empty cloned list */
342             addList(myType, myList.getEmptyList(PrometheusListStyle.CLONE));
343         }
344     }
345 
346     /**
347      * Construct a Clone for a DataSet.
348      *
349      * @param pSource the source DataSet
350      * @throws OceanusException on error
351      */
352     protected void deriveCloneSet(final PrometheusDataSet pSource) throws OceanusException {
353         /* Obtain listMaps */
354         final Map<MetisListKey, PrometheusDataList<?>> myOldMap = pSource.getListMap();
355 
356         /* Loop through the new lists */
357         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
358         while (myIterator.hasNext()) {
359             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
360 
361             /* Access components */
362             final MetisListKey myType = myEntry.getKey();
363             final PrometheusDataList<?> myNew = myEntry.getValue();
364             final PrometheusDataList<?> myOld = myOldMap.get(myType);
365 
366             /* Clone the list */
367             myNew.cloneList(this, myOld);
368         }
369     }
370 
371     /**
372      * Construct an update extract for a FinanceData Set.
373      *
374      * @return the extract
375      * @throws OceanusException on error
376      */
377     public abstract PrometheusDataSet deriveUpdateSet() throws OceanusException;
378 
379     /**
380      * Construct an update extract for a DataSet.
381      *
382      * @param pSource the source of the extract
383      * @throws OceanusException on error
384      */
385     protected void deriveUpdateSet(final PrometheusDataSet pSource) throws OceanusException {
386         /* Loop through the source lists */
387         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pSource.entryIterator();
388         while (myIterator.hasNext()) {
389             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
390 
391             /* Access components */
392             final MetisListKey myType = myEntry.getKey();
393             final PrometheusDataList<?> myList = myEntry.getValue();
394 
395             /* Create the update list */
396             addList(myType, myList.deriveList(PrometheusListStyle.UPDATE));
397         }
398 
399         /* If we have updates */
400         if (!isEmpty()) {
401             /* Update the version */
402             setVersion(1);
403         }
404     }
405 
406     /**
407      * Construct a difference extract between two DataSets. The difference extract will only contain
408      * items that differ between the two DataSets. Items that are in the new list, but not in the
409      * old list will be viewed as inserted. Items that are in the old list but not in the new list
410      * will be viewed as deleted. Items that are in both list but differ will be viewed as changed
411      *
412      * @param pReport the report
413      * @param pOld    The old list to extract from
414      * @return the difference set
415      * @throws OceanusException on error
416      */
417     public abstract PrometheusDataSet getDifferenceSet(TethysUIThreadStatusReport pReport,
418                                                        PrometheusDataSet pOld) throws OceanusException;
419 
420     /**
421      * Construct a difference extract between two DataSets. The difference extract will only contain
422      * items that differ between the two DataSets. Items that are in the new list, but not in the
423      * old list will be viewed as inserted. Items that are in the old list but not in the new list
424      * will be viewed as deleted. Items that are in both list but differ will be viewed as changed
425      *
426      * @param pReport the report
427      * @param pNew    The new list to compare
428      * @param pOld    The old list to compare
429      * @throws OceanusException on error
430      */
431     protected void deriveDifferences(final TethysUIThreadStatusReport pReport,
432                                      final PrometheusDataSet pNew,
433                                      final PrometheusDataSet pOld) throws OceanusException {
434         /* Access current profile */
435         final OceanusProfile myTask = pReport.getActiveTask();
436         final OceanusProfile myStage = myTask.startTask(TASK_DATADIFF);
437 
438         /* Obtain listMaps */
439         final Map<MetisListKey, PrometheusDataList<?>> myOldMap = pOld.getListMap();
440 
441         /* Loop through the new lists */
442         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = pNew.entryIterator();
443         while (myIterator.hasNext()) {
444             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
445 
446             /* Access components */
447             final MetisListKey myType = myEntry.getKey();
448             final PrometheusDataList<?> myNew = myEntry.getValue();
449             final PrometheusDataList<?> myOld = myOldMap.get(myType);
450 
451             /* Derive Differences */
452             myStage.startTask(myNew.listName());
453             addList(myType, myNew.deriveDifferences(this, myOld));
454         }
455 
456         /* Complete task */
457         myStage.end();
458     }
459 
460     /**
461      * ReBase this data set against an earlier version.
462      *
463      * @param pReport the report
464      * @param pOld    The old data to reBase against
465      * @throws OceanusException on error
466      */
467     public void reBase(final TethysUIThreadStatusReport pReport,
468                        final PrometheusDataSet pOld) throws OceanusException {
469         /* Access current profile */
470         final OceanusProfile myTask = pReport.getActiveTask();
471         final OceanusProfile myStage = myTask.startTask(TASK_DATAREBASE);
472 
473         /* Obtain old listMap */
474         final Map<MetisListKey, PrometheusDataList<?>> myMap = pOld.getListMap();
475 
476         /* Loop through the lists */
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             /* Access components */
483             final MetisListKey myType = myEntry.getKey();
484             final PrometheusDataList<?> myList = myEntry.getValue();
485 
486             /* ReBase on Old dataList */
487             myStage.startTask(myList.listName());
488             bUpdates |= myList.reBase(myMap.get(myType));
489         }
490 
491         /* If we have updates */
492         if (bUpdates) {
493             /* Update the version */
494             setVersion(getVersion() + 1);
495         }
496 
497         /* Complete task */
498         myStage.end();
499     }
500 
501     /**
502      * Add DataList to list of lists.
503      *
504      * @param pListType the list type
505      * @param pList     the list to add
506      */
507     protected void addList(final MetisListKey pListType,
508                            final PrometheusDataList<?> pList) {
509         /* Add the DataList to the map */
510         theListMap.put(pListType, pList);
511 
512         /* Note if the list is an encrypted list */
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         /* Access the list */
522         final PrometheusDataList<?> myList = theListMap.get(pListType);
523 
524         /* Cast correctly */
525         return myList == null
526                 ? null
527                 : pListClass.cast(myList);
528     }
529 
530     /**
531      * Obtain debug value for list.
532      *
533      * @param pListType the list type
534      * @return true/false
535      */
536     protected Object getFieldListValue(final MetisListKey pListType) {
537         /* Access the class */
538         final PrometheusDataList<?> myList = theListMap.get(pListType);
539 
540         /* Cast correctly */
541         return myList == null
542                 || myList.isEmpty()
543                 ? MetisDataFieldValue.SKIP
544                 : myList;
545     }
546 
547     /**
548      * Obtain DataList for an list class.
549      *
550      * @param <L>        the List type
551      * @param pListClass the class of the list
552      * @return the list of items
553      */
554     public <L extends PrometheusDataList<?>> L getDataList(final Class<L> pListClass) {
555         /* Loop through the lists */
556         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
557         while (myIterator.hasNext()) {
558             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
559 
560             /* Access components */
561             final PrometheusDataList<?> myList = myEntry.getValue();
562             if (pListClass.equals(myList.getClass())) {
563                 return pListClass.cast(myList);
564             }
565         }
566 
567         /* Not found */
568         return null;
569     }
570 
571     /**
572      * Set Version.
573      *
574      * @param pVersion the version
575      */
576     public void setVersion(final int pVersion) {
577         /* Record the version */
578         theVersion = pVersion;
579 
580         /* Loop through the List values */
581         final Iterator<PrometheusDataList<?>> myIterator = iterator();
582         while (myIterator.hasNext()) {
583             final PrometheusDataList<?> myList = myIterator.next();
584 
585             /* Set the Version */
586             myList.setVersion(pVersion);
587         }
588     }
589 
590     /**
591      * Rewind items to the required version.
592      *
593      * @param pVersion the version to rewind to
594      */
595     public void rewindToVersion(final int pVersion) {
596         /* Record the version */
597         theVersion = pVersion;
598 
599         /* Loop through the List values */
600         final Iterator<PrometheusDataList<?>> myIterator = iterator();
601         while (myIterator.hasNext()) {
602             final PrometheusDataList<?> myList = myIterator.next();
603 
604             /* Rewind the list */
605             myList.rewindToVersion(pVersion);
606         }
607     }
608 
609     @Override
610     public boolean equals(final Object pThat) {
611         /* Handle the trivial cases */
612         if (this == pThat) {
613             return true;
614         }
615         if (pThat == null) {
616             return false;
617         }
618 
619         /* Make sure that the object is a DataSet */
620         if (pThat.getClass() != this.getClass()) {
621             return false;
622         }
623 
624         /* Access the object as a DataSet */
625         final PrometheusDataSet myThat = (PrometheusDataSet) pThat;
626 
627         /* Check version and generation */
628         if (myThat.getVersion() != theVersion) {
629             return false;
630         }
631 
632         /* Compare the maps */
633         return theListMap.equals(myThat.getListMap());
634     }
635 
636     @Override
637     public int hashCode() {
638         /* Build initial hashCode */
639         int myHashCode = 0;
640 
641         /* Loop through the List values */
642         final Iterator<PrometheusDataList<?>> myIterator = iterator();
643         while (myIterator.hasNext()) {
644             final PrometheusDataList<?> myList = myIterator.next();
645 
646             /* Access equivalent list */
647             myHashCode *= HASH_PRIME;
648             myHashCode += myList.hashCode();
649         }
650 
651         /* Return the hashCode */
652         return myHashCode;
653     }
654 
655     /**
656      * Determine whether a DataSet has entries.
657      *
658      * @return <code>true</code> if the DataSet has entries
659      */
660     public boolean isEmpty() {
661         /* Loop through the List values */
662         final Iterator<PrometheusDataList<?>> myIterator = iterator();
663         while (myIterator.hasNext()) {
664             final PrometheusDataList<?> myList = myIterator.next();
665 
666             /* Determine whether the list is empty */
667             if (!myList.isEmpty()) {
668                 return false;
669             }
670         }
671 
672         /* Return the indication */
673         return true;
674     }
675 
676     /**
677      * Determine whether the Data-set has updates.
678      *
679      * @return <code>true</code> if the Data-set has updates, <code>false</code> if not
680      */
681     public boolean hasUpdates() {
682         /* Loop through the List values */
683         final Iterator<PrometheusDataList<?>> myIterator = iterator();
684         while (myIterator.hasNext()) {
685             final PrometheusDataList<?> myList = myIterator.next();
686 
687             /* Determine whether the list has updates */
688             if (myList.hasUpdates()) {
689                 return true;
690             }
691         }
692 
693         /* We have no updates */
694         return false;
695     }
696 
697     /**
698      * Get the control record.
699      *
700      * @return the control record
701      */
702     public PrometheusControlData getControl() {
703         /* Set the control */
704         return getControlData().getControl();
705     }
706 
707     @Override
708     public PrometheusControlKey getControlKey() {
709         /* Access the control element from the database */
710         final PrometheusControlData myControl = getControl();
711 
712         /* Return the key */
713         return myControl == null ? null : myControl.getControlKey();
714     }
715 
716     /**
717      * Initialise Security from database (if present).
718      *
719      * @param pReport the report
720      * @param pBase   the database data
721      * @throws OceanusException on error
722      */
723     public void initialiseSecurity(final TethysUIThreadStatusReport pReport,
724                                    final PrometheusDataSet pBase) throws OceanusException {
725         /* Access current profile */
726         final OceanusProfile myTask = pReport.getActiveTask();
727         final OceanusProfile myStage = myTask.startTask(TASK_SECINIT);
728 
729         /* Set the number of stages */
730         pReport.initTask(TASK_SECINIT);
731         pReport.setNumStages(theNumEncrypted);
732 
733         /* Initialise Security */
734         getControlKeys().initialiseSecurity(pBase);
735 
736         /* Obtain base listMap */
737         final Map<MetisListKey, PrometheusDataList<?>> myMap = pBase.getListMap();
738 
739         /* Loop through the List values */
740         final Iterator<Entry<MetisListKey, PrometheusDataList<?>>> myIterator = entryIterator();
741         while (myIterator.hasNext()) {
742             final Entry<MetisListKey, PrometheusDataList<?>> myEntry = myIterator.next();
743 
744             /* Access the two lists */
745             final PrometheusDataList<?> myList = myEntry.getValue();
746             final PrometheusDataList<?> myBase = myMap.get(myEntry.getKey());
747 
748             /* If the list is an encrypted list */
749             if (myList instanceof PrometheusEncryptedList) {
750                 /* Adopt the security */
751                 myStage.startTask(myList.listName());
752                 final PrometheusEncryptedList<?> myEncrypted = (PrometheusEncryptedList<?>) myList;
753                 myEncrypted.adoptSecurity(pReport, (PrometheusEncryptedList<?>) myBase);
754             }
755         }
756 
757         /* Complete the task */
758         myStage.end();
759     }
760 
761     /**
762      * Renew Security.
763      *
764      * @param pReport the report
765      * @throws OceanusException on error
766      */
767     public void renewSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
768         /* Access current profile */
769         final OceanusProfile myTask = pReport.getActiveTask();
770         final OceanusProfile myStage = myTask.startTask(TASK_SECRENEW);
771 
772         /* Access ControlData */
773         final PrometheusControlData myControl = getControl();
774 
775         /* Clone the control key */
776         final PrometheusControlKey myKey = getControlKeys().cloneItem(myControl.getControlKey());
777 
778         /* Declare the New Control Key */
779         myControl.setControlKey(myKey);
780 
781         /* Update Security */
782         updateSecurity(pReport);
783 
784         /* Complete task */
785         myStage.end();
786     }
787 
788     /**
789      * Check Security for incomplete security operations.
790      *
791      * @param pReport the report
792      * @throws OceanusException on error
793      */
794     public void checkSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
795         /* Access current profile */
796         final OceanusProfile myTask = pReport.getActiveTask();
797         final OceanusProfile myStage = myTask.startTask(TASK_SECCHECK);
798 
799         /* If there is more than one controlKey */
800         if (getControlKeys().size() > 1) {
801             /* Update to the selected controlKey */
802             updateSecurity(pReport);
803         }
804 
805         /* Complete task */
806         myStage.end();
807     }
808 
809     /**
810      * Update Security.
811      *
812      * @param pReport the report
813      * @throws OceanusException on error
814      */
815     public void updateSecurity(final TethysUIThreadStatusReport pReport) throws OceanusException {
816         /* Access the control key */
817         final PrometheusControlKey myControl = getControlKey();
818 
819         /* Set the number of stages */
820         pReport.initTask(TASK_SECUPDATE);
821         pReport.setNumStages(theNumEncrypted);
822 
823         /* Loop through the List values */
824         final Iterator<PrometheusDataList<?>> myIterator = iterator();
825         while (myIterator.hasNext()) {
826             final PrometheusDataList<?> myList = myIterator.next();
827 
828             /* If the list is an encrypted list */
829             if (myList instanceof PrometheusEncryptedList) {
830                 /* Update the security */
831                 final PrometheusEncryptedList<?> myEncrypted = (PrometheusEncryptedList<?>) myList;
832                 myEncrypted.updateSecurity(pReport, myControl);
833             }
834         }
835 
836         /* Delete old ControlSets */
837         getControlKeys().purgeOldControlKeys();
838         setVersion(1);
839     }
840 
841     /**
842      * Get the Password Hash.
843      *
844      * @return the password hash
845      * @throws OceanusException on error
846      */
847     public GordianFactoryLock getFactoryLock() throws OceanusException {
848         /* Access the active control key */
849         final PrometheusControlKey myKey = getControlKey();
850 
851         /* Set the control */
852         return myKey == null
853                 ? null
854                 : myKey.getFactoryLock();
855     }
856 
857     /**
858      * Update data with a new password.
859      *
860      * @param pReport the report
861      * @param pSource the source of the data
862      * @throws OceanusException on error
863      */
864     public void updateFactoryLock(final TethysUIThreadStatusReport pReport,
865                                   final String pSource) throws OceanusException {
866         /* Update the control details */
867         getControlKey().updateFactoryLock(pSource);
868     }
869 
870     /**
871      * Undo changes in a dataSet.
872      */
873     public void undoLastChange() {
874         /* Ignore if we have no changes */
875         if (theVersion == 0) {
876             return;
877         }
878 
879         /* Decrement version */
880         theVersion--;
881 
882         /* Rewind to the version */
883         rewindToVersion(theVersion);
884     }
885 
886     /**
887      * Reset changes in a dataSet.
888      */
889     public void resetChanges() {
890         /* Ignore if we have no changes */
891         if (theVersion == 0) {
892             return;
893         }
894 
895         /* Decrement version */
896         theVersion = 0;
897 
898         /* Rewind to the version */
899         rewindToVersion(theVersion);
900     }
901 
902     /**
903      * Obtain list iterator.
904      *
905      * @return the iterator
906      */
907     public Iterator<PrometheusDataList<?>> iterator() {
908         return theListMap.values().iterator();
909     }
910 
911     /**
912      * Obtain list iterator.
913      *
914      * @return the iterator
915      */
916     public Iterator<Entry<MetisListKey, PrometheusDataList<?>>> entryIterator() {
917         return theListMap.entrySet().iterator();
918     }
919 
920     /**
921      * Obtain listKey iterator.
922      *
923      * @return the iterator
924      */
925     public Iterator<MetisListKey> keyIterator() {
926         return theListMap.keySet().iterator();
927     }
928 }