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