1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.core.metapath.function;
28
29 import gov.nist.secauto.metaschema.core.metapath.ISequence;
30 import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
31 import gov.nist.secauto.metaschema.core.metapath.TypeMetapathException;
32 import gov.nist.secauto.metaschema.core.metapath.function.library.FnData;
33 import gov.nist.secauto.metaschema.core.metapath.item.IItem;
34 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
35 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDecimalItem;
36 import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;
37 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
38
39 import java.math.BigInteger;
40 import java.math.MathContext;
41 import java.util.List;
42
43 import edu.umd.cs.findbugs.annotations.NonNull;
44 import edu.umd.cs.findbugs.annotations.Nullable;
45
46 public final class FunctionUtils {
47 public static final MathContext MATH_CONTEXT = MathContext.DECIMAL64;
48
49 private FunctionUtils() {
50
51 }
52
53
54
55
56
57
58
59
60
61
62 public static int asInteger(@NonNull INumericItem value) {
63 return asInteger(value.asInteger());
64 }
65
66
67
68
69
70
71
72
73
74
75 public static int asInteger(@NonNull BigInteger value) {
76 return value.intValueExact();
77 }
78
79
80
81
82
83
84
85
86
87
88 public static long asLong(@NonNull INumericItem value) {
89 return asLong(value.asInteger());
90 }
91
92
93
94
95
96
97
98
99
100
101 public static long asLong(@NonNull BigInteger value) {
102 return value.longValueExact();
103 }
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 @NonNull
124 public static <ITEM extends IItem> ITEM requireFirstItem(@NonNull ISequence<ITEM> sequence,
125 boolean requireSingleton) {
126 if (sequence.isEmpty()) {
127 throw new InvalidTypeMetapathException(
128 null,
129 "Expected a non-empty sequence, but sequence was empty.");
130 }
131 List<ITEM> items = sequence.asList();
132 if (requireSingleton && items.size() != 1) {
133 throw new InvalidTypeMetapathException(
134 null,
135 String.format("sequence expected to contain one item, but found '%d'", items.size()));
136 }
137 return ObjectUtils.notNull(items.iterator().next());
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158 @Nullable
159 public static <ITEM extends IItem> ITEM getFirstItem(@NonNull ISequence<ITEM> sequence, boolean requireSingleton) {
160 @Nullable ITEM retval = null;
161 if (!sequence.isEmpty()) {
162 List<ITEM> items = sequence.asList();
163 if (requireSingleton && items.size() != 1) {
164 throw new InvalidTypeMetapathException(
165 null,
166 String.format("sequence expected to contain one item, but found '%d'", items.size()));
167 }
168 retval = items.iterator().next();
169 }
170 return retval;
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 @Nullable
190 public static INumericItem toNumeric(@NonNull ISequence<?> sequence, boolean requireSingleton) {
191 IItem item = getFirstItem(sequence, requireSingleton);
192 return item == null ? null : toNumeric(item);
193 }
194
195
196
197
198
199
200
201
202
203
204
205 @NonNull
206 public static INumericItem toNumeric(@NonNull IItem item) {
207
208 IAnyAtomicItem atomicItem = FnData.fnDataItem(item);
209 return toNumeric(atomicItem);
210 }
211
212
213
214
215
216
217
218
219
220
221 @NonNull
222 public static INumericItem toNumeric(@NonNull IAnyAtomicItem item) {
223 try {
224 return IDecimalItem.cast(item);
225 } catch (InvalidValueForCastFunctionException ex) {
226 throw new InvalidTypeMetapathException(item, ex.getLocalizedMessage(), ex);
227 }
228 }
229
230
231
232
233
234
235
236
237
238
239
240 @Nullable
241 public static INumericItem toNumericOrNull(@Nullable IAnyAtomicItem item) {
242 return item == null ? null : toNumeric(item);
243 }
244
245 @SuppressWarnings("unchecked")
246 @NonNull
247 public static <TYPE extends IItem> TYPE asType(@NonNull IItem item) {
248 return (TYPE) item;
249 }
250
251 @SuppressWarnings("unchecked")
252 @NonNull
253 public static <TYPE extends IItem> ISequence<TYPE> asType(@NonNull ISequence<?> sequence) {
254 return (ISequence<TYPE>) sequence;
255 }
256
257 @SuppressWarnings("unchecked")
258 @Nullable
259 public static <TYPE extends IItem> TYPE asTypeOrNull(@Nullable IItem item) {
260 return (TYPE) item;
261 }
262
263 @NonNull
264 public static <TYPE extends IItem> TYPE requireType(Class<TYPE> clazz, IItem item) {
265 if (item == null) {
266 throw new InvalidTypeMetapathException(
267 null,
268 String.format("Expected non-null type '%s', but the node was null.",
269 clazz.getName()));
270 } else if (!clazz.isInstance(item)) {
271 throw new InvalidTypeMetapathException(
272 item,
273 String.format("Expected type '%s', but the node was type '%s'.",
274 clazz.getName(),
275 item.getClass().getName()));
276 }
277 return FunctionUtils.asType(item);
278 }
279
280 @Nullable
281 public static <TYPE extends IItem> TYPE requireTypeOrNull(Class<TYPE> clazz, @Nullable IItem item) {
282 if (item == null || clazz.isInstance(item)) {
283 return FunctionUtils.asTypeOrNull(item);
284 }
285 throw new InvalidTypeMetapathException(
286 item,
287 String.format("Expected type '%s', but the node was type '%s'.",
288 clazz.getName(),
289 item.getClass().getName()));
290 }
291 }