Commit a2c1872d authored by cdanger's avatar cdanger

- Fixed typos in README

- Upgraded authzforce-ce-core-pdp-api dependency: 12.1.0 -> 13.0.0
- Implementation of feature requested in Github issue 10 (with unit
tests): creation of (XACML) AttributeValues from standard Java types
parent a2da6b4b
......@@ -88,14 +88,14 @@ Copy the content of [that folder](pdp-cli/src/test/resources/conformance/xacml-3
$ ./authzforce-ce-core-pdp-cli-10.0.0.jar pdp.xml IIA001/Request.xml
```
* `pdp.xml`: PDP configuration file, that defines the location(s) of XACML policy(ies), among other PDP engine parameters; this content of this file is a XML document compliant with the PDP configuration [XML schema](pdp-engine/src/main/resources/pdp.xsd), so you can read the documentation of every configuration parameter in that schema file;
* `request.xml`: XACML request in XACML 3.0/XML (core specification) format.
* `pdp.xml`: PDP configuration file, that defines the location(s) of XACML policy(ies), among other PDP engine parameters; the content of this file is a XML document compliant with the PDP configuration [XML schema](pdp-engine/src/main/resources/pdp.xsd), so you can read the documentation of every configuration parameter in that schema file;
* `Request.xml`: XACML request in XACML 3.0/XML (core specification) format.
If you want to test the JSON Profile of XACML 3.0, run it with extra option `-t XACML_JSON`:
```
$ ./authzforce-ce-core-pdp-cli-10.0.0.jar -t XACML_JSON pdp.xml IIA001/Request.json
```
* `request.json`: XACML request in XACML 3.0/JSON (Profile) format.
* `Request.json`: XACML request in XACML 3.0/JSON (Profile) format.
For more info, run it without parameters and you'll get detailed information on usage.
......@@ -233,7 +233,7 @@ If you are experiencing any issue with this project, please report it on the [OW
Please include as much information as possible; the more we know, the better the chance of a quicker resolution:
* Software version
* Platform (OS and JDK)
* Platform (OS and JRE)
* Stack traces generally really help! If in doubt include the whole thing; often exceptions get wrapped in other exceptions and the exception right near the bottom explains the actual error, not the first few lines at the top. It's very easy for us to skim-read past unnecessary parts of a stack trace.
* Log output can be useful too; sometimes enabling DEBUG logging can help;
* Your code & configuration files are often useful.
......
......@@ -42,7 +42,6 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>${artifactId.prefix}-core-pdp-api</artifactId>
<version>12.1.0</version>
</dependency>
<!-- /Authzforce dependencies -->
......
......@@ -18,22 +18,34 @@
package org.ow2.authzforce.core.pdp.impl.value;
import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.xml.namespace.QName;
import net.sf.saxon.s9api.XPathCompiler;
import org.ow2.authzforce.core.pdp.api.AttributeSources;
import org.ow2.authzforce.core.pdp.api.HashCollections;
import org.ow2.authzforce.core.pdp.api.expression.ConstantExpression;
import org.ow2.authzforce.core.pdp.api.expression.ConstantPrimitiveAttributeValueExpression;
import org.ow2.authzforce.core.pdp.api.value.AttributeBag;
import org.ow2.authzforce.core.pdp.api.value.AttributeValue;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactory;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactoryRegistry;
import org.ow2.authzforce.core.pdp.api.value.Bags;
import org.ow2.authzforce.core.pdp.api.value.Datatype;
import org.ow2.authzforce.core.pdp.api.value.SimpleValue.StringParseableValueFactory;
import org.ow2.authzforce.core.pdp.impl.BasePdpExtensionRegistry;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
/**
* Immutable <code>DatatypeFactoryRegistry</code>.
......@@ -45,19 +57,6 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
{
private static final IllegalArgumentException ILLEGAL_DATATYPE_ID_ARGUMENT_EXCEPTION = new IllegalArgumentException("Undefined datatype ID");
/**
* <p>
* Constructor for BaseDatatypeFactoryRegistry.
* </p>
*
* @param attributeValueFactories
* attribute value factories
*/
public ImmutableAttributeValueFactoryRegistry(final Set<? extends AttributeValueFactory<?>> attributeValueFactories)
{
super(AttributeValueFactory.class, Preconditions.checkNotNull(attributeValueFactories, "Input attribute datatype factories undefined (attributeValueFactories == null)"));
}
/**
* <p>
* createValue
......@@ -75,7 +74,7 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
* @throws java.lang.IllegalArgumentException
* if any.
*/
private static <V extends AttributeValue> V newValue(final AttributeValueFactory<V> attValFactory, final List<Serializable> content, final Map<QName, String> otherAttributes,
private static <V extends AttributeValue> V newAttributeValue(final AttributeValueFactory<V> attValFactory, final List<Serializable> content, final Map<QName, String> otherAttributes,
final XPathCompiler xPathCompiler) throws IllegalArgumentException
{
assert attValFactory != null;
......@@ -96,10 +95,75 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
final Map<QName, String> otherAttributes, final XPathCompiler xPathCompiler) throws IllegalArgumentException
{
assert attValFactory != null;
final V rawValue = newValue(attValFactory, content, otherAttributes, xPathCompiler);
final V rawValue = newAttributeValue(attValFactory, content, otherAttributes, xPathCompiler);
return new ConstantPrimitiveAttributeValueExpression<>(attValFactory.getDatatype(), rawValue);
}
/**
* Creates instance of immutable attribute bag from raw values, with {@link AttributeSources#REQUEST} as attribute source.
*
* @param attributeValueFactory
* factory in charge of create attribute values in the bag
*
* @param rawValues
* raw values to be parsed by {@code attributeValueFactory} to create {@link AttributeValue}s
*
* @return attribute bag
* @throws IllegalArgumentException
* if {@code attributeValueFactory == null } or {@code rawValues} has at least one element which is null:
* {@code rawValues != null && !rawValues.isEmpty() && rawValues.iterator().next() == null}
*/
private static <AV extends AttributeValue> AttributeBag<AV> newAttributeBag(final StringParseableValueFactory<AV> attributeValueFactory, final Collection<? extends Serializable> rawValues)
throws IllegalArgumentException
{
assert attributeValueFactory != null;
final Datatype<AV> elementDatatype = attributeValueFactory.getDatatype();
if (rawValues == null || rawValues.isEmpty())
{
return Bags.emptyAttributeBag(elementDatatype, null);
}
return Bags.newAttributeBag(elementDatatype, rawValues.stream().map(rawValue -> attributeValueFactory.getInstance(rawValue)).collect(Collectors.toList()));
}
private final Map<Class<? extends Serializable>, StringParseableValueFactory<?>> inputClassToAttValFactory;
private final Set<Entry<Class<? extends Serializable>, StringParseableValueFactory<?>>> nonFinalInputClassToAttValFactory;
/**
* <p>
* Constructor for BaseDatatypeFactoryRegistry.
* </p>
*
* @param attributeValueFactories
* attribute value factories
*/
public ImmutableAttributeValueFactoryRegistry(final Collection<? extends AttributeValueFactory<?>> attributeValueFactories)
{
super(AttributeValueFactory.class, HashCollections.newImmutableSet(Preconditions.checkNotNull(attributeValueFactories,
"Input attribute datatype factories undefined (attributeValueFactories == null)")));
final Map<Class<? extends Serializable>, StringParseableValueFactory<?>> mutableJavaClassToAttValFactory = HashCollections.newUpdatableMap();
attributeValueFactories.forEach(factory -> {
if (factory instanceof StringParseableValueFactory)
{
final StringParseableValueFactory<?> simpleValueFactory = (StringParseableValueFactory<?>) factory;
simpleValueFactory.getSupportedInputTypes().forEach(inputType -> mutableJavaClassToAttValFactory.putIfAbsent(inputType, simpleValueFactory));
}
});
inputClassToAttValFactory = HashCollections.newImmutableMap(mutableJavaClassToAttValFactory);
/*
* Using inputClassToAttValFactory.get(instanceClass) to get the corresponding factory is faster that doing many instanceOf checks but only works for equal match. For non-final classes, we
* still have to do the instanceOf check because the instance class might not be equal (i.e same class) but a subclass. So we gather the non-final classes for which instanceOf check is
* necessary iff no equal match.
*/
final Set<Entry<Class<? extends Serializable>, StringParseableValueFactory<?>>> mutableSet = inputClassToAttValFactory.entrySet().stream()
.filter(e -> !Modifier.isFinal(e.getKey().getModifiers())).collect(Collectors.toSet());// HashCollections.newUpdatableSet(JAVA_TYPE_TO_ATT_VALUE_FACTORY.size());
nonFinalInputClassToAttValFactory = ImmutableSet.copyOf(mutableSet);
}
/** {@inheritDoc} */
@Override
public ConstantExpression<? extends AttributeValue> newExpression(final String datatypeId, final List<Serializable> content, final Map<QName, String> otherAttributes,
......@@ -119,4 +183,55 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
return newExpression(datatypeFactory, content, otherAttributes, xPathCompiler);
}
private final StringParseableValueFactory<?> getCompatibleFactory(final Class<? extends Serializable> rawValueClass)
{
final StringParseableValueFactory<?> attValFactoryFromMap = inputClassToAttValFactory.get(rawValueClass);
if (attValFactoryFromMap == null)
{
/*
* This may look like the collection is fully filtered before findfirst() is called but it is not the case. "All intermediate operations e.g. filter(), map() etc are lazy and they are only
* executed when a terminal operation like findFirst() or forEach() is called.
*
* This also means, a lot of opportunity for optimization depending upon the size of the original list." (Quote from:
* http://javarevisited.blogspot.fr/2016/03/how-to-find-first-element-of-stream-in.html)
*/
final Optional<Entry<Class<? extends Serializable>, StringParseableValueFactory<?>>> optionalResult = nonFinalInputClassToAttValFactory.stream()
.filter(e -> e.getKey().isAssignableFrom(rawValueClass)).findFirst();
if (optionalResult.isPresent())
{
return optionalResult.get().getValue();
}
throw new UnsupportedOperationException("Unsupported input value type: '" + rawValueClass + "' (no suitable XACML datatype factory found)");
}
return attValFactoryFromMap;
}
@Override
public AttributeValue newAttributeValue(final Serializable rawValue) throws IllegalArgumentException, UnsupportedOperationException
{
Preconditions.checkArgument(rawValue != null, "Null arg");
final StringParseableValueFactory<?> factory = getCompatibleFactory(rawValue.getClass());
if (factory == null)
{
throw new UnsupportedOperationException("Unsupported input value type: '" + rawValue.getClass() + "' (no suitable XACML datatype factory found)");
}
return factory.getInstance(rawValue);
}
@Override
public AttributeBag<?> newAttributeBag(final Collection<? extends Serializable> rawVals) throws UnsupportedOperationException, IllegalArgumentException
{
Preconditions.checkArgument(rawVals != null && !rawVals.isEmpty(), "Null/empty arg");
final Serializable rawVal0 = rawVals.iterator().next();
final StringParseableValueFactory<?> factory = getCompatibleFactory(rawVal0.getClass());
if (factory == null)
{
throw new UnsupportedOperationException("Unsupported input value type: '" + rawVal0.getClass() + "' (no suitable XACML datatype factory found)");
}
return newAttributeBag(factory, rawVals);
}
}
......@@ -18,21 +18,21 @@
package org.ow2.authzforce.core.pdp.impl.value;
import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -45,13 +45,11 @@ import net.sf.saxon.s9api.XPathCompiler;
import org.ow2.authzforce.core.pdp.api.HashCollections;
import org.ow2.authzforce.core.pdp.api.PdpExtensionRegistry.PdpExtensionComparator;
import org.ow2.authzforce.core.pdp.api.XmlUtils;
import org.ow2.authzforce.core.pdp.api.value.AnyUriValue;
import org.ow2.authzforce.core.pdp.api.value.ArbitrarilyBigInteger;
import org.ow2.authzforce.core.pdp.api.value.AttributeBag;
import org.ow2.authzforce.core.pdp.api.value.AttributeValue;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactory;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactoryRegistry;
import org.ow2.authzforce.core.pdp.api.value.Bags;
import org.ow2.authzforce.core.pdp.api.value.Base64BinaryValue;
import org.ow2.authzforce.core.pdp.api.value.BooleanValue;
import org.ow2.authzforce.core.pdp.api.value.DateTimeValue;
......@@ -64,7 +62,6 @@ import org.ow2.authzforce.core.pdp.api.value.IntegerValue;
import org.ow2.authzforce.core.pdp.api.value.IpAddressValue;
import org.ow2.authzforce.core.pdp.api.value.Rfc822NameValue;
import org.ow2.authzforce.core.pdp.api.value.SimpleValue;
import org.ow2.authzforce.core.pdp.api.value.SimpleValue.StringParseableValueFactory;
import org.ow2.authzforce.core.pdp.api.value.StandardDatatypes;
import org.ow2.authzforce.core.pdp.api.value.StringValue;
import org.ow2.authzforce.core.pdp.api.value.TimeValue;
......@@ -74,8 +71,7 @@ import org.ow2.authzforce.core.pdp.api.value.YearMonthDurationValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableList;
/**
* XACML standard datatypes
......@@ -101,12 +97,20 @@ public final class StandardAttributeValueFactories
};
private static final Set<Class<? extends Serializable>> SUPPORTED_BOOLEAN_FACTORY_INPUT_TYPES = HashCollections.newImmutableSet(Arrays.asList(Boolean.class, String.class));
/**
* boolean
*/
public static final SimpleValue.StringParseableValueFactory<BooleanValue> BOOLEAN = new SimpleValue.StringParseableValueFactory<BooleanValue>(StandardDatatypes.BOOLEAN)
{
@Override
public Set<Class<? extends Serializable>> getSupportedInputTypes()
{
return SUPPORTED_BOOLEAN_FACTORY_INPUT_TYPES;
}
@Override
public BooleanValue parse(final String val)
{
......@@ -126,11 +130,14 @@ public final class StandardAttributeValueFactories
return parse((String) value);
}
throw new IllegalArgumentException("Invalid input type to Boolean AttributeValue factory: " + value.getClass().getName() + ". Expected one of: " + Boolean.class + "," + String.class);
throw newInvalidInputTypeException(value);
}
};
private static final Set<Class<? extends Serializable>> SUPPORTED_INTEGER_FACTORY_INPUT_TYPES = HashCollections.newImmutableSet(Arrays.asList(Short.class, Integer.class, Long.class,
BigInteger.class, String.class));
private static abstract class IntegerValueFactory extends SimpleValue.StringParseableValueFactory<IntegerValue>
{
......@@ -139,9 +146,13 @@ public final class StandardAttributeValueFactories
super(StandardDatatypes.INTEGER);
}
}
@Override
public Set<Class<? extends Serializable>> getSupportedInputTypes()
{
return SUPPORTED_INTEGER_FACTORY_INPUT_TYPES;
}
private static final String MEDIUM_INT_FACTORY_INPUT_TYPE_ERR_MSG_SUFFIX = ". Expected one of: " + Short.class + "," + Integer.class + "," + BigInteger.class + "," + String.class;
}
/**
* integer parsed into {@link Integer}, therefore supports medium-size integers (representing xsd:int)
......@@ -159,7 +170,7 @@ public final class StandardAttributeValueFactories
}
catch (final NumberFormatException e)
{
throw new IllegalArgumentException(this + ": input value not valid or too big: " + val);
throw new IllegalArgumentException(this + ": input value not valid or too big for Java int: " + val);
}
return IntegerValue.valueOf(i);
......@@ -178,6 +189,22 @@ public final class StandardAttributeValueFactories
return IntegerValue.valueOf(((Integer) value).intValue());
}
if (value instanceof Long)
{
final Long l = (Long) value;
final int i;
try
{
i = Math.toIntExact(l.longValue());
}
catch (final ArithmeticException e)
{
throw new IllegalArgumentException(this + ": input value not supported (too big for Java int): " + value);
}
return IntegerValue.valueOf(i);
}
if (value instanceof BigInteger)
{
final BigInteger bigInt = (BigInteger) value;
......@@ -188,7 +215,7 @@ public final class StandardAttributeValueFactories
}
catch (final ArithmeticException e)
{
throw new IllegalArgumentException(this + ": input value not supported (too big): " + bigInt);
throw new IllegalArgumentException(this + ": input value not supported (too big for Java int): " + value);
}
return IntegerValue.valueOf(i);
......@@ -199,13 +226,11 @@ public final class StandardAttributeValueFactories
return parse((String) value);
}
throw new IllegalArgumentException("Invalid input type to Integer AttributeValue factory: " + value.getClass().getName() + MEDIUM_INT_FACTORY_INPUT_TYPE_ERR_MSG_SUFFIX);
throw newInvalidInputTypeException(value);
}
};
private static final String LONG_INT_FACTORY_INPUT_TYPE_ERR_MSG_SUFFIX = ". Expected one of: " + Short.class + "," + Integer.class + "," + Long.class + "," + BigInteger.class + "," + String.class;
/**
* integer parsed into {@link Long}, therefore supports long integers (representing xsd:long)
*/
......@@ -222,7 +247,7 @@ public final class StandardAttributeValueFactories
}
catch (final NumberFormatException e)
{
throw new IllegalArgumentException(this + ": input value not valid or too big: " + val);
throw new IllegalArgumentException(this + ": input value not valid or too big for Java long: " + val);
}
return IntegerValue.valueOf(i);
......@@ -256,7 +281,7 @@ public final class StandardAttributeValueFactories
}
catch (final ArithmeticException e)
{
throw new IllegalArgumentException(this + ": input value not supported (too big): " + bigInt);
throw new IllegalArgumentException(this + ": input value not supported (too big for Java long): " + bigInt);
}
return IntegerValue.valueOf(i);
......@@ -267,7 +292,7 @@ public final class StandardAttributeValueFactories
return parse((String) value);
}
throw new IllegalArgumentException("Invalid input type to Integer AttributeValue factory: " + value.getClass().getName() + LONG_INT_FACTORY_INPUT_TYPE_ERR_MSG_SUFFIX);
throw newInvalidInputTypeException(value);
}
};
......@@ -339,17 +364,25 @@ public final class StandardAttributeValueFactories
return parse((String) value);
}
throw new IllegalArgumentException("Invalid input type to Integer AttributeValue factory: " + value.getClass().getName() + LONG_INT_FACTORY_INPUT_TYPE_ERR_MSG_SUFFIX);
throw newInvalidInputTypeException(value);
}
};
private static final Set<Class<? extends Serializable>> SUPPORTED_DOUBLE_FACTORY_INPUT_TYPES = HashCollections.newImmutableSet(Arrays.asList(Float.class, Double.class, String.class));
/**
* double
*/
public static final SimpleValue.StringParseableValueFactory<DoubleValue> DOUBLE = new SimpleValue.StringParseableValueFactory<DoubleValue>(StandardDatatypes.DOUBLE)
{
@Override
public Set<Class<? extends Serializable>> getSupportedInputTypes()
{
return SUPPORTED_DOUBLE_FACTORY_INPUT_TYPES;
}
@Override
public DoubleValue parse(final String val)
{
......@@ -374,85 +407,255 @@ public final class StandardAttributeValueFactories
return parse((String) value);
}
throw new IllegalArgumentException("Invalid input type to Double AttributeValue factory: " + value.getClass().getName() + ". Expected one of: " + Double.class + "," + String.class);
throw newInvalidInputTypeException(value);
}
};
private static TimeValue newUtcTimeValue(final int hours, final int minutes, final int seconds, final int nanoOfSec)
{
return TimeValue.getInstance(XmlUtils.XML_TEMPORAL_DATATYPE_FACTORY.newXMLGregorianCalendarTime(hours, minutes, seconds, BigDecimal.valueOf(nanoOfSec).movePointLeft(9), 0));
}
private static final Set<Class<? extends Serializable>> SUPPORTED_TIME_FACTORY_INPUT_TYPES = HashCollections.newImmutableSet(Arrays.asList(LocalTime.class, OffsetTime.class, String.class));
/**
* time
*/
public static final SimpleValue.StringContentOnlyFactory<TimeValue> TIME = new SimpleValue.StringContentOnlyFactory<TimeValue>(StandardDatatypes.TIME)
public static final SimpleValue.StringParseableValueFactory<TimeValue> TIME = new SimpleValue.StringParseableValueFactory<TimeValue>(StandardDatatypes.TIME)
{
@Override
public Set<Class<? extends Serializable>> getSupportedInputTypes()
{
return SUPPORTED_TIME_FACTORY_INPUT_TYPES;
}
@Override
public TimeValue parse(final String val)
{
return new TimeValue(val);
}
@Override
public TimeValue getInstance(final Serializable value) throws IllegalArgumentException
{
if (value instanceof LocalTime)
{
final LocalTime time = (LocalTime) value;
// We set time in UTC, so timezone offset is 0
return newUtcTimeValue(time.getHour(), time.getMinute(), time.getSecond(), time.getNano());
}
if (value instanceof OffsetTime)
{
final OffsetTime time = (OffsetTime) value;
// We set time in UTC, so timezone offset is 0
return newUtcTimeValue(time.getHour(), time.getMinute(), time.getSecond(), time.getNano());
}
if (value instanceof String)
{
return parse((String) value);
}
throw newInvalidInputTypeException(value);
}
};
private static final Set<Class<? extends Serializable>> SUPPORTED_DATE_FACTORY_INPUT_TYPES = HashCollections.newImmutableSet(Arrays.asList(LocalDate.class, String.class));
/**
* date
*/
public static final SimpleValue.StringContentOnlyFactory<DateValue> DATE = new SimpleValue.StringContentOnlyFactory<DateValue>(StandardDatatypes.DATE)
public static final SimpleValue.StringParseableValueFactory<DateValue> DATE = new SimpleValue.StringParseableValueFactory<DateValue>(StandardDatatypes.DATE)
{
@Override
public Set<Class<? extends Serializable>> getSupportedInputTypes()
{
return SUPPORTED_DATE_FACTORY_INPUT_TYPES;
}
@Override
public DateValue parse(final String val)
{
return new DateValue(val);
}
@Override
public DateValue getInstance(final Serializable value) throws IllegalArgumentException
{
if (value instanceof LocalDate)
{
final LocalDate date = (LocalDate) value;
// We set date in UTC, so timezone offset is 0
return DateValue.getInstance(XmlUtils.XML_TEMPORAL_DATATYPE_FACTORY.newXMLGregorianCalendarDate(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 0));
}
if (value instanceof String)
{
return parse((String) value);
}
throw newInvalidInputTypeException(value);
}
};
private static DateTimeValue newDateTimeValue(final int year, final int month, final int dayOfMonth, final int hours, final int minutes, final int seconds, final int nanoOfSec,
final int timezoneOffsetMinutes)
{
return new DateTimeValue(XmlUtils.XML_TEMPORAL_DATATYPE_FACTORY.newXMLGregorianCalendar(BigInteger.valueOf(year), month, dayOfMonth, hours, minutes, seconds, BigDecimal.valueOf(nanoOfSec)
.movePointLeft(9), timezoneOffsetMinutes));
}
private static final Set<Class<? extends Serializable>> SUPPORTED_DATETIME_FACTORY_INPUT_TYPES = HashCollections.newImmutableSet(Arrays.asList(LocalDateTime.class, OffsetDateTime.class,
ZonedDateTime.class, Instant.class, String.class));
/**
* dateTime
*/
public static final SimpleValue.StringContentOnlyFactory<DateTimeValue> DATETIME = new SimpleValue.StringContentOnlyFactory<DateTimeValue>(StandardDatatypes.DATETIME)
public static final SimpleValue.StringParseableValueFactory<DateTimeValue> DATETIME = new SimpleValue.StringParseableValueFactory<DateTimeValue>(StandardDatatypes.DATETIME)
{
@Override
public Set<Class<? extends Serializable>> getSupportedInputTypes()
{
return SUPPORTED_DATETIME_FACTORY_INPUT_TYPES;
}
@Override
public DateTimeValue parse(final String val)
{
return new DateTimeValue(val);
}
@Override
public DateTimeValue getInstance(final Serializable value) throws IllegalArgumentException
{
if (value instanceof LocalDateTime)
{
final LocalDateTime dateTime = (LocalDateTime) value;
// We set time in UTC, so timezone offset is 0
return newDateTimeValue(dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getNano(), 0);
}
if (value instanceof OffsetDateTime)
{
final OffsetDateTime dateTime = (OffsetDateTime) value;
return newDateTimeValue(dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getNano(),
dateTime.getOffset().getTotalSeconds() / 60);
}
if (value instanceof ZonedDateTime)
{
final ZonedDateTime dateTime = (ZonedDateTime) value;
return newDateTimeValue(dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getNano(),
dateTime.getOffset().getTotalSeconds() / 60);
}
if (value instanceof Instant)
{
final Instant instant = (Instant) value;
// We set time in UTC
final LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
return newDateTimeValue(dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getNano(), 0);
}
if (value instanceof String)
{
return parse((String) value);
}
throw newInvalidInputTypeException(value);
}
};
private static final Set<Class<? extends Serializable>> SUPPORTED_ANYURI_FACTORY_INPUT_TYPES = HashCollections.newImmutableSet(Arrays.asList(URI.class, String.class));
/**
* anyURI
*/
public static final SimpleValue.StringContentOnlyFactory<AnyUriValue> ANYURI = new SimpleValue.StringContentOnlyFactory<AnyUriValue>(StandardDatatypes.ANYURI)
public static final SimpleValue.StringParseableValueFactory<AnyUriValue> ANYURI = new SimpleValue.StringParseableValueFactory<AnyUriValue>(StandardDatatypes.ANYURI)
{
@Override
public Set<Class<? extends Serializable>> getSupportedInputTypes()
{
return SUPPORTED_ANYURI_FACTORY_INPUT_TYPES;
}
@Override
public AnyUriValue parse(final String val)
{
return new AnyUriValue(val);
}
@Override
public AnyUriValue getInstance(final Serializable value) throws IllegalArgumentException
{
if (value instanceof URI)
{
final URI uri = (URI) value;
return new AnyUriValue(uri.toString());
}
if (value instanceof String)
{
return parse((String) value);
}