de.escidoc.core.test.EscidocTestBase.java Source code

Java tutorial

Introduction

Here is the source code for de.escidoc.core.test.EscidocTestBase.java

Source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at license/ESCIDOC.LICENSE
 * or http://www.escidoc.de/license.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at license/ESCIDOC.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2006-2008 Fachinformationszentrum Karlsruhe Gesellschaft
 * fuer wissenschaftlich-technische Information mbH and Max-Planck-
 * Gesellschaft zur Foerderung der Wissenschaft e.V.  
 * All rights reserved.  Use is subject to license terms.
 */
package de.escidoc.core.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;
import javax.xml.XMLConstants;
import javax.xml.bind.DatatypeConverter;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import de.escidoc.core.test.common.client.servlet.om.*;
import de.escidoc.core.test.common.client.servlet.oum.OrganizationalUnitClient;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.xerces.dom.AttrImpl;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xpath.XPathAPI;
import org.escidoc.core.utils.io.MimeTypes;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.After;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;

import de.escidoc.core.test.common.AssignParam;
import de.escidoc.core.test.common.client.servlet.Constants;
import de.escidoc.core.test.common.client.servlet.adm.AdminClient;
import de.escidoc.core.test.common.client.servlet.interfaces.ResourceHandlerClientInterface;
import de.escidoc.core.test.common.client.servlet.st.StagingFileClient;
import de.escidoc.core.test.common.resources.PropertiesProvider;
import de.escidoc.core.test.common.resources.ResourceProvider;
import de.escidoc.core.test.common.util.xml.SchemaBaseResourceResolver;
import de.escidoc.core.test.om.OmTestBase;
import de.escidoc.core.test.security.client.PWCallback;
import de.escidoc.core.test.st.StagingFileTestBase;
import de.escidoc.core.test.utils.DateTimeJaxbConverter;
import etm.core.configuration.EtmManager;
import etm.core.monitor.EtmMonitor;
import etm.core.monitor.EtmPoint;

/**
 * Base class for Escidoc tests.
 * 
 * @author Michael Schneider
 */
public abstract class EscidocTestBase {

    public static final String VERSION_SUFFIX_SEPARATOR = ":";

    private static final String NAME_USER_ACCOUNT_LIST = "user-account-list";

    public static final String NAME_USER_ACCOUNT = "user-account";

    public static final String NAME_ATTRIBUTE = "attribute";

    private static final String NAME_USER_GROUP_LIST = "user-group-list";

    public static final String NAME_USER_GROUP = "user-group";

    private static final String NAME_SET_DEFINITION = "set-definition";

    public static final String NAME_LATEST_VERSION = "latest-version";

    public static final String NAME_AGG_DEF = "aggregation-definition";

    public static final String NAME_REP_DEF = "report-definition";

    public static final String NAME_SCOPE = "scope";

    private static Map<String, URL> urlCache = new HashMap<String, URL>();

    private static Map<URL, Schema> schemaCache = new HashMap<URL, Schema>();

    public static final String DEFAULT_CHARSET = "UTF-8";

    private static final Pattern PATTERN_ID_WITHOUT_VERSION = Pattern.compile("([a-zA-Z]+:[0-9]+):[0-9]+");

    private static final Logger LOGGER = LoggerFactory.getLogger(EscidocTestBase.class);

    protected static final EtmMonitor ETM_MONITOR = EtmManager.getEtmMonitor();

    private StagingFileClient stagingFileClient = null;

    /**
     * Id of a persistent content type object.
     */
    protected static final String CONTENT_TYPE_ID = "escidoc:persistent4";

    /**
     * Id of a persistent context object.
     */
    protected static final String CONTEXT_ID = "escidoc:persistent3";

    /**
     * another Id of a persistent context object.
     */
    protected static final String CONTEXT_ID1 = "escidoc:persistent23";

    /**
     * another Id of a persistent context object.
     */
    protected static final String CONTEXT_ID2 = "escidoc:persistent5";

    /**
     * another Id of a persistent context object.
     */
    protected static final String CONTEXT_ID3 = "escidoc:persistent10";

    /**
     * Id of a persistent statistic-scope.
     */
    protected static final String STATISTIC_SCOPE_ID = "escidoc:scope3";

    /**
     * Id of a persistent statistic-scope.
     */
    protected static final String STATISTIC_SCOPE_ID1 = "escidoc:scope4";

    /**
     * Id of a persistent org unit object.
     */
    protected static final String ORGANIZATIONAL_UNIT_ID = "escidoc:persistent11";

    /**
     * Id of a persistent org unit object.
     */
    protected static final String ORGANIZATIONAL_UNIT_ID1 = "escidoc:persistent1";

    /**
     * Id of a persistent user-group object containing a list of users.
     */
    protected static final String USER_GROUP_WITH_USER_LIST_ID = "escidoc:testgroupwithuser";

    /**
     * Id of a persistent user-group object containing a list of ous.
     */
    protected static final String USER_GROUP_WITH_OU_LIST_ID = "escidoc:testgroupwithorgunit";

    /**
     * Id of a persistent user-group object containing a list of groups.
     */
    protected static final String USER_GROUP_WITH_GROUP_LIST_ID = "escidoc:testgroupwithgroup";

    /**
     * Id of a persistent user-group object containing an attribute selector.
     */
    protected static final String USER_GROUP_WITH_EXTERNAL_SELECTOR = "escidoc:testgroupwithexternalselector";

    protected static final String TEST_SYSTEMADMINISTRATOR_ID1 = "escidoc:testsystemadministrator1";

    protected static final String TEST_USER_ACCOUNT_ID = "escidoc:test";

    protected static final String TEST_USER_ACCOUNT_ID1 = "escidoc:test1";

    protected static final String TEST_DEPOSITOR_ACCOUNT_ID = "escidoc:testdepositor";

    protected static final String TEST_USER_GROUP_ID = "escidoc:testgroup";

    /**
     * Id of a persistent aggregation-definition.
     */
    protected static final String TEST_AGGREGATION_DEFINITION_ID = "escidoc:aggdef1";

    /**
     * Pattern to detect place holder in Velocity templates that are not replaced by values.
     */
    private static final Pattern PATTERN_VELOCITY_PLACEHOLDER = Pattern.compile("\\$\\{.*?\\}");

    private static final Pattern PATTERN_VELOCITY_PLACEHOLDER2 = Pattern.compile("\\$esc\\.");

    public static final Pattern PATTERN_OBJID_ATTRIBUTE = Pattern.compile("objid=\"([^\"]*)\"");

    /**
     * Pattern used in modfyNamespacePrefixes to find and replace prefixes.
     */
    private static final Pattern PATTERN_MODIFY_NAMESPACE_PREFIXES_REPLACE_PREFIXES = Pattern
            .compile("(</{0,1}|[\\s])([a-zA-Z-]+?:[^ =/>]+)", Pattern.DOTALL | Pattern.MULTILINE);

    /**
     * Pattern used in modfyNamespacePrefixes to fix namespace declarations after changing prefixes.
     */
    private static final Pattern PATTERN_MODIFY_NAMESPACE_PREFIXES_FIX_NAMESPACE_DECLARATIONS = Pattern
            .compile("prefix-xmlns:([a-zA-Z-].+?)", Pattern.DOTALL | Pattern.MULTILINE);

    /**
     * Pattern used in modfyNamespacePrefixes to fix xml namespace declaration.
     */
    private static final Pattern PATTERN_MODIFY_NAMESPACE_PREFIXES_FIX_PREFIX_XML = Pattern.compile("prefix-xml");

    public static final String STATE_PENDING = "pending";

    public static final String STATE_IN_REVISION = "in-revision";

    public static final String STATE_SUBMITTED = "submitted";

    public static final String STATE_RELEASED = "released";

    public static final String STATE_WITHDRAWN = "withdrawn";

    public static final String STATE_LOCKED = "locked";

    public static final String STATE_UNLOCKED = "unlocked";

    public static final String NAME_ALTERNATIVE = "alternative";

    public static final String NAME_START_DATE = "start-date";

    public static final String NAME_END_DATE = "end-date";

    public static final String NAME_BASE = "base";

    public static final String NAME_CITY = "city";

    public static final String NAME_COMPONENT = "component";

    public static final String NAME_COMPONENTS = "components";

    public static final String NAME_COUNTRY = "country";

    public static final String NAME_CREATION_DATE = "creation-date";

    public static final String NAME_CURRENT_GRANTS = "current-grants";

    public static final String NAME_VERSION = "version";

    public static final String NAME_LATEST_RELEASE = "latest-release";

    public static final String NAME_CREATED_BY = "created-by";

    public static final String NAME_MD_RECORDS = "md-records";

    public static final String NAME_MD_RECORD = "md-record";

    public static final String NAME_DESCRIPTION = "description";

    public static final String NAME_IDENTIFIER = "identifier";

    public static final String NAME_FAX = "fax";

    public static final String NAME_GEO_COORDINATE = "geo-coordinate";

    public static final String NAME_GRANT_REMARK = "grant-remark";

    public static final String NAME_HAS_CHILDREN = "has-children";

    public static final String NAME_HREF = "href";

    public static final String NAME_ITEM = "item";

    public static final String XPATH_ITEM = "/" + NAME_ITEM;

    public static final String NAME_CONTAINER = "container";

    public static final String NAME_CONTENT_MODEL = "content-model";

    public static final String NAME_CONTENT_RELATION = "content-relation";

    public static final String NAME_GRANT = "grant";

    public static final String NAME_LAST_MODIFICATION_DATE = "last-modification-date";

    public static final String NAME_LOCATION_LATITUDE = "location-latitude";

    public static final String NAME_LOCATION_LONGITUDE = "location-longitude";

    public static final String NAME_MODIFIED_BY = "modified-by";

    public static final String NAME_NAME = "name";

    public static final String NAME_OBJID = "objid";

    public static final String NAME_ORGANIZATIONAL_UNIT = "organizational-unit";

    public static final String NAME_ORGANIZATIONAL_UNITS = "organizational-units";

    public static final String NAME_PARENT = "parent";

    public static final String NAME_PARENTS = "parents";

    public static final String NAME_POSTCODE = "postcode";

    public static final String NAME_PROPERTIES = "properties";

    public static final String NAME_PUBLIC_STATUS = "public-status";

    public static final String NAME_PUBLIC_STATUS_COMMENT = "public-status-comment";

    public static final String NAME_CONTEXT = "context";

    public static final String NAME_REGION = "region";

    public static final String NAME_RESOURCES = "resources";

    public static final String NAME_ROLE = "role";

    public static final String NAME_TELEPHONE = "telephone";

    public static final String NAME_TITLE = "title";

    public static final String NAME_URI = "uri";

    public static final String NAME_VERSION_STATUS = "status";

    public static final String NAME_ORGANIZATION_TYPE = "organization-type";

    public static final String NAME_TYPE = "type";

    public static final String PART_LAST_MODIFICATION_DATE = "/@" + NAME_LAST_MODIFICATION_DATE;

    public static final String PART_OBJID = "/@objid";

    public static final String PART_XLINK_TITLE = "/@title";

    public static final String PART_XLINK_TYPE = "/@type";

    public static final String PART_XLINK_HREF = "/@href";

    public static final String PART_XML_BASE = "/@" + NAME_BASE;

    public static final String PART_XLINK_NS = "/@xlink";

    public static final String GRANTS_PREFIX_TEMPLATES = "prefix-grants";

    public static final String GRANTS_PREFIX_ESCIDOC = "grants";

    public static final String ORGANIZATIONAL_UNIT_PREFIX_TEMPLATES = "prefix-organizational-unit";

    public static final String ORGANIZATIONAL_UNIT_PREFIX_ESCIDOC = "organizational-unit";

    public static final String ROLE_PREFIX_TEMPLATES = "prefix-role";

    public static final String ROLE_PREFIX_ESCIDOC = "role";

    public static final String SREL_PREFIX_TEMPLATES = "prefix-srel";

    public static final String SREL_PREFIX_ESCIDOC = "srel";

    public static final String USER_ACCOUNT_PREFIX_TEMPLATES = "prefix-user-account";

    public static final String USER_GROUP_PREFIX_TEMPLATES = "prefix-user-group";

    public static final String USER_ACCOUNT_PREFIX_ESCIDOC = NAME_USER_ACCOUNT;

    public static final String USER_GROUP_PREFIX_ESCIDOC = NAME_USER_GROUP;

    public static final String CONTAINER_NS_URI = "http://www.escidoc.de/schemas/container/0.7";

    public static final String PROPERTIES_NS_URI_04 = "http://escidoc.de/core/01/properties/";

    public static final String PROPERTIES_FILTER_PREFIX = "/properties/";

    public static final String RDF_NS_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";

    public static final String RDF_TYPE_NS_URI = RDF_NS_URI + "type";

    public static final String STRUCTURAL_RELATIONS_NS_URI = "http://escidoc.de/core/01/structural-relations/";

    public static final String STRUCTURAL_RELATIONS_FILTER_PREFIX = "/structural-relations/";

    public static final String RESOURCES_NS_URI = "http://escidoc.de/core/01/resources/";

    public static final String TYPE_FEDORA_OBJECT_URI = "info:fedora/fedora-system:def/model#FedoraObject";

    public static final String CONTEXT_NS_URI = "http://www.escidoc.de/schemas/context/0.6";

    public static final String CONTENT_TYPE_NS_URI = "http://www.escidoc.de/schemas/content-type/0.2";

    public static final String DC_NS_URI = "http://purl.org/dc/elements/1.1/";

    public static final String DCTERMS_NS_URI = "http://purl.org/dc/terms/";

    public static final String GRANTS_NS_URI = "http://www.escidoc.de/schemas/grants/0.5";

    public static final String INTERNAL_METADATA_NS_URI = "http://www.escidoc.de/schemas/internalmetadata/0.2";

    public static final String ITEM_NS_URI = "http://www.escidoc.de/schemas/item/0.6";

    public static final String COMPONENTS_NS_URI = "http://www.escidoc.de/schemas/components/0.7";

    public static final String ITEM_PREFIX_TEMPLATES = "prefix-escidocItem";

    public static final String MEMBER_LIST_NS_URI = "http://www.escidoc.de/schemas/memberlist/0.6";

    public static final String MEMBER_REF_LIST_NS_URI = "http://www.escidoc.de/schemas/memberreflist/0.2";

    public static final String METADATARECORDS_NS_URI = "http://www.escidoc.de/schemas/metadatarecords/0.2";

    public static final String METADATA_NS_URI = "http://www.escidoc.de/schemas/metadata/0.2";

    public static final String ORGANIZATIONAL_UNIT_NS_URI = "http://www.escidoc.de/schemas/organizationalunit/0.8";

    public static final String PROPERTIES_NS_URI = "http://www.escidoc.de/schemas/properties/0.2";

    public static final String RELATIONS_NS_URI = "http://www.escidoc.de/schemas/relations/0.2";

    public static final String REQUESTS_NS_URI = "http://www.escidoc.de/schemas/pdp/0.2/requests";

    public static final String RESULTS_NS_URI = "http://www.escidoc.de/schemas/pdp/0.2/results";

    public static final String ROLE_NS_URI = "http://www.escidoc.de/schemas/role/0.2";

    public static final String SREL_NS_URI = "http://escidoc.de/core/01/structural-relations/";

    public static final String STAGING_FILE_NS_URI = "http://www.escidoc.de/schemas/stagingfile/0.2";

    public static final String SCHEMA_NS_URI = "http://www.escidoc.de/schemas/xml-schema/0.2";

    public static final String STRUCT_MAP_NS_URI = "http://www.escidoc.de/schemas/structmap/0.4";

    public static final String USER_ACCOUNT_NS_URI = "http://www.escidoc.de/schemas/useraccount/0.7";

    public static final String USER_ACCOUNT_PREFERENCE_NS_URI = "http://www.escidoc.de/schemas/preferences/0.1";

    public static final String USER_ACCOUNT_ATTRIBUTE_NS_URI = "http://www.escidoc.de/schemas/attributes/0.1";

    public static final String USER_GROUP_NS_URI = "http://www.escidoc.de/schemas/usergroup/0.6";

    public static final String XACML_CONTEXT_NS_URI = "urn:oasis:names:tc:xacml:1.0:context";

    public static final String XACML_POLICY_NS_URI = "urn:oasis:names:tc:xacml:1.0:policy";

    public static final String XLINK_NS_URI = "http://www.w3.org/1999/xlink";

    public static final String XML_NS_URI = "http://www.w3.org/XML/1998/namespace";

    public static final String XSI_NS_URI = "http://www.w3.org/2001/XMLSchema-instance";

    public static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";

    public static final String UNKNOWN_ID = "escidoc:-1";

    public static final String TEMPLATE_BASE_PATH = "templates";

    public static final String TEMPLATE_EXAMPLE_PATH = "examples/escidoc";

    public static final String TEMPLATE_AA_PATH = TEMPLATE_BASE_PATH + "/aa/template";

    public static final String TEMPLATE_ST_PATH = TEMPLATE_BASE_PATH + "/st/template";

    public static final String TEMPLATE_REQUESTS_PATH = TEMPLATE_AA_PATH + "/requests";

    public static final String TEMPLATE_AA_ITEM_PATH = TEMPLATE_AA_PATH + "/item";

    public static final String TEMPLATE_ROLE_PATH = TEMPLATE_AA_PATH + "/role";

    public static final String TEMPLATE_CMM_PATH = TEMPLATE_BASE_PATH + "/cmm/template";

    public static final String TEMPLATE_OM_PATH = TEMPLATE_BASE_PATH + "/om/template";

    public static final String TEMPLATE_OAI_PATH = TEMPLATE_BASE_PATH + "/oai/template";

    public static final String TEMPLATE_OUM_PATH = TEMPLATE_BASE_PATH + "/oum/template";

    public static final String TEMPLATE_ADMIN_DESCRIPTOR_PATH = TEMPLATE_OM_PATH + "/admindescriptor";

    public static final String TEMPLATE_OM_COMMON_PATH = TEMPLATE_OM_PATH + "/common";

    public static final String TEMPLATE_CONTAINER_PATH = TEMPLATE_OM_PATH + "/container";

    public static final String TEMPLATE_CONTAINER_SEARCH_PATH = TEMPLATE_CONTAINER_PATH + "/search";

    public static final String TEMPLATE_XML_SCHEMA_PATH = TEMPLATE_OM_PATH + "/xmlschema";

    public static final String TEMPLATE_CONTEXT_PATH = TEMPLATE_OM_PATH + "/context";

    public static final String TEMPLATE_CONTENT_MODEL_PATH = TEMPLATE_CMM_PATH + "/content-model";

    public static final String TEMPLATE_CONTEXT_VERSION = "0.4";

    public static final String TEMPLATE_ITEM_PATH = TEMPLATE_OM_PATH + "/item";

    public static final String TEMPLATE_ITEM_SEARCH_PATH = TEMPLATE_ITEM_PATH + "/search";

