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.metis.data.MetisDataDifference;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataNamedItem;
22  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
23  import io.github.tonywasher.joceanus.metis.list.MetisListKey;
24  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
25  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
26  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
27  
28  import java.util.ArrayList;
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Map;
33  
34  /**
35   * Template for a Static Data item and List.
36   *
37   * @author Tony Washer
38   */
39  public abstract class PrometheusStaticDataItem
40          extends PrometheusEncryptedDataItem
41          implements MetisDataNamedItem {
42      /**
43       * Report fields.
44       */
45      private static final PrometheusEncryptedFieldSet<PrometheusStaticDataItem> FIELD_DEFS = PrometheusEncryptedFieldSet.newEncryptedFieldSet(PrometheusStaticDataItem.class);
46  
47      /*
48       * FieldIds.
49       */
50      static {
51          FIELD_DEFS.declareEncryptedStringField(PrometheusDataResource.DATAITEM_FIELD_NAME, NAMELEN);
52          FIELD_DEFS.declareEncryptedStringField(PrometheusDataResource.DATAITEM_FIELD_DESC, DESCLEN);
53          FIELD_DEFS.declareBooleanField(PrometheusDataResource.STATICDATA_ENABLED);
54          FIELD_DEFS.declareIntegerField(PrometheusDataResource.STATICDATA_SORT);
55          FIELD_DEFS.declareEnumField(PrometheusDataResource.STATICDATA_CLASS);
56      }
57  
58      /**
59       * BadId error.
60       */
61      public static final String ERROR_BADID = PrometheusDataResource.STATICDATA_ERROR_ID.getValue();
62  
63      /**
64       * BadName error.
65       */
66      public static final String ERROR_BADNAME = PrometheusDataResource.STATICDATA_ERROR_NAME.getValue();
67  
68      /**
69       * The Enum Class for this Static Data.
70       */
71      private final Class<? extends PrometheusStaticDataClass> theEnumClass;
72  
73      /**
74       * Copy Constructor.
75       *
76       * @param pList   The list to associate the Static Data with
77       * @param pSource The static data to copy
78       */
79      protected PrometheusStaticDataItem(final PrometheusStaticList<?> pList,
80                                         final PrometheusStaticDataItem pSource) {
81          super(pList, pSource);
82          theEnumClass = pSource.getEnumClass();
83          setIndexedId(pSource.getIndexedId());
84      }
85  
86      /**
87       * Basic Constructor.
88       *
89       * @param pList  The list to associate the Static Data with
90       * @param pValue the name of the new item
91       * @throws OceanusException on error
92       */
93      protected PrometheusStaticDataItem(final PrometheusStaticList<?> pList,
94                                         final String pValue) throws OceanusException {
95          /* Call super constructor */
96          super(pList, 0);
97  
98          /* Determine the class */
99          theEnumClass = pList.getEnumClass();
100         parseEnumValue(pValue);
101 
102         /* Record the name */
103         setValueName(pValue);
104         setValueEnabled(Boolean.TRUE);
105     }
106 
107     /**
108      * Basic Constructor.
109      *
110      * @param pList  The list to associate the Static Data with
111      * @param pClass the class of the new item
112      * @throws OceanusException on error
113      */
114     protected PrometheusStaticDataItem(final PrometheusStaticList<?> pList,
115                                        final PrometheusStaticDataClass pClass) throws OceanusException {
116         /* Call super constructor */
117         super(pList, 0);
118 
119         /* Determine the class */
120         theEnumClass = pList.getEnumClass();
121 
122         /* Store the class */
123         setValueClass(pClass);
124 
125         /* Set encryption */
126         setNextDataKeySet();
127 
128         /* Access classId and order */
129         setIndexedId(pClass.getClassId());
130         setValueOrder(pClass.getOrder());
131 
132         /* Record the name */
133         setValueName(pClass.toString());
134         setValueEnabled(Boolean.TRUE);
135 
136         /* Set the DataKeySet */
137         setNextDataKeySet();
138     }
139 
140     /**
141      * Values constructor.
142      *
143      * @param pList   the List to add to
144      * @param pValues the values constructor
145      * @throws OceanusException on error
146      */
147     protected PrometheusStaticDataItem(final PrometheusStaticList<?> pList,
148                                        final PrometheusDataValues pValues) throws OceanusException {
149         /* Initialise the item */
150         super(pList, pValues);
151 
152         /* Access formatter */
153         final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
154 
155         /* Protect against exceptions */
156         try {
157             /* Determine the class */
158             theEnumClass = pList.getEnumClass();
159 
160             /* Store the Name */
161             Object myValue = pValues.getValue(PrometheusDataResource.DATAITEM_FIELD_NAME);
162             if (myValue instanceof String s) {
163                 setValueName(s);
164             } else if (myValue instanceof byte[] ba) {
165                 setValueName(ba);
166             }
167 
168             /* Store the Description */
169             myValue = pValues.getValue(PrometheusDataResource.DATAITEM_FIELD_DESC);
170             if (myValue instanceof String s) {
171                 setValueDesc(s);
172             } else if (myValue instanceof byte[] ba) {
173                 setValueDesc(ba);
174             }
175 
176             /* Store the class */
177             myValue = pValues.getValue(PrometheusDataResource.STATICDATA_CLASS);
178             if (myValue instanceof String s) {
179                 parseEnumValue(s);
180             } else {
181                 parseEnumValue(getIndexedId());
182             }
183 
184             /* Store the Order */
185             myValue = pValues.getValue(PrometheusDataResource.STATICDATA_SORT);
186             if (myValue instanceof Integer i) {
187                 setValueOrder(i);
188             } else if (myValue instanceof String s) {
189                 setValueOrder(myFormatter.parseValue(s, Integer.class));
190             }
191 
192             /* Store the Enabled flag */
193             myValue = pValues.getValue(PrometheusDataResource.STATICDATA_ENABLED);
194             switch (myValue) {
195                 case Boolean b -> setValueEnabled(b);
196                 case String s -> setValueEnabled(myFormatter.parseValue(s, Boolean.class));
197                 case null, default -> setValueEnabled(Boolean.TRUE);
198             }
199 
200             /* Catch Exceptions */
201         } catch (NumberFormatException
202                  | OceanusException e) {
203             /* Pass on exception */
204             throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
205         }
206     }
207 
208     @Override
209     public MetisFieldSetDef getDataFieldSet() {
210         return FIELD_DEFS;
211     }
212 
213     @Override
214     public String formatObject(final OceanusDataFormatter pFormatter) {
215         return toString();
216     }
217 
218     @Override
219     public String toString() {
220         return getName();
221     }
222 
223     @Override
224     public boolean includeXmlField(final MetisDataFieldId pField) {
225         /* Determine whether fields should be included */
226         if (PrometheusDataResource.DATAITEM_FIELD_NAME.equals(pField)) {
227             return true;
228         }
229         if (PrometheusDataResource.DATAITEM_FIELD_DESC.equals(pField)) {
230             return getDesc() != null;
231         }
232         if (PrometheusDataResource.STATICDATA_ENABLED.equals(pField)) {
233             return !getEnabled();
234         }
235         if (PrometheusDataResource.STATICDATA_CLASS.equals(pField)) {
236             return !getName().equalsIgnoreCase(getStaticClass().name());
237         }
238 
239         /* Pass call on */
240         return super.includeXmlField(pField);
241     }
242 
243     @Override
244     public final String getName() {
245         return getValues().getValue(PrometheusDataResource.DATAITEM_FIELD_NAME, String.class);
246     }
247 
248     /**
249      * Return the encrypted name of the Static Data.
250      *
251      * @return the encrypted name
252      */
253     public final byte[] getNameBytes() {
254         return getValues().getEncryptedBytes(PrometheusDataResource.DATAITEM_FIELD_NAME);
255     }
256 
257     /**
258      * Return the encrypted name field of the Static Data.
259      *
260      * @return the encrypted field
261      */
262     private PrometheusEncryptedPair getNameField() {
263         return getValues().getEncryptedPair(PrometheusDataResource.DATAITEM_FIELD_NAME);
264     }
265 
266     /**
267      * Return the description of the Static Data.
268      *
269      * @return the description
270      */
271     public final String getDesc() {
272         return getValues().getValue(PrometheusDataResource.DATAITEM_FIELD_DESC, String.class);
273     }
274 
275     /**
276      * Return the encrypted description of the Static Data.
277      *
278      * @return the encrypted description
279      */
280     public final byte[] getDescBytes() {
281         return getValues().getEncryptedBytes(PrometheusDataResource.DATAITEM_FIELD_DESC);
282     }
283 
284     /**
285      * Return the encrypted description field of the Static Data.
286      *
287      * @return the encrypted name
288      */
289     private PrometheusEncryptedPair getDescField() {
290         return getValues().getEncryptedPair(PrometheusDataResource.DATAITEM_FIELD_DESC);
291     }
292 
293     /**
294      * Return the sort order of the Static Data.
295      *
296      * @return the order
297      */
298     public final Integer getOrder() {
299         return getValues().getValue(PrometheusDataResource.STATICDATA_SORT, Integer.class);
300     }
301 
302     /**
303      * Return the Static class of the Static Data.
304      *
305      * @return the class
306      */
307     public final PrometheusStaticDataClass getStaticClass() {
308         return getValues().getValue(PrometheusDataResource.STATICDATA_CLASS, PrometheusStaticDataClass.class);
309     }
310 
311     /**
312      * Is the Static item enabled.
313      *
314      * @return <code>true/false</code>
315      */
316     public final boolean getEnabled() {
317         return getValues().getValue(PrometheusDataResource.STATICDATA_ENABLED, Boolean.class);
318     }
319 
320     @Override
321     public boolean isDisabled() {
322         return !getEnabled();
323     }
324 
325     /**
326      * Obtain the Enum class of this Static Data.
327      *
328      * @return the class
329      */
330     protected final Class<? extends PrometheusStaticDataClass> getEnumClass() {
331         return theEnumClass;
332     }
333 
334     /**
335      * Set the Name.
336      *
337      * @param pValue the name
338      * @throws OceanusException on error
339      */
340     private void setValueName(final String pValue) throws OceanusException {
341         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pValue);
342     }
343 
344     /**
345      * Set the Name.
346      *
347      * @param pBytes the encrypted name
348      * @throws OceanusException on error
349      */
350     private void setValueName(final byte[] pBytes) throws OceanusException {
351         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pBytes, String.class);
352     }
353 
354     /**
355      * Set the Name field.
356      *
357      * @param pField the encrypted name
358      */
359     private void setValueName(final PrometheusEncryptedPair pField) {
360         getValues().setUncheckedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pField);
361     }
362 
363     /**
364      * Set the Description.
365      *
366      * @param pValue the description
367      * @throws OceanusException on error
368      */
369     protected final void setValueDesc(final String pValue) throws OceanusException {
370         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pValue);
371     }
372 
373     /**
374      * Set the Description.
375      *
376      * @param pBytes the encrypted description
377      * @throws OceanusException on error
378      */
379     private void setValueDesc(final byte[] pBytes) throws OceanusException {
380         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pBytes, String.class);
381     }
382 
383     /**
384      * Set the Description field.
385      *
386      * @param pField the encrypted description
387      */
388     private void setValueDesc(final PrometheusEncryptedPair pField) {
389         getValues().setUncheckedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pField);
390     }
391 
392     /**
393      * Set the Enabled flag.
394      *
395      * @param isEnabled TRUE/FALSE
396      */
397     protected final void setValueEnabled(final Boolean isEnabled) {
398         getValues().setUncheckedValue(PrometheusDataResource.STATICDATA_ENABLED, isEnabled);
399     }
400 
401     /**
402      * Set the Order.
403      *
404      * @param pOrder the order
405      */
406     private void setValueOrder(final Integer pOrder) {
407         getValues().setUncheckedValue(PrometheusDataResource.STATICDATA_SORT, pOrder);
408     }
409 
410     /**
411      * Set the Class.
412      *
413      * @param pClass the class
414      */
415     private void setValueClass(final PrometheusStaticDataClass pClass) {
416         getValues().setUncheckedValue(PrometheusDataResource.STATICDATA_CLASS, pClass);
417     }
418 
419     @Override
420     public int compareValues(final PrometheusDataItem pThat) {
421         /* Access as StaticDataItem */
422         final PrometheusStaticDataItem myThat = (PrometheusStaticDataItem) pThat;
423 
424         /* Make sure that the object is the same enumeration class */
425         if (!MetisDataDifference.isEqual(getEnumClass(), myThat.getEnumClass())) {
426             /* Order the classes by canonical name */
427             return getEnumClass().getCanonicalName().compareTo(myThat.getEnumClass().getCanonicalName());
428         }
429 
430         /* Compare on order and name */
431         final int iDiff = getOrder() - myThat.getOrder();
432         return iDiff != 0 ? iDiff : MetisDataDifference.compareObject(getName(), myThat.getName());
433     }
434 
435     @Override
436     public PrometheusStaticList<?> getList() {
437         return (PrometheusStaticList<?>) super.getList();
438     }
439 
440     /**
441      * Parse enum type.
442      *
443      * @param pValue the value
444      * @throws OceanusException on error
445      */
446     private void parseEnumValue(final String pValue) throws OceanusException {
447         final Class<? extends PrometheusStaticDataClass> myClass = getEnumClass();
448         final PrometheusStaticDataClass[] myEnums = myClass.getEnumConstants();
449 
450         /* Loop through the enum constants */
451         for (PrometheusStaticDataClass myValue : myEnums) {
452             /* If this is the desired value */
453             if (myValue.toString().equalsIgnoreCase(pValue)) {
454                 /* Store the class */
455                 setValueClass(myValue);
456 
457                 /* Access classId and order */
458                 setIndexedId(myValue.getClassId());
459                 setValueOrder(myValue.getOrder());
460                 break;
461             }
462         }
463 
464         /* Reject if we didn't find the class */
465         if (getStaticClass() == null) {
466             throw new PrometheusDataException(ERROR_BADNAME + " " + myClass.getSimpleName() + ": " + pValue);
467         }
468     }
469 
470     /**
471      * Parse enum type.
472      *
473      * @param pValue the value
474      * @throws OceanusException on error
475      */
476     private void parseEnumValue(final Integer pValue) throws OceanusException {
477         final Class<? extends PrometheusStaticDataClass> myClass = getEnumClass();
478         final PrometheusStaticDataClass[] myEnums = myClass.getEnumConstants();
479 
480         /* Loop through the enum constants */
481         for (PrometheusStaticDataClass myValue : myEnums) {
482             /* If this is the desired value */
483             if (pValue.equals(myValue.getClassId())) {
484                 /* Store the class */
485                 setValueClass(myValue);
486 
487                 /* Access classId and order */
488                 setIndexedId(myValue.getClassId());
489                 setValueOrder(myValue.getOrder());
490                 break;
491             }
492         }
493 
494         /* Reject if we didn't find the class */
495         if (getStaticClass() == null) {
496             throw new PrometheusDataException(ERROR_BADNAME + " " + myClass.getSimpleName() + ": " + pValue);
497         }
498     }
499 
500     /**
501      * Set a new name.
502      *
503      * @param pName the name
504      * @throws OceanusException on error
505      */
506     public void setName(final String pName) throws OceanusException {
507         setValueName(pName);
508     }
509 
510     /**
511      * Set a new description.
512      *
513      * @param pDesc the description
514      * @throws OceanusException on error
515      */
516     public void setDescription(final String pDesc) throws OceanusException {
517         /* Set the appropriate value */
518         setValueDesc(pDesc);
519     }
520 
521     /**
522      * Set Enabled indicator.
523      *
524      * @param isEnabled TRUE/FALSE
525      */
526     public void setEnabled(final boolean isEnabled) {
527         /* Set the appropriate value */
528         setValueEnabled(isEnabled);
529     }
530 
531     /**
532      * Set Order indicator.
533      *
534      * @param iOrder the order
535      */
536     public void setOrder(final int iOrder) {
537         /* Set the appropriate value */
538         setValueOrder(iOrder);
539     }
540 
541     @Override
542     public boolean applyChanges(final PrometheusDataItem pData) {
543         /* Can only apply changes for Static Data */
544         if (!(pData instanceof PrometheusStaticDataItem)) {
545             return false;
546         }
547 
548         /* Access the data */
549         final PrometheusStaticDataItem myData = (PrometheusStaticDataItem) pData;
550 
551         /* Store the current detail into history */
552         pushHistory();
553 
554         /* Apply basic changes */
555         applyBasicChanges(myData);
556 
557         /* Check for changes */
558         return checkForHistory();
559     }
560 
561     /**
562      * Apply basic changes.
563      *
564      * @param pData the changed element
565      */
566     protected void applyBasicChanges(final PrometheusStaticDataItem pData) {
567         /* Update the name if required */
568         if (!MetisDataDifference.isEqual(getName(), pData.getName())) {
569             setValueName(pData.getNameField());
570         }
571 
572         /* Update the description if required */
573         if (!MetisDataDifference.isEqual(getDesc(), pData.getDesc())) {
574             setValueDesc(pData.getDescField());
575         }
576 
577         /* Update the enabled indication if required */
578         if (!MetisDataDifference.isEqual(getEnabled(), pData.getEnabled())) {
579             setEnabled(pData.getEnabled());
580         }
581 
582         /* Update the order indication if required */
583         if (!MetisDataDifference.isEqual(getOrder(), pData.getOrder())) {
584             setOrder(pData.getOrder());
585         }
586     }
587 
588     @Override
589     public void adjustMapForItem() {
590         final PrometheusStaticList<?> myList = getList();
591         final PrometheusStaticDataMap<?> myMap = myList.getDataMap();
592         myMap.adjustForItem(myList.getBaseClass().cast(this));
593     }
594 
595     /**
596      * Represents a list of StaticData objects.
597      *
598      * @param <T> the item type
599      */
600     public abstract static class PrometheusStaticList<T extends PrometheusStaticDataItem>
601             extends PrometheusEncryptedList<T> {
602         /*
603          * Report fields.
604          */
605         static {
606             MetisFieldSet.newFieldSet(PrometheusStaticList.class);
607         }
608 
609         /**
610          * Construct a generic static data list.
611          *
612          * @param pBaseClass the class of the underlying object
613          * @param pData      the dataSet
614          * @param pItemType  the item type
615          * @param pStyle     the style of the list
616          */
617         protected PrometheusStaticList(final Class<T> pBaseClass,
618                                        final PrometheusDataSet pData,
619                                        final MetisListKey pItemType,
620                                        final PrometheusListStyle pStyle) {
621             super(pBaseClass, pData, pItemType, pStyle);
622         }
623 
624         /**
625          * Constructor for a cloned List.
626          *
627          * @param pSource the source List
628          */
629         protected PrometheusStaticList(final PrometheusStaticList<T> pSource) {
630             super(pSource);
631         }
632 
633         /**
634          * Obtain the enumClass.
635          *
636          * @return the enumClass
637          */
638         protected abstract Class<? extends PrometheusStaticDataClass> getEnumClass();
639 
640         @Override
641         @SuppressWarnings("unchecked")
642         public PrometheusStaticDataMap<T> getDataMap() {
643             return (PrometheusStaticDataMap<T>) super.getDataMap();
644         }
645 
646         /**
647          * Search for a particular item by class.
648          *
649          * @param eClass The class of the item to search for
650          * @return The Item if present (or <code>null</code> if not found)
651          */
652         public T findItemByClass(final PrometheusStaticDataClass eClass) {
653             /* Look for item by class Id */
654             return findItemById(eClass.getClassId());
655         }
656 
657         @Override
658         public T findItemByName(final String pName) {
659             /* look up the name in the map */
660             return getDataMap().findItemByName(pName);
661         }
662 
663         /**
664          * Is the list full?
665          *
666          * @return true/false
667          */
668         public boolean isFull() {
669             /* We can only be full with the correct number of items */
670             if (size() < getEnumClass().getEnumConstants().length) {
671                 return false;
672             }
673 
674             /* Loop through all elements */
675             final Iterator<T> myIterator = iterator();
676             while (myIterator.hasNext()) {
677                 final T myCurr = myIterator.next();
678 
679                 /* If the item is deleted */
680                 if (myCurr.isDeleted()) {
681                     /* Not full */
682                     return false;
683                 }
684             }
685 
686             /* Must be full */
687             return true;
688         }
689 
690         /**
691          * Obtain a list of classes that are missing/deleted.
692          *
693          * @return The List of classes
694          */
695         public List<PrometheusStaticDataClass> getMissingClasses() {
696             /* Allocate the list */
697             final List<PrometheusStaticDataClass> myList = new ArrayList<>();
698 
699             /* Loop through all elements */
700             for (PrometheusStaticDataClass myClass : getEnumClass().getEnumConstants()) {
701                 /* Locate the element */
702                 final T myItem = findItemById(myClass.getClassId());
703 
704                 /* If the item is missing or deleted */
705                 if ((myItem == null)
706                         || myItem.isDeleted()) {
707                     /* Add it to the list */
708                     myList.add(myClass);
709                 }
710             }
711 
712             /* Return the list */
713             return myList;
714         }
715 
716         /**
717          * Add Item for class.
718          *
719          * @param pClass the class to add
720          * @return the added class
721          * @throws OceanusException on error
722          */
723         public T addNewItem(final PrometheusStaticDataClass pClass) throws OceanusException {
724             /* Create the new item */
725             return newItem(pClass);
726         }
727 
728         /**
729          * Create new Item for class.
730          *
731          * @param pClass the class to create
732          * @return the created class
733          * @throws OceanusException on error
734          */
735         protected abstract T newItem(PrometheusStaticDataClass pClass) throws OceanusException;
736 
737         /**
738          * Populate default values.
739          *
740          * @throws OceanusException on error
741          */
742         public void populateDefaults() throws OceanusException {
743             /* Loop through all elements */
744             for (PrometheusStaticDataClass myClass : getEnumClass().getEnumConstants()) {
745                 /* Create new element */
746                 final T myItem = newItem(myClass);
747 
748                 /* Validate the item */
749                 myItem.validate();
750 
751                 /* Handle validation failure */
752                 if (myItem.hasErrors()) {
753                     throw new PrometheusDataException(myItem, ERROR_VALIDATION);
754                 }
755             }
756 
757             /* Ensure that the list is sorted */
758             reSort();
759         }
760 
761         @Override
762         protected PrometheusDataMapItem allocateDataMap() {
763             return new PrometheusStaticDataMap<>();
764         }
765     }
766 
767     /**
768      * The dataMap class.
769      *
770      * @param <T> the item type
771      */
772     public static class PrometheusStaticDataMap<T extends PrometheusStaticDataItem>
773             extends PrometheusDataInstanceMap<T, String> {
774         /**
775          * Report fields.
776          */
777         @SuppressWarnings("rawtypes")
778         private static final MetisFieldSet<PrometheusStaticDataMap> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusStaticDataMap.class);
779 
780         /*
781          * Declare Fields.
782          */
783         static {
784             FIELD_DEFS.declareLocalField(PrometheusDataResource.STATICDATAMAP_ORDERCOUNTS, PrometheusStaticDataMap::getOrderCountMap);
785         }
786 
787         /**
788          * Map of order counts.
789          */
790         private final Map<Integer, Integer> theOrderCountMap;
791 
792         /**
793          * Constructor.
794          */
795         public PrometheusStaticDataMap() {
796             /* Create the maps */
797             theOrderCountMap = new HashMap<>();
798         }
799 
800         @SuppressWarnings("rawtypes")
801         @Override
802         public MetisFieldSet<? extends PrometheusStaticDataMap> getDataFieldSet() {
803             return FIELD_DEFS;
804         }
805 
806         @Override
807         public String formatObject(final OceanusDataFormatter pFormatter) {
808             return FIELD_DEFS.getName();
809         }
810 
811         /**
812          * Obtain the keyMap.
813          *
814          * @return the map
815          */
816         private Map<Integer, Integer> getOrderCountMap() {
817             return theOrderCountMap;
818         }
819 
820         @Override
821         public void resetMap() {
822             super.resetMap();
823             theOrderCountMap.clear();
824         }
825 
826         @Override
827         @SuppressWarnings("unchecked")
828         public void adjustForItem(final PrometheusDataItem pItem) {
829             /* Access item */
830             final T myItem = (T) pItem;
831 
832             /* Adjust order count */
833             final Integer myOrder = myItem.getOrder();
834             final Integer myCount = theOrderCountMap.get(myOrder);
835             if (myCount == null) {
836                 theOrderCountMap.put(myOrder, ONE);
837             } else {
838                 theOrderCountMap.put(myOrder, myCount + 1);
839             }
840 
841             /* Adjust name count */
842             adjustForItem(myItem, myItem.getName());
843         }
844 
845         /**
846          * find item by name.
847          *
848          * @param pName the name to look up
849          * @return the matching item
850          */
851         public T findItemByName(final String pName) {
852             return findItemByKey(pName);
853         }
854 
855         /**
856          * Check validity of name.
857          *
858          * @param pName the name to look up
859          * @return true/false
860          */
861         public boolean validNameCount(final String pName) {
862             return validKeyCount(pName);
863         }
864 
865         /**
866          * Check availability of name.
867          *
868          * @param pName the key to look up
869          * @return true/false
870          */
871         public boolean availableName(final String pName) {
872             return availableKey(pName);
873         }
874 
875         /**
876          * Check validity of order.
877          *
878          * @param pOrder the order to look up
879          * @return true/false
880          */
881         public boolean validOrderCount(final Integer pOrder) {
882             final Integer myResult = theOrderCountMap.get(pOrder);
883             return ONE.equals(myResult);
884         }
885     }
886 }