From 3b4ac40d06a511bc3ac001f6a1cb3871edd51ae8 Mon Sep 17 00:00:00 2001 From: David Waltermire Date: Mon, 13 Jan 2025 13:22:02 -0500 Subject: [PATCH] WIP. Aligned atomic item map key implementations with the XPath 3.1 specification. --- .../adapter/AbstractDurationAdapter.java | 4 + .../core/datatype/adapter/DecimalAdapter.java | 6 +- .../AbstractBasicArithmeticExpression.java | 4 +- .../function/ComparisonFunctions.java | 51 ++++ .../function/impl/OperationFunctions.java | 218 ++++++++++++------ .../metapath/impl/AbstractDecimalMapKey.java | 29 +++ .../core/metapath/impl/AbstractMapKey.java | 15 ++ .../metapath/impl/AbstractOpaqueMapKey.java | 23 ++ .../metapath/impl/AbstractStringMapKey.java | 12 +- .../metapath/impl/AbstractTemporalMapKey.java | 45 ++++ .../atomic/AbstractUntypedAtomicItem.java | 5 + .../metapath/item/atomic/IDateTimeItem.java | 2 +- .../item/atomic/IDayTimeDurationItem.java | 21 +- .../metapath/item/atomic/IDurationItem.java | 15 +- .../metapath/item/atomic/IIPAddressItem.java | 1 + .../metapath/item/atomic/ITemporalItem.java | 15 +- .../core/metapath/item/atomic/ITimeItem.java | 49 ++-- .../item/atomic/IYearMonthDurationItem.java | 19 +- .../item/atomic/impl/AbstractDecimalItem.java | 26 ++- .../atomic/impl/AbstractDurationItem.java | 9 +- .../atomic/impl/AbstractIPAddressItem.java | 24 +- .../item/atomic/impl/AbstractMarkupItem.java | 24 +- .../item/atomic/impl/AbstractStringItem.java | 34 +-- .../atomic/impl/AbstractTemporalItem.java | 25 +- .../item/atomic/impl/AbstractTimeItem.java | 32 +-- .../item/atomic/impl/AbstractUriItem.java | 15 ++ .../atomic/impl/Base64BinaryItemImpl.java | 16 +- .../item/atomic/impl/BooleanItemImpl.java | 16 +- .../atomic/impl/DayTimeDurationItemImpl.java | 20 +- .../item/atomic/impl/HexBinaryItem.java | 16 +- .../item/atomic/impl/UuidItemImpl.java | 15 +- .../impl/YearMonthDurationItemImpl.java | 19 +- .../item/function/IDecimalMapKey.java | 20 ++ .../core/metapath/item/function/IMapKey.java | 6 + .../metapath/item/function/IOpaqueMapKey.java | 10 + .../metapath/item/function/IStringMapKey.java | 18 ++ .../item/function/ITemporalMapKey.java | 15 ++ .../metaschema/core/metapath/TestUtils.java | 12 +- .../metapath/item/function/IMapKeyTest.java | 51 ++++ 39 files changed, 623 insertions(+), 334 deletions(-) create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractDecimalMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractOpaqueMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractTemporalMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IDecimalMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IOpaqueMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IStringMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/ITemporalMapKey.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapKeyTest.java diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractDurationAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractDurationAdapter.java index 603672a77..22bc83566 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractDurationAdapter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractDurationAdapter.java @@ -1,3 +1,7 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ package gov.nist.secauto.metaschema.core.datatype.adapter; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java index d2dc55ebb..534dd4a0d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java @@ -23,9 +23,9 @@ import edu.umd.cs.findbugs.annotations.NonNull; /** - * Support for the Metaschema - * decimal data - * type. + * Support for the Metaschema decimal + * data type. */ public class DecimalAdapter extends AbstractDataTypeAdapter { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/math/AbstractBasicArithmeticExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/math/AbstractBasicArithmeticExpression.java index 24a24f47a..2ca6f53a4 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/math/AbstractBasicArithmeticExpression.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/math/AbstractBasicArithmeticExpression.java @@ -25,8 +25,8 @@ * result type. *

* The arithmetic operation method - * {@link #operation(IAnyAtomicItem, IAnyAtomicItem)} must be implemented by - * extending classes to provide the evaluation logic. + * {@link #operation(IAnyAtomicItem, IAnyAtomicItem, DynamicContext)} must be + * implemented by extending classes to provide the evaluation logic. */ public abstract class AbstractBasicArithmeticExpression extends AbstractArithmeticExpression { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java index 9b95dff5b..e06f048c5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java @@ -19,6 +19,7 @@ import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.ITimeItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUntypedAtomicItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IYearMonthDurationItem; import gov.nist.secauto.metaschema.core.metapath.type.InvalidTypeMetapathException; @@ -194,6 +195,8 @@ public static IBooleanItem compare( // NOPMD - unavoidable retval = dateTimeCompare((IDateTimeItem) left, operator, (IDateTimeItem) right); } else if (left instanceof IDateItem && right instanceof IDateItem) { retval = dateCompare((IDateItem) left, operator, (IDateItem) right); + } else if (left instanceof ITimeItem && right instanceof ITimeItem) { + retval = timeCompare((ITimeItem) left, operator, (ITimeItem) right); } else if (left instanceof IDurationItem && right instanceof IDurationItem) { retval = durationCompare((IDurationItem) left, operator, (IDurationItem) right); } else if (left instanceof IBase64BinaryItem && right instanceof IBase64BinaryItem) { @@ -440,6 +443,54 @@ public static IBooleanItem dateCompare(@NonNull IDateItem left, @NonNull Operato return retval; } + /** + * Perform a date-based comparison of the {@code right} item against the + * {@code left} item using the specified {@code operator}. + * + * @param left + * the value to compare against + * @param operator + * the comparison operator + * @param right + * the value to compare with + * @return the comparison result + */ + @NonNull + public static IBooleanItem timeCompare(@NonNull ITimeItem left, @NonNull Operator operator, + @NonNull ITimeItem right) { + + IBooleanItem retval; + switch (operator) { + case EQ: + retval = OperationFunctions.opTimeEqual(left, right); + break; + case GE: { + IBooleanItem gt = OperationFunctions.opTimeGreaterThan(left, right); + IBooleanItem eq = OperationFunctions.opTimeEqual(left, right); + retval = IBooleanItem.valueOf(gt.toBoolean() || eq.toBoolean()); + break; + } + case GT: + retval = OperationFunctions.opTimeGreaterThan(left, right); + break; + case LE: { + IBooleanItem lt = OperationFunctions.opTimeLessThan(left, right); + IBooleanItem eq = OperationFunctions.opTimeEqual(left, right); + retval = IBooleanItem.valueOf(lt.toBoolean() || eq.toBoolean()); + break; + } + case LT: + retval = OperationFunctions.opTimeLessThan(left, right); + break; + case NE: + retval = FnNot.fnNot(OperationFunctions.opTimeEqual(left, right)); + break; + default: + throw new IllegalArgumentException(String.format("Unsupported operator '%s'", operator.name())); + } + return retval; + } + /** * Perform a duration-based comparison of the {@code right} item against the * {@code left} item using the specified {@code operator}. diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/impl/OperationFunctions.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/impl/OperationFunctions.java index 7296f36bf..ac2c09ae3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/impl/OperationFunctions.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/impl/OperationFunctions.java @@ -228,8 +228,8 @@ public static ITimeItem opAddDayTimeDurationToTime( } /** - * Based on XPath 3.1 - * op:subtract-dates. + * Based on XPath 3.1 op:subtract-dates. * * @param date1 * the first point in time @@ -302,8 +302,8 @@ public static ITimeItem opSubtractDayTimeDurationFromTime( } /** - * Based on XPath 3.1 - * op:subtract-times. + * Based on XPath 3.1 op:subtract-times. * * @param arg1 * the first duration @@ -400,8 +400,9 @@ public static IDayTimeDurationItem opSubtractDateTimes( /** * Based on XPath 3.1 op:subtract-dateTimes and - * op:subtract-times. + * "https://www.w3.org/TR/xpath-functions-31/#func-subtract-dateTimes">op:subtract-dateTimes + * and op:subtract-times. * * @param time1 * the first point in time @@ -457,10 +458,12 @@ public static IDateTimeItem opSubtractDayTimeDurationFromDateTime( * the duration value * @param arg2 * the number to multiply by - * @return the result of multiplying a {@link IYearMonthDurationItem} by a number + * @return the result of multiplying a {@link IYearMonthDurationItem} by a + * number * @throws DateTimeFunctionException - * with the code {@link DateTimeFunctionException#DURATION_OVERFLOW_UNDERFLOW_ERROR} if - * arithmetic overflow occurs + * with the code + * {@link DateTimeFunctionException#DURATION_OVERFLOW_UNDERFLOW_ERROR} + * if arithmetic overflow occurs */ @NonNull public static IYearMonthDurationItem opMultiplyYearMonthDuration( @@ -531,7 +534,8 @@ public static IYearMonthDurationItem opDivideYearMonthDuration( * the first duration value * @param arg2 * the second duration value - * @return the result of dividing a the first duration value by the second duration value + * @return the result of dividing a the first duration value by the second + * duration value */ @NonNull public static IDecimalItem opDivideYearMonthDurationByYearMonthDuration( @@ -572,7 +576,8 @@ public static IDayTimeDurationItem opDivideDayTimeDuration( * the first duration value * @param arg2 * the second duration value - * @return the ratio of two {@link IDayTimeDurationItem} values, as a decimal number + * @return the ratio of two {@link IDayTimeDurationItem} values, as a decimal + * number */ @NonNull public static IDecimalItem opDivideDayTimeDurationByDayTimeDuration( @@ -585,15 +590,15 @@ public static IDecimalItem opDivideDayTimeDurationByDayTimeDuration( } /** - * Based on XPath 3.1 - * op:date-equal. + * Based on XPath 3.1 op:date-equal. * * @param arg1 * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is the same instant in time as the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is the same instant in time as the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDateEqual(@NonNull IDateItem arg1, @NonNull IDateItem arg2) { @@ -601,15 +606,15 @@ public static IBooleanItem opDateEqual(@NonNull IDateItem arg1, @NonNull IDateIt } /** - * Based on XPath 3.1 - * op:dateTime-equal. + * Based on XPath 3.1 op:dateTime-equal. * * @param arg1 * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is the same instant in time as the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is the same instant in time as the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDateTimeEqual(@NonNull IDateTimeItem arg1, @NonNull IDateTimeItem arg2) { @@ -617,15 +622,33 @@ public static IBooleanItem opDateTimeEqual(@NonNull IDateTimeItem arg1, @NonNull } /** - * Based on XPath 3.1 - * op:duration-equal. + * Based on XPath 3.1 op:time-equal. * * @param arg1 * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is the same duration as the second, or {@code false} - * otherwise + * @return {@code true} if the first argument is the same instant in time as the + * second, or {@code false} otherwise + */ + @NonNull + public static IBooleanItem opTimeEqual(@NonNull ITimeItem arg1, @NonNull ITimeItem arg2) { + IDateTimeItem time1 = IDateTimeItem.valueOf(DATE_1972_12_31, arg1); + IDateTimeItem time2 = IDateTimeItem.valueOf(DATE_1972_12_31, arg2); + return opDateTimeEqual(time1, time2); + } + + /** + * Based on XPath 3.1 op:duration-equal. + * + * @param arg1 + * the first value + * @param arg2 + * the second value + * @return {@code true} if the first argument is the same duration as the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDurationEqual(@NonNull IDurationItem arg1, @NonNull IDurationItem arg2) { @@ -640,7 +663,8 @@ public static IBooleanItem opDurationEqual(@NonNull IDurationItem arg1, @NonNull * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is equal to the second, or {@code false} otherwise + * @return {@code true} if the first argument is equal to the second, or + * {@code false} otherwise */ @NonNull public static IBooleanItem opBase64BinaryEqual(@NonNull IBase64BinaryItem arg1, @NonNull IBase64BinaryItem arg2) { @@ -655,8 +679,8 @@ public static IBooleanItem opBase64BinaryEqual(@NonNull IBase64BinaryItem arg1, * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is a later instant in time than the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is a later instant in time than + * the second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDateGreaterThan(@NonNull IDateItem arg1, @NonNull IDateItem arg2) { @@ -671,14 +695,32 @@ public static IBooleanItem opDateGreaterThan(@NonNull IDateItem arg1, @NonNull I * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is a later instant in time than the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is a later instant in time than + * the second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDateTimeGreaterThan(@NonNull IDateTimeItem arg1, @NonNull IDateTimeItem arg2) { return IBooleanItem.valueOf(arg1.asZonedDateTime().compareTo(arg2.asZonedDateTime()) > 0); } + /** + * Based on XPath 3.1 op:time-greater-than. + * + * @param arg1 + * the first value + * @param arg2 + * the second value + * @return {@code true} if the first argument is a later instant in time than + * the second, or {@code false} otherwise + */ + @NonNull + public static IBooleanItem opTimeGreaterThan(@NonNull ITimeItem arg1, @NonNull ITimeItem arg2) { + IDateTimeItem time1 = IDateTimeItem.valueOf(DATE_1972_12_31, arg1); + IDateTimeItem time2 = IDateTimeItem.valueOf(DATE_1972_12_31, arg2); + return opDateTimeGreaterThan(time1, time2); + } + /** * Based on XPath 3.1 op:yearMonthDuration-greater-than. @@ -687,8 +729,8 @@ public static IBooleanItem opDateTimeGreaterThan(@NonNull IDateTimeItem arg1, @N * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is a longer duration than the second, or {@code false} - * otherwise + * @return {@code true} if the first argument is a longer duration than the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opYearMonthDurationGreaterThan( @@ -705,8 +747,8 @@ public static IBooleanItem opYearMonthDurationGreaterThan( * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is a longer duration than the second, or {@code false} - * otherwise + * @return {@code true} if the first argument is a longer duration than the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDayTimeDurationGreaterThan( @@ -723,7 +765,8 @@ public static IBooleanItem opDayTimeDurationGreaterThan( * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is greater than the second, or {@code false} otherwise + * @return {@code true} if the first argument is greater than the second, or + * {@code false} otherwise */ @NonNull public static IBooleanItem opBase64BinaryGreaterThan( @@ -733,15 +776,15 @@ public static IBooleanItem opBase64BinaryGreaterThan( } /** - * Based on XPath 3.1 - * op:date-less-than. + * Based on XPath 3.1 op:date-less-than. * * @param arg1 * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is an earlier instant in time than the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is an earlier instant in time than + * the second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDateLessThan( @@ -758,8 +801,28 @@ public static IBooleanItem opDateLessThan( * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is an earlier instant in time than the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is an earlier instant in time than + * the second, or {@code false} otherwise + */ + @NonNull + public static IBooleanItem opTimeLessThan( + @NonNull ITimeItem arg1, + @NonNull ITimeItem arg2) { + IDateTimeItem time1 = IDateTimeItem.valueOf(DATE_1972_12_31, arg1); + IDateTimeItem time2 = IDateTimeItem.valueOf(DATE_1972_12_31, arg2); + return opDateTimeLessThan(time1, time2); + } + + /** + * Based on XPath 3.1 op:time-less-than. + * + * @param arg1 + * the first value + * @param arg2 + * the second value + * @return {@code true} if the first argument is an earlier instant in time than + * the second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDateTimeLessThan( @@ -776,8 +839,8 @@ public static IBooleanItem opDateTimeLessThan( * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is a shorter duration than the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is a shorter duration than the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opYearMonthDurationLessThan( @@ -794,8 +857,8 @@ public static IBooleanItem opYearMonthDurationLessThan( * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is a shorter duration than the second, or - * {@code false} otherwise + * @return {@code true} if the first argument is a shorter duration than the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opDayTimeDurationLessThan( @@ -812,7 +875,8 @@ public static IBooleanItem opDayTimeDurationLessThan( * the first value * @param arg2 * the second value - * @return {@code true} if the first argument is less than the second, or {@code false} otherwise + * @return {@code true} if the first argument is less than the second, or + * {@code false} otherwise */ @NonNull public static IBooleanItem opBase64BinaryLessThan( @@ -862,10 +926,11 @@ private interface ArithmeticOperation { } /** - * Create a new sum by adding first provided addend value to the second provided addend value. + * Create a new sum by adding first provided addend value to the second provided + * addend value. *

- * Based on XPath 3.1 - * op:numeric-add. + * Based on XPath 3.1 op:numeric-add. * * @param addend1 * the first addend @@ -883,8 +948,8 @@ public static INumericItem opNumericAdd(@NonNull INumericItem addend1, @NonNull } /** - * Determine the difference by subtracting the provided subtrahend value from the provided minuend - * value. + * Determine the difference by subtracting the provided subtrahend value from + * the provided minuend value. *

* Based on XPath 3.1 op:numeric-subtract. @@ -893,7 +958,8 @@ public static INumericItem opNumericAdd(@NonNull INumericItem addend1, @NonNull * the value to subtract from * @param subtrahend * the value to subtract - * @return a new value resulting from subtracting the subtrahend from the minuend + * @return a new value resulting from subtracting the subtrahend from the + * minuend */ @NonNull public static INumericItem opNumericSubtract( @@ -916,7 +982,8 @@ public static INumericItem opNumericSubtract( * the value to multiply * @param multiplier * the value to multiply by - * @return a new value resulting from multiplying the multiplicand by the multiplier + * @return a new value resulting from multiplying the multiplicand by the + * multiplier */ @NonNull public static INumericItem opNumericMultiply( @@ -930,8 +997,8 @@ public static INumericItem opNumericMultiply( } /** - * Based on XPath 3.1 - * op:numeric-divide. + * Based on XPath 3.1 op:numeric-divide. * * @param dividend * the number to be divided @@ -939,8 +1006,8 @@ public static INumericItem opNumericMultiply( * the number to divide by * @return the quotient * @throws ArithmeticFunctionException - * with the code {@link ArithmeticFunctionException#DIVISION_BY_ZERO} if the divisor is - * zero + * with the code {@link ArithmeticFunctionException#DIVISION_BY_ZERO} + * if the divisor is zero */ @NonNull public static IDecimalItem opNumericDivide(@NonNull INumericItem dividend, @NonNull INumericItem divisor) { @@ -969,8 +1036,8 @@ public static IIntegerItem opNumericIntegerDivide( } /** - * Based on XPath 3.1 - * op:numeric-mod. + * Based on XPath 3.1 op:numeric-mod. * * @param dividend * the number to be divided @@ -1009,14 +1076,15 @@ public static INumericItem opNumericUnaryMinus(@NonNull INumericItem item) { } /** - * Based on XPath 3.1 - * op:numeric-equal. + * Based on XPath 3.1 op:numeric-equal. * * @param arg1 * the first number to check for equality * @param arg2 * the second number to check for equality - * @return {@code true} if the numbers are numerically equal or {@code false} otherwise + * @return {@code true} if the numbers are numerically equal or {@code false} + * otherwise */ @NonNull public static IBooleanItem opNumericEqual(@Nullable INumericItem arg1, @Nullable INumericItem arg2) { @@ -1039,8 +1107,8 @@ public static IBooleanItem opNumericEqual(@Nullable INumericItem arg1, @Nullable * the first number to check * @param arg2 * the second number to check - * @return {@code true} if the first number is greater than or equal to the second, or {@code false} - * otherwise + * @return {@code true} if the first number is greater than or equal to the + * second, or {@code false} otherwise */ @NonNull public static IBooleanItem opNumericGreaterThan(@Nullable INumericItem arg1, @Nullable INumericItem arg2) { @@ -1065,8 +1133,8 @@ public static IBooleanItem opNumericGreaterThan(@Nullable INumericItem arg1, @Nu * the first number to check * @param arg2 * the second number to check - * @return {@code true} if the first number is less than or equal to the second, or {@code false} - * otherwise + * @return {@code true} if the first number is less than or equal to the second, + * or {@code false} otherwise */ @NonNull public static IBooleanItem opNumericLessThan(@Nullable INumericItem arg1, @Nullable INumericItem arg2) { @@ -1084,14 +1152,15 @@ public static IBooleanItem opNumericLessThan(@Nullable INumericItem arg1, @Nulla } /** - * Based on XPath 3.1 - * op:boolean-equal. + * Based on XPath 3.1 op:boolean-equal. * * @param arg1 * the first boolean to check * @param arg2 * the second boolean to check - * @return {@code true} if the first boolean is equal to the second, or {@code false} otherwise + * @return {@code true} if the first boolean is equal to the second, or + * {@code false} otherwise */ @NonNull public static IBooleanItem opBooleanEqual(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) { @@ -1109,8 +1178,8 @@ public static IBooleanItem opBooleanEqual(@Nullable IBooleanItem arg1, @Nullable * the first boolean to check * @param arg2 * the second boolean to check - * @return {@code true} if the first argument is {@link IBooleanItem#TRUE} and the second is - * {@link IBooleanItem#FALSE}, or {@code false} otherwise + * @return {@code true} if the first argument is {@link IBooleanItem#TRUE} and + * the second is {@link IBooleanItem#FALSE}, or {@code false} otherwise */ @NonNull public static IBooleanItem opBooleanGreaterThan(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) { @@ -1128,8 +1197,8 @@ public static IBooleanItem opBooleanGreaterThan(@Nullable IBooleanItem arg1, @Nu * the first boolean to check * @param arg2 * the second boolean to check - * @return {@code true} if the first argument is {@link IBooleanItem#FALSE} and the second is - * {@link IBooleanItem#TRUE}, or {@code false} otherwise + * @return {@code true} if the first argument is {@link IBooleanItem#FALSE} and + * the second is {@link IBooleanItem#TRUE}, or {@code false} otherwise */ @NonNull public static IBooleanItem opBooleanLessThan(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) { @@ -1140,14 +1209,15 @@ public static IBooleanItem opBooleanLessThan(@Nullable IBooleanItem arg1, @Nulla } /** - * Based on XPath 3.1 - * op:same-key. + * Based on XPath 3.1 op:same-key. * * @param k1 * the first key to compare * @param k2 * the second key to compare - * @return {@code true} if the compared keys are the same, or {@code false} otherwise + * @return {@code true} if the compared keys are the same, or {@code false} + * otherwise */ public static boolean opSameKey(@NonNull IAnyAtomicItem k1, @NonNull IAnyAtomicItem k2) { boolean retval; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractDecimalMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractDecimalMapKey.java new file mode 100644 index 000000000..47abd6a2f --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractDecimalMapKey.java @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.item.function.IDecimalMapKey; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; + +/** + * An implementation of a {@link IMapKey} that uses a string-based value. + */ +public abstract class AbstractDecimalMapKey + extends AbstractMapKey + implements IDecimalMapKey { + + @Override + public int hashCode() { + return asDecimal().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj + // TODO: implement fn:codepoint-equal per spec + || obj instanceof IDecimalMapKey && asDecimal().equals(((IDecimalMapKey) obj).asDecimal()); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapKey.java new file mode 100644 index 000000000..48fe859f8 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapKey.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; + +public abstract class AbstractMapKey implements IMapKey { + @Override + public String toString() { + return getKey().toSignature(); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractOpaqueMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractOpaqueMapKey.java new file mode 100644 index 000000000..c5aa6fed5 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractOpaqueMapKey.java @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.item.function.IOpaqueMapKey; + +public abstract class AbstractOpaqueMapKey + extends AbstractMapKey + implements IOpaqueMapKey { + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj + || obj instanceof IOpaqueMapKey && getKey().deepEquals(((IOpaqueMapKey) obj).getKey()); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java index 86b895874..92a990b3f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java @@ -6,22 +6,24 @@ package gov.nist.secauto.metaschema.core.metapath.impl; import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; +import gov.nist.secauto.metaschema.core.metapath.item.function.IStringMapKey; /** * An implementation of a {@link IMapKey} that uses a string-based value. */ public abstract class AbstractStringMapKey - implements IMapKey { + extends AbstractMapKey + implements IStringMapKey { @Override public int hashCode() { - return getKey().asStringItem().hashCode(); + return asString().hashCode(); } @Override public boolean equals(Object obj) { - return this == obj || - obj instanceof IMapKey - && getKey().asStringItem().equals(((AbstractStringMapKey) obj).getKey().asStringItem()); + return this == obj + // TODO: implement fn:codepoint-equal per spec + || obj instanceof IStringMapKey && getKey().asString().equals(((IStringMapKey) obj).getKey().asString()); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractTemporalMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractTemporalMapKey.java new file mode 100644 index 000000000..0edf61765 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractTemporalMapKey.java @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.item.atomic.ITemporalItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.ITemporalMapKey; + +import java.time.ZoneOffset; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractTemporalMapKey + extends AbstractMapKey + implements ITemporalMapKey { + @Override + public int hashCode() { + ITemporalItem temporal = asTemporalItem(); + int hash = 7; + hash = 31 * hash + temporal.getYear(); + hash = 31 * hash + temporal.getDay(); + hash = 31 * hash + temporal.getHour(); + hash = 31 * hash + temporal.getYear(); + hash = 31 * hash + temporal.getMinute(); + hash = 31 * hash + temporal.getSecond(); + hash = 31 * hash + temporal.getNano(); + + ZoneOffset offset = temporal.getZoneOffset(); + return 31 * hash + (offset == null ? 0 : offset.hashCode()); + } + + @Override + public boolean equals(Object obj) { + return this == obj + || obj instanceof ITemporalMapKey && equalsInternal((ITemporalMapKey) obj); + } + + private boolean equalsInternal(@NonNull ITemporalMapKey other) { + ITemporalItem focus = asTemporalItem(); + ITemporalItem that = other.asTemporalItem(); + return focus.hasTimezone() == that.hasTimezone() && focus.deepEquals(that); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java index 1bf43d499..90bf7cbc2 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java @@ -42,5 +42,10 @@ private final class MapKey public IUntypedAtomicItem getKey() { return AbstractUntypedAtomicItem.this; } + + @Override + public String asString() { + return getKey().asString(); + } } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java index b54836a2b..994f1f80f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java @@ -105,7 +105,7 @@ static IDateTimeItem valueOf(@NonNull ZonedDateTime value, boolean hasTimeZone) @NonNull static IDateTimeItem valueOf(@NonNull LocalDateTime value) { - return valueOf(new AmbiguousDateTime(value.atZone(ZoneOffset.UTC), false)); + return valueOf(new AmbiguousDateTime(ObjectUtils.notNull(value.atZone(ZoneOffset.UTC)), false)); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java index 3e2990337..0d59ebf9a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java @@ -19,7 +19,8 @@ import edu.umd.cs.findbugs.annotations.NonNull; /** - * An atomic Metapath item containing a duration data value in days, hours, and seconds. + * An atomic Metapath item containing a duration data value in days, hours, and + * seconds. */ public interface IDayTimeDurationItem extends IDurationItem { /** @@ -38,13 +39,15 @@ default IAtomicOrUnionType getType() { } /** - * Construct a new day time duration item using the provided string {@code value}. + * Construct a new day time duration item using the provided string + * {@code value}. * * @param value * a string representing a day time duration * @return the new item * @throws InvalidTypeMetapathException - * if the provided string value is not a day/time duration value according to ISO 8601 + * if the provided string value is not a day/time duration value + * according to ISO 8601 */ @NonNull static IDayTimeDurationItem valueOf(@NonNull String value) { @@ -98,7 +101,8 @@ default IDayTimeDurationItem negate() { * * @param item * the item to cast - * @return the original item if it is already this type, otherwise a new item cast to this type + * @return the original item if it is already this type, otherwise a new item + * cast to this type * @throws InvalidValueForCastFunctionException * if the provided {@code item} cannot be cast to this type */ @@ -124,8 +128,8 @@ default IDayTimeDurationItem castAsType(IAnyAtomicItem item) { * * @param item * the item to compare with this value - * @return a negative integer, zero, or a positive integer if this value is less than, equal to, or - * greater than the {@code item}. + * @return a negative integer, zero, or a positive integer if this value is less + * than, equal to, or greater than the {@code item}. */ default int compareTo(@NonNull IDayTimeDurationItem item) { return asDuration().compareTo(item.asDuration()); @@ -142,8 +146,9 @@ default int compareTo(IAnyAtomicItem item) { * * @return the offset * @throws DateTimeFunctionException - * with code {@link DateTimeFunctionException#INVALID_TIME_ZONE_VALUE_ERROR} if the offset - * is < -PT14H or > PT14H + * with code + * {@link DateTimeFunctionException#INVALID_TIME_ZONE_VALUE_ERROR} if + * the offset is < -PT14H or > PT14H */ @NonNull ZoneOffset asZoneOffset(); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java index d5368aed7..63745cbe5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java @@ -18,8 +18,8 @@ /** * An atomic Metapath item representing a duration data value. *

- * This interface supports both day-time and year-month duration formats following the ISO 8601 - * standard. Examples of valid durations include: + * This interface supports both day-time and year-month duration formats + * following the ISO 8601 standard. Examples of valid durations include: *