    public static final String TEMPLATE_ITEM_SEARCH_ADMIN_PATH = TEMPLATE_ITEM_SEARCH_PATH + "/admin";

    public static final String TEMPLATE_INGEST_PATH = TEMPLATE_OM_PATH + "/ingest";

    public static final String TEMPLATE_LANGUAGE_ITEMS_PATH = TEMPLATE_ITEM_PATH + "/language";

    public static final String TEMPLATE_TME_PATH = TEMPLATE_BASE_PATH + "/tme/template/tme/0.1";

    public static final String TEMPLATE_LICENSE_TYPE_PATH = TEMPLATE_OM_PATH + "/licensetype";

    public static final String TEMPLATE_ORGANIZATIONAL_UNIT_PATH = TEMPLATE_OUM_PATH + "/organizationalunit/0.8";

    public static final String TEMPLATE_SB_PATH = TEMPLATE_BASE_PATH + "/sb/template";

    public static final String TEMPLATE_SB_ORGANIZATIONAL_UNIT_PATH = TEMPLATE_SB_PATH + "/organizationalunit";

    public static final String TEMPLATE_SB_CONTEXT_PATH = TEMPLATE_SB_PATH + "/context";

    public static final String TEMPLATE_SB_CONTENT_MODEL_PATH = TEMPLATE_SB_PATH + "/contentmodel";

    public static final String TEMPLATE_SB_CONTENT_RELATION_PATH = TEMPLATE_SB_PATH + "/contentrelation";

    public static final String TEMPLATE_USER_ACCOUNT_PATH = TEMPLATE_AA_PATH + "/useraccount";

    public static final String TEMPLATE_USER_GROUP_PATH = TEMPLATE_AA_PATH + "/usergroup";

    public static final String TEMPLATE_SET_DEFINITION_PATH = TEMPLATE_OAI_PATH + "/setdefinition";

    public static final String TEMPLATE_SM_PATH = TEMPLATE_BASE_PATH + "/sm/template";

    public static final String TEMPLATE_STAT_DATA_PATH = TEMPLATE_SM_PATH + "/statisticdata";

    public static final String TEMPLATE_AGG_DEF_PATH = TEMPLATE_SM_PATH + "/aggregationdefinition";

    public static final String TEMPLATE_REP_DEF_PATH = TEMPLATE_SM_PATH + "/reportdefinition";

    public static final String TEMPLATE_REPORT_PATH = TEMPLATE_SM_PATH + "/report";

    public static final String TEMPLATE_SCOPE_PATH = TEMPLATE_SM_PATH + "/scope";

    public static final String TEMPLATE_REP_PARAMETERS_PATH = TEMPLATE_SM_PATH + "/reportparameters";

    public static final String TEMPLATE_PREPROCESSING_INFO_PATH = TEMPLATE_SM_PATH + "/preprocessinginformation";

    public static final String TEMPLATE_ST_ITEM_PATH = TEMPLATE_ST_PATH + "/item";

    public static final String ESCIDOC_OBJECTS_SAVE_PATH = "build/escidoc";

    public static final String VAR_COMPONENT_ID = "\\$\\{COMPONENT_ID\\}";

    public static final String VAR_MD_RECORD_NAME = "\\$\\{MD_RECORD_NAME\\}";

    public static final String STATUS_PENDING = "pending";

    public static final String STATUS_SUBMITTED = "submitted";

    public static final String STATUS_IN_REVISION = "in-revision";

    public static final String STATUS_RELEASED = "released";

    public static final String STATUS_WITHDRAWN = "withdrawn";

    public static final String CONTEXT_STATUS_CREATED = "created";

    public static final String CONTEXT_STATUS_OPENED = "opened";

    public static final String CONTEXT_STATUS_CLOSED = "closed";

    public static final String CONTEXT_STATUS_DELETED = "deleted";

    public static final String CONTENT_MODEL_STATUS_CREATED = "created";

    public static final String CONTENT_MODEL_STATUS_UPDATED = "updated";

    public static final String CONTENT_MODEL_STATUS_DELETED = "deleted";

    public static final String ORGANIZATIONAL_UNIT_STATUS_CREATED = "created";

    public static final String ORGANIZATIONAL_UNIT_STATUS_OPENED = "opened";

    public static final String ORGANIZATIONAL_UNIT_STATUS_CLOSED = "closed";

    public static final String ORGANIZATIONAL_UNIT_STATUS_DELETED = "deleted";

    protected static final String WITHDRAW_COMMENT = "This is a &lt; withdraw comment.";

    private static Schema resourcesSchema;

    protected static Schema stagingFileSchema;

    protected static String startTimestamp = getNowAsTimestamp();

    /**
     * Xlink namespace prefix in templates.
     */
    public static final String XLINK_PREFIX_TEMPLATES = "prefix-xlink";

    /**
     * Xlink namespace prefix in documents retrieved from the eSciDoc.
     */
    public static final String XLINK_PREFIX_ESCIDOC = "xlink";

    /**
     * Xlink namespace declaration in templates.
     */
    public static final String XLINK_NS_DECL_TEPLATES = "xmlns:" + XLINK_PREFIX_TEMPLATES + "=\"" + XLINK_NS_URI
            + "\" ";

    /**
     * Xlink namespace declaration in documents retrieved from the eSciDoc.
     */
    public static final String XLINK_NS_DECL_ESCIDOC = "xmlns:" + XLINK_PREFIX_ESCIDOC + "=\"" + XLINK_NS_URI
            + "\" ";

    /**
     * Prefix and name of xlink href attribute in templates.
     */
    public static final String XLINK_HREF_TEMPLATES = XLINK_PREFIX_TEMPLATES + ":href";

    /**
     * Prefix and name of xlink href attribute in documents retrieved from the eSciDoc.
     */
    public static final String XLINK_HREF_ESCIDOC = XLINK_PREFIX_ESCIDOC + ":href";

    /**
     * Prefix and name of objid attribute in documents retrieved from the eSciDoc.
     */
    public static final String ID_ESCIDOC = "objid";

    /**
     * Prefix and name of xlink title attribute in templates.
     */
    public static final String XLINK_TITLE_TEMPLATES = XLINK_PREFIX_TEMPLATES + ":title";

    /**
     * Prefix and name of xlink title attribute in documents retrieved from the eSciDoc.
     */
    public static final String XLINK_TITLE_ESCIDOC = XLINK_PREFIX_ESCIDOC + ":title";

    /**
     * Prefix and name of xlink type attribute in templates.
     */
    public static final String XLINK_TYPE_TEMPLATES = XLINK_PREFIX_TEMPLATES + ":type";

    /**
     * Prefix and name of xlink type attribute in documents retrieved from the eSciDoc.
     */
    public static final String XLINK_TYPE_ESCIDOC = XLINK_PREFIX_ESCIDOC + ":type";

    public static final String XPATH_ATTRIBUTE = "/" + NAME_ATTRIBUTE;

    public static final String XPATH_RESOURCES = "/resources";

    public static final String XPATH_RESOURCES_BASE = XPATH_RESOURCES + "/@" + NAME_BASE;

    public static final String XPATH_RESOURCES_XLINK_HREF = XPATH_RESOURCES + "/@" + NAME_HREF;

    public static final String XPATH_RESOURCES_XLINK_TITLE = XPATH_RESOURCES + "/@" + NAME_TITLE;

    public static final String XPATH_RESOURCES_XLINK_TYPE = XPATH_RESOURCES + "/@" + NAME_TYPE;

    public static final String XPATH_RESOURCES_CURRENT_GRANTS = XPATH_RESOURCES + "/" + NAME_CURRENT_GRANTS;

    public static final String XPATH_RESOURCES_CURRENT_GRANTS_XLINK_HREF = XPATH_RESOURCES_CURRENT_GRANTS + "/@"
            + NAME_HREF;

    public static final String XPATH_RESOURCES_CURRENT_GRANTS_XLINK_TYPE = XPATH_RESOURCES_CURRENT_GRANTS + "/@"
            + NAME_TYPE;

    public static final String XPATH_RESOURCES_CURRENT_GRANTS_XLINK_TITLE = XPATH_RESOURCES_CURRENT_GRANTS + "/@"
            + NAME_TITLE;

    public static final String XPATH_USER_ACCOUNT = "/" + NAME_USER_ACCOUNT;

    public static final String XPATH_USER_ACCOUNT_LIST = "/" + NAME_USER_ACCOUNT_LIST;

    public static final String XPATH_USER_ACCOUNT_LIST_USER_ACCOUNT = XPATH_USER_ACCOUNT_LIST + "/"
            + NAME_USER_ACCOUNT;

    public static final String XPATH_USER_ACCOUNT_OBJID = XPATH_USER_ACCOUNT + "/@objid";

    public static final String XPATH_USER_ACCOUNT_XLINK_TITLE = XPATH_USER_ACCOUNT + "/@title";

    public static final String XPATH_USER_ACCOUNT_LAST_MOD_DATE = XPATH_USER_ACCOUNT + "/@last-modification-date";

    public static final String XPATH_USER_ACCOUNT_XLINK_TYPE = XPATH_USER_ACCOUNT + "/@type";

    public static final String XPATH_USER_ACCOUNT_XLINK_HREF = XPATH_USER_ACCOUNT + "/@href";

    public static final String XPATH_USER_ACCOUNT_PROPERTIES = XPATH_USER_ACCOUNT + "/properties";

    public static final String XPATH_USER_ACCOUNT_CREATED_BY = XPATH_USER_ACCOUNT_PROPERTIES + "/"
            + NAME_CREATED_BY;

    public static final String XPATH_USER_ACCOUNT_MODIFIED_BY = XPATH_USER_ACCOUNT_PROPERTIES + "/"
            + NAME_MODIFIED_BY;

    public static final String XPATH_USER_ACCOUNT_MODIFIED_BY_OBJID = XPATH_USER_ACCOUNT_MODIFIED_BY + "/@"
            + NAME_OBJID;

    public static final String XPATH_USER_ACCOUNT_MODIFIED_BY_XLINK_HREF = XPATH_USER_ACCOUNT_MODIFIED_BY + "/@"
            + NAME_HREF;

    public static final String XPATH_USER_ACCOUNT_MODIFIED_BY_XLINK_TITLE = XPATH_USER_ACCOUNT_MODIFIED_BY + "/@"
            + NAME_TITLE;

    public static final String XPATH_USER_ACCOUNT_MODIFIED_BY_XLINK_TYPE = XPATH_USER_ACCOUNT_MODIFIED_BY + "/@"
            + NAME_TYPE;

    public static final String XPATH_USER_ACCOUNT_CREATED_BY_OBJID = XPATH_USER_ACCOUNT_CREATED_BY + "/@"
            + NAME_OBJID;

    public static final String XPATH_USER_ACCOUNT_CREATED_BY_XLINK_HREF = XPATH_USER_ACCOUNT_CREATED_BY + "/@"
            + NAME_HREF;

    public static final String XPATH_USER_ACCOUNT_CREATED_BY_XLINK_TITLE = XPATH_USER_ACCOUNT_CREATED_BY + "/@"
            + NAME_TITLE;

    public static final String XPATH_USER_ACCOUNT_CREATED_BY_XLINK_TYPE = XPATH_USER_ACCOUNT_CREATED_BY + "/@"
            + NAME_TYPE;

    public static final String XPATH_USER_ACCOUNT_CREATION_DATE = XPATH_USER_ACCOUNT_PROPERTIES + "/creation-date";

    public static final String XPATH_USER_ACCOUNT_RESOURCES = XPATH_USER_ACCOUNT + "/" + NAME_RESOURCES;

    public static final String XPATH_USER_ACCOUNT_RESOURCES_XLINK_HREF = XPATH_USER_ACCOUNT_RESOURCES
            + PART_XLINK_HREF;

    public static final String XPATH_USER_ACCOUNT_RESOURCES_XLINK_TITLE = XPATH_USER_ACCOUNT_RESOURCES
            + PART_XLINK_TITLE;

    public static final String XPATH_USER_ACCOUNT_RESOURCES_XLINK_TYPE = XPATH_USER_ACCOUNT_RESOURCES
            + PART_XLINK_TYPE;

    public static final String XPATH_USER_ACCOUNT_CURRENT_GRANTS = XPATH_USER_ACCOUNT_RESOURCES + "/"
            + NAME_CURRENT_GRANTS;

    public static final String XPATH_USER_ACCOUNT_CURRENT_GRANTS_XLINK_TYPE = XPATH_USER_ACCOUNT_CURRENT_GRANTS
            + PART_XLINK_TYPE;

    public static final String XPATH_USER_ACCOUNT_ACTIVE = XPATH_USER_ACCOUNT_PROPERTIES + "/active";

    public static final String XPATH_USER_ACCOUNT_LOGINNAME = XPATH_USER_ACCOUNT_PROPERTIES + "/login-name";

    public static final String XPATH_USER_ACCOUNT_NAME = XPATH_USER_ACCOUNT_PROPERTIES + "/name";

    public static final String XPATH_USER_GROUP = "/" + NAME_USER_GROUP;

    public static final String XPATH_SET_DEFINITION = "/" + NAME_SET_DEFINITION;

    public static final String XPATH_SRW_RESPONSE_ROOT = "/searchRetrieveResponse";

    public static final String XPATH_SRW_RESPONSE_RECORD = XPATH_SRW_RESPONSE_ROOT + "/records/record";

    public static final String XPATH_SRW_RESPONSE_OBJECT_SUBPATH = "/recordData/search-result-record/";

    public static final String XPATH_SRW_RESPONSE_OBJECT = XPATH_SRW_RESPONSE_RECORD
            + XPATH_SRW_RESPONSE_OBJECT_SUBPATH;

    public static final String XPATH_USER_GROUP_LIST = "/" + NAME_USER_GROUP_LIST;

    public static final String XPATH_USER_GROUP_LIST_USER_GROUP = XPATH_USER_GROUP_LIST + "/" + NAME_USER_GROUP;

    public static final String XPATH_SRW_USER_GROUP_LIST_USER_GROUP = XPATH_SRW_RESPONSE_OBJECT + NAME_USER_GROUP;

    public static final String XPATH_SRW_CONTAINER_LIST_CONTAINER = XPATH_SRW_RESPONSE_OBJECT + NAME_CONTAINER;

    public static final String XPATH_SRW_ITEM_LIST_ITEM = XPATH_SRW_RESPONSE_OBJECT + NAME_ITEM;

    public static final String XPATH_SRW_SET_DEFINITION_LIST_SET_DEFINITION = XPATH_SRW_RESPONSE_OBJECT
            + NAME_SET_DEFINITION;

    public static final String XPATH_SRW_ORGANIZATIONAL_UNIT_LIST_ORGANIZATIONAL_UNIT = XPATH_SRW_RESPONSE_OBJECT
            + NAME_ORGANIZATIONAL_UNIT;

    public static final String XPATH_SRW_CONTENT_MODEL_LIST_CONTENT_MODEL = XPATH_SRW_RESPONSE_OBJECT
            + NAME_CONTENT_MODEL;

    public static final String XPATH_USER_GROUP_OBJID = XPATH_USER_GROUP + "/@objid";

    public static final String XPATH_USER_GROUP_XLINK_TITLE = XPATH_USER_GROUP + "/@title";

    public static final String XPATH_USER_GROUP_LAST_MOD_DATE = XPATH_USER_GROUP + "/@last-modification-date";

    public static final String XPATH_USER_GROUP_XLINK_TYPE = XPATH_USER_GROUP + "/@type";

    public static final String XPATH_USER_GROUP_XLINK_HREF = XPATH_USER_GROUP + "/@href";

    public static final String XPATH_USER_GROUP_PROPERTIES = XPATH_USER_GROUP + "/properties";

    public static final String XPATH_USER_GROUP_SELECTORS = XPATH_USER_GROUP + "/selectors";

    public static final String XPATH_USER_GROUP_SELECTOR = XPATH_USER_GROUP + "/selectors/selector";

    public static final String XPATH_USER_GROUP_CREATED_BY = XPATH_USER_GROUP_PROPERTIES + "/" + NAME_CREATED_BY;

    public static final String XPATH_USER_GROUP_MODIFIED_BY = XPATH_USER_GROUP_PROPERTIES + "/" + NAME_MODIFIED_BY;

    public static final String XPATH_USER_GROUP_MODIFIED_BY_OBJID = XPATH_USER_GROUP_MODIFIED_BY + "/@"
            + NAME_OBJID;

    public static final String XPATH_USER_GROUP_MODIFIED_BY_XLINK_HREF = XPATH_USER_GROUP_MODIFIED_BY + "/@"
            + NAME_HREF;

    public static final String XPATH_USER_GROUP_MODIFIED_BY_XLINK_TITLE = XPATH_USER_GROUP_MODIFIED_BY + "/@"
            + NAME_TITLE;

    public static final String XPATH_USER_GROUP_MODIFIED_BY_XLINK_TYPE = XPATH_USER_GROUP_MODIFIED_BY + "/@"
            + NAME_TYPE;

    public static final String XPATH_USER_GROUP_CREATED_BY_OBJID = XPATH_USER_GROUP_CREATED_BY + "/@" + NAME_OBJID;

    public static final String XPATH_USER_GROUP_CREATED_BY_XLINK_HREF = XPATH_USER_GROUP_CREATED_BY + "/@"
            + NAME_HREF;

    public static final String XPATH_USER_GROUP_CREATED_BY_XLINK_TITLE = XPATH_USER_GROUP_CREATED_BY + "/@"
            + NAME_TITLE;

    public static final String XPATH_USER_GROUP_CREATED_BY_XLINK_TYPE = XPATH_USER_GROUP_CREATED_BY + "/@"
            + NAME_TYPE;

    public static final String XPATH_USER_GROUP_CREATION_DATE = XPATH_USER_GROUP_PROPERTIES + "/creation-date";

    public static final String XPATH_USER_GROUP_RESOURCES = XPATH_USER_GROUP + "/" + NAME_RESOURCES;

    public static final String XPATH_USER_GROUP_RESOURCES_XLINK_HREF = XPATH_USER_GROUP_RESOURCES + PART_XLINK_HREF;

    public static final String XPATH_USER_GROUP_RESOURCES_XLINK_TITLE = XPATH_USER_GROUP_RESOURCES
            + PART_XLINK_TITLE;

    public static final String XPATH_USER_GROUP_RESOURCES_XLINK_TYPE = XPATH_USER_GROUP_RESOURCES + PART_XLINK_TYPE;

    public static final String XPATH_USER_GROUP_CURRENT_GRANTS = XPATH_USER_GROUP_RESOURCES + "/"
            + NAME_CURRENT_GRANTS;

    public static final String XPATH_USER_GROUP_CURRENT_GRANTS_XLINK_TYPE = XPATH_USER_GROUP_CURRENT_GRANTS
            + PART_XLINK_TYPE;

    public static final String XPATH_USER_GROUP_ACTIVE = XPATH_USER_GROUP_PROPERTIES + "/active";

