Skip to content

Commit

Permalink
Added support for the adjust-dateTime-to-timezone Metapath function.
Browse files Browse the repository at this point in the history
  • Loading branch information
david-waltermire committed Jan 9, 2025
1 parent 97d1b7b commit 4fbe0af
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
import gov.nist.secauto.metaschema.core.metapath.function.CalledContext;
import gov.nist.secauto.metaschema.core.metapath.function.DateTimeFunctionException;
import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
import gov.nist.secauto.metaschema.core.metapath.function.IFunction.FunctionProperty;
import gov.nist.secauto.metaschema.core.metapath.item.ISequence;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDayTimeDurationItem;
import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
import gov.nist.secauto.metaschema.core.model.IUriResolver;
import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
Expand All @@ -23,7 +25,9 @@
import java.io.IOException;
import java.net.URI;
import java.time.Clock;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayDeque;
import java.util.ArrayList;
Expand All @@ -45,6 +49,7 @@
* context</a>.
*/
public class DynamicContext { // NOPMD - intentional data class

@NonNull
private final Map<Integer, ISequence<?>> letVariableMap;
@NonNull
Expand Down Expand Up @@ -77,8 +82,6 @@ private static class SharedState {
@NonNull
private final StaticContext staticContext;
@NonNull
private final ZoneId implicitTimeZone;
@NonNull
private final ZonedDateTime currentDateTime;
@NonNull
private final Map<URI, IDocumentNodeItem> availableDocuments;
Expand All @@ -90,6 +93,8 @@ private static class SharedState {
private final IMutableConfiguration<MetapathEvaluationFeature<?>> configuration;
@NonNull
private final Deque<IExpression> executionStack = new ArrayDeque<>();
@NonNull
private ZoneId implicitTimeZone;

public SharedState(@NonNull StaticContext staticContext) {
this.staticContext = staticContext;
Expand Down Expand Up @@ -143,6 +148,51 @@ public ZoneId getImplicitTimeZone() {
return sharedState.implicitTimeZone;
}

/**
* Get the default time zone used for evaluation.
*
* @return the time zone identifier object
*/
@NonNull
public IDayTimeDurationItem getImplicitTimeZoneAsDayTimeDuration() {
ZonedDateTime reference = MetapathConstants.REFERENCE_DATE_TIME.atZone(getImplicitTimeZone());
ZonedDateTime referenceZ = MetapathConstants.REFERENCE_DATE_TIME.atZone(ZoneOffset.UTC);

return IDayTimeDurationItem.valueOf(ObjectUtils.notNull(
Duration.between(
reference,
referenceZ)));
}

/**
* Set the implicit timezone to the provided value.
* <p>
* Note: This value should only be adjusted when the context is first create. Once the context is
* used, this value is expected to be stable.
*
* @param timezone
* the timezone to use
*/
public void setImplicitTimeZone(@NonNull ZoneId timezone) {
sharedState.implicitTimeZone = timezone;
}

/**
* Set the implicit timezone to the provided value.
* <p>
* Note: This value should only be adjusted when the context is first create. Once the context is
* used, this value is expected to be stable.
*
* @param offset
* the offset which must be >= -PT14H and <= PT13H
* @throws DateTimeFunctionException
* with the code {@link DateTimeFunctionException#INVALID_TIME_ZONE_VALUE_ERROR} if the
* offset is < -PT14H or > PT14H
*/
public void setImplicitTimeZone(@NonNull IDayTimeDurationItem offset) {
setImplicitTimeZone(offset.asZoneOffset());
}

/**
* Get the current date and time.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

package gov.nist.secauto.metaschema.core.metapath;

import gov.nist.secauto.metaschema.core.util.ObjectUtils;

import java.time.LocalDateTime;

import edu.umd.cs.findbugs.annotations.NonNull;

/**
Expand All @@ -13,8 +17,7 @@
@SuppressWarnings("PMD.DataClass")
public final class MetapathConstants {
/**
* The namespace URI for Metapath data types and built-in casting functions, as
* a string.
* The namespace URI for Metapath data types and built-in casting functions, as a string.
*/
@NonNull
public static final String NS_METAPATH = "http://csrc.nist.gov/ns/metaschema/metapath";
Expand All @@ -28,16 +31,14 @@ public final class MetapathConstants {
/**
* The namespace URI for Metapath math-related built-in functions, as a string.
*
* @see #PREFIX_METAPATH_FUNCTIONS_MATH for the default prefix for this
* namespace
* @see #PREFIX_METAPATH_FUNCTIONS_MATH for the default prefix for this namespace
*/
@NonNull
public static final String NS_METAPATH_FUNCTIONS_MATH = NS_METAPATH_FUNCTIONS + "/math";
/**
* The namespace URI for Metapath array-related built-in functions, as a string.
*
* @see #PREFIX_METAPATH_FUNCTIONS_ARRAY for the default prefix for this
* namespace
* @see #PREFIX_METAPATH_FUNCTIONS_ARRAY for the default prefix for this namespace
*/
@NonNull
public static final String NS_METAPATH_FUNCTIONS_ARRAY = NS_METAPATH_FUNCTIONS + "/array";
Expand All @@ -51,9 +52,8 @@ public final class MetapathConstants {
/**
* The namespace URI for Metapath extension built-in functions, as a string.
* <p>
* This is currently an alias for {@link #NS_METAPATH_FUNCTIONS} and can be used
* when implementing custom extension functions to distinguish them from core
* functions.
* This is currently an alias for {@link #NS_METAPATH_FUNCTIONS} and can be used when implementing
* custom extension functions to distinguish them from core functions.
*/
@NonNull
public static final String NS_METAPATH_FUNCTIONS_EXTENDED = NS_METAPATH_FUNCTIONS;
Expand Down Expand Up @@ -94,6 +94,12 @@ public final class MetapathConstants {
@NonNull
public static final String PREFIX_METAPATH_FUNCTIONS_MAP = "map";

/**
* A reference date/time value for use in date/time related calculations.
*/
@NonNull
public static final LocalDateTime REFERENCE_DATE_TIME = ObjectUtils.notNull(LocalDateTime.of(1972, 1, 1, 0, 0));

private MetapathConstants() {
// disable construction
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@
import edu.umd.cs.findbugs.annotations.NonNull;

/**
* Implements the XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-array-join">array:join</a>
* function.
* Implements the XPath 3.1
* <a href= "https://www.w3.org/TR/xpath-functions-31/#func-array-join">array:join</a> function.
*/
public final class ArrayJoin {
private static final String NAME = "join";
Expand Down Expand Up @@ -62,8 +61,8 @@ private static <T extends ICollectionValue> ISequence<? extends IArrayItem<T>> e
}

/**
* An implementation of XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-array-join">array:join</a>.
* An implementation of XPath 3.1
* <a href= "https://www.w3.org/TR/xpath-functions-31/#func-array-join">array:join</a>.
*
* @param <T>
* the type of items in the given Metapath array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public DefaultFunctionLibrary() { // NOPMD - intentional
// https://www.w3.org/TR/xpath-functions-31/#func-abs
registerFunction(FnAbs.SIGNATURE);
// https://www.w3.org/TR/xpath-functions-31/#func-adjust-dateTime-to-timezone
registerFunction(FnAdjustDateTimeToTimezone.ONE_ARG_SIGNATURE);
registerFunction(FnAdjustDateTimeToTimezone.TWO_ARG_SIGNATURE);
// https://www.w3.org/TR/xpath-functions-31/#func-adjust-date-to-timezone
// https://www.w3.org/TR/xpath-functions-31/#func-adjust-time-to-timezone
// https://www.w3.org/TR/xpath-functions-31/#func-avg
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/

package gov.nist.secauto.metaschema.core.metapath.function.library;

import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
import gov.nist.secauto.metaschema.core.metapath.item.IItem;
import gov.nist.secauto.metaschema.core.metapath.item.ISequence;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateTimeItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDayTimeDurationItem;

import java.util.List;

import edu.umd.cs.findbugs.annotations.NonNull;

/**
* Implements the XPath 3.1
* <a href= "https://www.w3.org/TR/xpath-functions-31/#func-current-time">fn:current-time</a>
* function.
*/
public final class FnAdjustDateTimeToTimezone {
private static final String NAME = "adjust-dateTime-to-timezone";
@NonNull
static final IFunction ONE_ARG_SIGNATURE = IFunction.builder()
.name(NAME)
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
.deterministic()
.contextDependent()
.focusIndependent()
.argument(IArgument.builder()
.name("arg")
.type(IDateTimeItem.type())
.zeroOrOne()
.build())
.returnType(IDateTimeItem.type())
.returnZeroOrOne()
.functionHandler(FnAdjustDateTimeToTimezone::executeOneArg)
.build();
@NonNull
static final IFunction TWO_ARG_SIGNATURE = IFunction.builder()
.name(NAME)
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
.deterministic()
.contextIndependent()
.focusIndependent()
.argument(IArgument.builder()
.name("arg")
.type(IDateTimeItem.type())
.zeroOrOne()
.build())
.argument(IArgument.builder()
.name("timezone")
.type(IDayTimeDurationItem.type())
.zeroOrOne()
.build())
.returnType(IDateTimeItem.type())
.returnZeroOrOne()
.functionHandler(FnAdjustDateTimeToTimezone::executeTwoArg)
.build();

private FnAdjustDateTimeToTimezone() {
// disable construction
}

@SuppressWarnings("unused")
@NonNull
private static ISequence<IDateTimeItem> executeOneArg(
@NonNull IFunction function,
@NonNull List<ISequence<?>> arguments,
@NonNull DynamicContext dynamicContext,
IItem focus) {
IDateTimeItem arg = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true));
// get the implicit timezone
IDayTimeDurationItem timezone = dynamicContext.getImplicitTimeZoneAsDayTimeDuration();
return arg == null ? ISequence.empty() : ISequence.of(arg.replaceTimezone(timezone));
}

@SuppressWarnings("unused")
@NonNull
private static ISequence<IDateTimeItem> executeTwoArg(
@NonNull IFunction function,
@NonNull List<ISequence<?>> arguments,
@NonNull DynamicContext dynamicContext,
IItem focus) {
IDateTimeItem arg = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true));
IDayTimeDurationItem timezone = FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true));
return arg == null ? ISequence.empty() : ISequence.of(arg.replaceTimezone(timezone));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
* function.
*/
public final class FnCurrentDateTime {
private static final String NAME = "current-dateTime";
@NonNull
static final IFunction SIGNATURE = IFunction.builder()
.name("current-dateTime")
.name(NAME)
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
.deterministic()
.contextDependent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
import edu.umd.cs.findbugs.annotations.NonNull;

/**
* Implements the XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-current-time">fn:current-time</a>
* Implements the XPath 3.1
* <a href= "https://www.w3.org/TR/xpath-functions-31/#func-current-time">fn:current-time</a>
* function.
*/
public final class FnCurrentTime {
private static final String NAME = "current-time";
@NonNull
static final IFunction SIGNATURE = IFunction.builder()
.name("current-time")
.name(NAME)
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
.deterministic()
.contextDependent()
Expand All @@ -49,8 +50,8 @@ private static ISequence<ITimeItem> execute(@NonNull IFunction function,
}

/**
* Implements <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-current-time">fn:current-time</a>.
* Implements
* <a href= "https://www.w3.org/TR/xpath-functions-31/#func-current-time">fn:current-time</a>.
*
* @param dynamicContext
* the dynamic evaluation context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*/
public final class FnDateTime {
@NonNull
private static final String NAME = "date-time";
private static final String NAME = "dateTime";
@NonNull
static final IFunction SIGNATURE = IFunction.builder()
.name(NAME)
Expand Down Expand Up @@ -79,6 +79,13 @@ private static ISequence<IDateTimeItem> execute(@NonNull IFunction function,
* Implements the XPath 3.1
* <a href= "https://www.w3.org/TR/xpath-functions-31/#func-current-date">fn:current-date</a>
* function.
*
* @param date
* the date value to get the year, month, and day from
* @param time
* the time value to get the hour, minute, seconds from
* @return the data/time value composed of the provided date and time values or {@code null} if
* either date or time value is {@code null}.
*/
@Nullable
public static IDateTimeItem fnDateTime(@Nullable IDateItem date, @Nullable ITimeItem time) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import java.time.Duration;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;

Expand Down Expand Up @@ -61,10 +62,11 @@ private static ISequence<IDayTimeDurationItem> execute(@NonNull IFunction functi
*/
@NonNull
public static IDayTimeDurationItem fnImplicitTimezone(@NonNull DynamicContext dynamicContext) {
ZonedDateTime now = dynamicContext.getCurrentDateTime();
ZoneId timezone = dynamicContext.getImplicitTimeZone();
ZonedDateTime now = dynamicContext.getCurrentDateTime().withZoneSameInstant(timezone);
return IDayTimeDurationItem.valueOf(ObjectUtils.notNull(
Duration.between(
now,
now.withZoneSameLocal(ZoneId.of("UTC")))));
now.withZoneSameLocal(ZoneOffset.UTC))));
}
}
Loading

0 comments on commit 4fbe0af

Please sign in to comment.