com.marklogic.client.functionaltest.TestBiTemporal.java Source code

Java tutorial

Introduction

Here is the source code for com.marklogic.client.functionaltest.TestBiTemporal.java

Source

/*
 * Copyright 2014-2015 MarkLogic Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.marklogic.client.functionaltest;

import static org.junit.Assert.*;

import java.io.File;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import javax.xml.bind.DatatypeConverter;
import javax.xml.parsers.DocumentBuilderFactory;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.ls.DOMImplementationLS;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.marklogic.client.DatabaseClient;
import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.client.DatabaseClientFactory.Authentication;
import com.marklogic.client.Transaction;
import com.marklogic.client.admin.ExtensionMetadata;
import com.marklogic.client.admin.TransformExtensionsManager;
import com.marklogic.client.document.DocumentDescriptor;
import com.marklogic.client.document.DocumentPage;
import com.marklogic.client.document.DocumentRecord;
import com.marklogic.client.document.DocumentUriTemplate;
import com.marklogic.client.document.DocumentWriteSet;
import com.marklogic.client.document.JSONDocumentManager;
import com.marklogic.client.document.ServerTransform;
import com.marklogic.client.document.XMLDocumentManager;
import com.marklogic.client.document.DocumentManager.Metadata;
import com.marklogic.client.io.DOMHandle;
import com.marklogic.client.io.DocumentMetadataHandle;
import com.marklogic.client.io.FileHandle;
import com.marklogic.client.io.JacksonDatabindHandle;
import com.marklogic.client.io.DocumentMetadataHandle.Capability;
import com.marklogic.client.io.DocumentMetadataHandle.DocumentPermissions;
import com.marklogic.client.io.DocumentMetadataHandle.DocumentProperties;
import com.marklogic.client.io.Format;
import com.marklogic.client.io.JacksonHandle;
import com.marklogic.client.query.QueryManager;
import com.marklogic.client.query.StringQueryDefinition;
import com.marklogic.client.query.StructuredQueryBuilder;
import com.marklogic.client.query.StructuredQueryDefinition;
import com.marklogic.client.query.StructuredQueryBuilder.TemporalOperator;

public class TestBiTemporal extends BasicJavaClientREST {

    private static String dbName = "TestBiTemporalJava";
    private static String[] fNames = { "TestBiTemporalJava-1" };
    private static String restServerName = "REST-Java-Client-API-Server";
    private static int restPort = 8011;
    private static int uberPort = 8000;
    private DatabaseClient adminClient = null;
    private DatabaseClient writerClient = null;
    private DatabaseClient readerClient = null;
    private DatabaseClient evalClient = null;

    private final static String dateTimeDataTypeString = "dateTime";

    private final static String systemStartERIName = "javaSystemStartERI";
    private final static String systemEndERIName = "javaSystemEndERI";
    private final static String validStartERIName = "javaValidStartERI";
    private final static String validEndERIName = "javaValidEndERI";

    private final static String axisSystemName = "javaERISystemAxis";
    private final static String axisValidName = "javaERIValidAxis";

    private final static String temporalCollectionName = "javaERITemporalCollection";
    private final static String bulktemporalCollectionName = "bulkjavaERITemporalCollection";
    private final static String temporalLsqtCollectionName = "javaERILsqtTemporalCollection";

    private final static String systemNodeName = "System";
    private final static String validNodeName = "Valid";
    private final static String addressNodeName = "Address";
    private final static String uriNodeName = "uri";

    private final static String latestCollectionName = "latest";
    private final static String updateCollectionName = "updateCollection";
    private final static String insertCollectionName = "insertCollection";

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        System.out.println("In setup");
        setupJavaRESTServer(dbName, fNames[0], restServerName, restPort);

        ConnectedRESTQA.addRangeElementIndex(dbName, dateTimeDataTypeString, "", systemStartERIName);
        ConnectedRESTQA.addRangeElementIndex(dbName, dateTimeDataTypeString, "", systemEndERIName);
        ConnectedRESTQA.addRangeElementIndex(dbName, dateTimeDataTypeString, "", validStartERIName);
        ConnectedRESTQA.addRangeElementIndex(dbName, dateTimeDataTypeString, "", validEndERIName);

        // Temporal axis must be created before temporal collection associated with
        // those axes is created
        ConnectedRESTQA.addElementRangeIndexTemporalAxis(dbName, axisSystemName, "", systemStartERIName, "",
                systemEndERIName);
        ConnectedRESTQA.addElementRangeIndexTemporalAxis(dbName, axisValidName, "", validStartERIName, "",
                validEndERIName);
        ConnectedRESTQA.addElementRangeIndexTemporalCollection(dbName, temporalCollectionName, axisSystemName,
                axisValidName);
        ConnectedRESTQA.addElementRangeIndexTemporalCollection(dbName, bulktemporalCollectionName, axisSystemName,
                axisValidName);
        ConnectedRESTQA.addElementRangeIndexTemporalCollection(dbName, temporalLsqtCollectionName, axisSystemName,
                axisValidName);
        ConnectedRESTQA.updateTemporalCollectionForLSQT(dbName, temporalLsqtCollectionName, true);
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        System.out.println("In tear down");

        // Delete database first. Otherwise axis and collection cannot be deleted
        tearDownJavaRESTServer(dbName, fNames, restServerName);
        deleteRESTUser("eval-user");
        deleteUserRole("test-eval");

        // Temporal collection needs to be delete before temporal axis associated
        // with it can be deleted
        ConnectedRESTQA.deleteElementRangeIndexTemporalCollection("Documents", temporalLsqtCollectionName);
        ConnectedRESTQA.deleteElementRangeIndexTemporalCollection("Documents", temporalCollectionName);
        ConnectedRESTQA.deleteElementRangeIndexTemporalCollection("Documents", bulktemporalCollectionName);
        ConnectedRESTQA.deleteElementRangeIndexTemporalAxis("Documents", axisValidName);
        ConnectedRESTQA.deleteElementRangeIndexTemporalAxis("Documents", axisSystemName);

    }

    @Before
    public void setUp() throws Exception {
        createUserRolesWithPrevilages("test-eval", "xdbc:eval", "xdbc:eval-in", "xdmp:eval-in", "any-uri",
                "xdbc:invoke");
        createRESTUser("eval-user", "x", "test-eval", "rest-admin", "rest-writer", "rest-reader");
        adminClient = DatabaseClientFactory.newClient("localhost", restPort, dbName, "rest-admin", "x",
                Authentication.DIGEST);
        writerClient = DatabaseClientFactory.newClient("localhost", restPort, dbName, "rest-writer", "x",
                Authentication.DIGEST);
        readerClient = DatabaseClientFactory.newClient("localhost", restPort, dbName, "rest-reader", "x",
                Authentication.DIGEST);
        evalClient = DatabaseClientFactory.newClient("localhost", uberPort, dbName, "eval-user", "x",
                Authentication.DIGEST);
    }

    @After
    public void tearDown() throws Exception {
        clearDB(restPort);
        adminClient.release();
    }

    public DocumentMetadataHandle setMetadata(boolean update) {
        // create and initialize a handle on the meta-data
        DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();

        if (update) {
            metadataHandle.getCollections().addAll("updateCollection");
            metadataHandle.getProperties().put("published", true);

            metadataHandle.getPermissions().add("app-user", Capability.UPDATE, Capability.READ);

            metadataHandle.setQuality(99);
        } else {
            metadataHandle.getCollections().addAll("insertCollection");
            metadataHandle.getProperties().put("reviewed", true);

            metadataHandle.getPermissions().add("app-user", Capability.UPDATE, Capability.READ, Capability.EXECUTE);

            metadataHandle.setQuality(11);
        }

        metadataHandle.getProperties().put("myString", "foo");
        metadataHandle.getProperties().put("myInteger", 10);
        metadataHandle.getProperties().put("myDecimal", 34.56678);
        metadataHandle.getProperties().put("myCalendar", Calendar.getInstance().get(Calendar.YEAR));

        return metadataHandle;
    }

    public void validateMetadata(DocumentMetadataHandle mh) {
        // get metadata values
        DocumentProperties properties = mh.getProperties();
        DocumentPermissions permissions = mh.getPermissions();

        // Properties
        // String expectedProperties =
        // "size:5|reviewed:true|myInteger:10|myDecimal:34.56678|myCalendar:2014|myString:foo|";
        String actualProperties = getDocumentPropertiesString(properties);
        boolean result = actualProperties.contains("size:5|");
        assertTrue("Document properties count", result);

        // Permissions
        String actualPermissions = getDocumentPermissionsString(permissions);
        System.out.println(actualPermissions);
    }

    private void validateLSQTQueryData(DatabaseClient client) throws Exception {
        // Fetch documents associated with a search term (such as XML) in Address
        // element
        QueryManager queryMgr = client.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();

        Calendar queryTime = DatatypeConverter.parseDateTime("2007-01-01T00:00:01");
        StructuredQueryDefinition periodQuery = sqb.temporalLsqtQuery(temporalLsqtCollectionName, queryTime, 0,
                new String[] {});

        long start = 1;
        JSONDocumentManager docMgr = client.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL); // Get all metadata
        DocumentPage termQueryResults = docMgr.search(periodQuery, start);

        long count = 0;
        while (termQueryResults.hasNext()) {
            ++count;
            DocumentRecord record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
            record.getMetadata(metadataHandle);
            Iterator<String> resCollections = metadataHandle.getCollections().iterator();
            while (resCollections.hasNext()) {
                System.out.println("Collection = " + resCollections.next());
            }

            if (record.getFormat() == Format.XML) {
                DOMHandle recordHandle = new DOMHandle();
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());
            } else {
                JacksonDatabindHandle<ObjectNode> recordHandle = new JacksonDatabindHandle<ObjectNode>(
                        ObjectNode.class);
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());

                JsonFactory factory = new JsonFactory();
                ObjectMapper mapper = new ObjectMapper(factory);
                TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
                };

                HashMap<String, Object> docObject = mapper.readValue(recordHandle.toString(), typeRef);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> systemNode = (HashMap<String, Object>) (docObject.get(systemNodeName));

                String systemStartDate = (String) systemNode.get(systemStartERIName);
                String systemEndDate = (String) systemNode.get(systemEndERIName);
                System.out.println("systemStartDate = " + systemStartDate);
                System.out.println("systemEndDate = " + systemEndDate);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> validNode = (HashMap<String, Object>) (docObject.get(validNodeName));

                String validStartDate = (String) validNode.get(validStartERIName);
                String validEndDate = (String) validNode.get(validEndERIName);
                System.out.println("validStartDate = " + validStartDate);
                System.out.println("validEndDate = " + validEndDate);

                assertTrue("Valid start date check failed",
                        (validStartDate.equals("2001-01-01T00:00:00") && validEndDate.equals("2011-12-31T23:59:59")
                                && systemStartDate.equals("2005-01-01T00:00:01-08:00")
                                && systemEndDate.equals("2010-01-01T00:00:01-08:00")));
            }
        }

        System.out.println("Number of results using SQB = " + count);
        assertEquals("Wrong number of results", 1, count);
    }

    // This covers passing transforms and descriptor
    private void insertXMLSingleDocument(String temporalCollection, String docId, String transformName)
            throws Exception {
        System.out.println("Inside insertXMLSingleDocument");

        DOMHandle handle = getXMLDocumentHandle("2001-01-01T00:00:00", "2011-12-31T23:59:59",
                "999 Skyway Park - XML", docId);

        XMLDocumentManager docMgr = writerClient.newXMLDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentDescriptor desc = docMgr.newDescriptor(docId);
        DocumentMetadataHandle mh = setMetadata(false);

        if (transformName != null) {
            TransformExtensionsManager transMgr = adminClient.newServerConfigManager()
                    .newTransformExtensionsManager();
            ExtensionMetadata metadata = new ExtensionMetadata();
            metadata.setTitle("Adding Element xquery Transform");
            metadata.setDescription("This plugin transforms an XML document by adding Element to root node");
            metadata.setProvider("MarkLogic");
            metadata.setVersion("0.1");
            // get the transform file
            File transformFile = new File(
                    "src/test/java/com/marklogic/client/functionaltest/transforms/" + transformName + ".xqy");
            FileHandle transformHandle = new FileHandle(transformFile);
            transMgr.writeXQueryTransform(transformName, transformHandle, metadata);
            ServerTransform transformer = new ServerTransform(transformName);
            transformer.put("name", "Lang");
            transformer.put("value", "English");

            docMgr.write(desc, mh, handle, transformer, null, temporalCollection);
        } else {
            docMgr.write(desc, mh, handle, null, null, temporalCollection);
        }
    }

    // This covers passing transforms and descriptor
    private void updateXMLSingleDocument(String temporalCollection, String docId, String transformName)
            throws Exception {
        System.out.println("Inside updateXMLSingleDocument");

        // Update the document
        DOMHandle handle = getXMLDocumentHandle("2003-01-01T00:00:00", "2008-12-31T23:59:59",
                "1999 Skyway Park - Updated - XML", docId);

        XMLDocumentManager docMgr = writerClient.newXMLDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        DocumentDescriptor desc = docMgr.newDescriptor(docId);
        DocumentMetadataHandle mh = setMetadata(true);
        if (transformName != null) {
            TransformExtensionsManager transMgr = adminClient.newServerConfigManager()
                    .newTransformExtensionsManager();
            ExtensionMetadata metadata = new ExtensionMetadata();
            metadata.setTitle("Adding Element xquery Transform");
            metadata.setDescription("This plugin transforms an XML document by adding Element to root node");
            metadata.setProvider("MarkLogic");
            metadata.setVersion("0.1");
            // get the transform file
            File transformFile = new File(
                    "src/test/java/com/marklogic/client/functionaltest/transforms/" + transformName + ".xqy");
            FileHandle transformHandle = new FileHandle(transformFile);
            transMgr.writeXQueryTransform(transformName, transformHandle, metadata);
            ServerTransform transformer = new ServerTransform(transformName);
            transformer.put("name", "Lang");
            transformer.put("value", "English");

            docMgr.write(desc, mh, handle, transformer, null, temporalCollection);
        } else {
            docMgr.write(desc, mh, handle, null, null, temporalCollection);
        }

    }

    // This covers passing descriptor
    public void deleteXMLSingleDocument(String temporalCollection, String docId) throws Exception {

        System.out.println("Inside deleteXMLSingleDocument");

        XMLDocumentManager docMgr = writerClient.newXMLDocumentManager();

        DocumentDescriptor desc = docMgr.newDescriptor(docId);
        docMgr.delete(desc, null, temporalCollection, null);
    }

    private DOMHandle getXMLDocumentHandle(String startValidTime, String endValidTime, String address, String uri)
            throws Exception {

        Document domDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        Element root = domDocument.createElement("root");

        // System start and End time
        Node systemNode = root.appendChild(domDocument.createElement("system"));
        systemNode.appendChild(domDocument.createElement(systemStartERIName));
        systemNode.appendChild(domDocument.createElement(systemEndERIName));

        // Valid start and End time
        Node validNode = root.appendChild(domDocument.createElement("valid"));

        Node validStartNode = validNode.appendChild(domDocument.createElement(validStartERIName));
        validStartNode.appendChild(domDocument.createTextNode(startValidTime));
        validNode.appendChild(validStartNode);

        Node validEndNode = validNode.appendChild(domDocument.createElement(validEndERIName));
        validEndNode.appendChild(domDocument.createTextNode(endValidTime));
        validNode.appendChild(validEndNode);

        // Address
        Node addressNode = root.appendChild(domDocument.createElement("Address"));
        addressNode.appendChild(domDocument.createTextNode(address));

        // uri
        Node uriNode = root.appendChild(domDocument.createElement("uri"));
        uriNode.appendChild(domDocument.createTextNode(uri));
        domDocument.appendChild(root);

        String domString = ((DOMImplementationLS) DocumentBuilderFactory.newInstance().newDocumentBuilder()
                .getDOMImplementation()).createLSSerializer().writeToString(domDocument);

        System.out.println(domString);

        DOMHandle handle = new DOMHandle().with(domDocument);

        return handle;
    }

    public void insertJSONSingleDocument(String temporalCollection, String docId, Transaction transaction,
            java.util.Calendar systemTime) throws Exception {

        insertJSONSingleDocument(temporalCollection, docId, null, transaction, systemTime);
    }

    public void insertJSONSingleDocument(String temporalCollection, String docId, String transformName)
            throws Exception {

        insertJSONSingleDocument(temporalCollection, docId, transformName, null, null);
    }

    public void insertJSONSingleDocument(String temporalCollection, String docId, String transformName,
            Transaction transaction, java.util.Calendar systemTime) throws Exception {

        System.out.println("Inside insertJSONSingleDocument");

        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2001-01-01T00:00:00",
                "2011-12-31T23:59:59", "999 Skyway Park - JSON", docId);

        JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentMetadataHandle mh = setMetadata(false);

        if (transformName != null) {
            TransformExtensionsManager transMgr = adminClient.newServerConfigManager()
                    .newTransformExtensionsManager();
            ExtensionMetadata metadata = new ExtensionMetadata();
            metadata.setTitle("Adding sjs Transform");
            metadata.setDescription("This plugin adds 2 properties to JSON document");
            metadata.setProvider("MarkLogic");
            metadata.setVersion("0.1");
            // get the transform file
            File transformFile = new File(
                    "src/test/java/com/marklogic/client/functionaltest/transforms/" + transformName + ".js");
            FileHandle transformHandle = new FileHandle(transformFile);
            transMgr.writeJavascriptTransform(transformName, transformHandle, metadata);
            ServerTransform transformer = new ServerTransform(transformName);
            transformer.put("name", "Lang");
            transformer.put("value", "English");

            if (systemTime != null) {
                docMgr.write(docId, mh, handle, transformer, null, temporalCollection, systemTime);
            } else {
                docMgr.write(docId, mh, handle, transformer, null, temporalCollection);
            }
        } else {
            if (systemTime != null) {
                docMgr.write(docId, mh, handle, null, transaction, temporalCollection, systemTime);
            } else {
                docMgr.write(docId, mh, handle, null, transaction, temporalCollection);
            }
        }
    }

    public void insertJSONSingleDocumentAsEvalUser(String temporalCollection, String docId) throws Exception {

        System.out.println("Inside insertJSONSingleDocumentAsEvalUser");

        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2001-01-01T00:00:00",
                "2011-12-31T23:59:59", "999 Skyway Park - JSON", docId);

        JSONDocumentManager docMgr = evalClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentMetadataHandle mh = setMetadata(false);
        docMgr.write(docId, mh, handle, null, null, temporalCollection);
    }

    public void updateJSONSingleDocument(String temporalCollection, String docId) throws Exception {

        updateJSONSingleDocument(temporalCollection, docId, null, null);
    }

    public void updateJSONSingleDocumentAsEvalUser(String temporalCollection, String docId) throws Exception {

        System.out.println("Inside updateJSONSingleDocumentString");

        // Update the temporal document
        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2003-01-01T00:00:00",
                "2008-12-31T23:59:59", "1999 Skyway Park - Updated - JSON", docId);

        JSONDocumentManager docMgr = evalClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);
        DocumentMetadataHandle mh = setMetadata(true);

        docMgr.write(docId, mh, handle, null, null, temporalCollection);
    }

    public void updateJSONSingleDocument(String temporalCollection, String docId, Transaction transaction,
            java.util.Calendar systemTime) throws Exception {

        System.out.println("Inside updateJSONSingleDocument");

        // Update the temporal document
        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2003-01-01T00:00:00",
                "2008-12-31T23:59:59", "1999 Skyway Park - Updated - JSON", docId);

        JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);
        DocumentMetadataHandle mh = setMetadata(true);

        docMgr.write(docId, mh, handle, null, transaction, temporalCollection, systemTime);
    }

    public void deleteJSONSingleDocument(String temporalCollection, String docId, Transaction transaction)
            throws Exception {

        deleteJSONSingleDocument(temporalCollection, docId, transaction, null);
    }

    public void deleteJSONSingleDocumentAsEvalUser(String temporalCollection, String docId) throws Exception {

        System.out.println("Inside deleteJSONSingleDocumentAsEvalUser");

        JSONDocumentManager docMgr = evalClient.newJSONDocumentManager();

        // Doing the logic here to exercise the overloaded methods
        docMgr.delete(docId, null, temporalCollection);
    }

    public void deleteJSONSingleDocument(String temporalCollection, String docId, Transaction transaction,
            java.util.Calendar systemTime) throws Exception {

        System.out.println("Inside deleteJSONSingleDocument");

        JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();

        // Doing the logic here to exercise the overloaded methods
        if (systemTime != null) {
            docMgr.delete(docId, transaction, temporalCollection, systemTime);
        } else {
            docMgr.delete(docId, transaction, temporalCollection);
        }
    }

    private JacksonDatabindHandle<ObjectNode> getJSONDocumentHandle(String startValidTime, String endValidTime,
            String address, String uri) throws Exception {

        // Setup for JSON document
        /**
         * 
         { "System": { systemStartERIName : "", systemEndERIName : "", }, "Valid":
         * { validStartERIName: "2001-01-01T00:00:00", validEndERIName:
         * "2011-12-31T23:59:59" }, "Address": "999 Skyway Park", "uri":
         * "javaSingleDoc1.json" }
         */

        ObjectMapper mapper = new ObjectMapper();
        ObjectNode rootNode = mapper.createObjectNode();

        // Set system time values
        ObjectNode system = mapper.createObjectNode();

        system.put(systemStartERIName, "");
        system.put(systemEndERIName, "");
        rootNode.set(systemNodeName, system);

        // Set valid time values
        ObjectNode valid = mapper.createObjectNode();

        valid.put(validStartERIName, startValidTime);
        valid.put(validEndERIName, endValidTime);
        rootNode.set(validNodeName, valid);

        // Set Address
        rootNode.put(addressNodeName, address);

        // Set uri
        rootNode.put(uriNodeName, uri);

        System.out.println(rootNode.toString());

        JacksonDatabindHandle<ObjectNode> handle = new JacksonDatabindHandle<ObjectNode>(ObjectNode.class)
                .withFormat(Format.JSON);
        handle.set(rootNode);

        return handle;
    }

    /*
    * Insert multiple temporal documents to test bulk write of temporal documents.
    */
    @Test
    public void testBulkWritReadeWithTransaction() throws Exception {

        boolean tstatus = false;
        DocumentPage termQueryResults = null;

        Transaction tx = writerClient.openTransaction();
        try {
            XMLDocumentManager docMgr = writerClient.newXMLDocumentManager();

            DocumentWriteSet writeset = docMgr.newWriteSet();
            String[] docId = new String[4];
            docId[0] = "1.xml";
            docId[1] = "2.xml";
            docId[2] = "3.xml";
            docId[3] = "4.xml";

            DOMHandle handle1 = getXMLDocumentHandle("2001-01-01T00:00:00", "2011-12-31T23:59:56",
                    "999 Skyway Park - XML", docId[0]);
            DOMHandle handle2 = getXMLDocumentHandle("2001-01-02T00:00:00", "2011-12-31T23:59:57",
                    "999 Skyway Park - XML", docId[1]);
            DOMHandle handle3 = getXMLDocumentHandle("2001-01-03T00:00:00", "2011-12-31T23:59:58",
                    "999 Skyway Park - XML", docId[2]);
            DOMHandle handle4 = getXMLDocumentHandle("2001-01-04T00:00:00", "2011-12-31T23:59:59",
                    "999 Skyway Park - XML", docId[3]);
            DocumentMetadataHandle mh = setMetadata(false);

            writeset.add(docId[0], mh, handle1);
            writeset.add(docId[1], mh, handle2);
            writeset.add(docId[2], mh, handle3);
            writeset.add(docId[3], mh, handle4);
            Map<String, DOMHandle> map = new TreeMap<String, DOMHandle>();
            map.put(docId[0], handle1);
            map.put(docId[1], handle2);
            map.put(docId[2], handle3);
            map.put(docId[3], handle4);

            docMgr.write(writeset, null, null, bulktemporalCollectionName);

            QueryManager queryMgr = readerClient.newQueryManager();
            StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();

            String[] collections = { latestCollectionName, bulktemporalCollectionName, "insertCollection" };
            StructuredQueryDefinition termQuery = sqb.collection(collections);

            long start = 1;
            docMgr = readerClient.newXMLDocumentManager();
            docMgr.setMetadataCategories(Metadata.ALL); // Get all metadata
            termQueryResults = docMgr.search(termQuery, start);
            assertEquals("Records counts is incorrect", 4, termQueryResults.size());
            // Verify the Document Record content with map contents for each record.
            while (termQueryResults.hasNext()) {

                DocumentRecord record = termQueryResults.next();

                DOMHandle recordHandle = new DOMHandle();
                record.getContent(recordHandle);

                String recordContent = recordHandle.toString();

                System.out.println("Record URI = " + record.getUri());
                System.out.println("Record content is = " + recordContent);

                DOMHandle readDOMHandle = map.get(record.getUri());
                String mapContent = readDOMHandle.evaluateXPath("/root/Address/text()", String.class);

                assertTrue("Address value is incorrect ", recordContent.contains(mapContent));

                readDOMHandle = null;
                mapContent = null;
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
            tstatus = true;
            throw e;
        } finally {
            if (tstatus) {
                if (termQueryResults != null)
                    termQueryResults.close();
            }
            tx.rollback();
            tx = null;
        }
    }

    @Test
    // Insert a temporal document using DocumentUriTemplate
    public void testInsertXMLSingleDocumentUsingTemplate() throws Exception {
        System.out.println("Inside testInsertXMLSingleDocumentUsingTemplate");

        String docId = "javaSingleXMLDoc.xml";
        DOMHandle handle = getXMLDocumentHandle("2001-01-01T00:00:00", "2011-12-31T23:59:59",
                "777 Skyway Park - XML", docId);

        XMLDocumentManager docMgr = writerClient.newXMLDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // Create document using using document template
        String dirName = "/java/bitemporal/";
        String fileSuffix = "xml";
        DocumentUriTemplate template = docMgr.newDocumentUriTemplate(fileSuffix);
        template.setDirectory(dirName);
        DocumentMetadataHandle mh = setMetadata(false);

        docMgr.create(template, mh, handle, null, null, temporalCollectionName);

        // Make sure there are no documents associated with "latest" collection
        QueryManager queryMgr = readerClient.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();

        String[] collections = { latestCollectionName, "insertCollection" };
        StructuredQueryDefinition termQuery = sqb.collection(collections);

        long start = 1;
        docMgr = readerClient.newXMLDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL); // Get all metadata
        DocumentPage termQueryResults = docMgr.search(termQuery, start);

        long count = 0;
        while (termQueryResults.hasNext()) {
            ++count;
            DocumentRecord record = termQueryResults.next();

            String uri = record.getUri();
            System.out.println("URI = " + uri);

            if (!uri.contains(dirName) && !uri.contains(fileSuffix)) {
                assertFalse("Uri name does not have the right prefix or suffix", true);
            }
        }

        System.out.println("Number of results = " + count);
        assertEquals("Wrong number of results", 1, count);

        System.out.println("Done");
    }

    @Test
    // Insert a temporal document and update it using an invalid transform.
    // The transform in this case creates a duplicate element against which as range index
    // has been setup
    public void testInsertAndUpdateXMLSingleDocumentUsingInvalidTransform() throws Exception {

        System.out.println("Inside testXMLWriteSingleDocument");
        String docId = "javaSingleXMLDoc.xml";

        boolean exceptionThrown = false;
        try {
            updateXMLSingleDocument(temporalCollectionName, docId, "add-element-xquery-invalid-bitemp-transform");
        } catch (com.marklogic.client.FailedRequestException ex) {
            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("XDMP-MULTIMATCH"));
            assertTrue("Status code", (statusCode == 400));
        }

        assertTrue("Exception not thrown for invalid transform", exceptionThrown);
    }

    @Test
    // This test validates the following -
    // 1. Inserts, updates and delete and and also makes sure number of documents
    //    in doc uri collection, latest collection are accurate after those operations.
    //    Do this for more than one document URI (we do this with JSON and XML)
    // 2. Make sure things are correct with transforms
    public void testConsolidated() throws Exception {

        System.out.println("Inside testXMLConsolidated");
        String xmlDocId = "javaSingleXMLDoc.xml";

        // =============================================================================
        // Check insert works
        // =============================================================================
        // Insert XML document
        insertXMLSingleDocument(temporalCollectionName, xmlDocId, "add-element-xquery-transform"); // Transforming during insert

        // Verify that the document was inserted
        XMLDocumentManager xmlDocMgr = readerClient.newXMLDocumentManager();
        DocumentPage readResults = xmlDocMgr.read(xmlDocId);
        System.out.println("Number of results = " + readResults.size());
        assertEquals("Wrong number of results", 1, readResults.size());

        // Now insert a JSON document
        String jsonDocId = "javaSingleJSONDoc.json";
        insertJSONSingleDocument(temporalCollectionName, jsonDocId, null);

        // Verify that the document was inserted
        JSONDocumentManager jsonDocMgr = readerClient.newJSONDocumentManager();
        readResults = jsonDocMgr.read(jsonDocId);
        System.out.println("Number of results = " + readResults.size());
        assertEquals("Wrong number of results", 1, readResults.size());

        // =============================================================================
        // Check update works
        // =============================================================================
        // Update XML document
        updateXMLSingleDocument(temporalCollectionName, xmlDocId, null);

        // Make sure there are 2 documents in latest collection
        QueryManager queryMgr = readerClient.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();
        StructuredQueryDefinition termQuery = sqb.collection(latestCollectionName);

        long start = 1;
        DocumentPage termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 2, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in xmlDocId collection with term XML
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.and(sqb.and(sqb.term("XML"), sqb.collection(xmlDocId)));

        start = 1;
        termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure transform on insert worked
        while (termQueryResults.hasNext()) {
            DocumentRecord record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            if (record.getFormat() != Format.XML) {
                assertFalse("Format is not JSON: " + Format.JSON, true);
            } else {

                DOMHandle recordHandle = new DOMHandle();
                record.getContent(recordHandle);

                String content = recordHandle.toString();
                System.out.println("Content = " + content);

                // Check if transform worked. We did transform only with XML document
                if ((content.contains("2001-01-01T00:00:00") && content.contains("2011-12-31T23:59:59")
                        && record.getFormat() != Format.XML)
                        && (!content.contains("new-element") || !content.contains("2007-12-31T23:59:59"))) {
                    assertFalse("Transform did not work", true);
                } else {
                    System.out.println("Transform Worked!");
                }
            }
        }

        // Update JSON document
        updateJSONSingleDocument(temporalCollectionName, jsonDocId);

        // Make sure there are still 2 documents in latest collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(latestCollectionName);

        start = 1;
        termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 2, termQueryResults.getTotalSize());

        // Docu URIs in latest collection must be the same as the one as the
        // original document
        while (termQueryResults.hasNext()) {
            DocumentRecord record = termQueryResults.next();

            String uri = record.getUri();
            System.out.println("URI = " + uri);

            if (!uri.equals(xmlDocId) && !uri.equals(jsonDocId)) {
                assertFalse("URIs are not what is expected", true);
            }
        }

        // Make sure there are 4 documents in jsonDocId collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(jsonDocId);

        start = 1;
        termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there are 8 documents in temporal collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(temporalCollectionName);

        start = 1;
        termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 8, termQueryResults.getTotalSize());

        // Make sure there are 8 documents in total. Use string search for this
        queryMgr = readerClient.newQueryManager();
        StringQueryDefinition stringQD = queryMgr.newStringDefinition();
        stringQD.setCriteria("");

        start = 1;
        termQueryResults = xmlDocMgr.search(stringQD, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 8, termQueryResults.getTotalSize());

        // =============================================================================
        // Check delete works
        // =============================================================================
        // Delete one of the document
        deleteXMLSingleDocument(temporalCollectionName, xmlDocId);

        // Make sure there are still 4 documents in xmlDocId collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(xmlDocId);

        start = 1;
        termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of readerClientresults", 4, termQueryResults.getTotalSize());

        // Make sure there is one document with xmlDocId uri
        XMLDocumentManager docMgr = readerClient.newXMLDocumentManager();
        readResults = docMgr.read(xmlDocId);

        System.out.println("Number of results = " + readResults.size());
        assertEquals("Wrong number of results", 1, readResults.size());

        // Make sure there is only 1 document in latest collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(latestCollectionName);

        start = 1;
        termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 1, termQueryResults.getTotalSize());

        // Docu URIs in latest collection must be the same as the one as the
        // original document
        while (termQueryResults.hasNext()) {
            DocumentRecord record = termQueryResults.next();

            String uri = record.getUri();
            System.out.println("URI = " + uri);

            if (!uri.equals(jsonDocId)) {
                assertFalse("URIs are not what is expected", true);
            }
        }

        // Make sure there are 8 documents in temporal collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(temporalCollectionName);

        start = 1;
        termQueryResults = xmlDocMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 8, termQueryResults.getTotalSize());
    }

    @Test
    // Test bitemporal create, update and delete works with a JSON document
    // All database operations in this method are done using 'eval-user' against port 8000 
    public void testJSONConsolidated() throws Exception {

        System.out.println("Inside testJSONConsolidated");

        String docId = "javaSingleJSONDoc.json";
        insertJSONSingleDocumentAsEvalUser(temporalCollectionName, docId);

        // Verify that the document was inserted
        JSONDocumentManager docMgr = evalClient.newJSONDocumentManager();
        DocumentPage readResults = docMgr.read(docId);

        System.out.println("Number of results = " + readResults.size());
        assertEquals("Wrong number of results", 1, readResults.size());

        DocumentRecord latestDoc = readResults.next();
        System.out.println("URI after insert = " + latestDoc.getUri());
        assertEquals("Document uri wrong after insert", docId, latestDoc.getUri());

        // Check if properties have been set. User XML DOcument Manager since
        // properties are written as XML
        JacksonDatabindHandle<ObjectNode> contentHandle = new JacksonDatabindHandle<ObjectNode>(ObjectNode.class);
        DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
        docMgr.read(docId, metadataHandle, contentHandle);

        validateMetadata(metadataHandle);

        // ================================================================
        // Update the document
        updateJSONSingleDocumentAsEvalUser(temporalCollectionName, docId);

        // Verify that the document was updated
        // Make sure there is 1 document in latest collection
        QueryManager queryMgr = evalClient.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();
        StructuredQueryDefinition termQuery = sqb.collection(latestCollectionName);
        long start = 1;
        DocumentPage termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 1, termQueryResults.getTotalSize());

        // Docu URIs in latest collection must be the same as the one as the
        // original document
        while (termQueryResults.hasNext()) {
            DocumentRecord record = termQueryResults.next();

            String uri = record.getUri();
            System.out.println("URI = " + uri);

            if (!uri.equals(docId)) {
                assertFalse("URIs are not what is expected", true);
            }
        }

        // Make sure there are 4 documents in jsonDocId collection
        queryMgr = evalClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(docId);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in temporal collection
        queryMgr = evalClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(temporalCollectionName);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in total. Use string search for this
        queryMgr = evalClient.newQueryManager();
        StringQueryDefinition stringQD = queryMgr.newStringDefinition();
        stringQD.setCriteria("");

        start = 1;
        docMgr.setMetadataCategories(Metadata.ALL);
        termQueryResults = docMgr.search(stringQD, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        while (termQueryResults.hasNext()) {
            DocumentRecord record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            metadataHandle = new DocumentMetadataHandle();
            record.getMetadata(metadataHandle);
            Iterator<String> resCollections = metadataHandle.getCollections().iterator();

            int count = 0;
            while (resCollections.hasNext()) {
                ++count;
                String collection = resCollections.next();
                System.out.println("Collection = " + collection);

                if (!collection.equals(docId) && !collection.equals(docId)
                        && !collection.equals(latestCollectionName) && !collection.equals(updateCollectionName)
                        && !collection.equals(insertCollectionName) && !collection.equals(temporalCollectionName)) {
                    assertFalse("Collection not what is expected: " + collection, true);
                }

                if (collection.equals(latestCollectionName)) {
                    // If there is a latest collection, docId must match the URI
                    assertTrue("Document URI", record.getUri().equals(docId));
                }
            }

            if (record.getUri().equals(docId)) {
                // Must belong to latest collection as well. So, count must be 4
                assertTrue("Count of collections", (count == 4));
            } else {
                assertTrue("Count of collections", (count == 3));
            }

            if (record.getFormat() != Format.JSON) {
                assertFalse("Format is not JSON: " + Format.JSON, true);
            } else {
                JacksonDatabindHandle<ObjectNode> recordHandle = new JacksonDatabindHandle<ObjectNode>(
                        ObjectNode.class);
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());
            }
        }

        // =============================================================================
        // Check delete works
        // =============================================================================
        // Delete one of the document
        deleteJSONSingleDocumentAsEvalUser(temporalCollectionName, docId);

        // Make sure there are still 4 documents in docId collection
        queryMgr = evalClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(docId);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there is one document with docId uri
        docMgr = evalClient.newJSONDocumentManager();
        readResults = docMgr.read(docId);

        System.out.println("Number of results = " + readResults.size());
        assertEquals("Wrong number of results", 1, readResults.size());

        // Make sure there are no documents in latest collection
        queryMgr = evalClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(latestCollectionName);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 0, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in temporal collection
        queryMgr = evalClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(temporalCollectionName);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in total. Use string search for this
        queryMgr = evalClient.newQueryManager();

        start = 1;
        termQueryResults = docMgr.search(stringQD, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());
    }

    @Test
    // Test bitemporal create, update and delete works with a JSON document while passing
    // system time. The temporal collection needs to be enabled for lsqt and we have enabled
    // automation for lsqt (lsqt will be advanced every second and system time will be set with 
    // a lag of 1 second)
    public void testSystemTime() throws Exception {

        System.out.println("Inside testSystemTime");
        ConnectedRESTQA.updateTemporalCollectionForLSQT(dbName, temporalLsqtCollectionName, true);

        String docId = "javaSingleJSONDoc.json";

        Calendar firstInsertTime = DatatypeConverter.parseDateTime("2010-01-01T00:00:01");
        insertJSONSingleDocument(temporalLsqtCollectionName, docId, null, null, firstInsertTime);

        // Verify that the document was inserted
        JSONDocumentManager docMgr = readerClient.newJSONDocumentManager();
        JacksonDatabindHandle<ObjectNode> recordHandle = new JacksonDatabindHandle<ObjectNode>(ObjectNode.class);
        DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
        docMgr.read(docId, metadataHandle, recordHandle);
        DocumentPage readResults = docMgr.read(docId);

        System.out.println("Number of results = " + readResults.size());
        assertEquals("Wrong number of results", 1, readResults.size());

        DocumentRecord record = readResults.next();
        System.out.println("URI after insert = " + record.getUri());
        assertEquals("Document uri wrong after insert", docId, record.getUri());
        System.out.println("Content = " + recordHandle.toString());

        // Make sure System start time was what was set ("2010-01-01T00:00:01")
        if (record.getFormat() != Format.JSON) {
            assertFalse("Invalid document format: " + record.getFormat(), true);
        } else {
            JsonFactory factory = new JsonFactory();
            ObjectMapper mapper = new ObjectMapper(factory);
            TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
            };

            HashMap<String, Object> docObject = mapper.readValue(recordHandle.toString(), typeRef);

            @SuppressWarnings("unchecked")
            HashMap<String, Object> validNode = (HashMap<String, Object>) (docObject.get(systemNodeName));

            String systemStartDate = (String) validNode.get(systemStartERIName);
            String systemEndDate = (String) validNode.get(systemEndERIName);
            System.out.println("systemStartDate = " + systemStartDate);
            System.out.println("systemEndDate = " + systemEndDate);

            assertTrue("System start date check failed", (systemStartDate.contains("2010-01-01T00:00:01")));
            assertTrue("System end date check failed", (systemEndDate.contains("9999-12-31T23:59:59")));

            // Validate collections
            Iterator<String> resCollections = metadataHandle.getCollections().iterator();
            while (resCollections.hasNext()) {
                String collection = resCollections.next();
                System.out.println("Collection = " + collection);

                if (!collection.equals(docId) && !collection.equals(insertCollectionName)
                        && !collection.equals(temporalLsqtCollectionName)
                        && !collection.equals(latestCollectionName)) {
                    assertFalse("Collection not what is expected: " + collection, true);
                }
            }

            // Validate permissions
            DocumentPermissions permissions = metadataHandle.getPermissions();
            System.out.println("Permissions: " + permissions);

            String actualPermissions = getDocumentPermissionsString(permissions);
            System.out.println("actualPermissions: " + actualPermissions);

            assertTrue("Document permissions difference in size value", actualPermissions.contains("size:3"));

            assertTrue("Document permissions difference in rest-reader permission",
                    actualPermissions.contains("rest-reader:[READ]"));
            assertTrue("Document permissions difference in rest-writer permission",
                    actualPermissions.contains("rest-writer:[UPDATE]"));
            assertTrue("Document permissions difference in app-user permission",
                    (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                            && actualPermissions.contains("UPDATE") && actualPermissions.contains("EXECUTE")));

            // Validate quality
            int quality = metadataHandle.getQuality();
            System.out.println("Quality: " + quality);
            assertEquals(quality, 11);

            validateMetadata(metadataHandle);
        }

        // =============================================================================
        // Check update works
        // =============================================================================
        Calendar updateTime = DatatypeConverter.parseDateTime("2011-01-01T00:00:01");
        updateJSONSingleDocument(temporalLsqtCollectionName, docId, null, updateTime);

        // Verify that the document was updated
        // Make sure there is 1 document in latest collection
        QueryManager queryMgr = readerClient.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();
        StructuredQueryDefinition termQuery = sqb.collection(latestCollectionName);
        long start = 1;
        DocumentPage termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 1, termQueryResults.getTotalSize());

        // Document URIs in latest collection must be the same as the one as the
        // original document
        while (termQueryResults.hasNext()) {
            record = termQueryResults.next();

            String uri = record.getUri();
            System.out.println("URI = " + uri);

            if (!uri.equals(docId)) {
                assertFalse("URIs are not what is expected", true);
            }
        }

        // Make sure there are 4 documents in jsonDocId collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(docId);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in temporal collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(temporalLsqtCollectionName);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in total. Use string search for this
        queryMgr = readerClient.newQueryManager();
        StringQueryDefinition stringQD = queryMgr.newStringDefinition();
        stringQD.setCriteria("");

        start = 1;
        docMgr.setMetadataCategories(Metadata.ALL);
        termQueryResults = docMgr.search(stringQD, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        while (termQueryResults.hasNext()) {
            record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            metadataHandle = new DocumentMetadataHandle();
            record.getMetadata(metadataHandle);

            if (record.getFormat() != Format.JSON) {
                assertFalse("Format is not JSON: " + Format.JSON, true);
            } else {
                // Make sure that system and valid times are what is expected
                recordHandle = new JacksonDatabindHandle<ObjectNode>(ObjectNode.class);
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());

                JsonFactory factory = new JsonFactory();
                ObjectMapper mapper = new ObjectMapper(factory);
                TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
                };

                HashMap<String, Object> docObject = mapper.readValue(recordHandle.toString(), typeRef);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> systemNode = (HashMap<String, Object>) (docObject.get(systemNodeName));

                String systemStartDate = (String) systemNode.get(systemStartERIName);
                String systemEndDate = (String) systemNode.get(systemEndERIName);
                System.out.println("systemStartDate = " + systemStartDate);
                System.out.println("systemEndDate = " + systemEndDate);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> validNode = (HashMap<String, Object>) (docObject.get(validNodeName));

                String validStartDate = (String) validNode.get(validStartERIName);
                String validEndDate = (String) validNode.get(validEndERIName);
                System.out.println("validStartDate = " + validStartDate);
                System.out.println("validEndDate = " + validEndDate);

                // Permissions
                DocumentPermissions permissions = metadataHandle.getPermissions();
                System.out.println("Permissions: " + permissions);

                String actualPermissions = getDocumentPermissionsString(permissions);
                System.out.println("actualPermissions: " + actualPermissions);

                int quality = metadataHandle.getQuality();
                System.out.println("Quality: " + quality);

                if (validStartDate.contains("2003-01-01T00:00:00")
                        && validEndDate.contains("2008-12-31T23:59:59")) {
                    assertTrue("System start date check failed", (systemStartDate.contains("2011-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("9999-12-31T23:59:59")));

                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(updateCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")));
                    assertFalse("Document permissions difference in app-user permission",
                            actualPermissions.contains("EXECUTE"));

                    assertEquals(quality, 99);
                }

                if (validStartDate.contains("2001-01-01T00:00:00")
                        && validEndDate.contains("2003-01-01T00:00:00")) {
                    assertTrue("System start date check failed", (systemStartDate.contains("2011-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("9999-12-31T23:59:59")));

                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(insertCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")
                                    && actualPermissions.contains("EXECUTE")));

                    assertEquals(quality, 11);
                }

                if (validStartDate.contains("2008-12-31T23:59:59")
                        && validEndDate.contains("2011-12-31T23:59:59")) {
                    // This is the latest document
                    assertTrue("System start date check failed", (systemStartDate.contains("2011-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("9999-12-31T23:59:59")));
                    assertTrue("URI should be the doc uri ", record.getUri().equals(docId));

                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(insertCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)
                                && !collection.equals(latestCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")
                                    && actualPermissions.contains("EXECUTE")));

                    assertEquals(quality, 11);

                    validateMetadata(metadataHandle);
                }

                if (validStartDate.contains("2001-01-01T00:00:00")
                        && validEndDate.contains("2011-12-31T23:59:59")) {
                    assertTrue("System start date check failed", (systemStartDate.contains("2010-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("2011-01-01T00:00:01")));

                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(insertCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")
                                    && actualPermissions.contains("EXECUTE")));

                    assertEquals(quality, 11);
                }
            }
        }

        // =============================================================================
        // Check delete works
        // =============================================================================
        // Delete one of the document
        Calendar deleteTime = DatatypeConverter.parseDateTime("2012-01-01T00:00:01");
        deleteJSONSingleDocument(temporalLsqtCollectionName, docId, null, deleteTime);

        // Make sure there are still 4 documents in docId collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(docId);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        // Make sure there is one document with docId uri
        docMgr = readerClient.newJSONDocumentManager();
        readResults = docMgr.read(docId);

        System.out.println("Number of results = " + readResults.size());
        assertEquals("Wrong number of results", 1, readResults.size());

        // Make sure there are no documents in latest collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(latestCollectionName);

        start = 1;
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 0, termQueryResults.getTotalSize());

        // Make sure there are 4 documents in temporal collection
        queryMgr = readerClient.newQueryManager();
        sqb = queryMgr.newStructuredQueryBuilder();
        termQuery = sqb.collection(temporalLsqtCollectionName);

        start = 1;
        docMgr.setMetadataCategories(Metadata.ALL);
        termQueryResults = docMgr.search(termQuery, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());

        while (termQueryResults.hasNext()) {
            record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            metadataHandle = new DocumentMetadataHandle();
            record.getMetadata(metadataHandle);

            if (record.getFormat() != Format.JSON) {
                assertFalse("Format is not JSON: " + Format.JSON, true);
            } else {
                // Make sure that system and valid times are what is expected
                recordHandle = new JacksonDatabindHandle<ObjectNode>(ObjectNode.class);
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());

                JsonFactory factory = new JsonFactory();
                ObjectMapper mapper = new ObjectMapper(factory);
                TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
                };

                HashMap<String, Object> docObject = mapper.readValue(recordHandle.toString(), typeRef);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> systemNode = (HashMap<String, Object>) (docObject.get(systemNodeName));

                String systemStartDate = (String) systemNode.get(systemStartERIName);
                String systemEndDate = (String) systemNode.get(systemEndERIName);
                System.out.println("systemStartDate = " + systemStartDate);
                System.out.println("systemEndDate = " + systemEndDate);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> validNode = (HashMap<String, Object>) (docObject.get(validNodeName));

                String validStartDate = (String) validNode.get(validStartERIName);
                String validEndDate = (String) validNode.get(validEndERIName);
                System.out.println("validStartDate = " + validStartDate);
                System.out.println("validEndDate = " + validEndDate);

                // Permissions
                DocumentPermissions permissions = metadataHandle.getPermissions();
                System.out.println("Permissions: " + permissions);

                String actualPermissions = getDocumentPermissionsString(permissions);
                System.out.println("actualPermissions: " + actualPermissions);

                int quality = metadataHandle.getQuality();
                System.out.println("Quality: " + quality);

                if (validStartDate.contains("2003-01-01T00:00:00")
                        && validEndDate.contains("2008-12-31T23:59:59")) {
                    assertTrue("System start date check failed", (systemStartDate.contains("2011-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("2012-01-01T00:00:01")));

                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(updateCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")));
                    assertFalse("Document permissions difference in app-user permission",
                            actualPermissions.contains("EXECUTE"));

                    assertEquals(quality, 99);
                }

                if (validStartDate.contains("2001-01-01T00:00:00")
                        && validEndDate.contains("2003-01-01T00:00:00")) {
                    assertTrue("System start date check failed", (systemStartDate.contains("2011-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("2012-01-01T00:00:01")));

                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(insertCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")
                                    && actualPermissions.contains("EXECUTE")));

                    assertEquals(quality, 11);
                }

                if (validStartDate.contains("2008-12-31T23:59:59")
                        && validEndDate.contains("2011-12-31T23:59:59")) {
                    assertTrue("System start date check failed", (systemStartDate.contains("2011-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("2012-01-01T00:00:01")));

                    assertTrue("URI should be the doc uri ", record.getUri().equals(docId));

                    // Document should not be in latest collection
                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(insertCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")
                                    && actualPermissions.contains("EXECUTE")));

                    assertEquals(quality, 11);

                    validateMetadata(metadataHandle);
                }

                if (validStartDate.contains("2001-01-01T00:00:00")
                        && validEndDate.contains("2011-12-31T23:59:59")) {
                    assertTrue("System start date check failed", (systemStartDate.contains("2010-01-01T00:00:01")));
                    assertTrue("System start date check failed", (systemEndDate.contains("2011-01-01T00:00:01")));
                    Iterator<String> resCollections = metadataHandle.getCollections().iterator();
                    while (resCollections.hasNext()) {
                        String collection = resCollections.next();
                        System.out.println("Collection = " + collection);

                        if (!collection.equals(docId) && !collection.equals(insertCollectionName)
                                && !collection.equals(temporalLsqtCollectionName)) {
                            assertFalse("Collection not what is expected: " + collection, true);
                        }
                    }

                    assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

                    assertTrue("Document permissions difference in size value",
                            actualPermissions.contains("size:3"));

                    assertTrue("Document permissions difference in rest-reader permission",
                            actualPermissions.contains("rest-reader:[READ]"));
                    assertTrue("Document permissions difference in rest-writer permission",
                            actualPermissions.contains("rest-writer:[UPDATE]"));
                    assertTrue("Document permissions difference in app-user permission",
                            (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ")
                                    && actualPermissions.contains("UPDATE")
                                    && actualPermissions.contains("EXECUTE")));

                    assertEquals(quality, 11);
                }
            }
        }

        // Make sure there are 4 documents in total. Use string search for this
        queryMgr = readerClient.newQueryManager();

        start = 1;
        termQueryResults = docMgr.search(stringQD, start);
        System.out.println("Number of results = " + termQueryResults.getTotalSize());
        assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());
    }

    @Test
    // Create a bitemporal document and update the document with a system time that is less than
    // the one used durign creation
    public void testSystemTimeUsingInvalidTime() throws Exception {

        System.out.println("Inside testSystemTimeUsingInvalidTime");
        ConnectedRESTQA.updateTemporalCollectionForLSQT(dbName, temporalLsqtCollectionName, true);

        String docId = "javaSingleJSONDoc.json";

        Calendar firstInsertTime = DatatypeConverter.parseDateTime("2010-01-01T00:00:01");
        insertJSONSingleDocument(temporalLsqtCollectionName, docId, null, null, firstInsertTime);

        // Sleep for 2 seconds for LSQT to be advanced
        Thread.sleep(2000);

        // Update by passing a system time that is less than previous one
        Calendar updateTime = DatatypeConverter.parseDateTime("2010-01-01T00:00:00");

        boolean exceptionThrown = false;
        try {
            updateJSONSingleDocument(temporalLsqtCollectionName, docId, null, updateTime);
        } catch (com.marklogic.client.FailedRequestException ex) {
            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("TEMPORAL-OPNOTAFTERLSQT"));
            assertTrue("Status code", (statusCode == 400));
        }

        assertTrue("Exception not thrown during invalid update of system time", exceptionThrown);

        // Delete by passing invalid time
        Calendar deleteTime = DatatypeConverter.parseDateTime("2010-01-01T00:00:00");

        exceptionThrown = false;
        try {
            deleteJSONSingleDocument(temporalLsqtCollectionName, docId, null, deleteTime);
        } catch (com.marklogic.client.FailedRequestException ex) {
            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("TEMPORAL-SYSTEMTIME-BACKWARDS"));
            assertTrue("Status code", (statusCode == 400));
        }

        assertTrue("Exception not thrown for invalid extension", exceptionThrown);
    }

    @Test
    // Test transaction commit with bitemporal documents
    public void testTransactionCommit() throws Exception {

        System.out.println("Inside testTransactionCommit");

        String docId = "javaSingleJSONDoc.json";

        Transaction transaction = writerClient.openTransaction("Transaction for BiTemporal");
        try {
            insertJSONSingleDocument(temporalCollectionName, docId, null, transaction, null);

            // Verify that the document was inserted
            JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();
            DocumentPage readResults = docMgr.read(transaction, docId);

            System.out.println("Number of results = " + readResults.size());
            if (readResults.size() != 1) {
                transaction.rollback();

                assertEquals("Wrong number of results", 1, readResults.size());
            }

            DocumentRecord latestDoc = readResults.next();
            System.out.println("URI after insert = " + latestDoc.getUri());

            if (!docId.equals(latestDoc.getUri())) {
                transaction.rollback();

                assertEquals("Document uri wrong after insert", docId, latestDoc.getUri());
            }

            // Make sure document is not visible to any other transaction
            boolean exceptionThrown = false;
            try {
                JacksonDatabindHandle<ObjectNode> contentHandle = new JacksonDatabindHandle<ObjectNode>(
                        ObjectNode.class);
                DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
                docMgr.read(docId, metadataHandle, contentHandle);
            } catch (Exception ex) {
                exceptionThrown = true;
            }

            if (!exceptionThrown) {
                transaction.rollback();

                assertTrue("Exception not thrown during read using no transaction handle", exceptionThrown);
            }

            updateJSONSingleDocument(temporalCollectionName, docId, transaction, null);

            QueryManager queryMgr = writerClient.newQueryManager();
            StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();
            StructuredQueryDefinition termQuery = sqb.collection(latestCollectionName);

            long start = 1;
            DocumentPage termQueryResults = docMgr.search(termQuery, start, transaction);
            System.out.println("Number of results = " + termQueryResults.getTotalSize());

            if (termQueryResults.getTotalSize() != 1) {
                transaction.rollback();

                assertEquals("Wrong number of results", 1, termQueryResults.getTotalSize());
            }

            // There should be 4 documents in docId collection
            queryMgr = writerClient.newQueryManager();
            sqb = queryMgr.newStructuredQueryBuilder();
            termQuery = sqb.collection(docId);

            start = 1;
            termQueryResults = docMgr.search(termQuery, start, transaction);
            System.out.println("Number of results = " + termQueryResults.getTotalSize());

            if (termQueryResults.getTotalSize() != 4) {
                transaction.rollback();

                assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());
            }

            // Search for documents using doc uri collection and no transaction object
            // passed.
            // There should be 0 documents in docId collection
            queryMgr = writerClient.newQueryManager();
            sqb = queryMgr.newStructuredQueryBuilder();
            termQuery = sqb.collection(docId);

            start = 1;
            termQueryResults = docMgr.search(termQuery, start);
            System.out.println("Number of results = " + termQueryResults.getTotalSize());

            if (termQueryResults.getTotalSize() != 0) {
                transaction.rollback();

                assertEquals("Wrong number of results", 0, termQueryResults.getTotalSize());
            }

            deleteJSONSingleDocument(temporalCollectionName, docId, transaction);

            // There should be no documents in latest collection
            queryMgr = writerClient.newQueryManager();
            sqb = queryMgr.newStructuredQueryBuilder();
            termQuery = sqb.collection(latestCollectionName);

            start = 1;
            termQueryResults = docMgr.search(termQuery, start, transaction);
            System.out.println("Number of results = " + termQueryResults.getTotalSize());

            if (termQueryResults.getTotalSize() != 0) {
                transaction.rollback();

                assertEquals("Wrong number of results", 0, termQueryResults.getTotalSize());
            }

            transaction.commit();
            transaction = null;

            // There should still be no documents in latest collection
            queryMgr = writerClient.newQueryManager();
            sqb = queryMgr.newStructuredQueryBuilder();
            termQuery = sqb.collection(latestCollectionName);

            start = 1;
            termQueryResults = docMgr.search(termQuery, start);
            System.out.println("Number of results = " + termQueryResults.getTotalSize());
            assertEquals("Wrong number of results", 0, termQueryResults.getTotalSize());
        } catch (Exception ex) {
            transaction.rollback();
            transaction = null;

            assertTrue("testTransactionCommit failed", false);
        } finally {
            if (transaction != null) {
                transaction.rollback();
                transaction = null;
            }
        }
    }

    @Test
    // Test transaction rollback with bitemporal documents
    public void testTransactionRollback() throws Exception {

        System.out.println("Inside testTransactionRollback");
        Transaction transaction = writerClient.openTransaction("Transaction for BiTemporal");

        try {
            String docId = "javaSingleJSONDoc.json";
            try {
                insertJSONSingleDocument(temporalCollectionName, docId, null, transaction, null);
            } catch (Exception ex) {
                transaction.rollback();
                transaction = null;

                assertTrue("insertJSONSingleDocument failed in testTransactionRollback", false);
            }

            // Verify that the document was inserted
            JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();
            DocumentPage readResults = docMgr.read(transaction, docId);

            System.out.println("Number of results = " + readResults.size());
            if (readResults.size() != 1) {
                transaction.rollback();

                assertEquals("Wrong number of results", 1, readResults.size());
            }

            DocumentRecord latestDoc = readResults.next();
            System.out.println("URI after insert = " + latestDoc.getUri());
            if (!docId.equals(latestDoc.getUri())) {
                transaction.rollback();

                assertEquals("Document uri wrong after insert", docId, latestDoc.getUri());
            }

            try {
                updateJSONSingleDocument(temporalCollectionName, docId, transaction, null);
            } catch (Exception ex) {
                transaction.rollback();
                transaction = null;

                assertTrue("updateJSONSingleDocument failed in testTransactionRollback", false);
            }

            // Verify that the document is visible and count is 4
            // Fetch documents associated with a search term (such as XML) in Address
            // element
            QueryManager queryMgr = writerClient.newQueryManager();
            StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();

            StructuredQueryDefinition termQuery = sqb.collection(docId);

            long start = 1;
            DocumentPage termQueryResults = docMgr.search(termQuery, start, transaction);
            System.out.println("Number of results = " + termQueryResults.getTotalSize());
            if (termQueryResults.getTotalSize() != 4) {
                transaction.rollback();

                assertEquals("Wrong number of results", 4, termQueryResults.getTotalSize());
            }

            transaction.rollback();

            // Verify that the document is not there after rollback
            boolean exceptionThrown = false;
            try {
                JacksonDatabindHandle<ObjectNode> contentHandle = new JacksonDatabindHandle<ObjectNode>(
                        ObjectNode.class);
                DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
                docMgr.read(docId, metadataHandle, contentHandle);
            } catch (Exception ex) {
                exceptionThrown = true;
            }

            if (!exceptionThrown) {
                transaction.rollback();

                assertTrue("Exception not thrown during read on non-existing uri", exceptionThrown);
            }

            // =======================================================================
            // Now try rollback with delete
            System.out.println("Test Rollback after delete");
            docId = "javaSingleJSONDocForDelete.json";

            transaction = writerClient.openTransaction("Transaction Rollback for BiTemporal Delete");

            try {
                insertJSONSingleDocument(temporalCollectionName, docId, null, transaction, null);
            } catch (Exception ex) {
                transaction.rollback();
                transaction = null;

                assertTrue("insertJSONSingleDocument failed in testTransactionRollback", false);
            }

            // Verify that the document was inserted
            docMgr = writerClient.newJSONDocumentManager();
            readResults = docMgr.read(transaction, docId);

            System.out.println("Number of results = " + readResults.size());
            if (readResults.size() != 1) {
                transaction.rollback();

                assertEquals("Wrong number of results", 1, readResults.size());
            }

            latestDoc = readResults.next();
            System.out.println("URI after insert = " + latestDoc.getUri());
            if (!docId.equals(latestDoc.getUri())) {
                transaction.rollback();

                assertEquals("Document uri wrong after insert", docId, latestDoc.getUri());
            }

            try {
                deleteJSONSingleDocument(temporalCollectionName, docId, transaction);
            } catch (Exception ex) {
                transaction.rollback();
                transaction = null;

                assertTrue("deleteJSONSingleDocument failed in testTransactionRollback", false);
            }

            // Verify that the document is visible and count is 1
            // Fetch documents associated with a search term (such as XML) in Address
            // element
            queryMgr = writerClient.newQueryManager();
            sqb = queryMgr.newStructuredQueryBuilder();

            termQuery = sqb.collection(docId);

            start = 1;
            termQueryResults = docMgr.search(termQuery, start, transaction);
            System.out.println("Number of results = " + termQueryResults.getTotalSize());
            if (termQueryResults.getTotalSize() != 1) {
                transaction.rollback();

                assertEquals("Wrong number of results", 1, termQueryResults.getTotalSize());
            }

            transaction.rollback();
            transaction = null;

            // Verify that the document was rolled back and count is 0
            exceptionThrown = false;
            try {
                readResults = docMgr.read(docId);
            } catch (Exception ex) {
                exceptionThrown = true;
            }

            System.out.println("Done");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (transaction != null) {
                transaction.rollback();
                transaction = null;
            }
        }
    }

    @Test
    // Test Period Range Query using ALN_CONTAINS. We use a single axis during query
    public void testPeriodRangeQuerySingleAxisBasedOnALNContains() throws Exception {
        System.out.println("Inside testPeriodRangeQuerySingleAxisBasedOnALNContains");

        // Read documents based on document URI and ALN Contains. We are just
        // looking for count of documents to be correct

        String docId = "javaSingleJSONDoc.json";

        insertJSONSingleDocument(temporalCollectionName, docId, null);

        updateJSONSingleDocument(temporalCollectionName, docId);

        // Fetch documents associated with a search term (such as XML) in Address
        // element
        QueryManager queryMgr = readerClient.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();

        StructuredQueryDefinition termQuery = sqb.collection(docId);

        StructuredQueryBuilder.Axis validAxis = sqb.axis(axisValidName);
        Calendar start1 = DatatypeConverter.parseDateTime("2001-01-01T00:00:01");
        Calendar end1 = DatatypeConverter.parseDateTime("2011-12-31T23:59:58");
        StructuredQueryBuilder.Period period1 = sqb.period(start1, end1);
        StructuredQueryDefinition periodQuery = sqb.and(termQuery,
                sqb.temporalPeriodRange(validAxis, TemporalOperator.ALN_CONTAINS, period1));

        long start = 1;
        JSONDocumentManager docMgr = readerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL); // Get all metadata
        DocumentPage termQueryResults = docMgr.search(periodQuery, start);

        long count = 0;
        while (termQueryResults.hasNext()) {
            ++count;
            DocumentRecord record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
            record.getMetadata(metadataHandle);
            Iterator<String> resCollections = metadataHandle.getCollections().iterator();
            while (resCollections.hasNext()) {
                System.out.println("Collection = " + resCollections.next());
            }

            if (record.getFormat() == Format.XML) {
                DOMHandle recordHandle = new DOMHandle();
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());
            } else {
                JacksonDatabindHandle<ObjectNode> recordHandle = new JacksonDatabindHandle<ObjectNode>(
                        ObjectNode.class);
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());

                JsonFactory factory = new JsonFactory();
                ObjectMapper mapper = new ObjectMapper(factory);
                TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
                };

                HashMap<String, Object> docObject = mapper.readValue(recordHandle.toString(), typeRef);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> systemNode = (HashMap<String, Object>) (docObject.get(systemNodeName));

                String systemStartDate = (String) systemNode.get(systemStartERIName);
                String systemEndDate = (String) systemNode.get(systemEndERIName);
                System.out.println("systemStartDate = " + systemStartDate);
                System.out.println("systemEndDate = " + systemEndDate);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> validNode = (HashMap<String, Object>) (docObject.get(validNodeName));

                String validStartDate = (String) validNode.get(validStartERIName);
                String validEndDate = (String) validNode.get(validEndERIName);
                System.out.println("validStartDate = " + validStartDate);
                System.out.println("validEndDate = " + validEndDate);

                assertTrue("Valid start date check failed", (validStartDate.equals("2001-01-01T00:00:00")
                        && validEndDate.equals("2011-12-31T23:59:59")));
            }
        }

        System.out.println("Number of results using SQB = " + count);
        assertEquals("Wrong number of results", 1, count);
    }

    @Test
    // Test Period Range Query usig ALN_CONTAINS. We use 2 axes during query
    // Note that the query will be done for every axis across every period. And
    // the results will be an OR of the result of each of the query done for every axis 
    // across every period
    public void testPeriodRangeQueryMultiplesAxesBasedOnALNContains() throws Exception {
        System.out.println("Inside testPeriodRangeQueryMultiplesAxesBasedOnALNContains");

        // Read documents based on document URI and ALN_OVERLAPS. We are just
        // looking
        // for count of documents to be correct

        String docId = "javaSingleJSONDoc.json";

        insertJSONSingleDocument(temporalCollectionName, docId, null);
        updateJSONSingleDocument(temporalCollectionName, docId);

        // Fetch documents associated with a search term (such as XML) in Address
        // element
        QueryManager queryMgr = readerClient.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();

        StructuredQueryDefinition termQuery = sqb.collection(docId);

        StructuredQueryBuilder.Axis validAxis1 = sqb.axis(axisValidName);
        Calendar start1 = DatatypeConverter.parseDateTime("2001-01-01T00:00:01");
        Calendar end1 = DatatypeConverter.parseDateTime("2011-12-31T23:59:58");
        StructuredQueryBuilder.Period period1 = sqb.period(start1, end1);

        StructuredQueryBuilder.Axis validAxis2 = sqb.axis(axisValidName);
        Calendar start2 = DatatypeConverter.parseDateTime("2003-01-01T00:00:01");
        Calendar end2 = DatatypeConverter.parseDateTime("2008-12-31T23:59:58");
        StructuredQueryBuilder.Period period2 = sqb.period(start2, end2);

        StructuredQueryBuilder.Axis[] axes = new StructuredQueryBuilder.Axis[] { validAxis1, validAxis2 };
        StructuredQueryBuilder.Period[] periods = new StructuredQueryBuilder.Period[] { period1, period2 };

        StructuredQueryDefinition periodQuery = sqb.and(termQuery,
                sqb.temporalPeriodRange(axes, TemporalOperator.ALN_CONTAINS, periods));

        // Note that the query will be done for every axis across every period. And
        // the results will be an OR of the result of each of the query done for every axis 
        // across every period
        long start = 1;
        JSONDocumentManager docMgr = readerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL); // Get all metadata
        DocumentPage termQueryResults = docMgr.search(periodQuery, start);

        long count = 0;
        while (termQueryResults.hasNext()) {
            ++count;
            DocumentRecord record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
            record.getMetadata(metadataHandle);
            Iterator<String> resCollections = metadataHandle.getCollections().iterator();
            while (resCollections.hasNext()) {
                System.out.println("Collection = " + resCollections.next());
            }

            if (record.getFormat() != Format.JSON) {
                assertFalse("Invalid document format: " + record.getFormat(), true);
            } else {
                JacksonDatabindHandle<ObjectNode> recordHandle = new JacksonDatabindHandle<ObjectNode>(
                        ObjectNode.class);
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());

                JsonFactory factory = new JsonFactory();
                ObjectMapper mapper = new ObjectMapper(factory);
                TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
                };

                HashMap<String, Object> docObject = mapper.readValue(recordHandle.toString(), typeRef);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> validNode = (HashMap<String, Object>) (docObject.get(validNodeName));

                String validStartDate = (String) validNode.get(validStartERIName);
                String validEndDate = (String) validNode.get(validEndERIName);
                System.out.println("validStartDate = " + validStartDate);
                System.out.println("validEndDate = " + validEndDate);

                assertTrue("Valid start date check failed", (validStartDate.equals("2001-01-01T00:00:00")
                        || validStartDate.equals("2003-01-01T00:00:00")));
                assertTrue("Valid end date check failed",
                        (validEndDate.equals("2011-12-31T23:59:59") || validEndDate.equals("2008-12-31T23:59:59")));
            }
        }

        System.out.println("Number of results using SQB = " + count);
        assertEquals("Wrong number of results", 2, count);
    }

    @Test
    // Test Period Compare Query using ALN_CONTAINS as the operator
    public void testPeriodCompareQueryBasedOnALNContains() throws Exception {
        System.out.println("Inside testPeriodCompareQueryBasedOnALNContains");

        // Read documents based on document URI and ALN Contains. We are just
        // looking for count of documents to be correct
        String docId = "javaSingleJSONDoc.json";
        ConnectedRESTQA.updateTemporalCollectionForLSQT(dbName, temporalLsqtCollectionName, true);

        Calendar insertTime = DatatypeConverter.parseDateTime("2005-01-01T00:00:01");
        insertJSONSingleDocument(temporalLsqtCollectionName, docId, null, null, insertTime);

        Calendar updateTime = DatatypeConverter.parseDateTime("2010-01-01T00:00:01");
        updateJSONSingleDocument(temporalLsqtCollectionName, docId, null, updateTime);

        // Fetch documents associated with a search term (such as XML) in Address
        // element
        QueryManager queryMgr = readerClient.newQueryManager();
        StructuredQueryBuilder sqb = queryMgr.newStructuredQueryBuilder();

        StructuredQueryBuilder.Axis validAxis = sqb.axis(axisValidName);
        StructuredQueryBuilder.Axis systemAxis = sqb.axis(axisSystemName);

        StructuredQueryDefinition termQuery = sqb.collection(docId);
        StructuredQueryDefinition periodQuery = sqb.and(termQuery,
                sqb.temporalPeriodCompare(validAxis, TemporalOperator.ALN_CONTAINS, systemAxis));

        long start = 1;
        JSONDocumentManager docMgr = readerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL); // Get all metadata
        DocumentPage termQueryResults = docMgr.search(periodQuery, start);

        long count = 0;
        while (termQueryResults.hasNext()) {
            ++count;
            DocumentRecord record = termQueryResults.next();
            System.out.println("URI = " + record.getUri());

            DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
            record.getMetadata(metadataHandle);
            Iterator<String> resCollections = metadataHandle.getCollections().iterator();
            while (resCollections.hasNext()) {
                System.out.println("Collection = " + resCollections.next());
            }

            if (record.getFormat() == Format.XML) {
                DOMHandle recordHandle = new DOMHandle();
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());
            } else {
                JacksonDatabindHandle<ObjectNode> recordHandle = new JacksonDatabindHandle<ObjectNode>(
                        ObjectNode.class);
                record.getContent(recordHandle);
                System.out.println("Content = " + recordHandle.toString());

                JsonFactory factory = new JsonFactory();
                ObjectMapper mapper = new ObjectMapper(factory);
                TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
                };

                HashMap<String, Object> docObject = mapper.readValue(recordHandle.toString(), typeRef);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> systemNode = (HashMap<String, Object>) (docObject.get(systemNodeName));

                String systemStartDate = (String) systemNode.get(systemStartERIName);
                String systemEndDate = (String) systemNode.get(systemEndERIName);
                System.out.println("systemStartDate = " + systemStartDate);
                System.out.println("systemEndDate = " + systemEndDate);

                @SuppressWarnings("unchecked")
                HashMap<String, Object> validNode = (HashMap<String, Object>) (docObject.get(validNodeName));

                String validStartDate = (String) validNode.get(validStartERIName);
                String validEndDate = (String) validNode.get(validEndERIName);
                System.out.println("validStartDate = " + validStartDate);
                System.out.println("validEndDate = " + validEndDate);

                assertTrue("Valid start date check failed", (validStartDate.contains("2001-01-01T00:00:00")
                        && validEndDate.contains("2011-12-31T23:59:59")));

                assertTrue("System start date check failed", (systemStartDate.contains("2005-01-01T00:00:01")
                        && systemEndDate.contains("2010-01-01T00:00:01")));

            }
        }

        System.out.println("Number of results using SQB = " + count);
        assertEquals("Wrong number of results", 1, count);
    }

    @Test
    // Test LSQT Query using temporalLsqtQuery. Do the query as REST reader
    public void testLsqtQuery() throws Exception {
        System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.wire", "debug");

        ConnectedRESTQA.updateTemporalCollectionForLSQT(dbName, temporalLsqtCollectionName, true);

        // Read documents based on document URI and ALN Contains. We are just
        // looking for count of documents to be correct
        String docId = "javaSingleJSONDoc.json";

        Calendar insertTime = DatatypeConverter.parseDateTime("2005-01-01T00:00:01");
        insertJSONSingleDocument(temporalLsqtCollectionName, docId, null, null, insertTime);

        Calendar updateTime = DatatypeConverter.parseDateTime("2010-01-01T00:00:01");
        updateJSONSingleDocument(temporalLsqtCollectionName, docId, null, updateTime);

        Thread.sleep(2000);

        validateLSQTQueryData(readerClient);
    }

    @Test
    // Test LSQT Query using temporalLsqtQuery. Do the query as REST admin
    public void testLsqtQueryAsAdmin() throws Exception {
        System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.wire", "debug");

        ConnectedRESTQA.updateTemporalCollectionForLSQT(dbName, temporalLsqtCollectionName, true);

        // Read documents based on document URI and ALN Contains. We are just
        // looking for count of documents to be correct
        String docId = "javaSingleJSONDoc.json";

        Calendar insertTime = DatatypeConverter.parseDateTime("2005-01-01T00:00:01");

        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2001-01-01T00:00:00",
                "2011-12-31T23:59:59", "999 Skyway Park - JSON", docId);

        JSONDocumentManager docMgr = adminClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentMetadataHandle mh = setMetadata(false);
        docMgr.write(docId, mh, handle, null, null, temporalLsqtCollectionName, insertTime);

        Calendar updateTime = DatatypeConverter.parseDateTime("2010-01-01T00:00:01");
        docMgr.write(docId, mh, handle, null, null, temporalLsqtCollectionName, updateTime);

        Thread.sleep(2000);

        validateLSQTQueryData(adminClient);
    }

    @Test
    // Test inserting a temporal document and transform it using server-side Javascript
    public void testJSTransforms() throws Exception {
        // Now insert a JSON document
        System.out.println("In testJSONTransforms .. testing JSON transforms");
        String jsonDocId = "javaSingleJSONDoc.json";

        insertJSONSingleDocument(temporalCollectionName, jsonDocId, "timestampTransform");

        System.out.println("Out testJSONTransforms .. testing JSON transforms");
    }

    @Test
    // Negative test
    // Test inserting a JSON temporal document by specifying XML as the extension
    public void testInsertJSONDocumentUsingXMLExtension() throws Exception {
        // Now insert a JSON document
        String jsonDocId = "javaSingleJSONDoc.xml";

        boolean exceptionThrown = false;
        try {
            insertJSONSingleDocument(temporalCollectionName, jsonDocId, null);
        } catch (com.marklogic.client.FailedRequestException ex) {
            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("XDMP-NOMATCH"));
            assertTrue("Status code", (statusCode == 400));
        }

        assertTrue("Exception not thrown for invalid extension", exceptionThrown);
    }

    @Test
    // Negative test
    // Test inserting a temporal document into a non-existing temporal document
    public void testInsertJSONDocumentUsingNonExistingTemporalCollection() throws Exception {
        // Now insert a JSON document
        String jsonDocId = "javaSingleJSONDoc.json";

        boolean exceptionThrown = false;

        System.out.println("Inside testInsertJSONDocumentUsingNonExistingTemporalCollection");

        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2001-01-01T00:00:00",
                "2011-12-31T23:59:59", "999 Skyway Park - JSON", jsonDocId);

        JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentMetadataHandle mh = setMetadata(false);

        try {
            docMgr.write(jsonDocId, mh, handle, null, null, "invalidCollection");
        } catch (com.marklogic.client.FailedRequestException ex) {

            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("TEMPORAL-COLLECTIONNOTFOUND"));
            assertTrue("Status code", (statusCode == 400));
        }

        assertTrue("Exception not thrown for invalid temporal collection", exceptionThrown);
    }

    @Test
    // Negative test
    // Test inserting a temporal document into the "latest" collection. Operation should fail
    public void testDocumentUsingCollectionNamedLatest() throws Exception {
        // Now insert a JSON document
        String jsonDocId = "javaSingleJSONDoc.json";

        boolean exceptionThrown = false;

        System.out.println("Inside testDocumentUsingCollectionNamedLatest");

        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2001-01-01T00:00:00",
                "2011-12-31T23:59:59", "999 Skyway Park - JSON", jsonDocId);

        JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentMetadataHandle mh = setMetadata(false);

        try {
            docMgr.write(jsonDocId, mh, handle, null, null, latestCollectionName);
        } catch (com.marklogic.client.FailedRequestException ex) {
            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("TEMPORAL-COLLECTIONLATEST"));
            assertTrue("Status code", (statusCode == 400));
        }

        assertTrue("Exception not thrown for invalid temporal collection", exceptionThrown);
    }

    @Test
    // Negative test
    // Test inserting a temporal document as REST reader who does not have the privilege for the 
    // operation
    public void testInsertJSONDocumentUsingAsRESTReader() throws Exception {
        // Now insert a JSON document
        String jsonDocId = "javaSingleJSONDoc.json";

        boolean exceptionThrown = false;

        System.out.println("Inside testInsertJSONDocumentUsingNonExistingTemporalCollection");

        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2001-01-01T00:00:00",
                "2011-12-31T23:59:59", "999 Skyway Park - JSON", jsonDocId);

        JSONDocumentManager docMgr = readerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentMetadataHandle mh = setMetadata(false);

        try {
            docMgr.write(jsonDocId, mh, handle, null, null, temporalCollectionName);
        } catch (com.marklogic.client.ForbiddenUserException ex) {
            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("SEC-PRIV"));
            assertTrue("Status code", (statusCode == 403));
        }

        assertTrue("Exception not thrown for invalid temporal collection", exceptionThrown);
    }

    @Test
    // Negative test. 
    // Insert a temporal document whose Doc URI Id is the same as the temporal collection name
    public void testInsertDocumentUsingDocumentURIAsCollectionName() throws Exception {
        // Now insert a JSON document
        String jsonDocId = "javaSingleJSONDoc.json";

        System.out.println("Inside testInserDocumentUsingDocumentURIAsCollectionName");

        // First Create collection a collection with same name as doci URI
        ConnectedRESTQA.addElementRangeIndexTemporalCollection(dbName, jsonDocId, axisSystemName, axisValidName);

        // Insert a document called as insertJSONSingleDocument
        insertJSONSingleDocument(temporalCollectionName, jsonDocId, null);

        JacksonDatabindHandle<ObjectNode> handle = getJSONDocumentHandle("2001-01-01T00:00:00",
                "2011-12-31T23:59:59", "999 Skyway Park - JSON", jsonDocId);

        JSONDocumentManager docMgr = writerClient.newJSONDocumentManager();
        docMgr.setMetadataCategories(Metadata.ALL);

        // put meta-data
        DocumentMetadataHandle mh = setMetadata(false);

        boolean exceptionThrown = false;
        try {
            docMgr.write(jsonDocId, mh, handle, null, null, jsonDocId);
        } catch (com.marklogic.client.FailedRequestException ex) {
            String message = ex.getFailedRequest().getMessageCode();
            int statusCode = ex.getFailedRequest().getStatusCode();

            exceptionThrown = true;

            System.out.println(message);
            System.out.println(statusCode);

            assertTrue("Error Message", message.equals("TEMPORAL-CANNOT-URI"));
            assertTrue("Status code", (statusCode == 400));
        }

        ConnectedRESTQA.deleteElementRangeIndexTemporalCollection("Documents", jsonDocId);

        assertTrue("Exception not thrown for invalid temporal collection", exceptionThrown);
    }
}