    public static final String XPATH_USER_GROUP_NAME = XPATH_USER_GROUP_PROPERTIES + "/name";

    public static final String XPATH_USER_GROUP_LABEL = XPATH_USER_GROUP_PROPERTIES + "/label";

    public static final String XPATH_GRANT = "/grant";

    public static final String XPATH_GRANT_PROPERTIES = XPATH_GRANT + "/" + NAME_PROPERTIES;

    public static final String XPATH_GRANT_GRANT_REMARK = XPATH_GRANT_PROPERTIES + "/" + NAME_GRANT_REMARK;

    public static final String XPATH_GRANT_ROLE = XPATH_GRANT_PROPERTIES + "/" + NAME_ROLE;

    public static final String XPATH_GRANT_ROLE_XLINK_TITLE = XPATH_GRANT_ROLE + PART_XLINK_TITLE;

    public static final String XPATH_GRANT_ROLE_XLINK_HREF = XPATH_GRANT_ROLE + PART_XLINK_HREF;

    public static final String XPATH_GRANT_ROLE_OBJID = XPATH_GRANT_ROLE + "/@" + NAME_OBJID;

    public static final String XPATH_GRANT_OBJECT = XPATH_GRANT_PROPERTIES + "/"
            + EscidocAbstractTest.NAME_ASSIGNED_ON;

    public static final String XPATH_GRANT_OBJECT_XLINK_TITLE = XPATH_GRANT_OBJECT + PART_XLINK_TITLE;

    public static final String XPATH_GRANT_OBJECT_XLINK_HREF = XPATH_GRANT_OBJECT + PART_XLINK_HREF;

    public static final String XPATH_GRANT_OBJECT_OBJID = XPATH_GRANT_OBJECT + PART_OBJID;

    public static final String XPATH_SCOPE = "/scope";

    public static final String XPATH_STATISTIC_DATA_SCOPE = "/statistic-record/scope";

    public static final String XPATH_AGGREGATION_DEFINITION_SCOPE = "/aggregation-definition/scope";

    public static final String XPATH_REPORT_DEFINITION_SCOPE = "/report-definition/scope";

    public static final String XPATH_SCOPE_OBJID = XPATH_SCOPE + PART_OBJID;

    public static final String XPATH_STATISTIC_DATA_SCOPE_OBJID = XPATH_STATISTIC_DATA_SCOPE + PART_OBJID;

    public static final String XPATH_AGGREGATION_DEFINITION = "/aggregation-definition";

    public static final String XPATH_REPORT_DEFINITION = "//report-definition";

    public static final String XPATH_REPORT_DEFINITION_OBJID = XPATH_REPORT_DEFINITION + PART_OBJID;

    public static final String XPATH_REPORT = "/report";

    public static final String XPATH_REPORT_REPORT_DEFINITION = "/report/report-definition";

    public static final String ENTITY_REFERENCES = "A &lt; &gt; &amp; &quot; &apos; &amp;lt; &amp;gt; &amp;amp; &amp;quot; &amp;apos; Z";

    public static final String XLINK_TYPE_VALUE = "simple";

    public static final String NAME_ADMIN_DESCRIPTOR = "admin-descriptor";

    public static final String NAME_ADMIN_DESCRIPTORS = "admin-descriptors";

    private static final Pattern PATTERN_GET_ID_FROM_URI_OR_FEDORA_ID = Pattern.compile(".*/([^/>]+)>{0,1}");

    private static String REPOSITORY_VERSION = null;

    private static String frameworkHost = null;

    private static String frameworkPort = null;

    private static String frameworkUrl = null;

    private AdminClient adminClient = null;

    private ItemClient itemClient = null;

    private IngestClient ingestClient = null;

    private ContainerClient containerClient = null;

    private ContextClient contextClient = null;

    private ContentRelationClient contentRelationClient = null;

    private DeviationClient deviationClient = null;

    private OrganizationalUnitClient ouClient = null;

    public EscidocTestBase() {
        this.stagingFileClient = new StagingFileClient();
    }

    /**
     * Tear down. Resets the user handle in <code>PWCallback</code>.
     * 
     * @throws Exception
     *             If an error occurs.
     */
    @After
    public void tearDown() throws Exception {
        PWCallback.resetHandle();
    }

    /**
     * @return Returns the client to use in the test.
     * @throws Exception
     *             If anything fails.
     */
    public ResourceHandlerClientInterface getClient() throws Exception {

        // get the current stack position
        try {
            throw new Exception();
        } catch (final Exception e) {
            throw new UnsupportedOperationException("getClient() not implemented by this test class.", e);
        }
    }

    /**
     * @return Returns the adminClient.
     */
    public AdminClient getAdminClient() {
        if (this.adminClient == null) {
            this.adminClient = new AdminClient();
        }
        return adminClient;
    }

    /**
     * @return Returns the itemClient.
     */
    public ItemClient getItemClient() {
        if (this.itemClient == null) {
            this.itemClient = new ItemClient();
        }
        return itemClient;
    }

    /**
     * @return Returns the IngestClient.
     */
    public IngestClient getIngestClient() {
        if (this.ingestClient == null) {
            this.ingestClient = new IngestClient();
        }
        return this.ingestClient;
    }

    /**
     * @return Returns the containerClient.
     */
    public ContainerClient getContainerClient() {
        if (this.containerClient == null) {
            this.containerClient = new ContainerClient();
        }
        return containerClient;
    }

    /**
     * @return Returns the contextClient.
     */
    public ContextClient getContextClient() {
        if (this.contextClient == null) {
            this.contextClient = new ContextClient();
        }
        return contextClient;
    }

    /**
     * @return Returns the contentRelationClient.
     */
    public ContentRelationClient getContentRelationClient() {
        if (this.contentRelationClient == null) {
            this.contentRelationClient = new ContentRelationClient();
        }
        return contentRelationClient;
    }

    /**
     * @return Returns the DeviationClient.
     */
    public DeviationClient getDeviationClient() {
        if (this.deviationClient == null) {
            this.deviationClient = new DeviationClient();
        }
        return this.deviationClient;
    }

    /**
     *
     * @return Returns the OrganizationalUnitClient.
     */
    public OrganizationalUnitClient getOrganizationalUnitClient() {
        if (this.ouClient == null) {
            this.ouClient = new OrganizationalUnitClient();
        }
        return this.ouClient;
    }

    /**
     * Returns the xml data of the provided result.
     * 
     * @param result
     *            The object holding the result.
     * @return Returns the xml string.
     * @throws Exception
     *             If anything fails.
     */
    protected String handleXmlResult(final Object result) throws Exception {

        String xmlResult = null;
        if (result instanceof HttpResponse) {
            HttpResponse httpRes = (HttpResponse) result;
            assertHttpStatusOfMethod("", httpRes);
            assertContentTypeTextXmlUTF8OfMethod("", httpRes);
            xmlResult = EntityUtils.toString(httpRes.getEntity(), HTTP.UTF_8);
        } else if (result instanceof String) {
            xmlResult = (String) result;
        }
        return xmlResult;
    }

