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