View Javadoc
1   /*
2    * Prometheus: Application Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.prometheus.data;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.keyset.GordianKeySet;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference.MetisDataDiffers;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataObjectFormat;
23  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
24  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
25  
26  import java.util.Arrays;
27  import java.util.Objects;
28  
29  /**
30   * Encrypted Pair.
31   */
32  public class PrometheusEncryptedPair
33          implements MetisDataObjectFormat, MetisDataDiffers {
34      /**
35       * The value.
36       */
37      private final Object theValue;
38  
39      /**
40       * The encryptedBytes.
41       */
42      private byte[] theBytes;
43  
44      /**
45       * The keyset.
46       */
47      private GordianKeySet theKeySet;
48  
49      /**
50       * Constructor.
51       *
52       * @param pKeySet the keySet
53       * @param pValue  the value.
54       * @param pBytes  the encrypted bytes
55       */
56      PrometheusEncryptedPair(final GordianKeySet pKeySet,
57                              final Object pValue,
58                              final byte[] pBytes) {
59          theKeySet = pKeySet;
60          theValue = pValue;
61          theBytes = pBytes;
62      }
63  
64      /**
65       * Obtain the keySet.
66       *
67       * @return the keySet.
68       */
69      public GordianKeySet getKeySet() {
70          return theKeySet;
71      }
72  
73      /**
74       * Obtain the value.
75       *
76       * @return the value.
77       */
78      public Object getValue() {
79          return theValue;
80      }
81  
82      /**
83       * Obtain the bytes.
84       *
85       * @return the bytes.
86       */
87      public byte[] getBytes() {
88          return theBytes;
89      }
90  
91      /**
92       * Adopt Encryption.
93       *
94       * @param pEncryptor the encryptor
95       * @param pSource    field to adopt encryption from
96       * @throws OceanusException on error
97       */
98      protected void adoptEncryption(final PrometheusEncryptor pEncryptor,
99                                     final PrometheusEncryptedPair pSource) throws OceanusException {
100         /* Store the keySet */
101         theKeySet = pEncryptor.getKeySet();
102 
103         /* If we need to renew the encryption */
104         if (pSource == null
105                 || MetisDataDifference.difference(theKeySet, pSource.getKeySet()).isDifferent()
106                 || MetisDataDifference.difference(getValue(), pSource.getValue()).isDifferent()) {
107             /* encrypt the value */
108             theBytes = pEncryptor.encryptValue(getValue());
109 
110             /* else we can simply adopt the underlying encryption */
111         } else {
112             /* Pick up the underlying encryption */
113             theBytes = pSource.getBytes();
114         }
115     }
116 
117     @Override
118     public String formatObject(final OceanusDataFormatter pFormatter) {
119         /* Format the unencrypted field */
120         return pFormatter.formatObject(theValue);
121     }
122 
123     @Override
124     public String toString() {
125         return theValue.toString();
126     }
127 
128     @Override
129     public boolean equals(final Object pThat) {
130         /* Handle the trivial cases */
131         if (this == pThat) {
132             return true;
133         }
134         if (pThat == null) {
135             return false;
136         }
137 
138         /* Make sure that the object is the same class */
139         if (pThat.getClass() != this.getClass()) {
140             return false;
141         }
142 
143         /* Access the target field */
144         final PrometheusEncryptedPair myThat = (PrometheusEncryptedPair) pThat;
145 
146         /* Check differences */
147         if (!theKeySet.equals(myThat.getKeySet())) {
148             return false;
149         }
150 
151         /* Check differences */
152         if (MetisDataDifference.difference(getValue(), myThat.getValue()).isDifferent()) {
153             return false;
154         }
155 
156         /* Check encryption */
157         return Arrays.equals(getBytes(), myThat.getBytes());
158     }
159 
160     @Override
161     public int hashCode() {
162         return Objects.hash(theKeySet, theValue, Arrays.hashCode(theBytes));
163     }
164 
165     @Override
166     public MetisDataDifference differs(final Object pThat) {
167         /* Reject if null */
168         if (pThat == null) {
169             return MetisDataDifference.DIFFERENT;
170         }
171 
172         /* Reject if wrong class */
173         if (!getClass().equals(pThat.getClass())) {
174             return MetisDataDifference.DIFFERENT;
175         }
176 
177         /* Access as correct class */
178         final PrometheusEncryptedPair myField = (PrometheusEncryptedPair) pThat;
179 
180         /* Compare Unencrypted value */
181         if (MetisDataDifference.difference(getValue(), myField.getValue()).isDifferent()) {
182             return MetisDataDifference.DIFFERENT;
183         }
184 
185         /* Compare Encrypted value */
186         if (!Arrays.equals(getBytes(), myField.getBytes())) {
187             return MetisDataDifference.SECURITY;
188         }
189 
190         /* Item is the Same */
191         return MetisDataDifference.IDENTICAL;
192     }
193 }