    /**
     * Grab the object id from URI.
     * 
     * @param uri
     *            Fedora URI with objid .
     * @return object id
     */
    public static String getIdFromURI(final String uri) {

        if (uri == null) {
            return null;
        }
        Matcher matcher = PATTERN_GET_ID_FROM_URI_OR_FEDORA_ID.matcher(uri);
        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return uri;
        }
    }

    /**
     * Test creating a resource using the specified resource handler.<br>
     * The client to use is determined by getClient() that must be implemented by the concrete test class.
     * 
     * @param resourceXml
     *            The xml representation of the resource.
     * @return The xml representation of the created resource.
     * @throws Exception
     *             If anything fails.
     */
    public String create(final String resourceXml) throws Exception {

        EtmPoint point = ETM_MONITOR.createPoint("EscidocTestBase:create");
        try {
            return handleXmlResult(getClient().create(resourceXml));
        } finally {
            point.collect();
        }
    }

    /**
     * Test deleting a resource from the framework.<br>
     * The client to use is determined by getClient() that must be implemented by the concrete test class.
     * 
     * @param id
     *            The id of the resource.
     * @throws Exception
     *             If anything fails.
     */
    public void delete(final String id) throws Exception {

        Object result = getClient().delete(id);
        if (result instanceof HttpResponse) {
            HttpResponse httpRes = (HttpResponse) result;
            assertHttpStatusOfMethod("", httpRes);
        }
    }

    /**
     * Test retrieving a resource from the framework.<br>
     * The client to use is determined by getClient() that must be implemented by the concrete test class.
     * 
     * @param id
     *            The id of the resource.
     * @return The retrieved resource.
     * @throws Exception
     *             If anything fails.
     */
    public String retrieve(final String id) throws Exception {

        EtmPoint point = ETM_MONITOR.createPoint("EscidocTestBase:retrieve");
        try {
            return handleXmlResult(getClient().retrieve(id));
        } finally {
            point.collect();
        }

    }

    /**
     * Test retrieving the virtual resources of a resource from the framework.<br>
     * The client to use is determined by getClient() that must be implemented by the concrete test class.
     * 
     * @param id
     *            The id of the resource.
     * @return The retrieved virtual resources.
     * @throws Exception
     *             If anything fails.
     */
    public String retrieveResources(final String id) throws Exception {

        return handleXmlResult(getClient().retrieveResources(id));
    }

    /**
     * Test updating a resource of the framework.<br>
     * The client to use is determined by getClient() that must be implemented by the concrete test class.
     * 
     * @param id
     *            The id of the resource.
     * @param resourceXml
     *            The xml representation of the resource.
     * @return The updated resource.
     * @throws Exception
     *             If anything fails.
     */
    public String update(final String id, final String resourceXml) throws Exception {

        EtmPoint point = ETM_MONITOR.createPoint("EscidocTestBase:update");
        try {
            return handleXmlResult(getClient().update(id, resourceXml));
        } finally {
            point.collect();
        }

    }

    /**
     * Assert that Map is empty.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param map
     *            The map to check.
     */
    public static void assertEmptyMap(final String message, final Map map) {
        if (map == null) {
            fail(message + " Map is null");
        }
        if (!map.isEmpty()) {
            StringBuffer buf = new StringBuffer("");
            for (Object key : map.keySet()) {
                buf.append(key);
            }
            fail(message + buf.toString());
        }
    }

    /**
     * Assert that the http request was successful.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param httpRes
     *            The http method.
     */
    public static void assertHttpStatusOK(final String message, final HttpResponse httpRes) {
        assertHttpStatus(message, HttpServletResponse.SC_OK, httpRes);

    }

    // Content-Type: text/xml;charset=UTF-8

    /**
     * Assert that the http request was successful.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param httpRes
     *            The http method.
     */
    public static void assertContentTypeTextXmlUTF8OfMethod(final String message, final HttpResponse httpRes) {
        assertContentType(message, MimeTypes.TEXT_XML, "utf-8", httpRes);
    }

    public static void assertContentType(final String message, final String expectedContentType,
            final String expectedCharset, final HttpResponse httpRes) {
        Header[] headers = httpRes.getAllHeaders();
        String contentTypeHeaderValue = null;
        for (int i = 0; i < headers.length && contentTypeHeaderValue == null; ++i) {
            if (headers[i].getName().toLowerCase(Locale.ENGLISH).equals("content-type")) {
                contentTypeHeaderValue = headers[i].getValue();
            }
        }
        assertNotNull("No content-type header found, but expected 'content-type=" + expectedContentType + ";"
                + expectedCharset + "'", contentTypeHeaderValue);
        assertTrue("Wrong content-type found, expected '" + expectedContentType + "' but was '"
                + contentTypeHeaderValue + "'", contentTypeHeaderValue.indexOf(expectedContentType) > -1);
        assertTrue(
                "Wrong charset found, expected '" + expectedCharset + "' but was '" + contentTypeHeaderValue + "'",
                contentTypeHeaderValue.indexOf(expectedContentType) > -1);
    }

    /**
     * Assert that the http request was successful.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param httpRes
     *            The http method.
     */
    public static void assertHttpStatusOfMethod(final String message, final HttpResponse httpRes) {
        // Delete Operation delivers Status code 206, HttpResponse doesn't
        // contain the original hhtp method
        if (httpRes.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK) {
            assertHttpStatus(message, HttpServletResponse.SC_OK, httpRes);

        } else if ((httpRes.getStatusLine().getStatusCode() == HttpServletResponse.SC_NO_CONTENT)) {
            assertHttpStatus(message, HttpServletResponse.SC_NO_CONTENT, httpRes);
        }

    }

    /**
     * Assert that the http response has the expected status.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param expectedStatus
     *            The expected status.
     * @param httpRes
     *            The http method.
     */
    public static void assertHttpStatus(final String message, final int expectedStatus,
            final HttpResponse httpRes) {
        assertEquals(message + " Wrong response status!", expectedStatus, httpRes.getStatusLine().getStatusCode());
    }

    /**
     * Assert that the http response has the expected status.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param matchString
     *            expected String to match.
     * @param toTest
     *            toTest.
     */
    public static void assertMatches(final String message, final String matchString, final String toTest) {
        if (!toTest.matches("(?s).*" + matchString + ".*")) {
            fail(message);
        }
    }

    /**
     * Assert XML content is equal.<br/>
     * <p/>
     * This methods compares the attributes (if any exist) and either recursively compares the child elements (if any
     * exists) or the text content.<br/>
     * Therefore, mixed content is NOT supported by this method.
     * 
     * @param messageIn
     *            The message printed if assertion fails.
     * @param expected
     *            The expected XML content.
     * @param toBeAsserted
     *            The XML content to be compared with the expected content.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String messageIn, final Node expected, final Node toBeAsserted)
            throws Exception {
        // Assert both nodes are null or both nodes are not null
        if (expected == null) {
            assertNull(messageIn + "Unexpected node. ", toBeAsserted);
            return;
        }
        assertNotNull(messageIn + " Expected node. ", toBeAsserted);
        if (expected.equals(toBeAsserted)) {
            return;
        }
        String nodeName = getLocalName(expected);
        String message = messageIn;
        if (!message.contains("-- Asserting ")) {
            message = message + "-- Asserting " + nodeName + ". ";
        } else {
            message = message + "/" + nodeName;
        }
        // assert both nodes are nodes of the same node type
        // if thedocument container xslt directive than is the nodeName
        // "#document" is here compared
        assertEquals(message + " Type of nodes are different", expected.getNodeType(), toBeAsserted.getNodeType());
        if (expected.getNodeType() == Node.TEXT_NODE) {
            assertEquals(message + " Text nodes are different. ", expected.getTextContent().trim(),
                    toBeAsserted.getTextContent().trim());
        }
        // assert attributes
        NamedNodeMap expectedAttributes = expected.getAttributes();
        NamedNodeMap toBeAssertedAttributes = toBeAsserted.getAttributes();
        if (expectedAttributes == null) {
            assertNull(message + " Unexpected attributes. [" + nodeName + "]", toBeAssertedAttributes);
        } else {
            assertNotNull(message + " Expected attributes. ", toBeAssertedAttributes);
            final int expectedNumberAttributes = expectedAttributes.getLength();
            for (int i = 0; i < expectedNumberAttributes; i++) {
                Node expectedAttribute = expectedAttributes.item(i);
                String expectedAttributeNamespace = expectedAttribute.getNamespaceURI();
                Node toBeAssertedAttribute = null;
                if (expectedAttributeNamespace != null) {
                    final String localName = expectedAttribute.getLocalName();
                    toBeAssertedAttribute = toBeAssertedAttributes.getNamedItemNS(expectedAttributeNamespace,
                            localName);
                    assertNotNull(message + " Expected attribute " + expectedAttribute.getNodeName(),
                            toBeAssertedAttribute);
                } else {
                    // not namespace aware parsed. Attributes may have different
                    // prefixes which are now part of their node name.
                    // To compare expected and to be asserted attribute, it is
                    // first it is tried to find the appropriate to be asserted
                    // attribute by the node name. If this fails, xpath
                    // selection is used after extracting the expected
                    // attribute name
                    final String expectedAttributeNodeName = expectedAttribute.getNodeName();
                    toBeAssertedAttribute = toBeAssertedAttributes.getNamedItem(expectedAttributeNodeName);
                    if (toBeAssertedAttribute == null) {
                        final String attributeName = getLocalName(expectedAttribute);
                        final String attributeXpath = "@" + attributeName;
                        toBeAssertedAttribute = selectSingleNode(toBeAsserted, attributeXpath);
                    }
                    assertNotNull(message + " Expected attribute " + expectedAttributeNodeName,
                            toBeAssertedAttribute);
                }
                assertEquals(message + " Attribute value mismatch [" + expectedAttribute.getNodeName() + "] ",
                        expectedAttribute.getTextContent(), toBeAssertedAttribute.getTextContent());
            }
        }
        // As mixed content (text + child elements) is not supported,
        // either the child elements or the text content have to be asserted.
        // Therefore, it is first tried to assert the children.
        // After that it is checked if children have been found. If this is not
        // the case, the text content is compared.
        NodeList expectedChildren = expected.getChildNodes();
        NodeList toBeAssertedChildren = toBeAsserted.getChildNodes();
        int expectedNumberElementNodes = 0;
        int toBeAssertedNumberElementNodes = 0;
        List<Node> previouslyAssertedChildren = new ArrayList<Node>();
        for (int i = 0; i < expectedChildren.getLength(); i++) {
            Node expectedChild = expectedChildren.item(i);
            if (expectedChild.getNodeType() == Node.ELEMENT_NODE) {
                expectedNumberElementNodes++;
                String expectedChildName = getLocalName(expectedChild);
                String expectedUri = expectedChild.getNamespaceURI();
                boolean expectedElementAsserted = false;
                for (int j = 0; j < toBeAssertedChildren.getLength(); j++) {
                    final Node toBeAssertedChild = toBeAssertedChildren.item(j);
                    // prevent previously asserted children from being
                    // asserted again
                    if (previouslyAssertedChildren.contains(toBeAssertedChild)) {
                        continue;
                    }
                    if (toBeAssertedChild.getNodeType() == Node.ELEMENT_NODE
                            && expectedChildName.equals(getLocalName(toBeAssertedChild))
                            && (expectedUri == null || expectedUri.equals(toBeAssertedChild.getNamespaceURI()))) {
                        expectedElementAsserted = true;
                        toBeAssertedNumberElementNodes++;
                        assertXmlEquals(message, expectedChild, toBeAssertedChild);
                        // add asserted child to list of asserted children to
                        // prevent it from being asserted again.
                        previouslyAssertedChildren.add(toBeAssertedChild);
                        break;
                    }
                }
                if (!expectedElementAsserted) {
                    fail(new StringBuffer(message).append(" Did not found expected corresponding element [")
                            .append(nodeName).append(", ").append(expectedChildName).append(", ").append(i)
                            .append("]").toString());
                }
            }
        }
        // check if any element node in toBeAssertedChildren exists
        // that has not been asserted. In this case, this element node
        // is unexpected!
        for (int i = 0; i < toBeAssertedChildren.getLength(); i++) {
            Node toBeAssertedChild = toBeAssertedChildren.item(i);
            // prevent previously asserted children from being
            // asserted again
            if (previouslyAssertedChildren.contains(toBeAssertedChild)) {
                continue;
            }
            if (toBeAssertedChild.getNodeType() == Node.ELEMENT_NODE) {
                fail(new StringBuffer(message).append("Found unexpected element node [").append(nodeName)
                        .append(", ").append(getLocalName(toBeAssertedChild)).append(", ").append(i).append("]")
                        .toString());
            }
        }
        // if no children have been found, text content must be compared
        if (expectedNumberElementNodes == 0 && toBeAssertedNumberElementNodes == 0) {
            String expectedContent = expected.getTextContent();
            String toBeAssertedContent = toBeAsserted.getTextContent();
            assertEquals(message, expectedContent, toBeAssertedContent);
        }
    }

    /**
     * Gets the local name (the node name without the namespace prefix) of the provided node.
     * 
     * @param node
     *            The node to extract the name from.
     * @return Returns <code>node.getLocalName</code> if this is set, or the value of <code>node.getNodeName</code>
     *         without the namespace prefix.
     */
    private static String getLocalName(final Node node) {

        String name = node.getLocalName();
        if (name == null) {
            name = node.getNodeName().replaceAll(".*?:", "");
        }
        return name;
    }

    /**
     * Assert XML content is equal.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param expected
     *            The expected XML content.
     * @param toBeAsserted
     *            The XML content to be compared with the expected content.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String message, final String expected, final String toBeAsserted)
            throws Exception {

        Document expectedDoc = EscidocAbstractTest.getDocument(expected);
        Document assertedDoc = EscidocAbstractTest.getDocument(toBeAsserted);

        assertXmlEquals(message, expectedDoc, assertedDoc);
    }

    /**
     * Get the host name of the framework (read from properties).
     * 
     * @return the host name of the framework
     */
    public static String getFrameworkHost() {
        if (frameworkHost == null) {
            frameworkHost = PropertiesProvider.getInstance().getProperty("server.name", "localhost");
        }
        return frameworkHost;
    }

    /**
     * Get the port number of the framework (read from properties).
     * 
     * @return the port number of the framework
     */
    public static String getFrameworkPort() {
        if (frameworkPort == null) {
            frameworkPort = PropertiesProvider.getInstance().getProperty("server.port", "8080");
        }
        return frameworkPort;
    }

    /**
     * Get the href of the framework (read from properties).
     * 
     * @return the href of the framework.
     */
    public static String getFrameworkUrl() {
        if (frameworkUrl == null) {
            frameworkUrl = Constants.PROTOCOL + "://" + getFrameworkHost() + ":" + getFrameworkPort();
        }
        return frameworkUrl;
    }

    /**
     * Assert XML content is equal.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param expected
     *            The expected XML content.
     * @param toBeAsserted
     *            The XML content to be compared with the expected content.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String message, final InputStream expected, final String toBeAsserted)
            throws Exception {

        Document expectedDoc = EscidocAbstractTest
                .getDocument(ResourceProvider.getContentsFromInputStream(expected));
        Document assertedDoc = EscidocAbstractTest.getDocument(toBeAsserted);
        assertXmlEquals(message, expectedDoc, assertedDoc);
    }

    /**
     * Assert XML content is equal.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param expected
     *            The expected XML content.
     * @param toBeAsserted
     *            The XML content to be compared with the expected content.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String message, final File expected, final String toBeAsserted)
            throws Exception {

        assertXmlEquals(message, new FileInputStream(expected), toBeAsserted);
    }

    /**
     * Assert that the Element/Attribute selected by the xPath exists.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param xml
     *            The xml document as String.
     * @param xPath
     *            The xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlExists(final String message, final String xml, final String xPath)
            throws Exception {

        assertXmlExists(message, EscidocAbstractTest.getDocument(xml), xPath);
    }

    /**
     * Assert that the Element/Attribute selected by the xPath exists.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param node
     *            The Node.
     * @param xPath
     *            The xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlExists(final String message, final Node node, final String xPath) throws Exception {

        NodeList nodes = selectNodeList(node, xPath);
        assertTrue(message, nodes.getLength() > 0);
    }

    /**
     * Assert that the Element/Attribute selected by the xPath exists.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param node
     *            The Node.
     * @param xPath
     *            The xPath.
     * @param namespaceNode
     *            The namespace node.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlExists(final String message, final Node node, final String xPath,
            final Node namespaceNode) throws Exception {

        NodeList nodes = selectNodeList(node, xPath, namespaceNode);
        assertTrue(message, nodes.getLength() > 0);
    }

    /**
     * Assert that the value in the Document selected by the xPath equals the expected value.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param xml
     *            The xml document as String.
     * @param xPath
     *            The xPath.
     * @param expectedValue
     *            The expected value.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String message, final String xml, final String xPath,
            final String expectedValue) throws Exception {
        assertXmlEquals(message, EscidocAbstractTest.getDocument(xml), xPath, expectedValue);
    }

    /**
     * Assert that the value in the Document selected by the xPath equals the expected value.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param node
     *            The Node.
     * @param xPath
     *            The xPath.
     * @param expectedValue
     *            The expected value.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String message, final Node node, final String xPath,
            final String expectedValue) throws Exception {
        Node comp = selectSingleNode(node, xPath);
        assertNotNull(message + " Node selected by xpath not found [" + xPath + "]", comp);
        final String trimmed = comp.getTextContent().trim();
        assertEquals(message, expectedValue, trimmed);
    }

    /**
     * Assert that the value in the Document selected by the xPath equals the expected value.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param expected
     *            The expected node
     * @param result
     *            The result to be asserted.
     * @param xPath
     *            The xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String message, final Node expected, final Node result,
            final String xPath) throws Exception {

        assertXmlEquals(message, expected, xPath, result, xPath);
    }

    /**
     * Assert that the value(s) in the to be asserted node selected by the xPath equals the expected value.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param expected
     *            The node from which the expected value is selected by the xpath.
     * @param expectedXpath
     *            The xpath expression navigating in the node to the expected value.
     * @param toBeAsserted
     *            The node for that the value selected by the xpath shall be asserted.
     * @param toBeAssertedXpath
     *            The xPath navigating to the value that shall be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlEquals(final String message, final Node expected, final String expectedXpath,
            final Node toBeAsserted, final String toBeAssertedXpath) throws Exception {

        final String msg = prepareAssertionFailedMessage(message);

        if (expected == toBeAsserted) {
            return;
        }
        final NodeList expectedNodes = selectNodeList(expected, expectedXpath);
        final NodeList toBeAssertedNodes = selectNodeList(toBeAsserted, toBeAssertedXpath);
        assertEquals(msg + "Number of selected nodes differ. ", expectedNodes.getLength(),
                toBeAssertedNodes.getLength());
        final int length = toBeAssertedNodes.getLength();
        for (int i = 0; i < length; i++) {
            assertXmlEquals(msg + "Asserting " + (i + 1) + ". node. ", expectedNodes.item(i),
                    toBeAssertedNodes.item(i));
        }
    }

    /**
     * Assert that the value in the Document selected by the xPath NOT equals the unexpected value.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param unexpected
     *            The unexpected node
     * @param toBeAsserted
     *            The result to be asserted.
     * @param xPath
     *            The xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlNotEquals(final String message, final Node unexpected, final Node toBeAsserted,
            final String xPath) throws Exception {

        Node toBeAssertedComp = selectSingleNode(toBeAsserted, xPath);
        Node unexpectedComp = selectSingleNode(unexpected, xPath);
        assertNotEquals(message, unexpectedComp.getTextContent(), toBeAssertedComp.getTextContent());
    }

    /**
     * Asserts that the timestamp has been updated.<br>
     * This assertion fails if the timestamp in the previous document is not less than the timestamp in the updated
     * document. The timestamp is identified by the root element's "last-modification-timestamp" attribute.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param previous
     *            The document containing the expected timestamp
     * @param toBeAsserted
     *            The document for that the timestamp shall be asserted.
     * @throws Exception
     *             If an error ocurres.
     */
    public static void assertXmlLastModificationDateUpdate(final String message, final Document previous,
            final Document toBeAsserted) throws Exception {

        final String previousLastModificationDateValue = getLastModificationDateValue(previous);
        final String toBeAssertedLastModificationDateValue = getLastModificationDateValue(toBeAsserted);
        assertDateBeforeAfter(previousLastModificationDateValue, toBeAssertedLastModificationDateValue);
    }

    /**
     * Asserts to objects are not equal.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param unexpected
     *            The unexpected node
     * @param toBeAsserted
     *            The result to be asserted.
     */
    public static void assertNotEquals(final String message, final Object unexpected, final Object toBeAsserted) {

        if (unexpected == null && toBeAsserted == null || unexpected.equals(toBeAsserted)) {
            if (message == null || message.isEmpty()) {
                fail("Values are equal. Expected unequal");
            } else {
                fail(message);
            }
        }
    }

    /**
     * Serialize the given Dom Object to a String.
     * 
     * @param xml
     *            The Xml Node to serialize.
     * @param omitXMLDeclaration
     *            Indicates if XML declaration will be omitted.
     * @return The String representation of the Xml Node.
     * @throws Exception
     *             If anything fails.
     */
    public static String toString(final Node xml, final boolean omitXMLDeclaration) throws Exception {

        String result = new String();
        if (xml instanceof AttrImpl) {
            result = xml.getTextContent();
        } else if (xml instanceof Document) {
            StringWriter stringOut = new StringWriter();
            // format
            OutputFormat format = new OutputFormat((Document) xml);
            format.setIndenting(true);
            format.setPreserveSpace(true);
            format.setOmitXMLDeclaration(omitXMLDeclaration);
            format.setEncoding(DEFAULT_CHARSET);
            // serialize
            XMLSerializer serial = new XMLSerializer(stringOut, format);
            serial.asDOMSerializer();

            serial.serialize((Document) xml);
            result = stringOut.toString();
        } else {
            DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
            DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
            LSOutput lsOutput = impl.createLSOutput();
            lsOutput.setEncoding(DEFAULT_CHARSET);

            ByteArrayOutputStream os = new ByteArrayOutputStream();
            lsOutput.setByteStream(os);
            LSSerializer writer = impl.createLSSerializer();
            // result = writer.writeToString(xml);
            writer.write(xml, lsOutput);
            result = ((ByteArrayOutputStream) lsOutput.getByteStream()).toString(DEFAULT_CHARSET);
            if ((omitXMLDeclaration) && (result.indexOf("?>") != -1)) {
                result = result.substring(result.indexOf("?>") + 2);
            }
            // result = toString(getDocument(writer.writeToString(xml)),
            // true);
        }
        return result;
    }

    /**
     * Delete an Element from a Node.
     * 
     * @param node
     *            the node.
     * @param xPath
     *            The xPath selecting the element.
     * @return The resulting node.
     * @throws Exception
     *             If anything fails.
     */
    public static Node deleteElement(final Node node, final String xPath) throws Exception {

        Node delete = selectSingleNode(node, xPath);
        assertNotNull("No node found for provided xpath [" + xPath + "]", delete);
        if (delete instanceof AttrImpl) {
            throw new Exception("Removal of Element not successful! " + "xPath selects an Attribute!");
        } else {
            delete.getParentNode().removeChild(delete);
        }
        return node;
    }

    /**
     * Delete all Elements from a Node.
     * 
     * @param node
     *            the node.
     * @param xPath
     *            The xPath selecting the element.
     * @return The resulting node.
     * @throws Exception
     *             If anything fails.
     */
    public static Node deleteElements(final Node node, final String xPath) throws Exception {

        NodeList nodes = selectNodeList(node, xPath);
        for (int i = 0; i < nodes.getLength(); ++i) {
            deleteElement(node, xPath);
        }
        return node;
    }

    /**
     * Return the text value of the selected attribute.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xpath to select the node contain the attribute,
     * @param attributeName
     *            The name of the attribute.
     * @return The text value of the selected attribute.
     * @throws Exception
     *             If anything fails.
     */
    public static String getAttributeValue(final Node node, final String xPath, final String attributeName)
            throws Exception {

        String result = null;
        Node attribute = selectSingleNode(node, xPath);
        if (attribute != null && attribute.hasAttributes()
                && attribute.getAttributes().getNamedItem(attributeName) != null) {

            result = attribute.getAttributes().getNamedItem(attributeName).getTextContent();
        }
        return result;
    }

    /**
     * Delete an Attribute from an Element of a Node.
     * 
     * @param node
     *            the node.
     * @param xPath
     *            The xPath selecting the element.
     * @param attributeName
     *            The name of the attribute.
     * @return The resulting node.
     * @throws Exception
     *             If anything fails.
     */
    public static Node deleteAttribute(final Node node, final String xPath, final String attributeName)
            throws Exception {

        if (node == null) {
            return node;
        }
        Node delete = selectSingleNode(node, xPath);
        if (delete == null) {
            return node;
        }
        if (delete.hasAttributes()) {
            for (int i = 0; i < delete.getAttributes().getLength(); ++i) {
                String nodeName = delete.getAttributes().item(i).getNodeName();
                if (nodeName.endsWith(":" + attributeName) || nodeName.equals(attributeName)) {
                    delete.getAttributes().removeNamedItem(nodeName);
                    break;
                }
            }
        }
        return node;
    }

    /**
     * Delete an Attribute from an Element of a Node.
     * 
     * @param node
     *            the node.
     * @param xPath
     *            The xPath selecting the attribute.
     * @return The resulting node.
     * @throws Exception
     *             If anything fails.
     */
    public static Node deleteAttribute(final Node node, final String xPath) throws Exception {

        final int index = xPath.lastIndexOf('/');
        final String elementXpath = xPath.substring(0, index);
        final String attrName = xPath.substring(index + 2);
        return deleteAttribute(node, elementXpath, attrName);
    }

    /**
     * Substitute the element selected by the xPath in the given node with the new value.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param newValue
     *            The newValue.
     * @return The resulting node after the substitution.
     * @throws Exception
     *             If anything fails.
     */
    public static Node substitute(final Node node, final String xPath, final String newValue) throws Exception {
        Node result = node;
        Node replace = selectSingleNode(result, xPath);
        assertNotNull("No node found for specified xpath [" + xPath + "]", replace);
        // if (replace.getNodeType() == Node.ELEMENT_NODE) {
        replace.setTextContent(newValue);
        // }
        // else if (replace.getNodeType() == Node.ATTRIBUTE_NODE) {
        // replace.setNodeValue(newValue);
        // }
        // else {
        // throw new Exception("Unsupported node type '"
        // + replace.getNodeType() + "' in EscidocTestBase.substitute.");
        // }
        return result;
    }

    /**
     * Substitute the element selected by the xPath in the given node with the new value.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param newValue
     *            The newValue.
     * @return The resulting node after the substitution.
     * @throws Exception
     *             If anything fails.
     */
    public Node substituteId(final Node node, final String xPath, final String newValue) throws Exception {
        Node result = node;
        Node replace = null;
        String path = "";
        replace = selectSingleNode(result, xPath + "/@href");
        path = replace.getTextContent().substring(0, replace.getTextContent().lastIndexOf("/") + 1);

        assertNotNull("No node found for specified xpath [" + xPath + "]", replace);
        // if (replace.getNodeType() == Node.ELEMENT_NODE) {
        replace.setTextContent(path + newValue);
        // }
        // else if (replace.getNodeType() == Node.ATTRIBUTE_NODE) {
        // replace.setNodeValue(newValue);
        // }
        // else {
        // throw new Exception("Unsupported node type '"
        // + replace.getNodeType() + "' in EscidocTestBase.substitute.");
        // }
        return result;
    }

    /**
     * Gets the prefix of the provided node.<br>
     * This returns Node.getPrefix() if this is not null. Otherwise, ittries to extract the prefix from
     * Node.getNodeName(). If this fails, null is returned.
     * 
     * @param node
     *            The node to get the prefix from.
     * @return Returns the determined prefix or null.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public static String getPrefix(final Node node) throws Exception {

        String prefix = node.getPrefix();
        if (prefix == null) {
            String nodeName = node.getNodeName();
            int index = nodeName.indexOf(":");
            if (index != -1) {
                prefix = nodeName.substring(0, index);
            }
        }
        return prefix;
    }

    /**
     * Creates a new element node for the provided document. The created element is an element that refers to another
     * resource, i.e. it has xlink attributes and an objid attribute.
     * 
     * @param doc
     *            The document for that the node shall be created.
     * @param namespaceUri
     *            The name space uri of the node to create. This may be null.
     * @param prefix
     *            The prefix to use.
     * @param tagName
     *            The tag name of the node.
     * @param xlinkPrefix
     *            The prefix to use for the xlink attributes.
     * @param title
     *            The title of the referencing element (=xlink:title)
     * @param href
     *            The href of the referencing element (=xlink:href). The objid attribute value is extracted from this
     *            href.
     * @return Returns the created node.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public Element createReferencingElementNode(final Document doc, final String namespaceUri, final String prefix,
            final String tagName, final String xlinkPrefix, final String title, final String href)
            throws Exception {

        Element newElement = createElementNodeWithXlink(doc, namespaceUri, prefix, tagName, xlinkPrefix, title,
                href);

        Attr objidAttr = createAttributeNode(doc, null, null, NAME_OBJID, getObjidFromHref(href));
        newElement.getAttributes().setNamedItemNS(objidAttr);

        return newElement;
    }

    /**
     * Creates a new element node for the provided document. The created element is an element that that has xlink
     * attributes, but does not have an objid attribute.
     * 
     * @param doc
     *            The document for that the node shall be created.
     * @param namespaceUri
     *            The name space uri of the node to create. This may be null.
     * @param prefix
     *            The prefix to use.
     * @param tagName
     *            The tag name of the node.
     * @param xlinkPrefix
     *            The prefix to use for the xlink attributes.
     * @param title
     *            The title of the referencing element (=xlink:title)
     * @param href
     *            The href of the referencing element (=xlink:href). The objid attribute value is extracted from this
     *            href.
     * @return Returns the created node.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public static Element createElementNodeWithXlink(final Document doc, final String namespaceUri,
            final String prefix, final String tagName, final String xlinkPrefix, final String title,
            final String href) throws Exception {

        Element newElement = createElementNode(doc, namespaceUri, prefix, tagName, null);
        Attr xlinkTypeAttr = createAttributeNode(doc, XLINK_NS_URI, xlinkPrefix, NAME_TYPE, "simple");
        Attr xlinkTitleAttr = createAttributeNode(doc, XLINK_NS_URI, xlinkPrefix, NAME_TITLE, title);
        Attr xlinkHrefAttr = createAttributeNode(doc, XLINK_NS_URI, xlinkPrefix, NAME_HREF, href);
        newElement.getAttributes().setNamedItemNS(xlinkTypeAttr);
        newElement.getAttributes().setNamedItemNS(xlinkTitleAttr);
        newElement.getAttributes().setNamedItemNS(xlinkHrefAttr);

        return newElement;
    }

    /**
     * Creates a new element node for the provided document.
     * 
     * @param doc
     *            The document for that the node shall be created.
     * @param namespaceUri
     *            The name space uri of the node to create. This may be null.
     * @param prefix
     *            The prefix to use.
     * @param tagName
     *            The tag name of the node.
     * @param textContent
     *            The text content of the node. This may be null.
     * @return Returns the created node.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public static Element createElementNode(final Document doc, final String namespaceUri, final String prefix,
            final String tagName, final String textContent) throws Exception {

        Element newNode = doc.createElementNS(namespaceUri, tagName);
        newNode.setPrefix(prefix);
        if (textContent != null) {
            newNode.setTextContent(textContent);
        }
        return newNode;
    }

    /**
     * Creates a new attribute node for the provided document.
     * 
     * @param doc
     *            The document for that the node shall be created.
     * @param namespaceUri
     *            The name space uri of the node to create. This may be null.
     * @param prefix
     *            The prefix to use.
     * @param tagName
     *            The tag name of the node.
     * @param value
     *            The attribute value.
     * @return Returns the created node.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public static Attr createAttributeNode(final Document doc, final String namespaceUri, final String prefix,
            final String tagName, final String value) throws Exception {

        Attr newAttribute = doc.createAttributeNS(namespaceUri, tagName);
        newAttribute.setPrefix(prefix);
        newAttribute.setValue(value);
        if (value != null) {
            newAttribute.setTextContent(value);
        }
        return newAttribute;
    }

    /**
     * Gets the prefix of the node selected by the xpath in the provided node.<br>
     * This returns Node.getPrefix() if this is not null. Otherwise, ittries to extract the prefix from
     * Node.getNodeName(). If this fails, null is returned.
     * 
     * @param node
     *            The node to get the prefix from.
     * @param xPath
     *            XPath to the Node to select the prefix from.
     * @return Returns the determined prefix or null.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public static String getPrefix(final Node node, final String xPath) throws Exception {

        return getPrefix(selectSingleNode(node, xPath));
    }

    /**
     * Adds the provided new node as the child of the element selected by the xPath in the given node.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param newNode
     *            The new node.
     * @return The resulting node after the substitution.
     * @throws Exception
     *             If anything fails.
     */
    public static Node addAsChild(final Node node, final String xPath, final Element newNode) throws Exception {

        Node result = node;
        Node parent = selectSingleNode(result, xPath);
        assertNotNull("No node for xpath found [" + xPath + "]", parent);
        // inserts at end of list
        parent.insertBefore(newNode, null);

        return result;
    }

    /**
     * Adds the provided new node after the element selected by the xPath in the given node.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param newNode
     *            The new node.
     * @return The resulting node after the substitution.
     * @throws Exception
     *             If anything fails.
     */
    public static Node addAfter(final Node node, final String xPath, final Node newNode) throws Exception {

        Node result = node;
        Node before = selectSingleNode(result, xPath);
        assertNotNull("No node for xpath [" + xPath + "] found", before);
        Node parent = before.getParentNode();
        parent.insertBefore(newNode, before.getNextSibling());
        return result;
    }

    /**
     * Adds the provided new node before the element selected by the xPath in the given node.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param newNode
     *            The new node.
     * @return The resulting node after the substitution.
     * @throws Exception
     *             If anything fails.
     */
    public static Node addBefore(final Node node, final String xPath, final Node newNode) throws Exception {

        Node result = node;
        Node after = selectSingleNode(result, xPath);
        assertNotNull("No node for xpath found [" + xPath + "]", after);
        Node parent = after.getParentNode();
        parent.insertBefore(newNode, after);
        return result;
    }

    /**
     * Adds the provided new attribute node to the element selected by the xPath in the given node.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param attributeNode
     *            The new attribute node.
     * @return The resulting node after the substitution.
     * @throws Exception
     *             If anything fails.
     */
    public static Node addAttribute(final Node node, final String xPath, final Attr attributeNode)
            throws Exception {

        Node result = node;
        Node element = selectSingleNodeAsserted(result, xPath);
        NamedNodeMap attributes = element.getAttributes();
        attributes.setNamedItemNS(attributeNode);
        return result;
    }

    /**
     * Substitute the element selected by the xPath in the given node with the new node.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param newNode
     *            The new node.
     * @return The resulting node after the substitution.
     * @throws Exception
     *             If anything fails.
     */
    public static Node substitute(final Node node, final String xPath, final Node newNode) throws Exception {
        Node result = node;
        Node replace = selectSingleNode(result, xPath);
        assertNotNull("No node selected for substitute. ", replace);
        Node parent = replace.getParentNode();
        parent.replaceChild(newNode, replace);
        return result;
    }

    /**
     * Return the list of children of the node selected by the xPath.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @return The list of children of the node selected by the xPath.
     * @throws TransformerException
     *             If anything fails.
     */
    public static NodeList selectNodeList(final Node node, final String xPath) throws TransformerException {
        NodeList result = XPathAPI.selectNodeList(node, xPath);
        return result;
    }

    /**
     * Return the list of children of the node selected by the xPath.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param namespaceNode
     *            The namespace node.
     * @return The list of children of the node selected by the xPath.
     * @throws TransformerException
     *             If anything fails.
     */
    public static NodeList selectNodeList(final Node node, final String xPath, final Node namespaceNode)
            throws TransformerException {
        NodeList result = XPathAPI.selectNodeList(node, xPath, namespaceNode);
        return result;
    }

    public static int getNoOfSelections(final Node node, final String xPath) throws TransformerException {
        int result = 0;
        NodeList matches = selectNodeList(node, xPath);
        if (matches != null) {
            result = matches.getLength();
        }
        return result;
    }

    /**
     * Return the child of the node selected by the xPath.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @return The child of the node selected by the xPath.
     * @throws TransformerException
     *             If anything fails.
     */
    public static Node selectSingleNode(final Node node, final String xPath) throws TransformerException {

        Node result = XPathAPI.selectSingleNode(node, xPath);
        return result;
    }

    /**
     * Return the child of the node selected by the xPath.<br>
     * This method includes an assert that the specified node exists.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @return The child of the node selected by the xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static Node selectSingleNodeAsserted(final Node node, final String xPath) throws Exception {

        Node result = selectSingleNode(node, xPath);
        assertNotNull("Node does not exist [" + xPath + "]", result);
        return result;
    }

    /**
     * Return the child of the node selected by the xPath.
     * 
     * @param node
     *            The node.
     * @param xPath
     *            The xPath.
     * @param namespaceNode
     *            The namespace node.
     * @return The child of the node selected by the xPath.
     * @throws TransformerException
     *             If anything fails.
     */
    public static Node selectSingleNode(final Node node, final String xPath, final Node namespaceNode)
            throws TransformerException {

        Node result = XPathAPI.selectSingleNode(node, xPath, namespaceNode);
        return result;
    }

    /**
     * Return a filter parameter including only an empty filter.
     * 
     * @return The filter parameter including only an empty filter.
     * @throws Exception
     *             If anything fails.
     */
    public static String getEmptyFilter() throws Exception {

        return EscidocAbstractTest.getTemplateAsString(TEMPLATE_OM_COMMON_PATH, "emptyFilter.xml");
    }

    /**
     * Get the filter parameter for retrieving contexts matching the given filter criteria. If a criteria is null the
     * filter is deleted from the parameter.
     * 
     * @param user
     *            The expected user.
     * @param role
     *            The expected role.
     * @param contextType
     *            The expected type of the context.
     * @return The filter parameter.
     * @throws Exception
     *             If anything fails.
     */
    public static Map<String, String[]> getFilterRetrieveContexts(final String user, final String role,
            final String contextType) throws Exception {
        Map<String, String[]> result = new HashMap<String, String[]>();
        StringBuffer filter = new StringBuffer();

        if ((user != null) && (user.length() > 0)) {
            filter.append("user=\"" + user + "\"");
        }
        if ((role != null) && (role.length() > 0)) {
            if (filter.length() > 0) {
                filter.append(" and ");
            }
            filter.append("role=\"" + role + "\"");
        }
        if ((contextType != null) && (contextType.length() > 0)) {
            if (filter.length() > 0) {
                filter.append(" and ");
            }
            filter.append("\"/properties/type\"=\"" + contextType + "\"");
        }
        if (filter.length() > 0) {
            result.put("query", new String[] { filter.toString() });
        }
        result.put("maximumRecords", new String[] { "1000" });
        return result;
    }

    /**
     * Get the filter parameter for retrieving members of a context matching the given filter criteria. If a criteria is
     * null the filter is deleted from the parameter.
     * 
     * @param members
     *            A list of members to restrict the resulting members.
     * @param objectType
     *            The type of the object (item or container).
     * @param user
     *            The expected user.
     * @param role
     *            The expected role.
     * @param status
     *            The expected status of the resulting objects.
     * @param contentType
     *            The expected contentType of the resulting objects.
     * @return The filter parameter.
     * @throws Exception
     *             If anything fails.
     */
    public static String getFilterRetrieveMembersOfContext(final List<String> members, final String objectType,
            final String user, final String role, final String status, final String contentType) throws Exception {

        Document filter = EscidocAbstractTest.getTemplateAsDocument(TEMPLATE_OM_COMMON_PATH,
                "filterRetrieveMembersOfContext.xml");
        if ((members != null) && (members.size() > 0)) {
            for (int i = 0; i < 5; ++i) {
                String value = null;
                try {
                    value = members.get(i);
                    filter = (Document) replaceInFilter(filter, value,
                            "/param/filter[@name=\"members\"]/id[" + (i + 1) + "]");
                } catch (final RuntimeException e) {
                    filter = (Document) replaceInFilter(filter, null,
                            "/param/filter[@name=\"members\"]/id[" + (members.size() + 1) + "]");
                }
            }
        } else {
            filter = (Document) replaceInFilter(filter, null, "param/filter[@name=\"members\"]");
        }

        filter = (Document) replaceInFilter(filter, objectType,
                "param/filter[@name=\"http://www.w3.org/1999/02/" + "22-rdf-syntax-ns#type\"]");
        filter = (Document) replaceInFilter(filter, user, "param/filter[@name=\"user\"]");
        filter = (Document) replaceInFilter(filter, role, "param/filter[@name=\"role\"]");

        filter = (Document) replaceInFilter(filter, status,
                "param/filter[@name=\"http://escidoc.de/core/01/" + "properties/public-status\"]");
        filter = (Document) replaceInFilter(filter, contentType,
                "param/filter[@name=\"http://escidoc.de/core/01/" + "structural-relations/content-model\"]");
        String result = toString(filter, true);
        return result;
    }

    /**
     * If value is null the element selected by xPath is removed from the filter otherwise the elements value is set to
     * vlaue.
     * 
     * @param filter
     *            The filter parameter.
     * @param value
     *            The value.
     * @param xPath
     *            The xPath.
     * @return The resulting filter parameter.
     * @throws Exception
     *             If anything fails.
     */
    public static Node replaceInFilter(final Node filter, final String value, final String xPath) throws Exception {

        if (value != null) {
            return substitute(filter, xPath, value);
        } else {
            return deleteElement(filter, xPath);
        }

    }

    /**
     * Gets the last modification date from the resource through retrieve.
     * 
     * @param id
     *            The id of the Resource.
     * @return last-modification-date
     * @throws Exception
     *             Thrown if anything fails.
     */
    public String getTheLastModificationDate(final String id) throws Exception {

        Document resource = EscidocAbstractTest.getDocument(retrieve(id));
        return getTheLastModificationDate(resource);
    }

    /**
     * Gets the last modification date from the Resource.
     * 
     * @param resource
     *            The Resource.
     * @return last-modification-date
     * @throws Exception
     *             Thrown if anything fails.
     */
    public String getTheLastModificationDate(final Document resource) throws Exception {

        // get last-modification-date
        NamedNodeMap atts = resource.getDocumentElement().getAttributes();
        Node lastModificationDateNode = atts.getNamedItem("last-modification-date");
        return (lastModificationDateNode.getNodeValue());

    }

    /**
     * Gets the task param containing the last modification date of the specified object.
     * 
     * @param includeComment
     *            Flag indicating if the comment shall be additionally included.
     * @param id
     *            The id of the object.
     * @return Returns the created task param xml.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public String getTheLastModificationParam(final boolean includeComment, final String id) throws Exception {
        return getTheLastModificationParam(includeComment, id, null);
    }

    /**
     * @param includeComment
     *            Flag indicating if the comment shall be additionally included.
     * @param id
     *            The id of the object.
     * @param comment
     *            The comment for the param structure (withdraw comment).
     * @return Returns the created task param xml.
     * @throws Exception
     *             If an error ocurres.
     */
    @Deprecated
    public String getTheLastModificationParam(final boolean includeComment, final String id, final String comment)
            throws Exception {

        String xml = null;
        if (includeComment) {
            xml = getStatusTaskParam(new DateTime(getTheLastModificationDate(id)), comment);
        } else {
            xml = getStatusTaskParam(new DateTime(getTheLastModificationDate(id)), null);
        }

        return xml;
    }

    /**
     * Get the last modification XML param.
     * 
     * @param includeComment
     *            Flag indicating if the comment shall be additionally included.
     * @param id
     *            The id of the object.
     * @param comment
     *            The comment.
     * @param lastModificationDate
     *            The timestamp of the resource.
     * @return Returns the created task param xml.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public String getTheLastModificationParam(final boolean includeComment, final String id, final String comment,
            final String lastModificationDate) throws Exception {

        String param = de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/status-task-param/0.1\" "
                + "last-modification-date=\"" + lastModificationDate + "\" >";

        if (includeComment) {
            if (comment != null) {
                param += "<comment>" + comment + "</comment>";
            } else {
                param += "<comment>" + WITHDRAW_COMMENT + "</comment>";
            }
        }
        param += "</param>";

        return param;
    }

    /**
     * Get task parameter for optimistic-locking method.
     * 
     * @param timestamp
     *            last-modification-date of the resource
     * @return task param XML (optimistic-locking-task-param.xsd)
     */
    public String getOptimisticLockingTaskParam(final DateTime timestamp) {

        return de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/optimistic-locking-task-param/0.1\" "
                + "last-modification-date=\"" + DateTimeJaxbConverter.printDate(timestamp) + "\" " + " />";
    }

    /**
     * Get task parameter for update password method.
     * 
     * @param timestamp
     *            last-modification-date of the resource
     * @return task param XML (update-password-task-param.xsd)
     */
    public String getUpdatePasswordTaskParam(final DateTime timestamp, final String password) {

        String taskParamXml = de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/update-password-task-param/0.1\" "
                + "last-modification-date=\"" + DateTimeJaxbConverter.printDate(timestamp) + "\" >\n";
        if (password != null) {
            taskParamXml += "<password>" + password + "</password>\n";
        }
        taskParamXml += "</param>\n";

        return taskParamXml;
    }

    /**
     * Get task parameter to revoke grant.
     * 
     * @param timestamp
     *            last-modification-date of the resource
     * @param revocationRemark
     *            revocation remark for param. Set null to exclude revocation-remark element from XML
     * @return task param XML (revoke-grant-task-param.xsd)
     */
    public String getRevokeGrantTaskParam(final DateTime timestamp, final String revocationRemark) {

        String xml = de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/revoke-grant-task-param/0.1\">";

        if (revocationRemark != null) {
            xml += "<revocation-remark>" + revocationRemark + "</revocation-remark>\n";
        }

        xml += "</param>\n";

        return xml;
    }

    /**
     * Get task param XML for add/remove members methods (see members-task-param.xsd)
     * 
     * @param timestamp
     *            Last modification date
     * @param ids
     *            member id parameter
     * @return task param XML (assign-pid-task-param.xsd)
     */
    public static String getMembersTaskParam(final DateTime timestamp, final List<String> ids) {

        String xml = de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/members-task-param/0.1\" last-modification-date=\""
                + DateTimeJaxbConverter.printDate(timestamp) + "\">\n";

        for (String id : ids) {
            xml += "<id>" + id + "</id>\n";
        }

        xml += "</param>\n";

        return xml;
    }

    /**
     * Get task param XML for add/remove members methods (see members-task-param.xsd)
     * 
     * @param ids
     *            member id parameter
     * @return task param XML (assign-pid-task-param.xsd)
     */
    public static String getIdSetTaskParam(final Set<String> ids) {

        StringBuilder xml = new StringBuilder(de.escidoc.core.test.Constants.XML_HEADER);
        xml.append("<param xmlns=\"http://www.escidoc.org/schemas/id-set-task-param/0.1\">\n");

        for (String id : ids) {
            xml.append("<id>" + id + "</id>\n");
        }

        xml.append("</param>\n");

        return xml.toString();
    }

    /**
     * Get task param XML for add/remove members methods (see members-task-param.xsd)
     * 
     * @param ids
     *            member id parameter
     * @param sync
     * @return task param XML (assign-pid-task-param.xsd)
     */
    public static String getDeleteObjectsTaskParam(final Set<String> ids, final Boolean sync) {

        // FIXME Namespace wrong but the real is'nt defined yet (INFR-1466)
        StringBuilder xml = new StringBuilder(de.escidoc.core.test.Constants.XML_HEADER);
        xml.append("<param xmlns=\"http://www.escidoc.org/schemas/delete-objects-task-param/0.1\">\n");

        for (String id : ids) {
            xml.append("<id>").append(id).append("</id>\n");
        }
        if (sync != null) {
            xml.append("<sync>").append(sync.toString()).append("</sync>\n");
        }
        xml.append("</param>\n");

        return xml.toString();
    }

    /**
     * Get task param XML for assing PID methods (see assing-pid-task-param.xsd)
     * 
     * @param timestamp
     *            Last modification date
     * @param param
     *            Assign PID parameter
     * @return task param XML (assign-pid-task-param.xsd)
     */
    public static String getAssignPidTaskParam(final DateTime timestamp, final AssignParam param) {

        String xml = de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/assign-pid-task-param/0.1\" last-modification-date=\""
                + DateTimeJaxbConverter.printDate(timestamp) + "\">";

        if (param.getUrl() != null) {
            xml += "<url>" + param.getUrl() + "</url>\n";
        }
        if (param.getPid() != null) {
            xml += "<pid>" + param.getPid() + "</pid>\n";
        }

        xml += "</param>\n";

        return xml;
    }

    /**
     * Get task parameter to revoke grants.
     * 
     * @param ids
     *            ids for filter, Set null to exclude filter
     * @param revocationRemark
     *            revocation remark for param. Set null to exclude revocation-remark element from XML
     * @return task param XML (revoke-grant-task-param.xsd)
     */
    public String getRevokeGrantsTaskParam(final Set<String> ids, final String revocationRemark) {

        StringBuffer xml = new StringBuffer(de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/revoke-grants-task-param/0.1\">");

        if (ids != null && !ids.isEmpty()) {
            xml.append("<filter name=\"" + DC_NS_URI + "identifier\">");
            for (final String id : ids) {
                xml.append("<id>");
                xml.append(id);
                xml.append("</id>\n");
            }
            xml.append("</filter>\n");
        }

        if (revocationRemark != null) {
            xml.append("<revocation-remark>");
            xml.append(revocationRemark);
            xml.append("</revocation-remark>\n");
        }

        xml.append("</param>\n");

        return xml.toString();
    }

    /**
     * Get task parameter for status methods.
     * 
     * @param timestamp
     *            Last modification date
     * @param comment
     *            The comment.
     * @return task param XML (status-task-param.xsd)
     */
    public static String getStatusTaskParam(final DateTime timestamp, final String comment) {

        StringBuffer xml = new StringBuffer(de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/status-task-param/0.1\" ");

        if (timestamp != null) {
            xml.append(" last-modification-date=\"" + DateTimeJaxbConverter.printDate(timestamp) + "\"");
        }
        xml.append(">");

        if (comment != null) {
            xml.append("<comment>");
            xml.append(comment);
            xml.append("</comment>\n");
        }

        xml.append("</param>\n");

        return xml.toString();
    }

    /**
     * Get task parameter for relation methods.
     * 
     * @param timestamp
     *            Last modification date
     * @param targetId
     *            targetId for the relation
     * @param predicate
     *            predicate for the relation
     * @return task param XML (relation-task-param.xsd)
     */
    public String getRelationTaskParam(final DateTime timestamp, final String targetId, String predicate) {

        StringBuffer xml = new StringBuffer(de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/relation-task-param/0.1\" last-modification-date=\""
                + DateTimeJaxbConverter.printDate(timestamp) + "\">");

        xml.append("<relation>\n");

        xml.append("<targetId>");
        xml.append(targetId);
        xml.append("</targetId>\n");

        xml.append("<predicate>");
        xml.append(predicate);
        xml.append("</predicate>\n");

        xml.append("</relation>\n");

        xml.append("</param>\n");

        return xml.toString();
    }

    /**
     * Assert that the before timestamp is lower than the after timestamp.
     * 
     * @param before
     *            Timestamp before the event
     * @param after
     *            Timestamp after event
     * @throws Exception
     *             Thrown if the before timestamp is not lower than after.
     */
    public static void assertDateBeforeAfter(final String before, final String after) throws Exception {
        Calendar oldModCal = getCalendarFromXmlDateString(before);
        Calendar newModCal = getCalendarFromXmlDateString(after);

        if (!oldModCal.before(newModCal)) {
            fail("Old last modification date is not before new last" + " modification date.");
        }
    }

    /**
     * Creates a <code>java.util.Calendar</code> object from an xml dateTime string.
     * 
     * @param dateTime
     *            The xml dateTime string.
     * @return The Calendar object.
     * @throws ParseException
     *             If the dateTime string can not be correctly parsed.
     */
    public static Calendar getCalendarFromXmlDateString(String dateTime) throws ParseException {
        Calendar cal = null;

        if (dateTime.length() >= 20 && dateTime.length() <= 23) {
            // no timezone
            // ensure 3 digits for millis
            int add = 23 - dateTime.length();
            while (add > 0) {
                dateTime += "0";
                add--;
            }
            dateTime += "+0000";
        } else if (dateTime.length() == 19) {
            // no timezone
            // not 3 digits for millis
            // no dot
            dateTime += ".000+0000";
        }
        // else if (dateTime.length() == 18) {
        // // no timezone
        // // not 3 digits for millis
        // // no dot
        // dateTime += "0.000+0000";
        // }
        // else if (dateTime.length() == 17) {
        // // no timezone
        // // not 3 digits for millis
        // // no dot
        // dateTime += "00.000+0000";
        // }
        // else if (dateTime.length() == 16) {
        // // no timezone
        // // not 3 digits for millis
        // // no dot
        // dateTime += ":00.000+0000";
        // }

        TimeZone gmt = TimeZone.getTimeZone("GMT");

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        DateFormat tf = new SimpleDateFormat("HH:mm:ss.SSS");

        Date oldModDateDate = df.parse(dateTime);
        Date oldModDateTime = tf.parse(dateTime, new ParsePosition(11));

        // DateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss.SSS");
        // dateTime = dateTime.replace('T', '-');
        // dateTime = dateTime.trim();

        cal = Calendar.getInstance();
        // cal.setTime(f.parse(dateTime));
        cal.setTimeZone(gmt);

        cal.setTime(oldModDateDate);
        long oldModDateDateMillis = cal.getTimeInMillis();

        cal.setTime(oldModDateTime);
        long oldModDateTimeMillis = cal.getTimeInMillis();

        long oldModDateMillis = oldModDateDateMillis + oldModDateTimeMillis;
        cal.setTimeInMillis(oldModDateMillis);

        return cal;
    }

    /**
     * Asserts first value to be greater or equals than second value.
     * 
     * @param greater
     *            first value.
     * @param lower
     *            second value.
     */
    protected void assertGreaterOrEquals(final int greater, final int lower) {

        if (lower > greater) {
            fail(lower + " is greater than " + greater);
        }
    }

    /**
     * Validates Item XML against the XML Schema, checks if the xml:base exists and if all placeholders are replaced.
     * 
     * @param xmlData
     *            The xml document as string.
     * @throws Exception
     *             If an error occures.
     */
    public void assertXmlValidItem(final String xmlData) throws Exception {

        URL url = new URL(getFrameworkUrl() + "/xsd/rest/item/0.10/item.xsd");
        assertXmlValid(xmlData, url);
        assertXlinkXmlBaseExists(xmlData);
        assertAllPlaceholderResolved(xmlData);
        assertItemXlinkTitles(xmlData);
    }

    /**
     * Validates Component XML against the XML Schema, checks if the xml:base exists and if all placeholders are
     * replaced.
     * 
     * @param xmlData
     *            The xml document as string.
     * @throws Exception
     *             If an error occures.
     */
    public void assertXmlValidComponent(final String xmlData) throws Exception {

        URL url = new URL(getFrameworkUrl() + "/xsd/rest/item/0.10/item.xsd");
        assertXmlValid(xmlData, url);
        assertXlinkXmlBaseExists(xmlData);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * Validates ContentRelation XML against the XML Schema, checks if the xml:base exists and if all placeholders are
     * replaced.
     * 
     * @param xmlData
     *            The xml document as string.
     * @throws Exception
     *             If an error occures.
     */
    public void assertXmlValidContentRelation(final String xmlData) throws Exception {

        URL url = new URL(getFrameworkUrl() + "/xsd/rest/content-relation/0.1/content-relation.xsd");
        assertXmlValid(xmlData, url);
        assertXlinkXmlBaseExists(xmlData);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * Validates ContentRelations reistered predicates list XML against the XML Schema, checks if the xml:base exists
     * and if all placeholders are replaced.
     * 
     * @param xmlData
     *            The xml document as string.
     * @throws Exception
     *             If an error occures.
     */
    public void assertXMLValidRegisteredPredicates(final String xmlData) throws Exception {

        URL url = new URL(getFrameworkUrl() + "/xsd/rest/content-relation/0.1/predicate-list.xsd");
        assertXmlValid(xmlData, url);
        assertXlinkXmlBaseExists(xmlData);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * Validates Content Model XML against the XML Schema, if the xml:base exists and if all placeholders are resolved.
     * 
     * @param xmlData
     *            The xml document as string.
     * @throws Exception
     *             If an error occures.
     */
    public void assertXmlValidContentModel(final String xmlData) throws Exception {

        URL url = new URL(getFrameworkUrl() + "/xsd/rest/content-model/0.1/content-model" + ".xsd");
        assertXmlValid(xmlData, url);
        assertXlinkXmlBaseExists(xmlData);
        assertAllPlaceholderResolved(xmlData);
    }

    public void assertXmlValidSetDefinition(final String xmlData) throws Exception {

        URL url = new URL(getFrameworkUrl() + "/xsd/rest/set-definition/0.2/set-definition.xsd");
        assertXmlValid(xmlData, url);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * Asserts there is no namespace declaration for prefixes starting with 'xml'.
     * 
     * @param xmlData
     *            The xml document as string.
     */
    public static void assertXmlPrefixNotDeclared(final String xmlData) {
        if (xmlData.contains("xmlns:xml")) {
            fail("Namespace declaration for prefixes starting with 'xml'"
                    + " is not allowed. Even not the declaration of the XML "
                    + "Namespace because MS Internet Explorer perceive it as " + "an error.");
        }
    }

    /**
     * Asserts that all template placeholders are replaced by values.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     */
    protected void assertAllPlaceholderResolved(final String xmlData) {

        assertTrue("Placeholder not resolved during rendering\n." + xmlData,
                !PATTERN_VELOCITY_PLACEHOLDER.matcher(xmlData).find());
        assertTrue("Placeholder not resolved during rendering\n." + xmlData,
                !PATTERN_VELOCITY_PLACEHOLDER2.matcher(xmlData).find());
    }

    /**
     * Asserts that no local href (without protocol and host) appears without xml:base.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If an error ocurres.
     */
    protected void assertXlinkXmlBaseExists(final String xmlData) throws Exception {

        Document document = EscidocAbstractTest.getDocument(xmlData);
        NodeList localHrefs = selectNodeList(document, "//*[starts-with(@href, '/')]");
        NodeList xmlBase = selectNodeList(document, "//@base", document);

        assertTrue("xml:base needed", localHrefs.getLength() == 0 || xmlBase.getLength() != 0);
    }

    /**
     * Assert the XML structure of the return value (task oriented methods).
     * 
     * @param xmlData
     *            The return value of task oriented method
     * @throws Exception
     *             Thrown if the XML has not the expected structure or values.
     */
    public void assertXmlValidResult(final String xmlData) throws Exception {

        URL url = new URL(getFrameworkUrl() + "/xsd/rest/common/0.1/result.xsd");
        assertXmlValid(xmlData, url);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * @param xmlData
     *            The xml document as string.
     * @throws Exception
     *             If an error occures.
     */
    public static void assertXmlValidTaskParam(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/common/0.2/add-relations.xsd");
        assertXmlValid(xmlData, url);
    }

    public void assertXmlValidItemList(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/item/0.10/item-list.xsd");
        assertXmlValid(xmlData, url);
        assertAllPlaceholderResolved(xmlData);
    }

    public void assertXmlValidItemRefList(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/item/0.4/item-ref-list.xsd");
        assertXmlValid(xmlData, url);
        assertAllPlaceholderResolved(xmlData);
    }

    public static void assertXmlValidXmlSchema(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/common/0.2/xml-schema.xsd");
        assertXmlValid(xmlData, url);
    }

    public void assertXmlValidContextMembersList(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/common/0.10/member-list.xsd");
        assertXmlValid(xmlData, url);
    }

    public static void assertXmlValidContextMemberRefsList(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/common/0.3/member-ref-list.xsd");
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is valid for the subresource resources.
     * 
     * @param toBeAsserted
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlValidResources(final String toBeAsserted) throws Exception {

        if (resourcesSchema == null) {
            resourcesSchema = getSchema(getFrameworkUrl() + "/xsd/common/0.2/resources.xsd");
        }
        assertXmlValid(toBeAsserted, resourcesSchema);
    }

    /**
     * Asserts that the provided xml data is a valid scope.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidScope(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/scope/0.4/scope.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is a valid scope-list.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidScopeList(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/scope/0.4/scope-list.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is a valid SRW response.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidSrwResponse(final String xmlData) throws Exception {
        Schema srwListSchema = getSchema(getFrameworkUrl() + "/xsd/rest/common/0.4/srw-types.xsd");

        assertXmlValid(xmlData, srwListSchema);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * Asserts that the provided XML data is a valid struct-map.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidStructMap(final String xmlData) throws Exception {
        Schema structMapSchema = getSchema(getFrameworkUrl() + "/xsd/rest/container/0.4/struct-map.xsd");

        assertXmlValid(xmlData, structMapSchema);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * Asserts that the provided XML data is valid agains successors XSD.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidSuccessors(final String xmlData) throws Exception {
        Schema structMapSchema = getSchema(
                getFrameworkUrl() + "/xsd/rest/organizational-unit/0.8/organizational-unit-successors.xsd");

        assertXmlValid(xmlData, structMapSchema);
        assertAllPlaceholderResolved(xmlData);
    }

    /**
     * Asserts that the provided xml data is a valid aggregation-definition.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidAggregationDefinition(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/aggregation-definition/0.4/aggregation-definition.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is a valid aggregation-definition.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidTmeResult(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/tme/jhove.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is a valid aggregation-definition-list.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidAggregationDefinitionList(final String xmlData) throws Exception {
        URL url = new URL(
                getFrameworkUrl() + "/xsd/rest/aggregation-definition/0.4/aggregation-definition-list.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is a valid report-definition.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidReportDefinition(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/report-definition/0.4/report-definition.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is a valid report-definition-list.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidReportDefinitionList(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/report-definition/0.4/report-definition-list.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is a valid report-definition.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public void assertXmlValidReport(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/report/0.4/report.xsd");
        assertAllPlaceholderResolved(xmlData);
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is valid for a search result.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlValidSearchResult(final String xmlData) throws Exception {
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/search-result/0.8/srw-types.xsd");
        assertXmlValid(xmlData, url);
    }

    /**
     * Asserts that the provided xml data is valid for a explain plan.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlValidExplainPlan(final String xmlData) throws Exception {
        String replacedData = xmlData;
        if (replacedData.indexOf("explainResponse") > -1) {
            replacedData = replacedData.replaceFirst("(?s).*?(<[^>]*?explain[\\s>].*?<\\/[^>]*?explain.*?>).*",
                    "$1");
        }
        URL url = new URL(getFrameworkUrl() + "/xsd/rest/search-result/0.4/zeerex-2.0.xsd");
        assertXmlValid(replacedData, url);
    }

    /**
     * Assert the provided XML data is valid against the provided schema.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @param schemaURL
     *            The URL of the schema.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlValid(final String xmlData, final URL schemaURL) throws Exception {

        Schema theSchema = getSchema(schemaURL);
        assertXmlValid(xmlData, theSchema);
    }

    /**
     * Assert the provided XML data is valid against the provided schema.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @param schema
     *            The schema inputstream.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlValid(final String xmlData, final InputStream schema) throws Exception {

        Schema theSchema = getSchema(schema);
        assertXmlValid(xmlData, theSchema);
    }

    /**
     * Assert the provided XML data is valid against the provided schema.
     * 
     * @param xmlData
     *            The xml data to be asserted.
     * @param schema
     *            The schema.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlValid(final String xmlData, final Schema schema) throws Exception {

        assertNotNull("No Xml data. ", xmlData);
        try {
            Validator validator = schema.newValidator();
            InputStream in = new ByteArrayInputStream(xmlData.getBytes(DEFAULT_CHARSET));
            validator.validate(new SAXSource(new InputSource(in)));
        } catch (final Exception e) {
            final StringBuffer errorMsg = new StringBuffer("XML invalid. ");
            errorMsg.append(e.getMessage());
            if (LOGGER.isDebugEnabled()) {
                errorMsg.append(xmlData);
                errorMsg.append("============ End of invalid xml ============\n");
            }
            fail(errorMsg.toString());
        }
        assertXmlPrefixNotDeclared(xmlData);
    }

    /**
     * Asserts that the objid and href attributes of the root element exist and are consistent.
     * 
     * @param document
     *            The document.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public void assertHrefObjidConsistency(final Document document) throws Exception {

        assertHrefObjidConsistency(document, null);
    }

    /**
     * Asserts that a given string has the structure of an eSciDoc objid.
     * 
     * @param objid
     *            The string.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public void assertObjid(final String objid) throws Exception {

        Pattern PATTERN_OBJID_ATTRIBUTE = Pattern.compile("[a-zA-Z]+:[a-zA-Z0-9_-]+");
        if (!PATTERN_OBJID_ATTRIBUTE.matcher(objid).find()) {
            fail("Does not look like an objid: " + objid);
        }
    }

    /**
     * Asserts that the objid and href attributes exist and are consistent.
     * 
     * @param document
     *            The document.
     * @param xPath
     *            The xpath to the element containing the objid and href attributes. If this parameter is
     *            <code>null</code>, the root element is used.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public void assertHrefObjidConsistency(final Document document, final String xPath) throws Exception {

        final String objid;
        final String objidFromHref;
        if (xPath == null) {
            objid = getRootElementAttributeValue(document, NAME_OBJID);
            objidFromHref = getObjidFromHref(getRootElementHrefValue(document));
            assertEquals("Href and objid are inconsistent in root element", objidFromHref, objid);
        } else {
            Node objidNode = selectSingleNode(document, xPath + "/@objid");
            Node hrefNode = selectSingleNode(document, xPath + "/@href");
            assertNotNull("Objid not found for element [" + xPath + "]", objidNode);
            assertNotNull("Href not found for element [" + xPath + "]", hrefNode);
            objid = objidNode.getTextContent();
            objidFromHref = getObjidFromHref(hrefNode.getTextContent());
            assertEquals("Href and objid are inconsistent [" + xPath + "]", objidFromHref, objid);
        }

    }

    /**
     * Assert if the framework created the necessary elements and attributes.
     * 
     * @param xmlData
     *            The xml representation of the context.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlCreatedContext(final String xmlData) throws Exception {

        Document document = EscidocAbstractTest.getDocument(xmlData);
        assertXmlNotNull("/context/@objid", document, "/context/@objid");
        assertXmlNotNull("/context/@last-modification-date", document, "/context/@last-modification-date");

        assertXmlNotNull("/context/properties/creator/@href", document, "/context/properties/creator/@href");
        assertXmlNotNull("/context/properties/creator/@title", document, "/context/properties/creator/@title");

        assertXmlNotNull("/context/admin-descriptor/@objid", document, "/context/admin-descriptor/@objid");
        assertXmlNotNull("/context/admin-descriptor/@href", document, "/context/admin-descriptor/@href");

        assertXmlNotNull("/context/admin-descriptor/properties/creator/@href", document,
                "/context/admin-descriptor/properties/creator/@href");
        assertXmlNotNull("/context/admin-descriptor/properties/creator/@title", document,
                "/context/admin-descriptor/properties/creator/@title");

        // TODO check this list for completeness?

    }

    /**
     * Assert that the Element/Attribute selected by the xPath does not exist.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param xml
     *            XML
     * @param xPath
     *            The xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlNotExists(final String message, final String xml, final String xPath)
            throws Exception {

    }

    /**
     * Assert that the Element/Attribute selected by the xPath does not exist.
     * 
     * @param message
     *            The message printed if assertion fails.
     * @param node
     *            The Node.
     * @param xPath
     *            The xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlNotExists(final String message, final Node node, final String xPath)
            throws Exception {

        NodeList nodes = selectNodeList(node, xPath);
        assertTrue(message, nodes.getLength() == 0);
    }

    /**
     * Assert that the node selected by the xpath exists int the given document and is not empty.
     * 
     * @param elementLabel
     *            The label for assertion messages.
     * @param document
     *            The document.
     * @param xPath
     *            The xPath.
     * @throws Exception
     *             If anything fails.
     */
    public static void assertXmlNotNull(final String elementLabel, final Node document, final String xPath)
            throws Exception {
        Node element = selectSingleNode(document, xPath);
        assertNotNull(elementLabel + " not found!", element);
        assertFalse(elementLabel + " must not be empty!", "".equals(element.getTextContent()));
    }

    /**
     * Extracts the id from the href attribute of the root element of the provided document.
     * 
     * @param document
     *            The document to retrieve the id from.
     * @return Returns the extracted id value.
     * @throws Exception
     *             If anything fails.
     */
    public static String getIdFromRootElementHref(final Document document) throws Exception {

        return getObjidFromHref(getRootElementHrefValue(document));
    }

    /**
     * Obtain the objid from the href.
     * 
     * @param val
     *            The href attribute.
     * @return objid
     */
    public String getIdFromHrefValue(final String val) {
        String result = null;
        // FIXME it's no objid pattern
        Pattern PATTERN_OBJID_ATTRIBUTE = Pattern.compile(".*\\/([^\"\\/]*)");

        Matcher m1 = PATTERN_OBJID_ATTRIBUTE.matcher(val);
        if (m1.find()) {
            result = m1.group(1);
        }
        return result;
    }

    /**
     * Obtain the objid from the XML root element.
     * 
     * @param xml
     *            The XML data.
     * @return objid
     */
    public String getIdFromRootElement(final String xml) {
        String result = null;
        // FIXME PATTERN_OBJID_ATTRIBUTE is static field !
        // FIXME this pattern does not work for componentId
        Pattern pATTERNoBJIDaTTRIBUTEjUSTfORtHISmETHOD = Pattern.compile("href=\"/ir/[^/]+/([^\"]*)\"");
        Matcher m1 = pATTERNoBJIDaTTRIBUTEjUSTfORtHISmETHOD.matcher(xml);
        if (m1.find()) {
            result = m1.group(1);
        }

        return result;
    }

    /**
     * Gets the id from the provided uri (href).
     * 
     * @param href
     *            The uri to extract the id from.
     * @return Returns the extracted id.
     */
    public static String getObjidFromHref(final String href) {

        String grantId = href.substring(href.lastIndexOf('/') + 1);
        return grantId;
    }

    /**
     * Gets the href attribute of the root element from the document.
     * 
     * @param document
     *            The document to retrieve the value from.
     * @return Returns the attribute value.
     * @throws Exception
     *             If anything fails.
     */
    public static String getRootElementHrefValue(final Document document) throws Exception {

        return getRootElementAttributeValueNS(document, NAME_HREF, XLINK_NS_URI);
    }

    /**
     * Gets the objid attribute of the element selected in the provided node.<br>
     * It tries to get the objid attribute of the selected node. If this fails, it tries to get the xlink:href
     * attribute. If both fails, an assertion exception is "thrown".
     * 
     * @param node
     *            The node to select an element from.
     * @param xPath
     *            The xpath to select the element in the provided node.
     * @return Returns the attribute value.
     * @throws Exception
     *             If anything fails.
     */
    public String getObjidValue(final Node node, final String xPath) throws Exception {

        Node selected = selectSingleNode(node, xPath);
        assertNotNull("No Element selected to retrieve the object id from", selected);
        NamedNodeMap attributes = selected.getAttributes();
        assertNotNull("Selected node has no attributes (not an element?) ", attributes);
        Node objidAttr = attributes.getNamedItem(NAME_OBJID);
        if (objidAttr != null) {
            return objidAttr.getTextContent();
        } else {
            objidAttr = selectSingleNode(selected, "." + PART_XLINK_HREF);
            assertNotNull("Selected node neither has an objid " + "attribute nor an xlink href attribute",
                    objidAttr);
            return getObjidFromHref(objidAttr.getTextContent());
        }
    }

    /**
     * Gets the objid attribute of the root element from the Xml.
     * 
     * @param xml
     *            The xml representation of an object to retrieve the value from.
     * @return Returns the objid.
     * @throws Exception
     *             If anything fails.
     */
    public String getObjidValue(final String xml) throws Exception {

        Matcher m = PATTERN_OBJID_ATTRIBUTE.matcher(xml);
        if (m.find()) {
            return m.group(1);
        } else {
            fail("Missing objid in provided xml data");
            return null;
        }
    }

    /**
     * Get objId with version part of latest version of document.
     * 
     * @param xml
     *            The Item XML.
     * @return The object id of the latest version.
     * @throws Exception
     *             If anything fails.
     */
    public final String getLatestVersionObjidValue(final String xml) throws Exception {

        Node latestVersionNode = selectSingleNode(EscidocAbstractTest.getDocument(xml),
                "//properties/latest-version/number");
        String id = getIdFromRootElement(xml) + VERSION_SUFFIX_SEPARATOR + latestVersionNode.getTextContent();
        return (id);
    }

    /**
     * Remove version informaion from given objid.
     * 
     * @param objid
     *            The objid.
     * @return The objid without version information.
     */
    public static String getObjidWithoutVersion(final String objid) {

        String result = objid;
        Matcher m = PATTERN_ID_WITHOUT_VERSION.matcher(objid);
        if (m.find()) {
            result = m.group(1);
        }
        return result;
    }

    /**
     * Gets the last-modification-date attribute of the root element from the document.
     * 
     * @param document
     *            The document to retrieve the value from.
     * @return Returns the attribute value.
     * @throws Exception
     *             If anything fails.
     */
    public static String getLastModificationDateValue(final Document document) throws Exception {

        return getRootElementAttributeValue(document, "last-modification-date");
    }

    /**
     * Gets the last-modification-date attribute of the root element from the document.
     * 
     * @param document
     *            The document to retrieve the value from.
     * @return Returns the attribute value.
     * @throws Exception
     *             If anything fails.
     */
    public static DateTime getLastModificationDateValue2(final Document document) throws Exception {

        String dateString = getRootElementAttributeValue(document, "last-modification-date");
        if (dateString == null) {
            return null;
        }
        final Calendar calendar = DatatypeConverter.parseDate(dateString);
        return new DateTime(calendar.getTimeInMillis(), DateTimeZone.forTimeZone(calendar.getTimeZone()));
    }

    /**
     * Gets the creation-date element of the first element named "properties" from the document.
     * 
     * @param document
     *            The document to retrieve the value from.
     * @return Returns the creation date value or <code>null</code>.
     * @throws Exception
     *             If anything fails.
     */
    public static String getCreationDateValue(final Document document) throws Exception {

        return getCreationDateValue(document, null);
    }

    /**
     * Gets the creation-date element of the specified properties element from the document.
     * 
     * @param document
     *            The document to retrieve the value from.
     * @param xPath
     *            The xpath to the parent element that contains the creation date element. If this is <code>null</code>,
     *            the first element named "properties" will be selected.
     * @return Returns the creation date value or <code>null</code>.
     * @throws Exception
     *             If anything fails.
     */
    public static String getCreationDateValue(final Document document, final String xPath) throws Exception {

        String creationDateXpath = "";
        if (xPath == null) {
            creationDateXpath = "//properties[1]/creation-date";
        } else {
            creationDateXpath = xPath + "/creation-date";
        }
        final Node creationDateElement = selectSingleNode(document, creationDateXpath);
        if (creationDateElement == null) {
            return null;
        } else {
            return creationDateElement.getTextContent();
        }
    }

    /**
     * Get objid from ordered component.
     * 
     * @param document
     *            the document.
     * @param componentNo
     *            the component order number.
     * @return component object id
     * @throws Exception
     *             Thrown in case of internal error.
     */
    // TODO should better be in OmTestBase
    public String getComponentObjidValue(final Document document, final int componentNo) throws Exception {
        return getObjidFromHref(getAttributeValue(document,
                OmTestBase.XPATH_ITEM_COMPONENTS + "/component[" + componentNo + "]", "xlink:href"));
    }

    /**
     * Get objid from component.
     * 
     * @param document
     *            the document.
     * @param xpath
     *            tXPath identifying the component.
     * @return component object id
     * @throws Exception
     *             Thrown in case of internal error.
     */
    public String getComponentObjidValue(final Document document, final String xpath) throws Exception {
        return getObjidFromHref(getAttributeValue(document, xpath, "xlink:href"));
    }

    /**
     * Asserts that the creation-date element of the document exists.
     * 
     * @param message
     *            The fail message.
     * @param document
     *            The document to retrieve the value from.
     * @return Returns the creation date value.
     * @throws Exception
     *             If anything fails.
     */
    public static String assertCreationDateExists(final String message, final Document document) throws Exception {

        return assertCreationDateExists(message, document, null);
    }

    /**
     * Asserts that the creation-date element of the specified properties element from the document exists.
     * 
     * @param message
     *            The fail message.
     * @param document
     *            The document to retrieve the value from.
     * @param xPath
     *            The xpath to the parent element that contains the creation date element. If this is <code>null</code>,
     *            the first element named "properties" will be selected.
     * @return Returns the creation date value.
     * @throws Exception
     *             If anything fails.
     */
    public static String assertCreationDateExists(final String message, final Document document, final String xPath)
            throws Exception {

        final String creationDate = getCreationDateValue(document, xPath);
        assertNotNull(prepareAssertionFailedMessage(message) + "No creation-date", creationDate);
        return creationDate;
    }

    /**
     * Gets the value of the specified attribute of the root element from the document.
     * 
     * @param document
     *            The document to retrieve the value from.
     * @param attributeName
     *            The name of the attribute whose value shall be retrieved.
     * @param namespaceURI
     *            The namespace URI of the attribute.
     * @return Returns the attribute value.
     * @throws Exception
     *             If anything fails.
     */
    public static String getRootElementAttributeValueNS(final Document document, final String attributeName,
            final String namespaceURI) throws Exception {

        Node root = getRootElement(document);
        if (root.getNamespaceURI() != null) {
            // has been parsed namespace aware
            Node attr = root.getAttributes().getNamedItemNS(namespaceURI, attributeName);
            assertNotNull("Attribute not found [" + namespaceURI + ":" + attributeName + "]. ", attr);
            return attr.getTextContent();
        } else {
            // has not been parsed namespace aware.
            String xPath;
            if (attributeName.startsWith("@")) {
                xPath = "/*/" + attributeName;
            } else {
                xPath = "/*/@" + attributeName;
            }
            assertXmlExists("Attribute not found [" + xPath + "]. ", document, xPath);
            final Node attr = selectSingleNode(root, xPath);
            assertNotNull("Attribute not found [" + attributeName + "]. ", attr);
            String value = attr.getTextContent();
            return value;
        }
    }

    /**
     * Gets the value of the specified attribute of the root element from the document.
     * 
     * @param document
     *            The document to retrieve the value from.
     * @param attributeName
     *            The name of the attribute whose value shall be retrieved.
     * @return Returns the attribute value.
     * @throws Exception
     *             If anything fails.
     */
    public static String getRootElementAttributeValue(final Document document, final String attributeName)
            throws Exception {

        Node root = getRootElement(document);

        // has not been parsed namespace aware.
        String xPath;
        if (attributeName.startsWith("@")) {
            xPath = "/*/" + attributeName;
        } else {
            xPath = "/*/@" + attributeName;
        }
        assertXmlExists("Attribute not found [" + attributeName + "]. ", document, xPath);
        final Node attr = selectSingleNode(root, xPath);
        assertNotNull("Attribute not found [" + attributeName + "]. ", attr);
        String value = attr.getTextContent();
        return value;
    }

    /**
     * Gets the <code>Schema</code> object for the provided url.
     * 
     * @param urlString
     *            The <code>String</code> specifying the URL.
     * @return Returns the <code>Schema</code> object.
     * @throws Exception
     *             If anything fails.
     */
    public static Schema getSchema(final String urlString) throws Exception {

        URL url = urlCache.get(urlString);
        if (url == null) {
            url = new URL(urlString);
            urlCache.put(urlString, url);
        }
        return getSchema(url);
    }

    /**
     * Gets the <code>Schema</code> object for the provided <code>URL</code>.
     * 
     * @param url
     *            The url to get the schema for.
     * @return Returns the <code>Schema</code> object.
     * @throws Exception
     *             If anything fails.
     */
    public static Schema getSchema(final URL url) throws Exception {

        Schema schema = schemaCache.get(url);
        if (schema == null) {
            URLConnection conn = url.openConnection();
            InputStream schemaStream = conn.getInputStream();
            schema = getSchema(schemaStream);
            schemaCache.put(url, schema);
        }
        return schema;
    }

    /**
     * Gets the <code>Schema</code> object for the provided <code>InputStream</code>.
     * 
     * @param schemaStream
     *            The Stream containing the schema.
     * @return Returns the <code>Schema</code> object.
     * @throws Exception
     *             If anything fails.
     */
    private static Schema getSchema(final InputStream schemaStream) throws Exception {

        if (schemaStream == null) {
            throw new Exception("No schema input stream provided");
        }

        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        // set resource resolver to change schema-location-host
        sf.setResourceResolver(new SchemaBaseResourceResolver());
        Schema theSchema = sf.newSchema(new SAXSource(new InputSource(schemaStream)));
        return theSchema;
    }

    /**
     * Asserts that ts1 depicts a time after ts2 (ts1 > ts2).
     * 
     * @param message
     *            The message is the assertion fails.
     * @param ts1
     *            The first timestamp.
     * @param ts2
     *            The second timestamp.
     * @throws Exception
     *             If anything fails (e.g. one timstamp has incorrect format)
     */
    public static void assertTimestampIsEqualOrAfter(final String message, final String ts1, final String ts2)
            throws Exception {

        assertTrue(message, compareTimestamps(ts1, ts2) >= 0);
    }

    /**
     * Asserts that ts1 and ts2 depict the same time (ts1 == ts2).
     * 
     * @param message
     *            The message is the assertion fails.
     * @param ts1
     *            The first timestamp.
     * @param ts2
     *            The second timestamp.
     * @throws Exception
     *             If anything fails (e.g. one timstamp has incorrect format)
     */
    public static void assertTimestampEquals(final String message, final String ts1, final String ts2)
            throws Exception {

        assertTrue(message, compareTimestamps(ts1, ts2) == 0);
    }

    /**
     * Returns a positive integer if ts1 depicts a time after ts2 (ts1 > ts2), 0 if ts1 and ts2 depict the same time
     * (ts1 == ts2), and a negative integer if if ts1 depicts a time before ts2 (ts1 < ts2).
     * 
     * @param ts1
     *            The first timestamp.
     * @param ts2
     *            The second timestamp.
     * @return The comparison result.
     * @throws Exception
     *             If anything fails (e.g. one timstamp has incorrect format).
     */
    public static int compareTimestamps(final String ts1, final String ts2) throws Exception {

        int result = 0;

        XMLGregorianCalendar date1 = DatatypeFactory.newInstance().newXMLGregorianCalendar(ts1);
        XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(ts2);

        int diff = date1.compare(date2);
        if (diff == DatatypeConstants.LESSER) {
            result = -1;
        } else if (diff == DatatypeConstants.GREATER) {
            result = 1;
        } else if (diff == DatatypeConstants.EQUAL) {
            result = 0;
        } else if (diff == DatatypeConstants.INDETERMINATE) {
            throw new Exception("Date comparing: INDETERMINATE");
        }

        return result;
    }

    /**
     * Get the current time as timestamp. The date format is yyyy-MM-dd'T'HH:mm:ss.SSSZ.
     * 
     * @return The current time as timestamp.
     */
    public static String getNowAsTimestamp() {

        DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_PATTERN);
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        return dateFormat.format(new Date()).replaceAll("\\+0000", "Z").replaceAll("([+-][0-9]{2}):([0-9]{2})",
                "$1$2");
    }

    /**
     * 
     * @param timestamp
     * @return
     */
    public static String normalizeTimestamp(final String timestamp) {

        return timestamp.replaceAll("Z", "+0000").replaceAll("([+-][0-9]{2}):([0-9]{2})", "$1$2");
    }

    /**
     * Return a unique name. It is the concatenation of the prefix and the current time in milli seconds.
     * 
     * @param prefix
     *            The prefix.
     * @return The unique name.
     */
    public static String getUniqueName(final String prefix) {

        return prefix + System.currentTimeMillis();
    }

    /**
     * Makes the value of the provided node unique by adding a timestamp to it.
     * 
     * @param node
     *            The node to find the "name" element in and make it unique.
     * @return Returns the unique value.
     */
    public String setUniqueName(final Node node) {

        final String uniqueName = getUniqueName(node.getTextContent().trim());
        node.setTextContent(uniqueName);
        return uniqueName;
    }

    /**
     * Makes the value of the selected node of the provided node unique by adding a timestamp to it.<br>
     * If no node can be selected, an assertion fails.
     * 
     * @param node
     *            The node to find the "name" element in and make it unique.
     * @param xpath
     *            The xpath selecting the "name" element to change.
     * @return Returns the unique value.
     * @throws Exception
     *             If anything fails.
     */
    public String setUniqueValue(final Node node, final String xpath) throws Exception {

        assertNotNull("No node provided to select a node in.", node);
        Node selected = selectSingleNodeAsserted(node, xpath);
        return setUniqueName(selected);
    }

    /**
     * Changes the given template. If currentElement (e.g. /context/properties/creation-date) is not a key in the
     * elements Map, currentElement is interpreted as a xpath and the selected node is removed from the template. If the
     * value for key currentElement is different from the empty String, the selected node's value is substituted with
     * this value.
     * 
     * @param template
     *            The context template.
     * @param elements
     *            The elements Map.
     * @param currentElement
     *            The currentElemnt.
     * @return The resulting template.
     * @throws Exception
     *             If anything fails.
     */
    public static Node changeTemplateWithReadOnly(final Node template, final Map<String, String> elements,
            final String currentElement) throws Exception {
        Node result = template;
        if (elements.get(currentElement) == null) {
            deleteNodes(template, currentElement);
            //
            // if (currentElement.indexOf("@") != -1) {
            // String xpath = currentElement.substring(0, currentElement
            // .indexOf("@") - 1);
            // String attribute = currentElement.substring(currentElement
            // .indexOf("@") + 1);
            // deleteAttribute(result, xpath, attribute);
            // }
            // else {
            // result = deleteElement(result, currentElement);
            // }
        } else if (!"".equals(elements.get(currentElement))) {
            String element = currentElement;
            if (element.indexOf("@" + XLINK_HREF_TEMPLATES) != -1) {
                element = element.replaceAll("@" + XLINK_HREF_TEMPLATES, "@href");
            }
            result = substitute(result, element, elements.get(currentElement));
        }
        return result;
    }

    /**
     * Gets the root element of the provided document.
     * 
     * @param doc
     *            The document to get the root element from.
     * @return Returns the first child of the document htat is an element node.
     * @throws Exception
     *             If anything fails.
     */
    public static Element getRootElement(final Document doc) throws Exception {

        Node node = doc.getFirstChild();
        while (node != null) {
            if (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
                return (Element) node;
            }
            node = node.getNextSibling();
        }
        return null;
    }

    /**
     * Inserts the namespaces into the provided element node.
     * 
     * @param element
     *            The element into that the namespace definitions shall be inserted.
     * @return Returns the changed element node.
     * @throws Exception
     *             If anything fails.
     */
    public Element insertNamespaces(final Element element) throws Exception {

        element.setAttribute("xmlns:prefix-container", CONTAINER_NS_URI);
        element.setAttribute("xmlns:prefix-content-type", CONTENT_TYPE_NS_URI);
        element.setAttribute("xmlns:prefix-context", CONTEXT_NS_URI);
        element.setAttribute("xmlns:prefix-dc", DC_NS_URI);
        element.setAttribute("xmlns:prefix-dcterms", DCTERMS_NS_URI);
        element.setAttribute("xmlns:prefix-grants", GRANTS_NS_URI);
        element.setAttribute("xmlns:prefix-internal-metadata", INTERNAL_METADATA_NS_URI);
        element.setAttribute("xmlns:prefix-item", ITEM_NS_URI);
        element.setAttribute("xmlns:prefix-member-list", MEMBER_LIST_NS_URI);
        element.setAttribute("xmlns:prefix-member-ref-list", MEMBER_REF_LIST_NS_URI);
        element.setAttribute("xmlns:prefix-metadata", METADATA_NS_URI);
        element.setAttribute("xmlns:prefix-metadatarecords", METADATARECORDS_NS_URI);
        element.setAttribute("xmlns:prefix-organizational-unit", ORGANIZATIONAL_UNIT_NS_URI);
        element.setAttribute("xmlns:prefix-properties", PROPERTIES_NS_URI);
        element.setAttribute("xmlns:prefix-schema", SCHEMA_NS_URI);
        element.setAttribute("xmlns:prefix-staging-file", STAGING_FILE_NS_URI);
        element.setAttribute("xmlns:prefix-user-account", USER_ACCOUNT_NS_URI);
        element.setAttribute("xmlns:prefix-xacml-context", XACML_CONTEXT_NS_URI);
        element.setAttribute("xmlns:prefix-xacml-policy", XACML_POLICY_NS_URI);
        element.setAttribute("xmlns:prefix-xlink", XLINK_NS_URI);
        element.setAttribute("xmlns:prefix-xsi", XSI_NS_URI);
        return element;
    }

    /**
     * Inserts the namespaces into the root element of the provided document.
     * 
     * @param doc
     *            The document that shall be changed.
     * @return Returns the changed document.
     * @throws Exception
     *             If anything fails.
     */
    public Document insertNamespacesInRootElement(final Document doc) throws Exception {

        final Element rootElement = getRootElement(doc);
        assertNotNull("No root element found in the provided document", rootElement);
        insertNamespaces(rootElement);
        return doc;
    }

    /**
     * Inserts the namespaces into the root element of the provided xml data.
     * 
     * @param xmlData
     *            The xmlData that shall be changed.
     * @return Returns the changed XML data.
     * @throws Exception
     *             If anything fails.
     */
    public String insertNamespacesInRootElement(final String xmlData) throws Exception {

        return toString(insertNamespacesInRootElement(EscidocAbstractTest.getDocument(xmlData)), false);
    }

    protected static String prepareAssertionFailedMessage(final String message) {

        final String msg;
        if (message == null) {
            msg = "";
        } else if (!message.endsWith(" ")) {
            msg = message + " ";
        } else {
            msg = message;
        }
        return msg;
    }

    /**
     * Deletes the node selected by the given XPath from the provided node.
     * 
     * @param node
     *            The Node to delete the selected nodes from.
     * @param xPath
     *            The XPath selecting the sub nodes in the provided node.
     * @return returns the provided <code>Node</code> object. This <code>Node</code> object may be changed.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public static Node deleteNodes(final Node node, final String xPath) throws Exception {

        NodeList nodes = selectNodeList(node, xPath);
        if (nodes == null || nodes.getLength() == 0) {
            return node;
        }

        for (int i = 0; i < nodes.getLength(); ++i) {
            Node delete = nodes.item(i);
            if (delete.getNodeType() == Node.ATTRIBUTE_NODE) {
                final int index = xPath.lastIndexOf('/');
                String attribute = delete.getNodeName();
                attribute = attribute.substring(attribute.lastIndexOf(':') + 1);
                String elementXpath = xPath.substring(0, index);
                elementXpath += "[@" + attribute + "=\"" + delete.getTextContent().trim() + "\"]";
                Node parent = selectSingleNode(node, elementXpath);
                if (parent.hasAttributes()) {
                    parent.getAttributes().removeNamedItem(delete.getNodeName());
                }
            } else {
                delete.getParentNode().removeChild(delete);
            }
        }

        return node;
    }

    /**
     * Asserts that the value of the selected node of the provided node starts with the expected base.
     * 
     * @param node
     *            The node in that the node shall be selected abd asserted.
     * @param xPath
     *            The Xpath to select the node that shall be asserted.
     * @param expectedBase
     *            The expected value with that the selected node's value shall start.
     * @return Returns the value of the node that has been successfully checked.
     * @throws Exception
     *             Thrown if anything fails.
     */
    public static String assertHrefBase(final Node node, final String xPath, final String expectedBase)
            throws Exception {

        final String value = selectSingleNode(node, xPath).getTextContent();
        assertTrue("href does not start with " + expectedBase, value.startsWith(expectedBase));

        return value;
    }

    /**
     * Asserts that the selected xlink:type attribute of the provided node has the value "simple".
     * 
     * @param document
     *            The node from that the xlink:type attribute shall be selected and asserted.
     * @throws Exception
     *             If an error ocurres.
     */
    public static void assertXlinkType(final Document document, final String xPath) throws Exception {

        assertXmlExists("No xlink:type attribute found [" + xPath + "]", document,
                XPATH_USER_ACCOUNT_CURRENT_GRANTS_XLINK_TYPE);
        assertXmlEquals("Unexpected xlink:type [" + xPath + "]", document, xPath, "simple");
    }

    /**
     * 
     * @param query
     * @param format
     * @return
     */
    public static String getSemanticStoreQuery(final String query, final String format) {
        String taskParam = de.escidoc.core.test.Constants.XML_HEADER
                + "<param xmlns=\"http://www.escidoc.org/schemas/semantic-store-query/0.4\" >\n";
        taskParam += "<query>" + query + "</query>\n";
        taskParam += "<format>" + format + "</format>\n";
        taskParam += "</param>";
        return taskParam;
    }

    /**
     * Modifies the namespace prefixes of the provided xml data by adding a prefix to the namespac.
     * 
     * @param xml
     *            The xml data to change the namespace prefixes in.
     * @return Returns the modified xml data.
     */
    public static String modifyNamespacePrefixes(final String xml) {

        Matcher matcher = PATTERN_MODIFY_NAMESPACE_PREFIXES_REPLACE_PREFIXES.matcher(xml);
        String ret = matcher.replaceAll("$1prefix-$2");
        matcher = PATTERN_MODIFY_NAMESPACE_PREFIXES_FIX_NAMESPACE_DECLARATIONS.matcher(ret);
        ret = matcher.replaceAll("xmlns:prefix-$1");
        matcher = PATTERN_MODIFY_NAMESPACE_PREFIXES_FIX_PREFIX_XML.matcher(ret);
        ret = matcher.replaceAll("xml");
        return ret;
    }

    public void assertRdfList(final Document xmlDoc, final String objectTypeUri, final String orderByPropertyUri,
            final boolean descending, final int limit, final int offset) throws Exception {
        selectSingleNodeAsserted(xmlDoc, "/RDF");
        selectSingleNodeAsserted(xmlDoc, "/RDF/Description");

        NodeList descriptions = selectNodeList(xmlDoc, "/RDF/Description");

        if (limit != 0) {
            assertOrderNotAfter(descriptions.getLength(), limit);
        }

        for (int i = 0; i < descriptions.getLength(); i++) {
            NodeList nl = selectNodeList(descriptions.item(i), "type");
            boolean foundTypeObjectTypeUri = false;
            for (int j = 0; j < nl.getLength(); j++) {
                Node n = nl.item(j);
                NamedNodeMap nnm = n.getAttributes();
                Node att = nnm.getNamedItem("rdf:resource");
                String uri = att.getNodeValue();
                if (uri.equals(objectTypeUri)) {
                    foundTypeObjectTypeUri = true;
                }
            }
            if (!foundTypeObjectTypeUri) {
                String about = selectSingleNode(descriptions.item(i), "@about").getNodeValue();
                fail("Could not find type element refering " + objectTypeUri + " in RDF description of " + about
                        + ".");
            }
        }

        if (orderByPropertyUri != null) {
            String localName = orderByPropertyUri.substring(orderByPropertyUri.lastIndexOf('/') + 1);
            Node orderNodeA = null;
            Node orderNodeB = null;
            // init order node A
            NodeList nl = selectNodeList(descriptions.item(0), localName);
            for (int j = 0; j < nl.getLength(); j++) {
                // FIXME compare with namespace
                orderNodeA = nl.item(j);
            }
            for (int i = 1; i < descriptions.getLength(); i++) {
                nl = selectNodeList(descriptions.item(i), localName);
                for (int j = 0; j < nl.getLength(); j++) {
                    // FIXME compare with namespace
                    // String curNsUri = nl.item(j).getNamespaceURI();
                    // if (nsUri.equals(curNsUri)) {
                    orderNodeB = nl.item(j);
                    // }
                }
                if (descending) {
                    assertOrderNotAfter(orderNodeB.getTextContent(), orderNodeA.getTextContent());
                } else {
                    assertOrderNotAfter(orderNodeA.getTextContent(), orderNodeB.getTextContent());
                }
                orderNodeA = orderNodeB;
            }
        } else {
            String orderValueXPath = "@about";
            // "/Description/"
            // + orderByPropertyUri.substring(orderByPropertyUri
            // .lastIndexOf('/') + 1);
            for (int i = 1; i < descriptions.getLength(); i++) {
                int a, b;
                if (descending) {
                    a = i;
                    b = i - 1;
                } else {
                    a = i - 1;
                    b = i;
                }
                String lower = selectSingleNodeAsserted(descriptions.item(a), orderValueXPath).getNodeValue();
                String higher = selectSingleNodeAsserted(descriptions.item(b), orderValueXPath).getNodeValue();
                assertOrderNotAfter(lower, higher);
            }
        }

    }

    public static void assertOrderNotAfter(final int lower, final int higher) throws Exception {
        if (lower > higher) {
            fail("Incorrect order: " + lower + " < " + higher + ".");
        }
    }

    public static void assertOrderNotAfter(final String lower, final String higher) throws Exception {
        if (lower.compareTo(higher) > 0) {
            LOGGER.debug("Incorrect order: " + lower + " < " + higher + ".");
        }
    }

    public void assertContentStreamsOf_escidoc_item_198_for_create_3content_streams(final String itemId,
            final Document itemDoc, final boolean isRootContentStreams) throws Exception {

        // there should be content streams
        selectSingleNodeAsserted(itemDoc, "//content-streams[1]");
        // but only once
        assertNull(selectSingleNode(itemDoc, "//content-streams[2]"));
        if (isRootContentStreams) {
            // there should be attributes xml:base, xlink:href and
            // last-modification-date in content streams container
            selectSingleNodeAsserted(itemDoc, "/content-streams[@base]");
            // = '" + Constants.PROTOCOL + "://" + Constants.HOST_PORT + "']");
            selectSingleNodeAsserted(itemDoc,
                    "/content-streams[@href = '/ir/item/" + itemId + "/content-streams']");
            selectSingleNodeAsserted(itemDoc, "/content-streams[@last-modification-date]");
            // TODO check if latter is date
        }
        // there should be three content streams
        selectSingleNodeAsserted(itemDoc, "//content-streams/content-stream[3]");
        // not more
        assertNull(selectSingleNode(itemDoc, "//content-streams/content-stream[4]"));
        // one of each storage type
        selectSingleNodeAsserted(itemDoc, "//content-streams/content-stream[@storage='external-managed']");
        selectSingleNodeAsserted(itemDoc, "//content-streams/content-stream[@storage='internal-managed']");
        selectSingleNodeAsserted(itemDoc, "//content-streams/content-stream[@storage='external-url']");
        // check content URLs
        selectSingleNodeAsserted(itemDoc, "//content-streams/content-stream[@storage='external-managed'"
                + " and starts-with(@href,'/ir/item/')]");
        selectSingleNodeAsserted(itemDoc, "//content-streams/content-stream[@storage='internal-managed'"
                + " and starts-with(@href,'/ir/item/')]");
        selectSingleNodeAsserted(itemDoc,
                "//content-streams/content-stream[@storage='external-url'" + " and starts-with(@href,'http://')]");

        selectSingleNodeAsserted(itemDoc,
                "//content-streams/content-stream[@storage='external-managed'"
                        + " and @name='external_image' and @mime-type='image/jpeg'" + " and @href = '/ir/item/"
                        + itemId + "/content-streams/content-stream/external_image/content']");
        selectSingleNodeAsserted(itemDoc,
                "//content-streams/content-stream[@storage='internal-managed'"
                        + " and @name='internal_xml' and @mime-type='text/xml'" + " and @href = '/ir/item/" + itemId
                        + "/content-streams/content-stream/internal_xml/content']");
        selectSingleNodeAsserted(itemDoc, "//content-streams/content-stream[@storage='external-url'"
                + " and @name='redirect_image' and @mime-type='image/jpeg']");

    }

    /**
     * Uploading file to Staging Service and get URL back.
     * 
     * @param file
     *            The file which is to upload to the staging service.
     * @return The URL at the staging service.
     * @throws Exception
     *             Thrown if uploading failed.
     */
    public URL uploadFileToStagingServlet(final File file) throws Exception {

        String mimeType = file.toURI().toURL().openConnection().getContentType();
        return uploadFileToStagingServlet(file, mimeType);
    }

    /**
     * Uploading file to Staging Service and get URL back.
     * 
     * @param file
     *            The file (which is to upload).
     * @param mimeType
     *            The mime type of the content.
     * @return The URL at the staging service.
     * @throws Exception
     *             Thrown if uploading failed.
     */
    public URL uploadFileToStagingServlet(final File file, final String mimeType) throws Exception {

        InputStream fileInputStream = new FileInputStream(file);

        return uploadFileToStagingServlet(fileInputStream, file.getName(), mimeType);
    }

    /**
     * Uploading file to Staging Service and get URL back.
     * 
     * @param fileInputStream
     *            The filenInputStream (whic upload).
     * @param filename
     *            The name of the file.
     * @param mimeType
     *            The mime type of the content.
     * @return The URL fro the staging service.
     * @throws Exception
     *             Thrown if uploading failed.
     */
    public URL uploadFileToStagingServlet(final InputStream fileInputStream, final String filename,
            final String mimeType) throws Exception {

        Object result = getStagingFileClient().create(fileInputStream, mimeType, filename);
        if (result instanceof HttpResponse) {
            HttpResponse httpRes = (HttpResponse) result;
            final String stagingFileXml = EntityUtils.toString(httpRes.getEntity(), HTTP.UTF_8);
            httpRes.getEntity().consumeContent();
            Document document = EscidocAbstractTest.getDocument(stagingFileXml);
            Node fileHref = selectSingleNode(document, "/staging-file/@href");
            URL url = new URL(getFrameworkUrl() + fileHref.getTextContent());

            return url;
        } else {
            fail("Unsupported result type [" + result.getClass().getName() + "]");
            throw new Exception("Upload to staging service failed.");
        }
    }

    /**
     * @return Returns the itemClient.
     */
    public StagingFileClient getStagingFileClient() {
        return this.stagingFileClient;
    }

    /**
     * count the number of testMethods in the testClass.
     * 
     * @return number of testMethods.
     */
    public int getTestMethodCount() {
        Method[] methods = this.getClass().getMethods();
        int count = 0;
        for (int i = 0; i < methods.length; i++) {
            if (methods[i].getName().startsWith("test") && methods[i].getParameterTypes().length == 0
                    && methods[i].getReturnType().getName().equals("void")) {
                count++;
            }
        }
        return count;
    }

    /**
     * count the number of testMethods in the testClass.
     * 
     * @return number of testMethods.
     */
    public int getTestAnnotationsCount() {
        Method[] methods = this.getClass().getMethods();
        int count = 0;
        for (int i = 0; i < methods.length; i++) {
            if (methods[i].getAnnotations() != null) {
                for (Annotation annotation : methods[i].getAnnotations()) {
                    if (annotation.annotationType().equals(org.junit.Test.class)) {
                        count++;
                    }
                }
            }
        }
        return count;
    }

    /**
     * Assert that all Xlink titles match the (eSciDoc) Xlink title conventions.
     * <p/>
     * TODO this test is not complete, because of an outstanding definition. (see issue INFR-865)
     * 
     * @param xmlData
     *            XML of the Item
     */
    public void assertItemXlinkTitles(final String xmlData) throws Exception {
        Document document = EscidocAbstractTest.getDocument(xmlData);
        // relations
        Node relations = XPathAPI.selectSingleNode(document, "/item/relations/@title", document);
        if (relations != null) {
            assertEquals("Xlink:title of relations differs from convention", "Relations of Item",
                    relations.getTextContent());
        }
    }

    /**
     * Assert that all Xlink titles match the (eSciDoc) Xlink title conventions.
     * <p/>
     * TODO this test is not complete, because of an outstanding definition. (see issue INFR-865)
     * 
     * @param xmlData
     *            XML of the Container
     */
    public void assertContainerXlinkTitles(final String xmlData) throws Exception {
        Document document = EscidocAbstractTest.getDocument(xmlData);
        // relations
        Node relations = XPathAPI.selectSingleNode(document, "/container/relations/@title", document);
        if (relations != null) {
            assertEquals("Xlink:title of relations differs from convention", "Relations of Container",
                    relations.getTextContent());
        }
    }

    /**
     * Obtain version number of framework by requesting it from Admin Service.
     * 
     * @return version number of framework.
     * @throws Exception
     *             Thrown if request failed.
     */
    public String obtainFrameworkVersion() throws Exception {

        if (REPOSITORY_VERSION == null) {

            AdminClient admClient = new AdminClient();
            String info = handleXmlResult(admClient.getRepositoryInfo());

            Pattern p = Pattern.compile(".*<entry key=\"escidoc-core.build\">([^<]*)</entry>.*");
            Matcher m = p.matcher(info);
            if (m.find()) {
                REPOSITORY_VERSION = m.group(1);
            } else {
                throw new Exception("Cannot obtain framework version " + "from eSciDoc Core installation.");
            }
        }
        return REPOSITORY_VERSION;
    }

}