changeset 472:783cc1b6b615

Moved directories to org.dive4elements
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 10:53:15 +0200
parents 1a87cb24a446
children d0ac790a6c89
files artifacts-common/src/main/java/de/intevation/artifacts/common/ArtifactNamespaceContext.java artifacts-common/src/main/java/de/intevation/artifacts/common/model/DefaultUser.java artifacts-common/src/main/java/de/intevation/artifacts/common/model/KVP.java artifacts-common/src/main/java/de/intevation/artifacts/common/model/User.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/Config.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/CreationFilter.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/DateUtils.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/JSON.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/LRUCache.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/MapXPathVariableResolver.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XSLTransformer.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/ArtifactNamespaceContext.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/model/DefaultUser.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/model/KVP.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/model/User.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/ClientProtocolUtils.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/Config.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/CreationFilter.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/DateUtils.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/FileTools.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/JSON.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/LRUCache.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/MapXPathVariableResolver.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/StringUtils.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/XMLUtils.java artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/XSLTransformer.java
diffstat 30 files changed, 3437 insertions(+), 3437 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/ArtifactNamespaceContext.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2010 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-
-package de.intevation.artifacts.common;
-
-import java.util.Iterator;
-
-import javax.xml.XMLConstants;
-
-import javax.xml.namespace.NamespaceContext;
-
-/**
- * The namespace used in artifact documents.
- * @author <a href="mailto:sascha.teichmann@intevation">Sascha L. Teichmann</a>
- */
-public class ArtifactNamespaceContext
-implements   NamespaceContext
-{
-    /**
-     * The URI of the namespace of the artifacts.
-     */
-    public final static String NAMESPACE_URI =
-        "http://www.intevation.de/2009/artifacts";
-
-    /**
-     * The XML prefix for the artifacts namespace.
-     */
-    public final static String NAMESPACE_PREFIX = "art";
-
-    /**
-     * Final instance to be easily used to avoid creation
-     * of instances.
-     */
-    public static final ArtifactNamespaceContext INSTANCE =
-        new ArtifactNamespaceContext();
-
-    /**
-     * The default constructor.
-     */
-    public ArtifactNamespaceContext() {
-    }
-
-    /**
-     * @see javax.xml.namespace.NamespaceContext#getNamespaceURI(String)
-     * @param prefix The prefix
-     * @return The corresponing URI
-     */
-    public String getNamespaceURI(String prefix) {
-
-        if (prefix == null) {
-            throw new NullPointerException("Null prefix");
-        }
-
-        if (NAMESPACE_PREFIX.equals(prefix)) {
-            return NAMESPACE_URI;
-        }
-
-        if ("xml".equals(prefix)) {
-            return XMLConstants.XML_NS_URI;
-        }
-
-        return XMLConstants.NULL_NS_URI;
-    }
-
-    /**
-     * @see javax.xml.namespace.NamespaceContext#getPrefix(String)
-     * @param uri The URI
-     * @return nothing.
-     * @throws java.lang.UnsupportedOperationException
-     */
-    public String getPrefix(String uri) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String)
-     * @param uri The URI
-     * @return nothing
-     * @throws java.lang.UnsupportedOperationException
-     */
-    public Iterator getPrefixes(String uri) {
-        throw new UnsupportedOperationException();
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/model/DefaultUser.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-package de.intevation.artifacts.common.model;
-
-/**
- * The default implementation of the {@link User} interface.
- *
- * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultUser implements User {
-
-    /** The user's firstname. */
-    protected String firstName;
-
-    /** The user's lastname. */
-    protected String lastName;
-
-
-    /**
-     * Creates an empty user without name.
-     */
-    public DefaultUser() {
-    }
-
-
-    /**
-     * Creates a user with first and lastname.
-     *
-     * @param firstName The user's firstname.
-     * @param lastName The user's lastname.
-     */
-    public DefaultUser(String firstName, String lastName) {
-        this.firstName = firstName;
-        this.lastName  = lastName;
-    }
-
-
-    /**
-     * This method returns the firstname of the user.
-     *
-     * @return the firstname.
-     */
-    public String getFirstName() {
-        return firstName;
-    }
-
-
-    /**
-     * Sets the user's firstname.
-     *
-     * @param firstName The user's firstname.
-     */
-    public void setFirstName(String firstName) {
-        this.firstName = firstName;
-    }
-
-
-    /**
-     * This method returns the lastname of the user.
-     *
-     * @return the lastname.
-     */
-    public String getLastName() {
-        return lastName;
-    }
-
-
-    /**
-     * Sets the user's lastname.
-     *
-     * @param lastName The user's lastname.
-     */
-    public void setLastName(String lastName) {
-        this.lastName = lastName;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/model/KVP.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2010 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-package de.intevation.artifacts.common.model;
-
-
-public class KVP<K, V> {
-
-    private K key;
-    private V value;
-
-
-    public KVP(K key, V value) {
-        this.key   = key;
-        this.value = value;
-    }
-
-
-    public K getKey() {
-        return key;
-    }
-
-
-    public V getValue() {
-        return value;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/model/User.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-package de.intevation.artifacts.common.model;
-
-import java.io.Serializable;
-
-/**
- * An interface that describes a user of the system.
- *
- * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
- */
-public interface User extends Serializable {
-
-    /**
-     * This method returns the firstname of the user.
-     *
-     * @return the firstname.
-     */
-    public String getFirstName();
-
-
-    /**
-     * Sets the user's firstname.
-     *
-     * @param firstName The user's firstname.
-     */
-    public void setFirstName(String firstName);
-
-
-    /**
-     * This method returns the lastname of the user.
-     *
-     * @return the lastname.
-     */
-    public String getLastName();
-
-
-    /**
-     * Sets the user's lastname.
-     *
-     * @param lastName The user's lastname.
-     */
-    public void setLastName(String lastName);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,860 +0,0 @@
-/*
- * Copyright (c) 2011 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-package de.intevation.artifacts.common.utils;
-
-import javax.xml.xpath.XPathConstants;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-
-
-/**
- * This class provides methods that help creating the artifact protocol
- * documents DESCRIBE, FEED, ADVANCE and OUT.
- *
- * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
- */
-public class ClientProtocolUtils {
-
-    /** The XPath to the current state in the DESCRIBE document. */
-    public static final String XPATH_CURRENT_STATE = "/art:result/art:state";
-
-    /** The XPath to the static UI part in the DESCRIBE document. */
-    public static final String XPATH_STATIC  = "/art:result/art:ui/art:static";
-
-    /** The XPath to the dynamic UI part in the DESCRIBE document. */
-    public static final String XPATH_DYNAMIC = "/art:result/art:ui/art:dynamic";
-
-    /** The XPath to the reachable states part in the DESCRIBE document. */
-    public static final String XPATH_STATES  =
-        "/art:result/art:reachable-states";
-
-    /** The XPath to the output modes in the DESCRIBE document. */
-    public static final String XPATH_OUTPUT_MODES  =
-        "/art:result/art:outputmodes/art:output";
-
-    /** The XPath to the select node relative to the dynamic UI node in the
-     * DESCRIBE document. */
-    public static final String XPATH_DATA_SELECT = "art:select";
-
-    /** The XPath to the choices nodes relative to the select node in the
-     * DESCRIBE document. */
-    public static final String XPATH_DATA_ITEMS = "art:choices/art:item";
-
-    /** The XPath that points to the min value of a range.*/
-    public static final String XPATH_MIN_NODE = "art:min/@art:value";
-
-    /** The XPath that points to the max value of a range.*/
-    public static final String XPATH_MAX_NODE = "art:max/@art:value";
-
-    /** The XPath that points to the default min value of a range.*/
-    public static final String XPATH_DEF_MIN = "art:min/@art:default";
-
-    /** The XPath that points to the default max value of a range.*/
-    public static final String XPATH_DEF_MAX = "art:max/@art:default";
-
-    /** The XPath to a label in the artifact's DESCRIBE document. */
-    public static final String XPATH_LABEL = "art:label/text()";
-
-    /** The XPath to a value in the artifact's DESCRIBE document. */
-    public static final String XPATH_VALUE = "art:value/text()";
-
-
-    /**
-     * It should not be necessary to create instances of this class.
-     */
-    private ClientProtocolUtils() {
-    }
-
-
-    /**
-     * This method creates a new CREATE document.
-     *
-     * @return the CREATE document.
-     */
-    public static Document newCreateDocument(String factory) {
-        return newCreateDocument(factory, null);
-    }
-
-
-    /**
-     * This method creates a new CREATE document.
-     *
-     * @return the CREATE document.
-     */
-    public static Document newCreateDocument(String factory, String uuid) {
-        return newCreateDocument(factory, uuid, null);
-    }
-
-    public static Document newCreateDocument(
-        String  factory,
-        String  uuid,
-        String  ids
-    ) {
-        return newCreateDocument(factory, uuid, ids, null);
-    }
-
-    /**
-     * This method creates a new CREATE document.
-     *
-     * @return the CREATE document.
-     */
-    public static Document newCreateDocument(
-        String         factory,
-        String         uuid,
-        String         ids,
-        CreationFilter filter
-    ) {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = cr.create("action");
-        Element type   = cr.create("type");
-        Element fac    = cr.create("factory");
-
-        type.setAttribute("name", "create");
-        fac.setAttribute("name", factory);
-
-        action.appendChild(type);
-        action.appendChild(fac);
-
-        if (uuid != null) {
-            Element templ = cr.create("template");
-            templ.setAttribute("uuid", uuid);
-            action.appendChild(templ);
-        }
-
-        if (ids != null) {
-            Element id = cr.create("ids");
-            id.setAttribute("value", ids);
-            action.appendChild(id);
-        }
-
-        if (filter != null) {
-            action.appendChild(filter.toXML(cr));
-        }
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-    /**
-     * This method creates a new FEED document.
-     *
-     * @param theUuid The identifier of the artifact.
-     * @param theHash The hash of the artifact.
-     * @param theData An array that contains key/value pairs that represent the
-     * data that should be included in the FEED document.
-     *
-     * @return the FEED document.
-     */
-    public static Document newFeedDocument(
-        String     theUuid,
-        String     theHash,
-        String[][] theData)
-    {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = cr.create("action");
-        Element type   = cr.create("type");
-        Element uuid   = cr.create("uuid");
-        Element hash   = cr.create("hash");
-        Element data   = cr.create("data");
-
-        // XXX It is not nice that the type has no attribute namespace, but to
-        // be backward compatible, we don't change this now.
-        cr.addAttr(type, "name", "feed", false);
-        cr.addAttr(uuid, "value", theUuid, true);
-        cr.addAttr(hash, "value", theHash, true);
-
-        for (String[] kvp: theData) {
-            Element input = cr.create("input");
-            cr.addAttr(input, "name", kvp[0], true);
-            cr.addAttr(input, "value", kvp[1], true);
-
-            data.appendChild(input);
-        }
-
-        action.appendChild(type);
-        action.appendChild(uuid);
-        action.appendChild(hash);
-        action.appendChild(data);
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-    /**
-     * This method creates a new DESCRIBE document.
-     *
-     * @param theUuid The identifier of the artifact.
-     * @param theHash The hash of the artifact.
-     * @param ui If true, the UI part is included.
-     *
-     * @return the DESCRIBE document.
-     */
-    public static Document newDescribeDocument(
-        String  theUuid,
-        String  theHash,
-        boolean incUI)
-    {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = cr.create("action");
-        Element type   = cr.create("type");
-        Element uuid   = cr.create("uuid");
-        Element hash   = cr.create("hash");
-        Element ui     = cr.create("include-ui");
-
-        // XXX It is not nice that the type has no attribute namespace, but to
-        // be backward compatible, we don't change this now.
-        cr.addAttr(type, "name", "describe", false);
-        cr.addAttr(uuid, "value", theUuid, true);
-        cr.addAttr(hash, "value", theHash, true);
-
-        ui.setTextContent(incUI ? "true" : "false");
-
-        action.appendChild(type);
-        action.appendChild(uuid);
-        action.appendChild(hash);
-        action.appendChild(ui);
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-    /**
-     * This method creates a new ADVANCE document.
-     *
-     * @param theUuid The identifier of the artifact.
-     * @param theHash The hash of the artifact.
-     * @param theTarget The target state identifier.
-     *
-     * @return the ADVANCE document.
-     */
-    public static Document newAdvanceDocument(
-        String theUuid,
-        String theHash,
-        String theTarget)
-    {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = cr.create("action");
-        Element type   = cr.create("type");
-        Element uuid   = cr.create("uuid");
-        Element hash   = cr.create("hash");
-        Element target = cr.create("target");
-
-        // XXX It is not nice that the type has no attribute namespace, but to
-        // be backward compatible, we don't change this now.
-        cr.addAttr(type, "name", "advance", false);
-        cr.addAttr(uuid, "value", theUuid, true);
-        cr.addAttr(hash, "value", theHash, true);
-        cr.addAttr(target, "name", theTarget, true);
-
-        action.appendChild(type);
-        action.appendChild(uuid);
-        action.appendChild(hash);
-        action.appendChild(target);
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-    /**
-     * This method creates a new document that is used to create new artifact
-     * collections in the artifact server.
-     *
-     * @param name <b>Optional</b> name of the collection.
-     *
-     * @return the document to create new collections.
-     */
-    public static Document newCreateCollectionDocument(String name) {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action     = cr.create("action");
-        Element type       = cr.create("type");
-        Element collection = cr.create("collection");
-        Element attribute  = cr.create("attribute");
-
-        cr.addAttr(type, "name", "create");
-        cr.addAttr(collection, "name", name != null ? name : "");
-
-        action.appendChild(type);
-        type.appendChild(collection);
-        collection.appendChild(attribute);
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-    /**
-     * This method creates a new Document that is used to add an artifact to a
-     * collection in the artifact server.
-     *
-     * @param artId The identifier of the artifact that should be added.
-     * @param attr A document that contains attributes for the artifact's
-     * life in the collection.
-     *
-     * @return the document to add an artifact into a collection.
-     */
-    public static Document newAddArtifactDocument(String artId, Document attr) {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action    = cr.create("action");
-        Element type      = cr.create("type");
-        Element artifact  = cr.create("artifact");
-        Element attribute = cr.create("attribute");
-
-        cr.addAttr(artifact, "uuid", artId);
-        cr.addAttr(type, "name", "addartifact");
-
-        if (attr != null) {
-            attr.appendChild(attr);
-        }
-
-        action.appendChild(type);
-        type.appendChild(artifact);
-        artifact.appendChild(attribute);
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-    /**
-     * Create a new Document that is used to remove an artifact from a
-     * collection in the artifact server.
-     *
-     * @param artId The identifier of the artifact that should be added.
-     *
-     * @return the document to add an artifact into a collection.
-     */
-    public static Document newRemoveArtifactDocument(String artId) {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action    = cr.create("action");
-        Element type      = cr.create("type");
-        Element artifact  = cr.create("artifact");
-
-        cr.addAttr(artifact, "uuid", artId);
-        cr.addAttr(type, "name", "removeartifact");
-
-        action.appendChild(type);
-        type.appendChild(artifact);
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-    /**
-     * This method creates a new Document that is used to trigger the DESCRIBE
-     * operation of a collection in the artifact server.
-     *
-     * @param uuid The identifier of the collection that should be described.
-     *
-     * @return the document to describe a collection.
-     */
-    public static Document newDescribeCollectionDocument(String uuid) {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action    = cr.create("action");
-        Element type      = cr.create("type");
-        cr.addAttr(type, "name", "describe");
-
-        action.appendChild(type);
-
-        doc.appendChild(action);
-
-        return doc;
-    }
-
-
-
-    /**
-     * This function builds a document that is used as request document of the
-     * out() operation of Collections.
-     *
-     * @param uuid The identifier of the collection.
-     * @param mode The name of the desired output mode.
-     * @param type The name of the desired output type.
-     *
-     * @return the request document.
-     */
-    public static Document newOutCollectionDocument(
-        String uuid,
-        String mode,
-        String type) {
-        return newOutCollectionDocument(uuid, mode, type, null);
-    }
-
-
-    /**
-     * This function builds a document that is used as request document of the
-     * out() operation of Collections. The document <i>attr</i> might be used to
-     * adjust some settings specific to the output.
-     *
-     * @param uuid The identifier of the collection.
-     * @param mode The name of the desired output mode.
-     * @param type The name of the desired output type.
-     * @param attr A document that contains settings specific to the output.
-     *
-     * @return the request document.
-     */
-    public static Document newOutCollectionDocument(
-        String   uuid,
-        String   mode,
-        String   type,
-        Document attr)
-    {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = cr.create("action");
-
-        cr.addAttr(action, "name", mode, true);
-        cr.addAttr(action, "type", type, true);
-
-        doc.appendChild(action);
-
-        if (attr != null) {
-            Node root = attr.getFirstChild();
-
-            if (root != null) {
-                action.appendChild(doc.importNode(root, true));
-            }
-        }
-
-        return doc;
-    }
-
-
-    /**
-     * This function creates a document that is used to set the attribute of a
-     * Collection.
-     *
-     * @param uuid The identifier of the Collection.
-     * @param attr The new attribute value for the Collection.
-     *
-     * @return the document that is used to set the attribute.
-     */
-    public static Document newSetAttributeDocument(
-        String uuid,
-        Document attr)
-    {
-        Node root = attr != null ? attr.getFirstChild() : null;
-
-        if (root == null) {
-            return null;
-        }
-
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action     = ec.create("action");
-        Element type       = ec.create("type");
-        Element collection = ec.create("collection");
-
-        ec.addAttr(type, "name", "setattribute", false);
-        ec.addAttr(collection, "uuid", uuid, false);
-
-        doc.appendChild(action);
-        action.appendChild(type);
-        type.appendChild(collection);
-
-        collection.appendChild(doc.importNode(root, true));
-
-        return doc;
-    }
-
-    /**
-     * This function creates a document that is used to set the attribute of a
-     * CollectionItem.
-     *
-     * @param uuid The identifier of the CollectionItem.
-     * @param attr The new attribute value for the CollectionItem.
-     *
-     * @return the document that is used to set the attribute.
-     */
-    public static Document newSetItemAttributeDocument(
-        String uuid,
-        Document attr)
-    {
-        Node root = attr.getFirstChild();
-
-        if (root == null) {
-            return null;
-        }
-
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action   = ec.create("action");
-        Element type     = ec.create("type");
-        Element artifact = ec.create("artifact");
-
-        ec.addAttr(type, "name", "setitemattribute");
-        ec.addAttr(artifact, "uuid", uuid);
-
-        doc.appendChild(action);
-        action.appendChild(type);
-        type.appendChild(artifact);
-
-        artifact.appendChild(doc.importNode(root, true));
-
-        return doc;
-    }
-
-
-    /**
-     * This function creates a document that is used to set the time-to-live
-     * of a collection.
-     *
-     * @param ttl The ttl for the Collection.
-     *
-     * @return the document that is used to set the time-to-live.
-     */
-    public static Document newSetCollectionTTLDocument(String ttl) {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = ec.create("action");
-        Element type   = ec.create("type");
-        Element ttlEl  = ec.create("ttl");
-
-        ec.addAttr(type, "name", "settimetolive");
-        ec.addAttr(ttlEl, "value", ttl);
-
-        doc.appendChild(action);
-        action.appendChild(type);
-        type.appendChild(ttlEl);
-
-        return doc;
-    }
-
-
-    /**
-     * This function creates a document that is used to set the name of a
-     * collection.
-     *
-     * @param name The name for the Collection.
-     *
-     * @return the document that is used to set the name of a collection.
-     */
-    public static Document newSetCollectionNameDocument(String name) {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = ec.create("action");
-        Element type   = ec.create("type");
-        Element coll   = ec.create("collection");
-
-        ec.addAttr(type, "name", "setname");
-        ec.addAttr(coll, "name", name);
-
-        doc.appendChild(action);
-        action.appendChild(type);
-        type.appendChild(coll);
-
-        return doc;
-    }
-
-
-    /**
-     * This function creates a document that is used to delete an existing
-     * collection.
-     *
-     * @return the document that is used to delete an existing collection.
-     */
-    public static Document newDeleteCollectionDocument() {
-        Document doc = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element action = ec.create("action");
-        Element type   = ec.create("type");
-
-        ec.addAttr(type, "name", "delete");
-
-        doc.appendChild(action);
-        action.appendChild(type);
-
-        return doc;
-    }
-
-
-    /**
-     * Returns string value found by {@link XPATH_LABEL} relative to
-     * <i>node</i>.
-     *
-     * @param node A node.
-     *
-     * @return the string value found by {@link XPATH_LABEL}.
-     */
-    public static String getLabel(Node node) {
-        return (String) XMLUtils.xpath(
-            node,
-            XPATH_LABEL,
-            XPathConstants.STRING,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * Returns string value found by {@link XPATH_VALUE} relative to
-     * <i>node</i>.
-     *
-     * @param node A node.
-     *
-     * @return the string value found by {@link XPATH_VALUE}.
-     */
-    public static String getValue(Node node) {
-        return (String) XMLUtils.xpath(
-            node,
-            XPATH_VALUE,
-            XPathConstants.STRING,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * This method returns the static UI part of the artifact's DESCRIBE
-     * document.
-     *
-     * @param description The document returned by the artifact server's
-     * DESCRIBE operation.
-     *
-     * @return the static UI node.
-     */
-    public static Node getStaticUI(Document description) {
-        return (Node) XMLUtils.xpath(
-            description,
-            XPATH_STATIC,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * This method returns the dynamic UI part of the artifact's DESCRIBE
-     * document.
-     *
-     * @param description The document returned by the artifact server's
-     * DESCRIBE operation.
-     *
-     * @return the dynamic UI node.
-     */
-    public static Node getDynamicUI(Document description) {
-        return (Node) XMLUtils.xpath(
-            description,
-            XPATH_DYNAMIC,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * This method returns the current state node contained in the DESCRIBE
-     * document.
-     *
-     * @param description The document returned by the artifact server's
-     * DESCRIBE operation.
-     *
-     * @return the node containing information about the current state.
-     */
-    public static Node getCurrentState(Document description) {
-        return (Node) XMLUtils.xpath(
-            description,
-            XPATH_CURRENT_STATE,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * This method returns the node that contains information about the
-     * reachable states of the artifact in the artifact's DESCRIBE document.
-     *
-     * @param description The document returned by the artifact server's
-     * DESCRIBE operation.
-     *
-     * @return the node that contains the reachable states.
-     */
-    public static Node getReachableStates(Document description) {
-        return (Node) XMLUtils.xpath(
-            description,
-            XPATH_STATES,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * This method returns the output mode nodes of the DESCRIBE document.
-     *
-     * @param description The document returned by the artifact server's
-     * DESCRIBE operation.
-     *
-     * @return the node that contains the output modes.
-     */
-    public static NodeList getOutputModes(Document description) {
-        return (NodeList) XMLUtils.xpath(
-            description,
-            XPATH_OUTPUT_MODES,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * Returns the node found by {@link XPATH_DATA_SELECT}.
-     *
-     * @param dynamicNode The dynamic UI node of the DESCRIBE document.
-     *
-     * @return the select node found in the dynamic UI node.
-     */
-    public static NodeList getSelectNode(Node dynamicNode) {
-        return (NodeList) XMLUtils.xpath(
-            dynamicNode,
-            XPATH_DATA_SELECT,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * Returns the items that could be found in the <i>node</i>.
-     *
-     * @param node A select node.
-     *
-     * @return the choices nodes as node list.
-     */
-    public static NodeList getItemNodes(Node node) {
-        return (NodeList) XMLUtils.xpath(
-            node,
-            XPATH_DATA_ITEMS,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    public static String getMinNode(Node parent) {
-        return (String) XMLUtils.xpath(
-            parent,
-            XPATH_MIN_NODE,
-            XPathConstants.STRING,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    public static String getMaxNode(Node parent) {
-        return (String) XMLUtils.xpath(
-            parent,
-            XPATH_MAX_NODE,
-            XPathConstants.STRING,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    public static String getDefMin(Node parent) {
-        return (String) XMLUtils.xpath(
-            parent,
-            XPATH_DEF_MIN,
-            XPathConstants.STRING,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    public static String getDefMax(Node parent) {
-        return (String) XMLUtils.xpath(
-            parent,
-            XPATH_DEF_MAX,
-            XPathConstants.STRING,
-            ArtifactNamespaceContext.INSTANCE);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/Config.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,276 +0,0 @@
-/*
- * Copyright (c) 2010 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-
-package de.intevation.artifacts.common.utils;
-
-import java.io.File;
-import java.io.IOException;
-
-import javax.xml.namespace.QName;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import javax.xml.xpath.XPathConstants;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import org.xml.sax.SAXException;
-
-/**
- * The central access to the configuration of the artifact database.
- * This class provides some static methods to access the central
- * configuration XML file via XPath.
- *
- * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
- */
-public final class Config
-{
-    private static Logger logger = Logger.getLogger(Config.class);
-
-    /**
-     * System property name where to find the configuration directory.
-     */
-    public static final String CONFIG_DIR = "artifact.database.dir";
-
-    /**
-     * Default path to the configuration directory if none
-     * was specified by the CONFIG_DIR system property.
-     */
-    public static final File CONFIG_DIR_DEFAULT =
-        new File(new File(System.getProperty("user.home",
-            System.getProperty("user.dir", "."))), ".artifactdb");
-
-    /**
-     * Name of the central configuration XML file.
-     */
-    public static final String CONFIG_FILE  = "conf.xml";
-
-    /**
-     * Name of the configuration filename alias to be use
-     * within the configuration. This alias is replaced by
-     * the real path.
-     */
-    public static final String CONFIG_DIR_PLACEHOLDER =
-        "${artifacts.config.dir}";
-
-    private static Document config;
-
-    private Config() {
-    }
-
-    /**
-     * Singleton access to the central XML configuration document.
-     * @return The central XML configuration document.
-     */
-    public static synchronized final Document getConfig() {
-        if (config == null) {
-            config = loadConfig();
-        }
-        return config;
-    }
-
-    /**
-     * Returns the path to the configuartion directory. If a path
-     * was specified via the CONFIG_DIR system property this one
-     * is used. Else it falls back to default configuration path.
-     * @return The path to the configuartion directory.
-     */
-    public static File getConfigDirectory() {
-        String configDirString = System.getProperty(CONFIG_DIR);
-
-        File configDir = configDirString != null
-            ? new File(configDirString)
-            : CONFIG_DIR_DEFAULT;
-
-        if (!configDir.isDirectory()) {
-            logger.warn("'" + configDir + "' is not a directory.");
-            configDir = CONFIG_DIR_DEFAULT;
-        }
-
-        return configDir;
-    }
-
-    /**
-     * Replaces the CONFIG_DIR_PLACEHOLDER alias with the real path
-     * of the configuration directory.
-     * @param path The path containing the CONFIG_DIR_PLACEHOLDER placeholder.
-     * @return The path where the CONFIG_DIR_PLACEHOLDER placeholders are
-     * replaced by the real path name.
-     */
-    public static String replaceConfigDir(String path) {
-        String configDir = getConfigDirectory().getAbsolutePath();
-        return path.replace(CONFIG_DIR_PLACEHOLDER, configDir);
-    }
-
-    private static Document loadConfig() {
-
-        File configDir = getConfigDirectory();
-
-        File file = new File(configDir, CONFIG_FILE);
-
-        if (!file.canRead() && !file.isFile()) {
-            logger.error("Cannot read config file '"
-                + file + "'.");
-            return null;
-        }
-
-        try {
-            DocumentBuilderFactory factory =
-                DocumentBuilderFactory.newInstance();
-            factory.setValidating(false); // XXX: This may change in future.
-            return factory.newDocumentBuilder().parse(file);
-        }
-        catch (SAXException se) {
-            logger.error(se.getLocalizedMessage(), se);
-        }
-        catch (ParserConfigurationException pce) {
-            logger.error(pce.getLocalizedMessage(), pce);
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage());
-        }
-
-        return null;
-    }
-
-    /**
-     * Convenience method to search within a given document tree via XPath.
-     * See {@link XMLUtils#xpath(Object, String, QName) } for details.
-     * @param root The object which is used as the root of the tree to
-     * be searched in.
-     * @param query The XPath query.
-     * @param returnType The type of the result.
-     * @return The result of type 'returnTyp' or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final Object getXPath(
-        Object root, String query, QName returnType
-    ) {
-        return XMLUtils.xpath(root, query, returnType);
-    }
-
-    /**
-     * Convenience method to search within the central configuration via XPath.
-     * See {@link XMLUtils#xpath(Object, String, QName) } for details.
-     * @param query The XPath query.
-     * @param returnType The type of the result.
-     * @return The result of type 'returnTyp' or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final Object getXPath(String query, QName returnType) {
-        return XMLUtils.xpath(getConfig(), query, returnType);
-    }
-
-    /**
-     * Convenience method to search for a node list within the central
-     * configuation document via XPath.
-     * @param query The XPath query.
-     * @return The queried node list or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final NodeList getNodeSetXPath(String query) {
-        return (NodeList)getXPath(query, XPathConstants.NODESET);
-    }
-
-    /**
-     * Convenience method to search for a node within the central
-     * configuation document via XPath.
-     * @param query The XPath query.
-     * @return The queried node or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final Node getNodeXPath(String query) {
-        return (Node)getXPath(query, XPathConstants.NODE);
-    }
-
-    /**
-     * Convenience method to search for a string within the central
-     * configuation document via XPath.
-     * @param xpath The XPath query.
-     * @return The queried string or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final String getStringXPath(String xpath) {
-        return getStringXPath(xpath, null);
-    }
-
-    /**
-     * Convenience method to search for a string within the central
-     * configuation document via XPath.
-     * @param query The XPath query.
-     * @param def The string to be returned if the search has no results.
-     * @return The queried string or the default value if something went
-     * wrong during XPath evaluation.
-     */
-    public static final String getStringXPath(String query, String def) {
-        String s = (String)getXPath(query, XPathConstants.STRING);
-        return s == null || s.length() == 0
-            ? def
-            : s;
-    }
-
-    /**
-     * Convenience method to search for a node list within a given tree
-     * via XPath.
-     * @param root The root of the tree to be searched in.
-     * @param query The XPath query.
-     * @return The queried node list or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final NodeList getNodeSetXPath(Object root, String query) {
-        return (NodeList)getXPath(root, query, XPathConstants.NODESET);
-    }
-
-    /**
-     * Convenience method to search for a node within a given tree
-     * via XPath.
-     * @param root The root of the tree to be searched in.
-     * @param query The XPath query.
-     * @return The queried node or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final Node getNodeXPath(Object root, String query) {
-        return (Node)getXPath(root, query, XPathConstants.NODE);
-    }
-
-    /**
-     * Convenience method to search for a string within a given tree
-     * via XPath.
-     * @param root The root of the tree to be searched in.
-     * @param xpath The XPath query.
-     * @return The queried string or null if something went
-     * wrong during XPath evaluation.
-     */
-    public static final String getStringXPath(Object root, String xpath) {
-        return getStringXPath(root, xpath, null);
-    }
-
-    /**
-     * Convenience method to search for a string within a given tree
-     * via XPath.
-     * @param root The root of the tree to be searched in.
-     * @param query xpath The XPath query.
-     * @param def The string to be returned if the search has no results.
-     * @return The queried string or the default value if something went
-     * wrong during XPath evaluation.
-     */
-    public static final String getStringXPath(
-        Object root, String query, String def
-    ) {
-        String s = (String)getXPath(root, query, XPathConstants.STRING);
-        return s == null || s.length() == 0
-            ? def
-            : s;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/CreationFilter.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-package de.intevation.artifacts.common.utils;
-
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-
-import org.w3c.dom.Element;
-
-public class CreationFilter
-{
-    public static class Facet {
-
-        protected String name;
-        protected String index;
-
-        public Facet() {
-        }
-
-        public Facet(String name, String index) {
-            this.name  = name;
-            this.index = index;
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public String getIndex() {
-            return index;
-        }
-    }
-
-    protected Map<String, List<Facet>> outs;
-
-    public CreationFilter() {
-        outs = new HashMap<String, List<Facet>>();
-    }
-
-    public void add(String out, List<Facet> facets) {
-        outs.put(out, facets);
-    }
-
-    public Element toXML(XMLUtils.ElementCreator ec) {
-        Element filter = ec.create("filter");
-
-        for (Map.Entry<String, List<Facet>> entry: outs.entrySet()) {
-            Element out = ec.create("out");
-            out.setAttribute("name", entry.getKey());
-            for (Facet facet: entry.getValue()) {
-                Element f = ec.create("facet");
-                f.setAttribute("name", facet.getName());
-                f.setAttribute("index", facet.getIndex());
-                out.appendChild(f);
-            }
-            filter.appendChild(out);
-        }
-
-        return filter;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/DateUtils.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-package de.intevation.artifacts.common.utils;
-
-import java.util.Calendar;
-import java.util.Date;
-
-
-public class DateUtils {
-
-    private DateUtils() {
-    }
-
-
-    /**
-     * This function extracts the year as int value from <i>date</i>.
-     *
-     * @param date The source date.
-     *
-     * @return the year as integer or -1 if date is empty.
-     */
-    public static int getYearFromDate(Date date) {
-        if (date == null) {
-            return -1;
-        }
-
-        Calendar cal = Calendar.getInstance();
-        cal.setTime(date);
-
-        return cal.get(Calendar.YEAR);
-    }
-}
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,613 +0,0 @@
-/*
- * Copyright (c) 2010, 2011 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-package de.intevation.artifacts.common.utils;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.io.BufferedOutputStream;
-import java.nio.channels.FileChannel;
-
-import java.util.Deque;
-import java.util.ArrayDeque;
-import java.util.List;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-
-import org.apache.log4j.Logger;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-public class FileTools
-{
-    private static Logger log = Logger.getLogger(FileTools.class);
-
-    public static final String DIGEST =
-        System.getProperty("artifacts.common.file.cmp.digest", "MD5");
-
-    private FileTools() {
-    }
-
-
-    /** Remove everything after dot from name. */
-    public static final String removeExtension(String name) {
-        int index = name.lastIndexOf('.');
-        return index == -1
-            ? name
-            : name.substring(0, index);
-    }
-
-
-    public static File getDirectory(String path, String name) {
-        if (path == null || name == null) {
-            return null;
-        }
-
-        File dir = new File(path, name);
-
-        if (!dir.exists()) {
-            log.debug(
-                "Directory '" + dir.getAbsolutePath() + "' doesn't " +
-                "exist. Try to create it.");
-
-            return dir.mkdir() ? dir : null;
-        }
-        else {
-            return dir.isDirectory() ? dir : null;
-        }
-    }
-
-    public static File repair(File file) {
-        file = file.getAbsoluteFile();
-        if (file.exists()) {
-            return file;
-        }
-        Deque<String> parts = new ArrayDeque<String>();
-        File curr = file;
-        while (curr != null) {
-            String name = curr.getName();
-            if (name.length() > 0) {
-                parts.push(curr.getName());
-            }
-            curr = curr.getParentFile();
-        }
-
-        curr = null;
-        OUTER: while (!parts.isEmpty()) {
-            String f = parts.pop();
-            log.debug("fixing: '" + f + "'");
-            if (f.equals(".") || f.equals("..")) {
-                // No need to fix . or ..
-                continue;
-            }
-            if (curr == null) {
-                // XXX: Not totaly correct because there
-                // more than one root on none unix systems.
-                for (File root: File.listRoots()) {
-                    File [] files = root.listFiles();
-                    if (files == null) {
-                        log.warn("cannot list '" + root);
-                        continue;
-                    }
-                    for (File candidate: files) {
-                        if (candidate.getName().equalsIgnoreCase(f)) {
-                            curr = new File(root, candidate.getName());
-                            continue OUTER;
-                        }
-                    }
-                }
-                break;
-            }
-            else {
-                File [] files = curr.listFiles();
-                if (files == null) {
-                    log.warn("cannot list: '" + curr + "'");
-                    return file;
-                }
-                for (File candidate: files) {
-                    if (candidate.getName().equalsIgnoreCase(f)) {
-                        curr = new File(curr, candidate.getName());
-                        continue OUTER;
-                    }
-                }
-                curr = null;
-                break;
-            }
-        }
-
-        if (curr == null) {
-            log.warn("cannot repair path '" + file + "'");
-            return file;
-        }
-
-        return curr;
-    }
-
-    /** Object that can calculate hash of file, compare two hashed files etc. */
-    public static class HashedFile
-    implements Comparable<HashedFile>
-    {
-        protected File    file;
-        protected long    length;
-        protected byte [] hash;
-
-        public HashedFile(File file) {
-            this.file = file;
-            length = file.length();
-        }
-
-        public File getFile() {
-            return file;
-        }
-
-        protected byte [] getHash() {
-            if (hash == null) {
-                InputStream in = null;
-
-                try {
-                    in = new FileInputStream(file);
-
-                    MessageDigest digest = MessageDigest.getInstance(DIGEST);
-
-                    byte [] buf = new byte[40*1024];
-                    int r;
-
-                    while ((r = in.read(buf)) >= 0) {
-                        digest.update(buf, 0, r);
-                    }
-
-                    hash = digest.digest();
-                }
-                catch (IOException ioe) {
-                    log.error(ioe);
-                    hash = new byte[0];
-                }
-                catch (NoSuchAlgorithmException nsae) {
-                    log.error(nsae);
-                    hash = new byte[0];
-                }
-                finally {
-                    if (in != null) {
-                        try {
-                            in.close();
-                        }
-                        catch (IOException ioe) {
-                            log.error(ioe);
-                        }
-                    }
-                }
-            }
-            return hash;
-        }
-
-        @Override
-        public int compareTo(HashedFile other) {
-            if (length < other.length) return -1;
-            if (length > other.length) return +1;
-            return compare(getHash(), other.getHash());
-        }
-
-        private static int compare(byte [] a, byte [] b) {
-            if (a.length < b.length) return -1;
-            if (a.length > b.length) return +1;
-            for (int i = 0; i < a.length; ++i) {
-                int x = a[i] & 0xff;
-                int y = b[i] & 0xff;
-                if (x < y) return -1;
-                if (x > y) return +1;
-            }
-            return 0;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            return other instanceof HashedFile
-                && ((HashedFile)other).compareTo(this) == 0;
-        }
-
-        @Override
-        public int hashCode() {
-            return (int)(length ^ (length >>> 32));
-        }
-    } // class HashedFile
-
-    public static List<File> uniqueFiles(List<File> files) {
-
-        Set<HashedFile> set = new HashSet<HashedFile>();
-
-        for (File file: files) {
-            if (!set.add(new HashedFile(file))) {
-                log.warn("file '" + file + "' is a duplicate.");
-            }
-        }
-
-        ArrayList<File> out = new ArrayList<File>(set.size());
-        for (HashedFile hf: set) {
-            out.add(hf.file);
-        }
-
-        return out;
-    }
-
-    public interface FileVisitor {
-        boolean visit(File file);
-    } // Visitor
-
-    public static void walkTree(File root, FileVisitor visitor) {
-
-        Deque<File> stack = new ArrayDeque<File>();
-
-        stack.push(root);
-
-        while (!stack.isEmpty()) {
-            File current = stack.pop();
-            if (!visitor.visit(current)) break;
-            if (current.isDirectory()) {
-                File [] subs = current.listFiles();
-                if (subs != null) {
-                    for (File f: subs) {
-                        stack.push(f);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Deletes everything in a directory.
-     *
-     * @param dir The directory.
-     */
-    public final static void deleteContent(File dir) {
-        if (dir == null || !dir.isDirectory()) {
-            return;
-        }
-
-        File[] files = dir.listFiles();
-        if (files != null) {
-            for (File file: files) {
-                deleteRecursive(file);
-            }
-        }
-
-        return;
-    }
-
-    /**
-     * Delete <i>file</i> and everything in <i>file</i> if it is a directory.
-     *
-     * @param file The file or directory.
-     * @return true, if deletion was successful - otherwise false.
-     */
-    public final static boolean deleteRecursive(File file) {
-
-        if (file == null) {
-            return false;
-        }
-
-        if (file.isDirectory()) {
-            File [] files = file.listFiles();
-            if (files != null) {
-                for (File sub: files) {
-                    if (!deleteRecursive(sub)) {
-                        return false;
-                    }
-                }
-            }
-        }
-
-        return file.delete();
-    }
-
-    /**
-     * Put the given file or directory into a zip archive.
-     *
-     * @param file The file or directory.
-     * @param outputStream The stream to write the archive to.
-     * @throws IOException if an error occured while zip creation or writing to
-     * output stream.
-     */
-    public static void createZipArchive(
-        File         file,
-        OutputStream outputStream
-    )
-    throws IOException
-    {
-        ZipOutputStream out = new ZipOutputStream(outputStream);
-
-        if (file.isFile()) {
-            copyFileToZip("", file, out);
-        }
-        else if (file.isDirectory()) {
-
-            Deque<PrefixDir> stack = new ArrayDeque<PrefixDir>();
-            stack.push(new PrefixDir(file.getName() + "/", file));
-
-            while (!stack.isEmpty()) {
-                PrefixDir pd = stack.pop();
-
-                ZipEntry dirEntry = new ZipEntry(pd.prefix);
-                out.putNextEntry(dirEntry);
-                out.closeEntry();
-
-                File [] files = pd.dir.listFiles();
-                if (files != null) {
-                    for (File sub: files) {
-                        if (sub.isDirectory()) {
-                            stack.push(new PrefixDir(
-                                pd.prefix + sub.getName() + "/",
-                                sub));
-                        }
-                        else if (sub.isFile()) {
-                            copyFileToZip(pd.prefix, sub, out);
-                        }
-                    }
-                }
-            }
-        }
-
-        out.finish();
-    }
-
-
-    public static void extractArchive(File archive, File destDir)
-    throws IOException {
-        if (!destDir.exists()) {
-            destDir.mkdir();
-        }
-
-        ZipFile zipFile = new ZipFile(archive);
-        try {
-            Enumeration<? extends ZipEntry> entries = zipFile.entries();
-
-            byte [] buffer = new byte[16384];
-
-            while (entries.hasMoreElements()) {
-                ZipEntry entry = entries.nextElement();
-
-                String entryFileName = entry.getName();
-
-                File dir = buildDirectoryHierarchyFor(entryFileName, destDir);
-                if (!dir.exists()) {
-                    dir.mkdirs();
-                }
-
-                if (!entry.isDirectory()) {
-                    BufferedInputStream bis = new BufferedInputStream(
-                        zipFile.getInputStream(entry));
-                    try {
-                        BufferedOutputStream bos = new BufferedOutputStream(
-                            new FileOutputStream(new File(destDir, entryFileName)));
-
-                        try {
-                            int len;
-                            while ((len = bis.read(buffer)) > 0) {
-                                bos.write(buffer, 0, len);
-                            }
-                            bos.flush();
-                        }
-                        finally {
-                            bos.close();
-                        }
-                    }
-                    finally {
-                        bis.close();
-                    }
-                } // is file
-            }
-        }
-        finally {
-            zipFile.close();
-        }
-    }
-
-    private static File buildDirectoryHierarchyFor(
-        String entryName,
-        File destDir)
-    {
-        int lastIndex = entryName.lastIndexOf('/');
-        String internalPathToEntry = entryName.substring(0, lastIndex + 1);
-        return new File(destDir, internalPathToEntry);
-    }
-
-    /**
-     * A class representing a directory with a prefix.
-     */
-    private static final class PrefixDir {
-
-        String prefix;
-        File   dir;
-
-        public PrefixDir(String prefix, File dir) {
-            this.prefix = prefix;
-            this.dir    = dir;
-        }
-
-    } // class PrefixDir
-
-    /**
-     * Write a file to zip archive.
-     *
-     * @param prefix A prefix.
-     * @param file The file.
-     * @param out The output stream.
-     * @throws IOException if an error occured while writing to zip output
-     * stream.
-     */
-    private static void copyFileToZip(
-        String          prefix,
-        File            file,
-        ZipOutputStream out
-    )
-    throws IOException
-    {
-        String   entryName = prefix + file.getName();
-        ZipEntry entry     = new ZipEntry(entryName);
-        out.putNextEntry(entry);
-        InputStream in = null;
-        try {
-            in =
-                new BufferedInputStream(
-                new FileInputStream(file), 20*1024);
-
-            byte [] buf = new byte[2048];
-
-            int r;
-            while ((r = in.read(buf)) > 0) {
-                out.write(buf, 0, r);
-            }
-        }
-        finally {
-            if (in != null) {
-                try { in.close(); }
-                catch (IOException ioe) {}
-            }
-        }
-        out.closeEntry();
-    }
-
-
-    /**
-     * Copies a <i>src</i> file to <i>target</i>.
-     *
-     * @param src A file (not a directory) that should be copied.
-     * @param target The destination. This might be a file or a directory.
-     *
-     * @return true, if <i>src</i> has been successfully copied; otherwise
-     * false.
-     */
-    public static boolean copyFile(File src, File target)
-    throws IOException
-    {
-        if (src == null || !src.exists()) {
-            log.warn("Source file does not exist!");
-            return false;
-        }
-
-        if (!src.canRead()) {
-            log.warn("Cannot read Source file!");
-            return false;
-        }
-
-        if (src.isDirectory()) {
-            log.warn("Source is a directory!");
-            return false;
-        }
-
-        if (target.isDirectory()) {
-            target = new File(target, src.getName());
-        }
-
-        FileInputStream  in  = null;
-        FileOutputStream out = null;
-
-        try {
-            in  = new FileInputStream(src);
-            out = new FileOutputStream(target);
-
-            FileChannel inChannel  = in.getChannel();
-            FileChannel outChannel = out.getChannel();
-
-            inChannel.transferTo(0l, inChannel.size(), outChannel);
-
-            return true;
-        }
-        catch (IOException ioe) {
-            log.warn(ioe, ioe);
-        }
-        finally {
-            if (in != null) {
-                try {
-                    in.close();
-                }
-                catch (IOException ioe) { /* do nothing here */ }
-            }
-
-            if (out != null) {
-                try {
-                    out.close();
-                }
-                catch (IOException ioe) { /* do nothing here */ }
-            }
-        }
-
-        return false;
-    }
-
-
-    /**
-     * Copies a directory <i>source</i> to a destination path <i>dest</i>.
-     *
-     * @param source A directory that should be copied.
-     * @param dest A destination directory which is created if it is not
-     * existing yet.
-     *
-     * @return true, if the directory has been successfully copied; otherwise
-     * false.
-     */
-    public static boolean copyDirectory(final File source, final File dest) {
-        if (source == null || !source.exists()) {
-            log.warn("Source directory does not exist!");
-            return false;
-        }
-
-        if (!source.isDirectory()) {
-            log.warn("Source is not a directory!");
-            return false;
-        }
-
-        if (dest == null) {
-            log.warn("Destination directory is null!");
-            return false;
-        }
-
-        if (!dest.exists()) {
-            if (!dest.mkdir()) {
-                log.warn("Cannot create destination directory!");
-                return false;
-            }
-        }
-
-        File[] children = source.listFiles();
-        int    failed   = 0;
-
-        if (children != null && children.length > 0) {
-            for (File child: children) {
-                if (child.isFile()) {
-                    try {
-                        if (!copyFile(child, dest)) {
-                            failed++;
-                        }
-                    }
-                    catch (IOException ioe) {
-                        log.warn(ioe, ioe);
-                        failed++;
-                    }
-                }
-                else if (child.isDirectory()) {
-                    copyDirectory(child, new File(dest, child.getName()));
-                }
-            }
-        }
-
-        log.debug("Failed to copy " + failed + " files.");
-
-        return true;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/JSON.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,445 +0,0 @@
-package de.intevation.artifacts.common.utils;
-
-import java.util.Map;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import java.io.IOException;
-import java.io.PushbackInputStream;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.io.ByteArrayInputStream;
-import java.io.StringWriter;
-
-import java.nio.charset.Charset;
-import java.nio.charset.UnsupportedCharsetException;
-
-public final class JSON
-{
-    private JSON() {
-    }
-
-    private static final boolean isDigit(int c) {
-        return c >= '0' && c <= '9';
-    }
-
-    public static final boolean isWhitespace(int c) {
-        return c == ' '  || c == '\n' || c == '\r'
-            || c == '\t' || c == '\f';
-    }
-
-    private static final void match(int c, int x) throws IOException {
-        if (c != x) {
-            throw new IOException(
-                "Expecting '" + (char)c + "' found '" + (char)x + "'");
-        }
-    }
-
-    private static final int eof(InputStream in)
-    throws IOException
-    {
-        int c = in.read();
-        if (c == -1) {
-            throw new IOException("EOF unexpected.");
-        }
-        return c;
-    }
-
-    private static final int whitespace(InputStream in)
-    throws IOException
-    {
-        int c;
-        while (isWhitespace(c = eof(in)));
-        return c;
-    }
-
-    private static final int parseHex(String hex) throws IOException {
-        try {
-            return Integer.parseInt(hex, 16);
-        }
-        catch (NumberFormatException nfe) {
-            throw new IOException("'" + hex + "' is not a hex string.");
-        }
-    }
-
-    public static final String jsonString(String string) {
-        StringBuilder sb = new StringBuilder(string.length()+2);
-
-        sb.append('"');
-
-        for (int i = 0, N = string.length(); i < N; ++i) {
-            char c = string.charAt(i);
-            switch (c) {
-                case '"':  sb.append("\\\""); break;
-                case '\t': sb.append("\\t"); break;
-                case '\r': sb.append("\\r"); break;
-                case '\n': sb.append("\\n"); break;
-                case '\b': sb.append("\\b"); break;
-                case '\f': sb.append("\\f"); break;
-                default:
-                    if (c >= 128) {
-                        sb.append("\\u");
-                        String hex = Integer.toHexString((int)c);
-                        for (int j = 4-hex.length(); j > 0; --j) {
-                            sb.append('0');
-                        }
-                        sb.append(hex);
-                    }
-                    else {
-                        sb.append(c);
-                    }
-            }
-        }
-
-        sb.append('"');
-
-        return sb.toString();
-    }
-
-    public static String toJSONString(Map<String, Object> map) {
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        write(pw, map);
-        pw.flush();
-        return sw.toString();
-    }
-
-
-    public static void write(PrintWriter out, Map<String, Object> map) {
-        writeObject(out, map);
-    }
-
-    private static void writeValue(PrintWriter out, Object value) {
-        if (value instanceof Map) {
-            writeObject(out, (Map)value);
-        }
-        else if (value instanceof List) {
-            writeList(out, (List)value);
-        }
-        else if (value instanceof Number) {
-            out.print(value);
-        }
-        else if (value instanceof Boolean) {
-            out.print(((Boolean)value) ? "true" : "false");
-        }
-        else if (value == null) {
-            out.print("null");
-        }
-        else {
-            out.print(jsonString(value.toString()));
-        }
-    }
-
-    private static void writeObject(PrintWriter out, Map map) {
-
-        out.print('{');
-        Iterator iter = map.entrySet().iterator();
-        while (iter.hasNext()) {
-            Map.Entry entry = (Map.Entry)iter.next();
-            out.print(jsonString(entry.getKey().toString()));
-            out.print(':');
-            writeValue(out, entry.getValue());
-            if (iter.hasNext()) {
-                out.print(',');
-            }
-        }
-        out.print('}');
-    }
-
-    private static void writeList(PrintWriter out, List list) {
-        out.print('[');
-        Iterator iter = list.iterator();
-        while (iter.hasNext()) {
-            writeValue(out, iter.next());
-            if (iter.hasNext()) {
-                out.print(',');
-            }
-        }
-        out.print(']');
-    }
-
-    public static Map<String, Object> parse(String in)
-    throws IOException
-    {
-        return parse(asInputStream(in));
-    }
-
-    private static InputStream asInputStream(String in) {
-        byte [] bytes;
-        try {
-            bytes = in.getBytes(Charset.forName("US-ASCII"));
-        }
-        catch (UnsupportedCharsetException uce) {
-            // Should not happen.
-            bytes = in.getBytes();
-        }
-        return new ByteArrayInputStream(bytes);
-    }
-
-    public static Map<String, Object> parse(InputStream in)
-    throws IOException
-    {
-        return parseObject(new PushbackInputStream(in, 1));
-    }
-
-    public static Map<String, Object> parse(PushbackInputStream in)
-    throws IOException
-    {
-        return parseObject(in);
-    }
-
-    private static final String parseString(
-        PushbackInputStream in
-    )
-    throws IOException
-    {
-        StringBuilder sb = new StringBuilder();
-
-        int mode = 0;
-
-        char [] hex = new char[4];
-
-        match('"', eof(in));
-
-        OUT: for (int c = eof(in);; c = eof(in)) {
-
-            switch (mode) {
-                case 0:
-                    if (c == '"') {
-                        break OUT;
-                    }
-                    if (c == '\\') {
-                        mode = 1;
-                    }
-                    else {
-                        sb.append((char)c);
-                    }
-                    break;
-                case 1:
-                    switch (c) {
-                        case 'u':
-                            mode = 2;
-                            continue;
-                        case 'b':
-                            sb.append('\b');
-                            break;
-                        case 'f':
-                            sb.append('\f');
-                            break;
-                        case 'n':
-                            sb.append('\n');
-                            break;
-                        case 'r':
-                            sb.append('\r');
-                            break;
-                        case 't':
-                            sb.append('\t');
-                            break;
-                        default:
-                            sb.append((char)c);
-                    }
-                    mode = 0;
-                    break;
-                case 2:
-                    hex[0] = (char)c;
-                    mode = 3;
-                    break;
-                case 3:
-                    hex[1] = (char)c;
-                    mode = 4;
-                    break;
-                case 4:
-                    hex[2] = (char)c;
-                    mode = 5;
-                    break;
-                case 5:
-                    hex[3] = (char)c;
-                    sb.append((char)parseHex(new String(hex)));
-                    mode = 0;
-                    break;
-            }
-        }
-        return sb.toString();
-    }
-
-    private static final Boolean parseTrue(InputStream in)
-    throws IOException
-    {
-        match('t', eof(in));
-        match('r', eof(in));
-        match('u', eof(in));
-        match('e', eof(in));
-        return Boolean.TRUE;
-    }
-
-    private static final Boolean parseFalse(InputStream in)
-    throws IOException
-    {
-        match('f', eof(in));
-        match('a', eof(in));
-        match('l', eof(in));
-        match('s', eof(in));
-        match('e', eof(in));
-        return Boolean.FALSE;
-    }
-
-    private static final Object parseNull(InputStream in)
-    throws IOException
-    {
-        match('n', eof(in));
-        match('u', eof(in));
-        match('l', eof(in));
-        match('l', eof(in));
-        return null;
-    }
-
-    private static final Number parseNumber(PushbackInputStream in)
-    throws IOException
-    {
-        StringBuilder sb = new StringBuilder();
-
-        boolean isInteger = true;
-
-        int c;
-        OUT: for (;;) {
-            switch (c = eof(in)) {
-                case '0': case '1': case '2': case '3': case '4':
-                case '5': case '6': case '7': case '8': case '9':
-                case '-': case '+':
-                    sb.append((char)c);
-                    break;
-                case '.': case 'e': case 'E':
-                    isInteger = false;
-                    sb.append((char)c);
-                    break;
-                default:
-                    in.unread(c);
-                    break OUT;
-            }
-        }
-
-        try {
-            if (isInteger) {
-                return sb.length() > 9
-                    ? (Number)Long   .valueOf(sb.toString())
-                    : (Number)Integer.valueOf(sb.toString());
-            }
-            return (Number)Double.valueOf(sb.toString());
-        }
-        catch (NumberFormatException nfe) {
-            throw new IOException("Not a number '" + sb + "'");
-        }
-    }
-
-    private static List<Object> parseList(PushbackInputStream in)
-    throws IOException
-    {
-        List<Object> list = new ArrayList<Object>();
-        match('[', whitespace(in));
-        int c = whitespace(in);
-        if (c == ']') {
-            return list;
-        }
-
-        for (;; c = whitespace(in)) {
-            Object value;
-            in.unread(c);
-            switch (c) {
-                case '{':
-                    value = parseObject(in);
-                    break;
-                case '[':
-                    value = parseList(in);
-                    break;
-                case '"':
-                    value = parseString(in);
-                    break;
-                case 't':
-                    value = parseTrue(in);
-                    break;
-                case 'f':
-                    value = parseFalse(in);
-                    break;
-                case 'n':
-                    value = parseNull(in);
-                    break;
-                default:
-                    value = parseNumber(in);
-            }
-            list.add(value);
-
-            if ((c = whitespace(in)) == ']') break;
-            match(',', c);
-        }
-        return list;
-    }
-
-    private static void parsePair(
-        PushbackInputStream in,
-        Map<String, Object> pairs
-    )
-    throws IOException
-    {
-        in.unread(whitespace(in));
-        String string = parseString(in);
-        match(':', whitespace(in));
-
-        Object value;
-
-        int c = whitespace(in);
-        in.unread(c);
-        switch (c) {
-            case '{':
-                value = parseObject(in);
-                break;
-            case '[':
-                value = parseList(in);
-                break;
-            case '"':
-                value = parseString(in);
-                break;
-            case 't':
-                value = parseTrue(in);
-                break;
-            case 'f':
-                value = parseFalse(in);
-                break;
-            case 'n':
-                value = parseNull(in);
-                break;
-            default:
-                value = parseNumber(in);
-        }
-        pairs.put(string, value);
-    }
-
-    private static Map<String, Object> parseObject(PushbackInputStream in)
-    throws IOException
-    {
-        Map<String, Object> pairs = new LinkedHashMap<String, Object>();
-
-        int c = whitespace(in);
-        match('{', c);
-
-        if ((c = whitespace(in)) == '}') {
-            return pairs;
-        }
-
-        in.unread(c);
-
-        for (;;) {
-            parsePair(in, pairs);
-
-            if ((c = whitespace(in)) == '}') {
-                break;
-            }
-
-            if (c == '}') break;
-            match(',', c);
-        }
-
-        return pairs;
-    }
-}
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/LRUCache.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-package de.intevation.artifacts.common.utils;
-
-import java.util.Map;
-import java.util.LinkedHashMap;
-
-public class LRUCache<K, V>
-extends      LinkedHashMap<K, V>
-{
-    public static final int DEFAULT_MAX_CAPACITY = 25;
-
-    private int maxCapacity;
-
-    public LRUCache() {
-        this(DEFAULT_MAX_CAPACITY);
-    }
-
-    public LRUCache(int maxCapacity) {
-        this.maxCapacity = maxCapacity;
-    }
-
-    @Override
-    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
-        return size() > maxCapacity;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/MapXPathVariableResolver.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2011 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-package de.intevation.artifacts.common.utils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.namespace.QName;
-import javax.xml.xpath.XPathVariableResolver;
-
-
-/**
- *  @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
- */
-public class MapXPathVariableResolver implements XPathVariableResolver {
-
-    protected Map<String, String> variables;
-
-
-    public MapXPathVariableResolver() {
-        this.variables = new HashMap<String, String>();
-    }
-
-
-    public MapXPathVariableResolver(Map<String, String> variables) {
-        this.variables = variables;
-    }
-
-
-    public void addVariable(String name, String value) {
-        if (name != null && value != null) {
-            variables.put(name, value);
-        }
-    }
-
-
-    @Override
-    public Object resolveVariable(QName variableName) {
-        String key = variableName.getLocalPart();
-        return variables.get(key);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/*
- * Copyright (c) 2010 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-
-package de.intevation.artifacts.common.utils;
-
-import java.io.UnsupportedEncodingException;
-
-import java.util.UUID;
-
-import org.apache.commons.codec.DecoderException;
-
-import org.apache.commons.codec.binary.Hex;
-
-import org.apache.log4j.Logger;
-
-/**
- * Commonly used string functions.
- *
- * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
- */
-public final class StringUtils
-{
-    private static Logger logger = Logger.getLogger(StringUtils.class);
-
-    /**
-     * Generated a random UUIDv4 in form of a string.
-     * @return the UUID
-     */
-    public static final String newUUID() {
-        return UUID.randomUUID().toString();
-    }
-
-    /**
-     * Checks if a given string is a valid UUID.
-     * @param uuid The string to test.
-     * @return true if the string is a valid UUID else false.
-     */
-    public static final boolean checkUUID(String uuid) {
-        try {
-            UUID.fromString(uuid);
-        }
-        catch (IllegalArgumentException iae) {
-            logger.warn(iae.getLocalizedMessage());
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Returns the UTF-8 byte array representation of a given string.
-     * @param s The string to be transformed.
-     * @return The byte array representation.
-     */
-    public static final byte [] getUTF8Bytes(String s) {
-        try {
-            return s.getBytes("UTF-8");
-        }
-        catch (UnsupportedEncodingException usee) {
-            logger.error(usee.getLocalizedMessage(), usee);
-            return s.getBytes();
-        }
-    }
-
-    /**
-     * Tries to convert a Base64 encoded string into the
-     * corresponing byte array.
-     * @param s The Base64 encoded string
-     * @return The byte array representation or null if
-     * an decoding error occurs.
-     */
-    public static final byte [] decodeHex(String s) {
-        try {
-            return Hex.decodeHex(s.toCharArray());
-        }
-        catch (DecoderException de) {
-            return null;
-        }
-    }
-
-    public static final String repeat(String s, int count, String sep) {
-        if (count <= 0) {
-            return "";
-        }
-        StringBuilder sb = new StringBuilder(s);
-        for (--count; count > 0; --count) {
-            sb.append(sep).append(s);
-        }
-        return sb.toString();
-    }
-
-    public static final String repeat(char c, int count, char sep) {
-        if (count <= 0) {
-            return "";
-        }
-        StringBuilder sb = new StringBuilder(2*count-1).append(c);
-        for (--count; count > 0; --count) {
-            sb.append(sep).append(c);
-        }
-        return sb.toString();
-    }
-
-    public static final String [] toUpperCase(String [] s) {
-        if (s == null) {
-            return null;
-        }
-        String [] d = new String[s.length];
-        for (int i = 0; i < s.length; ++i) {
-            if (s[i] != null) {
-                d[i] = s[i].toUpperCase();
-            }
-        }
-        return d;
-    }
-
-    public static String join(String sep, String [] strings) {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < strings.length; ++i) {
-            if (i > 0) sb.append(sep);
-            sb.append(strings[i]);
-        }
-        return sb.toString();
-    }
-
-    public static final String [] join(String [] a, String [] b) {
-        if (a == null && b == null) return null;
-        if (a == null) return b;
-        if (b == null) return a;
-        String [] dst = new String[a.length + b.length];
-        System.arraycopy(a, 0, dst, 0, a.length);
-        System.arraycopy(b, 0, dst, a.length, b.length);
-        return dst;
-    }
-
-    public static final boolean contains(String needle, String [] haystack) {
-        for (String stray: haystack) {
-            if (needle.equals(stray)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,617 +0,0 @@
-/*
- * Copyright (c) 2010 by Intevation GmbH
- *
- * This program is free software under the LGPL (>=v2.1)
- * Read the file LGPL.txt coming with the software for details
- * or visit http://www.gnu.org/licenses/ if it does not exist.
- */
-
-package de.intevation.artifacts.common.utils;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.LinkedHashMap;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-import java.io.ByteArrayInputStream;
-import java.io.FileInputStream;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.StringWriter;
-
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.namespace.QName;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-
-import javax.xml.transform.dom.DOMSource;
-
-import javax.xml.transform.stream.StreamResult;
-
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-import javax.xml.xpath.XPathVariableResolver;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import org.xml.sax.SAXException;
-
-/**
- * Some helper functions to ease work with XML concering namespaces, XPATH
- * and so on.
- *  @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
- */
-public final class XMLUtils
-{
-    /** W3C URL of XForms. */
-    public static final String XFORM_URL    = "http://www.w3.org/2002/xforms";
-
-    /** W3C prefix of XForms. */
-    public static final String XFORM_PREFIX = "xform";
-
-    /** Logger for this class. */
-    private static Logger logger = Logger.getLogger(XMLUtils.class);
-
-    private XMLUtils() {
-    }
-
-    /**
-     * Helper class to generate elements and attributes with
-     * namespaces.
-     */
-    public static class ElementCreator
-    {
-        /** Owner document of the elements to be created. */
-        protected Document document;
-
-        /** Namespace to be used. */
-        protected String   ns;
-
-        /** Prefix to be used. */
-        protected String   prefix;
-
-        /**
-         * Constructor to create an element/attribute creator
-         * with a given namespace and namespace prefix using a
-         * given owner document.
-         * @param document The owning document
-         * @param ns       The namespace
-         * @param prefix   The namespace prefix
-         */
-        public ElementCreator(Document document, String ns, String prefix) {
-            this.document = document;
-            this.ns       = ns;
-            this.prefix   = prefix;
-        }
-
-        /**
-         * Creates a new element using the owning document with
-         * the this creators namespace and namespace prefix.
-         * @param name The name of the element
-         * @return     The new element
-         */
-        public Element create(String name) {
-            Element element = document.createElementNS(ns, name);
-            element.setPrefix(prefix);
-            return element;
-        }
-
-        /**
-         * Adds a new attribute and its value to a given element.
-         * It does not set the namespace prefix.
-         * @param element The element to add the attribute to
-         * @param name    The name of the attribute
-         * @param value   The value of the attribute
-         */
-        public void addAttr(Element element, String name, String value) {
-            addAttr(element, name, value, false);
-        }
-
-        /**
-         * Adds a new attribute and its value to a given element.
-         * If the namespace prefix is used is decided by the 'addPrefix' flag.
-         * @param element The element to add the attribute to
-         * @param name    The name of the attribute
-         * @param value   The value of the attribute
-         * @param addPrefix If true the creators namespace prefix is
-         * set on the attribute.
-         */
-        public void addAttr(
-            Element element,
-            String  name,
-            String  value,
-            boolean addPrefix
-        ) {
-            if (addPrefix) {
-                Attr attr = document.createAttributeNS(ns, name);
-                attr.setValue(value);
-                attr.setPrefix(prefix);
-
-                element.setAttributeNode(attr);
-            }
-            else {
-                element.setAttribute(name, value);
-            }
-        }
-    } // class ElementCreator
-
-    /**
-     * Creates a new XML document
-     * @return the new XML document ot null if something went wrong during
-     * creation.
-     */
-    public static final Document newDocument() {
-        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-        factory.setNamespaceAware(true);
-
-        try {
-            return factory.newDocumentBuilder().newDocument();
-        }
-        catch (ParserConfigurationException pce) {
-            logger.error(pce.getLocalizedMessage(), pce);
-        }
-        return null;
-    }
-
-
-    /**
-     * Create xml/string representation of element (nested in otherwise empty
-     * document).
-     * @param element element to inspect in string.
-     * @return string with xml representation of element.
-     */
-    public final static String toString(Node node) {
-        Document doc = newDocument();
-        doc.appendChild(doc.importNode(node,true));
-        return toString(doc);
-    }
-
-
-    /**
-     * Loads a XML document namespace aware from a file
-     * @param file The file to load.
-     * @return the XML document or null if something went wrong
-     * during loading.
-     */
-    public static final Document parseDocument(File file) {
-        InputStream inputStream = null;
-        try {
-            inputStream = new BufferedInputStream(new FileInputStream(file));
-            return parseDocument(inputStream);
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-        }
-        finally {
-            if (inputStream != null) {
-                try { inputStream.close(); }
-                catch (IOException ioe) {}
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Parses a String to a xml document.
-     *
-     * @param string The xml string
-     * @return the XML document or null if something went wrong.
-     */
-    public static final Document parseDocument(String string) {
-        InputStream inputStream = new ByteArrayInputStream(string.getBytes());
-        return parseDocument(inputStream);
-    }
-
-
-    public static final Document parseDocument(InputStream inputStream) {
-        return parseDocument(inputStream, Boolean.TRUE);
-    }
-
-    public static final Document parseDocument(
-        InputStream inputStream,
-        Boolean     namespaceAware
-    ) {
-        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-
-        if (namespaceAware != null) {
-            factory.setNamespaceAware(namespaceAware.booleanValue());
-        }
-
-        try {
-            return factory.newDocumentBuilder().parse(inputStream);
-        }
-        catch (ParserConfigurationException pce) {
-            logger.error(pce.getLocalizedMessage(), pce);
-        }
-        catch (SAXException se) {
-            logger.error(se.getLocalizedMessage(), se);
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-        }
-        return null;
-    }
-
-    /**
-     * Creates a new XPath without a namespace context.
-     * @return the new XPath.
-     */
-    public static final XPath newXPath() {
-        return newXPath(null, null);
-    }
-
-    /**
-     * Creates a new XPath with a given namespace context.
-     * @param namespaceContext The namespace context to be used or null
-     * if none should be used.
-     * @return The new XPath
-     */
-    public static final XPath newXPath(
-        NamespaceContext      namespaceContext,
-        XPathVariableResolver resolver)
-    {
-        XPathFactory factory = XPathFactory.newInstance();
-        XPath        xpath   = factory.newXPath();
-        if (namespaceContext != null) {
-            xpath.setNamespaceContext(namespaceContext);
-        }
-
-        if (resolver != null) {
-            xpath.setXPathVariableResolver(resolver);
-        }
-        return xpath;
-    }
-
-    /**
-     * Evaluates an XPath query on a given object and returns the result
-     * as a given type. No namespace context is used.
-     * @param root  The object which is used as the root of the tree to
-     * be searched in.
-     * @param query The XPath query
-     * @param returnTyp The type of the result.
-     * @return The result of type 'returnTyp' or null if something
-     * went wrong during XPath evaluation.
-     */
-    public static final Object xpath(
-        Object root,
-        String query,
-        QName  returnTyp
-    ) {
-        return xpath(root, query, returnTyp, null);
-    }
-
-    /**
-     * Evaluates an XPath query on a given object and returns the result
-     * as a string. A given namespace context is used.
-     * @param root  The object which is used as the root of the tree to
-     * be searched in.
-     * @param query The XPath query
-     * @param namespaceContext The namespace context to be used or null
-     * if none should be used.
-     * @return The result of the query or null if something went wrong
-     * during XPath evaluation.
-     */
-    public static final String xpathString(
-        Object root, String query, NamespaceContext namespaceContext
-    ) {
-        return (String)xpath(
-            root, query, XPathConstants.STRING, namespaceContext);
-    }
-
-    /**
-     * Evaluates an XPath query on a given object and returns the result
-     * as a given type. Optionally a namespace context is used.
-     * @param root The object which is used as the root of the tree to
-     * be searched in.
-     * @param query The XPath query
-     * @param returnType The type of the result.
-     * @param namespaceContext The namespace context to be used or null
-     * if none should be used.
-     * @return The result of type 'returnTyp' or null if something
-     * went wrong during XPath evaluation.
-     */
-    public static final Object xpath(
-        Object           root,
-        String           query,
-        QName            returnType,
-        NamespaceContext namespaceContext
-    ) {
-        return xpath(root, query, returnType, namespaceContext, null);
-    }
-
-    public static final Object xpath(
-        Object           root,
-        String           query,
-        QName            returnType,
-        NamespaceContext namespaceContext,
-        Map<String, String> variables)
-    {
-        if (root == null) {
-            return null;
-        }
-
-        XPathVariableResolver resolver = variables != null
-            ? new MapXPathVariableResolver(variables)
-            : null;
-
-        try {
-            XPath xpath = newXPath(namespaceContext, resolver);
-            if (xpath != null) {
-                return xpath.evaluate(query, root, returnType);
-            }
-        }
-        catch (XPathExpressionException xpee) {
-            logger.error(xpee.getLocalizedMessage(), xpee);
-        }
-
-        return null;
-    }
-
-    /**
-     * Streams out an XML document to a given output stream.
-     * @param document The document to be streamed out.
-     * @param out      The output stream to be used.
-     * @return true if operation succeeded else false.
-     */
-    public static boolean toStream(Document document, OutputStream out) {
-        try {
-            Transformer transformer =
-                TransformerFactory.newInstance().newTransformer();
-            DOMSource    source = new DOMSource(document);
-            StreamResult result = new StreamResult(out);
-            transformer.transform(source, result);
-            return true;
-        }
-        catch (TransformerConfigurationException tce) {
-            logger.error(tce.getLocalizedMessage(), tce);
-        }
-        catch (TransformerFactoryConfigurationError tfce) {
-            logger.error(tfce.getLocalizedMessage(), tfce);
-        }
-        catch (TransformerException te) {
-            logger.error(te.getLocalizedMessage(), te);
-        }
-
-        return false;
-    }
-
-    public static String toString(Document document) {
-        try {
-            Transformer transformer =
-                TransformerFactory.newInstance().newTransformer();
-            DOMSource    source = new DOMSource(document);
-            StringWriter out    = new StringWriter();
-            StreamResult result = new StreamResult(out);
-            transformer.transform(source, result);
-            out.flush();
-            return out.toString();
-        }
-        catch (TransformerConfigurationException tce) {
-            logger.error(tce.getLocalizedMessage(), tce);
-        }
-        catch (TransformerFactoryConfigurationError tfce) {
-            logger.error(tfce.getLocalizedMessage(), tfce);
-        }
-        catch (TransformerException te) {
-            logger.error(te.getLocalizedMessage(), te);
-        }
-
-        return null;
-    }
-
-    public static byte [] toByteArray(Document document) {
-        return toByteArray(document, false);
-    }
-
-    /**
-     * Transforms an XML document into a byte array.
-     * @param document The document to be streamed out.
-     * @param compress The document should be compressed, too.
-     * @return the byte array or null if operation failed or
-     * document is null.
-     */
-    public static byte [] toByteArray(Document document, boolean compress) {
-        if (document != null) {
-            try {
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                OutputStream out = compress
-                    ? new GZIPOutputStream(baos)
-                    : baos;
-                boolean success = toStream(document, out);
-                out.flush();
-                out.close();
-                return success
-                    ? baos.toByteArray()
-                    : null;
-            }
-            catch (IOException ioe) {
-                logger.error(ioe);
-            }
-        }
-        return null;
-    }
-
-    public static Document fromByteArray(byte [] data) {
-        return fromByteArray(data, false);
-    }
-
-    public static Document fromByteArray(byte [] data, boolean decompress) {
-        if (data != null) {
-            InputStream in = new ByteArrayInputStream(data);
-            try {
-                if (decompress) {
-                    in = new GZIPInputStream(in);
-                }
-                return parseDocument(in);
-            }
-            catch (IOException ioe) {
-                logger.error(ioe);
-            }
-            finally {
-                try {
-                    in.close();
-                }
-                catch (IOException ioe) {
-                    logger.error(ioe);
-                }
-            }
-        }
-        return null;
-    }
-
-    private static class BuildResult {
-        List<Node>          children;
-        Map<String, String> attributes;
-        BuildResult() {
-            children   = new ArrayList<Node>();
-            attributes = new LinkedHashMap<String, String>();
-        }
-
-        void setAttributes(Element element) {
-            for (Map.Entry<String, String> entry: attributes.entrySet()) {
-                element.setAttribute(entry.getKey(), entry.getValue());
-            }
-        }
-
-        void finish(Element element) {
-            setAttributes(element);
-            for (Node child: children) {
-                element.appendChild(child);
-            }
-        }
-
-        void add(Node node) {
-            children.add(node);
-        }
-
-        void add(String key, Object value) {
-            attributes.put(key, value != null ? value.toString() : "null");
-        }
-
-        int numChildren() {
-            return children.size();
-        }
-
-        Node firstChild() {
-            return children.get(0);
-        }
-    } // class BuildResult
-
-    private static BuildResult recursiveBuild(
-        List     list,
-        Document document
-    ) {
-        BuildResult result = new BuildResult();
-        for (Object entry: list) {
-            if (entry instanceof Map) {
-                BuildResult subResult = recursiveBuild(
-                    (Map<String, Object>)entry, document);
-                if (subResult.numChildren() == 1) {
-                    result.add(subResult.firstChild());
-                }
-                else {
-                    Element element = document.createElement("map");
-                    subResult.finish(element);
-                    result.add(element);
-                }
-            }
-            else if (entry instanceof List) {
-                Element element = document.createElement("list");
-                BuildResult subResult = recursiveBuild((List)entry, document);
-                subResult.finish(element);
-                result.add(element);
-            }
-            else {
-                Element element = document.createElement("entry");
-                element.setAttribute(
-                    "value",
-                    entry != null ? entry.toString() : "null");
-            }
-        }
-        return result;
-    }
-
-    private static BuildResult recursiveBuild(
-        Map<String, Object> map,
-        Document            document
-    ) {
-        BuildResult result = new BuildResult();
-
-        List<Node> nodes = new ArrayList<Node>();
-        for (Map.Entry<String, Object> entry: map.entrySet()) {
-            Object value = entry.getValue();
-            if (value instanceof Map) {
-                Element element = document.createElement(entry.getKey());
-                BuildResult subResult = recursiveBuild(
-                    (Map<String, Object>)value, document);
-                subResult.finish(element);
-                result.add(element);
-            }
-            else if (value instanceof List) {
-                Element element = document.createElement(entry.getKey());
-                BuildResult subResult = recursiveBuild((List)value, document);
-                subResult.finish(element);
-                result.add(element);
-            }
-            else {
-                result.add(entry.getKey(), value);
-            }
-        }
-        return result;
-    }
-
-    public static Document jsonToXML(String input) {
-        Document document = newDocument();
-
-        if (document == null) {
-            return null;
-        }
-
-        Map<String, Object> map;
-        try {
-            map = JSON.parse(input);
-        }
-        catch (IOException ioe) {
-            logger.error(ioe);
-            return null;
-        }
-
-        BuildResult roots = recursiveBuild(map, document);
-
-        int N = roots.children.size();
-
-        if (N == 1) {
-            document.appendChild(roots.children.get(0));
-        }
-        else if (N > 1) {
-            Node root = document.createElement("root");
-            for (int i = 0; i < N; ++i) {
-                root.appendChild(roots.children.get(i));
-            }
-            document.appendChild(root);
-        }
-
-        return document;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XSLTransformer.java	Thu Apr 25 10:50:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-package de.intevation.artifacts.common.utils;
-
-import java.io.InputStream;
-import java.io.StringWriter;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-
-import javax.xml.transform.dom.DOMSource;
-
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Node;
-
-public class XSLTransformer {
-
-    private static Logger log = Logger.getLogger(XSLTransformer.class);
-
-    protected Map<String, Object> parameters;
-
-    public XSLTransformer() {
-    }
-
-    public String transform(Node source, InputStream transform) {
-
-        try {
-            Source templateSource = new StreamSource(transform);
-            TransformerFactory xformFactory =
-                TransformerFactory.newInstance();
-            Transformer transformer =
-                xformFactory.newTransformer(templateSource);
-
-            if (parameters != null) {
-                for (Map.Entry<String, Object> entry: parameters.entrySet()) {
-                    transformer.setParameter(entry.getKey(), entry.getValue());
-                }
-            }
-
-            StringWriter result = new StringWriter();
-
-            DOMSource    src = new DOMSource(source);
-            StreamResult dst = new StreamResult(result);
-            transformer.transform(src, dst);
-
-            return result.toString();
-        }
-        catch (TransformerConfigurationException tce) {
-            log.error(tce, tce);
-        }
-        catch (TransformerException te) {
-            log.error(te, te);
-        }
-
-        return null;
-    }
-
-    public void addParameter(String key, Object value) {
-        if (parameters == null) {
-            parameters = new HashMap<String, Object>();
-        }
-        parameters.put(key, value);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/ArtifactNamespaceContext.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+
+package de.intevation.artifacts.common;
+
+import java.util.Iterator;
+
+import javax.xml.XMLConstants;
+
+import javax.xml.namespace.NamespaceContext;
+
+/**
+ * The namespace used in artifact documents.
+ * @author <a href="mailto:sascha.teichmann@intevation">Sascha L. Teichmann</a>
+ */
+public class ArtifactNamespaceContext
+implements   NamespaceContext
+{
+    /**
+     * The URI of the namespace of the artifacts.
+     */
+    public final static String NAMESPACE_URI =
+        "http://www.intevation.de/2009/artifacts";
+
+    /**
+     * The XML prefix for the artifacts namespace.
+     */
+    public final static String NAMESPACE_PREFIX = "art";
+
+    /**
+     * Final instance to be easily used to avoid creation
+     * of instances.
+     */
+    public static final ArtifactNamespaceContext INSTANCE =
+        new ArtifactNamespaceContext();
+
+    /**
+     * The default constructor.
+     */
+    public ArtifactNamespaceContext() {
+    }
+
+    /**
+     * @see javax.xml.namespace.NamespaceContext#getNamespaceURI(String)
+     * @param prefix The prefix
+     * @return The corresponing URI
+     */
+    public String getNamespaceURI(String prefix) {
+
+        if (prefix == null) {
+            throw new NullPointerException("Null prefix");
+        }
+
+        if (NAMESPACE_PREFIX.equals(prefix)) {
+            return NAMESPACE_URI;
+        }
+
+        if ("xml".equals(prefix)) {
+            return XMLConstants.XML_NS_URI;
+        }
+
+        return XMLConstants.NULL_NS_URI;
+    }
+
+    /**
+     * @see javax.xml.namespace.NamespaceContext#getPrefix(String)
+     * @param uri The URI
+     * @return nothing.
+     * @throws java.lang.UnsupportedOperationException
+     */
+    public String getPrefix(String uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String)
+     * @param uri The URI
+     * @return nothing
+     * @throws java.lang.UnsupportedOperationException
+     */
+    public Iterator getPrefixes(String uri) {
+        throw new UnsupportedOperationException();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/model/DefaultUser.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,75 @@
+package de.intevation.artifacts.common.model;
+
+/**
+ * The default implementation of the {@link User} interface.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultUser implements User {
+
+    /** The user's firstname. */
+    protected String firstName;
+
+    /** The user's lastname. */
+    protected String lastName;
+
+
+    /**
+     * Creates an empty user without name.
+     */
+    public DefaultUser() {
+    }
+
+
+    /**
+     * Creates a user with first and lastname.
+     *
+     * @param firstName The user's firstname.
+     * @param lastName The user's lastname.
+     */
+    public DefaultUser(String firstName, String lastName) {
+        this.firstName = firstName;
+        this.lastName  = lastName;
+    }
+
+
+    /**
+     * This method returns the firstname of the user.
+     *
+     * @return the firstname.
+     */
+    public String getFirstName() {
+        return firstName;
+    }
+
+
+    /**
+     * Sets the user's firstname.
+     *
+     * @param firstName The user's firstname.
+     */
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+
+
+    /**
+     * This method returns the lastname of the user.
+     *
+     * @return the lastname.
+     */
+    public String getLastName() {
+        return lastName;
+    }
+
+
+    /**
+     * Sets the user's lastname.
+     *
+     * @param lastName The user's lastname.
+     */
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/model/KVP.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+package de.intevation.artifacts.common.model;
+
+
+public class KVP<K, V> {
+
+    private K key;
+    private V value;
+
+
+    public KVP(K key, V value) {
+        this.key   = key;
+        this.value = value;
+    }
+
+
+    public K getKey() {
+        return key;
+    }
+
+
+    public V getValue() {
+        return value;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/model/User.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,43 @@
+package de.intevation.artifacts.common.model;
+
+import java.io.Serializable;
+
+/**
+ * An interface that describes a user of the system.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public interface User extends Serializable {
+
+    /**
+     * This method returns the firstname of the user.
+     *
+     * @return the firstname.
+     */
+    public String getFirstName();
+
+
+    /**
+     * Sets the user's firstname.
+     *
+     * @param firstName The user's firstname.
+     */
+    public void setFirstName(String firstName);
+
+
+    /**
+     * This method returns the lastname of the user.
+     *
+     * @return the lastname.
+     */
+    public String getLastName();
+
+
+    /**
+     * Sets the user's lastname.
+     *
+     * @param lastName The user's lastname.
+     */
+    public void setLastName(String lastName);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/ClientProtocolUtils.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 2011 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+package de.intevation.artifacts.common.utils;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+
+
+/**
+ * This class provides methods that help creating the artifact protocol
+ * documents DESCRIBE, FEED, ADVANCE and OUT.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ClientProtocolUtils {
+
+    /** The XPath to the current state in the DESCRIBE document. */
+    public static final String XPATH_CURRENT_STATE = "/art:result/art:state";
+
+    /** The XPath to the static UI part in the DESCRIBE document. */
+    public static final String XPATH_STATIC  = "/art:result/art:ui/art:static";
+
+    /** The XPath to the dynamic UI part in the DESCRIBE document. */
+    public static final String XPATH_DYNAMIC = "/art:result/art:ui/art:dynamic";
+
+    /** The XPath to the reachable states part in the DESCRIBE document. */
+    public static final String XPATH_STATES  =
+        "/art:result/art:reachable-states";
+
+    /** The XPath to the output modes in the DESCRIBE document. */
+    public static final String XPATH_OUTPUT_MODES  =
+        "/art:result/art:outputmodes/art:output";
+
+    /** The XPath to the select node relative to the dynamic UI node in the
+     * DESCRIBE document. */
+    public static final String XPATH_DATA_SELECT = "art:select";
+
+    /** The XPath to the choices nodes relative to the select node in the
+     * DESCRIBE document. */
+    public static final String XPATH_DATA_ITEMS = "art:choices/art:item";
+
+    /** The XPath that points to the min value of a range.*/
+    public static final String XPATH_MIN_NODE = "art:min/@art:value";
+
+    /** The XPath that points to the max value of a range.*/
+    public static final String XPATH_MAX_NODE = "art:max/@art:value";
+
+    /** The XPath that points to the default min value of a range.*/
+    public static final String XPATH_DEF_MIN = "art:min/@art:default";
+
+    /** The XPath that points to the default max value of a range.*/
+    public static final String XPATH_DEF_MAX = "art:max/@art:default";
+
+    /** The XPath to a label in the artifact's DESCRIBE document. */
+    public static final String XPATH_LABEL = "art:label/text()";
+
+    /** The XPath to a value in the artifact's DESCRIBE document. */
+    public static final String XPATH_VALUE = "art:value/text()";
+
+
+    /**
+     * It should not be necessary to create instances of this class.
+     */
+    private ClientProtocolUtils() {
+    }
+
+
+    /**
+     * This method creates a new CREATE document.
+     *
+     * @return the CREATE document.
+     */
+    public static Document newCreateDocument(String factory) {
+        return newCreateDocument(factory, null);
+    }
+
+
+    /**
+     * This method creates a new CREATE document.
+     *
+     * @return the CREATE document.
+     */
+    public static Document newCreateDocument(String factory, String uuid) {
+        return newCreateDocument(factory, uuid, null);
+    }
+
+    public static Document newCreateDocument(
+        String  factory,
+        String  uuid,
+        String  ids
+    ) {
+        return newCreateDocument(factory, uuid, ids, null);
+    }
+
+    /**
+     * This method creates a new CREATE document.
+     *
+     * @return the CREATE document.
+     */
+    public static Document newCreateDocument(
+        String         factory,
+        String         uuid,
+        String         ids,
+        CreationFilter filter
+    ) {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = cr.create("action");
+        Element type   = cr.create("type");
+        Element fac    = cr.create("factory");
+
+        type.setAttribute("name", "create");
+        fac.setAttribute("name", factory);
+
+        action.appendChild(type);
+        action.appendChild(fac);
+
+        if (uuid != null) {
+            Element templ = cr.create("template");
+            templ.setAttribute("uuid", uuid);
+            action.appendChild(templ);
+        }
+
+        if (ids != null) {
+            Element id = cr.create("ids");
+            id.setAttribute("value", ids);
+            action.appendChild(id);
+        }
+
+        if (filter != null) {
+            action.appendChild(filter.toXML(cr));
+        }
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+    /**
+     * This method creates a new FEED document.
+     *
+     * @param theUuid The identifier of the artifact.
+     * @param theHash The hash of the artifact.
+     * @param theData An array that contains key/value pairs that represent the
+     * data that should be included in the FEED document.
+     *
+     * @return the FEED document.
+     */
+    public static Document newFeedDocument(
+        String     theUuid,
+        String     theHash,
+        String[][] theData)
+    {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = cr.create("action");
+        Element type   = cr.create("type");
+        Element uuid   = cr.create("uuid");
+        Element hash   = cr.create("hash");
+        Element data   = cr.create("data");
+
+        // XXX It is not nice that the type has no attribute namespace, but to
+        // be backward compatible, we don't change this now.
+        cr.addAttr(type, "name", "feed", false);
+        cr.addAttr(uuid, "value", theUuid, true);
+        cr.addAttr(hash, "value", theHash, true);
+
+        for (String[] kvp: theData) {
+            Element input = cr.create("input");
+            cr.addAttr(input, "name", kvp[0], true);
+            cr.addAttr(input, "value", kvp[1], true);
+
+            data.appendChild(input);
+        }
+
+        action.appendChild(type);
+        action.appendChild(uuid);
+        action.appendChild(hash);
+        action.appendChild(data);
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+    /**
+     * This method creates a new DESCRIBE document.
+     *
+     * @param theUuid The identifier of the artifact.
+     * @param theHash The hash of the artifact.
+     * @param ui If true, the UI part is included.
+     *
+     * @return the DESCRIBE document.
+     */
+    public static Document newDescribeDocument(
+        String  theUuid,
+        String  theHash,
+        boolean incUI)
+    {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = cr.create("action");
+        Element type   = cr.create("type");
+        Element uuid   = cr.create("uuid");
+        Element hash   = cr.create("hash");
+        Element ui     = cr.create("include-ui");
+
+        // XXX It is not nice that the type has no attribute namespace, but to
+        // be backward compatible, we don't change this now.
+        cr.addAttr(type, "name", "describe", false);
+        cr.addAttr(uuid, "value", theUuid, true);
+        cr.addAttr(hash, "value", theHash, true);
+
+        ui.setTextContent(incUI ? "true" : "false");
+
+        action.appendChild(type);
+        action.appendChild(uuid);
+        action.appendChild(hash);
+        action.appendChild(ui);
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+    /**
+     * This method creates a new ADVANCE document.
+     *
+     * @param theUuid The identifier of the artifact.
+     * @param theHash The hash of the artifact.
+     * @param theTarget The target state identifier.
+     *
+     * @return the ADVANCE document.
+     */
+    public static Document newAdvanceDocument(
+        String theUuid,
+        String theHash,
+        String theTarget)
+    {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = cr.create("action");
+        Element type   = cr.create("type");
+        Element uuid   = cr.create("uuid");
+        Element hash   = cr.create("hash");
+        Element target = cr.create("target");
+
+        // XXX It is not nice that the type has no attribute namespace, but to
+        // be backward compatible, we don't change this now.
+        cr.addAttr(type, "name", "advance", false);
+        cr.addAttr(uuid, "value", theUuid, true);
+        cr.addAttr(hash, "value", theHash, true);
+        cr.addAttr(target, "name", theTarget, true);
+
+        action.appendChild(type);
+        action.appendChild(uuid);
+        action.appendChild(hash);
+        action.appendChild(target);
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+    /**
+     * This method creates a new document that is used to create new artifact
+     * collections in the artifact server.
+     *
+     * @param name <b>Optional</b> name of the collection.
+     *
+     * @return the document to create new collections.
+     */
+    public static Document newCreateCollectionDocument(String name) {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action     = cr.create("action");
+        Element type       = cr.create("type");
+        Element collection = cr.create("collection");
+        Element attribute  = cr.create("attribute");
+
+        cr.addAttr(type, "name", "create");
+        cr.addAttr(collection, "name", name != null ? name : "");
+
+        action.appendChild(type);
+        type.appendChild(collection);
+        collection.appendChild(attribute);
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+    /**
+     * This method creates a new Document that is used to add an artifact to a
+     * collection in the artifact server.
+     *
+     * @param artId The identifier of the artifact that should be added.
+     * @param attr A document that contains attributes for the artifact's
+     * life in the collection.
+     *
+     * @return the document to add an artifact into a collection.
+     */
+    public static Document newAddArtifactDocument(String artId, Document attr) {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action    = cr.create("action");
+        Element type      = cr.create("type");
+        Element artifact  = cr.create("artifact");
+        Element attribute = cr.create("attribute");
+
+        cr.addAttr(artifact, "uuid", artId);
+        cr.addAttr(type, "name", "addartifact");
+
+        if (attr != null) {
+            attr.appendChild(attr);
+        }
+
+        action.appendChild(type);
+        type.appendChild(artifact);
+        artifact.appendChild(attribute);
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+    /**
+     * Create a new Document that is used to remove an artifact from a
+     * collection in the artifact server.
+     *
+     * @param artId The identifier of the artifact that should be added.
+     *
+     * @return the document to add an artifact into a collection.
+     */
+    public static Document newRemoveArtifactDocument(String artId) {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action    = cr.create("action");
+        Element type      = cr.create("type");
+        Element artifact  = cr.create("artifact");
+
+        cr.addAttr(artifact, "uuid", artId);
+        cr.addAttr(type, "name", "removeartifact");
+
+        action.appendChild(type);
+        type.appendChild(artifact);
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+    /**
+     * This method creates a new Document that is used to trigger the DESCRIBE
+     * operation of a collection in the artifact server.
+     *
+     * @param uuid The identifier of the collection that should be described.
+     *
+     * @return the document to describe a collection.
+     */
+    public static Document newDescribeCollectionDocument(String uuid) {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action    = cr.create("action");
+        Element type      = cr.create("type");
+        cr.addAttr(type, "name", "describe");
+
+        action.appendChild(type);
+
+        doc.appendChild(action);
+
+        return doc;
+    }
+
+
+
+    /**
+     * This function builds a document that is used as request document of the
+     * out() operation of Collections.
+     *
+     * @param uuid The identifier of the collection.
+     * @param mode The name of the desired output mode.
+     * @param type The name of the desired output type.
+     *
+     * @return the request document.
+     */
+    public static Document newOutCollectionDocument(
+        String uuid,
+        String mode,
+        String type) {
+        return newOutCollectionDocument(uuid, mode, type, null);
+    }
+
+
+    /**
+     * This function builds a document that is used as request document of the
+     * out() operation of Collections. The document <i>attr</i> might be used to
+     * adjust some settings specific to the output.
+     *
+     * @param uuid The identifier of the collection.
+     * @param mode The name of the desired output mode.
+     * @param type The name of the desired output type.
+     * @param attr A document that contains settings specific to the output.
+     *
+     * @return the request document.
+     */
+    public static Document newOutCollectionDocument(
+        String   uuid,
+        String   mode,
+        String   type,
+        Document attr)
+    {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = cr.create("action");
+
+        cr.addAttr(action, "name", mode, true);
+        cr.addAttr(action, "type", type, true);
+
+        doc.appendChild(action);
+
+        if (attr != null) {
+            Node root = attr.getFirstChild();
+
+            if (root != null) {
+                action.appendChild(doc.importNode(root, true));
+            }
+        }
+
+        return doc;
+    }
+
+
+    /**
+     * This function creates a document that is used to set the attribute of a
+     * Collection.
+     *
+     * @param uuid The identifier of the Collection.
+     * @param attr The new attribute value for the Collection.
+     *
+     * @return the document that is used to set the attribute.
+     */
+    public static Document newSetAttributeDocument(
+        String uuid,
+        Document attr)
+    {
+        Node root = attr != null ? attr.getFirstChild() : null;
+
+        if (root == null) {
+            return null;
+        }
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action     = ec.create("action");
+        Element type       = ec.create("type");
+        Element collection = ec.create("collection");
+
+        ec.addAttr(type, "name", "setattribute", false);
+        ec.addAttr(collection, "uuid", uuid, false);
+
+        doc.appendChild(action);
+        action.appendChild(type);
+        type.appendChild(collection);
+
+        collection.appendChild(doc.importNode(root, true));
+
+        return doc;
+    }
+
+    /**
+     * This function creates a document that is used to set the attribute of a
+     * CollectionItem.
+     *
+     * @param uuid The identifier of the CollectionItem.
+     * @param attr The new attribute value for the CollectionItem.
+     *
+     * @return the document that is used to set the attribute.
+     */
+    public static Document newSetItemAttributeDocument(
+        String uuid,
+        Document attr)
+    {
+        Node root = attr.getFirstChild();
+
+        if (root == null) {
+            return null;
+        }
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action   = ec.create("action");
+        Element type     = ec.create("type");
+        Element artifact = ec.create("artifact");
+
+        ec.addAttr(type, "name", "setitemattribute");
+        ec.addAttr(artifact, "uuid", uuid);
+
+        doc.appendChild(action);
+        action.appendChild(type);
+        type.appendChild(artifact);
+
+        artifact.appendChild(doc.importNode(root, true));
+
+        return doc;
+    }
+
+
+    /**
+     * This function creates a document that is used to set the time-to-live
+     * of a collection.
+     *
+     * @param ttl The ttl for the Collection.
+     *
+     * @return the document that is used to set the time-to-live.
+     */
+    public static Document newSetCollectionTTLDocument(String ttl) {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = ec.create("action");
+        Element type   = ec.create("type");
+        Element ttlEl  = ec.create("ttl");
+
+        ec.addAttr(type, "name", "settimetolive");
+        ec.addAttr(ttlEl, "value", ttl);
+
+        doc.appendChild(action);
+        action.appendChild(type);
+        type.appendChild(ttlEl);
+
+        return doc;
+    }
+
+
+    /**
+     * This function creates a document that is used to set the name of a
+     * collection.
+     *
+     * @param name The name for the Collection.
+     *
+     * @return the document that is used to set the name of a collection.
+     */
+    public static Document newSetCollectionNameDocument(String name) {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = ec.create("action");
+        Element type   = ec.create("type");
+        Element coll   = ec.create("collection");
+
+        ec.addAttr(type, "name", "setname");
+        ec.addAttr(coll, "name", name);
+
+        doc.appendChild(action);
+        action.appendChild(type);
+        type.appendChild(coll);
+
+        return doc;
+    }
+
+
+    /**
+     * This function creates a document that is used to delete an existing
+     * collection.
+     *
+     * @return the document that is used to delete an existing collection.
+     */
+    public static Document newDeleteCollectionDocument() {
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element action = ec.create("action");
+        Element type   = ec.create("type");
+
+        ec.addAttr(type, "name", "delete");
+
+        doc.appendChild(action);
+        action.appendChild(type);
+
+        return doc;
+    }
+
+
+    /**
+     * Returns string value found by {@link XPATH_LABEL} relative to
+     * <i>node</i>.
+     *
+     * @param node A node.
+     *
+     * @return the string value found by {@link XPATH_LABEL}.
+     */
+    public static String getLabel(Node node) {
+        return (String) XMLUtils.xpath(
+            node,
+            XPATH_LABEL,
+            XPathConstants.STRING,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * Returns string value found by {@link XPATH_VALUE} relative to
+     * <i>node</i>.
+     *
+     * @param node A node.
+     *
+     * @return the string value found by {@link XPATH_VALUE}.
+     */
+    public static String getValue(Node node) {
+        return (String) XMLUtils.xpath(
+            node,
+            XPATH_VALUE,
+            XPathConstants.STRING,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * This method returns the static UI part of the artifact's DESCRIBE
+     * document.
+     *
+     * @param description The document returned by the artifact server's
+     * DESCRIBE operation.
+     *
+     * @return the static UI node.
+     */
+    public static Node getStaticUI(Document description) {
+        return (Node) XMLUtils.xpath(
+            description,
+            XPATH_STATIC,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * This method returns the dynamic UI part of the artifact's DESCRIBE
+     * document.
+     *
+     * @param description The document returned by the artifact server's
+     * DESCRIBE operation.
+     *
+     * @return the dynamic UI node.
+     */
+    public static Node getDynamicUI(Document description) {
+        return (Node) XMLUtils.xpath(
+            description,
+            XPATH_DYNAMIC,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * This method returns the current state node contained in the DESCRIBE
+     * document.
+     *
+     * @param description The document returned by the artifact server's
+     * DESCRIBE operation.
+     *
+     * @return the node containing information about the current state.
+     */
+    public static Node getCurrentState(Document description) {
+        return (Node) XMLUtils.xpath(
+            description,
+            XPATH_CURRENT_STATE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * This method returns the node that contains information about the
+     * reachable states of the artifact in the artifact's DESCRIBE document.
+     *
+     * @param description The document returned by the artifact server's
+     * DESCRIBE operation.
+     *
+     * @return the node that contains the reachable states.
+     */
+    public static Node getReachableStates(Document description) {
+        return (Node) XMLUtils.xpath(
+            description,
+            XPATH_STATES,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * This method returns the output mode nodes of the DESCRIBE document.
+     *
+     * @param description The document returned by the artifact server's
+     * DESCRIBE operation.
+     *
+     * @return the node that contains the output modes.
+     */
+    public static NodeList getOutputModes(Document description) {
+        return (NodeList) XMLUtils.xpath(
+            description,
+            XPATH_OUTPUT_MODES,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * Returns the node found by {@link XPATH_DATA_SELECT}.
+     *
+     * @param dynamicNode The dynamic UI node of the DESCRIBE document.
+     *
+     * @return the select node found in the dynamic UI node.
+     */
+    public static NodeList getSelectNode(Node dynamicNode) {
+        return (NodeList) XMLUtils.xpath(
+            dynamicNode,
+            XPATH_DATA_SELECT,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * Returns the items that could be found in the <i>node</i>.
+     *
+     * @param node A select node.
+     *
+     * @return the choices nodes as node list.
+     */
+    public static NodeList getItemNodes(Node node) {
+        return (NodeList) XMLUtils.xpath(
+            node,
+            XPATH_DATA_ITEMS,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    public static String getMinNode(Node parent) {
+        return (String) XMLUtils.xpath(
+            parent,
+            XPATH_MIN_NODE,
+            XPathConstants.STRING,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    public static String getMaxNode(Node parent) {
+        return (String) XMLUtils.xpath(
+            parent,
+            XPATH_MAX_NODE,
+            XPathConstants.STRING,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    public static String getDefMin(Node parent) {
+        return (String) XMLUtils.xpath(
+            parent,
+            XPATH_DEF_MIN,
+            XPathConstants.STRING,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    public static String getDefMax(Node parent) {
+        return (String) XMLUtils.xpath(
+            parent,
+            XPATH_DEF_MAX,
+            XPathConstants.STRING,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/Config.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2010 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+
+package de.intevation.artifacts.common.utils;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.xml.namespace.QName;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.xml.sax.SAXException;
+
+/**
+ * The central access to the configuration of the artifact database.
+ * This class provides some static methods to access the central
+ * configuration XML file via XPath.
+ *
+ * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
+ */
+public final class Config
+{
+    private static Logger logger = Logger.getLogger(Config.class);
+
+    /**
+     * System property name where to find the configuration directory.
+     */
+    public static final String CONFIG_DIR = "artifact.database.dir";
+
+    /**
+     * Default path to the configuration directory if none
+     * was specified by the CONFIG_DIR system property.
+     */
+    public static final File CONFIG_DIR_DEFAULT =
+        new File(new File(System.getProperty("user.home",
+            System.getProperty("user.dir", "."))), ".artifactdb");
+
+    /**
+     * Name of the central configuration XML file.
+     */
+    public static final String CONFIG_FILE  = "conf.xml";
+
+    /**
+     * Name of the configuration filename alias to be use
+     * within the configuration. This alias is replaced by
+     * the real path.
+     */
+    public static final String CONFIG_DIR_PLACEHOLDER =
+        "${artifacts.config.dir}";
+
+    private static Document config;
+
+    private Config() {
+    }
+
+    /**
+     * Singleton access to the central XML configuration document.
+     * @return The central XML configuration document.
+     */
+    public static synchronized final Document getConfig() {
+        if (config == null) {
+            config = loadConfig();
+        }
+        return config;
+    }
+
+    /**
+     * Returns the path to the configuartion directory. If a path
+     * was specified via the CONFIG_DIR system property this one
+     * is used. Else it falls back to default configuration path.
+     * @return The path to the configuartion directory.
+     */
+    public static File getConfigDirectory() {
+        String configDirString = System.getProperty(CONFIG_DIR);
+
+        File configDir = configDirString != null
+            ? new File(configDirString)
+            : CONFIG_DIR_DEFAULT;
+
+        if (!configDir.isDirectory()) {
+            logger.warn("'" + configDir + "' is not a directory.");
+            configDir = CONFIG_DIR_DEFAULT;
+        }
+
+        return configDir;
+    }
+
+    /**
+     * Replaces the CONFIG_DIR_PLACEHOLDER alias with the real path
+     * of the configuration directory.
+     * @param path The path containing the CONFIG_DIR_PLACEHOLDER placeholder.
+     * @return The path where the CONFIG_DIR_PLACEHOLDER placeholders are
+     * replaced by the real path name.
+     */
+    public static String replaceConfigDir(String path) {
+        String configDir = getConfigDirectory().getAbsolutePath();
+        return path.replace(CONFIG_DIR_PLACEHOLDER, configDir);
+    }
+
+    private static Document loadConfig() {
+
+        File configDir = getConfigDirectory();
+
+        File file = new File(configDir, CONFIG_FILE);
+
+        if (!file.canRead() && !file.isFile()) {
+            logger.error("Cannot read config file '"
+                + file + "'.");
+            return null;
+        }
+
+        try {
+            DocumentBuilderFactory factory =
+                DocumentBuilderFactory.newInstance();
+            factory.setValidating(false); // XXX: This may change in future.
+            return factory.newDocumentBuilder().parse(file);
+        }
+        catch (SAXException se) {
+            logger.error(se.getLocalizedMessage(), se);
+        }
+        catch (ParserConfigurationException pce) {
+            logger.error(pce.getLocalizedMessage(), pce);
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage());
+        }
+
+        return null;
+    }
+
+    /**
+     * Convenience method to search within a given document tree via XPath.
+     * See {@link XMLUtils#xpath(Object, String, QName) } for details.
+     * @param root The object which is used as the root of the tree to
+     * be searched in.
+     * @param query The XPath query.
+     * @param returnType The type of the result.
+     * @return The result of type 'returnTyp' or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final Object getXPath(
+        Object root, String query, QName returnType
+    ) {
+        return XMLUtils.xpath(root, query, returnType);
+    }
+
+    /**
+     * Convenience method to search within the central configuration via XPath.
+     * See {@link XMLUtils#xpath(Object, String, QName) } for details.
+     * @param query The XPath query.
+     * @param returnType The type of the result.
+     * @return The result of type 'returnTyp' or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final Object getXPath(String query, QName returnType) {
+        return XMLUtils.xpath(getConfig(), query, returnType);
+    }
+
+    /**
+     * Convenience method to search for a node list within the central
+     * configuation document via XPath.
+     * @param query The XPath query.
+     * @return The queried node list or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final NodeList getNodeSetXPath(String query) {
+        return (NodeList)getXPath(query, XPathConstants.NODESET);
+    }
+
+    /**
+     * Convenience method to search for a node within the central
+     * configuation document via XPath.
+     * @param query The XPath query.
+     * @return The queried node or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final Node getNodeXPath(String query) {
+        return (Node)getXPath(query, XPathConstants.NODE);
+    }
+
+    /**
+     * Convenience method to search for a string within the central
+     * configuation document via XPath.
+     * @param xpath The XPath query.
+     * @return The queried string or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final String getStringXPath(String xpath) {
+        return getStringXPath(xpath, null);
+    }
+
+    /**
+     * Convenience method to search for a string within the central
+     * configuation document via XPath.
+     * @param query The XPath query.
+     * @param def The string to be returned if the search has no results.
+     * @return The queried string or the default value if something went
+     * wrong during XPath evaluation.
+     */
+    public static final String getStringXPath(String query, String def) {
+        String s = (String)getXPath(query, XPathConstants.STRING);
+        return s == null || s.length() == 0
+            ? def
+            : s;
+    }
+
+    /**
+     * Convenience method to search for a node list within a given tree
+     * via XPath.
+     * @param root The root of the tree to be searched in.
+     * @param query The XPath query.
+     * @return The queried node list or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final NodeList getNodeSetXPath(Object root, String query) {
+        return (NodeList)getXPath(root, query, XPathConstants.NODESET);
+    }
+
+    /**
+     * Convenience method to search for a node within a given tree
+     * via XPath.
+     * @param root The root of the tree to be searched in.
+     * @param query The XPath query.
+     * @return The queried node or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final Node getNodeXPath(Object root, String query) {
+        return (Node)getXPath(root, query, XPathConstants.NODE);
+    }
+
+    /**
+     * Convenience method to search for a string within a given tree
+     * via XPath.
+     * @param root The root of the tree to be searched in.
+     * @param xpath The XPath query.
+     * @return The queried string or null if something went
+     * wrong during XPath evaluation.
+     */
+    public static final String getStringXPath(Object root, String xpath) {
+        return getStringXPath(root, xpath, null);
+    }
+
+    /**
+     * Convenience method to search for a string within a given tree
+     * via XPath.
+     * @param root The root of the tree to be searched in.
+     * @param query xpath The XPath query.
+     * @param def The string to be returned if the search has no results.
+     * @return The queried string or the default value if something went
+     * wrong during XPath evaluation.
+     */
+    public static final String getStringXPath(
+        Object root, String query, String def
+    ) {
+        String s = (String)getXPath(root, query, XPathConstants.STRING);
+        return s == null || s.length() == 0
+            ? def
+            : s;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/CreationFilter.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,61 @@
+package de.intevation.artifacts.common.utils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+import org.w3c.dom.Element;
+
+public class CreationFilter
+{
+    public static class Facet {
+
+        protected String name;
+        protected String index;
+
+        public Facet() {
+        }
+
+        public Facet(String name, String index) {
+            this.name  = name;
+            this.index = index;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getIndex() {
+            return index;
+        }
+    }
+
+    protected Map<String, List<Facet>> outs;
+
+    public CreationFilter() {
+        outs = new HashMap<String, List<Facet>>();
+    }
+
+    public void add(String out, List<Facet> facets) {
+        outs.put(out, facets);
+    }
+
+    public Element toXML(XMLUtils.ElementCreator ec) {
+        Element filter = ec.create("filter");
+
+        for (Map.Entry<String, List<Facet>> entry: outs.entrySet()) {
+            Element out = ec.create("out");
+            out.setAttribute("name", entry.getKey());
+            for (Facet facet: entry.getValue()) {
+                Element f = ec.create("facet");
+                f.setAttribute("name", facet.getName());
+                f.setAttribute("index", facet.getIndex());
+                out.appendChild(f);
+            }
+            filter.appendChild(out);
+        }
+
+        return filter;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/DateUtils.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,30 @@
+package de.intevation.artifacts.common.utils;
+
+import java.util.Calendar;
+import java.util.Date;
+
+
+public class DateUtils {
+
+    private DateUtils() {
+    }
+
+
+    /**
+     * This function extracts the year as int value from <i>date</i>.
+     *
+     * @param date The source date.
+     *
+     * @return the year as integer or -1 if date is empty.
+     */
+    public static int getYearFromDate(Date date) {
+        if (date == null) {
+            return -1;
+        }
+
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+
+        return cal.get(Calendar.YEAR);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/FileTools.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2010, 2011 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+package de.intevation.artifacts.common.utils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.BufferedOutputStream;
+import java.nio.channels.FileChannel;
+
+import java.util.Deque;
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.log4j.Logger;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class FileTools
+{
+    private static Logger log = Logger.getLogger(FileTools.class);
+
+    public static final String DIGEST =
+        System.getProperty("artifacts.common.file.cmp.digest", "MD5");
+
+    private FileTools() {
+    }
+
+
+    /** Remove everything after dot from name. */
+    public static final String removeExtension(String name) {
+        int index = name.lastIndexOf('.');
+        return index == -1
+            ? name
+            : name.substring(0, index);
+    }
+
+
+    public static File getDirectory(String path, String name) {
+        if (path == null || name == null) {
+            return null;
+        }
+
+        File dir = new File(path, name);
+
+        if (!dir.exists()) {
+            log.debug(
+                "Directory '" + dir.getAbsolutePath() + "' doesn't " +
+                "exist. Try to create it.");
+
+            return dir.mkdir() ? dir : null;
+        }
+        else {
+            return dir.isDirectory() ? dir : null;
+        }
+    }
+
+    public static File repair(File file) {
+        file = file.getAbsoluteFile();
+        if (file.exists()) {
+            return file;
+        }
+        Deque<String> parts = new ArrayDeque<String>();
+        File curr = file;
+        while (curr != null) {
+            String name = curr.getName();
+            if (name.length() > 0) {
+                parts.push(curr.getName());
+            }
+            curr = curr.getParentFile();
+        }
+
+        curr = null;
+        OUTER: while (!parts.isEmpty()) {
+            String f = parts.pop();
+            log.debug("fixing: '" + f + "'");
+            if (f.equals(".") || f.equals("..")) {
+                // No need to fix . or ..
+                continue;
+            }
+            if (curr == null) {
+                // XXX: Not totaly correct because there
+                // more than one root on none unix systems.
+                for (File root: File.listRoots()) {
+                    File [] files = root.listFiles();
+                    if (files == null) {
+                        log.warn("cannot list '" + root);
+                        continue;
+                    }
+                    for (File candidate: files) {
+                        if (candidate.getName().equalsIgnoreCase(f)) {
+                            curr = new File(root, candidate.getName());
+                            continue OUTER;
+                        }
+                    }
+                }
+                break;
+            }
+            else {
+                File [] files = curr.listFiles();
+                if (files == null) {
+                    log.warn("cannot list: '" + curr + "'");
+                    return file;
+                }
+                for (File candidate: files) {
+                    if (candidate.getName().equalsIgnoreCase(f)) {
+                        curr = new File(curr, candidate.getName());
+                        continue OUTER;
+                    }
+                }
+                curr = null;
+                break;
+            }
+        }
+
+        if (curr == null) {
+            log.warn("cannot repair path '" + file + "'");
+            return file;
+        }
+
+        return curr;
+    }
+
+    /** Object that can calculate hash of file, compare two hashed files etc. */
+    public static class HashedFile
+    implements Comparable<HashedFile>
+    {
+        protected File    file;
+        protected long    length;
+        protected byte [] hash;
+
+        public HashedFile(File file) {
+            this.file = file;
+            length = file.length();
+        }
+
+        public File getFile() {
+            return file;
+        }
+
+        protected byte [] getHash() {
+            if (hash == null) {
+                InputStream in = null;
+
+                try {
+                    in = new FileInputStream(file);
+
+                    MessageDigest digest = MessageDigest.getInstance(DIGEST);
+
+                    byte [] buf = new byte[40*1024];
+                    int r;
+
+                    while ((r = in.read(buf)) >= 0) {
+                        digest.update(buf, 0, r);
+                    }
+
+                    hash = digest.digest();
+                }
+                catch (IOException ioe) {
+                    log.error(ioe);
+                    hash = new byte[0];
+                }
+                catch (NoSuchAlgorithmException nsae) {
+                    log.error(nsae);
+                    hash = new byte[0];
+                }
+                finally {
+                    if (in != null) {
+                        try {
+                            in.close();
+                        }
+                        catch (IOException ioe) {
+                            log.error(ioe);
+                        }
+                    }
+                }
+            }
+            return hash;
+        }
+
+        @Override
+        public int compareTo(HashedFile other) {
+            if (length < other.length) return -1;
+            if (length > other.length) return +1;
+            return compare(getHash(), other.getHash());
+        }
+
+        private static int compare(byte [] a, byte [] b) {
+            if (a.length < b.length) return -1;
+            if (a.length > b.length) return +1;
+            for (int i = 0; i < a.length; ++i) {
+                int x = a[i] & 0xff;
+                int y = b[i] & 0xff;
+                if (x < y) return -1;
+                if (x > y) return +1;
+            }
+            return 0;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            return other instanceof HashedFile
+                && ((HashedFile)other).compareTo(this) == 0;
+        }
+
+        @Override
+        public int hashCode() {
+            return (int)(length ^ (length >>> 32));
+        }
+    } // class HashedFile
+
+    public static List<File> uniqueFiles(List<File> files) {
+
+        Set<HashedFile> set = new HashSet<HashedFile>();
+
+        for (File file: files) {
+            if (!set.add(new HashedFile(file))) {
+                log.warn("file '" + file + "' is a duplicate.");
+            }
+        }
+
+        ArrayList<File> out = new ArrayList<File>(set.size());
+        for (HashedFile hf: set) {
+            out.add(hf.file);
+        }
+
+        return out;
+    }
+
+    public interface FileVisitor {
+        boolean visit(File file);
+    } // Visitor
+
+    public static void walkTree(File root, FileVisitor visitor) {
+
+        Deque<File> stack = new ArrayDeque<File>();
+
+        stack.push(root);
+
+        while (!stack.isEmpty()) {
+            File current = stack.pop();
+            if (!visitor.visit(current)) break;
+            if (current.isDirectory()) {
+                File [] subs = current.listFiles();
+                if (subs != null) {
+                    for (File f: subs) {
+                        stack.push(f);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Deletes everything in a directory.
+     *
+     * @param dir The directory.
+     */
+    public final static void deleteContent(File dir) {
+        if (dir == null || !dir.isDirectory()) {
+            return;
+        }
+
+        File[] files = dir.listFiles();
+        if (files != null) {
+            for (File file: files) {
+                deleteRecursive(file);
+            }
+        }
+
+        return;
+    }
+
+    /**
+     * Delete <i>file</i> and everything in <i>file</i> if it is a directory.
+     *
+     * @param file The file or directory.
+     * @return true, if deletion was successful - otherwise false.
+     */
+    public final static boolean deleteRecursive(File file) {
+
+        if (file == null) {
+            return false;
+        }
+
+        if (file.isDirectory()) {
+            File [] files = file.listFiles();
+            if (files != null) {
+                for (File sub: files) {
+                    if (!deleteRecursive(sub)) {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        return file.delete();
+    }
+
+    /**
+     * Put the given file or directory into a zip archive.
+     *
+     * @param file The file or directory.
+     * @param outputStream The stream to write the archive to.
+     * @throws IOException if an error occured while zip creation or writing to
+     * output stream.
+     */
+    public static void createZipArchive(
+        File         file,
+        OutputStream outputStream
+    )
+    throws IOException
+    {
+        ZipOutputStream out = new ZipOutputStream(outputStream);
+
+        if (file.isFile()) {
+            copyFileToZip("", file, out);
+        }
+        else if (file.isDirectory()) {
+
+            Deque<PrefixDir> stack = new ArrayDeque<PrefixDir>();
+            stack.push(new PrefixDir(file.getName() + "/", file));
+
+            while (!stack.isEmpty()) {
+                PrefixDir pd = stack.pop();
+
+                ZipEntry dirEntry = new ZipEntry(pd.prefix);
+                out.putNextEntry(dirEntry);
+                out.closeEntry();
+
+                File [] files = pd.dir.listFiles();
+                if (files != null) {
+                    for (File sub: files) {
+                        if (sub.isDirectory()) {
+                            stack.push(new PrefixDir(
+                                pd.prefix + sub.getName() + "/",
+                                sub));
+                        }
+                        else if (sub.isFile()) {
+                            copyFileToZip(pd.prefix, sub, out);
+                        }
+                    }
+                }
+            }
+        }
+
+        out.finish();
+    }
+
+
+    public static void extractArchive(File archive, File destDir)
+    throws IOException {
+        if (!destDir.exists()) {
+            destDir.mkdir();
+        }
+
+        ZipFile zipFile = new ZipFile(archive);
+        try {
+            Enumeration<? extends ZipEntry> entries = zipFile.entries();
+
+            byte [] buffer = new byte[16384];
+
+            while (entries.hasMoreElements()) {
+                ZipEntry entry = entries.nextElement();
+
+                String entryFileName = entry.getName();
+
+                File dir = buildDirectoryHierarchyFor(entryFileName, destDir);
+                if (!dir.exists()) {
+                    dir.mkdirs();
+                }
+
+                if (!entry.isDirectory()) {
+                    BufferedInputStream bis = new BufferedInputStream(
+                        zipFile.getInputStream(entry));
+                    try {
+                        BufferedOutputStream bos = new BufferedOutputStream(
+                            new FileOutputStream(new File(destDir, entryFileName)));
+
+                        try {
+                            int len;
+                            while ((len = bis.read(buffer)) > 0) {
+                                bos.write(buffer, 0, len);
+                            }
+                            bos.flush();
+                        }
+                        finally {
+                            bos.close();
+                        }
+                    }
+                    finally {
+                        bis.close();
+                    }
+                } // is file
+            }
+        }
+        finally {
+            zipFile.close();
+        }
+    }
+
+    private static File buildDirectoryHierarchyFor(
+        String entryName,
+        File destDir)
+    {
+        int lastIndex = entryName.lastIndexOf('/');
+        String internalPathToEntry = entryName.substring(0, lastIndex + 1);
+        return new File(destDir, internalPathToEntry);
+    }
+
+    /**
+     * A class representing a directory with a prefix.
+     */
+    private static final class PrefixDir {
+
+        String prefix;
+        File   dir;
+
+        public PrefixDir(String prefix, File dir) {
+            this.prefix = prefix;
+            this.dir    = dir;
+        }
+
+    } // class PrefixDir
+
+    /**
+     * Write a file to zip archive.
+     *
+     * @param prefix A prefix.
+     * @param file The file.
+     * @param out The output stream.
+     * @throws IOException if an error occured while writing to zip output
+     * stream.
+     */
+    private static void copyFileToZip(
+        String          prefix,
+        File            file,
+        ZipOutputStream out
+    )
+    throws IOException
+    {
+        String   entryName = prefix + file.getName();
+        ZipEntry entry     = new ZipEntry(entryName);
+        out.putNextEntry(entry);
+        InputStream in = null;
+        try {
+            in =
+                new BufferedInputStream(
+                new FileInputStream(file), 20*1024);
+
+            byte [] buf = new byte[2048];
+
+            int r;
+            while ((r = in.read(buf)) > 0) {
+                out.write(buf, 0, r);
+            }
+        }
+        finally {
+            if (in != null) {
+                try { in.close(); }
+                catch (IOException ioe) {}
+            }
+        }
+        out.closeEntry();
+    }
+
+
+    /**
+     * Copies a <i>src</i> file to <i>target</i>.
+     *
+     * @param src A file (not a directory) that should be copied.
+     * @param target The destination. This might be a file or a directory.
+     *
+     * @return true, if <i>src</i> has been successfully copied; otherwise
+     * false.
+     */
+    public static boolean copyFile(File src, File target)
+    throws IOException
+    {
+        if (src == null || !src.exists()) {
+            log.warn("Source file does not exist!");
+            return false;
+        }
+
+        if (!src.canRead()) {
+            log.warn("Cannot read Source file!");
+            return false;
+        }
+
+        if (src.isDirectory()) {
+            log.warn("Source is a directory!");
+            return false;
+        }
+
+        if (target.isDirectory()) {
+            target = new File(target, src.getName());
+        }
+
+        FileInputStream  in  = null;
+        FileOutputStream out = null;
+
+        try {
+            in  = new FileInputStream(src);
+            out = new FileOutputStream(target);
+
+            FileChannel inChannel  = in.getChannel();
+            FileChannel outChannel = out.getChannel();
+
+            inChannel.transferTo(0l, inChannel.size(), outChannel);
+
+            return true;
+        }
+        catch (IOException ioe) {
+            log.warn(ioe, ioe);
+        }
+        finally {
+            if (in != null) {
+                try {
+                    in.close();
+                }
+                catch (IOException ioe) { /* do nothing here */ }
+            }
+
+            if (out != null) {
+                try {
+                    out.close();
+                }
+                catch (IOException ioe) { /* do nothing here */ }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Copies a directory <i>source</i> to a destination path <i>dest</i>.
+     *
+     * @param source A directory that should be copied.
+     * @param dest A destination directory which is created if it is not
+     * existing yet.
+     *
+     * @return true, if the directory has been successfully copied; otherwise
+     * false.
+     */
+    public static boolean copyDirectory(final File source, final File dest) {
+        if (source == null || !source.exists()) {
+            log.warn("Source directory does not exist!");
+            return false;
+        }
+
+        if (!source.isDirectory()) {
+            log.warn("Source is not a directory!");
+            return false;
+        }
+
+        if (dest == null) {
+            log.warn("Destination directory is null!");
+            return false;
+        }
+
+        if (!dest.exists()) {
+            if (!dest.mkdir()) {
+                log.warn("Cannot create destination directory!");
+                return false;
+            }
+        }
+
+        File[] children = source.listFiles();
+        int    failed   = 0;
+
+        if (children != null && children.length > 0) {
+            for (File child: children) {
+                if (child.isFile()) {
+                    try {
+                        if (!copyFile(child, dest)) {
+                            failed++;
+                        }
+                    }
+                    catch (IOException ioe) {
+                        log.warn(ioe, ioe);
+                        failed++;
+                    }
+                }
+                else if (child.isDirectory()) {
+                    copyDirectory(child, new File(dest, child.getName()));
+                }
+            }
+        }
+
+        log.debug("Failed to copy " + failed + " files.");
+
+        return true;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/JSON.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,445 @@
+package de.intevation.artifacts.common.utils;
+
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import java.io.IOException;
+import java.io.PushbackInputStream;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.ByteArrayInputStream;
+import java.io.StringWriter;
+
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+
+public final class JSON
+{
+    private JSON() {
+    }
+
+    private static final boolean isDigit(int c) {
+        return c >= '0' && c <= '9';
+    }
+
+    public static final boolean isWhitespace(int c) {
+        return c == ' '  || c == '\n' || c == '\r'
+            || c == '\t' || c == '\f';
+    }
+
+    private static final void match(int c, int x) throws IOException {
+        if (c != x) {
+            throw new IOException(
+                "Expecting '" + (char)c + "' found '" + (char)x + "'");
+        }
+    }
+
+    private static final int eof(InputStream in)
+    throws IOException
+    {
+        int c = in.read();
+        if (c == -1) {
+            throw new IOException("EOF unexpected.");
+        }
+        return c;
+    }
+
+    private static final int whitespace(InputStream in)
+    throws IOException
+    {
+        int c;
+        while (isWhitespace(c = eof(in)));
+        return c;
+    }
+
+    private static final int parseHex(String hex) throws IOException {
+        try {
+            return Integer.parseInt(hex, 16);
+        }
+        catch (NumberFormatException nfe) {
+            throw new IOException("'" + hex + "' is not a hex string.");
+        }
+    }
+
+    public static final String jsonString(String string) {
+        StringBuilder sb = new StringBuilder(string.length()+2);
+
+        sb.append('"');
+
+        for (int i = 0, N = string.length(); i < N; ++i) {
+            char c = string.charAt(i);
+            switch (c) {
+                case '"':  sb.append("\\\""); break;
+                case '\t': sb.append("\\t"); break;
+                case '\r': sb.append("\\r"); break;
+                case '\n': sb.append("\\n"); break;
+                case '\b': sb.append("\\b"); break;
+                case '\f': sb.append("\\f"); break;
+                default:
+                    if (c >= 128) {
+                        sb.append("\\u");
+                        String hex = Integer.toHexString((int)c);
+                        for (int j = 4-hex.length(); j > 0; --j) {
+                            sb.append('0');
+                        }
+                        sb.append(hex);
+                    }
+                    else {
+                        sb.append(c);
+                    }
+            }
+        }
+
+        sb.append('"');
+
+        return sb.toString();
+    }
+
+    public static String toJSONString(Map<String, Object> map) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        write(pw, map);
+        pw.flush();
+        return sw.toString();
+    }
+
+
+    public static void write(PrintWriter out, Map<String, Object> map) {
+        writeObject(out, map);
+    }
+
+    private static void writeValue(PrintWriter out, Object value) {
+        if (value instanceof Map) {
+            writeObject(out, (Map)value);
+        }
+        else if (value instanceof List) {
+            writeList(out, (List)value);
+        }
+        else if (value instanceof Number) {
+            out.print(value);
+        }
+        else if (value instanceof Boolean) {
+            out.print(((Boolean)value) ? "true" : "false");
+        }
+        else if (value == null) {
+            out.print("null");
+        }
+        else {
+            out.print(jsonString(value.toString()));
+        }
+    }
+
+    private static void writeObject(PrintWriter out, Map map) {
+
+        out.print('{');
+        Iterator iter = map.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            out.print(jsonString(entry.getKey().toString()));
+            out.print(':');
+            writeValue(out, entry.getValue());
+            if (iter.hasNext()) {
+                out.print(',');
+            }
+        }
+        out.print('}');
+    }
+
+    private static void writeList(PrintWriter out, List list) {
+        out.print('[');
+        Iterator iter = list.iterator();
+        while (iter.hasNext()) {
+            writeValue(out, iter.next());
+            if (iter.hasNext()) {
+                out.print(',');
+            }
+        }
+        out.print(']');
+    }
+
+    public static Map<String, Object> parse(String in)
+    throws IOException
+    {
+        return parse(asInputStream(in));
+    }
+
+    private static InputStream asInputStream(String in) {
+        byte [] bytes;
+        try {
+            bytes = in.getBytes(Charset.forName("US-ASCII"));
+        }
+        catch (UnsupportedCharsetException uce) {
+            // Should not happen.
+            bytes = in.getBytes();
+        }
+        return new ByteArrayInputStream(bytes);
+    }
+
+    public static Map<String, Object> parse(InputStream in)
+    throws IOException
+    {
+        return parseObject(new PushbackInputStream(in, 1));
+    }
+
+    public static Map<String, Object> parse(PushbackInputStream in)
+    throws IOException
+    {
+        return parseObject(in);
+    }
+
+    private static final String parseString(
+        PushbackInputStream in
+    )
+    throws IOException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        int mode = 0;
+
+        char [] hex = new char[4];
+
+        match('"', eof(in));
+
+        OUT: for (int c = eof(in);; c = eof(in)) {
+
+            switch (mode) {
+                case 0:
+                    if (c == '"') {
+                        break OUT;
+                    }
+                    if (c == '\\') {
+                        mode = 1;
+                    }
+                    else {
+                        sb.append((char)c);
+                    }
+                    break;
+                case 1:
+                    switch (c) {
+                        case 'u':
+                            mode = 2;
+                            continue;
+                        case 'b':
+                            sb.append('\b');
+                            break;
+                        case 'f':
+                            sb.append('\f');
+                            break;
+                        case 'n':
+                            sb.append('\n');
+                            break;
+                        case 'r':
+                            sb.append('\r');
+                            break;
+                        case 't':
+                            sb.append('\t');
+                            break;
+                        default:
+                            sb.append((char)c);
+                    }
+                    mode = 0;
+                    break;
+                case 2:
+                    hex[0] = (char)c;
+                    mode = 3;
+                    break;
+                case 3:
+                    hex[1] = (char)c;
+                    mode = 4;
+                    break;
+                case 4:
+                    hex[2] = (char)c;
+                    mode = 5;
+                    break;
+                case 5:
+                    hex[3] = (char)c;
+                    sb.append((char)parseHex(new String(hex)));
+                    mode = 0;
+                    break;
+            }
+        }
+        return sb.toString();
+    }
+
+    private static final Boolean parseTrue(InputStream in)
+    throws IOException
+    {
+        match('t', eof(in));
+        match('r', eof(in));
+        match('u', eof(in));
+        match('e', eof(in));
+        return Boolean.TRUE;
+    }
+
+    private static final Boolean parseFalse(InputStream in)
+    throws IOException
+    {
+        match('f', eof(in));
+        match('a', eof(in));
+        match('l', eof(in));
+        match('s', eof(in));
+        match('e', eof(in));
+        return Boolean.FALSE;
+    }
+
+    private static final Object parseNull(InputStream in)
+    throws IOException
+    {
+        match('n', eof(in));
+        match('u', eof(in));
+        match('l', eof(in));
+        match('l', eof(in));
+        return null;
+    }
+
+    private static final Number parseNumber(PushbackInputStream in)
+    throws IOException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        boolean isInteger = true;
+
+        int c;
+        OUT: for (;;) {
+            switch (c = eof(in)) {
+                case '0': case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                case '-': case '+':
+                    sb.append((char)c);
+                    break;
+                case '.': case 'e': case 'E':
+                    isInteger = false;
+                    sb.append((char)c);
+                    break;
+                default:
+                    in.unread(c);
+                    break OUT;
+            }
+        }
+
+        try {
+            if (isInteger) {
+                return sb.length() > 9
+                    ? (Number)Long   .valueOf(sb.toString())
+                    : (Number)Integer.valueOf(sb.toString());
+            }
+            return (Number)Double.valueOf(sb.toString());
+        }
+        catch (NumberFormatException nfe) {
+            throw new IOException("Not a number '" + sb + "'");
+        }
+    }
+
+    private static List<Object> parseList(PushbackInputStream in)
+    throws IOException
+    {
+        List<Object> list = new ArrayList<Object>();
+        match('[', whitespace(in));
+        int c = whitespace(in);
+        if (c == ']') {
+            return list;
+        }
+
+        for (;; c = whitespace(in)) {
+            Object value;
+            in.unread(c);
+            switch (c) {
+                case '{':
+                    value = parseObject(in);
+                    break;
+                case '[':
+                    value = parseList(in);
+                    break;
+                case '"':
+                    value = parseString(in);
+                    break;
+                case 't':
+                    value = parseTrue(in);
+                    break;
+                case 'f':
+                    value = parseFalse(in);
+                    break;
+                case 'n':
+                    value = parseNull(in);
+                    break;
+                default:
+                    value = parseNumber(in);
+            }
+            list.add(value);
+
+            if ((c = whitespace(in)) == ']') break;
+            match(',', c);
+        }
+        return list;
+    }
+
+    private static void parsePair(
+        PushbackInputStream in,
+        Map<String, Object> pairs
+    )
+    throws IOException
+    {
+        in.unread(whitespace(in));
+        String string = parseString(in);
+        match(':', whitespace(in));
+
+        Object value;
+
+        int c = whitespace(in);
+        in.unread(c);
+        switch (c) {
+            case '{':
+                value = parseObject(in);
+                break;
+            case '[':
+                value = parseList(in);
+                break;
+            case '"':
+                value = parseString(in);
+                break;
+            case 't':
+                value = parseTrue(in);
+                break;
+            case 'f':
+                value = parseFalse(in);
+                break;
+            case 'n':
+                value = parseNull(in);
+                break;
+            default:
+                value = parseNumber(in);
+        }
+        pairs.put(string, value);
+    }
+
+    private static Map<String, Object> parseObject(PushbackInputStream in)
+    throws IOException
+    {
+        Map<String, Object> pairs = new LinkedHashMap<String, Object>();
+
+        int c = whitespace(in);
+        match('{', c);
+
+        if ((c = whitespace(in)) == '}') {
+            return pairs;
+        }
+
+        in.unread(c);
+
+        for (;;) {
+            parsePair(in, pairs);
+
+            if ((c = whitespace(in)) == '}') {
+                break;
+            }
+
+            if (c == '}') break;
+            match(',', c);
+        }
+
+        return pairs;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/LRUCache.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,26 @@
+package de.intevation.artifacts.common.utils;
+
+import java.util.Map;
+import java.util.LinkedHashMap;
+
+public class LRUCache<K, V>
+extends      LinkedHashMap<K, V>
+{
+    public static final int DEFAULT_MAX_CAPACITY = 25;
+
+    private int maxCapacity;
+
+    public LRUCache() {
+        this(DEFAULT_MAX_CAPACITY);
+    }
+
+    public LRUCache(int maxCapacity) {
+        this.maxCapacity = maxCapacity;
+    }
+
+    @Override
+    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+        return size() > maxCapacity;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/MapXPathVariableResolver.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+package de.intevation.artifacts.common.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathVariableResolver;
+
+
+/**
+ *  @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class MapXPathVariableResolver implements XPathVariableResolver {
+
+    protected Map<String, String> variables;
+
+
+    public MapXPathVariableResolver() {
+        this.variables = new HashMap<String, String>();
+    }
+
+
+    public MapXPathVariableResolver(Map<String, String> variables) {
+        this.variables = variables;
+    }
+
+
+    public void addVariable(String name, String value) {
+        if (name != null && value != null) {
+            variables.put(name, value);
+        }
+    }
+
+
+    @Override
+    public Object resolveVariable(QName variableName) {
+        String key = variableName.getLocalPart();
+        return variables.get(key);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/StringUtils.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2010 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+
+package de.intevation.artifacts.common.utils;
+
+import java.io.UnsupportedEncodingException;
+
+import java.util.UUID;
+
+import org.apache.commons.codec.DecoderException;
+
+import org.apache.commons.codec.binary.Hex;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Commonly used string functions.
+ *
+ * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
+ */
+public final class StringUtils
+{
+    private static Logger logger = Logger.getLogger(StringUtils.class);
+
+    /**
+     * Generated a random UUIDv4 in form of a string.
+     * @return the UUID
+     */
+    public static final String newUUID() {
+        return UUID.randomUUID().toString();
+    }
+
+    /**
+     * Checks if a given string is a valid UUID.
+     * @param uuid The string to test.
+     * @return true if the string is a valid UUID else false.
+     */
+    public static final boolean checkUUID(String uuid) {
+        try {
+            UUID.fromString(uuid);
+        }
+        catch (IllegalArgumentException iae) {
+            logger.warn(iae.getLocalizedMessage());
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the UTF-8 byte array representation of a given string.
+     * @param s The string to be transformed.
+     * @return The byte array representation.
+     */
+    public static final byte [] getUTF8Bytes(String s) {
+        try {
+            return s.getBytes("UTF-8");
+        }
+        catch (UnsupportedEncodingException usee) {
+            logger.error(usee.getLocalizedMessage(), usee);
+            return s.getBytes();
+        }
+    }
+
+    /**
+     * Tries to convert a Base64 encoded string into the
+     * corresponing byte array.
+     * @param s The Base64 encoded string
+     * @return The byte array representation or null if
+     * an decoding error occurs.
+     */
+    public static final byte [] decodeHex(String s) {
+        try {
+            return Hex.decodeHex(s.toCharArray());
+        }
+        catch (DecoderException de) {
+            return null;
+        }
+    }
+
+    public static final String repeat(String s, int count, String sep) {
+        if (count <= 0) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder(s);
+        for (--count; count > 0; --count) {
+            sb.append(sep).append(s);
+        }
+        return sb.toString();
+    }
+
+    public static final String repeat(char c, int count, char sep) {
+        if (count <= 0) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder(2*count-1).append(c);
+        for (--count; count > 0; --count) {
+            sb.append(sep).append(c);
+        }
+        return sb.toString();
+    }
+
+    public static final String [] toUpperCase(String [] s) {
+        if (s == null) {
+            return null;
+        }
+        String [] d = new String[s.length];
+        for (int i = 0; i < s.length; ++i) {
+            if (s[i] != null) {
+                d[i] = s[i].toUpperCase();
+            }
+        }
+        return d;
+    }
+
+    public static String join(String sep, String [] strings) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < strings.length; ++i) {
+            if (i > 0) sb.append(sep);
+            sb.append(strings[i]);
+        }
+        return sb.toString();
+    }
+
+    public static final String [] join(String [] a, String [] b) {
+        if (a == null && b == null) return null;
+        if (a == null) return b;
+        if (b == null) return a;
+        String [] dst = new String[a.length + b.length];
+        System.arraycopy(a, 0, dst, 0, a.length);
+        System.arraycopy(b, 0, dst, a.length, b.length);
+        return dst;
+    }
+
+    public static final boolean contains(String needle, String [] haystack) {
+        for (String stray: haystack) {
+            if (needle.equals(stray)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/XMLUtils.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2010 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+
+package de.intevation.artifacts.common.utils;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+
+import javax.xml.transform.dom.DOMSource;
+
+import javax.xml.transform.stream.StreamResult;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathVariableResolver;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Some helper functions to ease work with XML concering namespaces, XPATH
+ * and so on.
+ *  @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
+ */
+public final class XMLUtils
+{
+    /** W3C URL of XForms. */
+    public static final String XFORM_URL    = "http://www.w3.org/2002/xforms";
+
+    /** W3C prefix of XForms. */
+    public static final String XFORM_PREFIX = "xform";
+
+    /** Logger for this class. */
+    private static Logger logger = Logger.getLogger(XMLUtils.class);
+
+    private XMLUtils() {
+    }
+
+    /**
+     * Helper class to generate elements and attributes with
+     * namespaces.
+     */
+    public static class ElementCreator
+    {
+        /** Owner document of the elements to be created. */
+        protected Document document;
+
+        /** Namespace to be used. */
+        protected String   ns;
+
+        /** Prefix to be used. */
+        protected String   prefix;
+
+        /**
+         * Constructor to create an element/attribute creator
+         * with a given namespace and namespace prefix using a
+         * given owner document.
+         * @param document The owning document
+         * @param ns       The namespace
+         * @param prefix   The namespace prefix
+         */
+        public ElementCreator(Document document, String ns, String prefix) {
+            this.document = document;
+            this.ns       = ns;
+            this.prefix   = prefix;
+        }
+
+        /**
+         * Creates a new element using the owning document with
+         * the this creators namespace and namespace prefix.
+         * @param name The name of the element
+         * @return     The new element
+         */
+        public Element create(String name) {
+            Element element = document.createElementNS(ns, name);
+            element.setPrefix(prefix);
+            return element;
+        }
+
+        /**
+         * Adds a new attribute and its value to a given element.
+         * It does not set the namespace prefix.
+         * @param element The element to add the attribute to
+         * @param name    The name of the attribute
+         * @param value   The value of the attribute
+         */
+        public void addAttr(Element element, String name, String value) {
+            addAttr(element, name, value, false);
+        }
+
+        /**
+         * Adds a new attribute and its value to a given element.
+         * If the namespace prefix is used is decided by the 'addPrefix' flag.
+         * @param element The element to add the attribute to
+         * @param name    The name of the attribute
+         * @param value   The value of the attribute
+         * @param addPrefix If true the creators namespace prefix is
+         * set on the attribute.
+         */
+        public void addAttr(
+            Element element,
+            String  name,
+            String  value,
+            boolean addPrefix
+        ) {
+            if (addPrefix) {
+                Attr attr = document.createAttributeNS(ns, name);
+                attr.setValue(value);
+                attr.setPrefix(prefix);
+
+                element.setAttributeNode(attr);
+            }
+            else {
+                element.setAttribute(name, value);
+            }
+        }
+    } // class ElementCreator
+
+    /**
+     * Creates a new XML document
+     * @return the new XML document ot null if something went wrong during
+     * creation.
+     */
+    public static final Document newDocument() {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+
+        try {
+            return factory.newDocumentBuilder().newDocument();
+        }
+        catch (ParserConfigurationException pce) {
+            logger.error(pce.getLocalizedMessage(), pce);
+        }
+        return null;
+    }
+
+
+    /**
+     * Create xml/string representation of element (nested in otherwise empty
+     * document).
+     * @param element element to inspect in string.
+     * @return string with xml representation of element.
+     */
+    public final static String toString(Node node) {
+        Document doc = newDocument();
+        doc.appendChild(doc.importNode(node,true));
+        return toString(doc);
+    }
+
+
+    /**
+     * Loads a XML document namespace aware from a file
+     * @param file The file to load.
+     * @return the XML document or null if something went wrong
+     * during loading.
+     */
+    public static final Document parseDocument(File file) {
+        InputStream inputStream = null;
+        try {
+            inputStream = new BufferedInputStream(new FileInputStream(file));
+            return parseDocument(inputStream);
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+        }
+        finally {
+            if (inputStream != null) {
+                try { inputStream.close(); }
+                catch (IOException ioe) {}
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Parses a String to a xml document.
+     *
+     * @param string The xml string
+     * @return the XML document or null if something went wrong.
+     */
+    public static final Document parseDocument(String string) {
+        InputStream inputStream = new ByteArrayInputStream(string.getBytes());
+        return parseDocument(inputStream);
+    }
+
+
+    public static final Document parseDocument(InputStream inputStream) {
+        return parseDocument(inputStream, Boolean.TRUE);
+    }
+
+    public static final Document parseDocument(
+        InputStream inputStream,
+        Boolean     namespaceAware
+    ) {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+        if (namespaceAware != null) {
+            factory.setNamespaceAware(namespaceAware.booleanValue());
+        }
+
+        try {
+            return factory.newDocumentBuilder().parse(inputStream);
+        }
+        catch (ParserConfigurationException pce) {
+            logger.error(pce.getLocalizedMessage(), pce);
+        }
+        catch (SAXException se) {
+            logger.error(se.getLocalizedMessage(), se);
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+        }
+        return null;
+    }
+
+    /**
+     * Creates a new XPath without a namespace context.
+     * @return the new XPath.
+     */
+    public static final XPath newXPath() {
+        return newXPath(null, null);
+    }
+
+    /**
+     * Creates a new XPath with a given namespace context.
+     * @param namespaceContext The namespace context to be used or null
+     * if none should be used.
+     * @return The new XPath
+     */
+    public static final XPath newXPath(
+        NamespaceContext      namespaceContext,
+        XPathVariableResolver resolver)
+    {
+        XPathFactory factory = XPathFactory.newInstance();
+        XPath        xpath   = factory.newXPath();
+        if (namespaceContext != null) {
+            xpath.setNamespaceContext(namespaceContext);
+        }
+
+        if (resolver != null) {
+            xpath.setXPathVariableResolver(resolver);
+        }
+        return xpath;
+    }
+
+    /**
+     * Evaluates an XPath query on a given object and returns the result
+     * as a given type. No namespace context is used.
+     * @param root  The object which is used as the root of the tree to
+     * be searched in.
+     * @param query The XPath query
+     * @param returnTyp The type of the result.
+     * @return The result of type 'returnTyp' or null if something
+     * went wrong during XPath evaluation.
+     */
+    public static final Object xpath(
+        Object root,
+        String query,
+        QName  returnTyp
+    ) {
+        return xpath(root, query, returnTyp, null);
+    }
+
+    /**
+     * Evaluates an XPath query on a given object and returns the result
+     * as a string. A given namespace context is used.
+     * @param root  The object which is used as the root of the tree to
+     * be searched in.
+     * @param query The XPath query
+     * @param namespaceContext The namespace context to be used or null
+     * if none should be used.
+     * @return The result of the query or null if something went wrong
+     * during XPath evaluation.
+     */
+    public static final String xpathString(
+        Object root, String query, NamespaceContext namespaceContext
+    ) {
+        return (String)xpath(
+            root, query, XPathConstants.STRING, namespaceContext);
+    }
+
+    /**
+     * Evaluates an XPath query on a given object and returns the result
+     * as a given type. Optionally a namespace context is used.
+     * @param root The object which is used as the root of the tree to
+     * be searched in.
+     * @param query The XPath query
+     * @param returnType The type of the result.
+     * @param namespaceContext The namespace context to be used or null
+     * if none should be used.
+     * @return The result of type 'returnTyp' or null if something
+     * went wrong during XPath evaluation.
+     */
+    public static final Object xpath(
+        Object           root,
+        String           query,
+        QName            returnType,
+        NamespaceContext namespaceContext
+    ) {
+        return xpath(root, query, returnType, namespaceContext, null);
+    }
+
+    public static final Object xpath(
+        Object           root,
+        String           query,
+        QName            returnType,
+        NamespaceContext namespaceContext,
+        Map<String, String> variables)
+    {
+        if (root == null) {
+            return null;
+        }
+
+        XPathVariableResolver resolver = variables != null
+            ? new MapXPathVariableResolver(variables)
+            : null;
+
+        try {
+            XPath xpath = newXPath(namespaceContext, resolver);
+            if (xpath != null) {
+                return xpath.evaluate(query, root, returnType);
+            }
+        }
+        catch (XPathExpressionException xpee) {
+            logger.error(xpee.getLocalizedMessage(), xpee);
+        }
+
+        return null;
+    }
+
+    /**
+     * Streams out an XML document to a given output stream.
+     * @param document The document to be streamed out.
+     * @param out      The output stream to be used.
+     * @return true if operation succeeded else false.
+     */
+    public static boolean toStream(Document document, OutputStream out) {
+        try {
+            Transformer transformer =
+                TransformerFactory.newInstance().newTransformer();
+            DOMSource    source = new DOMSource(document);
+            StreamResult result = new StreamResult(out);
+            transformer.transform(source, result);
+            return true;
+        }
+        catch (TransformerConfigurationException tce) {
+            logger.error(tce.getLocalizedMessage(), tce);
+        }
+        catch (TransformerFactoryConfigurationError tfce) {
+            logger.error(tfce.getLocalizedMessage(), tfce);
+        }
+        catch (TransformerException te) {
+            logger.error(te.getLocalizedMessage(), te);
+        }
+
+        return false;
+    }
+
+    public static String toString(Document document) {
+        try {
+            Transformer transformer =
+                TransformerFactory.newInstance().newTransformer();
+            DOMSource    source = new DOMSource(document);
+            StringWriter out    = new StringWriter();
+            StreamResult result = new StreamResult(out);
+            transformer.transform(source, result);
+            out.flush();
+            return out.toString();
+        }
+        catch (TransformerConfigurationException tce) {
+            logger.error(tce.getLocalizedMessage(), tce);
+        }
+        catch (TransformerFactoryConfigurationError tfce) {
+            logger.error(tfce.getLocalizedMessage(), tfce);
+        }
+        catch (TransformerException te) {
+            logger.error(te.getLocalizedMessage(), te);
+        }
+
+        return null;
+    }
+
+    public static byte [] toByteArray(Document document) {
+        return toByteArray(document, false);
+    }
+
+    /**
+     * Transforms an XML document into a byte array.
+     * @param document The document to be streamed out.
+     * @param compress The document should be compressed, too.
+     * @return the byte array or null if operation failed or
+     * document is null.
+     */
+    public static byte [] toByteArray(Document document, boolean compress) {
+        if (document != null) {
+            try {
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                OutputStream out = compress
+                    ? new GZIPOutputStream(baos)
+                    : baos;
+                boolean success = toStream(document, out);
+                out.flush();
+                out.close();
+                return success
+                    ? baos.toByteArray()
+                    : null;
+            }
+            catch (IOException ioe) {
+                logger.error(ioe);
+            }
+        }
+        return null;
+    }
+
+    public static Document fromByteArray(byte [] data) {
+        return fromByteArray(data, false);
+    }
+
+    public static Document fromByteArray(byte [] data, boolean decompress) {
+        if (data != null) {
+            InputStream in = new ByteArrayInputStream(data);
+            try {
+                if (decompress) {
+                    in = new GZIPInputStream(in);
+                }
+                return parseDocument(in);
+            }
+            catch (IOException ioe) {
+                logger.error(ioe);
+            }
+            finally {
+                try {
+                    in.close();
+                }
+                catch (IOException ioe) {
+                    logger.error(ioe);
+                }
+            }
+        }
+        return null;
+    }
+
+    private static class BuildResult {
+        List<Node>          children;
+        Map<String, String> attributes;
+        BuildResult() {
+            children   = new ArrayList<Node>();
+            attributes = new LinkedHashMap<String, String>();
+        }
+
+        void setAttributes(Element element) {
+            for (Map.Entry<String, String> entry: attributes.entrySet()) {
+                element.setAttribute(entry.getKey(), entry.getValue());
+            }
+        }
+
+        void finish(Element element) {
+            setAttributes(element);
+            for (Node child: children) {
+                element.appendChild(child);
+            }
+        }
+
+        void add(Node node) {
+            children.add(node);
+        }
+
+        void add(String key, Object value) {
+            attributes.put(key, value != null ? value.toString() : "null");
+        }
+
+        int numChildren() {
+            return children.size();
+        }
+
+        Node firstChild() {
+            return children.get(0);
+        }
+    } // class BuildResult
+
+    private static BuildResult recursiveBuild(
+        List     list,
+        Document document
+    ) {
+        BuildResult result = new BuildResult();
+        for (Object entry: list) {
+            if (entry instanceof Map) {
+                BuildResult subResult = recursiveBuild(
+                    (Map<String, Object>)entry, document);
+                if (subResult.numChildren() == 1) {
+                    result.add(subResult.firstChild());
+                }
+                else {
+                    Element element = document.createElement("map");
+                    subResult.finish(element);
+                    result.add(element);
+                }
+            }
+            else if (entry instanceof List) {
+                Element element = document.createElement("list");
+                BuildResult subResult = recursiveBuild((List)entry, document);
+                subResult.finish(element);
+                result.add(element);
+            }
+            else {
+                Element element = document.createElement("entry");
+                element.setAttribute(
+                    "value",
+                    entry != null ? entry.toString() : "null");
+            }
+        }
+        return result;
+    }
+
+    private static BuildResult recursiveBuild(
+        Map<String, Object> map,
+        Document            document
+    ) {
+        BuildResult result = new BuildResult();
+
+        List<Node> nodes = new ArrayList<Node>();
+        for (Map.Entry<String, Object> entry: map.entrySet()) {
+            Object value = entry.getValue();
+            if (value instanceof Map) {
+                Element element = document.createElement(entry.getKey());
+                BuildResult subResult = recursiveBuild(
+                    (Map<String, Object>)value, document);
+                subResult.finish(element);
+                result.add(element);
+            }
+            else if (value instanceof List) {
+                Element element = document.createElement(entry.getKey());
+                BuildResult subResult = recursiveBuild((List)value, document);
+                subResult.finish(element);
+                result.add(element);
+            }
+            else {
+                result.add(entry.getKey(), value);
+            }
+        }
+        return result;
+    }
+
+    public static Document jsonToXML(String input) {
+        Document document = newDocument();
+
+        if (document == null) {
+            return null;
+        }
+
+        Map<String, Object> map;
+        try {
+            map = JSON.parse(input);
+        }
+        catch (IOException ioe) {
+            logger.error(ioe);
+            return null;
+        }
+
+        BuildResult roots = recursiveBuild(map, document);
+
+        int N = roots.children.size();
+
+        if (N == 1) {
+            document.appendChild(roots.children.get(0));
+        }
+        else if (N > 1) {
+            Node root = document.createElement("root");
+            for (int i = 0; i < N; ++i) {
+                root.appendChild(roots.children.get(i));
+            }
+            document.appendChild(root);
+        }
+
+        return document;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/XSLTransformer.java	Thu Apr 25 10:53:15 2013 +0200
@@ -0,0 +1,73 @@
+package de.intevation.artifacts.common.utils;
+
+import java.io.InputStream;
+import java.io.StringWriter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+
+import javax.xml.transform.dom.DOMSource;
+
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Node;
+
+public class XSLTransformer {
+
+    private static Logger log = Logger.getLogger(XSLTransformer.class);
+
+    protected Map<String, Object> parameters;
+
+    public XSLTransformer() {
+    }
+
+    public String transform(Node source, InputStream transform) {
+
+        try {
+            Source templateSource = new StreamSource(transform);
+            TransformerFactory xformFactory =
+                TransformerFactory.newInstance();
+            Transformer transformer =
+                xformFactory.newTransformer(templateSource);
+
+            if (parameters != null) {
+                for (Map.Entry<String, Object> entry: parameters.entrySet()) {
+                    transformer.setParameter(entry.getKey(), entry.getValue());
+                }
+            }
+
+            StringWriter result = new StringWriter();
+
+            DOMSource    src = new DOMSource(source);
+            StreamResult dst = new StreamResult(result);
+            transformer.transform(src, dst);
+
+            return result.toString();
+        }
+        catch (TransformerConfigurationException tce) {
+            log.error(tce, tce);
+        }
+        catch (TransformerException te) {
+            log.error(te, te);
+        }
+
+        return null;
+    }
+
+    public void addParameter(String key, Object value) {
+        if (parameters == null) {
+            parameters = new HashMap<String, Object>();
+        }
+        parameters.put(key, value);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org