blob: 655425de16a5182f2d7aae223fe713d026f0e63b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/package org.apache.rya.api.functions;
import java.time.Duration;
import java.time.Instant;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.datatypes.XMLDatatypeUtil;
import org.eclipse.rdf4j.model.vocabulary.FN;
import org.eclipse.rdf4j.model.vocabulary.XMLSchema;
import org.eclipse.rdf4j.query.algebra.evaluation.ValueExprEvaluationException;
import org.eclipse.rdf4j.query.algebra.evaluation.function.Function;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* This {@link Function} determines whether two {@link XMLSchema#DATETIME}s occur within a specified period of time of
* one another. The method {@link Function#evaluate(ValueFactory, Value...)} expects four values, where the first two
* values are the datetimes, the third value is an integer indicating the period, and the fourth value is a URI
* indicating the time unit of the period. The URI must be of Type DurationDescription in the OWL-Time ontology (see
* <a href ="https://www.w3.org/TR/owl-time/">https://www.w3.org/TR/owl-time/</a>). Examples of valid time unit URIs can
* be found in the class {@link OWLTime} and below
* <ul>
* <li>http://www.w3.org/2006/time#days</li>
* <li>http://www.w3.org/2006/time#hours</li>
* <li>http://www.w3.org/2006/time#minutes</li>
* <li>http://www.w3.org/2006/time#seconds</li>
* </ul>
*
*/
public class DateTimeWithinPeriod implements Function {
private static final String FUNCTION_URI = FN.NAMESPACE + "dateTimeWithin";
@Override
public String getURI() {
return FUNCTION_URI;
}
/**
* Determines whether two datetimes occur within a specified period of time of one another. This method expects four
* values, where the first two values are the datetimes, the third value is an integer indicating the period, and
* the fourth value is a URI indicating the time unit of the period. The URI must be of Type DurationDescription in
* the OWL-Time ontology (see <a href ="https://www.w3.org/TR/owl-time/">https://www.w3.org/TR/owl-time/</a>).
* Examples of valid time unit URIs can be found in the class {@link OWLTime} and below
* <ul>
* <li>http://www.w3.org/2006/time#days</li>
* <li>http://www.w3.org/2006/time#hours</li>
* <li>http://www.w3.org/2006/time#minutes</li>
* <li>http://www.w3.org/2006/time#seconds</li>
* </ul>
*
* @param valueFactory - factory for creating values (not null)
* @param values - array of Value arguments for this Function (not null).
*/
@Override
public Value evaluate(ValueFactory valueFactory, Value... values) throws ValueExprEvaluationException {
checkNotNull(valueFactory);
checkNotNull(values);
try {
// general validation of input
checkArgument(values.length == 4);
checkArgument(values[0] instanceof Literal);
checkArgument(values[1] instanceof Literal);
checkArgument(values[2] instanceof Literal);
checkArgument(values[3] instanceof IRI);
Instant dateTime1 = convertToInstant((Literal) values[0]);
Instant dateTime2 = convertToInstant((Literal) values[1]);
long periodMillis = convertPeriodToMillis((Literal) values[2], (IRI) values[3]);
long timeBetween = Math.abs(Duration.between(dateTime1, dateTime2).toMillis());
return valueFactory.createLiteral(timeBetween < periodMillis);
} catch (Exception e) {
throw new ValueExprEvaluationException(e);
}
}
private Instant convertToInstant(Literal literal) {
String stringVal = literal.getLabel();
IRI dataType = literal.getDatatype();
checkArgument(dataType.equals(XMLSchema.DATETIME) || dataType.equals(XMLSchema.DATE),
String.format("Invalid data type for date time. Data Type must be of type %s or %s .", XMLSchema.DATETIME, XMLSchema.DATE));
checkArgument(XMLDatatypeUtil.isValidDateTime(stringVal) || XMLDatatypeUtil.isValidDate(stringVal), "Invalid date time value.");
return literal.calendarValue().toGregorianCalendar().toInstant();
}
private long convertPeriodToMillis(Literal literal, IRI unit) {
String stringVal = literal.getLabel();
IRI dataType = literal.getDatatype();
checkArgument(dataType.equals(XMLSchema.INTEGER) || dataType.equals(XMLSchema.INT), String
.format("Invalid data type for period duration. Data Type must be of type %s or %s .", XMLSchema.INTEGER, XMLSchema.INT));
checkArgument(XMLDatatypeUtil.isValidInteger(stringVal) || XMLDatatypeUtil.isValidInt(stringVal), "Invalid duration value.");
return convertToMillis(Integer.parseInt(stringVal), unit);
}
/**
* Converts the period duration to milliseconds.
*
* @param duration - duration of temporal period
* @param unit - URI indicating the time unit (URI must be of type DurationDescription in the OWL-Time ontology
* indicated by the namespace <http://www.w3.org/2006/time#>)
* @return - duration in milliseconds
*/
private long convertToMillis(int duration, IRI unit) {
checkArgument(duration > 0);
return OWLTime.getMillis(duration, unit);
}
}