/*******************************************************************************
* Copyright (c) 2008 Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.openanzo.test.client;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.TimeZone;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang.time.DateUtils;
import org.openanzo.client.AnzoClient;
import org.openanzo.client.ClientGraph;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.AnzoRuntimeException;
import org.openanzo.glitter.query.QueryResults;
import org.openanzo.glitter.query.SolutionSet;
import org.openanzo.rdf.Constants;
import org.openanzo.rdf.Statement;
import org.openanzo.rdf.TypedLiteral;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.vocabulary.XMLSchema;
import org.openanzo.test.AbstractTest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Tests for date and time information used within the system via the AnzoClient API, SPARQL queries, etc.
*
* See http://www.openanzo.org/projects/openanzo/ticket/377
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
public class TestDateTime extends AbstractTest {
private static final Logger log = LoggerFactory.getLogger(TestDateTime.class);
private static final URI GRAPH_URI = createTestUri("graph1");
private int statementSuffix = 1;
/**
* The most basic of date/time handling tests. Here we make sure that we can add a date literal to the store and then retrieve it via find/contains and via
* a SPARQL query. The data must not have been changed in any way through this round-trip. This tests works by creating the literals with their raw lexical
* values. No special native Java type conversion is expected to be going on here.
*
* @throws Exception
*/
public void testLexicalDateTimeIsPreservedInServerRoundTrip() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
// xsd:dateTime
// UTC
addAndRetrieveLexicalLiteral(client, graph, "2008-07-11T16:48:32Z", XMLSchema.DATETIME);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "2008-07-12T16:48:32-04:00", XMLSchema.DATETIME);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "2008-07-13T16:48:32", XMLSchema.DATETIME);
// With fractional seconds
addAndRetrieveLexicalLiteral(client, graph, "2008-07-15T16:48:32.25", XMLSchema.DATETIME);
// With fractional seconds at the nanosecond precision
addAndRetrieveLexicalLiteral(client, graph, "2008-07-15T16:48:32.254221458", XMLSchema.DATETIME);
// With fractional seconds and time zone
addAndRetrieveLexicalLiteral(client, graph, "2008-07-16T16:48:32.25-05:00", XMLSchema.DATETIME);
// xsd:date
// UTC
addAndRetrieveLexicalLiteral(client, graph, "2008-07-11Z", XMLSchema.DATE);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "2008-07-12-04:00", XMLSchema.DATE);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "2008-07-13", XMLSchema.DATE);
// xsd:time
// UTC
addAndRetrieveLexicalLiteral(client, graph, "16:48:32Z", XMLSchema.TIME);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "17:48:32-04:00", XMLSchema.TIME);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "18:48:32", XMLSchema.TIME);
// With fractional seconds
addAndRetrieveLexicalLiteral(client, graph, "19:48:32.25", XMLSchema.TIME);
// With fractional seconds and time zone
addAndRetrieveLexicalLiteral(client, graph, "20:48:32.25-05:00", XMLSchema.TIME);
// xsd:gYearMonth
// UTC
addAndRetrieveLexicalLiteral(client, graph, "2008-06Z", XMLSchema.GYEARMONTH);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "2008-07-04:00", XMLSchema.GYEARMONTH);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "2008-08", XMLSchema.GYEARMONTH);
// xsd:gYear
// UTC
addAndRetrieveLexicalLiteral(client, graph, "2008", XMLSchema.GYEAR);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "2009-06:00", XMLSchema.GYEAR);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "2010", XMLSchema.GYEAR);
// xsd:gMonthDay
// UTC
addAndRetrieveLexicalLiteral(client, graph, "--07-14Z", XMLSchema.GMONTHDAY);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "--07-15-06:00", XMLSchema.GMONTHDAY);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "--07-16", XMLSchema.GMONTHDAY);
// xsd:gMonth
// UTC
addAndRetrieveLexicalLiteral(client, graph, "--07Z", XMLSchema.GMONTH);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "--08-06:00", XMLSchema.GMONTH);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "--09", XMLSchema.GMONTH);
// xsd:gDay
// UTC
addAndRetrieveLexicalLiteral(client, graph, "---14Z", XMLSchema.GDAY);
// With time zone offset
addAndRetrieveLexicalLiteral(client, graph, "---15-06:00", XMLSchema.GDAY);
// Without time zone
addAndRetrieveLexicalLiteral(client, graph, "---16", XMLSchema.GDAY);
// xsd:duration
addAndRetrieveLexicalLiteral(client, graph, "P1Y2M3DT10H30M13.136S", XMLSchema.DURATION);
addAndRetrieveLexicalLiteral(client, graph, "P1Y2MT2H", XMLSchema.DURATION);
// xsd:yearMonthDuration
addAndRetrieveLexicalLiteral(client, graph, "P28Y5M", XMLSchema.DURATION_YEARMONTH);
addAndRetrieveLexicalLiteral(client, graph, "P1347Y", XMLSchema.DURATION_YEARMONTH);
addAndRetrieveLexicalLiteral(client, graph, "P1347M", XMLSchema.DURATION_YEARMONTH);
// xsd:dayTimeDuration
addAndRetrieveLexicalLiteral(client, graph, "P3DT10H30M13.136S", XMLSchema.DURATION_DAYTIME);
addAndRetrieveLexicalLiteral(client, graph, "P32D", XMLSchema.DURATION_DAYTIME);
addAndRetrieveLexicalLiteral(client, graph, "PT47H", XMLSchema.DURATION_DAYTIME);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test that XMLGregorianCalendar objects of various flavors are converted into the appropriate lexical representation with the appropriate datatype.
*
* @throws Exception
*/
public void testXsdTimeRelatedTypeLiteralsBecomeXMLGregorianCalendar() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
DatatypeFactory df = DatatypeFactory.newInstance();
// xsd:dateTime
// Without time zone
XMLGregorianCalendar cal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 16, 48, 32, 357, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-11T16:48:32.357", XMLSchema.DATETIME, cal);
// Without time zone without fractional seconds
cal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 12, 16, 48, 32, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-12T16:48:32", XMLSchema.DATETIME, cal);
// With time zone
cal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 16, 48, 32, 357, 7 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-11T16:48:32.357+07:00", XMLSchema.DATETIME, cal);
// With time zone and nanosecond precision
cal = df.newXMLGregorianCalendar(BigInteger.valueOf(2008), DatatypeConstants.JULY, 11, 16, 48, 32, BigDecimal.valueOf(123665845, 9), -8 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-11T16:48:32.123665845-08:00", XMLSchema.DATETIME, cal);
// UTC
cal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 16, 48, 32, 357, 0);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-11T16:48:32.357Z", XMLSchema.DATETIME, cal);
// xsd:date
// Without time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.JULY, 12, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-12", XMLSchema.DATE, cal);
// With time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.JULY, 11, -8 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-11-08:00", XMLSchema.DATE, cal);
// xsd:time
// Without time zone
cal = df.newXMLGregorianCalendarTime(16, 48, 32, 357, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "16:48:32.357", XMLSchema.TIME, cal);
// With time zone
cal = df.newXMLGregorianCalendarTime(16, 48, 32, 357, 4 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "16:48:32.357+04:00", XMLSchema.TIME, cal);
// xsd:gYearMonth
// With time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.JULY, DatatypeConstants.FIELD_UNDEFINED, -4 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-04:00", XMLSchema.GYEARMONTH, cal);
// Without time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.AUGUST, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "2008-08", XMLSchema.GYEARMONTH, cal);
// xsd:gYear
// With time zone
cal = df.newXMLGregorianCalendarDate(2009, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, -6 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "2009-06:00", XMLSchema.GYEAR, cal);
// Without time zone
cal = df.newXMLGregorianCalendarDate(2010, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "2010", XMLSchema.GYEAR, cal);
// xsd:gMonthDay
// With time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.JULY, 15, -6 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "--07-15-06:00", XMLSchema.GMONTHDAY, cal);
// Without time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.JULY, 16, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "--07-16", XMLSchema.GMONTHDAY, cal);
// xsd:gMonth
// With time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.AUGUST, DatatypeConstants.FIELD_UNDEFINED, -6 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "--08-06:00", XMLSchema.GMONTH, cal);
// Without time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.SEPTEMBER, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "--09", XMLSchema.GMONTH, cal);
// xsd:gDay
// With time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, 15, -6 * 60);
retrieveLexicalLiteralAsNativeType(client, graph, "---15-06:00", XMLSchema.GDAY, cal);
// Without time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, 16, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "---16", XMLSchema.GDAY, cal);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test that Duration objects of various flavors are converted into the appropriate lexical representation with the appropriate datatype.
*
* @throws Exception
*/
public void testXsdDurationRelatedTypeLiteralsBecomeDuration() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
DatatypeFactory df = DatatypeFactory.newInstance();
// xsd:duration
Duration duration = df.newDuration(true, 28, 5, 16, 1, 15, 37);
retrieveLexicalLiteralAsNativeType(client, graph, "P28Y5M16DT1H15M37S", XMLSchema.DURATION, duration);
// xsd:yearMonthDuration
duration = df.newDuration(true, 28, 5, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
retrieveLexicalLiteralAsNativeType(client, graph, "P28Y5M", XMLSchema.DURATION_YEARMONTH, duration);
// xsd:dayTimeDuration
duration = df.newDuration(true, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, 16, 1, 15, 37);
retrieveLexicalLiteralAsNativeType(client, graph, "P16DT1H15M37S", XMLSchema.DURATION_DAYTIME, duration);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test the conversion of java.util.Calendar objects in the Anzo.java API into xsd:dateTime RDF literals with time zones. The test will add statements using
* java.util.Calendar objects and verify that when those statements are retrieved, the expected lexical value, datatype, etc. are correct.
*
* @throws Exception
*/
public void testCalendarBecomesXsdDateTime() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
DatatypeFactory df = DatatypeFactory.newInstance();
// UTC
Calendar cal = getCleanCalendar();
cal.set(2008, Calendar.JULY, 11, 16, 48, 32);
XMLGregorianCalendar xmlcal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 16, 48, 32, DatatypeConstants.FIELD_UNDEFINED, 0);
addAndRetrieveNativeLiteral(client, graph, cal, xmlcal, "2008-07-11T16:48:32Z", XMLSchema.DATETIME);
// Time zone offset
cal = getCleanCalendar();
cal.set(2008, Calendar.JULY, 11, 16, 48, 32);
cal.setTimeZone(TimeZone.getTimeZone("GMT-09:00"));
xmlcal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 16, 48, 32, DatatypeConstants.FIELD_UNDEFINED, -9 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, xmlcal, "2008-07-11T16:48:32-09:00", XMLSchema.DATETIME);
// Fractional seconds
cal = getCleanCalendar();
cal.set(2008, Calendar.JULY, 11, 16, 48, 32);
cal.set(Calendar.MILLISECOND, 357);
cal.setTimeZone(TimeZone.getTimeZone("GMT-03:00"));
xmlcal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 16, 48, 32, 357, -3 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, xmlcal, "2008-07-11T16:48:32.357-03:00", XMLSchema.DATETIME);
// A partially filled Calendar still ends up as a fully specified xsd:dateTime with the default values
// used for unspecified fields (i.e. 0 for time fields, January for month, 1 for day of month, etc.)
cal = getCleanCalendar();
cal.set(2008, Calendar.JULY, 11);
cal.setTimeZone(TimeZone.getTimeZone("GMT-03:00"));
xmlcal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 0, 0, 0, DatatypeConstants.FIELD_UNDEFINED, -3 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, xmlcal, "2008-07-11T00:00:00-03:00", XMLSchema.DATETIME);
// Another partially filled Calendar.
cal = getCleanCalendar();
cal.set(Calendar.YEAR, 2012);
xmlcal = df.newXMLGregorianCalendar(2012, DatatypeConstants.JANUARY, 1, 0, 0, 0, DatatypeConstants.FIELD_UNDEFINED, 0);
addAndRetrieveNativeLiteral(client, graph, cal, xmlcal, "2012-01-01T00:00:00Z", XMLSchema.DATETIME);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test the conversion of java.util.Date objects in the Anzo.java API into xsd:dateTime RDF literals in the UTC time zone. The test will add statements
* using java.util.Date objects and verify that when those statements are retrieved, the expected lexical value, datatype, etc. are correct.
*
* @throws Exception
*/
public void testJavaDateBecomesXsdDateTimeInUTCTimeZone() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
DatatypeFactory df = DatatypeFactory.newInstance();
Date d = new Date(1216330344703L); // Thu Jul 17 17:32:24.703 EDT 2008 which is Thu Jul 17 21:32:24.703 UTC 2008
XMLGregorianCalendar cal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 17, 21, 32, 24, 703, 0);
addAndRetrieveNativeLiteral(client, graph, d, cal, "2008-07-17T21:32:24.703Z", XMLSchema.DATETIME);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test the conversion of java.sql.Timestamp objects in the Anzo.java API into xsd:dateTime RDF literals in the UTC time zone. The test will add statements
* using java.util.Timestamp objects and verify that when those statements are retrieved, the expected lexical value, datatype, etc. are correct.
*
* We also make sure that the nanosecond precision of java.sql.Timestamp objects is maintained.
*
* @throws Exception
*/
public void testSqlTimestampBecomesXsdDateTimeInUTCTimeZone() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
DatatypeFactory df = DatatypeFactory.newInstance();
// Thu Jul 17 17:32:24.336512127 EDT 2008 which is Thu Jul 17 21:32:24.336512127 UTC 2008
Timestamp ts = new Timestamp(1216330344000L);
ts.setNanos(336512127);
XMLGregorianCalendar cal = df.newXMLGregorianCalendar(BigInteger.valueOf(2008), DatatypeConstants.JULY, 17, 21, 32, 24, BigDecimal.valueOf(336512127, 9), 0);
addAndRetrieveNativeLiteral(client, graph, ts, cal, "2008-07-17T21:32:24.336512127Z", XMLSchema.DATETIME);
// Thu Jul 17 17:32:24.000000001 EDT 2008 which is Thu Jul 17 21:32:24.000000001 UTC 2008
ts = new Timestamp(1216330344000L);
ts.setNanos(1); // If we don't account for some JDK bugs, then this can come out as 2008-07-17T21:32:24.1E-9Z
cal = df.newXMLGregorianCalendar(BigInteger.valueOf(2008), DatatypeConstants.JULY, 17, 21, 32, 24, BigDecimal.valueOf(1, 9), 0);
addAndRetrieveNativeLiteral(client, graph, ts, cal, "2008-07-17T21:32:24.000000001Z", XMLSchema.DATETIME);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test the conversion of javax.xml.datatype.XMLGregorianCalendar objects in the Anzo.java API into various XML Schema-types RDF literals. The test will add
* statements using javax.xml.datatype.XMLGregorianCalendar objects and verify that when those statements are retrieved, the expected lexical value,
* datatype, etc. are correct.
*
* @throws Exception
*/
public void testXMLGregorianCalendarBecomesXsdTypedLiterals() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
DatatypeFactory df = DatatypeFactory.newInstance();
// xsd:dateTime with time zone.
// With time zone, a literal with a time zone is represented as a java.util.Calendar when it is retrieved even if the input is an XMLGregorianCalendar.
XMLGregorianCalendar cal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 11, 16, 48, 32, 357, 9 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2008-07-11T16:48:32.357+09:00", XMLSchema.DATETIME);
// Without time zone
cal = df.newXMLGregorianCalendar(2008, DatatypeConstants.JULY, 12, 16, 48, 32, 357, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2008-07-12T16:48:32.357", XMLSchema.DATETIME);
// xsd:date
// Without time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.JULY, 12, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2008-07-12", XMLSchema.DATE);
// With time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.JULY, 11, -8 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2008-07-11-08:00", XMLSchema.DATE);
// xsd:time
// Without time zone
cal = df.newXMLGregorianCalendarTime(16, 48, 32, 357, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "16:48:32.357", XMLSchema.TIME);
// With time zone
cal = df.newXMLGregorianCalendarTime(16, 48, 32, 357, 4 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "16:48:32.357+04:00", XMLSchema.TIME);
// xsd:gYearMonth
// With time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.JULY, DatatypeConstants.FIELD_UNDEFINED, -4 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2008-07-04:00", XMLSchema.GYEARMONTH);
// Without time zone
cal = df.newXMLGregorianCalendarDate(2008, DatatypeConstants.AUGUST, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2008-08", XMLSchema.GYEARMONTH);
// xsd:gYear
// With time zone
cal = df.newXMLGregorianCalendarDate(2009, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, -6 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2009-06:00", XMLSchema.GYEAR);
// Without time zone
cal = df.newXMLGregorianCalendarDate(2010, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "2010", XMLSchema.GYEAR);
// xsd:gMonthDay
// With time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.JULY, 15, -6 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "--07-15-06:00", XMLSchema.GMONTHDAY);
// Without time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.JULY, 16, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "--07-16", XMLSchema.GMONTHDAY);
// xsd:gMonth
// With time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.AUGUST, DatatypeConstants.FIELD_UNDEFINED, -6 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "--08-06:00", XMLSchema.GMONTH);
// Without time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.SEPTEMBER, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "--09", XMLSchema.GMONTH);
// xsd:gDay
// With time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, 15, -6 * 60);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "---15-06:00", XMLSchema.GDAY);
// Without time zone
cal = df.newXMLGregorianCalendarDate(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, 16, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, cal, cal, "---16", XMLSchema.GDAY);
// Invalid XMLGregorianCalendar objects
// Incomplete data. No XML Schema built-in type allows just an hour. We expect an exception.
cal = df.newXMLGregorianCalendar();
cal.setHour(13);
try {
Constants.valueFactory.createTypedLiteral(cal);
fail("Should not get here since previous statement should throw exception.");
} catch (AnzoRuntimeException e) {
log.debug("Expected exception.");
}
// An XMLGregorianCalendar that has invalid data (February 31st) will go into the
// system but will not be able to be parsed back into an XMLGregorianCalendar on retrieval.
cal = df.newXMLGregorianCalendar();
cal.setDay(31);
cal.setMonth(DatatypeConstants.FEBRUARY);
addAndRetrieveNativeLiteral(client, graph, cal, null, "--02-31", XMLSchema.GMONTHDAY);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test the conversion of javax.xml.datatype.Duration objects in the Anzo.java API into various XML Schema-types RDF literals. The test will add statements
* using javax.xml.datatype.Duration objects and verify that when those statements are retrieved, the expected lexical value, datatype, etc. are correct.
*
* @throws Exception
*/
public void testDurationBecomesXsdTypedLiterals() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
DatatypeFactory df = DatatypeFactory.newInstance();
// xsd:duration
Duration duration = df.newDuration(true, 28, 5, 16, 1, 15, 37);
addAndRetrieveNativeLiteral(client, graph, duration, duration, "P28Y5M16DT1H15M37S", XMLSchema.DURATION);
// xsd:yearMonthDuration
duration = df.newDuration(true, 28, 5, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
addAndRetrieveNativeLiteral(client, graph, duration, duration, "P28Y5M", XMLSchema.DURATION_YEARMONTH);
// xsd:dayTimeDuration
duration = df.newDuration(true, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, 16, 1, 15, 37);
addAndRetrieveNativeLiteral(client, graph, duration, duration, "P16DT1H15M37S", XMLSchema.DURATION_DAYTIME);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Test various invalid lexical values for XML Schema date/time-related types. The system should allow you to enter those types but should throw exceptions
* for such literals' getNativeValue.
*
* @throws Exception
*/
public void testInvalidLexicalDateTimeLiteralsHaveNullNativeValue() throws Exception {
AnzoClient client = null;
try {
client = new AnzoClient(getDefaultClientConfiguration());
client.connect();
client.reset(loadStatements("initialize.trig"), null);
ClientGraph graph = client.getReplicaGraph(GRAPH_URI);
// xsd:dateTime
// Missing Seconds
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-11T16:48Z", XMLSchema.DATETIME, null);
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-11T16:48:12-17:00", XMLSchema.DATETIME, null);
// Single digit month
retrieveLexicalLiteralAsNativeType(client, graph, "2008-7-11T16:48:15", XMLSchema.DATETIME, null);
// xsd:date
// Missing day
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07", XMLSchema.DATE, null);
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-17:00", XMLSchema.DATE, null);
// Day of month too large
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-32", XMLSchema.DATE, null);
// xsd:time
// Missing Seconds
retrieveLexicalLiteralAsNativeType(client, graph, "16:48Z", XMLSchema.TIME, null);
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "16:48:12-17:00", XMLSchema.TIME, null);
// Hour too large
retrieveLexicalLiteralAsNativeType(client, graph, "25:48:15", XMLSchema.TIME, null);
// xsd:gYearMonth
// Single digit month
retrieveLexicalLiteralAsNativeType(client, graph, "2008-7", XMLSchema.GYEARMONTH, null);
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-17:00", XMLSchema.GYEARMONTH, null);
// Too much data
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-15", XMLSchema.GYEARMONTH, null);
// xsd:gYear
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "2008-17:00", XMLSchema.GYEAR, null);
// Too much data
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07", XMLSchema.GYEAR, null);
// xsd:gMonthDay
// Missing leading dashes
retrieveLexicalLiteralAsNativeType(client, graph, "07-13", XMLSchema.GMONTHDAY, null);
retrieveLexicalLiteralAsNativeType(client, graph, "-07-13", XMLSchema.GMONTHDAY, null);
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "--07-15-17:00", XMLSchema.GMONTHDAY, null);
// Too much data
retrieveLexicalLiteralAsNativeType(client, graph, "2008-07-15", XMLSchema.GMONTHDAY, null);
// xsd:gMonth
// Missing leading dashes
retrieveLexicalLiteralAsNativeType(client, graph, "07", XMLSchema.GMONTH, null);
retrieveLexicalLiteralAsNativeType(client, graph, "-07", XMLSchema.GMONTH, null);
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "--07-17:00", XMLSchema.GMONTH, null);
// Too much data
retrieveLexicalLiteralAsNativeType(client, graph, "--07-15", XMLSchema.GMONTH, null);
// xsd:gDay
// Missing leading dashes
retrieveLexicalLiteralAsNativeType(client, graph, "15", XMLSchema.GDAY, null);
retrieveLexicalLiteralAsNativeType(client, graph, "-16", XMLSchema.GDAY, null);
retrieveLexicalLiteralAsNativeType(client, graph, "--17", XMLSchema.GDAY, null);
// Time zone offset out of allowed range (-14 hours to +14 hours inclusive).
retrieveLexicalLiteralAsNativeType(client, graph, "---18-17:00", XMLSchema.GDAY, null);
// Day too large
retrieveLexicalLiteralAsNativeType(client, graph, "---32", XMLSchema.GDAY, null);
// xsd:duration
// Missing 'P'
retrieveLexicalLiteralAsNativeType(client, graph, "1Y2M3DT10H30M13.136S", XMLSchema.DURATION, null);
// Missing 'T'
retrieveLexicalLiteralAsNativeType(client, graph, "P1Y2M3D10H30M13.136S", XMLSchema.DURATION, null);
// xsd:yearMonthDuration
// Missing 'P'
retrieveLexicalLiteralAsNativeType(client, graph, "56Y34M", XMLSchema.DURATION_YEARMONTH, null);
// Too much data
retrieveLexicalLiteralAsNativeType(client, graph, "P56Y34M12D", XMLSchema.DURATION_YEARMONTH, null);
// xsd:dayTimeDuration
// Missing 'P'
retrieveLexicalLiteralAsNativeType(client, graph, "3DT10H30M13.136S", XMLSchema.DURATION_DAYTIME, null);
// Too much data
retrieveLexicalLiteralAsNativeType(client, graph, "P1Y2M3DT10H30M13.136S", XMLSchema.DURATION_DAYTIME, null);
} finally {
if (client != null) {
client.close();
}
}
}
/**
* Writes out a literal using the given lexical value and datatype. Then it retrieves the literal as a native object and compares it to the given expected
* native object instance.
*
* @param client
* @param graph
* @param lexicalLiteralString
* the lexical value of the literal to write to the server.
* @param literalDatatypeUri
* the datatype of the literal to write to the server.
* @param expectedNativeInstance
* the native object to which we'll compare the result of retrieving the literal and calling getNativeValue. We compare via .equals except for
* java.util.Calendar which we compare via the 'compareTo' method. If this is null, then we assert that the getNativeValue method throws an
* IllegalArgumentException.
* @throws AnzoException
*/
private void retrieveLexicalLiteralAsNativeType(AnzoClient client, ClientGraph graph, String lexicalLiteralString, URI literalDatatypeUri, Object expectedNativeInstance) throws AnzoException {
TypedLiteral lexicalLiteral = Constants.valueFactory.createLiteral(lexicalLiteralString, literalDatatypeUri);
Statement stmt = Constants.valueFactory.createStatement(createTestUri("subject" + statementSuffix), createTestUri("predicate" + statementSuffix), lexicalLiteral);
statementSuffix++;
graph.add(stmt);
client.updateRepository();
Iterator<Statement> iter = graph.find(stmt.getSubject(), stmt.getPredicate(), stmt.getObject()).iterator();
assertTrue(iter.hasNext());
TypedLiteral literal = (TypedLiteral) iter.next().getObject();
boolean exception = false;
Object nativeValue = null;
try {
nativeValue = literal.getNativeValue();
} catch (IllegalArgumentException iae) {
exception = true;
}
if (expectedNativeInstance == null) {
assertTrue(exception);
} else {
assertExpectedNativeValue(expectedNativeInstance, nativeValue);
}
iter = graph.find(stmt.getSubject(), stmt.getPredicate(), null).iterator();
assertTrue(iter.hasNext());
literal = (TypedLiteral) iter.next().getObject();
nativeValue = null;
exception = false;
try {
nativeValue = literal.getNativeValue();
} catch (IllegalArgumentException iae) {
exception = true;
}
if (expectedNativeInstance == null) {
assertTrue(exception);
} else {
assertExpectedNativeValue(expectedNativeInstance, nativeValue);
}
iter = client.serverFind(stmt.getSubject(), stmt.getPredicate(), null, graph.getNamedGraphUri()).iterator();
assertTrue(iter.hasNext());
literal = (TypedLiteral) iter.next().getObject();
nativeValue = null;
exception = false;
try {
nativeValue = literal.getNativeValue();
} catch (IllegalArgumentException iae) {
exception = true;
}
if (expectedNativeInstance == null) {
assertTrue(exception);
} else {
assertExpectedNativeValue(expectedNativeInstance, nativeValue);
}
String selectQuery = "SELECT ?x WHERE { <" + stmt.getSubject() + "> <" + stmt.getPredicate() + "> ?x }";
QueryResults queryResults = client.serverQuery(Collections.singleton(GRAPH_URI), Collections.<URI> emptySet(), Collections.<URI> emptySet(), selectQuery);
SolutionSet solutions = queryResults.getSelectResults();
assertTrue(solutions.size() == 1);
literal = (TypedLiteral) solutions.get(0).getBinding("x");
assertExpectedNativeValue(expectedNativeInstance, nativeValue);
}
/**
* The java.util.Calendar API makes it tricky to get a calendar initialized in a predictable state since most ways to create it use the system default time
* zone, locale, and sometimes the current time.
*
* This method helps ensure getting a calendar object that is more predictable across different systems.
*
* @return a new fairly clean Calendar, ready for you to put your dirty paws all over it.
*/
private Calendar getCleanCalendar() {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(DateUtils.UTC_TIME_ZONE);
cal.clear();
cal.setLenient(false);
return cal;
}
/**
* Adds a statement with the object being a typed literal with the given lexical value and datatype URIs. Then the contains, find, and serverQuery methods
* are called to make sure the literal can be retrieved properly.
*/
private void addAndRetrieveLexicalLiteral(AnzoClient client, ClientGraph graph, String lexicalLiteralString, URI literalDatatypeUri) throws AnzoException {
TypedLiteral lexicalLiteral = Constants.valueFactory.createLiteral(lexicalLiteralString, literalDatatypeUri);
Statement stmt = Constants.valueFactory.createStatement(createTestUri("subject" + statementSuffix), createTestUri("predicate" + statementSuffix), lexicalLiteral);
statementSuffix++;
graph.add(stmt);
assertTrue(graph.contains(stmt));
client.updateRepository();
assertTrue(graph.contains(stmt));
Iterator<Statement> iter = graph.find(stmt.getSubject(), stmt.getPredicate(), Constants.valueFactory.createLiteral(lexicalLiteralString, literalDatatypeUri)).iterator();
assertTrue(iter.hasNext());
TypedLiteral literal = (TypedLiteral) iter.next().getObject();
assertEquals(lexicalLiteralString, literal.getLabel());
assertEquals(literalDatatypeUri, literal.getDatatypeURI());
iter = client.serverFind(stmt.getSubject(), stmt.getPredicate(), stmt.getObject(), graph.getNamedGraphUri()).iterator();
assertTrue(iter.hasNext());
literal = (TypedLiteral) iter.next().getObject();
assertEquals(lexicalLiteralString, literal.getLabel());
assertEquals(literalDatatypeUri, literal.getDatatypeURI());
String askQuery = "ASK { <" + stmt.getSubject() + "> <" + stmt.getPredicate() + "> " + "'" + lexicalLiteralString + "'^^<" + literalDatatypeUri + "> }";
QueryResults queryResults = client.serverQuery(Collections.singleton(GRAPH_URI), Collections.<URI> emptySet(), Collections.<URI> emptySet(), askQuery);
assertTrue(queryResults.getAskResults());
String selectQuery = "SELECT ?x WHERE { <" + stmt.getSubject() + "> <" + stmt.getPredicate() + "> ?x }";
queryResults = client.serverQuery(Collections.singleton(GRAPH_URI), Collections.<URI> emptySet(), Collections.<URI> emptySet(), selectQuery);
SolutionSet solutions = queryResults.getSelectResults();
assertTrue(solutions.size() == 1);
assertTrue(solutions.get(0).getBinding("x").equals(lexicalLiteral));
}
/**
* Add and retrieves a literal created from the given native Java object and asserts that the expected values are maintained during the entire round trip,
* including via SPARQL queries.
*
* @param client
* @param graph
* @param obj
* The native Object to use in creating the literal
* @param expectedObj
* The native Object expected in the literal retrieved from the server. Equality is asserted via
* {@link #assertExpectedNativeValue(Object, Object)}.
* @param expectedLexicalDateTime
* The expected lexical value of the literal created from the given Calendar
* @param expectedDatatype
* The expected datatype URI of the literal created from the given Calendar
* @throws AnzoException
*/
private void addAndRetrieveNativeLiteral(AnzoClient client, ClientGraph graph, Object obj, Object expectedObj, String expectedLexicalDateTime, URI expectedDatatype) throws AnzoException {
TypedLiteral derivedLiteral = Constants.valueFactory.createTypedLiteral(obj);
TypedLiteral rawLiteral = Constants.valueFactory.createLiteral(expectedLexicalDateTime, expectedDatatype);
assertTrue(rawLiteral.equals(derivedLiteral));
Statement derivedStatement = Constants.valueFactory.createStatement(createTestUri("subject" + statementSuffix), createTestUri("predicate" + statementSuffix), derivedLiteral);
Statement rawStatement = Constants.valueFactory.createStatement(derivedStatement.getSubject(), derivedStatement.getPredicate(), rawLiteral);
statementSuffix++;
graph.add(derivedStatement);
assertTrue(graph.contains(derivedStatement));
assertTrue(graph.contains(rawStatement));
client.updateRepository();
assertTrue(graph.contains(derivedStatement));
assertTrue(graph.contains(rawStatement));
Iterator<Statement> iter = graph.find(rawStatement.getSubject(), rawStatement.getPredicate(), rawStatement.getObject()).iterator();
assertTrue(iter.hasNext());
TypedLiteral literal = (TypedLiteral) iter.next().getObject();
assertLiteral(literal, expectedObj, expectedLexicalDateTime, expectedDatatype, derivedLiteral, rawLiteral);
iter = graph.find(derivedStatement.getSubject(), derivedStatement.getPredicate(), derivedStatement.getObject()).iterator();
assertTrue(iter.hasNext());
literal = (TypedLiteral) iter.next().getObject();
assertLiteral(literal, expectedObj, expectedLexicalDateTime, expectedDatatype, derivedLiteral, rawLiteral);
iter = graph.find(rawStatement.getSubject(), rawStatement.getPredicate(), null).iterator();
assertTrue(iter.hasNext());
literal = (TypedLiteral) iter.next().getObject();
assertLiteral(literal, expectedObj, expectedLexicalDateTime, expectedDatatype, derivedLiteral, rawLiteral);
iter = client.serverFind(derivedStatement.getSubject(), derivedStatement.getPredicate(), derivedStatement.getObject(), graph.getNamedGraphUri()).iterator();
assertTrue(iter.hasNext());
literal = (TypedLiteral) iter.next().getObject();
assertLiteral(literal, expectedObj, expectedLexicalDateTime, expectedDatatype, derivedLiteral, rawLiteral);
String askQuery = "ASK { <" + derivedStatement.getSubject() + "> <" + derivedStatement.getPredicate() + "> " + "'" + expectedLexicalDateTime + "'^^<" + expectedDatatype + "> }";
QueryResults queryResults = client.serverQuery(Collections.singleton(GRAPH_URI), Collections.<URI> emptySet(), Collections.<URI> emptySet(), askQuery);
assertTrue(queryResults.getAskResults());
String selectQuery = "SELECT ?x WHERE { <" + derivedStatement.getSubject() + "> <" + derivedStatement.getPredicate() + "> ?x }";
queryResults = client.serverQuery(Collections.singleton(GRAPH_URI), Collections.<URI> emptySet(), Collections.<URI> emptySet(), selectQuery);
SolutionSet solutions = queryResults.getSelectResults();
assertTrue(solutions.size() == 1);
literal = (TypedLiteral) solutions.get(0).getBinding("x");
assertLiteral(literal, expectedObj, expectedLexicalDateTime, expectedDatatype, derivedLiteral, rawLiteral);
}
/**
* Assert that the given literal has the expected values as given.
*
* @param literal
* Literal being tested.
* @param obj
* Object to compare with the result of literal.getNativeValue(). Equality is asserted via {@link #assertExpectedNativeValue(Object, Object)} .
* @param expectedLexicalDateTime
* The expected value of literal.getLabel()
* @param expectedDatatype
* The expected value of literal.getDatatype()
* @param derivedLiteral
* literal should be equals to this via .equals
* @param rawLiteral
* literal should be equals to this via .equals
*/
private static void assertLiteral(TypedLiteral literal, Object obj, String expectedLexicalDateTime, URI expectedDatatype, TypedLiteral derivedLiteral, TypedLiteral rawLiteral) {
assertTrue(literal.equals(derivedLiteral));
assertTrue(literal.equals(rawLiteral));
assertEquals(expectedLexicalDateTime, literal.getLabel());
assertEquals(expectedDatatype, literal.getDatatypeURI());
if (obj == null) {
boolean exception = false;
try {
literal.getNativeValue();
} catch (IllegalArgumentException iae) {
exception = true;
}
assertTrue(exception);
} else {
assertExpectedNativeValue(obj, literal.getNativeValue());
}
}
/**
* Assert that the two objects are equal, or both null. java.util.Calendar is handled specially and compared via the compareTo method rather than equals.
*
* @param expectedNativeInstance
* @param nativeValue
*/
private static void assertExpectedNativeValue(Object expectedNativeInstance, Object nativeValue) {
if (expectedNativeInstance == null) {
assertNull(nativeValue);
} else if (expectedNativeInstance instanceof Calendar) {
assertTrue(((Calendar) expectedNativeInstance).compareTo((Calendar) nativeValue) == 0);
} else {
assertTrue(expectedNativeInstance.equals(nativeValue));
}
}
}