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.date.OceanusDate;
21  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateFormatter;
22  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimalParser;
23  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
24  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
25  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRate;
26  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
27  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
28  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
29  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
30  import io.github.tonywasher.joceanus.metis.list.MetisListKey;
31  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
32  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusLogicException;
33  
34  import java.util.Date;
35  
36  /**
37   * Representation of an information extension of a DataItem.
38   *
39   * @author Tony Washer
40   */
41  public abstract class PrometheusDataInfoItem
42          extends PrometheusEncryptedDataItem {
43      /**
44       * Maximum DataLength.
45       */
46      public static final int DATALEN = 512;
47  
48      /**
49       * Report fields.
50       */
51      private static final PrometheusEncryptedFieldSet<PrometheusDataInfoItem> FIELD_DEFS = PrometheusEncryptedFieldSet.newEncryptedFieldSet(PrometheusDataInfoItem.class);
52  
53      /*
54       * FieldIds.
55       */
56      static {
57          FIELD_DEFS.declareLinkField(PrometheusDataResource.DATAINFO_TYPE);
58          FIELD_DEFS.declareLinkField(PrometheusDataResource.DATAINFO_OWNER);
59          FIELD_DEFS.declareEncryptedContextField(PrometheusDataResource.DATAINFO_VALUE);
60          FIELD_DEFS.declareDerivedVersionedField(PrometheusDataResource.DATAINFO_LINK);
61      }
62  
63      /**
64       * Invalid Data Type Error.
65       */
66      protected static final String ERROR_BADDATATYPE = PrometheusDataResource.DATAINFO_ERROR_TYPE.getValue();
67  
68      /**
69       * Invalid Data Error.
70       */
71      protected static final String ERROR_BADDATA = PrometheusDataResource.DATAINFO_ERROR_DATA.getValue();
72  
73      /**
74       * Invalid Info Class Error.
75       */
76      protected static final String ERROR_BADINFOCLASS = PrometheusDataResource.DATAINFO_ERROR_CLASS.getValue();
77  
78      /**
79       * Copy Constructor.
80       *
81       * @param pList the list
82       * @param pInfo The Info to copy
83       */
84      protected PrometheusDataInfoItem(final PrometheusDataInfoList<?> pList,
85                                       final PrometheusDataInfoItem pInfo) {
86          /* Set standard values */
87          super(pList, pInfo);
88      }
89  
90      /**
91       * Edit Constructor.
92       *
93       * @param pList the list
94       */
95      protected PrometheusDataInfoItem(final PrometheusDataInfoList<?> pList) {
96          /* Set standard values */
97          super(pList, 0);
98      }
99  
100     /**
101      * Secure constructor.
102      *
103      * @param pList       the list
104      * @param uId         the id
105      * @param uKeySetId   the keySet id
106      * @param uInfoTypeId the info id
107      * @param uOwnerId    the owner id
108      * @throws OceanusException on error
109      */
110     protected PrometheusDataInfoItem(final PrometheusDataInfoList<?> pList,
111                                      final Integer uId,
112                                      final Integer uKeySetId,
113                                      final Integer uInfoTypeId,
114                                      final Integer uOwnerId) throws OceanusException {
115         /* Initialise the item */
116         super(pList, uId);
117 
118         /* Record the Ids */
119         setValueInfoType(uInfoTypeId);
120         setValueOwner(uOwnerId);
121 
122         /* Store the keySetId */
123         setDataKeySet(uKeySetId);
124     }
125 
126     /**
127      * Basic constructor.
128      *
129      * @param pList     the list
130      * @param uId       the id
131      * @param pInfoType the info type
132      * @param pOwner    the owner
133      */
134     protected PrometheusDataInfoItem(final PrometheusDataInfoList<?> pList,
135                                      final Integer uId,
136                                      final PrometheusStaticDataItem pInfoType,
137                                      final PrometheusDataItem pOwner) {
138         /* Initialise the item */
139         super(pList, uId);
140 
141         /* Record the parameters */
142         setValueInfoType(pInfoType);
143         setValueOwner(pOwner);
144     }
145 
146     /**
147      * Basic constructor.
148      *
149      * @param pList   the list
150      * @param pValues the values
151      * @throws OceanusException on error
152      */
153     protected PrometheusDataInfoItem(final PrometheusDataInfoList<?> pList,
154                                      final PrometheusDataValues pValues) throws OceanusException {
155         /* Initialise the item */
156         super(pList, pValues);
157 
158         /* Store the InfoType */
159         Object myValue = pValues.getValue(PrometheusDataResource.DATAINFO_TYPE);
160         if (myValue instanceof Integer i) {
161             setValueInfoType(i);
162         } else if (myValue instanceof String s) {
163             setValueInfoType(s);
164         } else if (myValue instanceof PrometheusStaticDataItem myStatic) {
165             setValueInfoType(myStatic);
166         }
167 
168         /* Store the Owner */
169         myValue = pValues.getValue(PrometheusDataResource.DATAINFO_OWNER);
170         if (myValue instanceof Integer i) {
171             setValueOwner(i);
172         } else if (myValue instanceof String s) {
173             setValueOwner(s);
174         } else if (myValue instanceof PrometheusDataItem myItem) {
175             setValueOwner(myItem);
176         }
177     }
178 
179     @Override
180     public String toString() {
181         /* Access Info Type Value */
182         final PrometheusEncryptedValues myValues = getValues();
183         final Object myType = myValues.getValue(PrometheusDataResource.DATAINFO_TYPE, Object.class);
184         if (!(myType instanceof PrometheusStaticDataItem)) {
185             return super.toString();
186         }
187 
188         /* Access InfoType */
189         final PrometheusStaticDataItem myInfoType = (PrometheusStaticDataItem) myType;
190 
191         /* Access class */
192         return myInfoType.getName() + "=" + super.toString();
193     }
194 
195     @Override
196     public String formatObject(final OceanusDataFormatter pFormatter) {
197         /* Access Info Type Value */
198         final PrometheusEncryptedValues myValues = getValues();
199         final Object myType = myValues.getValue(PrometheusDataResource.DATAINFO_TYPE, Object.class);
200         if (!(myType instanceof PrometheusStaticDataItem)) {
201             return super.formatObject(pFormatter);
202         }
203 
204         /* Access InfoType */
205         final PrometheusStaticDataItem myInfoType = getInfoType();
206 
207         /* Access formatter */
208         final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
209         final PrometheusDataInfoClass myInfoClass = (PrometheusDataInfoClass) myInfoType.getStaticClass();
210 
211         /* Switch on type of Data */
212         switch (myInfoClass.getDataType()) {
213             case LINK:
214             case LINKPAIR:
215             case LINKSET:
216                 return myFormatter.formatObject(getLink());
217             default:
218                 return myFormatter.formatObject(getValue(Object.class));
219         }
220     }
221 
222     /**
223      * Obtain InfoType.
224      *
225      * @return the InfoTypeId
226      */
227     public abstract PrometheusStaticDataItem getInfoType();
228 
229     /**
230      * Obtain InfoClass.
231      *
232      * @return the InfoClass
233      */
234     public abstract PrometheusDataInfoClass getInfoClass();
235 
236     /**
237      * Obtain InfoTypeId.
238      *
239      * @return the InfoTypeId
240      */
241     public Integer getInfoTypeId() {
242         return getInfoType().getIndexedId();
243     }
244 
245     /**
246      * Obtain Owner.
247      *
248      * @return the Owner
249      */
250     public abstract PrometheusDataItem getOwner();
251 
252     /**
253      * Obtain OwnerId.
254      *
255      * @return the OwnerId
256      */
257     public Integer getOwnerId() {
258         return getOwner().getIndexedId();
259     }
260 
261     /**
262      * Obtain Link.
263      *
264      * @param <X>    the link type
265      * @param pClass the class of the link
266      * @return the Link
267      */
268     public <X extends PrometheusDataItem> X getLink(final Class<X> pClass) {
269         return getValues().getValue(PrometheusDataResource.DATAINFO_LINK, pClass);
270     }
271 
272     /**
273      * Get Link name.
274      *
275      * @return the link name
276      */
277     public String getLinkName() {
278         return null;
279     }
280 
281     /**
282      * Obtain Link.
283      *
284      * @return the Link
285      */
286     protected PrometheusDataItem getLink() {
287         return getValues().getValue(PrometheusDataResource.DATAINFO_LINK, PrometheusDataItem.class);
288     }
289 
290     /**
291      * Obtain Value as object.
292      *
293      * @param <X>    the object type
294      * @param pClass the object class
295      * @return the Value
296      */
297     public <X> X getValue(final Class<X> pClass) {
298         return getValues().getValue(PrometheusDataResource.DATAINFO_VALUE, pClass);
299     }
300 
301     /**
302      * Obtain Value as underlying object.
303      *
304      * @return the Value
305      */
306     public PrometheusEncryptedPair getField() {
307         return getField(getValues());
308     }
309 
310     /**
311      * Obtain Encrypted Bytes.
312      *
313      * @return the Bytes
314      */
315     public byte[] getValueBytes() {
316         return getValues().getEncryptedBytes(PrometheusDataResource.DATAINFO_VALUE);
317     }
318 
319     /**
320      * Obtain Value as object.
321      *
322      * @param <X>       the object type
323      * @param pValueSet the valueSet
324      * @param pClass    the object class
325      * @return the Value
326      */
327     public static <X> X getValue(final PrometheusEncryptedValues pValueSet,
328                                  final Class<X> pClass) {
329         return pValueSet.isDeletion()
330                 ? null
331                 : pValueSet.getValue(PrometheusDataResource.DATAINFO_VALUE, pClass);
332     }
333 
334     /**
335      * Obtain Value as encrypted field.
336      *
337      * @param pValueSet the valueSet
338      * @return the Value
339      */
340     public static PrometheusEncryptedPair getField(final PrometheusEncryptedValues pValueSet) {
341         return pValueSet.isDeletion()
342                 ? null
343                 : pValueSet.getEncryptedPair(PrometheusDataResource.DATAINFO_VALUE);
344     }
345 
346 
347     /**
348      * Set InfoType.
349      *
350      * @param pValue the info Type
351      */
352     protected final void setValueInfoType(final PrometheusStaticDataItem pValue) {
353         getValues().setUncheckedValue(PrometheusDataResource.DATAINFO_TYPE, pValue);
354     }
355 
356     /**
357      * Set InfoType Id.
358      *
359      * @param pId the info Type id
360      */
361     protected final void setValueInfoType(final Integer pId) {
362         getValues().setUncheckedValue(PrometheusDataResource.DATAINFO_TYPE, pId);
363     }
364 
365     /**
366      * Set InfoType Name.
367      *
368      * @param pName the info Type name
369      */
370     protected final void setValueInfoType(final String pName) {
371         getValues().setUncheckedValue(PrometheusDataResource.DATAINFO_TYPE, pName);
372     }
373 
374     /**
375      * Set Owner.
376      *
377      * @param pValue the owner
378      */
379     protected final void setValueOwner(final PrometheusDataItem pValue) {
380         getValues().setUncheckedValue(PrometheusDataResource.DATAINFO_OWNER, pValue);
381     }
382 
383     /**
384      * Set Owner id.
385      *
386      * @param pId the owner id
387      */
388     protected final void setValueOwner(final Integer pId) {
389         getValues().setUncheckedValue(PrometheusDataResource.DATAINFO_OWNER, pId);
390     }
391 
392     /**
393      * Set Owner name.
394      *
395      * @param pName the owner name
396      */
397     protected final void setValueOwner(final String pName) {
398         getValues().setUncheckedValue(PrometheusDataResource.DATAINFO_OWNER, pName);
399     }
400 
401     /**
402      * Set Value.
403      *
404      * @param pValue the value
405      * @throws OceanusException on error
406      */
407     protected void setValueValue(final Object pValue) throws OceanusException {
408         getValues().setDeletion(false);
409         setEncryptedValue(PrometheusDataResource.DATAINFO_VALUE, pValue);
410     }
411 
412     /**
413      * Set value.
414      *
415      * @param pValue the value
416      */
417     protected void setValueValue(final PrometheusEncryptedPair pValue) {
418         final PrometheusEncryptedValues myValues = getValues();
419         myValues.setDeletion(false);
420         myValues.setUncheckedValue(PrometheusDataResource.DATAINFO_VALUE, pValue);
421     }
422 
423     /**
424      * Set Object Value.
425      *
426      * @param <X>    the object type
427      * @param pBytes the value
428      * @param pClass the object class
429      * @throws OceanusException on error
430      */
431     protected <X> void setValueBytes(final byte[] pBytes,
432                                      final Class<X> pClass) throws OceanusException {
433         setEncryptedValue(PrometheusDataResource.DATAINFO_VALUE, pBytes, pClass);
434     }
435 
436     /**
437      * Set link.
438      *
439      * @param pLink the link
440      */
441     protected void setValueLink(final PrometheusDataItem pLink) {
442         final PrometheusEncryptedValues myValues = getValues();
443         myValues.setDeletion(false);
444         myValues.setUncheckedValue(PrometheusDataResource.DATAINFO_LINK, pLink);
445     }
446 
447     /**
448      * Set link id.
449      *
450      * @param pId the linkId
451      */
452     private void setValueLink(final Integer pId) {
453         final PrometheusEncryptedValues myValues = getValues();
454         myValues.setUncheckedValue(PrometheusDataResource.DATAINFO_LINK, pId);
455     }
456 
457     /**
458      * Set link id.
459      *
460      * @param pId the linkId
461      */
462     private void setValueLink(final Long pId) {
463         final PrometheusEncryptedValues myValues = getValues();
464         myValues.setUncheckedValue(PrometheusDataResource.DATAINFO_LINK, pId);
465     }
466 
467     /**
468      * Set link name.
469      *
470      * @param pName the linkName
471      */
472     protected void setValueLink(final String pName) {
473         final PrometheusEncryptedValues myValues = getValues();
474         myValues.setUncheckedValue(PrometheusDataResource.DATAINFO_LINK, pName);
475     }
476 
477     /**
478      * Mark deleted.
479      */
480     public void markDeleted() {
481         /* Set deletion indication */
482         getValues().setDeletion(true);
483     }
484 
485     @Override
486     public void touchUnderlyingItems() {
487         /* Pass call on */
488         super.touchUnderlyingItems();
489 
490         /* Touch the info type */
491         getInfoType().touchItem(this);
492     }
493 
494     /**
495      * Set Value.
496      *
497      * @param pValue the Value
498      * @throws OceanusException on error
499      */
500     protected void setValue(final Object pValue) throws OceanusException {
501         /* Access the info Type */
502         final PrometheusStaticDataItem myType = getInfoType();
503         final PrometheusDataInfoClass myClass = (PrometheusDataInfoClass) myType.getStaticClass();
504 
505         /* Access the DataSet and parser */
506         final PrometheusDataSet myDataSet = getDataSet();
507         final OceanusDataFormatter myFormatter = myDataSet.getDataFormatter();
508         final OceanusDecimalParser myParser = myFormatter.getDecimalParser();
509 
510         /* Switch on Info Class */
511         boolean bValueOK = false;
512         switch (myClass.getDataType()) {
513             case DATE:
514                 bValueOK = setDateValue(myFormatter.getDateFormatter(), pValue);
515                 break;
516             case INTEGER:
517                 bValueOK = setIntegerValue(myFormatter, pValue);
518                 break;
519             case LINK:
520             case LINKSET:
521                 bValueOK = setLinkValue(pValue);
522                 break;
523             case LINKPAIR:
524                 bValueOK = setLinkPairValue(pValue);
525                 break;
526             case STRING:
527                 bValueOK = setStringValue(pValue);
528                 break;
529             case CHARARRAY:
530                 bValueOK = setCharArrayValue(pValue);
531                 break;
532             case MONEY:
533                 bValueOK = setMoneyValue(myParser, pValue);
534                 break;
535             case RATE:
536                 bValueOK = setRateValue(myParser, pValue);
537                 break;
538             case UNITS:
539                 bValueOK = setUnitsValue(myParser, pValue);
540                 break;
541             case PRICE:
542                 bValueOK = setPriceValue(myParser, pValue);
543                 break;
544             case RATIO:
545                 bValueOK = setRatioValue(myParser, pValue);
546                 break;
547             default:
548                 break;
549         }
550 
551         /* Reject invalid value */
552         if (!bValueOK) {
553             throw new PrometheusLogicException(this, ERROR_BADDATATYPE);
554         }
555     }
556 
557     /**
558      * Set Date Value.
559      *
560      * @param pFormatter the date formatter
561      * @param pValue     the Value
562      * @return is value valid true/false
563      * @throws OceanusException on error
564      */
565     private boolean setDateValue(final OceanusDateFormatter pFormatter,
566                                  final Object pValue) throws OceanusException {
567         try {
568             /* Handle various forms */
569             if (pValue instanceof Date d) {
570                 setValueValue(new OceanusDate(d));
571                 return true;
572             } else if (pValue instanceof OceanusDate) {
573                 setValueValue(pValue);
574                 return true;
575             } else if (pValue instanceof byte[] ba) {
576                 setValueBytes(ba, OceanusDate.class);
577                 return true;
578             } else if (pValue instanceof String s) {
579                 setValueValue(pFormatter.parseDate(s));
580                 return true;
581             }
582         } catch (IllegalArgumentException e) {
583             throw new PrometheusDataException(pValue, ERROR_BADDATA, e);
584         }
585         return false;
586     }
587 
588     /**
589      * Set Integer Value.
590      *
591      * @param pFormatter the data formatter
592      * @param pValue     the Value
593      * @return is value valid true/false
594      * @throws OceanusException on error
595      */
596     private boolean setIntegerValue(final OceanusDataFormatter pFormatter,
597                                     final Object pValue) throws OceanusException {
598         try {
599             /* Handle various forms */
600             if (pValue instanceof Integer) {
601                 setValueValue(pValue);
602                 return true;
603             } else if (pValue instanceof byte[] ba) {
604                 setValueBytes(ba, Integer.class);
605                 return true;
606             } else if (pValue instanceof String s) {
607                 setValueValue(pFormatter.parseValue(s, Integer.class));
608                 return true;
609             }
610         } catch (IllegalArgumentException e) {
611             throw new PrometheusDataException(pValue, ERROR_BADDATA, e);
612         }
613         return false;
614     }
615 
616     /**
617      * Set Link Value.
618      *
619      * @param pValue the Value
620      * @return is value valid true/false
621      * @throws OceanusException on error
622      */
623     private boolean setLinkValue(final Object pValue) throws OceanusException {
624         try {
625             /* Handle various forms */
626             if (pValue instanceof Integer i) {
627                 setValueValue(pValue);
628                 setValueLink(i);
629                 return true;
630             } else if (pValue instanceof byte[] ba) {
631                 setValueBytes(ba, Integer.class);
632                 setValueLink(getValue(Integer.class));
633                 return true;
634             } else if (pValue instanceof String s) {
635                 setValueLink(s);
636                 return true;
637             } else if (pValue instanceof PrometheusDataItem myItem) {
638                 setValueValue(myItem.getIndexedId());
639                 setValueLink(myItem);
640                 return true;
641             }
642         } catch (IllegalArgumentException e) {
643             throw new PrometheusDataException(pValue, ERROR_BADDATA, e);
644         }
645         return false;
646     }
647 
648     /**
649      * Set Link Value.
650      *
651      * @param pValue the Value
652      * @return is value valid true/false
653      * @throws OceanusException on error
654      */
655     private boolean setLinkPairValue(final Object pValue) throws OceanusException {
656         try {
657             /* Handle various forms */
658             if (pValue instanceof Long l) {
659                 setValueValue(pValue);
660                 setValueLink(l);
661                 return true;
662             } else if (pValue instanceof byte[] ba) {
663                 setValueBytes(ba, Long.class);
664                 setValueLink(getValue(Long.class));
665                 return true;
666             } else if (pValue instanceof String s) {
667                 setValueLink(s);
668                 return true;
669             } else if (pValue instanceof PrometheusDataItem myItem) {
670                 setValueValue(myItem.getIndexedId());
671                 setValueLink(myItem);
672                 return true;
673             }
674         } catch (IllegalArgumentException e) {
675             throw new PrometheusDataException(pValue, ERROR_BADDATA, e);
676         }
677         return false;
678     }
679 
680     /**
681      * Set String Value.
682      *
683      * @param pValue the Value
684      * @return is value valid true/false
685      * @throws OceanusException on error
686      */
687     private boolean setStringValue(final Object pValue) throws OceanusException {
688         /* Handle various forms */
689         if (pValue instanceof String) {
690             setValueValue(pValue);
691             return true;
692         } else if (pValue instanceof byte[] ba) {
693             setValueBytes(ba, String.class);
694             return true;
695         }
696         return false;
697     }
698 
699     /**
700      * Set CharArray Value.
701      *
702      * @param pValue the Value
703      * @return is value valid true/false
704      * @throws OceanusException on error
705      */
706     private boolean setCharArrayValue(final Object pValue) throws OceanusException {
707         /* Handle various forms */
708         if (pValue instanceof char[]) {
709             setValueValue(pValue);
710             return true;
711         } else if (pValue instanceof byte[] ba) {
712             setValueBytes(ba, char[].class);
713             return true;
714         } else if (pValue instanceof String s) {
715             setValueValue(s.toCharArray());
716             return true;
717         }
718         return false;
719     }
720 
721     /**
722      * Set Money Value.
723      *
724      * @param pParser the parser
725      * @param pValue  the Value
726      * @return is value valid true/false
727      * @throws OceanusException on error
728      */
729     private boolean setMoneyValue(final OceanusDecimalParser pParser,
730                                   final Object pValue) throws OceanusException {
731         /* Handle various forms */
732         if (pValue instanceof OceanusMoney) {
733             setValueValue(pValue);
734             return true;
735         } else if (pValue instanceof byte[] ba) {
736             setValueBytes(ba, OceanusMoney.class);
737             return true;
738         } else if (pValue instanceof String s) {
739             setValueValue(pParser.parseMoneyValue(s));
740             return true;
741         }
742         return false;
743     }
744 
745     /**
746      * Set Rate Value.
747      *
748      * @param pParser the parser
749      * @param pValue  the Value
750      * @return is value valid true/false
751      * @throws OceanusException on error
752      */
753     private boolean setRateValue(final OceanusDecimalParser pParser,
754                                  final Object pValue) throws OceanusException {
755         /* Handle various forms */
756         if (pValue instanceof OceanusRate) {
757             setValueValue(pValue);
758             return true;
759         } else if (pValue instanceof byte[] ba) {
760             setValueBytes(ba, OceanusRate.class);
761             return true;
762         } else if (pValue instanceof String s) {
763             setValueValue(pParser.parseRateValue(s));
764             return true;
765         }
766         return false;
767     }
768 
769     /**
770      * Set Ratio Value.
771      *
772      * @param pParser the parser
773      * @param pValue  the Value
774      * @return is value valid true/false
775      * @throws OceanusException on error
776      */
777     private boolean setRatioValue(final OceanusDecimalParser pParser,
778                                   final Object pValue) throws OceanusException {
779         /* Handle various forms */
780         if (pValue instanceof OceanusRatio) {
781             setValueValue(pValue);
782             return true;
783         } else if (pValue instanceof byte[] ba) {
784             setValueBytes(ba, OceanusRatio.class);
785             return true;
786         } else if (pValue instanceof String s) {
787             setValueValue(pParser.parseRatioValue(s));
788             return true;
789         }
790         return false;
791     }
792 
793     /**
794      * Set Units Value.
795      *
796      * @param pParser the parser
797      * @param pValue  the Value
798      * @return is value valid true/false
799      * @throws OceanusException on error
800      */
801     private boolean setUnitsValue(final OceanusDecimalParser pParser,
802                                   final Object pValue) throws OceanusException {
803         /* Handle various forms */
804         if (pValue instanceof OceanusUnits) {
805             setValueValue(pValue);
806             return true;
807         } else if (pValue instanceof byte[] ba) {
808             setValueBytes(ba, OceanusUnits.class);
809             return true;
810         } else if (pValue instanceof String s) {
811             setValueValue(pParser.parseUnitsValue(s));
812             return true;
813         }
814         return false;
815     }
816 
817     /**
818      * Set Price Value.
819      *
820      * @param pParser the parser
821      * @param pValue  the Value
822      * @return is value valid true/false
823      * @throws OceanusException on error
824      */
825     private boolean setPriceValue(final OceanusDecimalParser pParser,
826                                   final Object pValue) throws OceanusException {
827         /* Handle various forms */
828         if (pValue instanceof OceanusPrice) {
829             setValueValue(pValue);
830             return true;
831         } else if (pValue instanceof byte[] ba) {
832             setValueBytes(ba, OceanusPrice.class);
833             return true;
834         } else if (pValue instanceof String s) {
835             setValueValue(pParser.parsePriceValue(s));
836             return true;
837         }
838         return false;
839     }
840 
841     @Override
842     public void rewindToVersion(final int pVersion) {
843         /* Do the actual rewind */
844         super.rewindToVersion(pVersion);
845 
846         /* If this is a linkSet type */
847         if (getInfoClass().isLinkSet()) {
848             /* Note the rewind */
849             rewindInfoLinkSet();
850         }
851     }
852 
853     /**
854      * rewind any infoSet links.
855      */
856     public void rewindInfoLinkSet() {
857     }
858 
859     @Override
860     public int compareValues(final PrometheusDataItem pThat) {
861         /* Compare the owner and infoType */
862         final PrometheusDataInfoItem myThat = (PrometheusDataInfoItem) pThat;
863         int iDiff = getOwner().compareTo(myThat.getOwner());
864         if (iDiff == 0) {
865             iDiff = getInfoType().compareTo(myThat.getInfoType());
866         }
867         return iDiff;
868     }
869 
870     /**
871      * List class for DataInfo.
872      *
873      * @param <T> the DataType
874      */
875     public abstract static class PrometheusDataInfoList<T extends PrometheusDataInfoItem>
876             extends PrometheusEncryptedList<T> {
877         /*
878          * Report fields.
879          */
880         static {
881             MetisFieldSet.newFieldSet(PrometheusDataInfoList.class);
882         }
883 
884         /**
885          * Construct a generic data info list.
886          *
887          * @param pBaseClass the class of the underlying object
888          * @param pData      the dataSet
889          * @param pItemType  the list type
890          * @param pStyle     the style of the list
891          */
892         protected PrometheusDataInfoList(final Class<T> pBaseClass,
893                                          final PrometheusDataSet pData,
894                                          final MetisListKey pItemType,
895                                          final PrometheusListStyle pStyle) {
896             super(pBaseClass, pData, pItemType, pStyle);
897         }
898 
899         /**
900          * Constructor for a cloned List.
901          *
902          * @param pSource the source List
903          */
904         protected PrometheusDataInfoList(final PrometheusDataInfoList<T> pSource) {
905             super(pSource);
906         }
907 
908         @Override
909         public boolean includeDataXML() {
910             return false;
911         }
912 
913         @Override
914         protected abstract PrometheusDataInfoList<T> getEmptyList(PrometheusListStyle pStyle);
915 
916         /**
917          * Add new item to the list.
918          *
919          * @param pOwner    the owner
920          * @param pInfoType the information
921          * @return the new info item
922          */
923         protected abstract T addNewItem(PrometheusDataItem pOwner,
924                                         PrometheusStaticDataItem pInfoType);
925 
926         /**
927          * Add an info Item to the list.
928          *
929          * @param pId        the Id
930          * @param pOwner     the owner
931          * @param pInfoClass the infoClass
932          * @param pValue     the value
933          * @throws OceanusException on error
934          */
935         public abstract void addInfoItem(Integer pId,
936                                          PrometheusDataItem pOwner,
937                                          PrometheusDataInfoClass pInfoClass,
938                                          Object pValue) throws OceanusException;
939 
940         @Override
941         public void updateMaps() {
942             /* No activity, managed by owner */
943         }
944 
945         @Override
946         protected PrometheusDataMapItem allocateDataMap() {
947             /* Unused */
948             throw new UnsupportedOperationException();
949         }
950     }
951 }