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