org.openanzo.test.client.TestDateTime.java Source code

Java tutorial

Introduction

Here is the source code for org.openanzo.test.client.TestDateTime.java

Source

/*******************************************************************************
 * 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));
        }
    }

}