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;
20  import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory.GordianFactoryLock;
21  import io.github.tonywasher.joceanus.gordianknot.util.GordianUtilities;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
23  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
24  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
25  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
26  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
27  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
28  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
29  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
30  import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlKeySet.PrometheusControlKeySetList;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyData.PrometheusControlKeyCtl;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyData.PrometheusControlKeySetCtl;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyData.PrometheusCryptographicDataSet;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataSetCtl;
35  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
36  import io.github.tonywasher.joceanus.prometheus.security.PrometheusSecurityPasswordManager;
37  
38  import java.util.ArrayList;
39  import java.util.Iterator;
40  import java.util.List;
41  
42  /**
43   * ControlKey definition and list. The Control Key represents the passwordHash that controls
44   * securing of the dataKeys. It maintains a map of the associated DataKeys.
45   *
46   * @author Tony Washer
47   */
48  public final class PrometheusControlKey
49          extends PrometheusDataItem
50          implements PrometheusControlKeyCtl {
51      /**
52       * Object name.
53       */
54      public static final String OBJECT_NAME = PrometheusCryptographyDataType.CONTROLKEY.getItemName();
55  
56      /**
57       * List name.
58       */
59      public static final String LIST_NAME = PrometheusCryptographyDataType.CONTROLKEY.getListName();
60  
61      /**
62       * KeySetHash Length.
63       */
64      public static final int LOCKLEN = GordianUtilities.getFactoryLockLen();
65  
66      /**
67       * Report fields.
68       */
69      private static final MetisFieldVersionedSet<PrometheusControlKey> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(PrometheusControlKey.class);
70  
71      /*
72       * FieldIds.
73       */
74      static {
75          FIELD_DEFS.declareByteArrayField(PrometheusDataResource.CONTROLKEY_LOCKBYTES, LOCKLEN);
76          FIELD_DEFS.declareDateField(PrometheusDataResource.CONTROLKEY_CREATION);
77          FIELD_DEFS.declareDerivedVersionedField(PrometheusDataResource.CONTROLKEY_LOCK);
78          FIELD_DEFS.declareLocalField(PrometheusDataResource.CONTROLKEYSET_LIST, PrometheusControlKey::getControlKeySets);
79      }
80  
81      /**
82       * Name of Database.
83       */
84      public static final String NAME_DATABASE = PrometheusDataResource.CONTROLKEY_DATABASE.getValue();
85  
86      /**
87       * The DataKeySetCache.
88       */
89      private ControlKeySetCache theKeySetCache = new ControlKeySetCache();
90  
91      /**
92       * Copy constructor.
93       *
94       * @param pList   the List to add to
95       * @param pSource the source key to copy
96       */
97      private PrometheusControlKey(final PrometheusControlKeyList pList,
98                                   final PrometheusControlKey pSource) {
99          /* Initialise the item */
100         super(pList, pSource);
101     }
102 
103     /**
104      * Values constructor.
105      *
106      * @param pList   the List to add to
107      * @param pValues the values constructor
108      * @throws OceanusException on error
109      */
110     private PrometheusControlKey(final PrometheusControlKeyList pList,
111                                  final PrometheusDataValues pValues) throws OceanusException {
112         /* Initialise the item */
113         super(pList, pValues);
114 
115         /* Protect against exceptions */
116         try {
117             /* Store FactoryLock */
118             Object myValue = pValues.getValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES);
119             if (myValue instanceof byte[] ba) {
120                 setValueFactoryLockBytes(ba);
121             }
122 
123             /* Store/Resolve Hash */
124             myValue = pValues.getValue(PrometheusDataResource.CONTROLKEY_LOCK);
125             if (myValue instanceof GordianFactoryLock l) {
126                 setValueFactoryLock(l);
127             } else if (getLockBytes() != null) {
128                 /* Access the Security manager */
129                 final PrometheusDataSetCtl myData = getDataSet();
130                 final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
131 
132                 /* Resolve the factoryLock */
133                 final GordianFactoryLock myLock = myPasswordMgr.resolveFactoryLock(getLockBytes(), NAME_DATABASE);
134 
135                 /* Store the factoryLock */
136                 setValueFactoryLock(myLock);
137             }
138 
139             /* Store the CreationDate */
140             myValue = pValues.getValue(PrometheusDataResource.CONTROLKEY_CREATION);
141             if (!(myValue instanceof OceanusDate)) {
142                 myValue = new OceanusDate();
143             }
144             setValueCreationDate((OceanusDate) myValue);
145 
146             /* Catch Exceptions */
147         } catch (OceanusException e) {
148             /* Pass on exception */
149             throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
150         }
151     }
152 
153     /**
154      * Constructor for a new ControlKey.
155      * <p>
156      * This will create a new DataKeySet with a new set of DataKeys.
157      *
158      * @param pList the list to which to add the key to
159      * @throws OceanusException on error
160      */
161     private PrometheusControlKey(final PrometheusControlKeyList pList) throws OceanusException {
162         /* Initialise the item */
163         super(pList, 0);
164 
165         /* Protect against exceptions */
166         try {
167             /* Access the Security manager */
168             final PrometheusDataSetCtl myData = getDataSet();
169             final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
170 
171             /* Create a new factoryLock with new password */
172             final GordianFactoryLock myLock = myPasswordMgr.newFactoryLock(NAME_DATABASE);
173 
174             /* Store the factoryLock */
175             setValueFactoryLockBytes(myLock.getLockBytes());
176             setValueFactoryLock(myLock);
177 
178             /* Allocate the DataKeySets */
179             allocateControlKeySets(myData);
180 
181             /* Set the creationDate */
182             setValueCreationDate(new OceanusDate());
183 
184             /* Catch Exceptions */
185         } catch (OceanusException e) {
186             /* Pass on exception */
187             throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
188         }
189     }
190 
191     /**
192      * Constructor for a new ControlKey with the same password.
193      * <p>
194      * This will create a new DataKeySet with a new cloned set of DataKeys.
195      *
196      * @param pKey the key to copy
197      * @throws OceanusException on error
198      */
199     private PrometheusControlKey(final PrometheusControlKey pKey) throws OceanusException {
200         /* Initialise the item */
201         super(pKey.getList(), 0);
202 
203         /* Protect against exceptions */
204         try {
205             /* Access the Security manager */
206             final PrometheusDataSetCtl myData = getDataSet();
207             final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
208 
209             /* ReSeed the security generator */
210             final GordianFactory myFactory = myPasswordMgr.getSecurityFactory();
211             myFactory.reSeedRandom();
212 
213             /* Create a similar factoryLock */
214             final GordianFactoryLock myLock = myPasswordMgr.similarFactoryLock(pKey.getFactoryLock());
215 
216             /* Store the factoryLock */
217             setValueFactoryLockBytes(myLock.getLockBytes());
218             setValueFactoryLock(myLock);
219 
220             /* Allocate the ControlKeySets */
221             allocateControlKeySets(myData);
222 
223             /* Catch Exceptions */
224         } catch (OceanusException e) {
225             /* Pass on exception */
226             throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
227         }
228     }
229 
230     @Override
231     public MetisFieldSetDef getDataFieldSet() {
232         return FIELD_DEFS;
233     }
234 
235     /**
236      * Obtain the dataKeySetCache.
237      *
238      * @return the dataKeySets
239      */
240     private ControlKeySetCache getControlKeySets() {
241         return theKeySetCache;
242     }
243 
244     /**
245      * Get the LockBytes.
246      *
247      * @return the hash bytes
248      */
249     public byte[] getLockBytes() {
250         return getValues().getValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES, byte[].class);
251     }
252 
253     /**
254      * Get the factoryLock.
255      *
256      * @return the factoryLock
257      */
258     public GordianFactoryLock getFactoryLock() {
259         return getValues().getValue(PrometheusDataResource.CONTROLKEY_LOCK, GordianFactoryLock.class);
260     }
261 
262     @Override
263     public GordianFactory getSecurityFactory() {
264         final GordianFactoryLock myLock = getFactoryLock();
265         return myLock == null ? null : myLock.getFactory();
266     }
267 
268     /**
269      * Get the CreationDate.
270      *
271      * @return the creationDate
272      */
273     public OceanusDate getCreationDate() {
274         return getValues().getValue(PrometheusDataResource.CONTROLKEY_CREATION, OceanusDate.class);
275     }
276 
277     /**
278      * Set the FactoryLock Bytes.
279      *
280      * @param pValue the factoryLock bytes
281      * @throws OceanusException on error
282      */
283     private void setValueFactoryLockBytes(final byte[] pValue) throws OceanusException {
284         getValues().setValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES, pValue);
285     }
286 
287     /**
288      * Set the FactoryLock.
289      *
290      * @param pValue the factoryLock
291      * @throws OceanusException on error
292      */
293     private void setValueFactoryLock(final GordianFactoryLock pValue) throws OceanusException {
294         getValues().setValue(PrometheusDataResource.CONTROLKEY_LOCK, pValue);
295     }
296 
297     /**
298      * Set the CreationDate.
299      *
300      * @param pValue the creationDate
301      * @throws OceanusException on error
302      */
303     private void setValueCreationDate(final OceanusDate pValue) throws OceanusException {
304         getValues().setValue(PrometheusDataResource.CONTROLKEY_CREATION, pValue);
305     }
306 
307     @Override
308     public PrometheusControlKey getBase() {
309         return (PrometheusControlKey) super.getBase();
310     }
311 
312     @Override
313     public PrometheusControlKeyList getList() {
314         return (PrometheusControlKeyList) super.getList();
315     }
316 
317     /**
318      * Obtain the next DataKeySet.
319      *
320      * @return the next dataKeySet
321      */
322     PrometheusDataKeySet getNextDataKeySet() {
323         return theKeySetCache.getNextDataKeySet();
324     }
325 
326     @Override
327     public int compareValues(final PrometheusDataItem pThat) {
328         /* Only sort on id */
329         return 0;
330     }
331 
332     /**
333      * Allocate a new ControlKeySet.
334      *
335      * @param pData the DataSet
336      * @throws OceanusException on error
337      */
338     private void allocateControlKeySets(final PrometheusDataSetCtl pData) throws OceanusException {
339         /* Access the ControlKeySet List */
340         final PrometheusControlKeySetList mySets = pData.getDataList(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusControlKeySetList.class);
341         setNewVersion();
342 
343         /* Loop to create sufficient ControlKeySets */
344         final int myNumKeySets = pData.getNumActiveKeySets();
345         for (int i = 0; i < myNumKeySets; i++) {
346             /* Allocate the ControlKeySet */
347             final PrometheusControlKeySet mySet = new PrometheusControlKeySet(mySets, this);
348             mySet.setNewVersion();
349             mySets.add(mySet);
350 
351             /* Register the DataKeySet */
352             theKeySetCache.registerControlKeySet(mySet);
353         }
354     }
355 
356     /**
357      * Delete the old set of ControlKey and DataKeys.
358      */
359     void deleteControlSet() {
360         /* Delete the ControlKeySet */
361         theKeySetCache.deleteControlKeySets();
362 
363         /* Mark this control key as deleted */
364         setDeleted(true);
365     }
366 
367     /**
368      * Update factoryLock.
369      *
370      * @param pSource the source of the data
371      * @throws OceanusException on error
372      */
373     void updateFactoryLock(final String pSource) throws OceanusException {
374         /* Access the Security manager */
375         final PrometheusDataSetCtl myData = getDataSet();
376         final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
377 
378         /* Obtain a new factoryLock */
379         final GordianFactoryLock myLock = myPasswordMgr.newFactoryLock(getSecurityFactory(), pSource);
380 
381         /* Store the current detail into history */
382         pushHistory();
383 
384         /* Update the factoryLock */
385         setValueFactoryLock(myLock);
386         setValueFactoryLockBytes(myLock.getLockBytes());
387         myData.setVersion(myData.getVersion() + 1);
388 
389         /* Check for changes */
390         checkForHistory();
391     }
392 
393     @Override
394     public void registerControlKeySet(final PrometheusControlKeySetCtl pKeySet) {
395         /* Store the DataKey into the map */
396         theKeySetCache.registerControlKeySet((PrometheusControlKeySet) pKeySet);
397     }
398 
399     /**
400      * ControlKey List.
401      */
402     public static class PrometheusControlKeyList
403             extends PrometheusDataList<PrometheusControlKey> {
404         /**
405          * Report fields.
406          */
407         private static final MetisFieldSet<PrometheusControlKeyList> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusControlKeyList.class);
408 
409         /**
410          * Construct an empty CORE ControlKey list.
411          *
412          * @param pData the DataSet for the list
413          */
414         protected PrometheusControlKeyList(final PrometheusDataSetCtl pData) {
415             this(pData, PrometheusListStyle.CORE);
416         }
417 
418         /**
419          * Construct an empty generic ControlKey list.
420          *
421          * @param pData  the DataSet for the list
422          * @param pStyle the style of the list
423          */
424         protected PrometheusControlKeyList(final PrometheusDataSetCtl pData,
425                                            final PrometheusListStyle pStyle) {
426             super(PrometheusControlKey.class, pData, PrometheusCryptographyDataType.CONTROLKEY, pStyle);
427         }
428 
429         /**
430          * Constructor for a cloned List.
431          *
432          * @param pSource the source List
433          */
434         private PrometheusControlKeyList(final PrometheusControlKeyList pSource) {
435             super(pSource);
436         }
437 
438         @Override
439         public MetisFieldSet<PrometheusControlKeyList> getDataFieldSet() {
440             return FIELD_DEFS;
441         }
442 
443         @Override
444         public String listName() {
445             return LIST_NAME;
446         }
447 
448         @Override
449         public MetisFieldSet<PrometheusControlKey> getItemFields() {
450             return PrometheusControlKey.FIELD_DEFS;
451         }
452 
453         @Override
454         public boolean includeDataXML() {
455             return false;
456         }
457 
458         @Override
459         public PrometheusCryptographicDataSet getDataSet() {
460             return (PrometheusCryptographicDataSet) super.getDataSet();
461         }
462 
463         @Override
464         protected PrometheusControlKeyList getEmptyList(final PrometheusListStyle pStyle) {
465             final PrometheusControlKeyList myList = new PrometheusControlKeyList(this);
466             myList.setStyle(pStyle);
467             return myList;
468         }
469 
470         @Override
471         public PrometheusControlKeyList deriveList(final PrometheusListStyle pStyle) throws OceanusException {
472             return (PrometheusControlKeyList) super.deriveList(pStyle);
473         }
474 
475         @Override
476         public PrometheusControlKeyList deriveDifferences(final PrometheusDataSetCtl pDataSet,
477                                                           final PrometheusDataList<?> pOld) {
478             return (PrometheusControlKeyList) super.deriveDifferences(pDataSet, pOld);
479         }
480 
481         @Override
482         public PrometheusControlKey addCopyItem(final PrometheusDataItem pItem) {
483             /* Can only clone a ControlKey */
484             if (!(pItem instanceof PrometheusControlKey)) {
485                 return null;
486             }
487 
488             /* Clone the control key */
489             final PrometheusControlKey myKey = new PrometheusControlKey(this, (PrometheusControlKey) pItem);
490             add(myKey);
491             return myKey;
492         }
493 
494         @Override
495         public PrometheusControlKey addNewItem() {
496             throw new UnsupportedOperationException();
497         }
498 
499         @Override
500         public PrometheusControlKey addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
501             /* Create the controlKey */
502             final PrometheusControlKey myKey = new PrometheusControlKey(this, pValues);
503 
504             /* Check that this keyId has not been previously added */
505             if (!isIdUnique(myKey.getIndexedId())) {
506                 myKey.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
507                 throw new PrometheusDataException(myKey, ERROR_VALIDATION);
508             }
509 
510             /* Add to the list */
511             add(myKey);
512 
513             /* Return it */
514             return myKey;
515         }
516 
517         /**
518          * Create a new ControlKey (with associated DataKeys).
519          *
520          * @return the new item
521          * @throws OceanusException on error
522          */
523         public PrometheusControlKey createNewKeySet() throws OceanusException {
524             /* Create the key */
525             final PrometheusControlKey myKey = new PrometheusControlKey(this);
526 
527             /* Add to the list */
528             add(myKey);
529             return myKey;
530         }
531 
532         /**
533          * Add a cloned ControlKey (with associated DataKeys).
534          *
535          * @param pSource the source key
536          * @return the new item
537          * @throws OceanusException on error
538          */
539         public PrometheusControlKey cloneItem(final PrometheusControlKey pSource) throws OceanusException {
540             /* Create the key */
541             final PrometheusControlKey myKey = new PrometheusControlKey(pSource);
542 
543             /* Add to the list */
544             add(myKey);
545             return myKey;
546         }
547 
548         /**
549          * Initialise Security from a DataBase for a SpreadSheet load.
550          *
551          * @param pDatabase the DataSet for the Database
552          * @throws OceanusException on error
553          */
554         protected void initialiseSecurity(final PrometheusCryptographicDataSet pDatabase) throws OceanusException {
555             /* Access the active control key from the database */
556             final PrometheusCryptographicDataSet myData = getDataSet();
557             final PrometheusControlKey myDatabaseKey = (PrometheusControlKey) pDatabase.getControlKey();
558             final PrometheusControlKey myKey;
559 
560             /* If we have an existing security key */
561             if (myDatabaseKey != null) {
562                 /* Clone the Control Key and its DataKeySets */
563                 myKey = cloneControlKey(myDatabaseKey);
564 
565                 /* else create a new security set */
566             } else {
567                 /* Create the new security set */
568                 myKey = createNewKeySet();
569             }
570 
571             /* Declare the Control Key */
572             myData.getControl().setControlKey(myKey);
573         }
574 
575         /**
576          * Delete old controlKeys.
577          */
578         protected void purgeOldControlKeys() {
579             /* Access the current control Key */
580             final PrometheusCryptographicDataSet myData = getDataSet();
581             final PrometheusControlKeyCtl myKey = myData.getControl().getControlKey();
582 
583             /* Loop through the controlKeys */
584             final Iterator<PrometheusControlKey> myIterator = iterator();
585             while (myIterator.hasNext()) {
586                 final PrometheusControlKey myCurr = myIterator.next();
587 
588                 /* Delete if this is not the active key */
589                 if (!myKey.equals(myCurr)) {
590                     myCurr.deleteControlSet();
591                 }
592             }
593         }
594 
595         /**
596          * Clone ControlKey from dataBase.
597          *
598          * @param pControlKey the ControlKey to clone
599          * @return the new control key
600          * @throws OceanusException on error
601          */
602         private PrometheusControlKey cloneControlKey(final PrometheusControlKey pControlKey) throws OceanusException {
603             /* Build data values */
604             final PrometheusDataValues myValues = new PrometheusDataValues(OBJECT_NAME);
605             myValues.addValue(MetisDataResource.DATA_ID, pControlKey.getIndexedId());
606             myValues.addValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES, pControlKey.getLockBytes());
607             myValues.addValue(PrometheusDataResource.CONTROLKEY_CREATION, pControlKey.getCreationDate());
608             myValues.addValue(PrometheusDataResource.CONTROLKEY_LOCK, pControlKey.getFactoryLock());
609 
610             /* Clone the control key */
611             final PrometheusControlKey myControl = addValuesItem(myValues);
612 
613             /* Access the ControlKeySet List */
614             final PrometheusDataSetCtl myData = getDataSet();
615             final PrometheusControlKeySetList myKeySets
616                     = myData.getDataList(PrometheusCryptographyDataType.CONTROLKEYSET, PrometheusControlKeySetList.class);
617 
618             /* Create a new ControlKeySetCache for this ControlKey */
619             final ControlKeySetCache mySource = pControlKey.getControlKeySets();
620             myControl.theKeySetCache = mySource.cloneControlKeySetCache(myControl, myKeySets);
621 
622             /* return the cloned key */
623             return myControl;
624         }
625 
626         @Override
627         public void postProcessOnLoad() throws OceanusException {
628             /* Just sort the list */
629             reSort();
630         }
631 
632         @Override
633         protected PrometheusDataMapItem allocateDataMap() {
634             /* Unused */
635             throw new UnsupportedOperationException();
636         }
637     }
638 
639     /**
640      * ControlKeySetCache.
641      */
642     private static final class ControlKeySetCache
643             implements MetisFieldItem, MetisDataList<PrometheusControlKeySet> {
644         /**
645          * Report fields.
646          */
647         private static final MetisFieldSet<ControlKeySetCache> FIELD_DEFS = MetisFieldSet.newFieldSet(ControlKeySetCache.class);
648 
649         /*
650          * Size Field Id.
651          */
652         static {
653             FIELD_DEFS.declareLocalField(MetisDataResource.LIST_SIZE, ControlKeySetCache::size);
654         }
655 
656         /**
657          * The list.
658          */
659         private final List<PrometheusControlKeySet> theList;
660 
661         /**
662          * Iterator.
663          */
664         private Iterator<PrometheusControlKeySet> theIterator;
665 
666         /**
667          * Constructor.
668          */
669         ControlKeySetCache() {
670             theList = new ArrayList<>();
671         }
672 
673         @Override
674         public MetisFieldSet<ControlKeySetCache> getDataFieldSet() {
675             return FIELD_DEFS;
676         }
677 
678         @Override
679         public List<PrometheusControlKeySet> getUnderlyingList() {
680             return theList;
681         }
682 
683         @Override
684         public String formatObject(final OceanusDataFormatter pFormatter) {
685             return getDataFieldSet().getName();
686         }
687 
688         /**
689          * Register the KeySet.
690          *
691          * @param pKeySet the KeySet to register
692          */
693         private void registerControlKeySet(final PrometheusControlKeySet pKeySet) {
694             /* If this is first registration */
695             if (!theList.contains(pKeySet)) {
696                 /* Add the KeySet */
697                 theList.add(pKeySet);
698 
699                 /* Reset any iterator */
700                 if (theIterator != null) {
701                     theIterator = iterator();
702                 }
703             }
704         }
705 
706         /**
707          * Get next DataKeySet.
708          *
709          * @return the next KeySet
710          */
711         private PrometheusDataKeySet getNextDataKeySet() {
712             /* Handle empty list */
713             if (isEmpty()) {
714                 return null;
715             }
716 
717             /* Handle initialisation and wrapping */
718             if (theIterator == null
719                     || !theIterator.hasNext()) {
720                 theIterator = iterator();
721             }
722 
723             /* Return the next KeySet */
724             return theIterator.next().getNextDataKeySet();
725         }
726 
727         /**
728          * Delete the ControlKeySets.
729          */
730         private void deleteControlKeySets() {
731             /* Loop through the KeySets */
732             final Iterator<PrometheusControlKeySet> myIterator = iterator();
733             while (myIterator.hasNext()) {
734                 final PrometheusControlKeySet mySet = myIterator.next();
735 
736                 /* Delete the KeySet */
737                 mySet.deleteControlKeySet();
738             }
739         }
740 
741         /**
742          * Clone controlKeySet Cache from a DataBase.
743          *
744          * @param pControlKey the ControlKey to clone
745          * @param pKeySets    the ControlKeySetList
746          * @return the new ControlKeySetCache
747          * @throws OceanusException on error
748          */
749         private ControlKeySetCache cloneControlKeySetCache(final PrometheusControlKey pControlKey,
750                                                            final PrometheusControlKeySetList pKeySets) throws OceanusException {
751             /* Create a new resource */
752             final ControlKeySetCache myCache = new ControlKeySetCache();
753 
754             /* Loop through the KeySets */
755             final Iterator<PrometheusControlKeySet> myIterator = iterator();
756             while (myIterator.hasNext()) {
757                 final PrometheusControlKeySet mySet = myIterator.next();
758 
759                 /* Create a new ControlKeySet for this ControlKey */
760                 final PrometheusControlKeySet myNewSet = pKeySets.cloneControlKeySet(pControlKey, mySet);
761                 myCache.registerControlKeySet(myNewSet);
762             }
763 
764             /* Return the cache */
765             return myCache;
766         }
767     }
768 }