[Dive4elements-commits] [PATCH 3 of 4] Moved directories to org.dive4elements

Wald Commits scm-commit at wald.intevation.org
Thu Apr 25 11:08:52 CEST 2013


# HG changeset patch
# User Sascha L. Teichmann <teichmann at intevation.de>
# Date 1366880238 -7200
# Node ID d0ac790a6c89e32f2b68b640da0b6e1c985bb703
# Parent  783cc1b6b615f3c6d7dadc0bee54bec7fff1c02c
Moved directories to org.dive4elements

diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +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.artifactdatabase;
-
-import org.apache.log4j.Logger;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.DataProvider;
-
-
-/**
- * Abstract class that implements some basic methods of a CallContext.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public abstract class AbstractCallContext implements CallContext {
-
-    Logger logger = Logger.getLogger(AbstractCallContext.class);
-
-    /**
-     * The ArtifactDatabase instance.
-     */
-    protected ArtifactDatabaseImpl database;
-
-    /**
-     * The action to be performed after the artifacts or collections calls.
-     */
-    protected int action;
-
-    /**
-     * The meta information of the concrete call (preferred languages et. al.)
-     */
-    protected CallMeta callMeta;
-
-    /**
-     * Map to act like a clipboard when nesting calls like a proxy artifact.
-     */
-    protected Map customValues;
-
-    /**
-     * Map to act like a clipboard when nesting calls like a proxy artifact.
-     */
-    protected Map<Object, List<DataProvider>> dataProviders;
-
-
-    /**
-     * The default constructor of this abstract CallContext.
-     *
-     * @param artifactDatabase The artifact database.
-     * @param action The action.
-     * @param callMeta The CallMeta object.
-     */
-    public AbstractCallContext(
-        ArtifactDatabaseImpl artifactDatabase,
-        int                  action,
-        CallMeta             callMeta
-    ) {
-        this.database = artifactDatabase;
-        this.action   = action;
-        this.callMeta = callMeta;
-
-        database.initCallContext(this);
-    }
-
-
-    public void postCall() {
-        database.closeCallContext(this);
-    }
-
-    public abstract void afterCall(int action);
-
-    public abstract Long getTimeToLive();
-
-    public abstract void afterBackground(int action);
-
-
-    public Object globalContext() {
-        return database.context;
-    }
-
-
-    public ArtifactDatabase getDatabase() {
-        return database;
-    }
-
-
-    public CallMeta getMeta() {
-        return callMeta;
-    }
-
-
-    public Object getContextValue(Object key) {
-        return customValues != null
-            ? customValues.get(key)
-            : null;
-    }
-
-    public Object putContextValue(Object key, Object value) {
-        if (customValues == null) {
-            customValues = new HashMap();
-        }
-        return customValues.put(key, value);
-    }
-
-    /**
-     * Get list of DataProviders that registered for given key.
-     * @return list (empty list if none found, never null).
-     */
-    public List<DataProvider> getDataProvider(Object key) {
-        if (dataProviders != null) {
-            List<DataProvider> list = dataProviders.get(key);
-            return list != null
-                ? list
-                : java.util.Collections.<DataProvider>emptyList();
-        }
-        return java.util.Collections.<DataProvider>emptyList();
-    }
-
-
-    /**
-     * Let a DataProvider register itself with given key.
-     * Multiple DataProvider can register under the same key.
-     */
-    public Object registerDataProvider(Object key, DataProvider value) {
-        List<DataProvider> providers = null;
-        if (dataProviders == null) {
-            dataProviders = new HashMap();
-            providers = new ArrayList<DataProvider>();
-            providers.add(value);
-            return dataProviders.put(key, providers);
-        }
-        providers = dataProviders.get(key);
-
-        if (providers == null) {
-            providers = new ArrayList<DataProvider>();
-        }
-        providers.add(value);
-        return dataProviders.put(key, providers);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/App.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/App.java	Thu Apr 25 10:53:15 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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import de.intevation.artifactdatabase.rest.HTTPServer;
-
-import java.io.File;
-
-import java.net.MalformedURLException;
-
-import org.apache.log4j.PropertyConfigurator;
-
-import org.slf4j.bridge.SLF4JBridgeHandler;
-
-/**
- * Starting point of the artifact database.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class App
-{
-    /**
-     * The logging is done via Log4j. To configure the logging
-     * a file 'log4j.properties' is search in the configuration directory.
-     */
-    public static final String LOG4J_PROPERTIES =
-        "log4j.properties";
-
-    /**
-     * Trys to load the Log4j configuration from ${config.dir}/log4j.properties.
-     */
-    public static final void configureLogging() {
-        File configDir = Config.getConfigDirectory();
-        File propFile = new File(configDir, LOG4J_PROPERTIES);
-
-        if (propFile.isFile() && propFile.canRead()) {
-            try {
-                PropertyConfigurator.configure(propFile.toURI().toURL());
-                SLF4JBridgeHandler.install();
-            }
-            catch (MalformedURLException mue) {
-                mue.printStackTrace(System.err);
-            }
-        }
-    }
-
-    /**
-     * Starts the artifact database.
-     * @param args The commandline arguments. Unused.
-     */
-    public static void main(String[] args) {
-
-        configureLogging();
-
-        FactoryBootstrap bootstrap = new FactoryBootstrap();
-
-        bootstrap.boot();
-
-        Backend backend = Backend.getInstance();
-
-        ArtifactDatabaseImpl db = new ArtifactDatabaseImpl(
-            bootstrap, backend);
-
-        DatabaseCleaner cleaner = new DatabaseCleaner(
-            bootstrap.getContext(), backend, backend.getConfig());
-
-        HTTPServer httpServer = bootstrap.getHTTPServer();
-
-        bootstrap = null;
-
-        backend.setCleaner(cleaner);
-
-        cleaner.setLockedIdsProvider(db);
-
-        cleaner.start();
-
-        db.start();
-
-        httpServer.startAsServer(db);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactCallContext.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactCallContext.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +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.artifactdatabase;
-
-import java.util.LinkedList;
-
-import org.apache.log4j.Logger;
-
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.Message;
-
-import de.intevation.artifactdatabase.Backend.PersistentArtifact;
-
-
-/**
- * Class that implements the call context handed to the methods calls
- * describe(), feed(), etc. of the artifact.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class ArtifactCallContext extends AbstractCallContext {
-
-    private static Logger logger = Logger.getLogger(ArtifactCallContext.class);
-
-
-    /**
-     * Error message issued if an artifact wants to translate itself
-     * into a none valid persistent state.
-     */
-    public static final String INVALID_CALL_STATE = "Invalid after call state";
-
-    /**
-     * Error message issued if one tries to remove a requested artifact
-     * from the list of artifacts running in background which is
-     * not in this list.
-     */
-    public static final String NOT_IN_BACKGROUND = "Not in background";
-
-
-    /**
-     * The persistence wrapper around the living artifact
-     */
-    protected PersistentArtifact artifact;
-
-
-    public ArtifactCallContext(
-        ArtifactDatabaseImpl artifactDatabase,
-        int                  action,
-        CallMeta             callMeta,
-        PersistentArtifact   artifact)
-    {
-        super(artifactDatabase, action, callMeta);
-
-        this.artifact = artifact;
-    }
-
-
-    public void afterCall(int action) {
-        this.action = action;
-        if (action == BACKGROUND) {
-            database.addIdToBackground(artifact.getId());
-        }
-    }
-
-
-    public void afterBackground(int action) {
-        if (this.action != BACKGROUND) {
-            throw new IllegalStateException(NOT_IN_BACKGROUND);
-        }
-        database.fromBackground(artifact, action);
-    }
-
-
-    public boolean isInBackground() {
-        return database.getLockedIds().contains(artifact.getId());
-    }
-
-
-    public void addBackgroundMessage(Message msg) {
-        database.addBackgroundMessage(artifact.getArtifact().identifier(), msg);
-    }
-
-
-    public LinkedList<Message> getBackgroundMessages() {
-        return database.getBackgroundMessages(
-            artifact.getArtifact().identifier());
-    }
-
-
-    public Long getTimeToLive() {
-        return artifact.getTTL();
-    }
-
-
-    /**
-     * Dispatches and executes the persistence action after
-     * the return of the concrete artifact call.
-     */
-    public void postCall() {
-        try {
-            switch (action) {
-                case NOTHING:
-                    break;
-                case TOUCH:
-                    artifact.touch();
-                    break;
-                case STORE:
-                    artifact.store();
-                    break;
-                case BACKGROUND:
-                    logger.warn(
-                        "BACKGROUND processing is not fully implemented, yet!");
-                    artifact.store();
-                    break;
-                default:
-                    logger.error(INVALID_CALL_STATE + ": " + action);
-                    throw new IllegalStateException(INVALID_CALL_STATE);
-            }
-        }
-        finally {
-            super.postCall();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1976 +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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-import de.intevation.artifacts.common.utils.StringUtils;
-
-import de.intevation.artifactdatabase.Backend.PersistentArtifact;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactCollection;
-import de.intevation.artifacts.ArtifactCollectionFactory;
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.ArtifactSerializer;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.CollectionItem;
-import de.intevation.artifacts.GlobalContext;
-import de.intevation.artifacts.Hook;
-import de.intevation.artifacts.Message;
-import de.intevation.artifacts.Service;
-import de.intevation.artifacts.ServiceFactory;
-import de.intevation.artifacts.User;
-import de.intevation.artifacts.UserFactory;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.xml.xpath.XPathConstants;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-/**
- * The core implementation of artifact database. This layer exposes
- * the needed methods to the artifact runtime system which e.g. may
- * expose them via REST. The concrete persistent representation of the
- * artifacts is handled by the {@link Backend backend}.
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class ArtifactDatabaseImpl
-implements   ArtifactDatabase,
-             DatabaseCleaner.LockedIdsProvider,
-             Backend.FactoryLookup
-{
-    private static Logger logger =
-        Logger.getLogger(ArtifactDatabaseImpl.class);
-
-    /** The key under which the artifact database is stored in the global
-     * context.*/
-    public static final String GLOBAL_CONTEXT_KEY = "global.artifact.database";
-
-    /** Message that is returned if an operation was successful.*/
-    public static final String OPERATION_SUCCESSFUL =
-        "SUCCESS";
-
-    /** Message that is returned if an operation failed.*/
-    public static final String OPERATION_FAILURE =
-        "FAILURE";
-
-    /**
-     * Error message issued if a requested artifact factory
-     * is not registered to this database.
-     */
-    public static final String NO_SUCH_FACTORY =
-        "No such factory";
-
-    /**
-     * Error message issued if a requested artifact is not found
-     * in this database.
-     */
-    public static final String NO_SUCH_ARTIFACT =
-        "No such artifact";
-
-    /**
-     * Error message issued if a requested artifact is not found
-     * in this database.
-     */
-    public static final String NO_SUCH_COLLECTION =
-        "No such collection";
-
-    /**
-     * Error message issued if the creation of an artifact failed.
-     */
-    public static final String CREATION_FAILED =
-        "Creation of artifact failed";
-
-    /**
-     * Error message if an severe internal error occurred.
-     */
-    public static final String INTERNAL_ERROR =
-        "Creation of artifact failed";
-
-    /**
-     * Error message issued if a requested service is not
-     * offered by this database.
-     */
-    public static final String NO_SUCH_SERVICE =
-        "No such service";
-
-    /**
-     * Default digest hash to be used while im-/exporting artifacts.
-     */
-    public static final String DIGEST_ALGORITHM =
-        "SHA-1";
-
-    /**
-     * XPath to get the checksum from an XML representation of
-     * an exported artifact.
-     */
-    public static final String XPATH_IMPORT_CHECKSUM =
-        "/art:action/art:data/@checksum";
-
-    /**
-     * XPath to get the name of the factory which should be
-     * used to revive an antrifact that is going to be imported.
-     */
-    public static final String XPATH_IMPORT_FACTORY =
-        "/art:action/art:data/@factory";
-
-    /**
-     * XPath to get the base64 encoded data of an artifact
-     * that is going to be imported.
-     */
-    public static final String XPATH_IMPORT_DATA =
-        "/art:action/art:data/text()";
-
-    /**
-     * Error message issued if the checksum of an
-     * artifact to be imported has an invalid syntax.
-     */
-    public static final String INVALID_CHECKSUM =
-        "Invalid checksum";
-
-    /**
-     * Error message issued the checksum validation
-     * of an artifact to be imported fails.
-     */
-    public static final String CHECKSUM_MISMATCH =
-        "Mismatching checksum";
-
-    /**
-     * Error message issued if an artifact to be imported
-     * does not have any data.
-     */
-    public static final String NO_DATA =
-        "No data";
-
-    /**
-     * Error message issued if the deserialization of
-     * an artifact to be imported fails.
-     */
-    public static final String INVALID_ARTIFACT =
-        "Invalid artifact";
-
-
-    // User constants
-
-    /**
-     * Error message issued if the creation of a user failed.
-     */
-    public static final String USER_CREATION_FAILED =
-        "Creation of user failed.";
-
-    /** XPath to figure out the name of a new user.*/
-    public static final String XPATH_USERNAME =
-        "/art:action/art:user/@name";
-
-    /** XPath to figure out the role of a new user.*/
-    public static final String XPATH_USERROLE =
-        "/art:action/art:user/art:role";
-
-    /** XPath to figure out the account of a new user.*/
-    public static final String XPATH_USERACCOUNT =
-        "/art:action/art:user/art:account/@name";
-
-    /** XPath to figure out the account of when searching for a user .*/
-    public static final String XPATH_USERACCOUNT_FIND =
-        "/art:action/art:account/@name";
-
-    /** Error message if a specified user does not exist.*/
-    public static final String NO_SUCH_USER =
-        "No such user";
-
-    /** Error message if no username is given for user creation.*/
-    public static final String NO_USERNAME =
-        "Invalid username";
-
-    /** Error message if no user account is given for user creation.*/
-    public static final String NO_USERACCOUNT =
-        "Invalid user account name";
-
-    // Collection constants
-
-    /**
-     * Error message issued if the creation of a collection failed.
-     */
-    public static final String COLLECTION_CREATION_FAILED =
-        "Creation of collection failed";
-
-    /**
-     * XPath to figure out the name of a collection described in the incoming
-     * document.
-     */
-    public static final String XPATH_COLLECTION_NAME =
-        "/art:action/art:type/art:collection/@name";
-
-    /**
-     * XPath to figure out the attributes for a collection.
-     */
-    public static final String XPATH_COLLECTION_ATTRIBUTE =
-        "/art:action/art:type/art:collection/art:attribute";
-
-    /**
-     * XPath to figure out the attributes for an artifact that is put into a
-     * collection.
-     */
-    public static final String XPATH_COLLECTION_ITEM_ATTRIBUTE =
-        "/art:action/art:type/art:artifact/art:attribute";
-
-    /**
-     * XPath to figure out the time to live value for setting a new TTL.
-     */
-    public static final String XPATH_COLLECTION_TTL =
-        "/art:action/art:type/art:ttl/@value";
-
-
-    /**
-     * This inner class allows the deferral of writing the output
-     * of the artifact's out() call.
-     */
-    public class DeferredOutputImpl
-    implements   DeferredOutput
-    {
-        /**
-         * The persistence wrapper around a living artifact.
-         */
-        protected PersistentArtifact artifact;
-        /**
-         * The output type.
-         */
-        protected String type;
-        /**
-         * The input document for the artifact's out() call.
-         */
-        protected Document           format;
-        /**
-         * The meta information of the artifact's out() call.
-         */
-        protected CallMeta           callMeta;
-
-        /**
-         * Default constructor.
-         */
-        public DeferredOutputImpl() {
-        }
-
-        /**
-         * Constructor to create a deferred execution unit for
-         * the artifact's out() call given an artifact, an input document
-         * an the meta information.
-         * @param artifact The persistence wrapper around a living artifact.
-         * @param format   The input document for the artifact's out() call.
-         * @param callMeta The meta information of the artifact's out() call.
-         */
-        public DeferredOutputImpl(
-            PersistentArtifact artifact,
-            String             type,
-            Document           format,
-            CallMeta           callMeta
-        ) {
-            this.artifact = artifact;
-            this.type     = type;
-            this.format   = format;
-            this.callMeta = callMeta;
-        }
-
-        public void write(OutputStream output) throws IOException {
-
-            ArtifactCallContext cc = new ArtifactCallContext(
-                ArtifactDatabaseImpl.this,
-                CallContext.TOUCH,
-                callMeta,
-                artifact);
-
-            try {
-                artifact.getArtifact().out(type, format, output, cc);
-            }
-            finally {
-                cc.postCall();
-            }
-        }
-    } // class DeferredOutputImpl
-
-
-    /**
-     * This inner class allows the deferral of writing the output
-     * of the artifact's out() call.
-     */
-    public class DeferredCollectionOutputImpl
-    implements   DeferredOutput
-    {
-        /**
-         * The persistence wrapper around a living collection.
-         */
-        protected ArtifactCollection collection;
-        /**
-         * The output type.
-         */
-        protected String type;
-        /**
-         * The input document for the collection's out() call.
-         */
-        protected Document format;
-        /**
-         * The meta information of the collection's out() call.
-         */
-        protected CallMeta callMeta;
-
-        /**
-         * Default constructor.
-         */
-        public DeferredCollectionOutputImpl() {
-        }
-
-        /**
-         * Constructor to create a deferred execution unit for
-         * the collection's out() call given a collection, an input document
-         * an the meta information.
-         * @param collection The collection.
-         * @param format   The input document for the collection's out() call.
-         * @param callMeta The meta information of the collection's out() call.
-         */
-        public DeferredCollectionOutputImpl(
-            ArtifactCollection collection,
-            String             type,
-            Document           format,
-            CallMeta           callMeta
-        ) {
-            this.collection = collection;
-            this.type       = type;
-            this.format     = format;
-            this.callMeta   = callMeta;
-        }
-
-        public void write(OutputStream output) throws IOException {
-
-            CollectionCallContext cc = new CollectionCallContext(
-                ArtifactDatabaseImpl.this,
-                CallContext.TOUCH,
-                callMeta,
-                collection);
-
-            try {
-                collection.out(type, format, output, cc);
-            }
-            finally {
-                cc.postCall();
-            }
-        }
-    } // class DeferredCollectionOutputImpl
-
-    /**
-     * List of name/description pairs needed for
-     * {@link #artifactFactoryNamesAndDescriptions() }.
-     */
-    protected String [][] factoryNamesAndDescription;
-    /**
-     * Map to access artifact factories by there name.
-     */
-    protected HashMap     name2factory;
-
-    /**
-     * List of name/description pairs needed for
-     * {@link #serviceNamesAndDescriptions() }.
-     */
-    protected String [][] serviceNamesAndDescription;
-    /**
-     * Map to access services by there name.
-     */
-    protected HashMap     name2service;
-
-    /**
-     * The factory that is used to create new artifact collections.
-     */
-    protected ArtifactCollectionFactory collectionFactory;
-
-    /**
-     * The factory that is used to create and list users.
-     */
-    protected UserFactory userFactory;
-
-    /**
-     * Reference to the storage backend.
-     */
-    protected Backend     backend;
-    /**
-     * Reference of the global context of the artifact runtime system.
-     */
-    protected GlobalContext context;
-
-    /**
-     * The signing secret to be used for ex-/importing artifacts.
-     */
-    protected byte []     exportSecret;
-
-    /**
-     * A set of ids of artifact which currently running in background.
-     * This artifacts should not be removed from the database by the
-     * database cleaner.
-     */
-    protected HashSet<Integer> backgroundIds;
-
-    /**
-     * A list of background messages for Artifacts and Collections.
-     */
-    protected Map<String, LinkedList<Message>> backgroundMsgs;
-
-
-    protected CallContext.Listener callContextListener;
-
-    /**
-     * Hooks that are executed after an artifact has been fed.
-     */
-    protected List<Hook> postFeedHooks;
-
-    /**
-     * Hooks that are executed after an artifact has advanced.
-     */
-    protected List<Hook> postAdvanceHooks;
-
-    /**
-     * Hooks that are executed after an artifact's describe() operation was
-     * called.
-     */
-    protected List<Hook> postDescribeHooks;
-
-    protected List<LifetimeListener> lifetimeListeners;
-
-    /**
-     * Default constructor.
-     */
-    public ArtifactDatabaseImpl() {
-    }
-
-    /**
-     * Constructor to create a artifact database with the given
-     * bootstrap parameters like artifact- and service factories et. al.
-     * Created this way the artifact database has no backend.
-     * @param bootstrap The parameters to start this artifact database.
-     */
-    public ArtifactDatabaseImpl(FactoryBootstrap bootstrap) {
-        this(bootstrap, null);
-    }
-
-    /**
-     * Constructor to create a artifact database with the a given
-     * backend and
-     * bootstrap parameters like artifact- and service factories et. al.
-     * @param bootstrap The parameters to start this artifact database.
-     * @param backend   The storage backend.
-     */
-    public ArtifactDatabaseImpl(FactoryBootstrap bootstrap, Backend backend) {
-
-        logger.debug("new ArtifactDatabaseImpl");
-
-        backgroundIds  = new HashSet<Integer>();
-        backgroundMsgs = new HashMap<String, LinkedList<Message>>();
-
-        setupArtifactCollectionFactory(bootstrap);
-        setupArtifactFactories(bootstrap);
-        setupServices(bootstrap);
-        setupUserFactory(bootstrap);
-        setupCallContextListener(bootstrap);
-        setupHooks(bootstrap);
-        setupLifetimeListeners(bootstrap);
-
-        context = bootstrap.getContext();
-        context.put(GLOBAL_CONTEXT_KEY, this);
-
-        exportSecret = bootstrap.getExportSecret();
-
-        wireWithBackend(backend, bootstrap);
-    }
-
-    public CallContext.Listener getCallContextListener() {
-        return callContextListener;
-    }
-
-    public void setCallContextListener(
-        CallContext.Listener callContextListener
-    ) {
-        this.callContextListener = callContextListener;
-    }
-
-
-    public void setPostFeedHook(List<Hook> postFeedHooks) {
-        this.postFeedHooks = postFeedHooks;
-    }
-
-    public void setPostAdvanceHook(List<Hook> postAdvanceHooks) {
-        this.postAdvanceHooks = postAdvanceHooks;
-    }
-
-    public void setPostDescribeHook(List<Hook> postDescribeHooks) {
-        this.postDescribeHooks = postDescribeHooks;
-    }
-
-    /**
-     * Used to extract the artifact collection factory from bootstrap.
-     *
-     * @param bootstrap The bootstrap parameters.
-     */
-    protected void setupArtifactCollectionFactory(FactoryBootstrap bootstrap) {
-        collectionFactory = bootstrap.getArtifactCollectionFactory();
-    }
-
-    /**
-     * Used to extract the artifact factories from the bootstrap
-     * parameters and building the internal lookup tables.
-     * @param bootstrap The bootstrap parameters.
-     */
-    protected void setupArtifactFactories(FactoryBootstrap bootstrap) {
-        name2factory  = new HashMap();
-
-        ArtifactFactory [] factories = bootstrap.getArtifactFactories();
-        factoryNamesAndDescription = new String[factories.length][];
-
-        for (int i = 0; i < factories.length; ++i) {
-
-            ArtifactFactory factory = factories[i];
-
-            String name        = factory.getName();
-            String description = factory.getDescription();
-
-            factoryNamesAndDescription[i] =
-                new String [] { name, description };
-
-            name2factory.put(name, factory);
-        }
-    }
-
-    /**
-     * Used to extract the callContextListener from the bootstrap.
-     *
-     * @param bootstrap The bootstrap parameters.
-     */
-    protected void setupCallContextListener(FactoryBootstrap bootstrap) {
-        setCallContextListener(bootstrap.getCallContextListener());
-    }
-
-
-    protected void setupHooks(FactoryBootstrap bootstrap) {
-        setPostFeedHook(bootstrap.getPostFeedHooks());
-        setPostAdvanceHook(bootstrap.getPostAdvanceHooks());
-        setPostDescribeHook(bootstrap.getPostDescribeHooks());
-    }
-
-    protected void setupBackendListeners(FactoryBootstrap bootstrap) {
-        logger.debug("setupBackendListeners");
-        List<BackendListener> bls = bootstrap.getBackendListeners();
-        if (bls != null && !bls.isEmpty()) {
-            for (BackendListener listener: bls) {
-                listener.setup(context);
-            }
-            backend.addAllListeners(bls);
-        }
-    }
-
-    protected void setupLifetimeListeners(FactoryBootstrap bootstrap) {
-        this.lifetimeListeners = bootstrap.getLifetimeListeners();
-    }
-
-    /**
-     * Used to extract the user factory from the bootstrap.
-     */
-    protected void setupUserFactory(FactoryBootstrap bootstrap) {
-        userFactory = bootstrap.getUserFactory();
-    }
-
-    /**
-     * Used to extract the service factories from the bootstrap
-     * parameters, setting up the services and building the internal
-     * lookup tables.
-     * @param bootstrap The bootstrap parameters.
-     */
-    protected void setupServices(FactoryBootstrap bootstrap) {
-
-        name2service  = new HashMap();
-
-        ServiceFactory [] serviceFactories =
-            bootstrap.getServiceFactories();
-
-        serviceNamesAndDescription =
-            new String[serviceFactories.length][];
-
-        for (int i = 0; i < serviceFactories.length; ++i) {
-            ServiceFactory factory = serviceFactories[i];
-
-            String name        = factory.getName();
-            String description = factory.getDescription();
-
-            serviceNamesAndDescription[i] =
-                new String [] { name, description };
-
-            name2service.put(
-                name,
-                factory.createService(bootstrap.getContext()));
-        }
-
-    }
-
-    /**
-     * Wires a storage backend to this artifact database and
-     * establishes a callback to be able to revive artifacts
-     * via the serializers of this artifact factories.
-     * @param backend The backend to be wired with this artifact database.
-     */
-    public void wireWithBackend(Backend backend, FactoryBootstrap bootstrap) {
-        logger.debug("wireWithBackend");
-        if (backend != null) {
-            this.backend = backend;
-            backend.setFactoryLookup(this);
-            setupBackendListeners(bootstrap);
-        }
-    }
-
-    /**
-     * Called after an backgrounded artifact signals its
-     * will to be written back to the backend.
-     * @param artifact The persistence wrapper around
-     * the backgrounded artifact.
-     * @param action The action to be performed.
-     */
-    protected void fromBackground(PersistentArtifact artifact, int action) {
-        logger.warn("BACKGROUND processing is not fully implemented, yet!");
-        switch (action) {
-            case CallContext.NOTHING:
-                break;
-            case CallContext.TOUCH:
-                artifact.touch();
-                break;
-            case CallContext.STORE:
-                artifact.store();
-                break;
-            default:
-                logger.warn("operation not allowed in fromBackground");
-        }
-        removeIdFromBackground(artifact.getId());
-        removeBackgroundMessages(artifact.getArtifact().identifier());
-    }
-
-    /**
-     * Removes an artifact's database id from the set of backgrounded
-     * artifacts. The database cleaner is now able to remove it safely
-     * from the database again.
-     * @param id The database id of the artifact.
-     */
-    protected void removeIdFromBackground(int id) {
-        synchronized (backgroundIds) {
-            backgroundIds.remove(id);
-        }
-    }
-
-
-    /**
-     * Removes all messages that have been added to the <i>backgroundMsgs</i>
-     * list.
-     *
-     * @param uuid The UUID of an artifact or collection.
-     */
-    protected void removeBackgroundMessages(String uuid) {
-        logger.debug("Remove background messages for: " + uuid);
-
-        synchronized (backgroundMsgs) {
-            backgroundMsgs.remove(uuid);
-        }
-    }
-
-    /**
-     * Adds an artifact's database id to the set of artifacts
-     * running in backgroound. To be in this set prevents the
-     * artifact to be removed from the database by the database cleaner.
-     * @param id The database id of the artifact to be protected
-     * from being removed from the database.
-     */
-    protected void addIdToBackground(int id) {
-        synchronized (backgroundIds) {
-            backgroundIds.add(Integer.valueOf(id));
-        }
-    }
-
-    /**
-     * Adds a <i>Message</i> to the background messages list of the Artifact or
-     * Collection.
-     *
-     * @param uuid The UUID of the Artifact or Collection.
-     * @param msg The message that should be added to the background messages
-     * list.
-     */
-    public void addBackgroundMessage(String uuid, Message msg) {
-        logger.debug("Add new background messsage for: " + uuid);
-
-        synchronized (backgroundMsgs) {
-            LinkedList<Message> messages = backgroundMsgs.get(uuid);
-
-            if (messages == null) {
-                messages = new LinkedList<Message>();
-                backgroundMsgs.put(uuid, messages);
-            }
-
-            messages.addLast(msg);
-        }
-    }
-
-    public Set<Integer> getLockedIds() {
-        synchronized (backgroundIds) {
-            return new HashSet<Integer>(backgroundIds);
-        }
-    }
-
-    /**
-     * Returns the background <i>Message</i>s for a specific Artifact or
-     * Collection.
-     *
-     * @param uuid The Artifact's or Collection's UUID.
-     *
-     * @return a <i>List</i> of <i>Message</i>s or null if no messages are
-     * existing.
-     */
-    public LinkedList<Message> getBackgroundMessages(String uuid) {
-        logger.debug("Retrieve background message for: " + uuid);
-
-        synchronized (backgroundMsgs) {
-            return backgroundMsgs.get(uuid);
-        }
-    }
-
-    public String [][] artifactFactoryNamesAndDescriptions() {
-        return factoryNamesAndDescription;
-    }
-
-    public ArtifactFactory getInternalArtifactFactory(String factoryName) {
-        return getArtifactFactory(factoryName);
-    }
-
-    public ArtifactFactory getArtifactFactory(String factoryName) {
-        return (ArtifactFactory)name2factory.get(factoryName);
-    }
-
-    public UserFactory getUserFactory() {
-        return userFactory;
-    }
-
-    public ArtifactCollectionFactory getArtifactCollectionFactory() {
-        return collectionFactory;
-    }
-
-    public Document createArtifactWithFactory(
-        String   factoryName,
-        CallMeta callMeta,
-        Document data
-    )
-    throws ArtifactDatabaseException
-    {
-        logger.debug("ArtifactDatabaseImpl.createArtifactWithFactory "
-             + factoryName);
-        ArtifactFactory factory = getArtifactFactory(factoryName);
-
-        if (factory == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        Artifact artifact = factory.createArtifact(
-            backend.newIdentifier(),
-            context,
-            callMeta,
-            data);
-
-        if (artifact == null) {
-            throw new ArtifactDatabaseException(CREATION_FAILED);
-        }
-
-        PersistentArtifact persistentArtifact;
-
-        try {
-            persistentArtifact = backend.storeInitially(
-                artifact,
-                factory,
-                factory.timeToLiveUntouched(artifact, context));
-        }
-        catch (Exception e) {
-            logger.error(e.getLocalizedMessage(), e);
-            throw new ArtifactDatabaseException(CREATION_FAILED);
-        }
-
-        ArtifactCallContext cc = new ArtifactCallContext(
-            ArtifactDatabaseImpl.this,
-            CallContext.NOTHING,
-            callMeta,
-            persistentArtifact);
-
-        try {
-            return artifact.describe(null, cc);
-        }
-        finally {
-            cc.postCall();
-        }
-    }
-
-
-    public Artifact getRawArtifact(String identifier)
-    throws ArtifactDatabaseException
-    {
-        PersistentArtifact artifact = backend.getArtifact(identifier);
-
-        if (artifact == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
-        }
-
-        return artifact.getArtifact();
-    }
-
-
-    public Document describe(
-        String   identifier,
-        Document data,
-        CallMeta callMeta
-    )
-    throws ArtifactDatabaseException
-    {
-        // TODO: Handle background tasks
-        PersistentArtifact artifact = backend.getArtifact(identifier);
-
-        if (artifact == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
-        }
-
-        ArtifactCallContext cc = new ArtifactCallContext(
-            ArtifactDatabaseImpl.this,
-            CallContext.TOUCH,
-            callMeta,
-            artifact);
-
-        try {
-            Artifact art = artifact.getArtifact();
-            Document res = art.describe(data, cc);
-
-            if (postDescribeHooks != null) {
-                for (Hook hook: postDescribeHooks) {
-                    hook.execute(art, cc, res);
-                }
-            }
-
-            return res;
-        }
-        finally {
-            cc.postCall();
-        }
-    }
-
-    public Document advance(
-        String   identifier,
-        Document target,
-        CallMeta callMeta
-    )
-    throws ArtifactDatabaseException
-    {
-        // TODO: Handle background tasks
-        PersistentArtifact artifact = backend.getArtifact(identifier);
-
-        if (artifact == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
-        }
-
-        ArtifactCallContext cc = new ArtifactCallContext(
-            ArtifactDatabaseImpl.this,
-            CallContext.STORE,
-            callMeta,
-            artifact);
-
-        try {
-            Artifact art = artifact.getArtifact();
-            Document res = art.advance(target, cc);
-
-            if (postAdvanceHooks != null) {
-                for (Hook hook: postAdvanceHooks) {
-                    hook.execute(art, cc, res);
-                }
-            }
-
-            return res;
-        }
-        finally {
-            cc.postCall();
-        }
-    }
-
-    public Document feed(String identifier, Document data, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        // TODO: Handle background tasks
-        PersistentArtifact artifact = backend.getArtifact(identifier);
-
-        if (artifact == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
-        }
-
-        ArtifactCallContext cc = new ArtifactCallContext(
-            ArtifactDatabaseImpl.this,
-            CallContext.STORE,
-            callMeta,
-            artifact);
-
-        try {
-            Artifact art = artifact.getArtifact();
-            Document res = art.feed(data, cc);
-
-            if (postFeedHooks != null) {
-                for (Hook hook: postFeedHooks) {
-                    hook.execute(art, cc, res);
-                }
-            }
-
-            return res;
-        }
-        finally {
-            cc.postCall();
-        }
-    }
-
-    public DeferredOutput out(
-        String   identifier,
-        Document format,
-        CallMeta callMeta)
-    throws ArtifactDatabaseException
-    {
-        return out(identifier, null, format, callMeta);
-    }
-
-    public DeferredOutput out(
-        String   identifier,
-        String   type,
-        Document format,
-        CallMeta callMeta
-    )
-    throws ArtifactDatabaseException
-    {
-        // TODO: Handle background tasks
-        PersistentArtifact artifact = backend.getArtifact(identifier);
-
-        if (artifact == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
-        }
-
-        return new DeferredOutputImpl(artifact, type, format, callMeta);
-    }
-
-    public Document exportArtifact(String artifact, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        final String [] factoryName = new String[1];
-
-        byte [] bytes = (byte [])backend.loadArtifact(
-            artifact,
-            new Backend.ArtifactLoader() {
-                public Object load(
-                    ArtifactFactory factory,
-                    Long            ttl,
-                    byte []         bytes,
-                    int             id
-                ) {
-                    factoryName[0] = factory.getName();
-
-                    ArtifactSerializer serializer = factory.getSerializer();
-
-                    Artifact artifact = serializer.fromBytes(bytes);
-                    artifact.cleanup(context);
-
-                    return serializer.toBytes(artifact);
-                }
-            });
-
-        if (bytes == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
-        }
-
-        return createExportDocument(
-            factoryName[0],
-            bytes,
-            exportSecret);
-    }
-
-    /**
-     * Creates an exteral XML representation of an artifact.
-     * @param factoryName The name of the factory which is responsible
-     * for the serialized artifact.
-     * @param artifact The byte data of the artifact itself.
-     * @param secret   The signing secret.
-     * @return An XML document containing the external representation
-     * of the artifact.
-     */
-    protected static Document createExportDocument(
-        String  factoryName,
-        byte [] artifact,
-        byte [] secret
-    ) {
-        Document document = XMLUtils.newDocument();
-
-        MessageDigest md;
-        try {
-            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
-        }
-        catch (NoSuchAlgorithmException nsae) {
-            logger.error(nsae.getLocalizedMessage(), nsae);
-            return document;
-        }
-
-        md.update(artifact);
-        md.update(secret);
-
-        String checksum = Hex.encodeHexString(md.digest());
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            document,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("action");
-        document.appendChild(root);
-
-        Element type = ec.create("type");
-        ec.addAttr(type, "name", "export", true);
-        root.appendChild(type);
-
-        Element data = ec.create("data");
-        ec.addAttr(data, "checksum", checksum, true);
-        ec.addAttr(data, "factory",  factoryName, true);
-        data.setTextContent(Base64.encodeBase64String(artifact));
-
-        root.appendChild(data);
-
-        return document;
-    }
-
-    public Document importArtifact(Document input, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        String factoryName = XMLUtils.xpathString(
-            input,
-            XPATH_IMPORT_FACTORY,
-            ArtifactNamespaceContext.INSTANCE);
-
-        ArtifactFactory factory;
-
-        if (factoryName == null
-        || (factoryName = factoryName.trim()).length() == 0
-        || (factory = getArtifactFactory(factoryName)) == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        String checksumString = XMLUtils.xpathString(
-            input,
-            XPATH_IMPORT_CHECKSUM,
-            ArtifactNamespaceContext.INSTANCE);
-
-        byte [] checksum;
-
-        if (checksumString == null
-        || (checksumString = checksumString.trim()).length() == 0
-        || (checksum = StringUtils.decodeHex(checksumString)) == null
-        ) {
-            throw new ArtifactDatabaseException(INVALID_CHECKSUM);
-        }
-
-        checksumString = null;
-
-        String dataString = XMLUtils.xpathString(
-            input,
-            XPATH_IMPORT_DATA,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (dataString == null
-        || (dataString = dataString.trim()).length() == 0) {
-            throw new ArtifactDatabaseException(NO_DATA);
-        }
-
-        byte [] data = Base64.decodeBase64(dataString);
-
-        dataString = null;
-
-        MessageDigest md;
-        try {
-            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
-        }
-        catch (NoSuchAlgorithmException nsae) {
-            logger.error(nsae.getLocalizedMessage(), nsae);
-            return XMLUtils.newDocument();
-        }
-
-        md.update(data);
-        md.update(exportSecret);
-
-        byte [] digest = md.digest();
-
-        if (!Arrays.equals(checksum, digest)) {
-            throw new ArtifactDatabaseException(CHECKSUM_MISMATCH);
-        }
-
-        ArtifactSerializer serializer = factory.getSerializer();
-
-        Artifact artifact = serializer.fromBytes(data); data = null;
-
-        if (artifact == null) {
-            throw new ArtifactDatabaseException(INVALID_ARTIFACT);
-        }
-
-        artifact.setIdentifier(backend.newIdentifier());
-        PersistentArtifact persistentArtifact;
-
-        try {
-            persistentArtifact = backend.storeOrReplace(
-                artifact,
-                factory,
-                factory.timeToLiveUntouched(artifact, context));
-        }
-        catch (Exception e) {
-            logger.error(e.getLocalizedMessage(), e);
-            throw new ArtifactDatabaseException(CREATION_FAILED);
-        }
-
-        ArtifactCallContext cc = new ArtifactCallContext(
-            ArtifactDatabaseImpl.this,
-            CallContext.NOTHING,
-            callMeta,
-            persistentArtifact);
-
-        try {
-            return artifact.describe(input, cc);
-        }
-        finally {
-            cc.postCall();
-        }
-    }
-
-    public String [][] serviceNamesAndDescriptions() {
-        return serviceNamesAndDescription;
-    }
-
-    public Service.Output process(
-        String   serviceName,
-        Document input,
-        CallMeta callMeta
-    )
-    throws ArtifactDatabaseException
-    {
-        Service service = (Service)name2service.get(serviceName);
-
-        if (service == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_SERVICE);
-        }
-
-        return service.process(input, context, callMeta);
-    }
-
-    // User API
-
-    /** Returns user(s) elements. */
-    public Document listUsers(CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        UserFactory factory = getUserFactory();
-
-        if (factory == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        User [] users = backend.getUsers(factory, context);
-
-        if (users != null) {
-            logger.debug(users.length + " users found in the backend.");
-        }
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("users");
-        result.appendChild(root);
-
-        if(users != null) {
-            for (User user: users) {
-                Element ue = ec.create("user");
-                ec.addAttr(ue, "uuid", user.identifier(), true);
-                ec.addAttr(ue, "name", user.getName(), true);
-                Element ua = ec.create("account");
-                ec.addAttr(ua, "name", user.getAccount(), true);
-                ue.appendChild(ua);
-
-                Document role = user.getRole();
-
-                if (role != null) {
-                    ue.appendChild(result.importNode(role.getFirstChild(), true));
-                }
-
-                root.appendChild(ue);
-            }
-        }
-
-        return result;
-    }
-
-    /** Search for a user. */
-    public Document findUser(Document data, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        UserFactory factory = getUserFactory();
-
-        if (factory == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        String account = XMLUtils.xpathString(
-            data, XPATH_USERACCOUNT_FIND, ArtifactNamespaceContext.INSTANCE);
-
-        if (account == null || account.length() == 0) {
-            logger.warn("Can't find user without account!");
-            throw new ArtifactDatabaseException(NO_USERACCOUNT);
-        }
-
-        User user = backend.findUser(account, factory, context);
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element ue = ec.create("user");
-
-        if (user != null) {
-            logger.debug(user + " user found in the backend.");
-
-            ec.addAttr(ue, "uuid", user.identifier(), true);
-            ec.addAttr(ue, "name", user.getName(), true);
-            Element ua = ec.create("account");
-            ec.addAttr(ua, "name", user.getAccount(), true);
-            ue.appendChild(ua);
-
-            Document role = user.getRole();
-
-            if (role != null) {
-                ue.appendChild(result.importNode(role.getFirstChild(), true));
-            }
-        }
-
-        result.appendChild(ue);
-
-        return result;
-    }
-
-    public Document createUser(Document data, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        UserFactory factory = getUserFactory();
-
-        if (factory == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        String name = XMLUtils.xpathString(
-            data, XPATH_USERNAME, ArtifactNamespaceContext.INSTANCE);
-
-        if (name == null || name.length() == 0) {
-            logger.warn("User without username not accepted!");
-            throw new ArtifactDatabaseException(NO_USERNAME);
-        }
-
-        String account = XMLUtils.xpathString(
-            data, XPATH_USERACCOUNT, ArtifactNamespaceContext.INSTANCE);
-
-        if (account == null || account.length() == 0) {
-            logger.warn("User without account not accepted!");
-            throw new ArtifactDatabaseException(NO_USERACCOUNT);
-        }
-
-        Node tmp = (Node) XMLUtils.xpath(
-            data,
-            XPATH_USERROLE,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        Document role = XMLUtils.newDocument();
-
-        if (tmp != null) {
-            Node    clone = role.importNode(tmp, true);
-            role.appendChild(clone);
-        }
-
-        User newUser = null;
-
-        try {
-            newUser = backend.createUser(name, account, role, userFactory, context);
-        }
-        catch (Exception e) {
-            logger.error(e.getMessage(), e);
-            throw new ArtifactDatabaseException(USER_CREATION_FAILED);
-        }
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-
-        if (newUser != null) {
-            root.setTextContent(OPERATION_SUCCESSFUL);
-        }
-        else {
-            root.setTextContent(OPERATION_FAILURE);
-        }
-
-        result.appendChild(root);
-
-        return result;
-    }
-
-    public Document deleteUser(String userId, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        logger.debug("Delete user: " + userId);
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        boolean success = backend.deleteUser(userId);
-
-        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
-
-        return result;
-    }
-
-
-    // Collection API
-
-    public Document getCollectionsMasterArtifact(
-        String collectionId,
-        CallMeta meta)
-        throws ArtifactDatabaseException
-    {
-        Document result = XMLUtils.newDocument();
-        String masterUUID = backend.getMasterArtifact(collectionId);
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
-
-        if (acf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        UserFactory uf = getUserFactory();
-        if (uf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        ArtifactCollection c = backend.getCollection(
-            collectionId, acf, uf, context);
-
-        if (c == null) {
-            logger.warn("No collection found with identifier: " + collectionId);
-            throw new ArtifactDatabaseException(NO_SUCH_COLLECTION);
-        }
-
-        Element root = ec.create("artifact-collection");
-        ec.addAttr(root, "name", c.getName(), true);
-        ec.addAttr(root, "uuid", c.identifier(), true);
-        ec.addAttr(root, "ttl",  String.valueOf(c.getTTL()), true);
-
-        Date creationTime = c.getCreationTime();
-        String creation   = creationTime != null
-            ? Long.toString(creationTime.getTime())
-            : "";
-
-        ec.addAttr(root, "creation", creation,  true);
-        result.appendChild(root);
-
-        if (masterUUID == null || masterUUID.length() == 0) {
-            logger.debug("No master for the collection existing.");
-            return result;
-        }
-
-        Element master = ec.create("artifact");
-        ec.addAttr(master, "uuid", masterUUID, true);
-
-        root.appendChild(master);
-
-        return result;
-    }
-
-    public Document listCollections(String userId, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
-        UserFactory               uf  = getUserFactory();
-
-        if (acf == null || uf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        logger.debug("Fetch the list of collection for user: " + userId);
-
-        ArtifactCollection [] ac = backend.listCollections(
-            userId,
-            null, // XXX: fetch from REST
-            acf, uf,
-            context);
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("artifact-collections");
-        result.appendChild(root);
-
-        if (ac == null || ac.length == 0) {
-            logger.debug("No collections for the user existing.");
-
-            return result;
-        }
-
-        logger.debug("Found " + ac.length + " collections of the user.");
-
-        for (ArtifactCollection c: ac) {
-            Element collection = ec.create("artifact-collection");
-            ec.addAttr(collection, "name", c.getName(), true);
-            ec.addAttr(collection, "uuid", c.identifier(), true);
-            ec.addAttr(collection, "ttl",  String.valueOf(c.getTTL()), true);
-
-            Date creationTime = c.getCreationTime();
-            String creation   = creationTime != null
-                ? Long.toString(creationTime.getTime())
-                : "";
-
-            ec.addAttr(collection, "creation", creation,  true);
-
-            root.appendChild(collection);
-        }
-
-        return result;
-    }
-
-    public Document createCollection(String ownerId, Document data,
-        CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
-
-        if (acf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        String name = XMLUtils.xpathString(
-            data, XPATH_COLLECTION_NAME, ArtifactNamespaceContext.INSTANCE);
-
-        logger.debug("Create new collection with name: " + name);
-
-        Document attr = null;
-
-        Node attrNode = (Node) XMLUtils.xpath(
-            data,
-            XPATH_COLLECTION_ATTRIBUTE,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (attrNode != null) {
-            attr = XMLUtils.newDocument();
-            attr.appendChild(attr.importNode(attrNode, true));
-        }
-
-        ArtifactCollection ac = backend.createCollection(
-            ownerId, name, acf, attr, context);
-
-        if (ac == null) {
-            throw new ArtifactDatabaseException(COLLECTION_CREATION_FAILED);
-        }
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        Element acElement = ec.create("artifact-collection");
-        ec.addAttr(acElement, "uuid", ac.identifier(), true);
-        ec.addAttr(acElement, "ttl", String.valueOf(ac.getTTL()), true);
-
-        root.appendChild(acElement);
-
-        return result;
-    }
-
-    public Document deleteCollection(String collectionId, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        logger.debug("Delete collection: " + collectionId);
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        boolean success = backend.deleteCollection(collectionId);
-
-        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
-
-        return result;
-    }
-
-    public Document describeCollection(String collectionId, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        logger.debug("Describe collection: " + collectionId);
-        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
-
-        if (acf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        UserFactory uf = getUserFactory();
-        if (uf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        ArtifactCollection c = backend.getCollection(
-            collectionId, acf, uf, context);
-
-        if (c == null) {
-            logger.warn("No collection found with identifier: " + collectionId);
-            throw new ArtifactDatabaseException(NO_SUCH_COLLECTION);
-        }
-
-        CollectionCallContext cc = new CollectionCallContext(
-            ArtifactDatabaseImpl.this,
-            CallContext.NOTHING,
-            callMeta,
-            c);
-
-        try {
-            return c.describe(cc);
-        }
-        finally {
-            cc.postCall();
-        }
-    }
-
-
-    public Document getCollectionAttribute(String collectionId, CallMeta meta)
-    throws ArtifactDatabaseException
-    {
-        logger.debug("Fetch collection attribute for: " + collectionId);
-
-        return backend.getCollectionAttribute(collectionId);
-    }
-
-
-    public Document setCollectionAttribute(
-        String   collectionId,
-        CallMeta meta,
-        Document attribute)
-    throws ArtifactDatabaseException
-    {
-        logger.debug("Set new attribute for the collection: " + collectionId);
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        boolean success = backend.setCollectionAttribute(
-            collectionId, attribute);
-
-        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
-
-        return result;
-    }
-
-    public Document getCollectionItemAttribute(String collectionId, String artifactId,
-        CallMeta callMeta) throws ArtifactDatabaseException
-    {
-        logger.debug("Fetch the attribute for the artifact: " + artifactId);
-
-        return backend.getCollectionItemAttribute(collectionId, artifactId);
-    }
-
-    public Document setCollectionItemAttribute(String collectionId, String artifactId,
-        Document source, CallMeta callMeta)
-        throws ArtifactDatabaseException
-    {
-        logger.debug("Set the attribute for the artifact: " + artifactId);
-
-        Document attribute = null;
-
-        Node attr = (Node) XMLUtils.xpath(
-            source,
-            XPATH_COLLECTION_ITEM_ATTRIBUTE,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (attr != null) {
-            attribute = XMLUtils.newDocument();
-            attribute.appendChild(attribute.importNode(attr, true));
-        }
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        boolean success = backend.setCollectionItemAttribute(
-            collectionId, artifactId, attribute);
-
-        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
-
-        return result;
-    }
-
-    public Document addCollectionArtifact(
-        String   collectionId,
-        String   artifactId,
-        Document input,
-        CallMeta callMeta)
-    throws ArtifactDatabaseException
-    {
-        logger.debug(
-            "Add artifact '" + artifactId + "' collection '" +collectionId+"'");
-
-        Document attr = XMLUtils.newDocument();
-
-        Node attrNode = (Node) XMLUtils.xpath(
-            input,
-            XPATH_COLLECTION_ITEM_ATTRIBUTE,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (attrNode != null) {
-            attr.appendChild(attr.importNode(attrNode, true));
-        }
-
-        boolean success = backend.addCollectionArtifact(
-            collectionId,
-            artifactId,
-            attr);
-
-        if (!success) {
-            Document result = XMLUtils.newDocument();
-
-            XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-                result,
-                ArtifactNamespaceContext.NAMESPACE_URI,
-                ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-            Element root = ec.create("result");
-            result.appendChild(root);
-
-            root.setTextContent(OPERATION_FAILURE);
-
-            return result;
-        }
-
-        return describeCollection(collectionId, callMeta);
-    }
-
-    public Document removeCollectionArtifact(String collectionId, String artifactId,
-        CallMeta callMeta) throws ArtifactDatabaseException
-    {
-        logger.debug(
-            "Remove artifact '" + artifactId + "' from collection '" +
-            collectionId + "'");
-
-        Document attr = XMLUtils.newDocument();
-
-        boolean success = backend.removeCollectionArtifact(
-            collectionId,
-            artifactId);
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
-
-        return result;
-    }
-
-    public Document listCollectionArtifacts(String collectionId,
-        CallMeta callMeta) throws ArtifactDatabaseException
-    {
-        CollectionItem[] items = backend.listCollectionArtifacts(collectionId);
-
-        Document result = XMLUtils.newDocument();
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        Element ac   = ec.create("artifact-collection");
-        ec.addAttr(ac, "uuid", collectionId, true);
-
-        for (CollectionItem item: items) {
-            Element i    = ec.create("collection-item");
-            Element attr = ec.create("attribute");
-            ec.addAttr(i, "uuid", item.getArtifactIdentifier(), true);
-
-            Document attribute = item.getAttribute();
-            if (attribute != null) {
-                Node firstChild = attribute.getFirstChild();
-                attr.appendChild(result.importNode(firstChild, true));
-            }
-            else {
-                logger.debug("No attributes for the collection item!");
-            }
-
-            i.appendChild(attr);
-            ac.appendChild(i);
-        }
-
-        root.appendChild(ac);
-        result.appendChild(root);
-
-        return result;
-    }
-
-    public Document setCollectionTTL(String uuid, Document doc, CallMeta meta)
-    throws ArtifactDatabaseException
-    {
-        Document result            = XMLUtils.newDocument();
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        String tmp = XMLUtils.xpathString(
-            doc, XPATH_COLLECTION_TTL, ArtifactNamespaceContext.INSTANCE);
-
-        logger.info("Set TTL of artifact collection '" + uuid + "' to: " + tmp);
-
-        if (tmp == null || tmp.length() == 0) {
-            logger.warn("No ttl for this collection specified.");
-            root.setTextContent(OPERATION_FAILURE);
-
-            return result;
-        }
-
-        Long ttl = null;
-        if ((tmp = tmp.toUpperCase()).equals("INF")) {
-            ttl = null;
-        }
-        else if (tmp.equals("DEFAULT")) {
-            ArtifactCollectionFactory acf = getArtifactCollectionFactory();
-            ttl = acf.timeToLiveUntouched(null, context);
-        }
-        else {
-            try {
-                ttl = Long.valueOf(tmp);
-
-                if (ttl < 0) {
-                    throw new NumberFormatException("Negative value.");
-                }
-            }
-            catch (NumberFormatException nfe) {
-                logger.error("Could not determine TTL", nfe);
-                root.setTextContent(OPERATION_FAILURE);
-                return result;
-            }
-        }
-
-        boolean success = backend.setCollectionTTL(uuid, ttl);
-        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
-
-        return result;
-    }
-
-
-    public Document setCollectionName(String uuid, Document doc, CallMeta meta)
-    throws ArtifactDatabaseException
-    {
-        Document result            = XMLUtils.newDocument();
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            result,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ec.create("result");
-        result.appendChild(root);
-
-        String name = XMLUtils.xpathString(
-            doc, XPATH_COLLECTION_NAME, ArtifactNamespaceContext.INSTANCE);
-
-        logger.info("Set name of collection '" + uuid + "' to: " + name);
-
-        if (name == null || name.length() == 0) {
-            logger.warn("The new name is emtpy. No new name set!");
-            root.setTextContent(OPERATION_FAILURE);
-            return result;
-        }
-
-        boolean success = backend.setCollectionName(uuid, name);
-        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
-
-        return result;
-    }
-
-
-    public DeferredOutput outCollection(
-        String   collectionId,
-        Document format,
-        CallMeta callMeta)
-    throws ArtifactDatabaseException
-    {
-        return outCollection(collectionId, null, format, callMeta);
-    }
-
-    public DeferredOutput outCollection(
-        String   collectionId,
-        String   type,
-        Document format,
-        CallMeta callMeta)
-    throws ArtifactDatabaseException
-    {
-        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
-
-        if (acf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        UserFactory uf = getUserFactory();
-        if (uf == null) {
-            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
-        }
-
-        ArtifactCollection c = backend.getCollection(
-            collectionId, acf, uf, context);
-
-        if (c == null) {
-            logger.warn("No collection found with identifier: " + collectionId);
-            throw new ArtifactDatabaseException(NO_SUCH_COLLECTION);
-        }
-
-        return new DeferredCollectionOutputImpl(c, type, format, callMeta);
-    }
-
-    protected void initCallContext(CallContext cc) {
-        logger.debug("initCallContext");
-        if (callContextListener != null) {
-            callContextListener.init(cc);
-        }
-    }
-
-    protected void closeCallContext(CallContext cc) {
-        logger.debug("closeCallContext");
-        if (callContextListener != null) {
-            callContextListener.close(cc);
-        }
-    }
-
-    @Override
-    public void loadAllArtifacts(ArtifactLoadedCallback callback)
-        throws ArtifactDatabaseException
-    {
-        logger.debug("loadAllArtifacts");
-        boolean success = backend.loadAllArtifacts(callback);
-        if (!success) {
-            throw new ArtifactDatabaseException(INTERNAL_ERROR);
-        }
-    }
-
-    public void start() {
-        if (lifetimeListeners == null || lifetimeListeners.isEmpty()) {
-            return;
-        }
-
-        for (LifetimeListener ltl: lifetimeListeners) {
-            ltl.systemUp(context);
-        }
-
-        logger.debug("all lifetime listeners started");
-
-        Runtime.getRuntime().addShutdownHook(new Thread() {
-            @Override
-            public void run() {
-                for (LifetimeListener ltl: lifetimeListeners) {
-                    ltl.systemDown(context);
-                }
-            }
-        });
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1914 +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.artifactdatabase;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactCollection;
-import de.intevation.artifacts.ArtifactCollectionFactory;
-import de.intevation.artifacts.ArtifactDatabase.ArtifactLoadedCallback;
-import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.ArtifactSerializer;
-import de.intevation.artifacts.CollectionItem;
-import de.intevation.artifacts.User;
-import de.intevation.artifacts.UserFactory;
-
-import de.intevation.artifacts.common.utils.StringUtils;
-import de.intevation.artifacts.common.utils.XMLUtils;
-import de.intevation.artifacts.common.utils.LRUCache;
-
-import de.intevation.artifactdatabase.db.SQLExecutor;
-import de.intevation.artifactdatabase.db.SQL;
-
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.sql.Types;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-/**
- * The backend implements the low level layer used to store artifacts
- * in a SQL database.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class Backend
-implements   DatabaseCleaner.ArtifactReviver
-{
-    private static Logger logger = Logger.getLogger(Backend.class);
-
-    /**
-     * The SQL statement to create new artifact id inside the database.
-     */
-    public String SQL_NEXT_ID;
-
-    /**
-     * The SQL statement to insert an artifact into the database.
-     */
-    public String SQL_INSERT;
-
-    /**
-     * The SQL statement to update some columns of an existing
-     * artifact in the database.
-     */
-    public String SQL_UPDATE;
-
-    /**
-     * The SQL statement to touch the access time of an
-     * artifact inside the database.
-     */
-    public String SQL_TOUCH;
-
-    /**
-     * The SQL statement to load an artifact by a given
-     * identifier from the database.
-     */
-    public String SQL_LOAD_BY_GID;
-
-    /**
-     * The SQL statement to get the database id of an artifact
-     * identified by the identifier.
-     */
-    public String SQL_GET_ID;
-
-    /**
-     * The SQL statement to replace the content of an
-     * existing artifact inside the database.
-     */
-    public String SQL_REPLACE;
-
-    // USER SQL
-
-    public String SQL_USERS_NEXT_ID;
-    public String SQL_USERS_INSERT;
-    public String SQL_USERS_SELECT_ID_BY_GID;
-    public String SQL_USERS_SELECT_GID;
-    public String SQL_USERS_SELECT_ACCOUNT;
-    public String SQL_USERS_DELETE_ID;
-    public String SQL_USERS_DELETE_COLLECTIONS;
-    public String SQL_USERS_SELECT_ALL;
-    public String SQL_USERS_COLLECTIONS;
-    public String SQL_USERS_COLLECTION_IDS;
-    public String SQL_USERS_DELETE_ALL_COLLECTIONS;
-    public String SQL_ARTIFACTS_IN_ONLY_COLLECTION_ONLY;
-    public String SQL_OUTDATE_ARTIFACTS_COLLECTION;
-    public String SQL_UPDATE_COLLECTION_TTL;
-    public String SQL_UPDATE_COLLECTION_NAME;
-    public String SQL_OUTDATE_ARTIFACTS_USER;
-    public String SQL_DELETE_USER_COLLECTION_ITEMS;
-    public String SQL_COLLECTIONS_NEXT_ID;
-    public String SQL_COLLECTIONS_INSERT;
-    public String SQL_COLLECTIONS_SELECT_USER;
-    public String SQL_COLLECTIONS_SELECT_ALL;
-    public String SQL_COLLECTIONS_SELECT_GID;
-    public String SQL_COLLECTIONS_CREATION_TIME;
-    public String SQL_COLLECTIONS_ID_BY_GID;
-    public String SQL_COLLECTIONS_OLDEST_ARTIFACT;
-    public String SQL_DELETE_COLLECTION_ITEMS;
-    public String SQL_DELETE_COLLECTION;
-    public String SQL_COLLECTION_CHECK_ARTIFACT;
-    public String SQL_COLLECTION_ITEMS_ID_NEXTVAL;
-    public String SQL_COLLECTION_ITEMS_INSERT;
-    public String SQL_COLLECTION_GET_ATTRIBUTE;
-    public String SQL_COLLECTION_SET_ATTRIBUTE;
-    public String SQL_COLLECTION_ITEM_GET_ATTRIBUTE;
-    public String SQL_COLLECTION_ITEM_SET_ATTRIBUTE;
-    public String SQL_COLLECTIONS_TOUCH_BY_GID;
-    public String SQL_COLLECTION_ITEM_ID_CID_AID;
-    public String SQL_COLLECTION_ITEM_OUTDATE_ARTIFACT;
-    public String SQL_COLLECTION_ITEM_DELETE;
-    public String SQL_COLLECTIONS_TOUCH_BY_ID;
-    public String SQL_COLLECTION_ITEMS_LIST_GID;
-    public String SQL_ALL_ARTIFACTS;
-
-    /** The singleton.*/
-    protected static Backend instance;
-
-    protected SQLExecutor sqlExecutor;
-
-    protected List<BackendListener> listeners;
-
-    protected DBConfig config;
-
-    /**
-     * The database cleaner. Reference is stored here because
-     * the cleaner is woken up if the backend finds an outdated
-     * artifact. This artifact should be removed as soon as
-     * possible.
-     */
-    protected DatabaseCleaner cleaner;
-
-    /**
-     * To revive an artifact from the bytes coming from the database
-     * we need the artifact factory which references the artifact
-     * serializer which is able to do the reviving job.
-     */
-    protected FactoryLookup   factoryLookup;
-
-    /**
-     * Little helper interface to decouple the ArtifactDatabase
-     * from the Backend. A ArtifactDatabase should depend on a
-     * Backend but a Backend not from an ArtifactDatabase.
-     */
-    public interface FactoryLookup {
-
-        /**
-         * Returns an ArtifactFactory which is bound to a given name.
-         * @param factoryName The name of the artifact factory.
-         * @return The ArtifactFactory bound to the factory name or
-         * null if not matching factory is found.
-         */
-        ArtifactFactory getArtifactFactory(String factoryName);
-
-    } // interface FactoryLookup
-
-    /**
-     * Inner class that brigdes between the persisten form of the
-     * artifact and the living one inside the artifact database.
-     * After the describe(), feed(), advance() and out() operations
-     * of the artifact it must be possible to write to modified artifact
-     * back into the database.
-     */
-    public final class PersistentArtifact
-    {
-        private int                id;
-        private Artifact           artifact;
-        private ArtifactSerializer serializer;
-        private Long               ttl;
-
-        /**
-         * Cronstructor to create a persistent artifact.
-         * @param artifact   The living artifact.
-         * @param serializer The serializer to store the artifact
-         * after the operations.
-         * @param ttl The time to life of the artifact.
-         * @param id The database id of the artifact.
-         */
-        public PersistentArtifact(
-            Artifact           artifact,
-            ArtifactSerializer serializer,
-            Long               ttl,
-            int                id
-        ) {
-            this.id         = id;
-            this.artifact   = artifact;
-            this.serializer = serializer;
-            this.ttl        = ttl;
-        }
-
-        public int getId() {
-            return id;
-        }
-
-        /**
-         * Returns the wrapped living artifact.
-         * @return the living artifact.
-         */
-        public Artifact getArtifact() {
-            return artifact;
-        }
-
-        /**
-         * Returns the serialized which is able to write a
-         * modified artifact back into the database.
-         * @return The serializer.
-         */
-        public ArtifactSerializer getSerializer() {
-            return serializer;
-        }
-
-        /**
-         * The time to life of the artifact.
-         * @return The time to live.
-         */
-        public Long getTTL() {
-            return ttl;
-        }
-
-        /**
-         * Stores the living artifact back into the database.
-         */
-        public void store() {
-            if (logger.isDebugEnabled()) {
-                logger.debug("storing artifact id = " + getId());
-            }
-            Backend.this.store(this);
-        }
-
-        /**
-         * Only touches the access time of the artifact.
-         */
-        public void touch() {
-            if (logger.isDebugEnabled()) {
-                logger.debug("touching artifact id = " + getId());
-            }
-            Backend.this.touch(this);
-        }
-    } // class ArtifactWithId
-
-    /**
-     * Default constructor
-     */
-    public Backend() {
-        listeners = new CopyOnWriteArrayList<BackendListener>();
-    }
-
-    public Backend(DBConfig config) {
-        this();
-        this.config = config;
-        sqlExecutor = new SQLExecutor(config.getDBConnection());
-        setupSQL(config.getSQL());
-    }
-
-    /**
-     * Constructor to create a backend with a link to the database cleaner.
-     * @param cleaner The clean which periodically removes outdated
-     * artifacts from the database.
-     */
-    public Backend(DBConfig config, DatabaseCleaner cleaner) {
-        this(config);
-        this.cleaner = cleaner;
-    }
-
-    public DBConfig getConfig() {
-        return config;
-    }
-
-    /**
-     * Returns the singleton of this Backend.
-     *
-     * @return the backend.
-     */
-    public static synchronized Backend getInstance() {
-        if (instance == null) {
-            instance = new Backend(DBConfig.getInstance());
-        }
-
-        return instance;
-    }
-
-    protected void setupSQL(SQL sql) {
-        SQL_NEXT_ID = sql.get("artifacts.id.nextval");
-        SQL_INSERT = sql.get("artifacts.insert");
-        SQL_UPDATE = sql.get("artifacts.update");
-        SQL_TOUCH = sql.get("artifacts.touch");
-        SQL_LOAD_BY_GID = sql.get("artifacts.select.gid");
-        SQL_GET_ID = sql.get("artifacts.get.id");
-        SQL_REPLACE = sql.get("artifacts.replace");
-        SQL_USERS_NEXT_ID = sql.get("users.id.nextval");
-        SQL_USERS_INSERT = sql.get("users.insert");
-        SQL_USERS_SELECT_ID_BY_GID = sql.get("users.select.id.by.gid");
-        SQL_USERS_SELECT_GID = sql.get("users.select.gid");
-        SQL_USERS_SELECT_ACCOUNT = sql.get("users.select.account");
-        SQL_USERS_DELETE_ID = sql.get("users.delete.id");
-        SQL_USERS_DELETE_COLLECTIONS = sql.get("users.delete.collections");
-        SQL_USERS_SELECT_ALL = sql.get("users.select.all");
-        SQL_USERS_COLLECTIONS = sql.get("users.collections");
-        SQL_USERS_COLLECTION_IDS = sql.get("users.collection.ids");
-        SQL_USERS_DELETE_ALL_COLLECTIONS =
-            sql.get("users.delete.collections");
-        SQL_ARTIFACTS_IN_ONLY_COLLECTION_ONLY =
-            sql.get("artifacts.in.one.collection.only");
-        SQL_OUTDATE_ARTIFACTS_COLLECTION =
-            sql.get("outdate.artifacts.collection");
-        SQL_UPDATE_COLLECTION_TTL = sql.get("collections.update.ttl");
-        SQL_UPDATE_COLLECTION_NAME = sql.get("collections.update.name");
-        SQL_OUTDATE_ARTIFACTS_USER = sql.get("outdate.artifacts.user");
-        SQL_DELETE_USER_COLLECTION_ITEMS =
-            sql.get("delete.user.collection.items");
-        SQL_COLLECTIONS_NEXT_ID = sql.get("collections.id.nextval");
-        SQL_COLLECTIONS_INSERT = sql.get("collections.insert");
-        SQL_COLLECTIONS_SELECT_USER = sql.get("collections.select.user");
-        SQL_COLLECTIONS_SELECT_ALL = sql.get("collections.select.all");
-        SQL_COLLECTIONS_SELECT_GID = sql.get("collections.select.by.gid");
-        SQL_COLLECTIONS_CREATION_TIME = sql.get("collection.creation.time");
-        SQL_COLLECTIONS_OLDEST_ARTIFACT = sql.get("collections.artifacts.oldest");
-        SQL_COLLECTIONS_ID_BY_GID = sql.get("collections.id.by.gid");
-        SQL_DELETE_COLLECTION_ITEMS = sql.get("delete.collection.items");
-        SQL_DELETE_COLLECTION = sql.get("delete.collection");
-        SQL_COLLECTION_CHECK_ARTIFACT = sql.get("collection.check.artifact");
-        SQL_COLLECTION_ITEMS_ID_NEXTVAL =
-            sql.get("collection.items.id.nextval");
-        SQL_COLLECTION_ITEMS_INSERT = sql.get("collection.items.insert");
-        SQL_COLLECTION_GET_ATTRIBUTE = sql.get("collection.get.attribute");
-        SQL_COLLECTION_SET_ATTRIBUTE = sql.get("collection.set.attribute");
-        SQL_COLLECTION_ITEM_GET_ATTRIBUTE =
-            sql.get("collection.item.get.attribute");
-        SQL_COLLECTION_ITEM_SET_ATTRIBUTE =
-            sql.get("collection.item.set.attribute");
-        SQL_COLLECTIONS_TOUCH_BY_GID = sql.get("collections.touch.by.gid");
-        SQL_COLLECTION_ITEM_ID_CID_AID = sql.get("collection.item.id.cid.aid");
-        SQL_COLLECTION_ITEM_OUTDATE_ARTIFACT =
-            sql.get("collection.item.outdate.artifact");
-        SQL_COLLECTION_ITEM_DELETE = sql.get("collection.item.delete");
-        SQL_COLLECTIONS_TOUCH_BY_ID = sql.get("collections.touch.by.id");
-        SQL_COLLECTION_ITEMS_LIST_GID = sql.get("collection.items.list.gid");
-        SQL_ALL_ARTIFACTS = sql.get("all.artifacts");
-    }
-
-    public void addListener(BackendListener listener) {
-        listeners.add(listener);
-        logger.debug("# listeners: " + listeners.size());
-    }
-
-    public void addAllListeners(List<BackendListener> others) {
-        listeners.addAll(others);
-        logger.debug("# listeners: " + listeners.size());
-    }
-
-    /**
-     * Sets the factory lookup mechanism to decouple ArtifactDatabase
-     * and Backend.
-     * @param factoryLookup
-     */
-    public void setFactoryLookup(FactoryLookup factoryLookup) {
-        this.factoryLookup = factoryLookup;
-    }
-
-    /**
-     * Sets the database cleaner explicitly.
-     * @param cleaner The database cleaner
-     */
-    public void setCleaner(DatabaseCleaner cleaner) {
-        this.cleaner = cleaner;
-    }
-
-    /**
-     * Returns a new unique identifier to external identify
-     * the artifact across the system. This implementation
-     * uses random UUIDs v4 to achieve this target.
-     * @return the new identifier
-     */
-    public String newIdentifier() {
-        // TODO: check database for collisions.
-        return StringUtils.newUUID();
-    }
-
-    public boolean isValidIdentifier(String identifier) {
-        return StringUtils.checkUUID(identifier);
-    }
-
-    /**
-     * Stores a new artifact into the database.
-     * @param artifact The artifact to be stored
-     * @param factory  The factory which build the artifact
-     * @param ttl      The initial time to life of the artifact.
-     * @return         A persistent wrapper around the living
-     * artifact to be able to write modification later.
-     * @throws Exception Thrown if something went wrong with the
-     * storage process.
-     */
-    public PersistentArtifact storeInitially(
-        Artifact        artifact,
-        ArtifactFactory factory,
-        Long            ttl
-    )
-    throws Exception
-    {
-        return new PersistentArtifact(
-            artifact,
-            factory.getSerializer(),
-            ttl,
-            insertDatabase(artifact, factory, ttl));
-    }
-
-    /**
-     * Stores an artifact into database if it does not exist there.
-     * If it exists there it is only updated.
-     * @param artifact The artifact to store/update.
-     * @param factory The factory which created the artifact.
-     * @param ttl The initial time to live of the artifact.
-     * @return A persistent version of the artifact to be able
-     * to store a modification later.
-     * @throws Exception Thrown if something went wrong during
-     * storing/updating.
-     */
-    public PersistentArtifact storeOrReplace(
-        Artifact        artifact,
-        ArtifactFactory factory,
-        Long            ttl
-    )
-    throws Exception
-    {
-        return new PersistentArtifact(
-            artifact,
-            factory.getSerializer(),
-            ttl,
-            storeOrReplaceDatabase(artifact, factory, ttl));
-    }
-
-    /**
-     * Implementors of this interface are able to process the raw
-     * artifact data from the database for loading.
-     */
-    public interface ArtifactLoader {
-
-        /**
-         * Creates a custom object from the raw artifact database data.
-         * @param factory The factory that created this artifact.
-         * @param ttl The current time to life of the artifact.
-         * @param bytes The raw artifact bytes from the database.
-         * @param id The database id of the artifact.
-         * @return The custom object created by the implementation.
-         */
-        Object load(ArtifactFactory factory, Long ttl, byte [] bytes, int id);
-
-    } // interface ArtifactLoader
-
-    /**
-     * Fetches an artifact from the database identified by the
-     * given identifier.
-     * @param identifer The identifier of the artifact.
-     * @return A persistent wrapper around the found artifact
-     * to be able to write back a modifaction later or null
-     * if no artifact is found for this identifier.
-     */
-    public PersistentArtifact getArtifact(String identifer) {
-
-        return (PersistentArtifact)loadArtifact(
-            identifer,
-            new ArtifactLoader() {
-
-                public Object load(
-                    ArtifactFactory factory,
-                    Long            ttl,
-                    byte []         bytes,
-                    int             id
-                ) {
-                    ArtifactSerializer serializer = factory.getSerializer();
-
-                    Artifact artifact = serializer.fromBytes(bytes);
-
-                    return artifact == null
-                        ? null
-                        : new PersistentArtifact(artifact, serializer, ttl, id);
-                }
-            });
-    }
-
-    /**
-     * More general loading mechanism for artifacts. The concrete
-     * load processing is delegated to the given loader.
-     * @param identifer The identifier of the artifact.
-     * @param loader The loader which processes the raw database data.
-     * @return The object created by the loader.
-     */
-    public Object loadArtifact(
-        final String         identifer,
-        final ArtifactLoader loader
-    ) {
-        if (!isValidIdentifier(identifer)) {
-            return null;
-        }
-
-        if (factoryLookup == null) {
-            logger.error("factory lookup == null");
-            return false;
-        }
-
-        final Object [] loaded = new Object[1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_LOAD_BY_GID);
-                stmnt.setString(1, identifer);
-
-                result = stmnt.executeQuery();
-
-                if (!result.next()) {
-                    return false;
-                }
-
-                int  id   = result.getInt(1);
-                long ttlX = result.getLong(2);
-                Long ttl  = result.wasNull() ? null : ttlX;
-
-                String factoryName = result.getString(3);
-
-                ArtifactFactory factory = factoryLookup
-                    .getArtifactFactory(factoryName);
-
-                if (factory == null) {
-                    logger.error("factory '" + factoryName + "' not found");
-                    return false;
-                }
-
-                byte [] bytes = result.getBytes(4);
-
-                loaded[0] = loader.load(factory, ttl, bytes, id);
-                return true;
-            }
-        };
-
-        return exec.runRead() ? loaded[0] : null;
-    }
-
-    /**
-     * Called if the load mechanism found an outdated artifact.
-     * It  wakes up the database cleaner.
-     * @param id The id of the outdated artifact.
-     */
-    protected void artifactOutdated(int id) {
-        if (logger.isDebugEnabled()) {
-            logger.info("artifactOutdated: id = " + id);
-        }
-        if (cleaner != null) {
-            cleaner.wakeup();
-        }
-    }
-
-    public Artifact reviveArtifact(String factoryName, byte [] bytes) {
-        if (factoryLookup == null) {
-            logger.error("reviveArtifact: factory lookup == null");
-            return null;
-        }
-        ArtifactFactory factory = factoryLookup
-            .getArtifactFactory(factoryName);
-
-        if (factory == null) {
-            logger.error(
-                "reviveArtifact: no factory '" + factoryName + "' found");
-            return null;
-        }
-
-        ArtifactSerializer serializer = factory.getSerializer();
-
-        return serializer.fromBytes(bytes);
-    }
-
-    /**
-     * Internal method to store/replace an artifact inside the database.
-     * If an artifact with the given identifier does not exists it is
-     * created else only the content data is updated.
-     * @param artifact The artifact to be store/update inside the database.
-     * @param factory The factory that created the artifact.
-     * @param ttl The initial time to life of the artifact.
-     * @return The database id of the stored/updated artifact.
-     */
-    protected int storeOrReplaceDatabase(
-        final Artifact        artifact,
-        final ArtifactFactory factory,
-        final Long            ttl
-    ) {
-        final String uuid = artifact.identifier();
-
-        if (!isValidIdentifier(uuid)) {
-            throw new RuntimeException("No valid UUID");
-        }
-
-        final int     [] id     = new int[1];
-        final boolean [] stored = new boolean[1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-
-                prepareStatement(SQL_GET_ID);
-                stmnt.setString(1, uuid);
-                result = stmnt.executeQuery();
-
-                Integer ID = result.next()
-                    ? Integer.valueOf(result.getInt(1))
-                    : null;
-
-                reset();
-
-                if (stored[0] = ID != null) { // already in database
-                    prepareStatement(SQL_REPLACE);
-
-                    if (ttl == null) {
-                        stmnt.setNull(1, Types.BIGINT);
-                    }
-                    else {
-                        stmnt.setLong(1, ttl.longValue());
-                    }
-
-                    stmnt.setString(2, factory.getName());
-                    stmnt.setBytes(
-                        3,
-                        factory.getSerializer().toBytes(artifact));
-                    id[0] = ID.intValue();
-                    stmnt.setInt(4, id[0]);
-                }
-                else { // new artifact
-                    prepareStatement(SQL_NEXT_ID);
-                    result = stmnt.executeQuery();
-
-                    if (!result.next()) {
-                        logger.error("No id generated");
-                        return false;
-                    }
-
-                    reset();
-
-                    prepareStatement(SQL_INSERT);
-
-                    id[0] = result.getInt(1);
-                    stmnt.setInt(1, id[0]);
-                    stmnt.setString(2, uuid);
-                    if (ttl == null) {
-                        stmnt.setNull(3, Types.BIGINT);
-                    }
-                    else {
-                        stmnt.setLong(3, ttl.longValue());
-                    }
-
-                    stmnt.setString(4, factory.getName());
-
-                    stmnt.setBytes(
-                        5,
-                        factory.getSerializer().toBytes(artifact));
-                }
-                stmnt.execute();
-                conn.commit();
-                return true;
-            }
-        };
-
-        if (!exec.runWrite()) {
-            throw new RuntimeException("failed insert artifact into database");
-        }
-
-        if (stored[0]) {
-            fireStoredArtifact(artifact);
-        }
-        else {
-            fireCreatedArtifact(artifact);
-        }
-
-        return id[0];
-    }
-
-    /**
-     * Internal method to store an artifact inside the database.
-     * @param artifact The artifact to be stored.
-     * @param factory The factory which created the artifact.
-     * @param ttl The initial time to live of the artifact.
-     * @return The database id of the stored artifact.
-     */
-    protected int insertDatabase(
-        final Artifact        artifact,
-        final ArtifactFactory factory,
-        final Long            ttl
-    ) {
-        final int [] id = new int[1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_NEXT_ID);
-                result = stmnt.executeQuery();
-
-                if (!result.next()) {
-                    logger.error("No id generated");
-                    return false;
-                }
-
-                id[0] = result.getInt(1);
-
-                reset();
-                prepareStatement(SQL_INSERT);
-
-                String uuid = artifact.identifier();
-                stmnt.setInt(1, id[0]);
-                stmnt.setString(2, uuid);
-                if (ttl == null) {
-                    stmnt.setNull(3, Types.BIGINT);
-                }
-                else {
-                    stmnt.setLong(3, ttl.longValue());
-                }
-
-                stmnt.setString(4, factory.getName());
-
-                stmnt.setBytes(
-                    5,
-                    factory.getSerializer().toBytes(artifact));
-
-                stmnt.execute();
-
-                conn.commit();
-                return true;
-            }
-        };
-
-        if (!exec.runWrite()) {
-            throw new RuntimeException("failed insert artifact into database");
-        }
-
-        fireCreatedArtifact(artifact);
-
-        return id[0];
-    }
-
-    protected void fireCreatedArtifact(Artifact artifact) {
-        for (BackendListener listener: listeners) {
-            listener.createdArtifact(artifact, this);
-        }
-    }
-
-    /**
-     * Touches the access timestamp of a given artifact to prevent
-     * that it will be removed from the database by the database cleaner.
-     * @param artifact The persistent wrapper around the living artifact.
-     */
-    public void touch(final PersistentArtifact artifact) {
-        sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_TOUCH);
-                stmnt.setInt(1, artifact.getId());
-                stmnt.execute();
-                conn.commit();
-                return true;
-            }
-        }.runWrite();
-    }
-
-    /**
-     * Writes modification of an artifact back to the database.
-     * @param artifact The persistent wrapper around a living
-     * artifact.
-     */
-    public void store(final PersistentArtifact artifact) {
-        boolean success = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_UPDATE);
-                stmnt.setInt(2, artifact.getId());
-
-                byte [] bytes = artifact
-                    .getSerializer()
-                    .toBytes(artifact.getArtifact());
-
-                stmnt.setBytes(1, bytes);
-                stmnt.execute();
-                conn.commit();
-                return true;
-            }
-        }.runWrite();
-
-        if (success) {
-            fireStoredArtifact(artifact.getArtifact());
-        }
-    }
-
-    protected void fireStoredArtifact(Artifact artifact) {
-        for (BackendListener listener: listeners) {
-            listener.storedArtifact(artifact, this);
-        }
-    }
-
-
-    public User createUser(
-        final String      name,
-        final String      account,
-        final Document    role,
-        final UserFactory factory,
-        final Object      context
-    ) {
-        final User [] user = new User[1];
-
-        final byte [] roleData = XMLUtils.toByteArray(role, true);
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-
-                prepareStatement(SQL_USERS_NEXT_ID);
-                result = stmnt.executeQuery();
-
-                if (!result.next()) {
-                    return false;
-                }
-
-                int id = result.getInt(1);
-
-                reset();
-
-                String identifier = newIdentifier();
-
-                prepareStatement(SQL_USERS_INSERT);
-
-                stmnt.setInt(1, id);
-                stmnt.setString(2, identifier);
-                stmnt.setString(3, name);
-                stmnt.setString(4, account);
-
-                if (roleData == null) {
-                    stmnt.setNull(5, Types.BIGINT);
-                }
-                else {
-                    stmnt.setBytes(5, roleData);
-                }
-
-                stmnt.execute();
-                conn.commit();
-
-                user[0] = factory.createUser(
-                    identifier, name, account, role, context);
-                return true;
-            }
-        };
-
-        boolean success = exec.runWrite();
-
-        if (success) {
-            fireCreatedUser(user[0]);
-            return user[0];
-        }
-
-        return null;
-    }
-
-    protected void fireCreatedUser(User user) {
-        for (BackendListener listener: listeners) {
-            listener.createdUser(user, this);
-        }
-    }
-
-    public boolean deleteUser(final String identifier) {
-
-        if (!isValidIdentifier(identifier)) {
-            return false;
-        }
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_USERS_SELECT_ID_BY_GID);
-
-                stmnt.setString(1, identifier);
-                result = stmnt.executeQuery();
-
-                if (!result.next()) { // No such user
-                    return false;
-                }
-
-                int id = result.getInt(1);
-
-                reset();
-
-                // outdate the artifacts exclusively used by the user
-
-                prepareStatement(SQL_OUTDATE_ARTIFACTS_USER);
-                stmnt.setInt(1, id);
-                stmnt.setInt(2, id);
-                stmnt.execute();
-
-                reset();
-
-                // delete the collection items of the user
-
-                prepareStatement(SQL_DELETE_USER_COLLECTION_ITEMS);
-                stmnt.setInt(1, id);
-                stmnt.execute();
-
-                reset();
-
-                // delete the collections of the user
-
-                prepareStatement(SQL_USERS_DELETE_COLLECTIONS);
-                stmnt.setInt(1, id);
-                stmnt.execute();
-
-                reset();
-
-                // delete the user
-
-                prepareStatement(SQL_USERS_DELETE_ID);
-                stmnt.setInt(1, id);
-                stmnt.execute();
-
-                conn.commit();
-                return true;
-            }
-        };
-
-        boolean success = exec.runWrite();
-
-        if (success) {
-            fireDeletedUser(identifier);
-        }
-
-        return success;
-    }
-
-    protected void fireDeletedUser(String identifier) {
-        for (BackendListener listener: listeners) {
-            listener.deletedUser(identifier, this);
-        }
-    }
-
-    public User getUser(
-        final String      identifier,
-        final UserFactory factory,
-        final Object      context
-    ) {
-        if (!isValidIdentifier(identifier)) {
-            logger.debug("Invalid UUID: '" + identifier + "'");
-            return null;
-        }
-
-        final User [] user = new User[1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_USERS_SELECT_GID);
-                stmnt.setString(1, identifier);
-                result = stmnt.executeQuery();
-                if (!result.next()) { // no such user
-                    return false;
-                }
-                // omit id
-                String  name     = result.getString(2);
-                String account   = result.getString(3);
-                byte [] roleData = result.getBytes(4);
-
-                Document role = null;
-                if (roleData != null) {
-                    role = XMLUtils.fromByteArray(roleData, true);
-                }
-
-                user[0] = factory.createUser(
-                    identifier, name, account, role, context);
-                return true;
-            }
-        };
-
-        return exec.runRead() ? user[0] : null;
-    }
-
-    /**
-     * Find/Get user by account.
-     */
-    public User findUser(
-        final String      account,
-        final UserFactory factory,
-        final Object      context
-    ) {
-
-        final User [] user = new User[1];
-        logger.debug("Trying to find user by account " + account);
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_USERS_SELECT_ACCOUNT);
-                stmnt.setString(1, account);
-                result = stmnt.executeQuery();
-                if (!result.next()) { // no such user
-                    logger.debug("No user found.");
-                    return false;
-                }
-                String  identifier = result.getString(1);
-                String  name     = result.getString(2);
-                String account   = result.getString(3);
-                byte [] roleData = result.getBytes(4);
-
-                Document role = null;
-                if (roleData != null) {
-                    role = XMLUtils.fromByteArray(roleData, true);
-                }
-
-                user[0] = factory.createUser(
-                    identifier, name, account, role, context);
-                return true;
-            }
-        };
-
-        return exec.runRead() ? user[0] : null;
-    }
-
-    public User [] getUsers(
-        final UserFactory factory,
-        final Object      context
-    ) {
-        final ArrayList<User> users = new ArrayList<User>();
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_USERS_SELECT_ALL);
-                result = stmnt.executeQuery();
-
-                while (result.next()) {
-                    // omit id
-                    String  identifier = result.getString(2);
-                    String  name       = result.getString(3);
-                    String  account    = result.getString(4);
-                    byte [] roleData   = result.getBytes(5);
-
-                    Document role = XMLUtils.fromByteArray(roleData, true);
-                    User user = factory.createUser(
-                        identifier, name, account, role, context);
-                    users.add(user);
-                }
-                return true;
-            }
-        };
-
-        return exec.runRead()
-            ? users.toArray(new User[users.size()])
-            : null;
-    }
-
-    public ArtifactCollection createCollection(
-        final String                    ownerIdentifier,
-        final String                    name,
-        final ArtifactCollectionFactory factory,
-        final Document                  attribute,
-        final Object                    context
-    ) {
-        if (name == null) {
-            logger.debug("Name is null");
-            return null;
-        }
-
-        if (!isValidIdentifier(ownerIdentifier)) {
-            logger.debug("Invalid owner id: '" + ownerIdentifier + "'");
-            return null;
-        }
-
-        final ArtifactCollection [] collection = new ArtifactCollection[1];
-
-        final byte [] data = XMLUtils.toByteArray(attribute, true);
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                // fetch owner id
-                prepareStatement(SQL_USERS_SELECT_ID_BY_GID);
-                stmnt.setString(1, ownerIdentifier);
-                result = stmnt.executeQuery();
-
-                if (!result.next()) { // no such user
-                    return false;
-                }
-
-                int ownerId = result.getInt(1);
-                reset();
-
-                // fetch new collection seq number.
-                prepareStatement(SQL_COLLECTIONS_NEXT_ID);
-                result = stmnt.executeQuery();
-
-                if (!result.next()) { // no identifier generated
-                    return false;
-                }
-
-                int id = result.getInt(1);
-                reset();
-
-                String identifier = newIdentifier();
-
-                prepareStatement(SQL_COLLECTIONS_INSERT);
-
-                stmnt.setInt(1, id);
-                stmnt.setString(2, identifier);
-                stmnt.setString(3, name);
-                stmnt.setInt(4, ownerId);
-
-                // XXX: A bit odd: we don't have a collection, yet.
-                Long ttl = factory.timeToLiveUntouched(null, context);
-
-                if (ttl == null) {
-                    stmnt.setNull(5, Types.BIGINT);
-                }
-                else {
-                    stmnt.setLong(5, ttl);
-                }
-
-                if (data == null) {
-                    stmnt.setNull(6, Types.BINARY);
-                }
-                else {
-                    stmnt.setBytes(6, data);
-                }
-
-                stmnt.execute();
-                conn.commit();
-
-                reset();
-
-                // fetch creation time from database
-                // done this way to use the time system
-                // of the database.
-
-                prepareStatement(SQL_COLLECTIONS_CREATION_TIME);
-                stmnt.setInt(1, id);
-
-                result = stmnt.executeQuery();
-
-                Date creationTime = null;
-
-                if (result.next()) {
-                    Timestamp timestamp = result.getTimestamp(1);
-                    creationTime = new Date(timestamp.getTime());
-                }
-
-                collection[0] = factory.createCollection(
-                    identifier, name, creationTime, ttl, attribute, context);
-
-                if (collection[0] != null) {
-                    // XXX: Little hack to make the listeners happy
-                    collection[0].setUser(new DefaultUser(ownerIdentifier));
-                }
-
-                return true;
-            }
-        };
-
-        boolean success = exec.runWrite();
-
-        if (success) {
-            fireCreatedCollection(collection[0]);
-            return collection[0];
-        }
-        return null;
-    }
-
-    protected void fireCreatedCollection(ArtifactCollection collection) {
-        for (BackendListener listener: listeners) {
-            listener.createdCollection(collection, this);
-        }
-    }
-
-    public ArtifactCollection getCollection(
-        final String                    collectionId,
-        final ArtifactCollectionFactory collectionFactory,
-        final UserFactory               userFactory,
-        final Object                    context
-    ) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("collection id is not valid: " + collectionId);
-            return null;
-        }
-
-        final ArtifactCollection[] ac = new ArtifactCollection[1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-
-                prepareStatement(SQL_COLLECTIONS_SELECT_GID);
-                stmnt.setString(1, collectionId);
-
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such collection");
-                    return false;
-                }
-
-                String collectionName = result.getString(2);
-                String ownerId        = result.getString(3);
-                Date   creationTime   =
-                    new Date(result.getTimestamp(4).getTime());
-                Date   lastAccess     =
-                    new Date(result.getTimestamp(5).getTime());
-                Document attr         =
-                    XMLUtils.fromByteArray(result.getBytes(6), true);
-                long ttl              = result.getLong(7);
-
-                ArtifactCollection collection =
-                    collectionFactory.createCollection(
-                        collectionId,
-                        collectionName,
-                        creationTime,
-                        ttl,
-                        attr,
-                        context);
-
-                if (ownerId != null) {
-                    collection.setUser(new LazyBackendUser(
-                        ownerId, userFactory, Backend.this, context));
-                }
-
-                ac[0] = collection;
-
-                return true;
-            }
-        };
-
-        return exec.runRead() ? ac[0] : null;
-    }
-
-    public ArtifactCollection [] listCollections(
-        final String                    ownerIdentifier,
-        final Document                  data,
-        final ArtifactCollectionFactory collectionFactory,
-        final UserFactory               userFactory,
-        final Object                    context
-    ) {
-        if (ownerIdentifier != null
-        && !isValidIdentifier(ownerIdentifier)) {
-            logger.debug("Invalid owner id: '" + ownerIdentifier + "'");
-            return null;
-        }
-
-        final ArrayList<ArtifactCollection> collections =
-            new ArrayList<ArtifactCollection>();
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-
-            public boolean doIt() throws SQLException {
-
-                if (ownerIdentifier != null) {
-                    prepareStatement(SQL_COLLECTIONS_SELECT_USER);
-                    stmnt.setString(1, ownerIdentifier);
-                }
-                else {
-                    prepareStatement(SQL_COLLECTIONS_SELECT_ALL);
-                }
-
-                result = stmnt.executeQuery();
-
-                HashMap<String, LazyBackendUser> users =
-                    new HashMap<String, LazyBackendUser>();
-
-                while (result.next()) {
-                    String collectionIdentifier = result.getString(1);
-                    String collectionName       = result.getString(2);
-                    Date   creationTime         =
-                        new Date(result.getTimestamp(3).getTime());
-                    String userIdentifier       = result.getString(4);
-                    long   ttl                  = result.getLong(5);
-
-                    ArtifactCollection collection =
-                        collectionFactory.createCollection(
-                            collectionIdentifier,
-                            collectionName,
-                            creationTime,
-                            ttl,
-                            data,
-                            context);
-
-                    if (userIdentifier != null) {
-                        LazyBackendUser user = users.get(userIdentifier);
-                        if (user == null) {
-                            user = new LazyBackendUser(
-                                userIdentifier, userFactory,
-                                Backend.this, context);
-                            users.put(userIdentifier, user);
-                        }
-                        collection.setUser(user);
-                    }
-
-                    collections.add(collection);
-                }
-                return true;
-            }
-        };
-
-        return exec.runRead()
-            ? collections.toArray(new ArtifactCollection[collections.size()])
-            : null;
-    }
-
-
-    public String getMasterArtifact(final String collectionId) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("Invalid collection id: '" + collectionId + "'");
-            return null;
-        }
-        final String [] uuid = new String[1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                // Fetch masters (oldest artifact) id.
-                prepareStatement(SQL_COLLECTIONS_OLDEST_ARTIFACT);
-                stmnt.setString(1, collectionId);
-                stmnt.setMaxRows(1); //
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such collection: " + collectionId);
-                    return false;
-                }
-                uuid[0] = result.getString(1);
-                if (logger.isDebugEnabled()) {
-                    logger.debug("getMasterArtifact result.getString " +
-                        uuid[0]);
-                }
-                return true;
-            }
-        };
-        return exec.runRead() ? uuid[0] : null;
-    }
-
-    public boolean deleteCollection(final String collectionId) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("Invalid collection id: '" + collectionId + "'");
-            return false;
-        }
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                // fetch collection id
-                prepareStatement(SQL_COLLECTIONS_ID_BY_GID);
-                stmnt.setString(1, collectionId);
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such collection: " + collectionId);
-                    return false;
-                }
-                int id = result.getInt(1);
-                reset();
-
-                // outdate artifacts that are only in this collection
-                logger.info("Outdate Artifacts that belong to collection: " + id);
-
-                prepareStatement(SQL_OUTDATE_ARTIFACTS_COLLECTION);
-                stmnt.setInt(1, id);
-                stmnt.setInt(2, id);
-                stmnt.execute();
-                reset();
-
-                // delete the collection items
-                prepareStatement(SQL_DELETE_COLLECTION_ITEMS);
-                stmnt.setInt(1, id);
-                stmnt.execute();
-                reset();
-
-                // delete the collection
-                prepareStatement(SQL_DELETE_COLLECTION);
-                stmnt.setInt(1, id);
-                stmnt.execute();
-                conn.commit();
-                return true;
-            }
-        };
-        boolean success = exec.runWrite();
-
-        if (success) {
-            fireDeletedCollection(collectionId);
-        }
-
-        return success;
-    }
-
-    protected void fireDeletedCollection(String identifier) {
-        for (BackendListener listener: listeners) {
-            listener.deletedCollection(identifier, this);
-        }
-    }
-
-    public Document getCollectionAttribute(final String collectionId) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("collection id is not valid: " + collectionId);
-        }
-
-        final byte[][] data = new byte[1][1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_COLLECTION_GET_ATTRIBUTE);
-                stmnt.setString(1, collectionId);
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such collection.");
-                    return false;
-                }
-
-                data[0] = result.getBytes(1);
-                return true;
-            }
-        };
-
-        return exec.runRead()
-            ? XMLUtils.fromByteArray(data[0], true)
-            : null;
-    }
-
-    public boolean setCollectionAttribute(
-        final String   collectionId,
-        Document       attribute
-    ) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("collection id is not valid: " + collectionId);
-            return false;
-        }
-
-        final byte [] data = XMLUtils.toByteArray(attribute, true);
-
-        boolean success = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-
-                // set the column in collection items
-                prepareStatement(SQL_COLLECTION_SET_ATTRIBUTE);
-                if (data == null) {
-                    stmnt.setNull(1, Types.BINARY);
-                }
-                else {
-                    stmnt.setBytes(1, data);
-                }
-                stmnt.setString(2, collectionId);
-                stmnt.execute();
-                reset();
-
-                // touch the collection
-                prepareStatement(SQL_COLLECTIONS_TOUCH_BY_GID);
-                stmnt.setString(1, collectionId);
-                stmnt.execute();
-
-                conn.commit();
-                return true;
-            }
-        }.runWrite();
-
-        if (success) {
-            fireChangedCollectionAttribute(collectionId, attribute);
-        }
-
-        return success;
-    }
-
-    protected void fireChangedCollectionAttribute(
-        String   collectionId,
-        Document document
-    ) {
-        for (BackendListener listener: listeners) {
-            listener.changedCollectionAttribute(collectionId, document, this);
-        }
-    }
-
-    public Document getCollectionItemAttribute(
-        final String collectionId,
-        final String artifactId
-    ) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("collection id is not valid: " + collectionId);
-            return null;
-        }
-        if (!isValidIdentifier(artifactId)) {
-            logger.debug("artifact id is not valid: " + artifactId);
-            return null;
-        }
-
-        final byte [][] data = new byte[1][1];
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_COLLECTION_ITEM_GET_ATTRIBUTE);
-                stmnt.setString(1, collectionId);
-                stmnt.setString(2, artifactId);
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such collection item");
-                    return false;
-                }
-                data[0] = result.getBytes(1);
-                return true;
-            }
-        };
-
-        return exec.runRead()
-            ? XMLUtils.fromByteArray(data[0], true)
-            : null;
-    }
-
-    public boolean setCollectionItemAttribute(
-        final String   collectionId,
-        final String   artifactId,
-        Document       attribute
-    ) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("collection id is not valid: " + collectionId);
-            return false;
-        }
-        if (!isValidIdentifier(artifactId)) {
-            logger.debug("artifact id is not valid: " + artifactId);
-            return false;
-        }
-
-        final byte [] data = XMLUtils.toByteArray(attribute, true);
-
-        boolean success = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-
-                // set the column in collection items
-                prepareStatement(SQL_COLLECTION_ITEM_SET_ATTRIBUTE);
-                if (data == null) {
-                    stmnt.setNull(1, Types.BINARY);
-                }
-                else {
-                    stmnt.setBytes(1, data);
-                }
-                stmnt.setString(2, collectionId);
-                stmnt.setString(3, artifactId);
-                stmnt.execute();
-                reset();
-
-                // touch the collection
-                prepareStatement(SQL_COLLECTIONS_TOUCH_BY_GID);
-                stmnt.setString(1, collectionId);
-                stmnt.execute();
-
-                conn.commit();
-                return true;
-            }
-        }.runWrite();
-
-        if (success) {
-            fireChangedCollectionItemAttribute(
-                collectionId, artifactId, attribute);
-        }
-
-        return success;
-    }
-
-    protected void fireChangedCollectionItemAttribute(
-        String collectionId,
-        String artifactId,
-        Document document
-    ) {
-        for (BackendListener listener: listeners) {
-            listener.changedCollectionItemAttribute(
-                collectionId, artifactId, document, this);
-        }
-    }
-
-    public boolean addCollectionArtifact(
-        final String   collectionId,
-        final String   artifactId,
-        final Document attribute
-    ) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("Invalid collection id: '" + collectionId + "'");
-            return false;
-        }
-
-        if (!isValidIdentifier(artifactId)) {
-            logger.debug("Invalid artifact id: '" + artifactId + "'");
-            return false;
-        }
-
-        final byte [] data = XMLUtils.toByteArray(attribute, true);
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                // fetch artifact id
-                prepareStatement(SQL_GET_ID);
-                stmnt.setString(1, artifactId);
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such artifact: " + artifactId);
-                    return false;
-                }
-                int aid = result.getInt(1);
-                reset();
-
-                // fetch collection id
-                prepareStatement(SQL_COLLECTIONS_ID_BY_GID);
-                stmnt.setString(1, collectionId);
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such collection: " + collectionId);
-                }
-                int cid = result.getInt(1);
-                reset();
-
-                // check if artifact is already in collection
-                prepareStatement(SQL_COLLECTION_CHECK_ARTIFACT);
-                stmnt.setInt(1, aid);
-                stmnt.setInt(2, cid);
-                result = stmnt.executeQuery();
-                if (result.next()) {
-                    logger.debug("artifact already in collection");
-                    return false;
-                }
-                reset();
-
-                // fetch fresh id for new collection item
-                prepareStatement(SQL_COLLECTION_ITEMS_ID_NEXTVAL);
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("no collection item id generated");
-                    return false;
-                }
-                int ci_id = result.getInt(1);
-                reset();
-
-                // insert new collection item
-                prepareStatement(SQL_COLLECTION_ITEMS_INSERT);
-                stmnt.setInt(1, ci_id);
-                stmnt.setInt(2, cid);
-                stmnt.setInt(3, aid);
-
-                if (data == null) {
-                    stmnt.setNull(4, Types.BINARY);
-                }
-                else {
-                    stmnt.setBytes(4, data);
-                }
-                stmnt.execute();
-                conn.commit();
-
-                return true;
-            }
-        };
-        boolean success = exec.runWrite();
-
-        if (success) {
-            fireAddedArtifactToCollection(artifactId, collectionId);
-        }
-
-        return success;
-    }
-
-    protected void fireAddedArtifactToCollection(
-        String artifactId,
-        String collectionId
-    ) {
-        for (BackendListener listener: listeners) {
-            listener.addedArtifactToCollection(
-                artifactId, collectionId, this);
-        }
-    }
-
-    public boolean removeCollectionArtifact(
-        final String collectionId,
-        final String artifactId
-    ) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("Invalid collection id: '" + collectionId + "'");
-            return false;
-        }
-
-        boolean success = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-
-                // fetch id, collection id and artitfact id
-                prepareStatement(SQL_COLLECTION_ITEM_ID_CID_AID);
-                stmnt.setString(1, collectionId);
-                stmnt.setString(2, artifactId);
-                result = stmnt.executeQuery();
-                if (!result.next()) {
-                    logger.debug("No such collection item");
-                    return false;
-                }
-                int  id = result.getInt(1);
-                int cid = result.getInt(2);
-                int aid = result.getInt(3);
-                reset();
-
-                // outdate artifact iff it is only in this collection
-                prepareStatement(SQL_COLLECTION_ITEM_OUTDATE_ARTIFACT);
-                stmnt.setInt(1, aid);
-                stmnt.setInt(2, cid);
-                stmnt.setInt(3, aid);
-                stmnt.execute();
-                reset();
-
-                // delete collection item
-                prepareStatement(SQL_COLLECTION_ITEM_DELETE);
-                stmnt.setInt(1, id);
-                stmnt.execute();
-                reset();
-
-                // touch collection
-                prepareStatement(SQL_COLLECTIONS_TOUCH_BY_ID);
-                stmnt.setInt(1, cid);
-                stmnt.execute();
-
-                conn.commit();
-                return true;
-            }
-        }.runWrite();
-
-        if (success) {
-            fireRemovedArtifactFromCollection(artifactId, collectionId);
-        }
-
-        return success;
-    }
-
-    protected void fireRemovedArtifactFromCollection(
-        String artifactId,
-        String collectionId
-    ) {
-        for (BackendListener listener: listeners) {
-            listener.removedArtifactFromCollection(
-                artifactId, collectionId, this);
-        }
-    }
-
-    public CollectionItem [] listCollectionArtifacts(
-        final String collectionId
-    ) {
-        if (!isValidIdentifier(collectionId)) {
-            logger.debug("Invalid collection id: '" + collectionId + "'");
-            return null;
-        }
-
-        final ArrayList<CollectionItem> collectionItems =
-            new ArrayList<CollectionItem>();
-
-        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_COLLECTION_ITEMS_LIST_GID);
-                stmnt.setString(1, collectionId);
-                result = stmnt.executeQuery();
-                while (result.next()) {
-                    CollectionItem item = new DefaultCollectionItem(
-                        result.getString(1),
-                        result.getBytes(2));
-                    collectionItems.add(item);
-                }
-                return true;
-            }
-        };
-
-        return exec.runRead()
-            ? collectionItems.toArray(
-                new CollectionItem[collectionItems.size()])
-            : null;
-    }
-
-
-    public boolean setCollectionTTL(final String uuid, final Long ttl) {
-        if (!isValidIdentifier(uuid)) {
-            logger.debug("Invalid collection id: '" + uuid + "'");
-            return false;
-        }
-
-        return sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_UPDATE_COLLECTION_TTL);
-                if (ttl == null) {
-                    stmnt.setNull(1, Types.BIGINT);
-                }
-                else {
-                    stmnt.setLong(1, ttl);
-                }
-                stmnt.setString(2, uuid);
-                stmnt.execute();
-                conn.commit();
-
-                return true;
-            }
-        }.runWrite();
-    }
-
-
-    public boolean setCollectionName(final String uuid, final String name) {
-        if (!isValidIdentifier(uuid)) {
-            logger.debug("Invalid collection id: '" + uuid + "'");
-            return false;
-        }
-
-        boolean success = sqlExecutor.new Instance() {
-            public boolean doIt() throws SQLException {
-                prepareStatement(SQL_UPDATE_COLLECTION_NAME);
-                stmnt.setString(1, name);
-                stmnt.setString(2, uuid);
-                stmnt.execute();
-                conn.commit();
-
-                return true;
-            }
-        }.runWrite();
-
-        if (success) {
-            fireSetCollectionName(uuid, name);
-        }
-
-        return success;
-    }
-
-    protected void fireSetCollectionName(String identifier, String name) {
-        for (BackendListener listener: listeners) {
-            listener.setCollectionName(identifier, name);
-        }
-    }
-
-    public boolean loadAllArtifacts(final ArtifactLoadedCallback alc) {
-
-        logger.debug("loadAllArtifacts");
-
-        if (factoryLookup == null) {
-            logger.error("factory lookup == null");
-            return false;
-        }
-
-        boolean success = sqlExecutor.new Instance() {
-            @Override
-            public boolean doIt() throws SQLException {
-                // a little cache to avoid too much deserializations.
-                LRUCache<String, Artifact> alreadyLoaded =
-                    new LRUCache<String, Artifact>(200);
-
-                prepareStatement(SQL_ALL_ARTIFACTS);
-                result = stmnt.executeQuery();
-                while (result.next()) {
-                    String userId         = result.getString("u_gid");
-                    String collectionId   = result.getString("c_gid");
-                    String collectionName = result.getString("c_name");
-                    String artifactId     = result.getString("a_gid");
-                    String factoryName    = result.getString("factory");
-                    Date collectionCreated =
-                        new Date(result.getTimestamp("c_creation").getTime());
-                    Date artifactCreated =
-                        new Date(result.getTimestamp("a_creation").getTime());
-
-                    Artifact artifact = alreadyLoaded.get(artifactId);
-
-                    if (artifact != null) {
-                        alc.artifactLoaded(
-                            userId,
-                            collectionId, collectionName,
-                            collectionCreated,
-                            artifactId, artifactCreated, artifact);
-                        continue;
-                    }
-
-                    ArtifactFactory factory = factoryLookup
-                        .getArtifactFactory(factoryName);
-
-                    if (factory == null) {
-                        logger.error("factory '" + factoryName + "' not found");
-                        continue;
-                    }
-
-                    byte [] bytes = result.getBytes("data");
-
-                    artifact = factory.getSerializer().fromBytes(bytes);
-
-                    if (artifact != null) {
-                        alc.artifactLoaded(
-                            userId,
-                            collectionId, collectionName, collectionCreated,
-                            artifactId, artifactCreated, artifact);
-                    }
-
-                    alreadyLoaded.put(artifactId, artifact);
-                }
-                return true;
-            }
-        }.runRead();
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("loadAllArtifacts success: " + success);
-        }
-
-        return success;
-    }
-
-    @Override
-    public void killedArtifacts(List<String> identifiers) {
-        logger.debug("killedArtifacts");
-        for (BackendListener listener: listeners) {
-            listener.killedArtifacts(identifiers, this);
-        }
-    }
-
-    @Override
-    public void killedCollections(List<String> identifiers) {
-        logger.debug("killedCollections");
-        for (BackendListener listener: listeners) {
-            listener.killedCollections(identifiers, this);
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/BackendListener.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/BackendListener.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-package de.intevation.artifactdatabase;
-
-import java.util.List;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactCollection;
-import de.intevation.artifacts.GlobalContext;
-import de.intevation.artifacts.User;
-
-import org.w3c.dom.Document;
-
-public interface BackendListener
-{
-    void setup(GlobalContext globalContext);
-
-    void createdArtifact(Artifact artifact, Backend backend);
-
-    void storedArtifact(Artifact artifact, Backend backend);
-
-    void createdUser(User user, Backend backend);
-
-    void deletedUser(String identifier, Backend backend);
-
-    void createdCollection(ArtifactCollection collection, Backend backend);
-
-    void deletedCollection(String identifier, Backend backend);
-
-    void changedCollectionAttribute(
-        String   identifier,
-        Document document,
-        Backend  backend);
-
-    void changedCollectionItemAttribute(
-        String   collectionId,
-        String   artifactId,
-        Document document,
-        Backend  backend);
-
-    void addedArtifactToCollection(
-        String  artifactId,
-        String  collectionId,
-        Backend backend);
-
-    void removedArtifactFromCollection(
-        String  artifactId,
-        String  collectionId,
-        Backend backend);
-
-    void setCollectionName(
-        String collectionId,
-        String name);
-
-    void killedCollections(
-        List<String> identifiers,
-        Backend      backend);
-
-    void killedArtifacts(
-        List<String> identifiers,
-        Backend      backend);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/CollectionCallContext.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/CollectionCallContext.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.artifactdatabase;
-
-import java.util.LinkedList;
-
-import org.apache.log4j.Logger;
-
-import de.intevation.artifacts.ArtifactCollection;
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.Message;
-
-
-/**
- * Class that implements the call context handed to ArtifactCollection specific
- * operations.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class CollectionCallContext extends AbstractCallContext {
-
-    private static Logger log = Logger.getLogger(CollectionCallContext.class);
-
-    /**
-     * The ArtifactCollection.
-     */
-    protected ArtifactCollection collection;
-
-
-    public CollectionCallContext(
-        ArtifactDatabaseImpl artifactDatabase,
-        int                  action,
-        CallMeta             callMeta,
-        ArtifactCollection   collection)
-    {
-        super(artifactDatabase, action, callMeta);
-
-        this.collection = collection;
-    }
-
-
-    public void afterCall(int action) {
-        log.debug("CollectionCallContext.afterCall - NOT IMPLEMENTED");
-    }
-
-
-    public void afterBackground(int action) {
-        log.debug("CollectionCallContext.afterBackground - NOT IMPLEMENTED");
-    }
-
-
-    public boolean isInBackground() {
-        log.debug("CollectionCallContext.isInBackground - NOT IMPLEMENTED");
-        return false;
-    }
-
-
-    public void addBackgroundMessage(Message msg) {
-        log.debug("CollectionCallContext.addBackgroundMessage NOT IMPLEMENTED");
-    }
-
-
-    public LinkedList<Message> getBackgroundMessages() {
-        log.debug("CollectionCallContext.addBackgroundMessage NOT IMPLEMENTED");
-        return null;
-    }
-
-
-    public Long getTimeToLive() {
-        log.debug("CollectionCallContext.getTimeToLive - NOT IMPLEMENTED");
-        return null;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DBConfig.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DBConfig.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-package de.intevation.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import de.intevation.artifactdatabase.db.SQL;
-import de.intevation.artifactdatabase.db.DBConnection;
-
-public class DBConfig
-{
-    /**
-     * XPath to access the database driver within the global configuration.
-     */
-    public static final String DB_DRIVER =
-        "/artifact-database/database/driver/text()";
-    /**
-     * XPath to access the database URL within the global configuration.
-     */
-    public static final String DB_URL =
-        "/artifact-database/database/url/text()";
-    /**
-     * XPath to access the database use within the global configuration.
-     */
-    public static final String DB_USER =
-        "/artifact-database/database/user/text()";
-    /**
-     * XPath to access the database password within the global configuration.
-     */
-    public static final String DB_PASSWORD =
-        "/artifact-database/database/password/text()";
-
-    private static DBConfig instance;
-
-    private DBConnection dbConnection;
-    private SQL          sql;
-
-    private DBConfig() {
-    }
-
-    private DBConfig(DBConnection dbConnection, SQL sql) {
-        this.dbConnection = dbConnection;
-        this.sql          = sql;
-    }
-
-    public static synchronized DBConfig getInstance() {
-        if (instance == null) {
-            instance = createInstance();
-        }
-        return instance;
-    }
-
-    public SQL getSQL() {
-        return sql;
-    }
-
-    public DBConnection getDBConnection() {
-        return dbConnection;
-    }
-
-    private static DBConfig createInstance() {
-
-        String driver = Config.getStringXPath(
-            DB_DRIVER, DBConnection.DEFAULT_DRIVER);
-
-        String url = Config.getStringXPath(
-            DB_URL, DBConnection.DEFAULT_URL);
-
-        url = Config.replaceConfigDir(url);
-
-        String user = Config.getStringXPath(
-            DB_USER, DBConnection.DEFAULT_USER);
-
-        String password = Config.getStringXPath(
-            DB_PASSWORD, DBConnection.DEFAULT_PASSWORD);
-
-        DBConnection dbConnection = new DBConnection(
-            driver, url, user, password);
-
-        SQL sql = new SQL(driver);
-
-        return new DBConfig(dbConnection, sql);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,446 +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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.Config;
-import de.intevation.artifacts.common.utils.StringUtils;
-
-import de.intevation.artifacts.Artifact;
-
-import de.intevation.artifactdatabase.db.SQL;
-import de.intevation.artifactdatabase.db.DBConnection;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.Collections;
-
-import javax.sql.DataSource;
-
-import org.apache.log4j.Logger;
-
-/**
- * The database cleaner runs in background. It sleep for a configurable
- * while and when it wakes up it removes outdated artifacts from the
- * database. Outdated means that the the last access to the artifact
- * is longer aga then the time to live of this artifact.<br>
- * Before the artifact is finally removed from the system it is
- * revived one last time an the #endOfLife() method of the artifact
- * is called.<br>
- * The artifact implementations may e.g. use this to remove some extrenal
- * resources form the system.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DatabaseCleaner
-extends      Thread
-{
-    /**
-     * Implementors of this interface are able to create a
-     * living artifact from a given byte array.
-     */
-    public interface ArtifactReviver {
-
-        /**
-         * Called to revive an artifact from a given byte array.
-         * @param factoryName The name of the factory which
-         * created this artifact.
-         * @param bytes The bytes of the serialized artifact.
-         * @return The revived artfiact.
-         */
-        Artifact reviveArtifact(String factoryName, byte [] bytes);
-
-        void killedArtifacts(List<String> identifiers);
-        void killedCollections(List<String> identifiers);
-
-    } // interface ArtifactReviver
-
-    public interface LockedIdsProvider {
-        Set<Integer> getLockedIds();
-    } // interface LockedIdsProvider
-
-    private static Logger logger = Logger.getLogger(DatabaseCleaner.class);
-
-    /**
-     * Number of artifacts to be loaded at once. Used to
-     * mitigate the problem of a massive denial of service
-     * if too many artifacts have died since last cleanup.
-     */
-    public static final int MAX_ROWS = 50;
-
-    public static final Set<Integer> EMPTY_IDS = Collections.emptySet();
-
-    /**
-     * The SQL statement to select the outdated artifacts.
-     */
-    public String SQL_OUTDATED;
-
-    public String SQL_OUTDATED_COLLECTIONS;
-    public String SQL_DELETE_COLLECTION_ITEMS;
-    public String SQL_DELETE_COLLECTION;
-
-    /**
-     * The SQL statement to delete some artifacts from the database.
-     */
-    public String SQL_DELETE_ARTIFACT;
-
-    /**
-     * XPath to figure out how long the cleaner should sleep between
-     * cleanups. This is stored in the global configuration.
-     */
-    public static final String SLEEP_XPATH =
-        "/artifact-database/cleaner/sleep-time/text()";
-
-    /**
-     * Default nap time between cleanups: 5 minutes.
-     */
-    public static final long SLEEP_DEFAULT =
-        5 * 60 * 1000L; // 5 minutes
-
-    /**
-     * The configured nap time.
-     */
-    protected long sleepTime;
-
-    /**
-     * Internal locking mechanism to prevent some race conditions.
-     */
-    protected Object sleepLock = new Object();
-
-    /**
-     * A reference to the global context.
-     */
-    protected Object context;
-
-    /**
-     * A specialized Id filter which only delete some artifacts.
-     * This is used to prevent deletion of living artifacts.
-     */
-    protected LockedIdsProvider lockedIdsProvider;
-
-    /**
-     * The reviver used to bring the dead artifact on last
-     * time back to live to call endOfLife() on them.
-     */
-    protected ArtifactReviver reviver;
-
-    protected DBConnection dbConnection;
-
-    /**
-     * Default constructor.
-     */
-    public DatabaseCleaner() {
-    }
-
-    /**
-     * Constructor to create a cleaner with a given global context
-     * and a given reviver.
-     * @param context The global context of the artifact database
-     * @param reviver The reviver to awake artifact one last time.
-     */
-    public DatabaseCleaner(Object context, ArtifactReviver reviver, DBConfig config) {
-        setDaemon(true);
-        sleepTime = getSleepTime();
-        this.context = context;
-        this.reviver = reviver;
-        this.dbConnection = config.getDBConnection();
-        setupSQL(config.getSQL());
-    }
-
-    protected void setupSQL(SQL sql) {
-        SQL_OUTDATED                = sql.get("artifacts.outdated");
-        SQL_OUTDATED_COLLECTIONS    = sql.get("collections.outdated");
-        SQL_DELETE_COLLECTION_ITEMS = sql.get("delete.collection.items");
-        SQL_DELETE_COLLECTION       = sql.get("delete.collection");
-        SQL_DELETE_ARTIFACT         = sql.get("artifacts.delete");
-    }
-
-    /**
-     * Sets the filter that prevents deletion of living artifacts.
-     * Living artifacts are artifacts which are currently active
-     * inside the artifact database. Deleting them in this state
-     * would create severe internal problems.
-     */
-    public void setLockedIdsProvider(LockedIdsProvider lockedIdsProvider) {
-        this.lockedIdsProvider = lockedIdsProvider;
-    }
-
-    /**
-     * External hook to tell the cleaner to wake up before its
-     * regular nap time is over. This is the case when the artifact
-     * database finds an artifact which is already outdated.
-     */
-    public void wakeup() {
-        synchronized (sleepLock) {
-            sleepLock.notify();
-        }
-    }
-
-    /**
-     * Fetches the sleep time from the global configuration.
-     * @return the time to sleep between database cleanups in ms.
-     */
-    protected static long getSleepTime() {
-        String sleepTimeString = Config.getStringXPath(SLEEP_XPATH);
-
-        if (sleepTimeString == null) {
-            return SLEEP_DEFAULT;
-        }
-        try {
-            // sleep at least one second
-            return Math.max(Long.parseLong(sleepTimeString), 1000L);
-        }
-        catch (NumberFormatException nfe) {
-            logger.warn("Cleaner sleep time defaults to " + SLEEP_DEFAULT);
-        }
-        return SLEEP_DEFAULT;
-    }
-
-    private static class IdIdentifier {
-
-        int     id;
-        String  identifier;
-
-        private IdIdentifier(int id, String identifier) {
-            this.id         = id;
-            this.identifier = identifier;
-        }
-    } // class IdIdentifier
-
-    private static final class IdData
-    extends IdIdentifier
-    {
-        byte [] data;
-        String  factoryName;
-
-        public IdData(
-            int     id,
-            String  factoryName,
-            byte [] data,
-            String  identifier
-        ) {
-            super(id, identifier);
-            this.factoryName = factoryName;
-            this.data        = data;
-        }
-    } // class IdData
-
-    /**
-     * Cleaning is done in two phases. First we fetch a list of ids
-     * of artifacts. If there are artifacts the cleaning is done.
-     * Second we load the artifacts one by one one and call there
-     * endOfLife() method. In this loop we remove them from database, too.
-     * Each deletion is commited to ensure that a sudden failure
-     * of the artifact database server does delete artifacts twice
-     * or does not delete them at all. After this the first step
-     * is repeated.
-     */
-    protected void cleanup() {
-        logger.info("database cleanup");
-
-        Connection        connection = null;
-        PreparedStatement fetchIds   = null;
-        PreparedStatement stmnt      = null;
-        ResultSet         result     = null;
-
-        DataSource dataSource = dbConnection.getDataSource();
-
-        Set<Integer> lockedIds = lockedIdsProvider != null
-            ? lockedIdsProvider.getLockedIds()
-            : EMPTY_IDS;
-
-        String questionMarks = lockedIds.isEmpty()
-            ? "-666" // XXX: A bit hackish.
-            : StringUtils.repeat('?', lockedIds.size(), ',');
-
-        List<String> deletedCollections = new ArrayList<String>();
-        List<String> deletedArtifacts   = new ArrayList<String>();
-
-        try {
-            connection = dataSource.getConnection();
-            connection.setAutoCommit(false);
-
-            fetchIds = connection.prepareStatement(
-                SQL_OUTDATED.replace("$LOCKED_IDS$", questionMarks));
-
-            // some dbms like derby do not support LIMIT
-            // in SQL statements.
-            fetchIds.setMaxRows(MAX_ROWS);
-
-            // Fetch ids of outdated collections
-            stmnt = connection.prepareStatement(
-                SQL_OUTDATED_COLLECTIONS.replace(
-                    "$LOCKED_IDS$", questionMarks));
-
-            // fill in the locked ids
-            int idx = 1;
-            for (Integer id: lockedIds) {
-                fetchIds.setInt(idx, id);
-                stmnt   .setInt(idx, id);
-                ++idx;
-            }
-
-            ArrayList<IdIdentifier> cs = new ArrayList<IdIdentifier>();
-            result = stmnt.executeQuery();
-            while (result.next()) {
-                cs.add(new IdIdentifier(
-                    result.getInt(1),
-                    result.getString(2)));
-            }
-
-            result.close(); result = null;
-            stmnt.close();  stmnt  = null;
-
-            // delete collection items
-            stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION_ITEMS);
-
-            for (IdIdentifier id: cs) {
-                logger.debug("Mark collection for deletion: " + id.id);
-                stmnt.setInt(1, id.id);
-                stmnt.execute();
-            }
-
-            stmnt.close(); stmnt = null;
-
-            // delete collections
-            stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION);
-
-            for (IdIdentifier id: cs) {
-                stmnt.setInt(1, id.id);
-                stmnt.execute();
-                deletedCollections.add(id.identifier);
-            }
-
-            stmnt.close(); stmnt = null;
-            connection.commit();
-
-            cs = null;
-
-            // remove artifacts
-            stmnt = connection.prepareStatement(SQL_DELETE_ARTIFACT);
-
-            for (;;) {
-                List<IdData> ids = new ArrayList<IdData>();
-
-                result = fetchIds.executeQuery();
-
-                while (result.next()) {
-                    ids.add(new IdData(
-                        result.getInt(1),
-                        result.getString(2),
-                        result.getBytes(3),
-                        result.getString(4)));
-                }
-
-                result.close(); result = null;
-
-                if (ids.isEmpty()) {
-                    break;
-                }
-
-                for (int i = ids.size()-1; i >= 0; --i) {
-                    IdData idData = ids.get(i);
-                    Artifact artifact = reviver.reviveArtifact(
-                        idData.factoryName, idData.data);
-                    idData.data = null;
-
-                    logger.debug("Prepare Artifact (id="
-                        + idData.id + ") for deletion.");
-
-                    stmnt.setInt(1, idData.id);
-                    stmnt.execute();
-                    connection.commit();
-
-                    try {
-                        if (artifact != null) {
-                            logger.debug("Call endOfLife for Artifact: "
-                                + artifact.identifier());
-
-                            artifact.endOfLife(context);
-                        }
-                    }
-                    catch (Exception e) {
-                        logger.error(e.getMessage(), e);
-                    }
-
-                    deletedArtifacts.add(idData.identifier);
-                } // for all fetched data
-            }
-        }
-        catch (SQLException sqle) {
-            logger.error(sqle.getLocalizedMessage(), sqle);
-        }
-        finally {
-            if (result != null) {
-                try { result.close(); }
-                catch (SQLException sqle) {}
-            }
-            if (stmnt != null) {
-                try { stmnt.close(); }
-                catch (SQLException sqle) {}
-            }
-            if (fetchIds != null) {
-                try { fetchIds.close(); }
-                catch (SQLException sqle) {}
-            }
-            if (connection != null) {
-                try { connection.close(); }
-                catch (SQLException sqle) {}
-            }
-        }
-
-        if (!deletedCollections.isEmpty()) {
-            reviver.killedCollections(deletedCollections);
-        }
-
-        if (!deletedArtifacts.isEmpty()) {
-            reviver.killedArtifacts(deletedArtifacts);
-        }
-
-        if (logger.isDebugEnabled()) {
-            logger.debug(
-                "collections removed: " + deletedCollections.size());
-            logger.debug(
-                "artifacts removed: " + deletedArtifacts.size());
-        }
-    }
-
-    /**
-     * The main code of the cleaner. It sleeps for the configured
-     * nap time, cleans up the database, sleeps again and so on.
-     */
-    @Override
-    public void run() {
-        logger.info("sleep time: " + sleepTime + "ms");
-        for (;;) {
-            cleanup();
-            long startTime = System.currentTimeMillis();
-
-            try {
-                synchronized (sleepLock) {
-                    sleepLock.wait(sleepTime);
-                }
-            }
-            catch (InterruptedException ie) {
-            }
-
-            long stopTime = System.currentTimeMillis();
-
-            if (logger.isDebugEnabled()) {
-                logger.debug("Cleaner slept " + (stopTime - startTime) + "ms");
-            }
-        } // for (;;)
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.CallMeta;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-/**
- * Trivial implementation of an artifact. Useful to be subclassed.
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultArtifact
-implements   Artifact
-{
-    private static Logger logger = Logger.getLogger(DefaultArtifact.class);
-
-    /**
-     * The identifier of the artifact.
-     */
-    protected String identifier;
-
-
-    /**
-     * Default constructor.
-     */
-    public DefaultArtifact() {
-    }
-
-
-    public void setIdentifier(String identifier) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("Change identifier: "
-                + this.identifier + " -> " + identifier);
-        }
-        this.identifier = identifier;
-    }
-
-    public String identifier() {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.identifier: " + identifier);
-        }
-        return this.identifier;
-    }
-
-
-    public String hash() {
-        String hash = String.valueOf(hashCode());
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.hashCode: "
-                + identifier + " (" + hash + ")");
-        }
-        return hash;
-    }
-
-    public Document describe(Document data, CallContext context) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.describe: " + identifier);
-        }
-        return XMLUtils.newDocument();
-    }
-
-    public Document advance(Document target, CallContext context) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.advance: " + identifier);
-        }
-        return XMLUtils.newDocument();
-    }
-
-    public Document feed(Document target, CallContext context) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.feed: " + identifier);
-        }
-        return XMLUtils.newDocument();
-    }
-
-    public void out(
-        Document     format,
-        OutputStream out,
-        CallContext  context
-    )
-    throws IOException
-    {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.out: " + identifier);
-        }
-    }
-
-    public void out(
-        String       type,
-        Document     format,
-        OutputStream out,
-        CallContext  context
-    )
-    throws IOException
-    {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.out: " + identifier);
-        }
-    }
-
-    public void setup(String identifier,
-        ArtifactFactory factory,
-        Object          context,
-        CallMeta        callMeta,
-        Document        data)
-    {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.setup: " + identifier);
-        }
-        this.identifier = identifier;
-    }
-
-    public void endOfLife(Object context) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.endOfLife: " + identifier);
-        }
-    }
-
-    public void cleanup(Object context) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("DefaultArtifact.cleanup: " + identifier);
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,353 +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.artifactdatabase;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactCollection;
-import de.intevation.artifacts.ArtifactCollectionFactory;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.User;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-
-/**
- * Trivial implementation of an artifact collection. Useful to be subclassed.
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultArtifactCollection
-implements   ArtifactCollection
-{
-    /** The logger used in this class. */
-    private static Logger logger =
-        Logger.getLogger(DefaultArtifactCollection.class);
-
-    /** The identifier of the collection. */
-    protected String identifier;
-
-    /** The identifier of the collection. */
-    protected String name;
-
-    /** The owner of this collection. */
-    protected User user;
-
-    /** The attribute of this collection. */
-    protected Document attribute;
-
-    /** The artifacts stored in this collection. */
-    protected List<Artifact> artifacts;
-
-    /**
-     * The attributes used for the artifacts stored in this collection. The key
-     * of this map represents the identifier of the artifact which the attribute
-     * belong to.
-     */
-    protected Map<String, Document> attributes;
-
-    /** The creation time of this collection.*/
-    protected Date creationTime;
-
-    protected long ttl;
-
-
-    /**
-     * Default constructor.
-     */
-    public DefaultArtifactCollection() {
-    }
-
-
-    /**
-     * When created by a factory this method is called to
-     * initialize the collection.
-     * @param identifier The identifier from collection database
-     * @param factory    The factory which created this collection.
-     * @param context    The global context of the runtime system.
-     * @param data       The data which can be use to setup a collection with
-     *                   more details.
-     */
-    public void setup(
-        String                    identifier,
-        String                    name,
-        Date                      creationTime,
-        long                      ttl,
-        ArtifactCollectionFactory factory,
-        Object                    context,
-        Document                  data)
-    {
-        logger.debug("DefaultArtifactCollection.setup: " + identifier);
-
-        artifacts  = new ArrayList<Artifact>();
-        attributes = new HashMap<String, Document>();
-
-        setIdentifier(identifier);
-        setName(name);
-        setCreationTime(creationTime);
-        setTTL(ttl);
-        setAttribute(data);
-    }
-
-
-    public Document describe(CallContext context) {
-        logger.debug("DefaultArtifactCollection.describe: " + identifier);
-
-        return XMLUtils.newDocument();
-    }
-
-
-    /**
-     * Set a new identifier for this collection.
-     * @param identifier New identifier for this collection.
-     */
-    public void setIdentifier(String identifier) {
-        this.identifier = identifier;
-    }
-
-
-    /**
-     * Identify this collection.
-     * @return Returns unique string to identify this collection globally.
-     */
-    public String identifier() {
-        return identifier;
-    }
-
-
-    /**
-     * Name of this collection.
-     * @return Returns the name of this collection
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Name of this collection.
-     * @param name the name of this collection
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-
-    /**
-     * Set a new owner of this collection.
-     * @param user New owner for this collection.
-     */
-    public void setUser(User user) {
-        this.user = user;
-    }
-
-
-    /**
-     * Identify the owner of the collection.
-     * @return Returns owner of the collection.
-     */
-    public User getUser() {
-        return user;
-    }
-
-
-    /**
-     * Returns the creation time of the collection.
-     *
-     * @return the creation time of the collection.
-     */
-    public Date getCreationTime() {
-        return creationTime;
-    }
-
-
-    /**
-     * Sets the creation time of the collection.
-     *
-     * @param creationTime The new creation time.
-     */
-    public void setCreationTime(Date creationTime) {
-        this.creationTime = creationTime;
-    }
-
-
-    public long getTTL() {
-        return ttl;
-    }
-
-
-    public void setTTL(long ttl) {
-        this.ttl = ttl;
-    }
-
-
-    /**
-     * Returns the attribute of the collection.
-     *
-     * @return the attribute of the collection.
-     */
-    public Document getAttribute() {
-        return attribute;
-    }
-
-
-    /**
-     * Sets the attribute of the collection.
-     *
-     * @param attribute The attribute of this collection.
-     */
-    public void setAttribute(Document attribute) {
-        this.attribute = attribute;
-    }
-
-
-    /**
-     * Called from artifact database when an artifact is
-     * going to be removed from system.
-     * @param context The global context of the runtime system.
-     */
-    public void endOfLife(Object context) {
-        logger.debug("DefaultArtifactCollection.endOfLife");
-    }
-
-
-    /**
-     * Internal hash of this collection.
-     * @return Returns hash that should stay the same if the internal
-     *         value has not changed. Useful for caching
-     */
-    public String hash() {
-        logger.debug("DefaultArtifactCollection.hash");
-
-        return String.valueOf(hashCode());
-    }
-
-
-    /**
-     * Called from artifact database before an artifact is
-     * going to be exported as xml document.
-     * @param context The global context of the runtime system.
-     */
-    public void cleanup(Object context) {
-        logger.debug("DefaultArtifactCollection.cleanup");
-    }
-
-
-    /**
-     * Adds a new artifact to this collection.
-     *
-     * @param artifact The new artifact.
-     * @param attribute The attributes used for this artifact.
-     * @param context The CallContext.
-     */
-    public void addArtifact(
-        Artifact    artifact,
-        Document    attribute,
-        CallContext context)
-    {
-        logger.debug("DefaultArtifactCollection.addArtifact");
-
-        artifacts.add(artifact);
-        attributes.put(artifact.identifier(), attribute);
-    }
-
-
-    /**
-     * Removes the given artifact from this collection.
-     *
-     * @param artifact The artifact that should be removed.
-     * @param context The CallContext.
-     */
-    public void removeArtifact(Artifact artifact, CallContext context) {
-        logger.debug("DefaultArtifactCollection.removeArtifact");
-
-        if (artifact == null) {
-            return;
-        }
-
-        artifacts.remove(artifact);
-        attributes.remove(artifact.identifier());
-    }
-
-
-    /**
-     * Returns a list of artifacts that are stored in this collection.
-     *
-     * @param context The CallContext.
-     *
-     * @return the list of artifacts stored in this collection.
-     */
-    public Artifact[] getArtifacts(CallContext context) {
-        logger.debug("DefaultArtifactCollection.getArtifacts");
-
-        return (Artifact[]) artifacts.toArray();
-    }
-
-
-    /**
-     * Returns the attribute document for the given artifact.
-     *
-     * @param artifact The artifact.
-     * @param context The CallContext.
-     *
-     * @return a document that contains the attributes of the artifact.
-     */
-    public Document getAttribute(Artifact artifact, CallContext context) {
-        logger.debug("DefaultArtifactCollection.getAttribute");
-
-        return attributes.get(artifact.identifier());
-    }
-
-
-    /**
-     * Set the attribute for the given artifact.
-     *
-     * @param artifact The artifact of the attribute.
-     * @param document The new attribute of the artifact.
-     * @param context The CallContext.
-     */
-    public void setAttribute(
-        Artifact    artifact,
-        Document    document,
-        CallContext context)
-    {
-        logger.debug("DefaultArtifactCollection.setAttribute");
-
-        attributes.put(artifact.identifier(), document);
-    }
-
-
-    /**
-     * Produce output for this collection.
-     * @param type Specifies the output type.
-     * @param format Specifies the format of the output.
-     * @param out Stream to write the result data to.
-     * @param context The global context of the runtime system.
-     * @throws IOException Thrown if an I/O occurs.
-     */
-    public void out(
-        String       type,
-        Document     format,
-        OutputStream out,
-        CallContext  context)
-    throws IOException
-    {
-        logger.debug("DefaultArtifactCollection.out");
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-import de.intevation.artifacts.ArtifactCollection;
-import de.intevation.artifacts.ArtifactCollectionFactory;
-
-import java.util.Date;
-
-
-/**
- * The default implementation of a ArtifactCollectionFactory.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultArtifactCollectionFactory
-implements   ArtifactCollectionFactory
-{
-    /** The logger that is used in this factory.*/
-    private static Logger logger =
-        Logger.getLogger(DefaultArtifactCollectionFactory.class);
-
-    /** XPath to access the TTL of this artifact.*/
-    public static final String XPATH_TTL = "@ttl";
-
-    /** XPath to access the name of this factory.*/
-    public static final String XPATH_NAME = "@name";
-
-    /** XPath to access the description of this artifact factory.*/
-    public static final String XPATH_DESCRIPTION = "@description";
-
-    /**
-     * XPath to access the class name of the artifacts to be build
-     * by this factory.
-     */
-    public static final String XPATH_ARTIFACTCOLLECTION = "@artifact-collection";
-
-    /**
-     * Default description of this factory if none is given by the
-     * configuration.
-     */
-    public static final String DEFAULT_DESCRIPTION =
-        "No description available";
-
-    /**
-     * Class to load if no artifact class is given in the configuration.
-     */
-    public static final String DEFAULT_ARTIFACTCOLLECTION =
-        "de.intevation.artifactdatabase.DefaultArtifact";
-
-
-    /** The name of the factory.*/
-    protected String name;
-
-    /** The description of the factory.*/
-    protected String description;
-
-    /** The class that is used to instantiate new ArtifactCollection.*/
-    protected Class clazz;
-
-    /** The time to live of the artifact collection build by this factory.*/
-    protected Long ttl;
-
-
-    /**
-     * The default constructor.
-     */
-    public DefaultArtifactCollectionFactory() {
-    }
-
-
-   /**
-    * The short name of this factory.
-    *
-    * @return the name of this factory.
-    */
-    public String getName() {
-        return name;
-    }
-
-
-    /**
-     * Description of this factory.
-     *
-     * @return description of the factory.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-
-    /**
-     * Returns the time to live of the given artifact.
-     */
-    public Long timeToLiveUntouched(
-        ArtifactCollection collection,
-        Object             context)
-    {
-        return ttl;
-    }
-
-
-    /**
-     * Create a new artifact of certain type, given a general purpose context and
-     * an identifier.
-     * @param context a context from the ArtifactDatabase.
-     * @param identifier unique identifer for the new artifact
-     * @param data  the data containing more details for the setup of an Artifact.
-     * @return a new {@linkplain de.intevation.artifacts.ArtifactCollection ArtifactCollection}
-     */
-    public ArtifactCollection createCollection(
-        String   identifier,
-        String   name,
-        Date     creationTime,
-        long     ttl,
-        Document data,
-        Object   context
-    ) {
-        try {
-            ArtifactCollection collection =
-                (ArtifactCollection) clazz.newInstance();
-
-            collection.setup(identifier,
-                name,
-                creationTime,
-                ttl,
-                this,
-                context,
-                data);
-
-            return collection;
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-
-        return null;
-    }
-
-    /**
-     * Setup the factory with a given configuration
-     * @param config the configuration
-     * @param factoryNode the ConfigurationNode of this Factory
-     */
-    public void setup(Document config, Node factoryNode) {
-        String ttlString = Config.getStringXPath(factoryNode, XPATH_TTL);
-        if (ttlString != null) {
-            try {
-                ttl = Long.valueOf(ttlString);
-            }
-            catch (NumberFormatException nfe) {
-                logger.warn("'" + ttlString + "' is not an integer.");
-            }
-        }
-
-        description = Config.getStringXPath(
-            factoryNode, XPATH_DESCRIPTION, DEFAULT_DESCRIPTION);
-
-        name = Config.getStringXPath(factoryNode, XPATH_NAME, toString());
-
-        String artifactCollection = Config.getStringXPath(
-            factoryNode, XPATH_ARTIFACTCOLLECTION, DEFAULT_ARTIFACTCOLLECTION);
-
-        try {
-            clazz = Class.forName(artifactCollection);
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-
-        if (clazz == null) {
-            clazz = DefaultArtifactCollection.class;
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContext.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContext.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +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.artifactdatabase;
-
-import java.util.HashMap;
-
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.GlobalContext;
-
-/**
- * Default implementation of the context.
- * Besides of the configuration it hosts a map to store key/value pairs.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultArtifactContext implements GlobalContext
-{
-    /**
-     * The global configuration document of the artifact database.
-     */
-    protected Document config;
-
-    /**
-     * Custom key/value pairs to be used globally in the whole server.
-     */
-    protected HashMap map;
-
-    /**
-     * Default constructor
-     */
-    public DefaultArtifactContext() {
-        this(null);
-    }
-
-    /**
-     * Constructor to create a context with a given global
-     * configuration document and an empty map of custom
-     * key/value pairs.
-     * @param config
-     */
-    public DefaultArtifactContext(Document config) {
-        this.config = config;
-        map = new HashMap();
-    }
-
-    /**
-     * Fetch a custom value from the global key/value map using
-     * a given key.
-     * @param key The key.
-     * @return The stored value or null if no value was found under
-     * this key.
-     */
-    public synchronized Object get(Object key) {
-        return map.get(key);
-    }
-
-    /**
-     * Store a custom key/value pair in the global map.
-     * @param key The key to store
-     * @param value The value to store
-     * @return The old value registered under the key or null
-     * if none wa there before.
-     */
-    public synchronized Object put(Object key, Object value) {
-        return map.put(key, value);
-    }
-
-    /**
-     * Returns a reference to the global configuration document.
-     * @return The global configuration document.
-     */
-    public Document getConfig() {
-        return config;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContextFactory.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContextFactory.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +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.artifactdatabase;
-
-import de.intevation.artifacts.ArtifactContextFactory;
-import de.intevation.artifacts.GlobalContext;
-
-import org.w3c.dom.Document;
-
-/**
- * Default implementation of the context factory.
- * Creates a new @see DefaultArtifactContext.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultArtifactContextFactory
-implements   ArtifactContextFactory
-{
-    /**
-     * Default constructor.
-     */
-    public DefaultArtifactContextFactory() {
-    }
-
-    public GlobalContext createArtifactContext(Document config) {
-        return new DefaultArtifactContext(config);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactFactory.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactFactory.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.ArtifactSerializer;
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.GlobalContext;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-/**
- * Trivial implementation of the ArtifactFactory interface.
- * Time to live (ttl), name and description are configured
- * via the Node given to #setup(Document, Node) with attributes
- * of same name. The class name of the artifacts to be build by this
- * factory is configures with the attribute 'artifact'.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultArtifactFactory
-implements   ArtifactFactory
-{
-    private static Logger logger =
-        Logger.getLogger(DefaultArtifactFactory.class);
-
-    /**
-     * XPath to access the TTL of this artifact.
-     */
-    public static final String XPATH_TTL         = "@ttl";
-    /**
-     * XPath to access the name of this factory.
-     */
-    public static final String XPATH_NAME        = "@name";
-    /**
-     * XPath to access the description of this artifact factory.
-     */
-    public static final String XPATH_DESCRIPTION = "@description";
-    /**
-     * XPath to access the class name of the artifacts to be build
-     * by this factory.
-     */
-    public static final String XPATH_ARTIFACT    = "@artifact";
-
-    /**
-     * Default description of this factory if none is given by the
-     * configuration.
-     */
-    public static final String DEFAULT_DESCRIPTION =
-        "No description available";
-
-    /**
-     * Class to load if no artifact class is given in the configuration.
-     */
-    public static final String DEFAULT_ARTIFACT =
-        "de.intevation.artifactdatabase.DefaultArtifact";
-
-    /**
-     * The Time to live of the artifacts build by this factory.
-     */
-    protected Long   ttl;
-
-    /**
-     * The name of this factory.
-     */
-    protected String name;
-
-    /**
-     * The description of this factory.
-     */
-    protected String description;
-
-    /**
-     * The class of the artifacts to be build by this factory.
-     */
-    protected Class  artifactClass;
-
-    /**
-     * Default constructor.
-     */
-    public DefaultArtifactFactory() {
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public Artifact createArtifact(
-        String        identifier,
-        GlobalContext context,
-        CallMeta      callMeta,
-        Document      data
-    ) {
-        try {
-            Artifact artifact =
-                (Artifact)artifactClass.newInstance();
-
-            artifact.setup(identifier, this, context, callMeta, data);
-
-            return artifact;
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-
-        return null;
-    }
-
-    public void setup(Document document, Node factoryNode) {
-
-        String ttlString = Config.getStringXPath(factoryNode, XPATH_TTL);
-        if (ttlString != null) {
-            try {
-                ttl = Long.valueOf(ttlString);
-            }
-            catch (NumberFormatException nfe) {
-                logger.warn("'" + ttlString + "' is not an integer.");
-            }
-        }
-
-        description = Config.getStringXPath(
-            factoryNode, XPATH_DESCRIPTION, DEFAULT_DESCRIPTION);
-
-        name = Config.getStringXPath(
-            factoryNode, XPATH_NAME, toString());
-
-        String artifact = Config.getStringXPath(
-            factoryNode, XPATH_ARTIFACT, DEFAULT_ARTIFACT);
-
-        try {
-            artifactClass = Class.forName(artifact);
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-
-        if (artifactClass == null) {
-            artifactClass = DefaultArtifact.class;
-        }
-    }
-
-    public Long timeToLiveUntouched(Artifact artifact, Object context) {
-        return ttl;
-    }
-
-    public ArtifactSerializer getSerializer() {
-        return DefaultArtifactSerializer.INSTANCE;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactSerializer.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactSerializer.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +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.artifactdatabase;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactSerializer;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-import org.apache.log4j.Logger;
-
-/**
- * Default implementation of the ArtifactSerializer interface.
- * It uses serialized Java objects which are gzipped and
- * turned into bytes.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultArtifactSerializer
-implements   ArtifactSerializer
-{
-    private static Logger logger =
-        Logger.getLogger(DefaultArtifactSerializer.class);
-
-    /**
-     * Static instance to avoid repeated creation of Serializers.
-     */
-    public static final ArtifactSerializer INSTANCE =
-        new DefaultArtifactSerializer();
-
-    /**
-     * Default constructor.
-     */
-    public DefaultArtifactSerializer() {
-    }
-
-    public Artifact fromBytes(byte [] bytes) {
-
-        if (bytes == null) {
-            return null;
-        }
-
-        ObjectInputStream ois = null;
-
-        try {
-            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
-            GZIPInputStream      gis = new GZIPInputStream(bis);
-                                 ois = getObjectInputStream(gis);
-
-            return (Artifact)ois.readObject();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-        finally {
-            if (ois != null) {
-                try { ois.close(); }
-                catch (IOException ioe) { }
-            }
-        }
-
-        return null;
-    }
-
-    public byte [] toBytes(Artifact artifact) {
-        try {
-            ByteArrayOutputStream bos = new ByteArrayOutputStream();
-            GZIPOutputStream      gos = new GZIPOutputStream(bos);
-            ObjectOutputStream    oos = getObjectOutputStream(gos);
-
-            oos.writeObject(artifact);
-            oos.flush();
-            oos.close();
-
-            return bos.toByteArray();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-            throw new RuntimeException(ioe);
-        }
-    }
-
-    /**
-     * Wraps an input stream into an object input stream. You may
-     * overwrite this to get a more specialized deserializer.
-     * @param is The raw input stream
-     * @return An instance of a subclass of ObjectInputStream.
-     * @throws IOException Thrown if something went wrong during
-     * creation of the object input stream.
-     */
-    protected ObjectInputStream getObjectInputStream(InputStream is)
-    throws    IOException
-    {
-        return new ObjectInputStream(is);
-    }
-
-    /**
-     * Wraps an output stream into an object output stream. You may
-     * overwrite this to get a more specialized serializer.
-     * @param os the raw output stream.
-     * @return An instance of a subclass of ObjectOutputStream.
-     * @throws IOException Thrown if something went wrong during
-     * creation of the object output stream.
-     */
-    protected ObjectOutputStream getObjectOutputStream(OutputStream os)
-    throws    IOException
-    {
-        return new ObjectOutputStream(os);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultBackendListener.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultBackendListener.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-package de.intevation.artifactdatabase;
-
-import java.util.List;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactCollection;
-import de.intevation.artifacts.GlobalContext;
-import de.intevation.artifacts.User;
-
-import org.w3c.dom.Document;
-
-import org.apache.log4j.Logger;
-
-public class DefaultBackendListener
-implements   BackendListener
-{
-    private static Logger log = Logger.getLogger(DefaultBackendListener.class);
-
-    public DefaultBackendListener() {
-    }
-
-    @Override
-    public void setup(GlobalContext globalContext) {
-        log.debug("setup");
-    }
-
-    @Override
-    public void createdArtifact(Artifact artifact, Backend backend) {
-        log.debug("createdArtifact");
-    }
-
-    @Override
-    public void storedArtifact(Artifact artifact, Backend backend) {
-        log.debug("storedArtifact");
-    }
-
-    @Override
-    public void createdUser(User user, Backend backend) {
-        log.debug("createdUser");
-    }
-
-    @Override
-    public void deletedUser(String identifier, Backend backend) {
-        log.debug("deletedUser");
-    }
-
-    @Override
-    public void createdCollection(
-        ArtifactCollection collection,
-        Backend            backend
-    ) {
-        log.debug("createdCollection");
-    }
-
-    @Override
-    public void deletedCollection(String identifier, Backend backend) {
-        log.debug("deletedCollection");
-    }
-
-    @Override
-    public void changedCollectionAttribute(
-        String   identifier,
-        Document document,
-        Backend  backend
-    ) {
-        log.debug("changedCollectionAttribute");
-    }
-
-    @Override
-    public void changedCollectionItemAttribute(
-        String   collectionId,
-        String   artifactId,
-        Document document,
-        Backend  backend
-    ) {
-        log.debug("changedCollectionItemAttribute");
-    }
-
-    @Override
-    public void addedArtifactToCollection(
-        String  artifactId,
-        String  collectionId,
-        Backend backend
-    ) {
-        log.debug("addedArtifactToCollection");
-    }
-
-    @Override
-    public void removedArtifactFromCollection(
-        String  artifactId,
-        String  collectionId,
-        Backend backend
-    ) {
-        log.debug("removedArtifactFromCollection");
-    }
-
-    @Override
-    public void setCollectionName(
-        String collectionId,
-        String name
-    ) {
-        log.debug("setCollectionName");
-    }
-
-    @Override
-    public void killedCollections(List<String> identifiers, Backend backend) {
-        log.debug("killedCollections");
-    }
-
-    @Override
-    public void killedArtifacts(List<String> identifiers, Backend backend) {
-        log.debug("killedArtifacts");
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
-
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultCallMeta.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultCallMeta.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +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.artifactdatabase;
-
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.PreferredLocale;
-
-import java.util.Locale;
-
-/**
- * Default implementation of CallMeta. It provides a list of
- * preferred langauages and implements an intersection mechanism
- * to figure out the best matching language given a list of server
- * provided languages.
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultCallMeta
-implements   CallMeta
-{
-    /**
-     * The list of preferred languages.
-     */
-    protected PreferredLocale [] languages;
-
-    /**
-     * Default constructor.
-     */
-    public DefaultCallMeta() {
-    }
-
-    /**
-     * Creates new DefaultCallMeta with a given list of languages.
-     * @param languages The list of preferred languages.
-     */
-    public DefaultCallMeta(PreferredLocale [] languages) {
-        this.languages = languages;
-    }
-
-    public PreferredLocale [] getLanguages() {
-        return languages;
-    }
-
-    public Locale getPreferredLocale(Locale [] locales) {
-        if (locales == null || locales.length == 0) {
-            return null;
-        }
-
-        Locale best    = null;
-        float  quality = -Float.MAX_VALUE;
-
-        for (int i = 0; i < locales.length; ++i) {
-            Locale wish         = locales[i];
-            String wishLanguage = wish.getLanguage();
-
-            for (int j = 0; j < languages.length; ++j) {
-                PreferredLocale have        = languages[j];
-                Locale          haveLocale  = have.getLocale();
-                if (haveLocale.getLanguage().equals(wishLanguage)) {
-                    float haveQuality = have.getQuality();
-                    if (haveQuality > quality) {
-                        quality = haveQuality;
-                        best    = wish;
-                    }
-                    break; // Languages should not contain
-                           // same locale twice.
-                }
-            }
-        }
-
-        return best == null
-            ? locales[0]
-            : best;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultCollectionItem.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultCollectionItem.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +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.artifactdatabase;
-
-import de.intevation.artifacts.CollectionItem;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import org.w3c.dom.Document;
-
-public class DefaultCollectionItem
-implements   CollectionItem
-{
-    protected String artifactIdentifier;
-
-    protected byte [] data;
-
-    protected Document document;
-
-    public DefaultCollectionItem() {
-    }
-
-    public DefaultCollectionItem(String artifactIdentifier, byte [] attribute) {
-        this.artifactIdentifier = artifactIdentifier;
-        this.data               = attribute;
-    }
-
-    public String getArtifactIdentifier() {
-        return artifactIdentifier;
-    }
-
-    public synchronized Document getAttribute() {
-        if (document == null) {
-            if (data != null) {
-                document = XMLUtils.fromByteArray(data, true);
-            }
-        }
-        return document;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultPreferredLocale.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultPreferredLocale.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +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.artifactdatabase;
-
-import de.intevation.artifacts.PreferredLocale;
-
-import java.util.Locale;
-
-/**
- * Models a pair of Locale and quality (0.0-1.0) to be used to
- * find best matching locale between server offerings and clients requests.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultPreferredLocale
-implements   PreferredLocale
-{
-    /**
-     * The locale of this tuple pair.
-     */
-    protected Locale locale;
-    /**
-     * The quality of this tuple pair between 0.0 and 1.0.
-     */
-    protected float  quality;
-
-    /**
-     * Default constructor
-     */
-    public DefaultPreferredLocale() {
-    }
-
-    /**
-     * Constructor to build a pair of given a locale speficied by
-     * string 'lang' and an given 'quality'.
-     * @param lang The name of the locale.
-     * @param quality The quality of the locale.
-     */
-    public DefaultPreferredLocale(String lang, float quality) {
-        locale = new Locale(lang);
-        this.quality = quality;
-    }
-
-    public Locale getLocale() {
-        return locale;
-    }
-
-    public float getQuality() {
-        return quality;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultService.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultService.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +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.artifactdatabase;
-
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.Service;
-import de.intevation.artifacts.GlobalContext;
-import de.intevation.artifacts.ServiceFactory;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-/**
- * Trivial implementation of an artifact database service. Useful to
- * be subclassed.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultService
-implements   Service
-{
-    private static Logger logger = Logger.getLogger(DefaultService.class);
-
-    public static class Output implements Service.Output {
-
-        protected Object data;
-        protected String mimeType;
-
-        public Output() {
-        }
-
-        public Output(Object data, String mimeType) {
-            this.data     = data;
-            this.mimeType = mimeType;
-        }
-
-        @Override
-        public Object getData() {
-            return data;
-        }
-
-        @Override
-        public String getMIMEType() {
-            return mimeType;
-        }
-    } // class Output
-
-    @Override
-    public Service.Output process(
-        Document      data,
-        GlobalContext globalContext,
-        CallMeta      callMeta
-    ) {
-        logger.debug("Service.process");
-        return new Output(new byte[0], "application/octet-stream");
-    }
-
-    @Override
-    public void setup(ServiceFactory factory, GlobalContext globalContext) {
-        logger.debug("Service.setup");
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultServiceFactory.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultServiceFactory.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import de.intevation.artifacts.Service;
-import de.intevation.artifacts.GlobalContext;
-import de.intevation.artifacts.ServiceFactory;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-/**
- * Trivial implementation of the ServiceFactory interface.
- * Name and an description are configured by the given Node given to
- * #setup(Document, Node) via the 'name' and 'description' attributes.
- * The name of the class that provides the concrete serice is configured
- * by the 'service' attribute.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class DefaultServiceFactory
-implements   ServiceFactory
-{
-    private static Logger logger =
-        Logger.getLogger(DefaultServiceFactory.class);
-
-    /**
-     * XPath to access the name of the service.
-     */
-    public static final String XPATH_NAME        = "@name";
-    /**
-     * XPath to access the description of the service.
-     */
-    public static final String XPATH_DESCRIPTION = "@description";
-    /**
-     * XPath to access the class name of the service to be build by
-     * this factory.
-     */
-    public static final String XPATH_SERVICE     = "@service";
-
-    /**
-     * Default description if no description is given in configuration.
-     */
-    public static final String DEFAULT_DESCRIPTION =
-        "No description available";
-
-    /**
-     * Loaded service class if no class name is given in the configuration.
-     */
-    public static final String DEFAULT_SERVICE =
-        "de.intevation.artifactdatabase.DefaultService";
-
-    /**
-     * The name of the service factory.
-     */
-    protected String name;
-
-    /**
-     * The description of the service factory.
-     */
-    protected String description;
-
-    /**
-     * The loaded class used to build the concrete service.
-     */
-    protected Class  serviceClass;
-
-    /**
-     * Default constructor.
-     */
-    public DefaultServiceFactory() {
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-
-    @Override
-    public Service createService(GlobalContext globalContext) {
-        try {
-            Service service = (Service)serviceClass.newInstance();
-
-            service.setup(this, globalContext);
-
-            return service;
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-
-        return null;
-    }
-
-    @Override
-    public void setup(Document config, Node factoryNode) {
-
-        description = Config.getStringXPath(
-            factoryNode, XPATH_DESCRIPTION, DEFAULT_DESCRIPTION);
-
-        name = Config.getStringXPath(
-            factoryNode, XPATH_NAME, toString());
-
-        String service = Config.getStringXPath(
-            factoryNode, XPATH_SERVICE, DEFAULT_SERVICE);
-
-        try {
-            serviceClass = Class.forName(service);
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-
-        if (serviceClass == null) {
-            serviceClass = DefaultService.class;
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUser.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUser.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +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.artifactdatabase;
-
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.User;
-
-
-/**
- * Trivial implementation of a user. Useful to be subclassed.
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultUser
-implements   User
-{
-    /** The identifier of the user.*/
-    protected String identifier;
-
-    /** The name of the user.*/
-    protected String name;
-
-    /** The account name of the user.*/
-    protected String account;
-
-    /** The role of the user.*/
-    protected Document role;
-
-
-    /**
-     * The default constructor.
-     */
-    public DefaultUser() {
-    }
-
-    public DefaultUser(String identifier) {
-        this.identifier = identifier;
-    }
-
-    /**
-     * A constructor that creates a new user.
-     *
-     * @param identifier The uuid of the user.
-     * @param name The name of the user.
-     * @param account The account name of the user.
-     * @param role The role of the user.
-     */
-    public DefaultUser(String identifier, String name, String account,
-                       Document role) {
-        this.identifier = identifier;
-        this.name       = name;
-        this.role       = role;
-        this.account    = account;
-    }
-
-
-    /**
-     * Returns the identifier of this user.
-     *
-     * @return the identifier of this user.
-     */
-    @Override
-    public String identifier() {
-        return identifier;
-    }
-
-
-    /**
-     * Returns the name of the user.
-     *
-     * @return the name of the user.
-     */
-    @Override
-    public String getName() {
-        return name;
-    }
-
-
-    /**
-     * Set the name of the user.
-     *
-     * @param name The name for this user.
-     */
-    @Override
-    public void setName(String name) {
-        this.name = name;
-    }
-
-
-    /**
-     * Set the identifier of the user.
-     *
-     * @param identifier The new identifier.
-     */
-    @Override
-    public void setIdentifier(String identifier) {
-        this.identifier = identifier;
-    }
-
-
-    /**
-     * Set the role of the user.
-     *
-     * @param role The new role of the user.
-     */
-    @Override
-    public void setRole(Document role) {
-        this.role = role;
-    }
-
-
-    /**
-     * Returns the role of the user.
-     *
-     * @return the role of the user.
-     */
-    @Override
-    public Document getRole() {
-        return role;
-    }
-
-    /**
-     * Returns the account of the user.
-     *
-     * @return the account name of the user.
-     */
-    @Override
-    public String getAccount() {
-        return account;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUserFactory.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUserFactory.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +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.artifactdatabase;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-import de.intevation.artifacts.User;
-import de.intevation.artifacts.UserFactory;
-
-
-/**
- * Default implementation of a UserFactory.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultUserFactory
-implements   UserFactory
-{
-    /** The logger that is used in this factory.*/
-    private static Logger logger = Logger.getLogger(DefaultUserFactory.class);
-
-
-    /**
-     * Default constructor.
-     */
-    public DefaultUserFactory() {
-    }
-
-
-    public void setup(Document config, Node factoryNode) {
-        logger.debug("DefaultUserFactory.setup");
-    }
-
-
-    /**
-     * This method creates a new DefaultUser with the given identifier, name and
-     * role.
-     *
-     * @param identifier The identifier for the new user.
-     * @param name The name for the new user.
-     * @param account The name of the new users account.
-     * @param role The role for the new user.
-     * @param context The CallContext.
-     */
-    public User createUser(
-        String   identifier,
-        String   name,
-        String   account,
-        Document role,
-        Object   context)
-    {
-        logger.debug("DefaultUserFactory.createUser: " + name);
-        return new DefaultUser(identifier, name, account, role);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,733 +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.artifactdatabase;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import de.intevation.artifacts.ArtifactCollectionFactory;
-import de.intevation.artifacts.ArtifactContextFactory;
-import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.GlobalContext;
-import de.intevation.artifacts.Hook;
-import de.intevation.artifacts.ServiceFactory;
-import de.intevation.artifacts.UserFactory;
-
-import de.intevation.artifacts.common.utils.StringUtils;
-
-import de.intevation.artifactdatabase.rest.HTTPServer;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * Bootstrap facility for the global context and the artifact factories.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class FactoryBootstrap
-{
-    private static Logger logger = Logger.getLogger(FactoryBootstrap.class);
-
-    /**
-     * XPath to figure out the class name of the context factory from
-     * the global configuration.
-     */
-    public static final String CONTEXT_FACTORY =
-        "/artifact-database/factories/context-factory/text()";
-
-    /**
-     * The name of the default context factory.
-     */
-    public static final String DEFAULT_CONTEXT_FACTORY =
-        "de.intevation.artifactdatabase.DefaultArtifactContextFactory";
-
-    /**
-     * XPath to figure out the names of the artifact factories from
-     * the global configuration to be exposed by the artifact database.
-     */
-    public static final String ARTIFACT_FACTORIES =
-        "/artifact-database/factories/artifact-factories/artifact-factory";
-
-    /**
-     * XPath to figure out the names of the service factories from
-     * the global configuration to build the services offered by the
-     * artifact database.
-     */
-    public static final String SERVICE_FACTORIES =
-        "/artifact-database/factories/service-factories/service-factory";
-
-    /**
-     * XPath to figure out the class name of the user factory from global
-     * configuration.
-     */
-    public static final String USER_FACTORY =
-        "/artifact-database/factories/user-factory";
-
-    /**
-     * The name of the default user factory.
-     */
-    public static final String DEFAULT_USER_FACTORY =
-        "de.intevation.artifactdatabase.DefaultUserFactory";
-
-    /**
-     * XPath to figure out the class name of the collection factory from global
-     * configuration.
-     */
-    public static final String COLLECTION_FACTORY =
-        "/artifact-database/factories/collection-factory";
-
-    /**
-     * The name of the default user factory.
-     */
-    public static final String DEFAULT_COLLECTION_FACTORY =
-        "de.intevation.artifactdatabase.DefaultArtifactCollectionFactory";
-
-    /**
-     * XPath to figure out the secret used to sign the artifact exports
-     * made by the artfifact database server.
-     */
-    public static final String EXPORT_SECRET =
-        "/artifact-database/export-secret/text()";
-
-    /**
-     * XPAth that points to a configuration node for a CallContext.Listener.
-     */
-    public static final String CALLCONTEXT_LISTENER =
-        "/artifact-database/callcontext-listener";
-
-    /**
-     * XPath that points to configuration nodes for hooks.
-     */
-    public static final String HOOKS =
-        "/artifact-database/hooks/hook";
-
-    public static final String HTTP_SERVER =
-        "/artifact-database/rest-server/http-server/text()";
-
-    public static final String DEFAULT_HTTP_SERVER =
-        "de.intevation.artifactdatabase.rest.Standalone";
-
-    public static final String LIFETIME_LISTENERS =
-        "/artifact-database/lifetime-listeners/listener";
-
-    public static final String BACKEND_LISTENERS =
-        "/artifact-database/backend-listeners/listener";
-
-    /**
-     * Default export signing secret.
-     * <strong>PLEASE CHANGE THE SECRET VIA THE XPATH EXPORT_SECRET
-     * IN THE CONFIGURATION.</strong>.
-     */
-    public static final String DEFAULT_EXPORT_SECRET =
-        "!!!CHANGE ME! I'M NO SECRET!!!";
-
-    /**
-     * Reference to the global context build by the global context factory.
-     */
-    protected GlobalContext context;
-
-    /**
-     * List of the artifact factories to be exposed by the
-     * artifact database.
-     */
-    protected ArtifactFactory [] artifactFactories;
-
-    /**
-     * List of service factories which creates services that are
-     * exposed by the artifact database.
-     */
-    protected ServiceFactory [] serviceFactories;
-
-    /**
-     * The factory that is used to create and list users.
-     */
-    protected UserFactory userFactory;
-
-    /**
-     * The factory that is used to create new artifact collections.
-     */
-    protected ArtifactCollectionFactory collectionFactory;
-
-    /**
-     * The CallContext.Listener.
-     */
-    protected CallContext.Listener callContextListener;
-
-    protected List<Hook> postFeedHooks;
-
-    protected List<Hook> postAdvanceHooks;
-
-    protected List<Hook> postDescribeHooks;
-
-    protected List<LifetimeListener> lifetimeListeners;
-
-    protected List<BackendListener> backendListeners;
-
-    /**
-     * byte array holding the export signing secret.
-     */
-    protected byte [] exportSecret;
-
-    protected HTTPServer httpServer;
-
-
-    /**
-     * Default constructor
-     */
-    public FactoryBootstrap() {
-    }
-
-    void buildContext() {
-        String className = Config.getStringXPath(
-            CONTEXT_FACTORY, DEFAULT_CONTEXT_FACTORY);
-
-        ArtifactContextFactory factory = null;
-
-        try {
-            Class clazz = Class.forName(className);
-            factory = (ArtifactContextFactory)clazz.newInstance();
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-
-        if (factory == null) {
-            factory = new DefaultArtifactContextFactory();
-        }
-
-        logger.info("Using class '" + factory.getClass().getName()
-            + "' for context creation.");
-
-        context = factory.createArtifactContext(Config.getConfig());
-    }
-
-
-    /**
-     * Scans the global configuration to load the configured collection factory
-     * and sets it up.
-     */
-    protected void loadCollectionFactory() {
-
-        logger.info("loading collection factory.");
-
-        Node factory = Config.getNodeXPath(COLLECTION_FACTORY);
-
-        String className = Config.getStringXPath(
-            factory, "text()", DEFAULT_COLLECTION_FACTORY);
-
-        try {
-            Class clazz       = Class.forName(className);
-            collectionFactory = (ArtifactCollectionFactory) clazz.newInstance();
-
-            collectionFactory.setup(Config.getConfig(), factory);
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-    }
-
-    /**
-     * Scans the global configuration to load the configured
-     * artifact factories and sets them up.
-     */
-    protected void loadArtifactFactories() {
-
-        logger.info("loading artifact factories");
-
-        ArrayList loadedFactories = new ArrayList();
-
-        NodeList nodes = Config.getNodeSetXPath(ARTIFACT_FACTORIES);
-
-        if (nodes == null) {
-            logger.warn("No factories found");
-        }
-
-        Document config = Config.getConfig();
-
-        for (int i = 0, N = nodes != null ? nodes.getLength() : 0; i < N; ++i) {
-            String className = nodes.item(i).getTextContent().trim();
-
-            ArtifactFactory factory = null;
-
-            try {
-                Class clazz = Class.forName(className);
-                factory = (ArtifactFactory)clazz.newInstance();
-            }
-            catch (ClassNotFoundException cnfe) {
-                logger.error(cnfe.getLocalizedMessage(), cnfe);
-            }
-            catch (InstantiationException ie) {
-                logger.error(ie.getLocalizedMessage(), ie);
-            }
-            catch (ClassCastException cce) {
-                logger.error(cce.getLocalizedMessage(), cce);
-            }
-            catch (IllegalAccessException iae) {
-                logger.error(iae.getLocalizedMessage(), iae);
-            }
-
-            if (factory != null) {
-                factory.setup(config, nodes.item(i));
-                loadedFactories.add(factory);
-                logger.info("Registering '"
-                    + factory.getName() + "' as artifact factory.");
-            }
-        }
-
-        artifactFactories = (ArtifactFactory [])loadedFactories.toArray(
-            new ArtifactFactory[loadedFactories.size()]);
-    }
-
-    /**
-     * Scans the global configuration for the configured service factories
-     * and sets them up.
-     */
-    protected void loadServiceFactories() {
-
-        logger.info("loading service factories");
-
-        ArrayList loadedFactories = new ArrayList();
-
-        NodeList nodes = Config.getNodeSetXPath(SERVICE_FACTORIES);
-
-        if (nodes == null) {
-            logger.warn("No factories found");
-        }
-
-        Document config = Config.getConfig();
-
-        for (int i = 0, N = nodes != null ? nodes.getLength() : 0; i < N; ++i) {
-            String className = nodes.item(i).getTextContent().trim();
-
-            ServiceFactory factory = null;
-
-            try {
-                Class clazz = Class.forName(className);
-                factory = (ServiceFactory)clazz.newInstance();
-            }
-            catch (ClassNotFoundException cnfe) {
-                logger.error(cnfe.getLocalizedMessage(), cnfe);
-            }
-            catch (InstantiationException ie) {
-                logger.error(ie.getLocalizedMessage(), ie);
-            }
-            catch (ClassCastException cce) {
-                logger.error(cce.getLocalizedMessage(), cce);
-            }
-            catch (IllegalAccessException iae) {
-                logger.error(iae.getLocalizedMessage(), iae);
-            }
-
-            if (factory != null) {
-                factory.setup(config, nodes.item(i));
-                loadedFactories.add(factory);
-                logger.info( "Registering '" + factory.getName()
-                    + "' as service factory.");
-            }
-        }
-
-        serviceFactories = (ServiceFactory [])loadedFactories.toArray(
-            new ServiceFactory[loadedFactories.size()]);
-    }
-
-
-    /**
-     * Scans the global configuration for the configured user factory.
-     */
-    protected void loadUserFactory() {
-        logger.info("loading user factory");
-
-        Node factory = Config.getNodeXPath(USER_FACTORY);
-
-        String className = Config.getStringXPath(
-            factory, "text()", DEFAULT_USER_FACTORY);
-
-        try {
-            Class clazz = Class.forName(className);
-            userFactory = (UserFactory) clazz.newInstance();
-
-            userFactory.setup(Config.getConfig(), factory);
-        }
-        catch (ClassNotFoundException cnfe) {
-                logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-    }
-
-
-    protected void loadCallContextListener() {
-        logger.info("loading CallContext.Listener");
-
-        Node listener = Config.getNodeXPath(CALLCONTEXT_LISTENER);
-
-        if (listener == null) {
-            return;
-        }
-
-        String className = Config.getStringXPath(listener, "text()");
-
-        try {
-            Class clazz         = Class.forName(className);
-            callContextListener = (CallContext.Listener) clazz.newInstance();
-
-            callContextListener.setup(Config.getConfig(), listener);
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-    }
-
-    protected void loadHTTPServer() {
-        logger.info("loading HTTPServer");
-
-        String className = Config.getStringXPath(
-            HTTP_SERVER, DEFAULT_HTTP_SERVER);
-
-        logger.info("using HTTP server: " + className);
-
-        try {
-            Class clazz = Class.forName(className);
-            httpServer  = (HTTPServer)clazz.newInstance();
-
-            httpServer.setup(Config.getConfig());
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-    }
-
-    protected void loadLifetimeListeners() {
-        logger.info("loading lifetime listeners");
-
-        NodeList nodes = Config.getNodeSetXPath(LIFETIME_LISTENERS);
-
-        if (nodes == null) {
-            logger.debug("no lifetime listeners configure");
-            return;
-        }
-
-        List<LifetimeListener> ltls = new ArrayList<LifetimeListener>();
-
-        for (int i = 0, N = nodes.getLength(); i < N; ++i) {
-            Node node = nodes.item(i);
-            String className = node.getTextContent();
-            if (className == null
-            || (className = className.trim()).length() == 0) {
-                continue;
-            }
-            try {
-                Class clazz = Class.forName(className);
-                LifetimeListener listener =
-                    (LifetimeListener)clazz.newInstance();
-
-                listener.setup(Config.getConfig());
-
-                ltls.add(listener);
-            }
-            catch (ClassNotFoundException cnfe) {
-                logger.error(cnfe.getLocalizedMessage(), cnfe);
-            }
-            catch (InstantiationException ie) {
-                logger.error(ie.getLocalizedMessage(), ie);
-            }
-            catch (ClassCastException cce) {
-                logger.error(cce.getLocalizedMessage(), cce);
-            }
-            catch (IllegalAccessException iae) {
-                logger.error(iae.getLocalizedMessage(), iae);
-            }
-        }
-
-        lifetimeListeners = ltls;
-    }
-
-    protected void loadBackendListeners() {
-        logger.info("loading backend listeners");
-
-        NodeList nodes = Config.getNodeSetXPath(BACKEND_LISTENERS);
-
-        if (nodes == null) {
-            logger.debug("no backend listeners configure");
-            return;
-        }
-
-        List<BackendListener> bls = new ArrayList<BackendListener>();
-
-        for (int i = 0, N = nodes.getLength(); i < N; ++i) {
-            Node node = nodes.item(i);
-            String className = node.getTextContent();
-            if (className == null
-            || (className = className.trim()).length() == 0) {
-                continue;
-            }
-            try {
-                Class clazz = Class.forName(className);
-                BackendListener listener =
-                    (BackendListener)clazz.newInstance();
-
-                bls.add(listener);
-            }
-            catch (ClassNotFoundException cnfe) {
-                logger.error(cnfe.getLocalizedMessage(), cnfe);
-            }
-            catch (InstantiationException ie) {
-                logger.error(ie.getLocalizedMessage(), ie);
-            }
-            catch (ClassCastException cce) {
-                logger.error(cce.getLocalizedMessage(), cce);
-            }
-            catch (IllegalAccessException iae) {
-                logger.error(iae.getLocalizedMessage(), iae);
-            }
-        }
-
-        backendListeners = bls;
-    }
-
-    protected void loadHooks() {
-        logger.info("loading hooks");
-
-        postFeedHooks     = new ArrayList<Hook>();
-        postAdvanceHooks  = new ArrayList<Hook>();
-        postDescribeHooks = new ArrayList<Hook>();
-
-        NodeList nodes = Config.getNodeSetXPath(HOOKS);
-
-        if (nodes == null) {
-            logger.info("No hooks found");
-            return;
-        }
-
-        for (int i = 0, len = nodes.getLength(); i < len; i++) {
-            Node   cfg     = nodes.item(i);
-            String applies = Config.getStringXPath(cfg, "@applies");
-
-            if (applies == null || applies.length() == 0) {
-                continue;
-            }
-
-            Hook     hook  = loadHook(cfg);
-            String[] apply = applies.split(",");
-
-            for (String a: apply) {
-                a = a.trim().toLowerCase();
-
-                if (a.equals("post-feed")) {
-                    postFeedHooks.add(hook);
-                }
-                else if (a.equals("post-advance")) {
-                    postAdvanceHooks.add(hook);
-                }
-                else if (a.equals("post-describe")) {
-                    postDescribeHooks.add(hook);
-                }
-            }
-        }
-    }
-
-    protected Hook loadHook(Node hookCfg) {
-        if (hookCfg == null) {
-            return null;
-        }
-
-        Hook hook = null;
-
-        String className = Config.getStringXPath(hookCfg, "@class");
-
-        try {
-            Class clazz = Class.forName(className);
-            hook        = (Hook) clazz.newInstance();
-
-            hook.setup(hookCfg);
-        }
-        catch (ClassNotFoundException cnfe) {
-            logger.error(cnfe.getLocalizedMessage(), cnfe);
-        }
-        catch (InstantiationException ie) {
-            logger.error(ie.getLocalizedMessage(), ie);
-        }
-        catch (ClassCastException cce) {
-            logger.error(cce.getLocalizedMessage(), cce);
-        }
-        catch (IllegalAccessException iae) {
-            logger.error(iae.getLocalizedMessage(), iae);
-        }
-
-        return hook;
-    }
-
-    /**
-     * Fetches the export signing secret from the global configuration.
-     * If none is found if defaults to the DEFAULT_EXORT_SECRET which
-     * is insecure.
-     */
-    protected void setupExportSecret() {
-        String secret = Config.getStringXPath(EXPORT_SECRET);
-
-        if (secret == null) {
-            logger.warn("NO EXPORT SECRET SET! USING INSECURE DEFAULT!");
-            secret = DEFAULT_EXPORT_SECRET;
-        }
-
-        exportSecret = StringUtils.getUTF8Bytes(secret);
-    }
-
-    /**
-     * Loads all the dynamic classes configured by the global configuration.
-     */
-    public void boot() {
-        setupExportSecret();
-        buildContext();
-        loadCollectionFactory();
-        loadArtifactFactories();
-        loadServiceFactories();
-        loadUserFactory();
-        loadCallContextListener();
-        loadHTTPServer();
-        loadHooks();
-        loadLifetimeListeners();
-        loadBackendListeners();
-    }
-
-    /**
-     * Returns the artifact collection factory.
-     *
-     * @return the artifact collection factory.
-     */
-    public ArtifactCollectionFactory getArtifactCollectionFactory() {
-        return collectionFactory;
-    }
-
-    /**
-     * Returns the list of ready to use artifact factories.
-     * @return The list of artifact factories.
-     */
-    public ArtifactFactory [] getArtifactFactories() {
-        return artifactFactories;
-    }
-
-    /**
-     * Returns the ready to use service factories.
-     * @return The list of service factories.
-     */
-    public ServiceFactory [] getServiceFactories() {
-        return serviceFactories;
-    }
-
-    /**
-     * Returns the user factory.
-     *
-     * @return the user factory.
-     */
-    public UserFactory getUserFactory() {
-        return userFactory;
-    }
-
-    /**
-     * Returns the global context created by the global context factory.
-     * @return The global context.
-     */
-    public GlobalContext getContext() {
-        return context;
-    }
-
-    /**
-     * Returns the signing secret to be used when ex- and importing
-     * artifacts from and into the artifact database.
-     * @return the byte array containg the signing secret.
-     */
-    public byte [] getExportSecret() {
-        return exportSecret;
-    }
-
-    /**
-     * Returns a CallContext.Listener if configured or null.
-     *
-     * @return a CallContext.Listener.
-     */
-    public CallContext.Listener getCallContextListener() {
-        return callContextListener;
-    }
-
-    public List<Hook> getPostFeedHooks() {
-        return postFeedHooks;
-    }
-
-    public List<Hook> getPostAdvanceHooks() {
-        return postAdvanceHooks;
-    }
-
-    public List<Hook> getPostDescribeHooks() {
-        return postDescribeHooks;
-    }
-
-    public HTTPServer getHTTPServer() {
-        return httpServer;
-    }
-
-    public List<LifetimeListener> getLifetimeListeners() {
-        return lifetimeListeners;
-    }
-
-    public List<BackendListener> getBackendListeners() {
-        return backendListeners;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/LazyBackendUser.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/LazyBackendUser.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +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.artifactdatabase;
-
-import de.intevation.artifacts.User;
-import de.intevation.artifacts.UserFactory;
-
-import org.w3c.dom.Document;
-
-public class LazyBackendUser
-implements   User
-{
-    protected UserFactory factory;
-    protected Backend     backend;
-    protected String      identifier;
-    protected User        user;
-    protected Object      context;
-
-    public LazyBackendUser(
-        String      identifier,
-        UserFactory factory,
-        Backend     backend,
-        Object      context
-    ) {
-        this.identifier = identifier;
-        this.factory    = factory;
-        this.backend    = backend;
-        this.context    = context;
-    }
-
-    protected User getUser() {
-        if (user == null) {
-            user = backend.getUser(identifier, factory, context);
-            if (user == null) {
-                throw new IllegalStateException("loading user failed");
-            }
-        }
-        return user;
-    }
-
-    @Override
-    public String identifier() {
-        return getUser().identifier();
-    }
-
-    @Override
-    public String getName() {
-        return getUser().getName();
-    }
-
-    @Override
-    public void setName(String name) {
-        getUser().setName(name);
-    }
-
-    @Override
-    public void setIdentifier(String identifier) {
-        getUser().setIdentifier(identifier);
-    }
-
-    @Override
-    public Document getRole() {
-        return getUser().getRole();
-    }
-
-    @Override
-    public void setRole(Document document) {
-        getUser().setRole(document);
-    }
-
-    @Override
-    public String getAccount() {
-        return getUser().getAccount();
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/LifetimeListener.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/LifetimeListener.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-package de.intevation.artifactdatabase;
-
-import de.intevation.artifacts.GlobalContext;
-
-import org.w3c.dom.Document;
-
-public interface LifetimeListener
-{
-    void setup(Document document);
-
-    void systemUp(GlobalContext globalContext);
-
-    void systemDown(GlobalContext globalContext);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/ProtocolUtils.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/ProtocolUtils.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +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.artifactdatabase;
-
-import java.util.List;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import de.intevation.artifacts.ArtifactNamespaceContext;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
-
-import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifactdatabase.state.Output;
-import de.intevation.artifactdatabase.state.State;
-
-
-/**
- * This class provides methods that help creating the artifact protocol
- * documents describe, feed, advance and out.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class ProtocolUtils {
-
-    /**
-     * It should not be necessary to create instances of this class.
-     */
-    private ProtocolUtils() {}
-
-
-    /**
-     * This method creates a node that might be used for the artifact protocol.
-     *
-     * @param creator The ElementCreator that is used to create the node.
-     * @param nodeName The node name.
-     * @param attrName The names of optional attributes.
-     * @param value The values for the optional attributes.
-     *
-     * @return the created node.
-     */
-    public static Element createArtNode(
-        XMLUtils.ElementCreator creator,
-        String nodeName, String[] attrName, String[] value)
-    {
-        Element typeNode = creator.create(nodeName);
-
-        if (attrName != null && value != null) {
-            for (int i = 0; i < attrName.length; i++) {
-                if (i < value.length) {
-                    creator.addAttr(typeNode, attrName[i], value[i], true);
-                }
-                else {
-                    break;
-                }
-            }
-        }
-
-        return typeNode;
-    }
-
-
-    /**
-     * This method creates the root node for all artifact protocol documents.
-     *
-     * @param creator The ElementCreator used to create new elements.
-     *
-     * @return the root node for the artifact protocol document.
-     */
-    public static Element createRootNode(XMLUtils.ElementCreator creator) {
-        return createArtNode(creator, "result", null, null);
-    }
-
-
-    /**
-     * This method appends the three necessary nodes <i>type</i>, <i>uuid</i>
-     * and <i>hash</i> of the describe document to <i>root</i> node.
-     *
-     * @param creator The ElementCreator that is used to create new nodes.
-     * @param root The root node of the describe document.
-     * @param uuid The UUID of the artifact.
-     * @param hash The hash if the artifact.
-     */
-    public static void appendDescribeHeader(
-        XMLUtils.ElementCreator creator, Element root, String uuid, String hash)
-    {
-        root.appendChild(createArtNode(
-            creator,
-            "type",
-            new String[] {"name"},
-            new String[] {"describe"}));
-
-        root.appendChild(createArtNode(
-            creator,
-            "uuid",
-            new String[] {"value"},
-            new String[] {uuid}));
-
-        root.appendChild(createArtNode(
-            creator,
-            "hash",
-            new String[] {"value"},
-            new String[] {hash}));
-    }
-
-
-    /**
-     * This method appends a node that describes the current state to
-     * <i>root</i>.
-     *
-     * @param creator The ElementCreator used to create new elements.
-     * @param root The parent node for new elements.
-     * @param state The state to be appended.
-     */
-    public static void appendState(
-        XMLUtils.ElementCreator creator, Element root, State state)
-    {
-        root.appendChild(createArtNode(
-            creator, "state",
-            new String[] { "description", "name" },
-            new String[] { state.getDescription(), state.getID() }));
-    }
-
-
-    /**
-     * This method appends a node with reachable states to <i>root</i>.
-     *
-     * @param creator The ElementCreator used to create new elements.
-     * @param root The parent node for new elements.
-     * @param states The reachable states to be appended.
-     */
-    public static void appendReachableStates(
-        XMLUtils.ElementCreator creator,
-        Element                 root,
-        List<State>             states)
-    {
-        Element reachable = createArtNode(
-            creator, "reachable-states", null, null);
-
-        for (State s: states) {
-            appendState(creator, reachable, s);
-        }
-
-        root.appendChild(reachable);
-    }
-
-
-    /**
-     * This method appends a node for each Output in the <i>outputs</i> list to
-     * <i>out</i>. Note: an output node includes its provided facets!
-     *
-     * @param doc The document to which to add new elements.
-     * @param out The parent node for new elements.
-     * @param outputs The list of reachable outputs.
-     */
-    public static void appendOutputModes(
-        Document     doc,
-        Element      out,
-        List<Output> outputs)
-    {
-        ElementCreator creator = new ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        for (Output o: outputs) {
-            Element newOut = createArtNode(
-                creator,
-                "output",
-                new String[] {"name", "description", "mime-type", "type"},
-                new String[] {
-                    o.getName(),
-                    o.getDescription(),
-                    o.getMimeType(),
-                    o.getType() });
-
-            Element facets = createArtNode(creator, "facets", null, null);
-            appendFacets(doc, facets, o.getFacets());
-
-            newOut.appendChild(facets);
-            out.appendChild(newOut);
-        }
-    }
-
-
-    /**
-     * This method appends a node for each Facet in the <i>facets</i> list to
-     * <i>facet</i>.
-     *
-     * @param doc The document to wich to add new elements.
-     * @param facet The root node for new elements.
-     * @param facets The list of facets.
-     */
-    public static void appendFacets(
-        Document    doc,
-        Element     facet,
-        List<Facet> facets)
-    {
-        if (facets == null || facets.size() == 0) {
-            return;
-        }
-
-        ElementCreator creator = new ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        for (Facet f: facets) {
-            Node node = f.toXML(doc);
-
-            if (node != null) {
-                facet.appendChild(node);
-            }
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/ProxyArtifact.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/ProxyArtifact.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +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.artifactdatabase;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-/**
- * The proxy artifact is a wrapper around another artifact. It simply forwards
- * the interface calls to this underlaying artifact.
- * The reason for using proxy artifacts is enable the workflow to exchange
- * artifacts at any time by something else without losing the concrete
- * artifact. From the outside it always looks like there is only one
- * distinct artifact.<br>
- *
- * An inner artifact is able to replace itself by indirectly hand over
- * the replacement via the call context to the proxy artifact.<br>
- * To do so the proxied artifact has to call
- * <code>callContext.getContextValue(EPLACE_PROXY, replacement);</code>.
- * After the current call (describe, feed, advance and out) of the proxied
- * artifact is finished the proxy artifact replaces the former proxied artifact
- * with the replacement.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class ProxyArtifact
-extends      DefaultArtifact
-{
-    /**
-     * Key to signal that the proxied artifact should be replaced.
-     */
-    public static final Object REPLACE_PROXY = new Object();
-
-    private static Logger logger = Logger.getLogger(ProxyArtifact.class);
-
-    /**
-     * The proxied artifact.
-     */
-    protected Artifact proxied;
-
-    /**
-     * Default constructor.
-     */
-    public ProxyArtifact() {
-    }
-
-    /**
-     * Constructor to create a new proxy artifact around a given artifact.
-     * @param proxied The artifact to be proxied.
-     */
-    public ProxyArtifact(Artifact proxied) {
-        this.proxied = proxied;
-    }
-
-    /**
-     * The currently proxied artifact.
-     * @return The proxied artifact.
-     */
-    public Artifact getProxied() {
-        return proxied;
-    }
-
-    /**
-     * Explicitly set the proxied artifacts.
-     * @param proxied
-     */
-    public void setProxied(Artifact proxied) {
-        this.proxied = proxied;
-    }
-
-    @Override
-    public void setIdentifier(String identifier) {
-        this.identifier = identifier;
-
-        if (proxied != null)
-            proxied.setIdentifier(identifier);
-    }
-
-    /**
-     * Method to check if the current proxied artifact should be replaced
-     * by a new one coming from the call context.
-     * @param callContext
-     */
-    protected void checkReplacement(CallContext callContext) {
-        Object replacement = callContext.getContextValue(REPLACE_PROXY);
-        if (replacement instanceof Artifact) {
-            setProxied((Artifact)replacement);
-        }
-    }
-
-    @Override
-    public String hash() {
-        return proxied != null
-            ? proxied.hash()
-            : super.hash();
-    }
-
-    @Override
-    public Document describe(Document data, CallContext context) {
-        try {
-            return proxied != null
-                ? proxied.describe(data, context)
-                : super.describe(data, context);
-        }
-        finally {
-            checkReplacement(context);
-        }
-    }
-
-    @Override
-    public Document advance(Document target, CallContext context) {
-        try {
-            return proxied != null
-                ? proxied.advance(target, context)
-                : super.advance(target, context);
-        }
-        finally {
-            checkReplacement(context);
-        }
-    }
-
-    @Override
-    public Document feed(Document target, CallContext context) {
-        try {
-            return proxied != null
-                ? proxied.feed(target, context)
-                : super.feed(target, context);
-        }
-        finally {
-            checkReplacement(context);
-        }
-    }
-
-    @Override
-    public void out(
-        Document     format,
-        OutputStream out,
-        CallContext  context
-    )
-    throws IOException
-    {
-        try {
-            if (proxied != null) {
-                proxied.out(format, out, context);
-            }
-            else {
-                super.out(format, out, context);
-            }
-        }
-        finally {
-            checkReplacement(context);
-        }
-    }
-
-    @Override
-    public void endOfLife(Object context) {
-        if (proxied != null) {
-            proxied.endOfLife(context);
-        }
-        else {
-            super.endOfLife(context);
-        }
-    }
-
-    @Override
-    public void cleanup(Object context) {
-        if (proxied != null)
-            proxied.cleanup(context);
-        else
-            super.cleanup(context);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/XMLService.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/XMLService.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +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.artifactdatabase;
-
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.Service;
-import de.intevation.artifacts.GlobalContext;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-/**
- * Trivial implementation of an artifact database service. Useful to
- * be subclassed.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class XMLService
-extends      DefaultService
-{
-    private static Logger logger = Logger.getLogger(XMLService.class);
-
-    @Override
-    public Service.Output process(
-        Document      data,
-        GlobalContext globalContext,
-        CallMeta      callMeta
-    ) {
-        return new Output(
-            processXML(data, globalContext, callMeta),
-            "application/xml");
-    }
-
-    public Document processXML(
-        Document      data,
-        GlobalContext globalContext,
-        CallMeta      callMeta
-    ) {
-        return XMLUtils.newDocument();
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/data/DefaultStateData.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/data/DefaultStateData.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +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.artifactdatabase.data;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultStateData implements StateData {
-
-    /** The name of the data. */
-    protected String name;
-
-    /** The description of the data. */
-    protected String description;
-
-    /** The type of the data. */
-    protected String type;
-
-    /** The value. */
-    protected Object value;
-
-    public DefaultStateData() {
-    }
-
-    /**
-     * The default constructor. It creates empty StateData objects with no
-     * value.
-     *
-     * @param name The name.
-     * @param description The description.
-     * @param type The type.
-     */
-    public DefaultStateData(String name, String description, String type) {
-        this.name        = name;
-        this.description = description;
-        this.type        = type;
-    }
-
-    public void set(StateData other) {
-        name        = other.getName();
-        description = other.getDescription();
-        type        = other.getType();
-        value       = other.getValue();
-    }
-
-
-    /**
-     * A constructor that takes the name of the data, its value and the
-     * describing parameters description and type.
-     *
-     * @param name The name of the data item.
-     * @param description The description.
-     * @param type The type.
-     * @param value The value of the data item.
-     */
-    public DefaultStateData(
-        String name,
-        String description,
-        String type,
-        String value)
-    {
-        this.name        = name;
-        this.description = description;
-        this.type        = type;
-        this.value       = value;
-    }
-
-
-    /**
-     * Returns the name of the data object.
-     *
-     * @return the name.
-     */
-    public String getName() {
-        return name;
-    }
-
-
-    /**
-     * Returns the description of the data object.
-     *
-     * @return the description of the data object.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-
-    /**
-     * Returns the type of the data object as string.
-     *
-     * @return the type as string.
-     */
-    public String getType() {
-        return type;
-    }
-
-
-    /**
-     * Returns the value of the data object.
-     *
-     * @return the value.
-     */
-    public Object getValue() {
-        return value;
-    }
-
-
-    /**
-     * Set the value of this data object.
-     *
-     * @param value The new value for this data object.
-     */
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    @Override
-    public StateData deepCopy() {
-        DefaultStateData copy = new DefaultStateData();
-        copy.set(this);
-        return copy;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/data/StateData.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/data/StateData.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +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.artifactdatabase.data;
-
-import java.io.Serializable;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface StateData extends Serializable {
-
-    /**
-     * Returns the name of the data object.
-     *
-     * @return the name.
-     */
-    public String getName();
-
-
-    /**
-     * Returns the description of the data object.
-     *
-     * @return the description of the data object.
-     */
-    public String getDescription();
-
-
-    /**
-     * Returns the type of the data object as string.
-     *
-     * @return the type as string.
-     */
-    public String getType();
-
-
-    /**
-     * Returns the value of the data object.
-     *
-     * @return the value.
-     */
-    public Object getValue();
-
-
-    /**
-     * Set the value of this data object.
-     *
-     * @param value The new value for this data object.
-     */
-    public void setValue(Object value);
-
-    public StateData deepCopy();
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/db/DBConnection.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/db/DBConnection.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-package de.intevation.artifactdatabase.db;
-
-import javax.sql.DataSource;
-
-import java.io.File;
-
-import org.apache.commons.pool.ObjectPool;
-
-import org.apache.commons.pool.impl.GenericObjectPool;
-
-import org.apache.commons.dbcp.DriverManagerConnectionFactory;
-import org.apache.commons.dbcp.PoolableConnectionFactory;
-import org.apache.commons.dbcp.PoolingDataSource;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import org.apache.log4j.Logger;
-
-public class DBConnection
-{
-    private static Logger log = Logger.getLogger(DBConnection.class);
-
-    public static final String DEFAULT_DRIVER        = "org.h2.Driver";
-    public static final String DEFAULT_USER          = "";
-    public static final String DEFAULT_PASSWORD      = "";
-    public static final String DEFAULT_DATABASE_FILE = "artifacts.db";
-    public static final String DEFAULT_URL           = getDefaultURL();
-
-    public static final String getDefaultURL() {
-        File configDir = Config.getConfigDirectory();
-        File databaseFile = new File(configDir, DEFAULT_DATABASE_FILE);
-        return "jdbc:h2:" + databaseFile;
-    }
-
-    protected DataSource dataSource;
-
-    protected String driver;
-    protected String url;
-    protected String user;
-    protected String password;
-
-    public DBConnection() {
-    }
-
-    public DBConnection(
-        String driver,
-        String url,
-        String user,
-        String password
-    ) {
-        this.driver   = driver;
-        this.url      = url;
-        this.user     = user;
-        this.password = password;
-    }
-
-    public String getUser() {
-        return user;
-    }
-
-    public void setUser(String user) {
-        this.user = user;
-    }
-
-    public String getPassword() {
-        return password;
-    }
-
-    public void setPassword(String password) {
-        this.password = password;
-    }
-
-    public String getDriver() {
-        return driver;
-    }
-
-    public void setDriver(String driver) {
-        this.driver = driver;
-    }
-
-    public String getUrl() {
-        return url;
-    }
-
-    public void setUrl(String url) {
-        this.url = url;
-    }
-
-    public synchronized DataSource getDataSource() {
-        if (dataSource == null) {
-            if (log.isDebugEnabled()) {
-                log.debug("create new datasource:");
-                log.debug(" driver: " + driver);
-                log.debug(" url   : " + url);
-                log.debug(" user  : " + user);
-            }
-
-            try {
-                synchronized (DBConnection.class) {
-                    Class.forName(driver);
-                }
-            }
-            catch (ClassNotFoundException cnfe) {
-                log.error("cannot load driver", cnfe);
-                return null;
-            }
-
-            DriverManagerConnectionFactory dmcf =
-                new DriverManagerConnectionFactory(url, user, password);
-
-            ObjectPool cp = new GenericObjectPool();
-
-            PoolableConnectionFactory pcf = new PoolableConnectionFactory(
-                dmcf, cp, null, null, false, false);
-
-            dataSource = new PoolingDataSource(cp);
-        }
-        return dataSource;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/db/SQL.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/db/SQL.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-package de.intevation.artifactdatabase.db;
-
-import java.util.Properties;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.log4j.Logger;
-
-public class SQL {
-
-    private static Logger logger = Logger.getLogger(SQL.class);
-
-    protected Properties statements;
-
-    public SQL() {
-    }
-
-    public SQL(String driver) {
-        this(SQL.class, driver);
-    }
-
-    public SQL(Class clazz, String driver) {
-        this(clazz, "/sql", driver);
-    }
-
-    public SQL(Class clazz, String resourcePath, String driver) {
-        statements = loadStatements(clazz, resourcePath, driver);
-    }
-
-    public static final String driverToProperties(String driver) {
-        return driver.replace('.', '-').toLowerCase() + ".properties";
-    }
-
-    /**
-     * Returns key/value pairs of SQL statements for the used database
-     * backend.
-     * The concrete set of SQL statements is determined by the
-     * used JDBC database driver which is configured in conf.xml.
-     * The class name of the driver is transformed by replacing
-     * all '.' with '_' and lower case the resulting string.
-     * The transformed string is used to load a properties file
-     * in '/sql/' which should contain the statements.
-     * Example:<br>
-     * <code>org.postgresql.Driver</code> results in loading of
-     * <code>/sql/org-postgresql-driver.properties</code>.
-     * @return The key/value pairs of SQL statements.
-     */
-    protected Properties loadStatements(
-        Class  clazz,
-        String resourcePath,
-        String driver
-    ) {
-        logger.debug("loadStatements");
-
-        Properties properties = new Properties();
-
-        String resDriver = driverToProperties(driver);
-
-        InputStream in = null;
-        try {
-            String res = resourcePath + "/" + resDriver;
-
-            in = clazz.getResourceAsStream(res);
-
-            if (in == null) {
-                logger.warn("No SQL file for driver '" + driver + "' found.");
-                resDriver = driverToProperties(DBConnection.DEFAULT_DRIVER);
-                res = resourcePath + "/" + resDriver;
-
-                in = clazz.getResourceAsStream(res);
-                if (in == null) {
-                    logger.error("No SQL file for driver '" +
-                        DBConnection.DEFAULT_DRIVER + "' found.");
-                }
-            }
-            else {
-                if (logger.isDebugEnabled()) {
-                    logger.debug("found resource: " + res);
-                }
-            }
-
-            if (in != null) {
-                properties.load(in);
-            }
-        }
-        catch (IOException ioe) {
-            logger.error(ioe);
-        }
-
-        return properties;
-    }
-
-    public String get(String key) {
-        boolean debug = logger.isDebugEnabled();
-        if (debug) {
-            logger.debug("looking for SQL " + key);
-            logger.debug("statements != null: " + (statements != null));
-        }
-
-        String sql = statements.getProperty(key);
-
-        if (sql == null) {
-            logger.error("cannot find SQL for key '" + key + "'");
-        }
-
-        if (debug) {
-            logger.debug("-> '" + sql + "'");
-        }
-
-        return sql;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/db/SQLExecutor.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/db/SQLExecutor.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-package de.intevation.artifactdatabase.db;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-
-import javax.sql.DataSource;
-
-import org.apache.log4j.Logger;
-
-public class SQLExecutor
-{
-    private static Logger logger = Logger.getLogger(SQLExecutor.class);
-
-    public class Instance {
-
-        public Connection        conn;
-        public PreparedStatement stmnt;
-        public ResultSet         result;
-
-        public Instance() {
-        }
-
-        public void reset() throws SQLException {
-            if (result != null) {
-                result.close();
-                result = null;
-            }
-            if (stmnt != null) {
-                result = null;
-                stmnt.close();
-            }
-        }
-
-        public PreparedStatement prepareStatement(String query)
-        throws SQLException {
-            return stmnt = conn.prepareStatement(query);
-        }
-
-        public void close() {
-            if (result != null) {
-                try { result.close(); }
-                catch (SQLException sqle) {}
-            }
-            if (stmnt != null) {
-                try { stmnt.close(); }
-                catch (SQLException sqle) {}
-            }
-            if (conn != null) {
-                try { conn.close(); }
-                catch (SQLException sqle) {}
-            }
-        }
-
-        public boolean runWrite() {
-            DataSource dataSource = dbConnection.getDataSource();
-            try {
-                conn = dataSource.getConnection();
-                try {
-                    conn.setAutoCommit(false);
-                    return doIt();
-                }
-                catch (SQLException sqle) {
-                    conn.rollback();
-                    throw sqle;
-                }
-            }
-            catch (SQLException sqle) {
-                logger.error(sqle.getLocalizedMessage(), sqle);
-            }
-            finally {
-                close();
-            }
-            return false;
-        }
-
-        public boolean runRead() {
-            DataSource dataSource = dbConnection.getDataSource();
-            try {
-                conn = dataSource.getConnection();
-                return doIt();
-            }
-            catch (SQLException sqle) {
-                logger.error(sqle.getLocalizedMessage(), sqle);
-            }
-            finally {
-                close();
-            }
-            return false;
-        }
-
-        public boolean doIt() throws SQLException {
-            return true;
-        }
-    } // class Instance
-
-    protected DBConnection dbConnection;
-
-    public SQLExecutor() {
-    }
-
-    public SQLExecutor(DBConnection dbConnection) {
-        this.dbConnection = dbConnection;
-    }
-
-    public DBConnection getDBConnection() {
-        return dbConnection;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/h2/CollectionAccessUpdateTrigger.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/h2/CollectionAccessUpdateTrigger.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-package de.intevation.artifactdatabase.h2;
-
-import org.h2.api.Trigger;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.sql.PreparedStatement;
-
-import de.intevation.artifactdatabase.DBConfig;
-
-import de.intevation.artifactdatabase.db.SQL;
-
-import org.apache.log4j.Logger;
-
-public class CollectionAccessUpdateTrigger
-implements   Trigger
-{
-    private static Logger logger =
-        Logger.getLogger(CollectionAccessUpdateTrigger.class);
-
-    public String COLLECTIONS_TOUCH_TRIGGER_FUNCTION;
-
-    public void init(
-        Connection conn,
-        String     schemaName,
-        String     triggerName,
-        String     tableName,
-        boolean    before,
-        int        type
-    )
-    throws SQLException {
-        logger.debug("CollectionAccessUpdateTrigger.init");
-        setupSQL(DBConfig.getInstance().getSQL());
-    }
-
-    protected void setupSQL(SQL sql) {
-        COLLECTIONS_TOUCH_TRIGGER_FUNCTION =
-            sql.get("collections.touch.trigger.function");
-    }
-
-    public void fire(
-        Connection conn,
-        Object []  oldRow,
-        Object []  newRow
-    )
-    throws SQLException {
-        logger.debug("CollectionAccessUpdateTrigger.fire");
-        PreparedStatement stmnt = conn.prepareStatement(
-            COLLECTIONS_TOUCH_TRIGGER_FUNCTION);
-        stmnt.setObject(1, newRow[0]);
-        stmnt.execute();
-        stmnt.close();
-    }
-
-    public void close() throws SQLException {
-        logger.debug("CollectionAccessUpdateTrigger.close");
-    }
-
-    public void remove() throws SQLException {
-        logger.debug("CollectionAccessUpdateTrigger.remove");
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/package.html
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/package.html	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-<html>
-<head>
-</head>
-<body>
-The reference implementation of an artifact database. It starts
-an HTTP server and publishes the interface of the artifact database
-via REST.
-</body>
-</html>
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ArtifactOutResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ArtifactOutResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.CallMeta;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Request;
-
-import org.w3c.dom.Document;
-
-/**
- * Resource to serve the out()-outputs of artifacts.
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class ArtifactOutResource
-extends      BaseOutResource
-{
-    /**
-     * server URL where to find the resource.
-     */
-    public static final String PATH = "/artifact/{uuid}/{type}";
-
-    private static Logger logger = Logger.getLogger(ArtifactOutResource.class);
-
-
-    /**
-     * Returns the identifier of the collection.
-     *
-     * @return the identifier of the collection.
-     */
-    protected String getIdentifier() {
-        Request request = getRequest();
-
-        return (String) request.getAttributes().get("uuid");
-    }
-
-
-    protected String getType() {
-        Request request = getRequest();
-
-        return (String) request.getAttributes().get("type");
-    }
-
-
-    /**
-     * Call the ArtifactDatabase.out method.
-     */
-    protected ArtifactDatabase.DeferredOutput doOut(
-        String           identifier,
-        String           type,
-        Document         input,
-        ArtifactDatabase db,
-        CallMeta         meta)
-    throws ArtifactDatabaseException
-    {
-        logger.debug("ArtifactOutResource.doOut");
-
-        return db.out(identifier, type, input, meta);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ArtifactResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ArtifactResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,204 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Request;
-import org.restlet.Response;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-
-import org.restlet.resource.ResourceException;
-
-import org.w3c.dom.Document;
-
-/**
- * Resource to expose the core artifact methods
- * (describe, feed and advance) via REST.
- *
- * <ul>
- * <li>describe() is modelled via GET.</li>
- * <li>advance() and feed() are modelled via POST.</li>
- * </ul>
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class ArtifactResource
-extends      BaseResource
-{
-    private static Logger logger = Logger.getLogger(ArtifactResource.class);
-
-    /**
-     * XPath to figure out the type of action (feed, advance) via the
-     * incoming POST request.
-     */
-    public static final String XPATH_ACTION = "/art:action/art:type/@name";
-
-    /**
-     * server URL where to reach the resource.
-     */
-    public static final String PATH = "/artifact/{uuid}";
-
-    /**
-     * Error message if no action was given.
-     */
-    public static final String NO_ACTION_MESSAGE      = "no action given";
-
-    /**
-     * Error message if a unknown action was given.
-     */
-    public static final String NO_SUCH_ACTION_MESSAGE = "no such action";
-
-    /**
-     * Error message if the requested artifact was not found in
-     * the artifact database.
-     */
-    public static final String NO_ARTIFACT_FOUND = "Artifact not found";
-
-    /**
-     * Action name 'advance'.
-     */
-    public static final String ADVANCE  = "advance";
-    /**
-     * Action name 'feed'.
-     */
-    public static final String FEED     = "feed";
-    /**
-     * Action name 'describe'.
-     */
-    public static final String DESCRIBE = "describe";
-
-    @Override
-    protected Representation innerGet()
-    throws                   ResourceException
-    {
-        Request request = getRequest();
-
-        String identifier = (String)request.getAttributes().get("uuid");
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("looking for artifact id '" + identifier + "'");
-        }
-
-        ArtifactDatabase db = (ArtifactDatabase)getContext()
-            .getAttributes().get("database");
-
-        try {
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.describe(identifier, null, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-
-    /**
-     * Method to figure out which POST action (feed or advance) was
-     * triggered and perform this operation on the artifact specified
-     * by 'identifier' and found in the artifact database 'db'.
-     *
-     * @param identifier The identifier of the artifact.
-     * @param action The action to be performed.
-     * @param source The input document to further parameterize the
-     * operation.
-     * @param db The artifact database where to find the artifact.
-     * @return The representation produced by the performed action.
-     */
-    protected Representation dispatch(
-        String           identifier,
-        String           action,
-        Document         source,
-        ArtifactDatabase db
-    ) {
-        Document out = null;
-
-        try {
-            if (action.equals(FEED)) {
-                out = db.feed(identifier, source, getCallMeta());
-            }
-            else if (action.equals(ADVANCE)) {
-                out = db.advance(identifier, source, getCallMeta());
-            }
-            else if (action.equals(DESCRIBE)) {
-                out = db.describe(identifier, source, getCallMeta());
-            }
-            else {
-                throw new ArtifactDatabaseException(NO_SUCH_ACTION_MESSAGE);
-            }
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-
-        return new DomRepresentation(MediaType.APPLICATION_XML, out);
-    }
-
-    @Override
-    protected Representation innerPost(Representation requestRepr) {
-
-        Document inputDocument = null;
-        try {
-            DomRepresentation input = new DomRepresentation(requestRepr);
-            input.setNamespaceAware(true);
-            inputDocument = input.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getMessage());
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        String action = XMLUtils.xpathString(
-            inputDocument,
-            XPATH_ACTION,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (action == null || action.length() == 0) {
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, NO_ACTION_MESSAGE);
-            return new EmptyRepresentation();
-        }
-
-        Request request = getRequest();
-
-        String identifier = (String)request.getAttributes().get("uuid");
-
-        ArtifactDatabase db = (ArtifactDatabase)getContext()
-            .getAttributes().get("database");
-
-        return dispatch(identifier, action, inputDocument, db);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/BaseOutResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/BaseOutResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.CallMeta;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Request;
-import org.restlet.Response;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-
-import org.restlet.resource.ResourceException;
-
-import org.w3c.dom.Document;
-
-
-/**
- * Base Resource to serve the out()-outputs of collections and artifacts.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public abstract class BaseOutResource
-extends               BaseResource
-{
-    /** The logger used in this class.*/
-    private static Logger logger = Logger.getLogger(BaseOutResource.class);
-
-    /** XPath to figure out the MIME type of the requested result.*/
-    public static final String XPATH_MIME_TYPE =
-        "/art:action/art:out/art:mime-type/@value";
-
-    /** Default result MIME type: octet stream.*/
-    public static final MediaType DEFAULT_MIME_TYPE =
-        MediaType.APPLICATION_OCTET_STREAM;
-
-
-    @Override
-    protected Representation innerPost(Representation requestRepr)
-    throws    ResourceException
-    {
-        Document inputDocument = null;
-
-        try {
-            DomRepresentation input = new DomRepresentation(requestRepr);
-            input.setNamespaceAware(true);
-            inputDocument = input.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getMessage());
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        Request request = getRequest();
-
-        String identifier = getIdentifier();
-        String outType    = getType();
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("looking for artifact id '" + identifier + "'");
-        }
-
-        String mimeTypeString = XMLUtils.xpathString(
-            inputDocument,
-            XPATH_MIME_TYPE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        MediaType mimeType = DEFAULT_MIME_TYPE;
-
-        if (mimeTypeString != null && mimeTypeString.length() != 0) {
-            try {
-                mimeType = MediaType.valueOf(mimeTypeString);
-            }
-            catch (Exception e) {
-                logger.error(e.getLocalizedMessage());
-            }
-        }
-
-        try {
-            return new OutRepresentation(
-                mimeType,
-                doOut(identifier, outType, inputDocument, db, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-
-    /**
-     * Returns the identifier of the artifact or collection.
-     *
-     * @return the identifier.
-     */
-    protected abstract String getIdentifier();
-
-
-    /**
-     * Returns the concrete output type of the artifact or collection.
-     *
-     * @return the output type.
-     */
-    protected abstract String getType();
-
-    /**
-     * This method is called to process the operation on artifacts or
-     * collections.
-     *
-     * @param identifier The identifier of the artifact or collection.
-     * @param type The output type.
-     * @param input The input document of the request.
-     * @param db The artifact database.
-     * @param meta The CallMeta object.
-     *
-     * @return the result of the operation.
-     */
-    protected abstract ArtifactDatabase.DeferredOutput doOut(
-        String           identifier,
-        String           type,
-        Document         input,
-        ArtifactDatabase db,
-        CallMeta         meta)
-    throws ArtifactDatabaseException;
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/BaseResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/BaseResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +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.artifactdatabase.rest;
-
-import de.intevation.artifactdatabase.DefaultCallMeta;
-import de.intevation.artifactdatabase.DefaultPreferredLocale;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.PreferredLocale;
-
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.ClientInfo;
-import org.restlet.data.Language;
-import org.restlet.data.Preference;
-
-import org.restlet.representation.Representation;
-
-import org.restlet.resource.ResourceException;
-import org.restlet.resource.ServerResource;
-
-/**
- * Base class for the resources of REST interface of the artifact database.
- * Primarily used to unify the logging.
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class BaseResource
-extends      ServerResource
-{
-    private static Logger logger = Logger.getLogger(BaseResource.class);
-
-    /**
-     * Default constructor.
-     */
-    public BaseResource() {
-    }
-
-    /**
-     * Overrides the post method of ServerResource to handle some
-     * exceptions and to the required logging.
-     * The call bridges to #innerPost(Representation) which
-     * should be overwitten by the subclasses to do the real
-     * request processing.
-     * @param requestRepr The incoming represention of the HTTP request.
-     * @return The representation produced by #innerPost(Representation).
-     * @throws ResourceException Thrown if something went wrong during
-     * request processing.
-     */
-    @Override
-    protected Representation post(Representation requestRepr)
-    throws    ResourceException
-    {
-        try {
-            return innerPost(requestRepr);
-        }
-        catch (ResourceException re) {
-            throw re;
-        }
-        catch (RuntimeException re) {
-            logger.error(re.getLocalizedMessage(), re);
-            throw re;
-        }
-    }
-
-    /**
-     * Trivial implementation of innerPost() which is called by
-     * #post(Representation) which simply calls super.post(Representation).
-     * This should be overwritten by subclasses which need POST support.
-     * @param requestRepr The incoming representation of the request.
-     * @return The representation produced by super.post(Representation).
-     * @throws ResourceException Thrown if something went wrong during
-     * request processing.
-     */
-    protected Representation innerPost(Representation requestRepr)
-    throws    ResourceException
-    {
-        return super.post(requestRepr);
-    }
-
-    /**
-     * Wrapper around get() of the super class to handle some exceptions
-     * and do the corresponing logging. The call is bridged to #innerGet()
-     * which should be overwritten by subclasses.
-     * @return The representation produced by #innerGet()
-     * @throws ResourceException Thrown if something went wrong during
-     * request processing.
-     */
-    @Override
-    protected Representation get()
-    throws    ResourceException
-    {
-        try {
-            return innerGet();
-        }
-        catch (ResourceException re) {
-            throw re;
-        }
-        catch (RuntimeException re) {
-            logger.error(re.getLocalizedMessage(), re);
-            throw re;
-        }
-    }
-
-    /**
-     * Trivial implementaion of innerGet() which simply calls
-     * super.get() to produce some output representation. This method
-     * should be overwritten by subclasses which need GET support.
-     * @return The representation produced by super.get().
-     * @throws ResourceException Thrown if something went wrong during
-     * request processing.
-     */
-    protected Representation innerGet()
-    throws    ResourceException
-    {
-        return super.get();
-    }
-
-    /**
-     * Returns meta information (preferred languages et. al.)
-     * of the current HTTP request.
-     * @return the meta information
-     */
-    protected CallMeta getCallMeta() {
-        ClientInfo clientInfo = getClientInfo();
-
-        List<Preference<Language>> pl = clientInfo.getAcceptedLanguages();
-
-        PreferredLocale [] languages = new PreferredLocale[pl.size()];
-
-        int index = 0;
-
-        for (Preference<Language> p: pl) {
-            String lang    = p.getMetadata().getName();
-            float  quality = p.getQuality();
-            languages[index++] = new DefaultPreferredLocale(lang, quality);
-        }
-
-        return new DefaultCallMeta(languages);
-    }
-
-
-    /**
-     * Returns the artifact database stored in the context of the REST
-     * application.
-     *
-     * @return the artifact database.
-     */
-    protected ArtifactDatabase getArtifactDatabase() {
-        return (ArtifactDatabase) getContext().getAttributes().get("database");
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ByteArrayRepresentation.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ByteArrayRepresentation.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-package de.intevation.artifactdatabase.rest;
-
-import org.restlet.representation.Representation;
-
-import java.io.Reader;
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.Writer;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.ByteArrayInputStream;
-
-import java.nio.ByteBuffer;
-
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-
-import org.restlet.data.MediaType;
-
-public class ByteArrayRepresentation
-extends      Representation
-{
-    protected byte [] data;
-
-    public ByteArrayRepresentation(MediaType mediaType, byte [] data) {
-        super(mediaType);
-        this.data = data;
-    }
-
-    @Override
-    public long getSize() {
-        return data.length;
-    }
-
-    @Override
-    public ReadableByteChannel getChannel() throws IOException {
-        return null;
-    }
-
-    @Override
-    public Reader getReader() throws IOException {
-        return new InputStreamReader(getStream());
-    }
-
-    @Override
-    public InputStream getStream() throws IOException {
-        return new ByteArrayInputStream(data);
-    }
-
-    @Override
-    public void write(Writer writer) throws IOException {
-        writer.append(ByteBuffer.wrap(data).asCharBuffer());
-    }
-
-    @Override
-    public void write(WritableByteChannel writableChannel) throws IOException {
-        writableChannel.write(ByteBuffer.wrap(data));
-    }
-
-    @Override
-    public void write(OutputStream outputStream) throws IOException {
-        outputStream.write(data);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CollectionOutResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CollectionOutResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.CallMeta;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Request;
-
-import org.w3c.dom.Document;
-
-
-/**
- * Resource to serve the out()-outputs of collections.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class CollectionOutResource
-extends      BaseOutResource
-{
-    /** The logger used in this class.*/
-    private static Logger logger = Logger.getLogger(CollectionOutResource.class);
-
-    /** server URL where to find the resource.*/
-    public static final String PATH = "/collection/{uuid}/{type}";
-
-
-    /**
-     * Returns the identifier of the collection.
-     *
-     * @return the identifier of the collection.
-     */
-    protected String getIdentifier() {
-        Request request = getRequest();
-
-        return (String) request.getAttributes().get("uuid");
-    }
-
-
-    protected String getType() {
-        Request request = getRequest();
-
-        return (String) request.getAttributes().get("type");
-    }
-
-
-    /**
-     * Call the ArtifactDatabase.outCollection method.
-     */
-    protected ArtifactDatabase.DeferredOutput doOut(
-        String           identifier,
-        String           type,
-        Document         input,
-        ArtifactDatabase db,
-        CallMeta         meta)
-    throws ArtifactDatabaseException
-    {
-        logger.debug("CollectionOutResource.doOut");
-
-        return db.outCollection(identifier, type, input, meta);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CollectionResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CollectionResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,276 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.CallMeta;
-
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifactdatabase.ArtifactDatabaseImpl;
-
-import java.io.IOException;
-
-import javax.xml.xpath.XPathConstants;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.xml.DomRepresentation;
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.Request;
-import org.restlet.Response;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class CollectionResource
-extends      BaseResource
-{
-    /** The logger that is used in this class.*/
-    private static Logger logger = Logger.getLogger(CollectionResource.class);
-
-    /** server URL where to reach the resource.*/
-    public static final String PATH = "/collection/{uuid}";
-
-    /**
-     * XPath to figure out the type of action (feed, advance) via the
-     * incoming POST request.
-     */
-    public static final String XPATH_ACTION = "/art:action/art:type/@name";
-
-    /**
-     * XPath to figure out the identifier of the artifact described in the
-     * action.
-     */
-    public static final String XPATH_ARTIFACT =
-        "/art:action/art:type/art:artifact/@uuid";
-
-    /** Error message if no action was given.*/
-    public static final String NO_ACTION_MSG = "no action given";
-
-    /** Error message if a unknown action was given.*/
-    public static final String NO_SUCH_ACTION_MSG = "no such action";
-
-    /** Action name for deleting a collection.*/
-    public static final String ACTION_DELETE = "delete";
-
-    /** Action name for describing the collection.*/
-    public static final String ACTION_DESCRIBE = "describe";
-
-    /** Action name for retrieving the attribute of a collection.*/
-    public static final String ACTION_GET_ATTRIBUTE = "getattribute";
-
-    /** Action name for retrieving the attributes of an artifact stored in the
-     * collection.*/
-    public static final String ACTION_GET_ITEM_ATTRIBUTE = "getitemattribute";
-
-    /** Action name for setting the attribute of a collection.*/
-    public static final String ACTION_SET_ATTRIBUTE = "setattribute";
-
-    /** Action name for setting the attribute for an artifact stored in the
-     * collection.*/
-    public static final String ACTION_SET_ITEM_ATTRIBUTE = "setitemattribute";
-
-    /** Action name for adding a new artifact to the collection.*/
-    public static final String ACTION_ADD_ARTIFACT = "addartifact";
-
-    /** Action name for removing an artifact from the collection.*/
-    public static final String ACTION_REMOVE_ARTIFACT = "removeartifact";
-
-    /** Action name for listing the artifacts of the collection.*/
-    public static final String ACTION_LIST_ARTIFACTS = "listartifacts";
-
-    /** Action name for setting the ttl of a collection.*/
-    public static final String ACTION_SET_TTL = "settimetolive";
-
-    /** Action name for setting the name of a collection.*/
-    public static final String ACTION_SET_NAME = "setname";
-
-
-    /**
-     * Method to figure out which POST action was triggered and perform this
-     * operation on the collection specified by 'identifier' and found in the
-     * artifact database 'db'.
-     *
-     * @param identifier The identifier of the collection.
-     * @param action The action to be performed.
-     * @param source The input document to further parameterize the operation.
-     * @param db The artifact database where to find the collection.
-     *
-     * @return The representation produced by the performed action.
-     */
-    protected Representation dispatch(
-        String           identifier,
-        String           action,
-        Document         source,
-        ArtifactDatabase db
-    ) {
-        Document out = null;
-
-        try {
-            CallMeta meta = getCallMeta();
-
-            if (action.equals(ACTION_DELETE)) {
-                logger.info("Delete collection '" + identifier + "'");
-                out = db.deleteCollection(identifier, getCallMeta());
-            }
-            else if (action.equals(ACTION_DESCRIBE)) {
-                logger.info("Describe collection '" + identifier + "'");
-
-                out = db.describeCollection(identifier, meta);
-            }
-            else if (action.equals(ACTION_ADD_ARTIFACT)) {
-                String art = getArtifactIdentifier(source);
-
-                logger.info("Add artifact '" + art + "' to collection.");
-                out = db.addCollectionArtifact(identifier, art, source, meta);
-            }
-            else if (action.equals(ACTION_REMOVE_ARTIFACT)) {
-                String art = getArtifactIdentifier(source);
-
-                logger.info("Remove artifact '" + art + "' from collection.");
-                out = db.removeCollectionArtifact(identifier, art, meta);
-            }
-            else if (action.equals(ACTION_LIST_ARTIFACTS)) {
-                logger.info("List artifacts of collection '" + identifier +"'");
-                out = db.listCollectionArtifacts(identifier, meta);
-            }
-            else if (action.equals(ACTION_SET_ATTRIBUTE)) {
-                String art = getArtifactIdentifier(source);
-
-                logger.info("Set attribute for collection '" + identifier + "'");
-
-                Document attr = getCollectionAttribute(source);
-
-                out = db.setCollectionAttribute(identifier, meta, attr);
-            }
-            else if (action.equals(ACTION_SET_ITEM_ATTRIBUTE)) {
-                String art = getArtifactIdentifier(source);
-
-                logger.info("Set attribute for artifact '" + art + "'");
-                out = db.setCollectionItemAttribute(identifier, art, source, meta);
-            }
-            else if (action.equals(ACTION_GET_ATTRIBUTE)) {
-                String art = getArtifactIdentifier(source);
-
-                logger.info("Retrieve attribute of collection '" + identifier + "'");
-                out = db.getCollectionAttribute(identifier, meta);
-            }
-            else if (action.equals(ACTION_GET_ITEM_ATTRIBUTE)) {
-                String art = getArtifactIdentifier(source);
-
-                logger.info("Retrieve attribute of artifact '" + art + "'");
-                out = db.getCollectionItemAttribute(identifier, art, meta);
-            }
-            else if (action.equals(ACTION_SET_TTL)) {
-                out = db.setCollectionTTL(identifier, source, meta);
-            }
-            else if (action.equals(ACTION_SET_NAME)) {
-                out = db.setCollectionName(identifier, source, meta);
-            }
-            else {
-                throw new ArtifactDatabaseException(NO_SUCH_ACTION_MSG);
-            }
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-
-        return new DomRepresentation(MediaType.APPLICATION_XML, out);
-    }
-
-
-    @Override
-    protected Representation innerPost(Representation requestRepr) {
-        Document input = null;
-        try {
-            DomRepresentation in = new DomRepresentation(requestRepr);
-            in.setNamespaceAware(true);
-            input = in.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        String action = XMLUtils.xpathString(
-            input, XPATH_ACTION, ArtifactNamespaceContext.INSTANCE);
-
-        if (action == null || action.length() == 0) {
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, NO_ACTION_MSG);
-            return new EmptyRepresentation();
-        }
-
-        Request request = getRequest();
-
-        String identifier = (String) request.getAttributes().get("uuid");
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        return dispatch(identifier, action, input, db);
-    }
-
-
-    /**
-     * Retrieves the identifier of the artifact used in the action.
-     *
-     * @param source The incoming document that describes the operation.
-     *
-     * @return the uuid of the artifact described in the document.
-     */
-    protected String getArtifactIdentifier(Document source) {
-        return XMLUtils.xpathString(
-            source, XPATH_ARTIFACT, ArtifactNamespaceContext.INSTANCE);
-    }
-
-
-    /**
-     * Returns the attribute for a collection of the incoming request document.
-     *
-     * @param request The request document.
-     *
-     * @return the contained attribute as document.
-     */
-    protected Document getCollectionAttribute(Document request) {
-        Node attr = (Node) XMLUtils.xpath(
-            request,
-            ArtifactDatabaseImpl.XPATH_COLLECTION_ATTRIBUTE,
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        Document newAttr = XMLUtils.newDocument();
-
-        if (attr == null) {
-            logger.error("Collection attribute document not found!");
-            return newAttr;
-        }
-
-        newAttr.appendChild(newAttr.importNode(attr, true));
-
-        return newAttr;
-    }
-}
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CreateCollectionResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CreateCollectionResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.xml.DomRepresentation;
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ResourceException;
-import org.restlet.Response;
-import org.restlet.Request;
-
-import org.w3c.dom.Document;
-
-/**
- * Resource to create a new collections within the artifact database.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class CreateCollectionResource
-extends      BaseResource
-{
-    /** The logger used in this class.*/
-    private static Logger logger =
-        Logger.getLogger(CreateCollectionResource.class);
-
-    /** The URL part for this resource.*/
-    public static final String PATH = "/create-collection/{ownerid}";
-
-
-    @Override
-    protected Representation innerPost(Representation requestRepr)
-    throws    ResourceException
-    {
-        Document input = null;
-
-        try {
-            DomRepresentation in = new DomRepresentation(requestRepr);
-            in.setNamespaceAware(true);
-            input = in.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        Request request     = getRequest();
-
-        String ownerId      = (String) request.getAttributes().get("ownerid");
-
-        logger.info("Create new collection owned by: " + ownerId);
-
-        try {
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.createCollection(ownerId, input, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CreateResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CreateResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Response;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-
-import org.restlet.resource.ResourceException;
-
-import org.w3c.dom.Document;
-
-/**
- * Resource to create a new artifact within artifact database.
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class CreateResource
-extends      BaseResource
-{
-    private static Logger logger = Logger.getLogger(CreateResource.class);
-
-    /**
-     * server URL where to reach the resource.
-     */
-    public static final String PATH = "/create";
-
-    /**
-     * XPATH to figure out the name of the factory which should be used
-     * to create the new artifact.
-     */
-    public static final String XPATH_FACTORY = "/art:action/art:factory/@name";
-
-    /**
-     * Error message if no factory was given.
-     */
-    public static final String NO_FACTORY_MESSAGE = "No factory given";
-
-    /**
-     * Error message if no artifact was created.
-     */
-    public static final String NO_ARTIFACT_CREATED = "No artifact created";
-
-    @Override
-    protected Representation innerPost(Representation requestRepr)
-    throws ResourceException
-    {
-        Document inputDocument = null;
-        try {
-            DomRepresentation input = new DomRepresentation(requestRepr);
-            input.setNamespaceAware(true);
-            inputDocument = input.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getMessage());
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        String factory = XMLUtils.xpathString(
-            inputDocument,
-            XPATH_FACTORY,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (factory == null || factory.length() == 0) {
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, NO_FACTORY_MESSAGE);
-            return new EmptyRepresentation();
-        }
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("Create artifact with factory '" + factory + "'");
-        }
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        try {
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.createArtifactWithFactory(factory,
-                                             getCallMeta(),
-                                             inputDocument));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CreateUserResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/CreateUserResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.artifactdatabase.rest;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Response;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.xml.DomRepresentation;
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ResourceException;
-
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-
-/**
- * Resource to create a new users within the artifact database.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class CreateUserResource
-extends      BaseResource
-{
-    /** The logger used in this class.*/
-    private static Logger logger = Logger.getLogger(CreateUserResource.class);
-
-    /** The URL part for this resource.*/
-    public static final String PATH = "/create-user";
-
-
-    @Override
-    protected Representation innerPost(Representation requestRepr)
-    throws    ResourceException
-    {
-        Document input = null;
-
-        try {
-            DomRepresentation in = new DomRepresentation(requestRepr);
-            in.setNamespaceAware(true);
-            input = in.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        logger.debug("Create user");
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        try {
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.createUser(input, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ExportResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ExportResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Request;
-import org.restlet.Response;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-
-import org.restlet.resource.ResourceException;
-
-/**
- * Resource to produce an external XML representation of a given
- * artifact to be import by ImportResource later on.
- *
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class ExportResource
-extends      BaseResource
-{
-    private static Logger logger = Logger.getLogger(ExportResource.class);
-
-    /**
-     * server URL where to reach the resource.
-     */
-    public static final String PATH = "/export/{uuid}";
-
-    @Override
-    protected Representation innerGet()
-    throws                   ResourceException
-    {
-        Request request = getRequest();
-
-        String identifier = (String)request.getAttributes().get("uuid");
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("looking for artifact id '" + identifier + "'");
-        }
-
-        ArtifactDatabase db = (ArtifactDatabase)getContext()
-            .getAttributes().get("database");
-
-        try {
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.exportArtifact(identifier, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/FactoriesResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/FactoriesResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.Representation;
-
-import org.restlet.resource.ResourceException;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-/**
- * Resource to list the available factories.
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class FactoriesResource
-extends      BaseResource
-{
-    private static Logger logger = Logger.getLogger(FactoriesResource.class);
-
-    /**
-     * server URL where to reach the resource.
-     */
-    public static final String PATH = "/factories";
-
-    @Override
-    protected Representation innerGet()
-    throws                   ResourceException
-    {
-        Document document = XMLUtils.newDocument();
-
-        ElementCreator ec = new ElementCreator(
-            document,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        ArtifactDatabase db = (ArtifactDatabase)getContext()
-            .getAttributes().get("database");
-
-        Element root = ec.create("result");
-        document.appendChild(root);
-
-        Element type = ec.create("type");
-        ec.addAttr(type, "name", "factory-list");
-        root.appendChild(type);
-
-        Element factories = ec.create("factories");
-        root.appendChild(factories);
-
-        String [][] factoryNames = db.artifactFactoryNamesAndDescriptions();
-
-        for (int i = 0; i < factoryNames.length; ++i) {
-            String [] nd = factoryNames[i];
-            Element factoryElement = ec.create("factory");
-            ec.addAttr(factoryElement, "name", nd[0]);
-            ec.addAttr(factoryElement, "description", nd[1]);
-            factories.appendChild(factoryElement);
-        }
-
-        document.normalizeDocument();
-
-        return new DomRepresentation(
-            MediaType.APPLICATION_XML, document);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/FindUserResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/FindUserResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.artifactdatabase.rest;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.xml.DomRepresentation;
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ResourceException;
-import org.restlet.Response;
-
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-/**
- * A Rest resource that finds the user provided by the artifact database.
- *
- */
-public class FindUserResource
-extends      BaseResource
-{
-    /** The logger that is used in this class.*/
-    private static Logger logger = Logger.getLogger(FindUserResource.class);
-
-    /** server URL where to reach the resource.*/
-    public static final String PATH = "/find-user";
-
-
-    @Override
-    protected Representation innerPost(Representation requestRepr)
-    throws    ResourceException
-    {
-        Document input = null;
-
-        try {
-            DomRepresentation in = new DomRepresentation(requestRepr);
-            in.setNamespaceAware(true);
-            input = in.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getLocalizedMessage(), ioe);
-
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        try {
-            logger.info(PATH);
-
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.findUser(input, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/HTTPServer.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/HTTPServer.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-package de.intevation.artifactdatabase.rest;
-
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.ArtifactDatabase;
-
-public interface HTTPServer
-{
-    void setup(Document document);
-
-    void startAsServer(ArtifactDatabase database);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ImportResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ImportResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Request;
-import org.restlet.Response;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-
-import org.w3c.dom.Document;
-
-/**
- * Resource to import an XML document containg an artifact produced by
- * the ExportResource.
- *
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class ImportResource
-extends      BaseResource
-{
-    private static Logger logger = Logger.getLogger(ImportResource.class);
-
-    /**
-     * server URL where to reach the resource.
-     */
-    public static final String PATH = "/import";
-
-    @Override
-    protected Representation innerPost(Representation requestRepr) {
-
-        Document inputDocument = null;
-        try {
-            DomRepresentation input = new DomRepresentation(requestRepr);
-            input.setNamespaceAware(true);
-            inputDocument = input.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getMessage());
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        Request request = getRequest();
-
-        ArtifactDatabase db = (ArtifactDatabase)getContext()
-            .getAttributes().get("database");
-
-        try {
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.importArtifact(inputDocument, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/JettyServer.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/JettyServer.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-package de.intevation.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-
-import org.restlet.Component;
-import org.restlet.Server;
-
-import org.restlet.ext.jetty.HttpServerHelper;
-
-import org.apache.log4j.Logger;
-
-public class JettyServer
-extends      Standalone
-{
-    private static Logger logger = Logger.getLogger(JettyServer.class);
-
-    @Override
-    public void startAsServer(ArtifactDatabase db) {
-
-        Component component = new Component();
-
-        RestApp app = new RestApp(db);
-
-        Server server = createServer();
-
-        // TODO: Do more sophisticated Jetty server configuration here.
-
-        component.getServers().add(server);
-
-        component.getDefaultHost().attach(app);
-
-        logServerStart();
-
-        HttpServerHelper serverHelper = new HttpServerHelper(server);
-
-        try {
-            serverHelper.start();
-        }
-        catch (Exception e) {
-            logger.error(e.getLocalizedMessage(), e);
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ListCollectionsResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ListCollectionsResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.xml.DomRepresentation;
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.Request;
-import org.restlet.resource.ResourceException;
-import org.restlet.Response;
-
-
-/**
- * A Rest resource that lists the collections of a specific user provided by
- * the artifact database.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class ListCollectionsResource
-extends      BaseResource
-{
-   /** The logger that is used in this class.*/
-    private static Logger logger =
-        Logger.getLogger(ListCollectionsResource.class);
-
-    /** server URL where to reach the resource.*/
-    public static final String PATH = "/list-collections/{ownerid}";
-
-
-    @Override
-    protected Representation innerGet()
-    throws                   ResourceException
-    {
-        Request request     = getRequest();
-
-        String ownerId      = (String) request.getAttributes().get("ownerid");
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        try {
-            logger.info("List collections owned by " + ownerId);
-
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.listCollections(ownerId, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ListUsersResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ListUsersResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.xml.DomRepresentation;
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ResourceException;
-import org.restlet.Response;
-
-/**
- * A Rest resource that lists the users provided by the artifact database.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class ListUsersResource
-extends      BaseResource
-{
-    /** The logger that is used in this class.*/
-    private static Logger logger = Logger.getLogger(ListUsersResource.class);
-
-    /** server URL where to reach the resource.*/
-    public static final String PATH = "/list-users";
-
-
-    @Override
-    protected Representation innerGet()
-    throws                   ResourceException
-    {
-        ArtifactDatabase db = getArtifactDatabase();
-
-        try {
-            logger.info(PATH);
-
-            return new DomRepresentation(
-                MediaType.APPLICATION_XML,
-                db.listUsers(getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/OutRepresentation.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/OutRepresentation.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase.DeferredOutput;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.restlet.data.MediaType;
-
-import org.restlet.representation.OutputRepresentation;
-
-/**
- * Special representation to serve the out()-outputs
- * via DeferredOutput efficently .
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class OutRepresentation
-extends      OutputRepresentation
-{
-    /**
-     * The deferred output fetched from ArtifactDatabase.out().
-     */
-    protected DeferredOutput out;
-
-    /**
-     * Constructor to create representation with a given MIME type and
-     * a deferred output.
-     * @param mediaType The MIME type of this representation.
-     * @param out The deferred output from the ArtifactDatabase.out() call.
-     */
-    public OutRepresentation(MediaType mediaType, DeferredOutput out) {
-        super(mediaType);
-        this.out = out;
-    }
-
-    /**
-     * Overwrites the write(OutputStream) of OutRepresentation to serve
-     * the data from the deferred output.
-     * @param output the stream where to write the data into.
-     * @throws IOException Thrown if an exception occurred while writing
-     * the data to the output stream.
-     */
-    public void write(OutputStream output) throws IOException {
-        out.write(output);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/RestApp.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/RestApp.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-
-import java.util.concurrent.ConcurrentMap;
-
-import org.restlet.Application;
-import org.restlet.Context;
-import org.restlet.Restlet;
-
-import org.restlet.routing.Router;
-
-/**
- * This is the core REST application that binds the serveral resources
- * used to manage the artifact database to the HTTP server provided
- * by the Restlet framework.
- *
- * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
- */
-public class RestApp
-extends      Application
-{
-    /**
-     * The central artifact database instance to work with.
-     */
-    protected ArtifactDatabase database;
-
-    /**
-     * Default constructor
-     */
-    public RestApp() {
-    }
-
-    public RestApp(Context context, ArtifactDatabase database) {
-        super(context);
-        this.database = database;
-    }
-
-    /**
-     * Constructor to create REST appliction bound to a specific
-     * artifact database.
-     *
-     * @param database The artifact database to be used.
-     */
-    public RestApp(ArtifactDatabase database) {
-        this.database = database;
-    }
-
-    /**
-     * Overwrites the createRoot() method of Application to
-     * build the resource tree to form the exposed server URLs.
-     *
-     * @return The root of the URL tree exposed by the HTTP server.
-     */
-    @Override
-    public Restlet createRoot() {
-
-        Context context = getContext();
-
-        ConcurrentMap map = context.getAttributes();
-        map.put("database", database);
-
-        Router router = new Router(context);
-
-        router.attach(ServicesResource.PATH,    ServicesResource.class);
-        router.attach(ServiceResource.PATH,     ServiceResource.class);
-        router.attach(FactoriesResource.PATH,   FactoriesResource.class);
-        router.attach(CreateResource.PATH,      CreateResource.class);
-        router.attach(ArtifactResource.PATH,    ArtifactResource.class);
-        router.attach(ArtifactOutResource.PATH, ArtifactOutResource.class);
-        router.attach(ExportResource.PATH,      ExportResource.class);
-        router.attach(ImportResource.PATH,      ImportResource.class);
-        router.attach(CreateUserResource.PATH,  CreateUserResource.class);
-        router.attach(ListUsersResource.PATH,   ListUsersResource.class);
-        router.attach(UserResource.PATH,        UserResource.class);
-        router.attach(FindUserResource.PATH,    FindUserResource.class);
-        router.attach(
-            CreateCollectionResource.PATH, CreateCollectionResource.class);
-        router.attach(
-            ListCollectionsResource.PATH, ListCollectionsResource.class);
-        router.attach(
-            CollectionResource.PATH, CollectionResource.class);
-        router.attach(
-            CollectionOutResource.PATH, CollectionOutResource.class);
-
-        return router;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServiceResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServiceResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.Service;
-
-/**
- * Resource to process incoming XML documents with a given service.
- *
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class ServiceResource
-extends      BaseResource
-{
-    private static Logger logger = Logger.getLogger(ServiceResource.class);
-
-    /**
-     * server URL where to reach the resource.
-     */
-    public static final String PATH = "/service/{service}";
-
-    /**
-     * Error message if no corresponing service is provided by
-     * the artifact database.
-     */
-    public static final String NO_SUCH_ACTION_MESSAGE = "no such service";
-
-    @Override
-    protected Representation innerPost(Representation requestRepr) {
-
-        Document inputDocument = null;
-        try {
-            DomRepresentation input = new DomRepresentation(requestRepr);
-            input.setNamespaceAware(true);
-            inputDocument = input.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getMessage());
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        Request request = getRequest();
-
-        String service = (String)request.getAttributes().get("service");
-
-        ArtifactDatabase db = (ArtifactDatabase)getContext()
-            .getAttributes().get("database");
-
-        try {
-            return guessRepresentation(
-                db.process(service, inputDocument, getCallMeta()));
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-    }
-
-    protected static Representation guessRepresentation(Service.Output output) {
-
-        MediaType mediaType = new MediaType(output.getMIMEType());
-        Object    data      = output.getData();
-
-        if (data instanceof Document) {
-            return new DomRepresentation(mediaType, (Document)data);
-        }
-
-        if (data instanceof byte []) {
-            return new ByteArrayRepresentation(mediaType, (byte [])data);
-        }
-
-        return new EmptyRepresentation();
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServicesResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServicesResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-
-import org.restlet.ext.xml.DomRepresentation;
-
-import org.restlet.representation.Representation;
-
-import org.restlet.resource.ResourceException;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-/**
- * Resource to list the available service offered by the artifact database.
- *
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class ServicesResource
-extends      BaseResource
-{
-    private static Logger logger = Logger.getLogger(ServicesResource.class);
-
-    /**
-     * server URL where to reach the resource.
-     */
-    public static final String PATH = "/services";
-
-    @Override
-    protected Representation innerGet()
-    throws                   ResourceException
-    {
-        Document document = XMLUtils.newDocument();
-
-        ElementCreator ec = new ElementCreator(
-            document,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        ArtifactDatabase db = (ArtifactDatabase)getContext()
-            .getAttributes().get("database");
-
-        Element root = ec.create("result");
-        document.appendChild(root);
-
-        Element type = ec.create("type");
-        ec.addAttr(type, "name", "service-list");
-        root.appendChild(type);
-
-        Element factories = ec.create("services");
-        root.appendChild(factories);
-
-        String [][] factoryNames = db.serviceNamesAndDescriptions();
-
-        for (int i = 0; i < factoryNames.length; ++i) {
-            String [] nd = factoryNames[i];
-            Element factoryElement = ec.create("service");
-            ec.addAttr(factoryElement, "name", nd[0]);
-            ec.addAttr(factoryElement, "description", nd[1]);
-            factories.appendChild(factoryElement);
-        }
-
-        document.normalizeDocument();
-
-        return new DomRepresentation(
-            MediaType.APPLICATION_XML, document);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/Standalone.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/Standalone.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifacts.ArtifactDatabase;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Component;
-import org.restlet.Server;
-
-import org.restlet.data.Protocol;
-
-import org.w3c.dom.Document;
-
-/**
- * Starts an HTTP server bound to a RestApp.
- * The server (binding interface and port) is configure via the
- * global configuration.
- *
- * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
- */
-public class Standalone
-implements   HTTPServer
-{
-    private static Logger logger = Logger.getLogger(Standalone.class);
-
-    /**
-     * XPath to figure out the port where to listen from the
-     * global configuration.
-     */
-    public static final String REST_PORT =
-        "/artifact-database/rest-server/port/text()";
-
-    /**
-     * XPath to figure out from global configuration
-     * which network interface to use to bind the HTTP server.
-     */
-    public static final String LISTEN_INTERFACE =
-        "/artifact-database/rest-server/listen/text()";
-
-    /**
-     * The default port of the HTTP server: 8181
-     */
-    public static final int DEFAULT_PORT = 8181;
-
-    public static final String MAX_THREADS =
-        "/artifact-database/rest-server/max-threads/text()";
-
-    public static final String MAX_THREADS_DEFAULT =
-        "1024";
-
-    protected int     port;
-
-    protected String  listen;
-
-    protected String  maxThreads;
-
-    public Standalone() {
-    }
-
-    @Override
-    public void setup(Document document) {
-        String portString = XMLUtils.xpathString(document, REST_PORT, null);
-
-        port = DEFAULT_PORT;
-
-        if (portString != null) {
-            try {
-                port = Integer.parseInt(portString);
-                if (port < 0) {
-                    throw new NumberFormatException();
-                }
-            }
-            catch (NumberFormatException nfe) {
-                logger.error("rest port is not a positive integer value.", nfe);
-                return;
-            }
-        }
-
-        listen     = XMLUtils.xpathString(document, LISTEN_INTERFACE, null);
-        maxThreads = XMLUtils.xpathString(document, MAX_THREADS, null);
-    }
-
-    protected Server createServer() {
-        return listen != null && listen.length() > 0
-            ? new Server(Protocol.HTTP, listen, port)
-            : new Server(Protocol.HTTP, port);
-    }
-
-    protected void logServerStart() {
-        logger.info("Starting " + getClass().getName() + " HTTP server on "
-            + (listen != null ? listen : "*")
-            + ":" + port);
-    }
-
-    /**
-     * Builds a RestApp wrapped around the given artifact database,
-     * and bind this application to HTTP server. The HTTP server
-     * is configured by the global configuration. If no port is
-     * given by the configuration the default port is used. If
-     * no interface is given the HTTP server is reachable from
-     * all interfaces.
-     * @param db The artifact database to be exposed via the
-     * REST application.
-     */
-    @Override
-    public void startAsServer(ArtifactDatabase db) {
-
-        RestApp app = new RestApp(db);
-
-        Component component = new Component();
-
-        Server server = createServer();
-
-        component.getServers().add(server);
-
-        server.getContext().getParameters().add(
-            "maxThreads", maxThreads != null && maxThreads.length() > 0
-                ? maxThreads
-                : MAX_THREADS_DEFAULT);
-
-        component.getDefaultHost().attach(app);
-
-        logServerStart();
-
-        try {
-            component.start();
-        }
-        catch (Exception e) {
-            logger.error(e.getLocalizedMessage(), e);
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/UserResource.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/UserResource.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +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.artifactdatabase.rest;
-
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.xml.DomRepresentation;
-import org.restlet.representation.EmptyRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.Request;
-import org.restlet.Response;
-
-import org.w3c.dom.Document;
-
-/**
- * A resource that handles actions to a specific user.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
- */
-public class UserResource
-extends      BaseResource
-{
-    /** The logger that is used in this class. */
-    private static Logger logger = Logger.getLogger(UserResource.class);
-
-    /** server URL where to reach the resource. */
-    public static final String PATH = "/user/{uuid}";
-
-    /**
-     * XPath to figure out the type of action (feed, advance) via the
-     * incoming POST request.
-     */
-    public static final String XPATH_ACTION = "/art:action/art:type/@name";
-
-    /** Error message if no action was given. */
-    public static final String NO_ACTION_MSG = "no action given";
-
-    /** Error message if a unknown action was given. */
-    public static final String NO_SUCH_ACTION_MSG = "no such action";
-
-    /** Action name for deleting users. */
-    public static final String ACTION_DELETE = "delete";
-
-
-    @Override
-    protected Representation innerPost(Representation requestRepr) {
-        Document inputDocument = null;
-
-        try {
-            DomRepresentation input = new DomRepresentation(requestRepr);
-            input.setNamespaceAware(true);
-            inputDocument = input.getDocument();
-        }
-        catch (IOException ioe) {
-            logger.error(ioe.getMessage());
-            Response response = getResponse();
-            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
-            return new EmptyRepresentation();
-        }
-
-        String action = XMLUtils.xpathString(
-            inputDocument,
-            XPATH_ACTION,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (action == null || action.length() == 0) {
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, NO_ACTION_MSG);
-            return new EmptyRepresentation();
-        }
-
-        Request request = getRequest();
-
-        String identifier = (String)request.getAttributes().get("uuid");
-
-        ArtifactDatabase db = getArtifactDatabase();
-
-        return dispatch(identifier, action, inputDocument, db);
-    }
-
-    /**
-     * Method to figure out which POST action (feed or advance) was
-     * triggered and perform this operation on the artifact specified
-     * by 'identifier' and found in the artifact database 'db'
-     * @param identifier The identifier of the artifact.
-     * @param action The action to be performed.
-     * @param source The input document to further parameterize the
-     * operation.
-     * @param db The artifact database where to find the artifact.
-     * @return The representation produced by the performed action.
-     */
-    protected Representation dispatch(
-        String           identifier,
-        String           action,
-        Document         source,
-        ArtifactDatabase db)
-    {
-        Document out = null;
-
-        logger.info("Action: " + action + " | User: " + identifier);
-
-        try {
-            if (action.equals(ACTION_DELETE)) {
-                out = db.deleteUser(identifier, getCallMeta());
-            }
-            else {
-                throw new ArtifactDatabaseException(NO_SUCH_ACTION_MSG);
-            }
-        }
-        catch (ArtifactDatabaseException adbe) {
-            logger.warn(adbe.getLocalizedMessage(), adbe);
-            Response response = getResponse();
-            response.setStatus(
-                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
-            return new EmptyRepresentation();
-        }
-
-        return new DomRepresentation(MediaType.APPLICATION_XML, out);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/package.html
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/package.html	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-</head>
-<body>
-The REST interface of the artfifact database.  This package contains classes
-that offer the URL resources to manage the artifacts via REST.
-</body>
-</html>
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,406 +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.artifactdatabase.state;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.xpath.XPathConstants;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.CallMeta;
-
-import de.intevation.artifacts.common.utils.Config;
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifactdatabase.data.StateData;
-
-
-/**
- * An abstract implementation of a {@link State}. It implements some basic
- * methods that return the id, description and data. The methods
- * <code>describe()</code> and <code>setup()</code> depend on the concrete class
- * and need to be implemented by those.
- */
-public abstract class AbstractState implements State {
-
-    /** The XPath to the ID of the state relative to the state node in the
-     * configuration. */
-    public static final String XPATH_ID = "@id";
-
-    /** The XPath to the description of the state relative to the state node in
-     * the configuration. */
-    public static final String XPATH_DESCRIPTION = "@description";
-
-    /** The XPath that points to the help text.*/
-    public static final String XPATH_HELP_TEXT = "@helpText";
-
-    /** The XPath to the output nodes of the state configuration. */
-    public static final String XPATH_OUTPUT_MODES = "outputmodes/outputmode";
-
-    /** The XPath to the list of facets relative to the output mode it belongs
-     * to. */
-    public static final String XPATH_FACETS = "facets/facet";
-
-    public static final String XPATH_HELP_URL = "/artifact-database/help-url/text()";
-
-    public static final String HELP_URL = "${help.url}";
-
-
-    /** The logger that is used in this class. */
-    private static Logger logger = Logger.getLogger(AbstractState.class);
-
-
-    /** The ID of the state. */
-    protected String id;
-
-    /** The description of the state. */
-    protected String description;
-
-    /** The help text for this state.*/
-    protected String helpText;
-
-    /** The data provided by this state. */
-    protected Map<String, StateData> data;
-
-    /** A list of output modes which are available for this state. */
-    protected List<Output> outputs;
-
-    private static String helpUrl;
-
-
-    public AbstractState() {
-        outputs = new ArrayList<Output>();
-    }
-
-    public static synchronized final String getHelpUrl() {
-        if (helpUrl == null) {
-            helpUrl = Config.getStringXPath(XPATH_HELP_URL, HELP_URL);
-        }
-        return helpUrl;
-    }
-
-    public static String replaceHelpUrl(String string) {
-        return string.replace(HELP_URL, getHelpUrl());
-    }
-
-
-    /**
-     * The default constructor.
-     *
-     * @param id The ID of the state.
-     * @param description The description of the state.
-     */
-    public AbstractState(String id, String description) {
-        super();
-
-        this.id          = id;
-        this.description = description;
-    }
-
-
-    public AbstractState(String id, String description, String helpText) {
-        this(id, description);
-        this.helpText = replaceHelpUrl(helpText);
-    }
-
-
-    /**
-     * Returns the ID of the state.
-     *
-     * @return the ID of the state.
-     */
-    public String getID() {
-        return id;
-    }
-
-
-    /**
-     * Set the ID of the state.
-     *
-     * @param id The ID of the state.
-     */
-    public void setID(String id) {
-        this.id = id;
-    }
-
-
-    /**
-     * Returns the description of the state.
-     *
-     * @return the description of the state.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-
-    /**
-     * Set the description of the state.
-     *
-     * @param description The description of the state.
-     */
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-
-    /**
-     * Returns the help text of this state.
-     *
-     * @return the help text.
-     */
-    public String getHelpText() {
-        return helpText;
-    }
-
-
-    /**
-     * Set the help text for this state.
-     *
-     * @param helpText The help text.
-     */
-    public void setHelpText(String helpText) {
-        this.helpText = replaceHelpUrl(helpText);
-    }
-
-
-    /**
-     * Returns the data of the state.
-     *
-     * @return the data of the state.
-     */
-    public Map<String, StateData> getData() {
-        return data;
-    }
-
-
-    /**
-     * Returns a specific data object of the state.
-     *
-     * @param name The name of the data object.
-     *
-     * @return a data object of the state or null if no such data object exists.
-     */
-    public StateData getData(String name) {
-        if (data != null) {
-            return data.get(name);
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Add new data to the state. NOTE: If there is already an object existing
-     * with the key <i>name</i>, this object is overwritten by the new value.
-     *
-     * @param name The name of the data object.
-     * @param data The data object.
-     */
-    public void addData(String name, StateData data) {
-        if (this.data == null) {
-            this.data = new HashMap<String, StateData>();
-        }
-
-        this.data.put(name, data);
-    }
-
-
-    /**
-     * Returns the list of possible outputs of this state. The list is empty
-     * if no output is available for this state.
-     *
-     * @return a list of possible outputs of this state.
-     */
-    public List<Output> getOutputs() {
-        return outputs;
-    }
-
-
-    /**
-     * Initialize the state based on the state node in the configuration.
-     *
-     * @param config The state configuration node.
-     */
-    public void setup(Node config) {
-        logger.info("AbstractState.setup");
-
-        id = (String) XMLUtils.xpath(config, XPATH_ID, XPathConstants.STRING);
-
-        description = (String) XMLUtils.xpath(
-            config, XPATH_DESCRIPTION, XPathConstants.STRING);
-
-        helpText = (String) XMLUtils.xpath(
-            config, XPATH_HELP_TEXT, XPathConstants.STRING);
-
-        if (helpUrl != null) {
-            helpUrl = replaceHelpUrl(helpUrl);
-        }
-
-        setupOutputs(config);
-    }
-
-
-    /**
-     * This default implementation does nothing at all.
-     *
-     * @param orig
-     * @param owner
-     * @param context
-     * @param callMeta
-     */
-    public void initialize(
-        Artifact orig,
-        Artifact owner,
-        Object   context,
-        CallMeta callMeta
-    ) {
-        // do nothing.
-    }
-
-
-    /**
-     * This method tries reading the available output nodes configured in the
-     * state configuration and adds possible Outputs to the outputs list.
-     *
-     * @param config The state configuration node.
-     */
-    protected void setupOutputs(Node config) {
-        NodeList outs = (NodeList) XMLUtils.xpath(
-            config,
-            XPATH_OUTPUT_MODES,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (outs == null || outs.getLength() == 0) {
-            return;
-        }
-
-        int size = outs.getLength();
-
-        for (int i = 0; i < size; i++) {
-            addOutput(buildOutput(outs.item(i)));
-        }
-    }
-
-    /**
-     * This methods allows subclasses to manually add outputs
-     *
-     * @param out The output to add
-     */
-    protected void addOutput(Output out) {
-        outputs.add(out);
-    }
-
-    /**
-     * A helper method that creates an Output object based on the <i>out</i>
-     * node.
-     *
-     * @param out The output node configuration.
-     *
-     * @return an Output object.
-     */
-    protected Output buildOutput(Node out) {
-        String name = XMLUtils.xpathString(
-            out, "@name", ArtifactNamespaceContext.INSTANCE);
-
-        String desc = XMLUtils.xpathString(
-            out, "@description", ArtifactNamespaceContext.INSTANCE);
-
-        String mimetype = XMLUtils.xpathString(
-            out, "@mime-type", ArtifactNamespaceContext.INSTANCE);
-
-        String type = XMLUtils.xpathString(
-            out, "@type", ArtifactNamespaceContext.INSTANCE);
-
-        if (name == null) {
-            return null;
-        }
-
-        NodeList facets = (NodeList) XMLUtils.xpath(
-            out,
-            XPATH_FACETS,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (facets == null || facets.getLength() == 0) {
-            return new DefaultOutput(name, desc, mimetype, type);
-        }
-
-        int num = facets.getLength();
-
-        List<Facet> facetList = new ArrayList<Facet>(num);
-
-        for (int i = 0; i < num; i++) {
-            Facet facet = buildFacet(facets.item(i));
-
-            if (facet != null) {
-                facetList.add(facet);
-            }
-        }
-
-        return new DefaultOutput(name, desc, mimetype, facetList, type);
-    }
-
-
-    /**
-     * A helper method that creates a Facet object based on the <i>facet</i>
-     * node.
-     *
-     * @param facet The facet node.
-     *
-     * @return a Facet object or null if no valid Facet was found.
-     */
-    protected Facet buildFacet(Node facet) {
-        String name = XMLUtils.xpathString(
-            facet, "@name", ArtifactNamespaceContext.INSTANCE);
-
-        String desc = XMLUtils.xpathString(
-            facet, "@description", ArtifactNamespaceContext.INSTANCE);
-
-        return name != null ? new DefaultFacet(name, desc) : null;
-    }
-
-
-    /**
-     * Describes the UI of the state. This method needs to be implemented by
-     * concrete subclasses.
-     *
-     * @param artifact A reference to the artifact this state belongs to.
-     * @param document Describe doucment.
-     * @param rootNode Parent node for all new elements.
-     * @param context The CallContext.
-     * @param uuid The uuid of an artifact.
-     */
-    public abstract Element describe(
-        Artifact    artifact,
-        Document    document,
-        Node        rootNode,
-        CallContext context,
-        String      uuid
-    );
-
-
-    @Override
-    public void endOfLife(Artifact artifact, Object context) {
-        // nothing to do here
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.List;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.DataProvider;
-
-
-/**
- * A bundle of a "native" Facet and its Artifact.
- */
-public class ArtifactAndFacet implements DataProvider {
-    /** The Artifact. */
-    protected Artifact artifact;
-
-    /** The (native) facet. */
-    protected Facet    facet;
-
-    /** An alternative facet description that might be set from outside. */
-    protected String facetDescription;
-
-
-    /** Trivial constructor. */
-    public ArtifactAndFacet(
-        Artifact a,
-        Facet f
-    ) {
-        this.artifact   = a;
-        this.facet      = f;
-    }
-
-
-    /** Get data (to plot). */
-    public Object getData(CallContext context) {
-        return facet.getData(artifact, context);
-    }
-
-
-    /** Get data (for other facet). */
-    @Override
-    public Object provideData(Object key, Object param, CallContext context) {
-        return facet.provideBlackboardData(artifact, key, param, context);
-    }
-
-
-    /** (Maybe) Register on blackboard (depending on facet). */
-    @Override
-    public void register(CallContext context) {
-        List keys = facet.getDataProviderKeys(this.artifact, context);
-        if (keys == null) {
-            return;
-        }
-        for (Object key: keys) {
-            context.registerDataProvider(key, this);
-        }
-    }
-
-
-    /** Access the artifact. */
-    public Artifact getArtifact() {
-        return artifact;
-    }
-
-
-    /** Access the (native) facet. */
-    public Facet getFacet() {
-        return facet;
-    }
-
-
-    /** Shortcut to facets name. */
-    public String getFacetName() {
-        return facet.getName();
-    }
-
-
-    /**
-     * Returns the description for a facet. The return value depends on the
-     * internal <i>facetDescription</i> instance variable. If this has been set
-     * by setFacetDescription, this value is returned, otherwise the return
-     * value of facet.getDescription().
-     */
-    public String getFacetDescription() {
-        if (facetDescription == null) {
-            return facet.getDescription();
-        }
-
-        return facetDescription;
-    }
-
-
-    public void setFacetDescription(String facetDescription) {
-        this.facetDescription = facetDescription;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Attribute.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Attribute.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.io.Serializable;
-
-import org.w3c.dom.Node;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface Attribute extends Serializable {
-
-    /**
-     * Returns the name of this Attribute.
-     *
-     * @return the name of this Attribute.
-     */
-    String getName();
-
-    /**
-     * Returns the value of this Attribute.
-     *
-     * @return the value of this Attribute.
-     */
-    Object getValue();
-
-    /**
-     * Sets the value of this Attribute.
-     *
-     * @param value The new value.
-     */
-    void setValue(Object value);
-
-    /**
-     * Transforms this Attribute into XML.
-     *
-     * @param parent The parent node.
-     *
-     * @return the Node that represents this Attribute.
-     */
-    Node toXML(Node parent);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultAttribute.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultAttribute.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultAttribute implements Attribute {
-
-    protected String name;
-
-    protected Object value;
-
-
-    public DefaultAttribute(String name, Object value) {
-        this.name  = name;
-        this.value = value;
-    }
-
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-
-    @Override
-    public Object getValue() {
-        return value;
-    }
-
-
-    @Override
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-
-    @Override
-    public Node toXML(Node parent) {
-        Document owner = parent.getOwnerDocument();
-        Element   attr = owner.createElement(getName());
-
-        parent.appendChild(attr);
-
-        attr.setTextContent(String.valueOf(getValue()));
-
-        return attr;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.List;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.CallContext;
-
-import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
-
-
-/**
- * The default implementation of a Facet.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultFacet implements Facet {
-
-    /** The index of this facet. */
-    protected int index;
-
-    /** The name of this facet. */
-    protected String name;
-
-    /** The description of this facet. */
-    protected String description;
-
-
-    /** Trivial, empty constructor. */
-    public DefaultFacet() {
-    }
-
-
-    /**
-     * The default constructor to create new Facet objects.
-     *
-     * @param name The name of this new facet.
-     * @param description The description of this new facet.
-     */
-    public DefaultFacet(String name, String description) {
-        this(0, name, description);
-    }
-
-
-    /**
-     * The default constructor to create new Facet objects.
-     *
-     * @param index The index of this new facet.
-     * @param name The name of this new facet.
-     * @param description The description of this new facet.
-     */
-    public DefaultFacet(int index, String name, String description) {
-        this.index       = index;
-        this.name        = name;
-        this.description = description;
-    }
-
-
-    /** Get index. */
-    public int getIndex() {
-        return index;
-    }
-
-
-    /** Returns the name ('type'). */
-    public String getName() {
-        return name;
-    }
-
-
-    /** Returns the description (e.g. displayed in gui). */
-    public String getDescription() {
-        return description;
-    }
-
-
-    /**
-     * @return null
-     */
-    public Object getData(Artifact artifact, CallContext context) {
-        return null;
-    }
-
-
-    /**
-     * (Do not) provide data.
-     * Override to allow other facets to access your data.
-     * @return always null.
-     */
-    public Object provideBlackboardData(
-        Artifact artifact,
-        Object key,
-        Object param,
-        CallContext context
-    ) {
-        return null;
-    }
-
-
-    /*
-     * Return list of keys (objects) for which this facet can provide data
-     * ("external parameterization"), for other facets, via blackboard.
-     * These are the keys that are independent from the current call (thus
-     * 'static').
-     * @param artifact that this facet belongs to.
-     */
-    public List getStaticDataProviderKeys(Artifact artifact) {
-        return null;
-    }
-
-    /**
-     * Return list of keys (objects) for which this facet can provide data
-     * ("external parameterization"), for other facets, via blackboard.
-     * @param artifact that this facet belongs to.
-     */
-    public List getDataProviderKeys(Artifact artifact, CallContext context) {
-        return getStaticDataProviderKeys(artifact);
-    }
-
-
-    /** Create a xml represantation. */
-    public Node toXML(Document doc) {
-        ElementCreator ec = new ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element facet = ec.create("facet");
-        ec.addAttr(facet, "description", description, true);
-        ec.addAttr(facet, "name", name, true);
-        ec.addAttr(facet, "index", String.valueOf(index), true);
-
-        return facet;
-    }
-
-
-    /** Create a string representation. */
-    public String toString() {
-        return new StringBuilder("name = '")
-            .append(name).append("', index = ")
-            .append(index).append(", description = '")
-            .append(description).append("'")
-            .toString();
-    }
-
-
-    /**
-     * Copies name, index and description of other facet.
-     */
-    public void set(Facet other) {
-        index       = other.getIndex();
-        name        = other.getName();
-        description = other.getDescription();
-    }
-
-
-    /** Create a deep copy of this facet. */
-    public Facet deepCopy() {
-        DefaultFacet copy = new DefaultFacet();
-        copy.set(this);
-        return copy;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * The default implementation of an Output.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultOutput implements Output {
-
-    protected String name;
-
-    protected String description;
-
-    protected String mimeType;
-
-    protected String type;
-
-    protected List<Facet> facets;
-
-    protected Settings settings;
-
-
-    /**
-     * The default constructor that instantiates a new DefaultOutput object.
-     *
-     * @param name The name of this output.
-     * @param description The description of this output.
-     * @param mimeType The mimetype of this output.
-     */
-    public DefaultOutput(String name, String description, String mimeType) {
-        this.name        = name;
-        this.description = description;
-        this.mimeType    = mimeType;
-        this.type        = "";
-        this.facets      = new ArrayList<Facet>();
-    }
-
-
-    public DefaultOutput(
-        String      name,
-        String      description,
-        String      mimeType,
-        String      type)
-    {
-        this(name, description, mimeType);
-
-        this.facets = new ArrayList<Facet>();
-        this.type   = type;
-    }
-
-
-    public DefaultOutput(
-        String      name,
-        String      description,
-        String      mimeType,
-        List<Facet> facets)
-    {
-        this(name, description, mimeType);
-
-        this.type   = "";
-        this.facets = facets;
-    }
-
-
-    /**
-     * This constructor builds a new Output object that contains facets as well.
-     *
-     * @param name The name of this output.
-     * @param description The description of this output.
-     * @param mimeType The mimetype of this output.
-     * @param facets The list of facets supported by this output.
-     * @param type The type of the Output e.g. chart
-     */
-    public DefaultOutput(
-        String      name,
-        String      description,
-        String      mimeType,
-        List<Facet> facets,
-        String      type)
-    {
-        this(name, description, mimeType, facets);
-
-        this.type = type;
-    }
-
-
-    /**
-     * Returns the name of this output.
-     *
-     * @return the name of this output.
-     */
-    public String getName() {
-        return name;
-    }
-
-
-    /**
-     * Returns the description of this output.
-     *
-     * @return the description of this output.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-
-    /**
-     * Returns the mimetype of this output.
-     *
-     * @return the mimetype of this output.
-     */
-    public String getMimeType() {
-        return mimeType;
-    }
-
-
-    public String getType() {
-        return type;
-    }
-
-
-    /**
-     * Returns the list of facets supported by this output.
-     *
-     * @return the list of facets supported by this output.
-     */
-    public List<Facet> getFacets() {
-        return facets;
-    }
-
-
-    public void addFacet(Facet facet) {
-        if (facet != null && !facets.contains(facet)) {
-            facets.add(facet);
-        }
-    }
-
-
-    public void addFacets(List<Facet> facets) {
-        this.facets.addAll(facets);
-    }
-
-
-    @Override
-    public void setFacets(List<Facet> facets) {
-        this.facets = facets;
-    }
-
-
-    @Override
-    public void setSettings(Settings settings) {
-        this.settings = settings;
-    }
-
-
-    @Override
-    public Settings getSettings() {
-        return settings;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSection.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSection.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-/**
- * Attributes keep the order in which they were inserted.
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultSection implements Section {
-
-    protected String id;
-
-    protected List<Section> subsections;
-
-    /** Attribute-map. */
-    protected Map<String, Attribute> attributes;
-
-
-    /**
-     * Creates a new DefaultSection instance. <b>Note, that the <i>id</i> is used
-     * as Node name of the new Element that is created in toXML().</b>
-     */
-    public DefaultSection(String id) {
-        this.id          = id;
-        // Use LinkedHashMap to keep insertion order.
-        this.attributes  = new LinkedHashMap<String, Attribute>();
-        this.subsections = new ArrayList<Section>();
-    }
-
-
-    @Override
-    public String getId() {
-        return id;
-    }
-
-
-    @Override
-    public void addSubsection(Section subsection) {
-        if (subsection != null) {
-            subsections.add(subsection);
-        }
-    }
-
-
-    @Override
-    public int getSubsectionCount() {
-        return subsections.size();
-    }
-
-
-    @Override
-    public Section getSubsection(int pos) {
-        if (pos >= 0 && pos < getSubsectionCount()) {
-            return subsections.get(pos);
-        }
-
-        return null;
-    }
-
-
-    /** Adding attribute to end of list. */
-    @Override
-    public void addAttribute(String key, Attribute attribute) {
-        if (key != null && key.length() > 0 && attribute != null) {
-            attributes.put(key, attribute);
-        }
-    }
-
-
-    @Override
-    public Attribute getAttribute(String key) {
-        if (key == null || key.length() == 0) {
-            return null;
-        }
-
-        return attributes.get(key);
-    }
-
-
-    @Override
-    public Set<String> getKeys() {
-        return attributes.keySet();
-    }
-
-
-    @Override
-    public void toXML(Node parent) {
-        Document owner     = parent.getOwnerDocument();
-        Element  sectionEl = owner.createElement(getId());
-
-        parent.appendChild(sectionEl);
-
-        for (String key: getKeys()) {
-            Attribute attr = getAttribute(key);
-            attr.toXML(sectionEl);
-        }
-
-        for (int i = 0, n = getSubsectionCount(); i < n; i++) {
-            Section subsection = getSubsection(i);
-            subsection.toXML(sectionEl);
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSettings.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSettings.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class DefaultSettings implements Settings {
-
-    protected List<Section> sections;
-
-    public DefaultSettings() {
-        sections = new ArrayList<Section>();
-    }
-
-    @Override
-    public void addSection(Section section) {
-        if (section != null) {
-            sections.add(section);
-        }
-    }
-
-    @Override
-    public int getSectionCount() {
-        return sections.size();
-    }
-
-    @Override
-    public Section getSection(int pos) {
-        if (pos >= 0 && pos < getSectionCount()) {
-            return sections.get(pos);
-        }
-
-        return null;
-    }
-
-    @Override
-    public void removeSection(Section section) {
-        if (section != null) {
-            sections.remove(section);
-        }
-    }
-
-    @Override
-    public void toXML(Node parent) {
-        Document owner    = parent.getOwnerDocument();
-        Element  settings = owner.createElement("settings");
-
-        parent.appendChild(settings);
-
-        for (Section section: sections) {
-            section.toXML(settings);
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.List;
-
-import java.io.Serializable;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface Facet extends Serializable {
-
-    /**
-     * Returns the index of this facet.
-     *
-     * @return the index of this facet.
-     */
-    int getIndex();
-
-    /**
-     * Returns the name of this facet.
-     *
-     * @return the name of this facet.
-     */
-    String getName();
-
-
-    /**
-     * Returns the description of this facet.
-     *
-     * @return the description of this facet.
-     */
-    String getDescription();
-
-
-    /**
-     * Returns the data this facet requires.
-     *
-     * @param artifact The owner artifact.
-     * @param context The CallContext.
-     *
-     * @return the data.
-     */
-    Object getData(Artifact artifact, CallContext context);
-
-
-    /**
-     * Get keys for which this Facet can provide data (for other facets, not
-     * for plot).
-     * @param artifact Artifact that this facet belongs to.
-     * @return list of keys
-     */
-    List getDataProviderKeys(Artifact artifact, CallContext context);
-
-
-    /**
-     * Provide data to other facet.
-     *
-     * @param art  The artifact that this facet belongs to.
-     * @param key  the key of the requested service.
-     * @param prm  optional parameters.
-     * @param ctxt the callcontext.
-     *
-     * @return the data
-     */
-    Object provideBlackboardData(
-        Artifact art,
-        Object key,
-        Object prm,
-        CallContext ctxt);
-
-
-    /**
-     * Write the internal representation of a facet to a node.
-     *
-     * @param doc A Document.
-     *
-     * @return the representation as Node.
-     */
-    Node toXML(Document doc);
-
-    Facet deepCopy();
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/FacetActivity.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/FacetActivity.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import de.intevation.artifacts.Artifact;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-
-
-/**
- * System used in practice used by AttributeWriter in flys-artifacts to decide
- * whether a facet is initially active.
- * Provides a singleton Registry into which FacetActivities can be registered
- * under a key (in practice the artifacts name.  This Registry is queried for
- * new Facets in order to find whether they are active or inactive.
- */
-public interface FacetActivity
-{
-    /** Static 'activity' that lets all facets be active. */
-    public static final FacetActivity ACTIVE = new FacetActivity() {
-        @Override
-        public Boolean isInitialActive(
-            Artifact artifact,
-            Facet    facet,
-            String   output
-        ) {
-            return Boolean.TRUE;
-        }
-    };
-
-    /** Static 'activity' that lets all facets be inactive. */
-    public static final FacetActivity INACTIVE = new FacetActivity() {
-        @Override
-        public Boolean isInitialActive(
-            Artifact artifact,
-            Facet    facet,
-            String   output
-        ) {
-            return Boolean.FALSE;
-        }
-    };
-
-    Boolean isInitialActive(Artifact artifact, Facet facet, String output);
-
-    /** Singleton registry, that maps artifact names to the activities, which
-     * decide whether or not a facet should be (initially) active. */
-    public static final class Registry {
-
-        /** The logger for this class. */
-        private static Logger logger = Logger.getLogger(Registry.class);
-
-        /** Singleton instance. */
-        private static final Registry INSTANCE = new Registry();
-
-        /** Map of keys (artifact names) to the activities. */
-        private Map<String, List<FacetActivity>> activities;
-
-        /** Private singleton constructor for the Facet-Activity-Registry. */
-        private Registry() {
-            activities = new HashMap<String, List<FacetActivity>>();
-        }
-
-        /** Access Singleton instance. */
-        public static Registry getInstance() {
-            return INSTANCE;
-        }
-
-        /** Queries whether a given facet should be active or not. */
-        public synchronized boolean isInitialActive(
-            String   key,
-            Artifact artifact,
-            Facet    facet,
-            String   output
-        ) {
-            List<FacetActivity> activityList = activities.get(key);
-            if (activityList == null) {
-                logger.debug("FacetActivity.Registry: No activity " +
-                             "registered for " + key);
-                return true;
-            }
-            if (activityList.size() != 1) {
-                logger.warn("FacetActivity.Registry: More than one " +
-                            "FacetActivity registered for " + key);
-            }
-            for (FacetActivity activity: activityList) {
-                Boolean isActive =
-                    activity.isInitialActive(artifact, facet, output);
-                // Nice. Only, in practice they never return NULL.
-                if (isActive != null) {
-                    return isActive;
-                }
-            }
-            return true;
-        }
-
-
-        /** Add a FacetActivity under given key (usually artifacts name). */
-        public synchronized void register(String key, FacetActivity activity) {
-            List<FacetActivity> activityList = activities.get(key);
-            if (activityList == null) {
-                activityList = new ArrayList<FacetActivity>(3);
-                activities.put(key, activityList);
-            }
-            activityList.add(activity);
-        }
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Output.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Output.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.List;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface Output {
-
-    /**
-     * Retrieve the name of this output mode.
-     *
-     * @return the name of this output mode.
-     */
-    public String getName();
-
-    /**
-     * Retrieve the description of an output.
-     *
-     * @return the description.
-     */
-    public String getDescription();
-
-    /**
-     * Retrieve the mimetype used for the output.
-     *
-     * @return the mimetype.
-     */
-    public String getMimeType();
-
-
-    /**
-     * Returns the type of this output.
-     *
-     * @return the type.
-     */
-    public String getType();
-
-    /**
-     * Retrieve the facets of this output.
-     *
-     * @return the facets of this output.
-     */
-    public List<Facet> getFacets();
-
-    /**
-     * Add a new facet to this output.
-     *
-     * @param facet The new facet.
-     */
-    public void addFacet(Facet facet);
-
-    /**
-     * Add a list of facet to this output.
-     *
-     * @param facets A list of facets.
-     */
-    public void addFacets(List<Facet> facets);
-
-    /**
-     * Replaces the old list of facets with a new one.
-     *
-     * @param facets A list of new facets.
-     */
-    public void setFacets(List<Facet> facets);
-
-    /**
-     * Returns a Settings object for this Output.
-     */
-    public Settings getSettings();
-
-    /**
-     * Sets the Settings for this Output.
-     *
-     * @param settings the Settings for this Output.
-     */
-    public void setSettings(Settings settings);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Section.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Section.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.io.Serializable;
-import java.util.Set;
-
-import org.w3c.dom.Node;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface Section extends Serializable {
-
-    /**
-     * Returns an ID for this Section.
-     *
-     * @return an ID for this Section.
-     */
-    String getId();
-
-    /**
-     * Adds a new subsection to this Section object.
-     *
-     * @param subsection the new Section.
-     */
-    void addSubsection(Section subsection);
-
-    /**
-     * Returns the number of subsections in this Section.
-     *
-     * @return the number of subsections.
-     */
-    int getSubsectionCount();
-
-    /**
-     * Returns a subsection at position <i>pos</i>.
-     *
-     * @param pos The position of the target subsection.
-     *
-     * @return the subsection at position <i>pos</i>.
-     */
-    Section getSubsection(int pos);
-
-    /**
-     * Adds a new Attribute to this Section.
-     *
-     * @param key The key that is used to store/retrieve the Attribute.
-     * @param attribute The new Attribute.
-     */
-    void addAttribute(String key, Attribute attribute);
-
-    /**
-     * Returns an Attribute for the specified <i>key</i>.
-     *
-     * @param key The key that is used to retrieve the target Attribute.
-     *
-     * @return the Attribute specified by <i>key</i>.
-     */
-    Attribute getAttribute(String key);
-
-    /**
-     * Returns all keys of all Attributes currently stored in this Section.
-     *
-     * @return all keys of all Attributes.
-     */
-    Set<String> getKeys();
-
-    /**
-     * Transforms this Section into XML using Attribute.toXML() for each
-     * Attribute and Section.toXML() for each subsection stored in this Section.
-     *
-     * @param parent The parent node.
-     */
-    void toXML(Node parent);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Settings.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Settings.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.io.Serializable;
-
-import org.w3c.dom.Node;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface Settings extends Serializable {
-
-    /**
-     * Adds a new Section to this Settings object.
-     *
-     * @param section the new Section.
-     */
-    void addSection(Section section);
-
-    /**
-     * Returns the number of Sections in this Settings object.
-     *
-     * @return the number of sections.
-     */
-    int getSectionCount();
-
-    /**
-     * Returns the section at position <i>pos</i>.
-     *
-     * @param pos the position of the target Section.
-     *
-     * @return the Section at position <i>pos</i> or null if no Section is
-     * existing at <i>pos</i>.
-     */
-    Section getSection(int pos);
-
-    /**
-     * Removes a Section if it is existing in this Settings.
-     *
-     * @param section The section that should be removed.
-     */
-    void removeSection(Section section);
-
-    /**
-     * Transforms this Settings object into a XML representation. Therefore,
-     * each Section object's <i>toXML</i> method is called to append its XML
-     * representation to the final document.
-     *
-     * @param parent The parent node.
-     */
-    void toXML(Node parent);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +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.artifactdatabase.state;
-
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.CallMeta;
-
-import de.intevation.artifactdatabase.data.StateData;
-
-
-/**
- * This interface describes the basic methods a concrete state class needs to
- * implement.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface State extends Serializable {
-
-    /**
-     * Return the id of the state.
-     *
-     * @return the id.
-     */
-    public String getID();
-
-
-    /**
-     * Return the description of the state.
-     *
-     * @return the description of the state.
-     */
-    public String getDescription();
-
-
-    /**
-     * Returns the help text configured for the state.
-     *
-     * @return the help text configured for the state.
-     */
-    public String getHelpText();
-
-
-    /**
-     * Returns the data provided by this state.
-     *
-     * @return the data stored in this state.
-     */
-    public Map<String, StateData> getData();
-
-
-    /**
-     * Returns a single desired StateData object based on its name.
-     *
-     * @param name The name of the desired StateData object.
-     *
-     * @return the desired StateData object.
-     */
-    public StateData getData(String name);
-
-
-    /**
-     * This method should be used to add a new {@link StateData} object to the
-     * data pool of the state.
-     *
-     * @param name The name of the data object.
-     * @param data The data object.
-     */
-    public void addData(String name, StateData data);
-
-
-    /**
-     * Returns the list of possible outputs of this state. The list is empty
-     * if no output is available for this state.
-     *
-     * @return a list of possible outputs of this state.
-     */
-    public List<Output> getOutputs();
-
-
-    /**
-     * Initialize the state based on the state node in the configuration.
-     *
-     * @param config The state configuration node.
-     */
-    public void setup(Node config);
-
-
-    /**
-     * Initializes the internal state of this State based on an other State.
-     *
-     * @param orig The owner Artifact or the original State.
-     * @param owner The owner Artifact of this State.
-     * @param context The context object.
-     * @param callMeta The CallMeta of the current call.
-     */
-    public void initialize(
-        Artifact orig,
-        Artifact owner,
-        Object   context,
-        CallMeta callMeta);
-
-
-    /**
-     * This method is called when an artifacts retrieves a describe request. It
-     * creates the user interface description of the current state.
-     *
-     * @param artifact A reference to the artifact this state belongs to.
-     * @param document Describe doucment.
-     * @param rootNode Parent node for all new elements.
-     * @param context The CallContext.
-     * @param uuid The uuid of an artifact.
-     */
-    public Element describe(
-        Artifact    artifact,
-        Document    document,
-        Node        rootNode,
-        CallContext context,
-        String      uuid
-    );
-
-
-    /**
-     * This method should be called by an Artifact that removes this State
-     * (current State and previous States). E.g. this might be interesting to
-     * remove generated files or stuff like that.
-     *
-     * @param artifact A parent Artifact.
-     * @param context The CallContext.
-     */
-    public void endOfLife(Artifact artifact, Object context);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/state/StateEngine.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/StateEngine.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-package de.intevation.artifactdatabase.state;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-
-import de.intevation.artifactdatabase.data.StateData;
-
-
-/**
- * The StateEngine stores all states and associated information about
- * outputs and facets for each Artifact.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class StateEngine {
-
-    /** The logger used in this class. */
-    private static Logger logger = Logger.getLogger(StateEngine.class);
-
-    /**
-     * A map that contains the states of the artifacts. The key of this map is
-     * the name of an artifact, its value is a list of all states the artifact
-     * can reach.
-     */
-    protected Map<String, List<State>> states;
-
-
-    /**
-     * A map that contains all existing states. The key of this map is the ID of
-     * the state, its value is the state itself.
-     */
-    protected Map<String, State> allStates;
-
-
-    /**
-     * The default constructor.
-     */
-    public StateEngine() {
-        states    = new HashMap<String, List<State>>();
-        allStates = new HashMap<String, State>();
-    }
-
-
-    /**
-     * This method adds a state into the map <i>allStates</i>.
-     *
-     * @param state The state to add.
-     */
-    protected void addState(State state) {
-        allStates.put(state.getID(), state);
-    }
-
-
-    /**
-     * Returns the state based on its ID.
-     *
-     * @param stateId The ID of the desired state.
-     *
-     * @return the state.
-     */
-    public State getState(String stateId) {
-        return allStates.get(stateId);
-    }
-
-
-    public StateData getStateData(String artifact, String dataName) {
-        List<State> artifactStates = getStates(artifact);
-
-        if (artifactStates == null || artifactStates.size() == 0) {
-            logger.warn("No States for Artifact '" + artifact + "' existing.");
-            return null;
-        }
-
-        for (State state: artifactStates) {
-            StateData sd = state.getData(dataName);
-
-            if (sd != null) {
-                return sd;
-            }
-        }
-
-        logger.warn(
-            "No StateData for Artifact '" + artifact +
-            "' with name '" + dataName + "' existing.");
-
-        return null;
-    }
-
-
-    /**
-     * Add new states for a specific artifact.
-     *
-     * @param artifact The name of the artifact.
-     * @param states A list of states that the artifact can reach.
-     *
-     * @return true, if the states were added, otherwise false.
-     */
-    public boolean addStates(String artifact, List<State> states) {
-        List tmp = this.states.get(artifact);
-
-        if (tmp != null) {
-            logger.info(
-                "States for the artifact '" + artifact + "' already stored.");
-
-            return false;
-        }
-
-        // add the state to the map with all existing states
-        for (State s: states) {
-            addState(s);
-        }
-
-        logger.debug("Add new states for the artifact '" + artifact + "'");
-        return this.states.put(artifact, states) != null;
-    }
-
-
-    /**
-     * Returns the state list of an artifact specified by its name.
-     *
-     * @param artifact The name of the artifact (e.g. "winfo").
-     *
-     * @return the list of states of this artifact or <i>null</i> if no states
-     * are existing for this <i>artifact</i>.
-     */
-    public List<State> getStates(String artifact) {
-        return states.get(artifact);
-    }
-
-
-    /**
-     * Return mapping of output to facets for an artifact in its states.
-     */
-    public Map<String, List<String>> getCompatibleFacets(List<String> aStates) {
-        Map<String, List<String>> compatibilityMatrix =
-            new HashMap<String, List<String>>();
-
-        // For all states that the artifact had seen, add outputs facets.
-        logger.debug("Searching in " + aStates);
-        for (String stateId: aStates) {
-
-            State state = allStates.get(stateId);
-            if (state == null) {
-                logger.debug("No state found for id " + stateId);
-                continue;
-            }
-
-            for (Output output: state.getOutputs()) {
-                List<Facet> outFacets = output.getFacets();
-                logger.debug("Facets for output " + output.getName() + " :" + outFacets);
-
-                List<String> oldFacets = compatibilityMatrix.get(output.getName());
-
-                if (oldFacets == null) {
-                    oldFacets = new ArrayList<String>();
-                }
-
-                for (Facet facet: outFacets) {
-                    oldFacets.add(facet.getName());
-                }
-
-                compatibilityMatrix.put(output.getName(), oldFacets);
-            }
-        }
-        return compatibilityMatrix;
-    }
-}
-// vim:set ts=4 sw=4 et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/transition/Transition.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/transition/Transition.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-package de.intevation.artifactdatabase.transition;
-
-import org.w3c.dom.Node;
-
-import de.intevation.artifacts.Artifact;
-
-import de.intevation.artifactdatabase.state.State;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public interface Transition {
-
-    /**
-     * Initializes the transition.
-     *
-     * @param config The configuration node for the transition.
-     */
-    public void init(Node config);
-
-    /**
-     * Return the ID of the start State.
-     */
-    public String getFrom();
-
-    /**
-     * Return the ID of the target State.
-     */
-    public String getTo();
-
-    /**
-     * Set the ID of the current State.
-     *
-     * @param from The ID of the current state.
-     */
-    public void setFrom(String from);
-
-    /**
-     * Set the ID of the target State.
-     *
-     * @param to The ID of the target state.
-     */
-    public void setTo(String to);
-
-    /**
-     * Determines if its valid to step from state <i>a</i> of an artifact
-     * <i>artifact</i> to state <i>b</i>.
-     *
-     * @param artifact The owner artifact of state a and b.
-     * @param a The current state.
-     * @param b The target state.
-     *
-     * @return true, if it is valid to step from a to b, otherwise false.
-     */
-    public boolean isValid(Artifact artifact, State a, State b);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/de/intevation/artifactdatabase/transition/TransitionEngine.java
--- a/artifact-database/src/main/java/de/intevation/artifactdatabase/transition/TransitionEngine.java	Thu Apr 25 10:53:15 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
-package de.intevation.artifactdatabase.transition;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-
-import de.intevation.artifacts.Artifact;
-
-import de.intevation.artifactdatabase.state.State;
-import de.intevation.artifactdatabase.state.StateEngine;
-
-
-/**
- * The TransitionEngine stores all transitions for each Artifact and should be
- * used to determine, if an Artifact is able to advance from one to another
- * state.
- *
- * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
- */
-public class TransitionEngine {
-
-    /** The logger used in this class. */
-    private static Logger logger = Logger.getLogger(TransitionEngine.class);
-
-    /**
-     * A map that contains the transitions of the artifacts. The key is the name
-     * of the artifact, its value is a list of all transitions of this artifact.
-     */
-    protected Map<String, List> transitions;
-
-
-    /**
-     * The default constructor.
-     */
-    public TransitionEngine() {
-        transitions = new HashMap<String, List>();
-    }
-
-
-    /**
-     * Add new transitions for a specific artifact.
-     *
-     * @param stateId the name of the Artifact.
-     * @param transition the list of transition of the artifact.
-     *
-     * @return true, if the transitions were added, otherwise false.
-     */
-    public boolean addTransition(String stateId, Transition transition) {
-        List tmp = transitions.get(stateId);
-
-        if (tmp == null) {
-            tmp = new ArrayList<Transition>();
-        }
-
-        tmp.add(transition);
-
-        logger.debug("Add new transitions for state '" + stateId + "'");
-
-        return transitions.put(stateId, tmp) != null;
-    }
-
-
-    /**
-     * This method returns all existing transitions of a state.
-     *
-     * @param state The state
-     *
-     * @return the existing transition of <i>state</i>.
-     */
-    public List<Transition> getTransitions(State state) {
-        return transitions.get(state.getID());
-    }
-
-
-    /**
-     * This method returns the reachable states of <i>state</i>.
-     *
-     * @param state The current state.
-     * @param engine The state engine.
-     *
-     * @return a list of reachable states.
-     */
-    public List<State> getReachableStates(
-        Artifact    artifact,
-        State       state,
-        StateEngine engine) {
-        List<Transition> transitions = getTransitions(state);
-        List<State>      reachable   = new ArrayList<State>();
-
-        if (transitions == null) {
-            return reachable;
-        }
-
-        for (Transition t: transitions) {
-            State target = engine.getState(t.getTo());
-
-            if (t.isValid(artifact, state, target)) {
-                reachable.add(target);
-            }
-        }
-
-        return reachable;
-    }
-
-
-    /**
-     * Determines if a state with a given identifier is reachable from a current
-     * state.
-     *
-     * @param artifact The owner artifact of state <i>state</i>.
-     * @param targetId The identifier of the target state.
-     * @param state The start state.
-     * @param stateEngine The StateEngine.
-     *
-     * @return true, if the target state is reachable, otherwise false.
-     */
-    public boolean isStateReachable(
-        Artifact    artifact,
-        String      targetId,
-        State       state,
-        StateEngine stateEngine)
-    {
-        List<State> reachable = getReachableStates(artifact, state,stateEngine);
-
-        if (reachable == null || reachable.size() == 0) {
-            return false;
-        }
-
-        for (State s: reachable) {
-            if (targetId.equals(s.getID())) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/AbstractCallContext.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/AbstractCallContext.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,154 @@
+/*
+ * 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.artifactdatabase;
+
+import org.apache.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.DataProvider;
+
+
+/**
+ * Abstract class that implements some basic methods of a CallContext.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public abstract class AbstractCallContext implements CallContext {
+
+    Logger logger = Logger.getLogger(AbstractCallContext.class);
+
+    /**
+     * The ArtifactDatabase instance.
+     */
+    protected ArtifactDatabaseImpl database;
+
+    /**
+     * The action to be performed after the artifacts or collections calls.
+     */
+    protected int action;
+
+    /**
+     * The meta information of the concrete call (preferred languages et. al.)
+     */
+    protected CallMeta callMeta;
+
+    /**
+     * Map to act like a clipboard when nesting calls like a proxy artifact.
+     */
+    protected Map customValues;
+
+    /**
+     * Map to act like a clipboard when nesting calls like a proxy artifact.
+     */
+    protected Map<Object, List<DataProvider>> dataProviders;
+
+
+    /**
+     * The default constructor of this abstract CallContext.
+     *
+     * @param artifactDatabase The artifact database.
+     * @param action The action.
+     * @param callMeta The CallMeta object.
+     */
+    public AbstractCallContext(
+        ArtifactDatabaseImpl artifactDatabase,
+        int                  action,
+        CallMeta             callMeta
+    ) {
+        this.database = artifactDatabase;
+        this.action   = action;
+        this.callMeta = callMeta;
+
+        database.initCallContext(this);
+    }
+
+
+    public void postCall() {
+        database.closeCallContext(this);
+    }
+
+    public abstract void afterCall(int action);
+
+    public abstract Long getTimeToLive();
+
+    public abstract void afterBackground(int action);
+
+
+    public Object globalContext() {
+        return database.context;
+    }
+
+
+    public ArtifactDatabase getDatabase() {
+        return database;
+    }
+
+
+    public CallMeta getMeta() {
+        return callMeta;
+    }
+
+
+    public Object getContextValue(Object key) {
+        return customValues != null
+            ? customValues.get(key)
+            : null;
+    }
+
+    public Object putContextValue(Object key, Object value) {
+        if (customValues == null) {
+            customValues = new HashMap();
+        }
+        return customValues.put(key, value);
+    }
+
+    /**
+     * Get list of DataProviders that registered for given key.
+     * @return list (empty list if none found, never null).
+     */
+    public List<DataProvider> getDataProvider(Object key) {
+        if (dataProviders != null) {
+            List<DataProvider> list = dataProviders.get(key);
+            return list != null
+                ? list
+                : java.util.Collections.<DataProvider>emptyList();
+        }
+        return java.util.Collections.<DataProvider>emptyList();
+    }
+
+
+    /**
+     * Let a DataProvider register itself with given key.
+     * Multiple DataProvider can register under the same key.
+     */
+    public Object registerDataProvider(Object key, DataProvider value) {
+        List<DataProvider> providers = null;
+        if (dataProviders == null) {
+            dataProviders = new HashMap();
+            providers = new ArrayList<DataProvider>();
+            providers.add(value);
+            return dataProviders.put(key, providers);
+        }
+        providers = dataProviders.get(key);
+
+        if (providers == null) {
+            providers = new ArrayList<DataProvider>();
+        }
+        providers.add(value);
+        return dataProviders.put(key, providers);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/App.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/App.java	Thu Apr 25 10:57:18 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.artifactdatabase.rest.HTTPServer;
+
+import java.io.File;
+
+import java.net.MalformedURLException;
+
+import org.apache.log4j.PropertyConfigurator;
+
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
+/**
+ * Starting point of the artifact database.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class App
+{
+    /**
+     * The logging is done via Log4j. To configure the logging
+     * a file 'log4j.properties' is search in the configuration directory.
+     */
+    public static final String LOG4J_PROPERTIES =
+        "log4j.properties";
+
+    /**
+     * Trys to load the Log4j configuration from ${config.dir}/log4j.properties.
+     */
+    public static final void configureLogging() {
+        File configDir = Config.getConfigDirectory();
+        File propFile = new File(configDir, LOG4J_PROPERTIES);
+
+        if (propFile.isFile() && propFile.canRead()) {
+            try {
+                PropertyConfigurator.configure(propFile.toURI().toURL());
+                SLF4JBridgeHandler.install();
+            }
+            catch (MalformedURLException mue) {
+                mue.printStackTrace(System.err);
+            }
+        }
+    }
+
+    /**
+     * Starts the artifact database.
+     * @param args The commandline arguments. Unused.
+     */
+    public static void main(String[] args) {
+
+        configureLogging();
+
+        FactoryBootstrap bootstrap = new FactoryBootstrap();
+
+        bootstrap.boot();
+
+        Backend backend = Backend.getInstance();
+
+        ArtifactDatabaseImpl db = new ArtifactDatabaseImpl(
+            bootstrap, backend);
+
+        DatabaseCleaner cleaner = new DatabaseCleaner(
+            bootstrap.getContext(), backend, backend.getConfig());
+
+        HTTPServer httpServer = bootstrap.getHTTPServer();
+
+        bootstrap = null;
+
+        backend.setCleaner(cleaner);
+
+        cleaner.setLockedIdsProvider(db);
+
+        cleaner.start();
+
+        db.start();
+
+        httpServer.startAsServer(db);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactCallContext.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactCallContext.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,130 @@
+/*
+ * 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.artifactdatabase;
+
+import java.util.LinkedList;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.Message;
+
+import de.intevation.artifactdatabase.Backend.PersistentArtifact;
+
+
+/**
+ * Class that implements the call context handed to the methods calls
+ * describe(), feed(), etc. of the artifact.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class ArtifactCallContext extends AbstractCallContext {
+
+    private static Logger logger = Logger.getLogger(ArtifactCallContext.class);
+
+
+    /**
+     * Error message issued if an artifact wants to translate itself
+     * into a none valid persistent state.
+     */
+    public static final String INVALID_CALL_STATE = "Invalid after call state";
+
+    /**
+     * Error message issued if one tries to remove a requested artifact
+     * from the list of artifacts running in background which is
+     * not in this list.
+     */
+    public static final String NOT_IN_BACKGROUND = "Not in background";
+
+
+    /**
+     * The persistence wrapper around the living artifact
+     */
+    protected PersistentArtifact artifact;
+
+
+    public ArtifactCallContext(
+        ArtifactDatabaseImpl artifactDatabase,
+        int                  action,
+        CallMeta             callMeta,
+        PersistentArtifact   artifact)
+    {
+        super(artifactDatabase, action, callMeta);
+
+        this.artifact = artifact;
+    }
+
+
+    public void afterCall(int action) {
+        this.action = action;
+        if (action == BACKGROUND) {
+            database.addIdToBackground(artifact.getId());
+        }
+    }
+
+
+    public void afterBackground(int action) {
+        if (this.action != BACKGROUND) {
+            throw new IllegalStateException(NOT_IN_BACKGROUND);
+        }
+        database.fromBackground(artifact, action);
+    }
+
+
+    public boolean isInBackground() {
+        return database.getLockedIds().contains(artifact.getId());
+    }
+
+
+    public void addBackgroundMessage(Message msg) {
+        database.addBackgroundMessage(artifact.getArtifact().identifier(), msg);
+    }
+
+
+    public LinkedList<Message> getBackgroundMessages() {
+        return database.getBackgroundMessages(
+            artifact.getArtifact().identifier());
+    }
+
+
+    public Long getTimeToLive() {
+        return artifact.getTTL();
+    }
+
+
+    /**
+     * Dispatches and executes the persistence action after
+     * the return of the concrete artifact call.
+     */
+    public void postCall() {
+        try {
+            switch (action) {
+                case NOTHING:
+                    break;
+                case TOUCH:
+                    artifact.touch();
+                    break;
+                case STORE:
+                    artifact.store();
+                    break;
+                case BACKGROUND:
+                    logger.warn(
+                        "BACKGROUND processing is not fully implemented, yet!");
+                    artifact.store();
+                    break;
+                default:
+                    logger.error(INVALID_CALL_STATE + ": " + action);
+                    throw new IllegalStateException(INVALID_CALL_STATE);
+            }
+        }
+        finally {
+            super.postCall();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,1976 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.StringUtils;
+
+import de.intevation.artifactdatabase.Backend.PersistentArtifact;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.ArtifactCollectionFactory;
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.ArtifactSerializer;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.CollectionItem;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.Hook;
+import de.intevation.artifacts.Message;
+import de.intevation.artifacts.Service;
+import de.intevation.artifacts.ServiceFactory;
+import de.intevation.artifacts.User;
+import de.intevation.artifacts.UserFactory;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * The core implementation of artifact database. This layer exposes
+ * the needed methods to the artifact runtime system which e.g. may
+ * expose them via REST. The concrete persistent representation of the
+ * artifacts is handled by the {@link Backend backend}.
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class ArtifactDatabaseImpl
+implements   ArtifactDatabase,
+             DatabaseCleaner.LockedIdsProvider,
+             Backend.FactoryLookup
+{
+    private static Logger logger =
+        Logger.getLogger(ArtifactDatabaseImpl.class);
+
+    /** The key under which the artifact database is stored in the global
+     * context.*/
+    public static final String GLOBAL_CONTEXT_KEY = "global.artifact.database";
+
+    /** Message that is returned if an operation was successful.*/
+    public static final String OPERATION_SUCCESSFUL =
+        "SUCCESS";
+
+    /** Message that is returned if an operation failed.*/
+    public static final String OPERATION_FAILURE =
+        "FAILURE";
+
+    /**
+     * Error message issued if a requested artifact factory
+     * is not registered to this database.
+     */
+    public static final String NO_SUCH_FACTORY =
+        "No such factory";
+
+    /**
+     * Error message issued if a requested artifact is not found
+     * in this database.
+     */
+    public static final String NO_SUCH_ARTIFACT =
+        "No such artifact";
+
+    /**
+     * Error message issued if a requested artifact is not found
+     * in this database.
+     */
+    public static final String NO_SUCH_COLLECTION =
+        "No such collection";
+
+    /**
+     * Error message issued if the creation of an artifact failed.
+     */
+    public static final String CREATION_FAILED =
+        "Creation of artifact failed";
+
+    /**
+     * Error message if an severe internal error occurred.
+     */
+    public static final String INTERNAL_ERROR =
+        "Creation of artifact failed";
+
+    /**
+     * Error message issued if a requested service is not
+     * offered by this database.
+     */
+    public static final String NO_SUCH_SERVICE =
+        "No such service";
+
+    /**
+     * Default digest hash to be used while im-/exporting artifacts.
+     */
+    public static final String DIGEST_ALGORITHM =
+        "SHA-1";
+
+    /**
+     * XPath to get the checksum from an XML representation of
+     * an exported artifact.
+     */
+    public static final String XPATH_IMPORT_CHECKSUM =
+        "/art:action/art:data/@checksum";
+
+    /**
+     * XPath to get the name of the factory which should be
+     * used to revive an antrifact that is going to be imported.
+     */
+    public static final String XPATH_IMPORT_FACTORY =
+        "/art:action/art:data/@factory";
+
+    /**
+     * XPath to get the base64 encoded data of an artifact
+     * that is going to be imported.
+     */
+    public static final String XPATH_IMPORT_DATA =
+        "/art:action/art:data/text()";
+
+    /**
+     * Error message issued if the checksum of an
+     * artifact to be imported has an invalid syntax.
+     */
+    public static final String INVALID_CHECKSUM =
+        "Invalid checksum";
+
+    /**
+     * Error message issued the checksum validation
+     * of an artifact to be imported fails.
+     */
+    public static final String CHECKSUM_MISMATCH =
+        "Mismatching checksum";
+
+    /**
+     * Error message issued if an artifact to be imported
+     * does not have any data.
+     */
+    public static final String NO_DATA =
+        "No data";
+
+    /**
+     * Error message issued if the deserialization of
+     * an artifact to be imported fails.
+     */
+    public static final String INVALID_ARTIFACT =
+        "Invalid artifact";
+
+
+    // User constants
+
+    /**
+     * Error message issued if the creation of a user failed.
+     */
+    public static final String USER_CREATION_FAILED =
+        "Creation of user failed.";
+
+    /** XPath to figure out the name of a new user.*/
+    public static final String XPATH_USERNAME =
+        "/art:action/art:user/@name";
+
+    /** XPath to figure out the role of a new user.*/
+    public static final String XPATH_USERROLE =
+        "/art:action/art:user/art:role";
+
+    /** XPath to figure out the account of a new user.*/
+    public static final String XPATH_USERACCOUNT =
+        "/art:action/art:user/art:account/@name";
+
+    /** XPath to figure out the account of when searching for a user .*/
+    public static final String XPATH_USERACCOUNT_FIND =
+        "/art:action/art:account/@name";
+
+    /** Error message if a specified user does not exist.*/
+    public static final String NO_SUCH_USER =
+        "No such user";
+
+    /** Error message if no username is given for user creation.*/
+    public static final String NO_USERNAME =
+        "Invalid username";
+
+    /** Error message if no user account is given for user creation.*/
+    public static final String NO_USERACCOUNT =
+        "Invalid user account name";
+
+    // Collection constants
+
+    /**
+     * Error message issued if the creation of a collection failed.
+     */
+    public static final String COLLECTION_CREATION_FAILED =
+        "Creation of collection failed";
+
+    /**
+     * XPath to figure out the name of a collection described in the incoming
+     * document.
+     */
+    public static final String XPATH_COLLECTION_NAME =
+        "/art:action/art:type/art:collection/@name";
+
+    /**
+     * XPath to figure out the attributes for a collection.
+     */
+    public static final String XPATH_COLLECTION_ATTRIBUTE =
+        "/art:action/art:type/art:collection/art:attribute";
+
+    /**
+     * XPath to figure out the attributes for an artifact that is put into a
+     * collection.
+     */
+    public static final String XPATH_COLLECTION_ITEM_ATTRIBUTE =
+        "/art:action/art:type/art:artifact/art:attribute";
+
+    /**
+     * XPath to figure out the time to live value for setting a new TTL.
+     */
+    public static final String XPATH_COLLECTION_TTL =
+        "/art:action/art:type/art:ttl/@value";
+
+
+    /**
+     * This inner class allows the deferral of writing the output
+     * of the artifact's out() call.
+     */
+    public class DeferredOutputImpl
+    implements   DeferredOutput
+    {
+        /**
+         * The persistence wrapper around a living artifact.
+         */
+        protected PersistentArtifact artifact;
+        /**
+         * The output type.
+         */
+        protected String type;
+        /**
+         * The input document for the artifact's out() call.
+         */
+        protected Document           format;
+        /**
+         * The meta information of the artifact's out() call.
+         */
+        protected CallMeta           callMeta;
+
+        /**
+         * Default constructor.
+         */
+        public DeferredOutputImpl() {
+        }
+
+        /**
+         * Constructor to create a deferred execution unit for
+         * the artifact's out() call given an artifact, an input document
+         * an the meta information.
+         * @param artifact The persistence wrapper around a living artifact.
+         * @param format   The input document for the artifact's out() call.
+         * @param callMeta The meta information of the artifact's out() call.
+         */
+        public DeferredOutputImpl(
+            PersistentArtifact artifact,
+            String             type,
+            Document           format,
+            CallMeta           callMeta
+        ) {
+            this.artifact = artifact;
+            this.type     = type;
+            this.format   = format;
+            this.callMeta = callMeta;
+        }
+
+        public void write(OutputStream output) throws IOException {
+
+            ArtifactCallContext cc = new ArtifactCallContext(
+                ArtifactDatabaseImpl.this,
+                CallContext.TOUCH,
+                callMeta,
+                artifact);
+
+            try {
+                artifact.getArtifact().out(type, format, output, cc);
+            }
+            finally {
+                cc.postCall();
+            }
+        }
+    } // class DeferredOutputImpl
+
+
+    /**
+     * This inner class allows the deferral of writing the output
+     * of the artifact's out() call.
+     */
+    public class DeferredCollectionOutputImpl
+    implements   DeferredOutput
+    {
+        /**
+         * The persistence wrapper around a living collection.
+         */
+        protected ArtifactCollection collection;
+        /**
+         * The output type.
+         */
+        protected String type;
+        /**
+         * The input document for the collection's out() call.
+         */
+        protected Document format;
+        /**
+         * The meta information of the collection's out() call.
+         */
+        protected CallMeta callMeta;
+
+        /**
+         * Default constructor.
+         */
+        public DeferredCollectionOutputImpl() {
+        }
+
+        /**
+         * Constructor to create a deferred execution unit for
+         * the collection's out() call given a collection, an input document
+         * an the meta information.
+         * @param collection The collection.
+         * @param format   The input document for the collection's out() call.
+         * @param callMeta The meta information of the collection's out() call.
+         */
+        public DeferredCollectionOutputImpl(
+            ArtifactCollection collection,
+            String             type,
+            Document           format,
+            CallMeta           callMeta
+        ) {
+            this.collection = collection;
+            this.type       = type;
+            this.format     = format;
+            this.callMeta   = callMeta;
+        }
+
+        public void write(OutputStream output) throws IOException {
+
+            CollectionCallContext cc = new CollectionCallContext(
+                ArtifactDatabaseImpl.this,
+                CallContext.TOUCH,
+                callMeta,
+                collection);
+
+            try {
+                collection.out(type, format, output, cc);
+            }
+            finally {
+                cc.postCall();
+            }
+        }
+    } // class DeferredCollectionOutputImpl
+
+    /**
+     * List of name/description pairs needed for
+     * {@link #artifactFactoryNamesAndDescriptions() }.
+     */
+    protected String [][] factoryNamesAndDescription;
+    /**
+     * Map to access artifact factories by there name.
+     */
+    protected HashMap     name2factory;
+
+    /**
+     * List of name/description pairs needed for
+     * {@link #serviceNamesAndDescriptions() }.
+     */
+    protected String [][] serviceNamesAndDescription;
+    /**
+     * Map to access services by there name.
+     */
+    protected HashMap     name2service;
+
+    /**
+     * The factory that is used to create new artifact collections.
+     */
+    protected ArtifactCollectionFactory collectionFactory;
+
+    /**
+     * The factory that is used to create and list users.
+     */
+    protected UserFactory userFactory;
+
+    /**
+     * Reference to the storage backend.
+     */
+    protected Backend     backend;
+    /**
+     * Reference of the global context of the artifact runtime system.
+     */
+    protected GlobalContext context;
+
+    /**
+     * The signing secret to be used for ex-/importing artifacts.
+     */
+    protected byte []     exportSecret;
+
+    /**
+     * A set of ids of artifact which currently running in background.
+     * This artifacts should not be removed from the database by the
+     * database cleaner.
+     */
+    protected HashSet<Integer> backgroundIds;
+
+    /**
+     * A list of background messages for Artifacts and Collections.
+     */
+    protected Map<String, LinkedList<Message>> backgroundMsgs;
+
+
+    protected CallContext.Listener callContextListener;
+
+    /**
+     * Hooks that are executed after an artifact has been fed.
+     */
+    protected List<Hook> postFeedHooks;
+
+    /**
+     * Hooks that are executed after an artifact has advanced.
+     */
+    protected List<Hook> postAdvanceHooks;
+
+    /**
+     * Hooks that are executed after an artifact's describe() operation was
+     * called.
+     */
+    protected List<Hook> postDescribeHooks;
+
+    protected List<LifetimeListener> lifetimeListeners;
+
+    /**
+     * Default constructor.
+     */
+    public ArtifactDatabaseImpl() {
+    }
+
+    /**
+     * Constructor to create a artifact database with the given
+     * bootstrap parameters like artifact- and service factories et. al.
+     * Created this way the artifact database has no backend.
+     * @param bootstrap The parameters to start this artifact database.
+     */
+    public ArtifactDatabaseImpl(FactoryBootstrap bootstrap) {
+        this(bootstrap, null);
+    }
+
+    /**
+     * Constructor to create a artifact database with the a given
+     * backend and
+     * bootstrap parameters like artifact- and service factories et. al.
+     * @param bootstrap The parameters to start this artifact database.
+     * @param backend   The storage backend.
+     */
+    public ArtifactDatabaseImpl(FactoryBootstrap bootstrap, Backend backend) {
+
+        logger.debug("new ArtifactDatabaseImpl");
+
+        backgroundIds  = new HashSet<Integer>();
+        backgroundMsgs = new HashMap<String, LinkedList<Message>>();
+
+        setupArtifactCollectionFactory(bootstrap);
+        setupArtifactFactories(bootstrap);
+        setupServices(bootstrap);
+        setupUserFactory(bootstrap);
+        setupCallContextListener(bootstrap);
+        setupHooks(bootstrap);
+        setupLifetimeListeners(bootstrap);
+
+        context = bootstrap.getContext();
+        context.put(GLOBAL_CONTEXT_KEY, this);
+
+        exportSecret = bootstrap.getExportSecret();
+
+        wireWithBackend(backend, bootstrap);
+    }
+
+    public CallContext.Listener getCallContextListener() {
+        return callContextListener;
+    }
+
+    public void setCallContextListener(
+        CallContext.Listener callContextListener
+    ) {
+        this.callContextListener = callContextListener;
+    }
+
+
+    public void setPostFeedHook(List<Hook> postFeedHooks) {
+        this.postFeedHooks = postFeedHooks;
+    }
+
+    public void setPostAdvanceHook(List<Hook> postAdvanceHooks) {
+        this.postAdvanceHooks = postAdvanceHooks;
+    }
+
+    public void setPostDescribeHook(List<Hook> postDescribeHooks) {
+        this.postDescribeHooks = postDescribeHooks;
+    }
+
+    /**
+     * Used to extract the artifact collection factory from bootstrap.
+     *
+     * @param bootstrap The bootstrap parameters.
+     */
+    protected void setupArtifactCollectionFactory(FactoryBootstrap bootstrap) {
+        collectionFactory = bootstrap.getArtifactCollectionFactory();
+    }
+
+    /**
+     * Used to extract the artifact factories from the bootstrap
+     * parameters and building the internal lookup tables.
+     * @param bootstrap The bootstrap parameters.
+     */
+    protected void setupArtifactFactories(FactoryBootstrap bootstrap) {
+        name2factory  = new HashMap();
+
+        ArtifactFactory [] factories = bootstrap.getArtifactFactories();
+        factoryNamesAndDescription = new String[factories.length][];
+
+        for (int i = 0; i < factories.length; ++i) {
+
+            ArtifactFactory factory = factories[i];
+
+            String name        = factory.getName();
+            String description = factory.getDescription();
+
+            factoryNamesAndDescription[i] =
+                new String [] { name, description };
+
+            name2factory.put(name, factory);
+        }
+    }
+
+    /**
+     * Used to extract the callContextListener from the bootstrap.
+     *
+     * @param bootstrap The bootstrap parameters.
+     */
+    protected void setupCallContextListener(FactoryBootstrap bootstrap) {
+        setCallContextListener(bootstrap.getCallContextListener());
+    }
+
+
+    protected void setupHooks(FactoryBootstrap bootstrap) {
+        setPostFeedHook(bootstrap.getPostFeedHooks());
+        setPostAdvanceHook(bootstrap.getPostAdvanceHooks());
+        setPostDescribeHook(bootstrap.getPostDescribeHooks());
+    }
+
+    protected void setupBackendListeners(FactoryBootstrap bootstrap) {
+        logger.debug("setupBackendListeners");
+        List<BackendListener> bls = bootstrap.getBackendListeners();
+        if (bls != null && !bls.isEmpty()) {
+            for (BackendListener listener: bls) {
+                listener.setup(context);
+            }
+            backend.addAllListeners(bls);
+        }
+    }
+
+    protected void setupLifetimeListeners(FactoryBootstrap bootstrap) {
+        this.lifetimeListeners = bootstrap.getLifetimeListeners();
+    }
+
+    /**
+     * Used to extract the user factory from the bootstrap.
+     */
+    protected void setupUserFactory(FactoryBootstrap bootstrap) {
+        userFactory = bootstrap.getUserFactory();
+    }
+
+    /**
+     * Used to extract the service factories from the bootstrap
+     * parameters, setting up the services and building the internal
+     * lookup tables.
+     * @param bootstrap The bootstrap parameters.
+     */
+    protected void setupServices(FactoryBootstrap bootstrap) {
+
+        name2service  = new HashMap();
+
+        ServiceFactory [] serviceFactories =
+            bootstrap.getServiceFactories();
+
+        serviceNamesAndDescription =
+            new String[serviceFactories.length][];
+
+        for (int i = 0; i < serviceFactories.length; ++i) {
+            ServiceFactory factory = serviceFactories[i];
+
+            String name        = factory.getName();
+            String description = factory.getDescription();
+
+            serviceNamesAndDescription[i] =
+                new String [] { name, description };
+
+            name2service.put(
+                name,
+                factory.createService(bootstrap.getContext()));
+        }
+
+    }
+
+    /**
+     * Wires a storage backend to this artifact database and
+     * establishes a callback to be able to revive artifacts
+     * via the serializers of this artifact factories.
+     * @param backend The backend to be wired with this artifact database.
+     */
+    public void wireWithBackend(Backend backend, FactoryBootstrap bootstrap) {
+        logger.debug("wireWithBackend");
+        if (backend != null) {
+            this.backend = backend;
+            backend.setFactoryLookup(this);
+            setupBackendListeners(bootstrap);
+        }
+    }
+
+    /**
+     * Called after an backgrounded artifact signals its
+     * will to be written back to the backend.
+     * @param artifact The persistence wrapper around
+     * the backgrounded artifact.
+     * @param action The action to be performed.
+     */
+    protected void fromBackground(PersistentArtifact artifact, int action) {
+        logger.warn("BACKGROUND processing is not fully implemented, yet!");
+        switch (action) {
+            case CallContext.NOTHING:
+                break;
+            case CallContext.TOUCH:
+                artifact.touch();
+                break;
+            case CallContext.STORE:
+                artifact.store();
+                break;
+            default:
+                logger.warn("operation not allowed in fromBackground");
+        }
+        removeIdFromBackground(artifact.getId());
+        removeBackgroundMessages(artifact.getArtifact().identifier());
+    }
+
+    /**
+     * Removes an artifact's database id from the set of backgrounded
+     * artifacts. The database cleaner is now able to remove it safely
+     * from the database again.
+     * @param id The database id of the artifact.
+     */
+    protected void removeIdFromBackground(int id) {
+        synchronized (backgroundIds) {
+            backgroundIds.remove(id);
+        }
+    }
+
+
+    /**
+     * Removes all messages that have been added to the <i>backgroundMsgs</i>
+     * list.
+     *
+     * @param uuid The UUID of an artifact or collection.
+     */
+    protected void removeBackgroundMessages(String uuid) {
+        logger.debug("Remove background messages for: " + uuid);
+
+        synchronized (backgroundMsgs) {
+            backgroundMsgs.remove(uuid);
+        }
+    }
+
+    /**
+     * Adds an artifact's database id to the set of artifacts
+     * running in backgroound. To be in this set prevents the
+     * artifact to be removed from the database by the database cleaner.
+     * @param id The database id of the artifact to be protected
+     * from being removed from the database.
+     */
+    protected void addIdToBackground(int id) {
+        synchronized (backgroundIds) {
+            backgroundIds.add(Integer.valueOf(id));
+        }
+    }
+
+    /**
+     * Adds a <i>Message</i> to the background messages list of the Artifact or
+     * Collection.
+     *
+     * @param uuid The UUID of the Artifact or Collection.
+     * @param msg The message that should be added to the background messages
+     * list.
+     */
+    public void addBackgroundMessage(String uuid, Message msg) {
+        logger.debug("Add new background messsage for: " + uuid);
+
+        synchronized (backgroundMsgs) {
+            LinkedList<Message> messages = backgroundMsgs.get(uuid);
+
+            if (messages == null) {
+                messages = new LinkedList<Message>();
+                backgroundMsgs.put(uuid, messages);
+            }
+
+            messages.addLast(msg);
+        }
+    }
+
+    public Set<Integer> getLockedIds() {
+        synchronized (backgroundIds) {
+            return new HashSet<Integer>(backgroundIds);
+        }
+    }
+
+    /**
+     * Returns the background <i>Message</i>s for a specific Artifact or
+     * Collection.
+     *
+     * @param uuid The Artifact's or Collection's UUID.
+     *
+     * @return a <i>List</i> of <i>Message</i>s or null if no messages are
+     * existing.
+     */
+    public LinkedList<Message> getBackgroundMessages(String uuid) {
+        logger.debug("Retrieve background message for: " + uuid);
+
+        synchronized (backgroundMsgs) {
+            return backgroundMsgs.get(uuid);
+        }
+    }
+
+    public String [][] artifactFactoryNamesAndDescriptions() {
+        return factoryNamesAndDescription;
+    }
+
+    public ArtifactFactory getInternalArtifactFactory(String factoryName) {
+        return getArtifactFactory(factoryName);
+    }
+
+    public ArtifactFactory getArtifactFactory(String factoryName) {
+        return (ArtifactFactory)name2factory.get(factoryName);
+    }
+
+    public UserFactory getUserFactory() {
+        return userFactory;
+    }
+
+    public ArtifactCollectionFactory getArtifactCollectionFactory() {
+        return collectionFactory;
+    }
+
+    public Document createArtifactWithFactory(
+        String   factoryName,
+        CallMeta callMeta,
+        Document data
+    )
+    throws ArtifactDatabaseException
+    {
+        logger.debug("ArtifactDatabaseImpl.createArtifactWithFactory "
+             + factoryName);
+        ArtifactFactory factory = getArtifactFactory(factoryName);
+
+        if (factory == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        Artifact artifact = factory.createArtifact(
+            backend.newIdentifier(),
+            context,
+            callMeta,
+            data);
+
+        if (artifact == null) {
+            throw new ArtifactDatabaseException(CREATION_FAILED);
+        }
+
+        PersistentArtifact persistentArtifact;
+
+        try {
+            persistentArtifact = backend.storeInitially(
+                artifact,
+                factory,
+                factory.timeToLiveUntouched(artifact, context));
+        }
+        catch (Exception e) {
+            logger.error(e.getLocalizedMessage(), e);
+            throw new ArtifactDatabaseException(CREATION_FAILED);
+        }
+
+        ArtifactCallContext cc = new ArtifactCallContext(
+            ArtifactDatabaseImpl.this,
+            CallContext.NOTHING,
+            callMeta,
+            persistentArtifact);
+
+        try {
+            return artifact.describe(null, cc);
+        }
+        finally {
+            cc.postCall();
+        }
+    }
+
+
+    public Artifact getRawArtifact(String identifier)
+    throws ArtifactDatabaseException
+    {
+        PersistentArtifact artifact = backend.getArtifact(identifier);
+
+        if (artifact == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
+        }
+
+        return artifact.getArtifact();
+    }
+
+
+    public Document describe(
+        String   identifier,
+        Document data,
+        CallMeta callMeta
+    )
+    throws ArtifactDatabaseException
+    {
+        // TODO: Handle background tasks
+        PersistentArtifact artifact = backend.getArtifact(identifier);
+
+        if (artifact == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
+        }
+
+        ArtifactCallContext cc = new ArtifactCallContext(
+            ArtifactDatabaseImpl.this,
+            CallContext.TOUCH,
+            callMeta,
+            artifact);
+
+        try {
+            Artifact art = artifact.getArtifact();
+            Document res = art.describe(data, cc);
+
+            if (postDescribeHooks != null) {
+                for (Hook hook: postDescribeHooks) {
+                    hook.execute(art, cc, res);
+                }
+            }
+
+            return res;
+        }
+        finally {
+            cc.postCall();
+        }
+    }
+
+    public Document advance(
+        String   identifier,
+        Document target,
+        CallMeta callMeta
+    )
+    throws ArtifactDatabaseException
+    {
+        // TODO: Handle background tasks
+        PersistentArtifact artifact = backend.getArtifact(identifier);
+
+        if (artifact == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
+        }
+
+        ArtifactCallContext cc = new ArtifactCallContext(
+            ArtifactDatabaseImpl.this,
+            CallContext.STORE,
+            callMeta,
+            artifact);
+
+        try {
+            Artifact art = artifact.getArtifact();
+            Document res = art.advance(target, cc);
+
+            if (postAdvanceHooks != null) {
+                for (Hook hook: postAdvanceHooks) {
+                    hook.execute(art, cc, res);
+                }
+            }
+
+            return res;
+        }
+        finally {
+            cc.postCall();
+        }
+    }
+
+    public Document feed(String identifier, Document data, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        // TODO: Handle background tasks
+        PersistentArtifact artifact = backend.getArtifact(identifier);
+
+        if (artifact == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
+        }
+
+        ArtifactCallContext cc = new ArtifactCallContext(
+            ArtifactDatabaseImpl.this,
+            CallContext.STORE,
+            callMeta,
+            artifact);
+
+        try {
+            Artifact art = artifact.getArtifact();
+            Document res = art.feed(data, cc);
+
+            if (postFeedHooks != null) {
+                for (Hook hook: postFeedHooks) {
+                    hook.execute(art, cc, res);
+                }
+            }
+
+            return res;
+        }
+        finally {
+            cc.postCall();
+        }
+    }
+
+    public DeferredOutput out(
+        String   identifier,
+        Document format,
+        CallMeta callMeta)
+    throws ArtifactDatabaseException
+    {
+        return out(identifier, null, format, callMeta);
+    }
+
+    public DeferredOutput out(
+        String   identifier,
+        String   type,
+        Document format,
+        CallMeta callMeta
+    )
+    throws ArtifactDatabaseException
+    {
+        // TODO: Handle background tasks
+        PersistentArtifact artifact = backend.getArtifact(identifier);
+
+        if (artifact == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
+        }
+
+        return new DeferredOutputImpl(artifact, type, format, callMeta);
+    }
+
+    public Document exportArtifact(String artifact, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        final String [] factoryName = new String[1];
+
+        byte [] bytes = (byte [])backend.loadArtifact(
+            artifact,
+            new Backend.ArtifactLoader() {
+                public Object load(
+                    ArtifactFactory factory,
+                    Long            ttl,
+                    byte []         bytes,
+                    int             id
+                ) {
+                    factoryName[0] = factory.getName();
+
+                    ArtifactSerializer serializer = factory.getSerializer();
+
+                    Artifact artifact = serializer.fromBytes(bytes);
+                    artifact.cleanup(context);
+
+                    return serializer.toBytes(artifact);
+                }
+            });
+
+        if (bytes == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
+        }
+
+        return createExportDocument(
+            factoryName[0],
+            bytes,
+            exportSecret);
+    }
+
+    /**
+     * Creates an exteral XML representation of an artifact.
+     * @param factoryName The name of the factory which is responsible
+     * for the serialized artifact.
+     * @param artifact The byte data of the artifact itself.
+     * @param secret   The signing secret.
+     * @return An XML document containing the external representation
+     * of the artifact.
+     */
+    protected static Document createExportDocument(
+        String  factoryName,
+        byte [] artifact,
+        byte [] secret
+    ) {
+        Document document = XMLUtils.newDocument();
+
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
+        }
+        catch (NoSuchAlgorithmException nsae) {
+            logger.error(nsae.getLocalizedMessage(), nsae);
+            return document;
+        }
+
+        md.update(artifact);
+        md.update(secret);
+
+        String checksum = Hex.encodeHexString(md.digest());
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            document,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("action");
+        document.appendChild(root);
+
+        Element type = ec.create("type");
+        ec.addAttr(type, "name", "export", true);
+        root.appendChild(type);
+
+        Element data = ec.create("data");
+        ec.addAttr(data, "checksum", checksum, true);
+        ec.addAttr(data, "factory",  factoryName, true);
+        data.setTextContent(Base64.encodeBase64String(artifact));
+
+        root.appendChild(data);
+
+        return document;
+    }
+
+    public Document importArtifact(Document input, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        String factoryName = XMLUtils.xpathString(
+            input,
+            XPATH_IMPORT_FACTORY,
+            ArtifactNamespaceContext.INSTANCE);
+
+        ArtifactFactory factory;
+
+        if (factoryName == null
+        || (factoryName = factoryName.trim()).length() == 0
+        || (factory = getArtifactFactory(factoryName)) == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        String checksumString = XMLUtils.xpathString(
+            input,
+            XPATH_IMPORT_CHECKSUM,
+            ArtifactNamespaceContext.INSTANCE);
+
+        byte [] checksum;
+
+        if (checksumString == null
+        || (checksumString = checksumString.trim()).length() == 0
+        || (checksum = StringUtils.decodeHex(checksumString)) == null
+        ) {
+            throw new ArtifactDatabaseException(INVALID_CHECKSUM);
+        }
+
+        checksumString = null;
+
+        String dataString = XMLUtils.xpathString(
+            input,
+            XPATH_IMPORT_DATA,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (dataString == null
+        || (dataString = dataString.trim()).length() == 0) {
+            throw new ArtifactDatabaseException(NO_DATA);
+        }
+
+        byte [] data = Base64.decodeBase64(dataString);
+
+        dataString = null;
+
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
+        }
+        catch (NoSuchAlgorithmException nsae) {
+            logger.error(nsae.getLocalizedMessage(), nsae);
+            return XMLUtils.newDocument();
+        }
+
+        md.update(data);
+        md.update(exportSecret);
+
+        byte [] digest = md.digest();
+
+        if (!Arrays.equals(checksum, digest)) {
+            throw new ArtifactDatabaseException(CHECKSUM_MISMATCH);
+        }
+
+        ArtifactSerializer serializer = factory.getSerializer();
+
+        Artifact artifact = serializer.fromBytes(data); data = null;
+
+        if (artifact == null) {
+            throw new ArtifactDatabaseException(INVALID_ARTIFACT);
+        }
+
+        artifact.setIdentifier(backend.newIdentifier());
+        PersistentArtifact persistentArtifact;
+
+        try {
+            persistentArtifact = backend.storeOrReplace(
+                artifact,
+                factory,
+                factory.timeToLiveUntouched(artifact, context));
+        }
+        catch (Exception e) {
+            logger.error(e.getLocalizedMessage(), e);
+            throw new ArtifactDatabaseException(CREATION_FAILED);
+        }
+
+        ArtifactCallContext cc = new ArtifactCallContext(
+            ArtifactDatabaseImpl.this,
+            CallContext.NOTHING,
+            callMeta,
+            persistentArtifact);
+
+        try {
+            return artifact.describe(input, cc);
+        }
+        finally {
+            cc.postCall();
+        }
+    }
+
+    public String [][] serviceNamesAndDescriptions() {
+        return serviceNamesAndDescription;
+    }
+
+    public Service.Output process(
+        String   serviceName,
+        Document input,
+        CallMeta callMeta
+    )
+    throws ArtifactDatabaseException
+    {
+        Service service = (Service)name2service.get(serviceName);
+
+        if (service == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_SERVICE);
+        }
+
+        return service.process(input, context, callMeta);
+    }
+
+    // User API
+
+    /** Returns user(s) elements. */
+    public Document listUsers(CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        UserFactory factory = getUserFactory();
+
+        if (factory == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        User [] users = backend.getUsers(factory, context);
+
+        if (users != null) {
+            logger.debug(users.length + " users found in the backend.");
+        }
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("users");
+        result.appendChild(root);
+
+        if(users != null) {
+            for (User user: users) {
+                Element ue = ec.create("user");
+                ec.addAttr(ue, "uuid", user.identifier(), true);
+                ec.addAttr(ue, "name", user.getName(), true);
+                Element ua = ec.create("account");
+                ec.addAttr(ua, "name", user.getAccount(), true);
+                ue.appendChild(ua);
+
+                Document role = user.getRole();
+
+                if (role != null) {
+                    ue.appendChild(result.importNode(role.getFirstChild(), true));
+                }
+
+                root.appendChild(ue);
+            }
+        }
+
+        return result;
+    }
+
+    /** Search for a user. */
+    public Document findUser(Document data, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        UserFactory factory = getUserFactory();
+
+        if (factory == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        String account = XMLUtils.xpathString(
+            data, XPATH_USERACCOUNT_FIND, ArtifactNamespaceContext.INSTANCE);
+
+        if (account == null || account.length() == 0) {
+            logger.warn("Can't find user without account!");
+            throw new ArtifactDatabaseException(NO_USERACCOUNT);
+        }
+
+        User user = backend.findUser(account, factory, context);
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element ue = ec.create("user");
+
+        if (user != null) {
+            logger.debug(user + " user found in the backend.");
+
+            ec.addAttr(ue, "uuid", user.identifier(), true);
+            ec.addAttr(ue, "name", user.getName(), true);
+            Element ua = ec.create("account");
+            ec.addAttr(ua, "name", user.getAccount(), true);
+            ue.appendChild(ua);
+
+            Document role = user.getRole();
+
+            if (role != null) {
+                ue.appendChild(result.importNode(role.getFirstChild(), true));
+            }
+        }
+
+        result.appendChild(ue);
+
+        return result;
+    }
+
+    public Document createUser(Document data, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        UserFactory factory = getUserFactory();
+
+        if (factory == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        String name = XMLUtils.xpathString(
+            data, XPATH_USERNAME, ArtifactNamespaceContext.INSTANCE);
+
+        if (name == null || name.length() == 0) {
+            logger.warn("User without username not accepted!");
+            throw new ArtifactDatabaseException(NO_USERNAME);
+        }
+
+        String account = XMLUtils.xpathString(
+            data, XPATH_USERACCOUNT, ArtifactNamespaceContext.INSTANCE);
+
+        if (account == null || account.length() == 0) {
+            logger.warn("User without account not accepted!");
+            throw new ArtifactDatabaseException(NO_USERACCOUNT);
+        }
+
+        Node tmp = (Node) XMLUtils.xpath(
+            data,
+            XPATH_USERROLE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        Document role = XMLUtils.newDocument();
+
+        if (tmp != null) {
+            Node    clone = role.importNode(tmp, true);
+            role.appendChild(clone);
+        }
+
+        User newUser = null;
+
+        try {
+            newUser = backend.createUser(name, account, role, userFactory, context);
+        }
+        catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            throw new ArtifactDatabaseException(USER_CREATION_FAILED);
+        }
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+
+        if (newUser != null) {
+            root.setTextContent(OPERATION_SUCCESSFUL);
+        }
+        else {
+            root.setTextContent(OPERATION_FAILURE);
+        }
+
+        result.appendChild(root);
+
+        return result;
+    }
+
+    public Document deleteUser(String userId, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        logger.debug("Delete user: " + userId);
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        boolean success = backend.deleteUser(userId);
+
+        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
+
+        return result;
+    }
+
+
+    // Collection API
+
+    public Document getCollectionsMasterArtifact(
+        String collectionId,
+        CallMeta meta)
+        throws ArtifactDatabaseException
+    {
+        Document result = XMLUtils.newDocument();
+        String masterUUID = backend.getMasterArtifact(collectionId);
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
+
+        if (acf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        UserFactory uf = getUserFactory();
+        if (uf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        ArtifactCollection c = backend.getCollection(
+            collectionId, acf, uf, context);
+
+        if (c == null) {
+            logger.warn("No collection found with identifier: " + collectionId);
+            throw new ArtifactDatabaseException(NO_SUCH_COLLECTION);
+        }
+
+        Element root = ec.create("artifact-collection");
+        ec.addAttr(root, "name", c.getName(), true);
+        ec.addAttr(root, "uuid", c.identifier(), true);
+        ec.addAttr(root, "ttl",  String.valueOf(c.getTTL()), true);
+
+        Date creationTime = c.getCreationTime();
+        String creation   = creationTime != null
+            ? Long.toString(creationTime.getTime())
+            : "";
+
+        ec.addAttr(root, "creation", creation,  true);
+        result.appendChild(root);
+
+        if (masterUUID == null || masterUUID.length() == 0) {
+            logger.debug("No master for the collection existing.");
+            return result;
+        }
+
+        Element master = ec.create("artifact");
+        ec.addAttr(master, "uuid", masterUUID, true);
+
+        root.appendChild(master);
+
+        return result;
+    }
+
+    public Document listCollections(String userId, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
+        UserFactory               uf  = getUserFactory();
+
+        if (acf == null || uf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        logger.debug("Fetch the list of collection for user: " + userId);
+
+        ArtifactCollection [] ac = backend.listCollections(
+            userId,
+            null, // XXX: fetch from REST
+            acf, uf,
+            context);
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("artifact-collections");
+        result.appendChild(root);
+
+        if (ac == null || ac.length == 0) {
+            logger.debug("No collections for the user existing.");
+
+            return result;
+        }
+
+        logger.debug("Found " + ac.length + " collections of the user.");
+
+        for (ArtifactCollection c: ac) {
+            Element collection = ec.create("artifact-collection");
+            ec.addAttr(collection, "name", c.getName(), true);
+            ec.addAttr(collection, "uuid", c.identifier(), true);
+            ec.addAttr(collection, "ttl",  String.valueOf(c.getTTL()), true);
+
+            Date creationTime = c.getCreationTime();
+            String creation   = creationTime != null
+                ? Long.toString(creationTime.getTime())
+                : "";
+
+            ec.addAttr(collection, "creation", creation,  true);
+
+            root.appendChild(collection);
+        }
+
+        return result;
+    }
+
+    public Document createCollection(String ownerId, Document data,
+        CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
+
+        if (acf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        String name = XMLUtils.xpathString(
+            data, XPATH_COLLECTION_NAME, ArtifactNamespaceContext.INSTANCE);
+
+        logger.debug("Create new collection with name: " + name);
+
+        Document attr = null;
+
+        Node attrNode = (Node) XMLUtils.xpath(
+            data,
+            XPATH_COLLECTION_ATTRIBUTE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (attrNode != null) {
+            attr = XMLUtils.newDocument();
+            attr.appendChild(attr.importNode(attrNode, true));
+        }
+
+        ArtifactCollection ac = backend.createCollection(
+            ownerId, name, acf, attr, context);
+
+        if (ac == null) {
+            throw new ArtifactDatabaseException(COLLECTION_CREATION_FAILED);
+        }
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        Element acElement = ec.create("artifact-collection");
+        ec.addAttr(acElement, "uuid", ac.identifier(), true);
+        ec.addAttr(acElement, "ttl", String.valueOf(ac.getTTL()), true);
+
+        root.appendChild(acElement);
+
+        return result;
+    }
+
+    public Document deleteCollection(String collectionId, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        logger.debug("Delete collection: " + collectionId);
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        boolean success = backend.deleteCollection(collectionId);
+
+        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
+
+        return result;
+    }
+
+    public Document describeCollection(String collectionId, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        logger.debug("Describe collection: " + collectionId);
+        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
+
+        if (acf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        UserFactory uf = getUserFactory();
+        if (uf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        ArtifactCollection c = backend.getCollection(
+            collectionId, acf, uf, context);
+
+        if (c == null) {
+            logger.warn("No collection found with identifier: " + collectionId);
+            throw new ArtifactDatabaseException(NO_SUCH_COLLECTION);
+        }
+
+        CollectionCallContext cc = new CollectionCallContext(
+            ArtifactDatabaseImpl.this,
+            CallContext.NOTHING,
+            callMeta,
+            c);
+
+        try {
+            return c.describe(cc);
+        }
+        finally {
+            cc.postCall();
+        }
+    }
+
+
+    public Document getCollectionAttribute(String collectionId, CallMeta meta)
+    throws ArtifactDatabaseException
+    {
+        logger.debug("Fetch collection attribute for: " + collectionId);
+
+        return backend.getCollectionAttribute(collectionId);
+    }
+
+
+    public Document setCollectionAttribute(
+        String   collectionId,
+        CallMeta meta,
+        Document attribute)
+    throws ArtifactDatabaseException
+    {
+        logger.debug("Set new attribute for the collection: " + collectionId);
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        boolean success = backend.setCollectionAttribute(
+            collectionId, attribute);
+
+        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
+
+        return result;
+    }
+
+    public Document getCollectionItemAttribute(String collectionId, String artifactId,
+        CallMeta callMeta) throws ArtifactDatabaseException
+    {
+        logger.debug("Fetch the attribute for the artifact: " + artifactId);
+
+        return backend.getCollectionItemAttribute(collectionId, artifactId);
+    }
+
+    public Document setCollectionItemAttribute(String collectionId, String artifactId,
+        Document source, CallMeta callMeta)
+        throws ArtifactDatabaseException
+    {
+        logger.debug("Set the attribute for the artifact: " + artifactId);
+
+        Document attribute = null;
+
+        Node attr = (Node) XMLUtils.xpath(
+            source,
+            XPATH_COLLECTION_ITEM_ATTRIBUTE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (attr != null) {
+            attribute = XMLUtils.newDocument();
+            attribute.appendChild(attribute.importNode(attr, true));
+        }
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        boolean success = backend.setCollectionItemAttribute(
+            collectionId, artifactId, attribute);
+
+        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
+
+        return result;
+    }
+
+    public Document addCollectionArtifact(
+        String   collectionId,
+        String   artifactId,
+        Document input,
+        CallMeta callMeta)
+    throws ArtifactDatabaseException
+    {
+        logger.debug(
+            "Add artifact '" + artifactId + "' collection '" +collectionId+"'");
+
+        Document attr = XMLUtils.newDocument();
+
+        Node attrNode = (Node) XMLUtils.xpath(
+            input,
+            XPATH_COLLECTION_ITEM_ATTRIBUTE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (attrNode != null) {
+            attr.appendChild(attr.importNode(attrNode, true));
+        }
+
+        boolean success = backend.addCollectionArtifact(
+            collectionId,
+            artifactId,
+            attr);
+
+        if (!success) {
+            Document result = XMLUtils.newDocument();
+
+            XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+                result,
+                ArtifactNamespaceContext.NAMESPACE_URI,
+                ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+            Element root = ec.create("result");
+            result.appendChild(root);
+
+            root.setTextContent(OPERATION_FAILURE);
+
+            return result;
+        }
+
+        return describeCollection(collectionId, callMeta);
+    }
+
+    public Document removeCollectionArtifact(String collectionId, String artifactId,
+        CallMeta callMeta) throws ArtifactDatabaseException
+    {
+        logger.debug(
+            "Remove artifact '" + artifactId + "' from collection '" +
+            collectionId + "'");
+
+        Document attr = XMLUtils.newDocument();
+
+        boolean success = backend.removeCollectionArtifact(
+            collectionId,
+            artifactId);
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
+
+        return result;
+    }
+
+    public Document listCollectionArtifacts(String collectionId,
+        CallMeta callMeta) throws ArtifactDatabaseException
+    {
+        CollectionItem[] items = backend.listCollectionArtifacts(collectionId);
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        Element ac   = ec.create("artifact-collection");
+        ec.addAttr(ac, "uuid", collectionId, true);
+
+        for (CollectionItem item: items) {
+            Element i    = ec.create("collection-item");
+            Element attr = ec.create("attribute");
+            ec.addAttr(i, "uuid", item.getArtifactIdentifier(), true);
+
+            Document attribute = item.getAttribute();
+            if (attribute != null) {
+                Node firstChild = attribute.getFirstChild();
+                attr.appendChild(result.importNode(firstChild, true));
+            }
+            else {
+                logger.debug("No attributes for the collection item!");
+            }
+
+            i.appendChild(attr);
+            ac.appendChild(i);
+        }
+
+        root.appendChild(ac);
+        result.appendChild(root);
+
+        return result;
+    }
+
+    public Document setCollectionTTL(String uuid, Document doc, CallMeta meta)
+    throws ArtifactDatabaseException
+    {
+        Document result            = XMLUtils.newDocument();
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        String tmp = XMLUtils.xpathString(
+            doc, XPATH_COLLECTION_TTL, ArtifactNamespaceContext.INSTANCE);
+
+        logger.info("Set TTL of artifact collection '" + uuid + "' to: " + tmp);
+
+        if (tmp == null || tmp.length() == 0) {
+            logger.warn("No ttl for this collection specified.");
+            root.setTextContent(OPERATION_FAILURE);
+
+            return result;
+        }
+
+        Long ttl = null;
+        if ((tmp = tmp.toUpperCase()).equals("INF")) {
+            ttl = null;
+        }
+        else if (tmp.equals("DEFAULT")) {
+            ArtifactCollectionFactory acf = getArtifactCollectionFactory();
+            ttl = acf.timeToLiveUntouched(null, context);
+        }
+        else {
+            try {
+                ttl = Long.valueOf(tmp);
+
+                if (ttl < 0) {
+                    throw new NumberFormatException("Negative value.");
+                }
+            }
+            catch (NumberFormatException nfe) {
+                logger.error("Could not determine TTL", nfe);
+                root.setTextContent(OPERATION_FAILURE);
+                return result;
+            }
+        }
+
+        boolean success = backend.setCollectionTTL(uuid, ttl);
+        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
+
+        return result;
+    }
+
+
+    public Document setCollectionName(String uuid, Document doc, CallMeta meta)
+    throws ArtifactDatabaseException
+    {
+        Document result            = XMLUtils.newDocument();
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ec.create("result");
+        result.appendChild(root);
+
+        String name = XMLUtils.xpathString(
+            doc, XPATH_COLLECTION_NAME, ArtifactNamespaceContext.INSTANCE);
+
+        logger.info("Set name of collection '" + uuid + "' to: " + name);
+
+        if (name == null || name.length() == 0) {
+            logger.warn("The new name is emtpy. No new name set!");
+            root.setTextContent(OPERATION_FAILURE);
+            return result;
+        }
+
+        boolean success = backend.setCollectionName(uuid, name);
+        root.setTextContent(success ? OPERATION_SUCCESSFUL: OPERATION_FAILURE);
+
+        return result;
+    }
+
+
+    public DeferredOutput outCollection(
+        String   collectionId,
+        Document format,
+        CallMeta callMeta)
+    throws ArtifactDatabaseException
+    {
+        return outCollection(collectionId, null, format, callMeta);
+    }
+
+    public DeferredOutput outCollection(
+        String   collectionId,
+        String   type,
+        Document format,
+        CallMeta callMeta)
+    throws ArtifactDatabaseException
+    {
+        ArtifactCollectionFactory acf = getArtifactCollectionFactory();
+
+        if (acf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        UserFactory uf = getUserFactory();
+        if (uf == null) {
+            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
+        }
+
+        ArtifactCollection c = backend.getCollection(
+            collectionId, acf, uf, context);
+
+        if (c == null) {
+            logger.warn("No collection found with identifier: " + collectionId);
+            throw new ArtifactDatabaseException(NO_SUCH_COLLECTION);
+        }
+
+        return new DeferredCollectionOutputImpl(c, type, format, callMeta);
+    }
+
+    protected void initCallContext(CallContext cc) {
+        logger.debug("initCallContext");
+        if (callContextListener != null) {
+            callContextListener.init(cc);
+        }
+    }
+
+    protected void closeCallContext(CallContext cc) {
+        logger.debug("closeCallContext");
+        if (callContextListener != null) {
+            callContextListener.close(cc);
+        }
+    }
+
+    @Override
+    public void loadAllArtifacts(ArtifactLoadedCallback callback)
+        throws ArtifactDatabaseException
+    {
+        logger.debug("loadAllArtifacts");
+        boolean success = backend.loadAllArtifacts(callback);
+        if (!success) {
+            throw new ArtifactDatabaseException(INTERNAL_ERROR);
+        }
+    }
+
+    public void start() {
+        if (lifetimeListeners == null || lifetimeListeners.isEmpty()) {
+            return;
+        }
+
+        for (LifetimeListener ltl: lifetimeListeners) {
+            ltl.systemUp(context);
+        }
+
+        logger.debug("all lifetime listeners started");
+
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                for (LifetimeListener ltl: lifetimeListeners) {
+                    ltl.systemDown(context);
+                }
+            }
+        });
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/Backend.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/Backend.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,1914 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.ArtifactCollectionFactory;
+import de.intevation.artifacts.ArtifactDatabase.ArtifactLoadedCallback;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.ArtifactSerializer;
+import de.intevation.artifacts.CollectionItem;
+import de.intevation.artifacts.User;
+import de.intevation.artifacts.UserFactory;
+
+import de.intevation.artifacts.common.utils.StringUtils;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.LRUCache;
+
+import de.intevation.artifactdatabase.db.SQLExecutor;
+import de.intevation.artifactdatabase.db.SQL;
+
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+/**
+ * The backend implements the low level layer used to store artifacts
+ * in a SQL database.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class Backend
+implements   DatabaseCleaner.ArtifactReviver
+{
+    private static Logger logger = Logger.getLogger(Backend.class);
+
+    /**
+     * The SQL statement to create new artifact id inside the database.
+     */
+    public String SQL_NEXT_ID;
+
+    /**
+     * The SQL statement to insert an artifact into the database.
+     */
+    public String SQL_INSERT;
+
+    /**
+     * The SQL statement to update some columns of an existing
+     * artifact in the database.
+     */
+    public String SQL_UPDATE;
+
+    /**
+     * The SQL statement to touch the access time of an
+     * artifact inside the database.
+     */
+    public String SQL_TOUCH;
+
+    /**
+     * The SQL statement to load an artifact by a given
+     * identifier from the database.
+     */
+    public String SQL_LOAD_BY_GID;
+
+    /**
+     * The SQL statement to get the database id of an artifact
+     * identified by the identifier.
+     */
+    public String SQL_GET_ID;
+
+    /**
+     * The SQL statement to replace the content of an
+     * existing artifact inside the database.
+     */
+    public String SQL_REPLACE;
+
+    // USER SQL
+
+    public String SQL_USERS_NEXT_ID;
+    public String SQL_USERS_INSERT;
+    public String SQL_USERS_SELECT_ID_BY_GID;
+    public String SQL_USERS_SELECT_GID;
+    public String SQL_USERS_SELECT_ACCOUNT;
+    public String SQL_USERS_DELETE_ID;
+    public String SQL_USERS_DELETE_COLLECTIONS;
+    public String SQL_USERS_SELECT_ALL;
+    public String SQL_USERS_COLLECTIONS;
+    public String SQL_USERS_COLLECTION_IDS;
+    public String SQL_USERS_DELETE_ALL_COLLECTIONS;
+    public String SQL_ARTIFACTS_IN_ONLY_COLLECTION_ONLY;
+    public String SQL_OUTDATE_ARTIFACTS_COLLECTION;
+    public String SQL_UPDATE_COLLECTION_TTL;
+    public String SQL_UPDATE_COLLECTION_NAME;
+    public String SQL_OUTDATE_ARTIFACTS_USER;
+    public String SQL_DELETE_USER_COLLECTION_ITEMS;
+    public String SQL_COLLECTIONS_NEXT_ID;
+    public String SQL_COLLECTIONS_INSERT;
+    public String SQL_COLLECTIONS_SELECT_USER;
+    public String SQL_COLLECTIONS_SELECT_ALL;
+    public String SQL_COLLECTIONS_SELECT_GID;
+    public String SQL_COLLECTIONS_CREATION_TIME;
+    public String SQL_COLLECTIONS_ID_BY_GID;
+    public String SQL_COLLECTIONS_OLDEST_ARTIFACT;
+    public String SQL_DELETE_COLLECTION_ITEMS;
+    public String SQL_DELETE_COLLECTION;
+    public String SQL_COLLECTION_CHECK_ARTIFACT;
+    public String SQL_COLLECTION_ITEMS_ID_NEXTVAL;
+    public String SQL_COLLECTION_ITEMS_INSERT;
+    public String SQL_COLLECTION_GET_ATTRIBUTE;
+    public String SQL_COLLECTION_SET_ATTRIBUTE;
+    public String SQL_COLLECTION_ITEM_GET_ATTRIBUTE;
+    public String SQL_COLLECTION_ITEM_SET_ATTRIBUTE;
+    public String SQL_COLLECTIONS_TOUCH_BY_GID;
+    public String SQL_COLLECTION_ITEM_ID_CID_AID;
+    public String SQL_COLLECTION_ITEM_OUTDATE_ARTIFACT;
+    public String SQL_COLLECTION_ITEM_DELETE;
+    public String SQL_COLLECTIONS_TOUCH_BY_ID;
+    public String SQL_COLLECTION_ITEMS_LIST_GID;
+    public String SQL_ALL_ARTIFACTS;
+
+    /** The singleton.*/
+    protected static Backend instance;
+
+    protected SQLExecutor sqlExecutor;
+
+    protected List<BackendListener> listeners;
+
+    protected DBConfig config;
+
+    /**
+     * The database cleaner. Reference is stored here because
+     * the cleaner is woken up if the backend finds an outdated
+     * artifact. This artifact should be removed as soon as
+     * possible.
+     */
+    protected DatabaseCleaner cleaner;
+
+    /**
+     * To revive an artifact from the bytes coming from the database
+     * we need the artifact factory which references the artifact
+     * serializer which is able to do the reviving job.
+     */
+    protected FactoryLookup   factoryLookup;
+
+    /**
+     * Little helper interface to decouple the ArtifactDatabase
+     * from the Backend. A ArtifactDatabase should depend on a
+     * Backend but a Backend not from an ArtifactDatabase.
+     */
+    public interface FactoryLookup {
+
+        /**
+         * Returns an ArtifactFactory which is bound to a given name.
+         * @param factoryName The name of the artifact factory.
+         * @return The ArtifactFactory bound to the factory name or
+         * null if not matching factory is found.
+         */
+        ArtifactFactory getArtifactFactory(String factoryName);
+
+    } // interface FactoryLookup
+
+    /**
+     * Inner class that brigdes between the persisten form of the
+     * artifact and the living one inside the artifact database.
+     * After the describe(), feed(), advance() and out() operations
+     * of the artifact it must be possible to write to modified artifact
+     * back into the database.
+     */
+    public final class PersistentArtifact
+    {
+        private int                id;
+        private Artifact           artifact;
+        private ArtifactSerializer serializer;
+        private Long               ttl;
+
+        /**
+         * Cronstructor to create a persistent artifact.
+         * @param artifact   The living artifact.
+         * @param serializer The serializer to store the artifact
+         * after the operations.
+         * @param ttl The time to life of the artifact.
+         * @param id The database id of the artifact.
+         */
+        public PersistentArtifact(
+            Artifact           artifact,
+            ArtifactSerializer serializer,
+            Long               ttl,
+            int                id
+        ) {
+            this.id         = id;
+            this.artifact   = artifact;
+            this.serializer = serializer;
+            this.ttl        = ttl;
+        }
+
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * Returns the wrapped living artifact.
+         * @return the living artifact.
+         */
+        public Artifact getArtifact() {
+            return artifact;
+        }
+
+        /**
+         * Returns the serialized which is able to write a
+         * modified artifact back into the database.
+         * @return The serializer.
+         */
+        public ArtifactSerializer getSerializer() {
+            return serializer;
+        }
+
+        /**
+         * The time to life of the artifact.
+         * @return The time to live.
+         */
+        public Long getTTL() {
+            return ttl;
+        }
+
+        /**
+         * Stores the living artifact back into the database.
+         */
+        public void store() {
+            if (logger.isDebugEnabled()) {
+                logger.debug("storing artifact id = " + getId());
+            }
+            Backend.this.store(this);
+        }
+
+        /**
+         * Only touches the access time of the artifact.
+         */
+        public void touch() {
+            if (logger.isDebugEnabled()) {
+                logger.debug("touching artifact id = " + getId());
+            }
+            Backend.this.touch(this);
+        }
+    } // class ArtifactWithId
+
+    /**
+     * Default constructor
+     */
+    public Backend() {
+        listeners = new CopyOnWriteArrayList<BackendListener>();
+    }
+
+    public Backend(DBConfig config) {
+        this();
+        this.config = config;
+        sqlExecutor = new SQLExecutor(config.getDBConnection());
+        setupSQL(config.getSQL());
+    }
+
+    /**
+     * Constructor to create a backend with a link to the database cleaner.
+     * @param cleaner The clean which periodically removes outdated
+     * artifacts from the database.
+     */
+    public Backend(DBConfig config, DatabaseCleaner cleaner) {
+        this(config);
+        this.cleaner = cleaner;
+    }
+
+    public DBConfig getConfig() {
+        return config;
+    }
+
+    /**
+     * Returns the singleton of this Backend.
+     *
+     * @return the backend.
+     */
+    public static synchronized Backend getInstance() {
+        if (instance == null) {
+            instance = new Backend(DBConfig.getInstance());
+        }
+
+        return instance;
+    }
+
+    protected void setupSQL(SQL sql) {
+        SQL_NEXT_ID = sql.get("artifacts.id.nextval");
+        SQL_INSERT = sql.get("artifacts.insert");
+        SQL_UPDATE = sql.get("artifacts.update");
+        SQL_TOUCH = sql.get("artifacts.touch");
+        SQL_LOAD_BY_GID = sql.get("artifacts.select.gid");
+        SQL_GET_ID = sql.get("artifacts.get.id");
+        SQL_REPLACE = sql.get("artifacts.replace");
+        SQL_USERS_NEXT_ID = sql.get("users.id.nextval");
+        SQL_USERS_INSERT = sql.get("users.insert");
+        SQL_USERS_SELECT_ID_BY_GID = sql.get("users.select.id.by.gid");
+        SQL_USERS_SELECT_GID = sql.get("users.select.gid");
+        SQL_USERS_SELECT_ACCOUNT = sql.get("users.select.account");
+        SQL_USERS_DELETE_ID = sql.get("users.delete.id");
+        SQL_USERS_DELETE_COLLECTIONS = sql.get("users.delete.collections");
+        SQL_USERS_SELECT_ALL = sql.get("users.select.all");
+        SQL_USERS_COLLECTIONS = sql.get("users.collections");
+        SQL_USERS_COLLECTION_IDS = sql.get("users.collection.ids");
+        SQL_USERS_DELETE_ALL_COLLECTIONS =
+            sql.get("users.delete.collections");
+        SQL_ARTIFACTS_IN_ONLY_COLLECTION_ONLY =
+            sql.get("artifacts.in.one.collection.only");
+        SQL_OUTDATE_ARTIFACTS_COLLECTION =
+            sql.get("outdate.artifacts.collection");
+        SQL_UPDATE_COLLECTION_TTL = sql.get("collections.update.ttl");
+        SQL_UPDATE_COLLECTION_NAME = sql.get("collections.update.name");
+        SQL_OUTDATE_ARTIFACTS_USER = sql.get("outdate.artifacts.user");
+        SQL_DELETE_USER_COLLECTION_ITEMS =
+            sql.get("delete.user.collection.items");
+        SQL_COLLECTIONS_NEXT_ID = sql.get("collections.id.nextval");
+        SQL_COLLECTIONS_INSERT = sql.get("collections.insert");
+        SQL_COLLECTIONS_SELECT_USER = sql.get("collections.select.user");
+        SQL_COLLECTIONS_SELECT_ALL = sql.get("collections.select.all");
+        SQL_COLLECTIONS_SELECT_GID = sql.get("collections.select.by.gid");
+        SQL_COLLECTIONS_CREATION_TIME = sql.get("collection.creation.time");
+        SQL_COLLECTIONS_OLDEST_ARTIFACT = sql.get("collections.artifacts.oldest");
+        SQL_COLLECTIONS_ID_BY_GID = sql.get("collections.id.by.gid");
+        SQL_DELETE_COLLECTION_ITEMS = sql.get("delete.collection.items");
+        SQL_DELETE_COLLECTION = sql.get("delete.collection");
+        SQL_COLLECTION_CHECK_ARTIFACT = sql.get("collection.check.artifact");
+        SQL_COLLECTION_ITEMS_ID_NEXTVAL =
+            sql.get("collection.items.id.nextval");
+        SQL_COLLECTION_ITEMS_INSERT = sql.get("collection.items.insert");
+        SQL_COLLECTION_GET_ATTRIBUTE = sql.get("collection.get.attribute");
+        SQL_COLLECTION_SET_ATTRIBUTE = sql.get("collection.set.attribute");
+        SQL_COLLECTION_ITEM_GET_ATTRIBUTE =
+            sql.get("collection.item.get.attribute");
+        SQL_COLLECTION_ITEM_SET_ATTRIBUTE =
+            sql.get("collection.item.set.attribute");
+        SQL_COLLECTIONS_TOUCH_BY_GID = sql.get("collections.touch.by.gid");
+        SQL_COLLECTION_ITEM_ID_CID_AID = sql.get("collection.item.id.cid.aid");
+        SQL_COLLECTION_ITEM_OUTDATE_ARTIFACT =
+            sql.get("collection.item.outdate.artifact");
+        SQL_COLLECTION_ITEM_DELETE = sql.get("collection.item.delete");
+        SQL_COLLECTIONS_TOUCH_BY_ID = sql.get("collections.touch.by.id");
+        SQL_COLLECTION_ITEMS_LIST_GID = sql.get("collection.items.list.gid");
+        SQL_ALL_ARTIFACTS = sql.get("all.artifacts");
+    }
+
+    public void addListener(BackendListener listener) {
+        listeners.add(listener);
+        logger.debug("# listeners: " + listeners.size());
+    }
+
+    public void addAllListeners(List<BackendListener> others) {
+        listeners.addAll(others);
+        logger.debug("# listeners: " + listeners.size());
+    }
+
+    /**
+     * Sets the factory lookup mechanism to decouple ArtifactDatabase
+     * and Backend.
+     * @param factoryLookup
+     */
+    public void setFactoryLookup(FactoryLookup factoryLookup) {
+        this.factoryLookup = factoryLookup;
+    }
+
+    /**
+     * Sets the database cleaner explicitly.
+     * @param cleaner The database cleaner
+     */
+    public void setCleaner(DatabaseCleaner cleaner) {
+        this.cleaner = cleaner;
+    }
+
+    /**
+     * Returns a new unique identifier to external identify
+     * the artifact across the system. This implementation
+     * uses random UUIDs v4 to achieve this target.
+     * @return the new identifier
+     */
+    public String newIdentifier() {
+        // TODO: check database for collisions.
+        return StringUtils.newUUID();
+    }
+
+    public boolean isValidIdentifier(String identifier) {
+        return StringUtils.checkUUID(identifier);
+    }
+
+    /**
+     * Stores a new artifact into the database.
+     * @param artifact The artifact to be stored
+     * @param factory  The factory which build the artifact
+     * @param ttl      The initial time to life of the artifact.
+     * @return         A persistent wrapper around the living
+     * artifact to be able to write modification later.
+     * @throws Exception Thrown if something went wrong with the
+     * storage process.
+     */
+    public PersistentArtifact storeInitially(
+        Artifact        artifact,
+        ArtifactFactory factory,
+        Long            ttl
+    )
+    throws Exception
+    {
+        return new PersistentArtifact(
+            artifact,
+            factory.getSerializer(),
+            ttl,
+            insertDatabase(artifact, factory, ttl));
+    }
+
+    /**
+     * Stores an artifact into database if it does not exist there.
+     * If it exists there it is only updated.
+     * @param artifact The artifact to store/update.
+     * @param factory The factory which created the artifact.
+     * @param ttl The initial time to live of the artifact.
+     * @return A persistent version of the artifact to be able
+     * to store a modification later.
+     * @throws Exception Thrown if something went wrong during
+     * storing/updating.
+     */
+    public PersistentArtifact storeOrReplace(
+        Artifact        artifact,
+        ArtifactFactory factory,
+        Long            ttl
+    )
+    throws Exception
+    {
+        return new PersistentArtifact(
+            artifact,
+            factory.getSerializer(),
+            ttl,
+            storeOrReplaceDatabase(artifact, factory, ttl));
+    }
+
+    /**
+     * Implementors of this interface are able to process the raw
+     * artifact data from the database for loading.
+     */
+    public interface ArtifactLoader {
+
+        /**
+         * Creates a custom object from the raw artifact database data.
+         * @param factory The factory that created this artifact.
+         * @param ttl The current time to life of the artifact.
+         * @param bytes The raw artifact bytes from the database.
+         * @param id The database id of the artifact.
+         * @return The custom object created by the implementation.
+         */
+        Object load(ArtifactFactory factory, Long ttl, byte [] bytes, int id);
+
+    } // interface ArtifactLoader
+
+    /**
+     * Fetches an artifact from the database identified by the
+     * given identifier.
+     * @param identifer The identifier of the artifact.
+     * @return A persistent wrapper around the found artifact
+     * to be able to write back a modifaction later or null
+     * if no artifact is found for this identifier.
+     */
+    public PersistentArtifact getArtifact(String identifer) {
+
+        return (PersistentArtifact)loadArtifact(
+            identifer,
+            new ArtifactLoader() {
+
+                public Object load(
+                    ArtifactFactory factory,
+                    Long            ttl,
+                    byte []         bytes,
+                    int             id
+                ) {
+                    ArtifactSerializer serializer = factory.getSerializer();
+
+                    Artifact artifact = serializer.fromBytes(bytes);
+
+                    return artifact == null
+                        ? null
+                        : new PersistentArtifact(artifact, serializer, ttl, id);
+                }
+            });
+    }
+
+    /**
+     * More general loading mechanism for artifacts. The concrete
+     * load processing is delegated to the given loader.
+     * @param identifer The identifier of the artifact.
+     * @param loader The loader which processes the raw database data.
+     * @return The object created by the loader.
+     */
+    public Object loadArtifact(
+        final String         identifer,
+        final ArtifactLoader loader
+    ) {
+        if (!isValidIdentifier(identifer)) {
+            return null;
+        }
+
+        if (factoryLookup == null) {
+            logger.error("factory lookup == null");
+            return false;
+        }
+
+        final Object [] loaded = new Object[1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_LOAD_BY_GID);
+                stmnt.setString(1, identifer);
+
+                result = stmnt.executeQuery();
+
+                if (!result.next()) {
+                    return false;
+                }
+
+                int  id   = result.getInt(1);
+                long ttlX = result.getLong(2);
+                Long ttl  = result.wasNull() ? null : ttlX;
+
+                String factoryName = result.getString(3);
+
+                ArtifactFactory factory = factoryLookup
+                    .getArtifactFactory(factoryName);
+
+                if (factory == null) {
+                    logger.error("factory '" + factoryName + "' not found");
+                    return false;
+                }
+
+                byte [] bytes = result.getBytes(4);
+
+                loaded[0] = loader.load(factory, ttl, bytes, id);
+                return true;
+            }
+        };
+
+        return exec.runRead() ? loaded[0] : null;
+    }
+
+    /**
+     * Called if the load mechanism found an outdated artifact.
+     * It  wakes up the database cleaner.
+     * @param id The id of the outdated artifact.
+     */
+    protected void artifactOutdated(int id) {
+        if (logger.isDebugEnabled()) {
+            logger.info("artifactOutdated: id = " + id);
+        }
+        if (cleaner != null) {
+            cleaner.wakeup();
+        }
+    }
+
+    public Artifact reviveArtifact(String factoryName, byte [] bytes) {
+        if (factoryLookup == null) {
+            logger.error("reviveArtifact: factory lookup == null");
+            return null;
+        }
+        ArtifactFactory factory = factoryLookup
+            .getArtifactFactory(factoryName);
+
+        if (factory == null) {
+            logger.error(
+                "reviveArtifact: no factory '" + factoryName + "' found");
+            return null;
+        }
+
+        ArtifactSerializer serializer = factory.getSerializer();
+
+        return serializer.fromBytes(bytes);
+    }
+
+    /**
+     * Internal method to store/replace an artifact inside the database.
+     * If an artifact with the given identifier does not exists it is
+     * created else only the content data is updated.
+     * @param artifact The artifact to be store/update inside the database.
+     * @param factory The factory that created the artifact.
+     * @param ttl The initial time to life of the artifact.
+     * @return The database id of the stored/updated artifact.
+     */
+    protected int storeOrReplaceDatabase(
+        final Artifact        artifact,
+        final ArtifactFactory factory,
+        final Long            ttl
+    ) {
+        final String uuid = artifact.identifier();
+
+        if (!isValidIdentifier(uuid)) {
+            throw new RuntimeException("No valid UUID");
+        }
+
+        final int     [] id     = new int[1];
+        final boolean [] stored = new boolean[1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+
+                prepareStatement(SQL_GET_ID);
+                stmnt.setString(1, uuid);
+                result = stmnt.executeQuery();
+
+                Integer ID = result.next()
+                    ? Integer.valueOf(result.getInt(1))
+                    : null;
+
+                reset();
+
+                if (stored[0] = ID != null) { // already in database
+                    prepareStatement(SQL_REPLACE);
+
+                    if (ttl == null) {
+                        stmnt.setNull(1, Types.BIGINT);
+                    }
+                    else {
+                        stmnt.setLong(1, ttl.longValue());
+                    }
+
+                    stmnt.setString(2, factory.getName());
+                    stmnt.setBytes(
+                        3,
+                        factory.getSerializer().toBytes(artifact));
+                    id[0] = ID.intValue();
+                    stmnt.setInt(4, id[0]);
+                }
+                else { // new artifact
+                    prepareStatement(SQL_NEXT_ID);
+                    result = stmnt.executeQuery();
+
+                    if (!result.next()) {
+                        logger.error("No id generated");
+                        return false;
+                    }
+
+                    reset();
+
+                    prepareStatement(SQL_INSERT);
+
+                    id[0] = result.getInt(1);
+                    stmnt.setInt(1, id[0]);
+                    stmnt.setString(2, uuid);
+                    if (ttl == null) {
+                        stmnt.setNull(3, Types.BIGINT);
+                    }
+                    else {
+                        stmnt.setLong(3, ttl.longValue());
+                    }
+
+                    stmnt.setString(4, factory.getName());
+
+                    stmnt.setBytes(
+                        5,
+                        factory.getSerializer().toBytes(artifact));
+                }
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            throw new RuntimeException("failed insert artifact into database");
+        }
+
+        if (stored[0]) {
+            fireStoredArtifact(artifact);
+        }
+        else {
+            fireCreatedArtifact(artifact);
+        }
+
+        return id[0];
+    }
+
+    /**
+     * Internal method to store an artifact inside the database.
+     * @param artifact The artifact to be stored.
+     * @param factory The factory which created the artifact.
+     * @param ttl The initial time to live of the artifact.
+     * @return The database id of the stored artifact.
+     */
+    protected int insertDatabase(
+        final Artifact        artifact,
+        final ArtifactFactory factory,
+        final Long            ttl
+    ) {
+        final int [] id = new int[1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_NEXT_ID);
+                result = stmnt.executeQuery();
+
+                if (!result.next()) {
+                    logger.error("No id generated");
+                    return false;
+                }
+
+                id[0] = result.getInt(1);
+
+                reset();
+                prepareStatement(SQL_INSERT);
+
+                String uuid = artifact.identifier();
+                stmnt.setInt(1, id[0]);
+                stmnt.setString(2, uuid);
+                if (ttl == null) {
+                    stmnt.setNull(3, Types.BIGINT);
+                }
+                else {
+                    stmnt.setLong(3, ttl.longValue());
+                }
+
+                stmnt.setString(4, factory.getName());
+
+                stmnt.setBytes(
+                    5,
+                    factory.getSerializer().toBytes(artifact));
+
+                stmnt.execute();
+
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            throw new RuntimeException("failed insert artifact into database");
+        }
+
+        fireCreatedArtifact(artifact);
+
+        return id[0];
+    }
+
+    protected void fireCreatedArtifact(Artifact artifact) {
+        for (BackendListener listener: listeners) {
+            listener.createdArtifact(artifact, this);
+        }
+    }
+
+    /**
+     * Touches the access timestamp of a given artifact to prevent
+     * that it will be removed from the database by the database cleaner.
+     * @param artifact The persistent wrapper around the living artifact.
+     */
+    public void touch(final PersistentArtifact artifact) {
+        sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_TOUCH);
+                stmnt.setInt(1, artifact.getId());
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        }.runWrite();
+    }
+
+    /**
+     * Writes modification of an artifact back to the database.
+     * @param artifact The persistent wrapper around a living
+     * artifact.
+     */
+    public void store(final PersistentArtifact artifact) {
+        boolean success = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_UPDATE);
+                stmnt.setInt(2, artifact.getId());
+
+                byte [] bytes = artifact
+                    .getSerializer()
+                    .toBytes(artifact.getArtifact());
+
+                stmnt.setBytes(1, bytes);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        }.runWrite();
+
+        if (success) {
+            fireStoredArtifact(artifact.getArtifact());
+        }
+    }
+
+    protected void fireStoredArtifact(Artifact artifact) {
+        for (BackendListener listener: listeners) {
+            listener.storedArtifact(artifact, this);
+        }
+    }
+
+
+    public User createUser(
+        final String      name,
+        final String      account,
+        final Document    role,
+        final UserFactory factory,
+        final Object      context
+    ) {
+        final User [] user = new User[1];
+
+        final byte [] roleData = XMLUtils.toByteArray(role, true);
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+
+                prepareStatement(SQL_USERS_NEXT_ID);
+                result = stmnt.executeQuery();
+
+                if (!result.next()) {
+                    return false;
+                }
+
+                int id = result.getInt(1);
+
+                reset();
+
+                String identifier = newIdentifier();
+
+                prepareStatement(SQL_USERS_INSERT);
+
+                stmnt.setInt(1, id);
+                stmnt.setString(2, identifier);
+                stmnt.setString(3, name);
+                stmnt.setString(4, account);
+
+                if (roleData == null) {
+                    stmnt.setNull(5, Types.BIGINT);
+                }
+                else {
+                    stmnt.setBytes(5, roleData);
+                }
+
+                stmnt.execute();
+                conn.commit();
+
+                user[0] = factory.createUser(
+                    identifier, name, account, role, context);
+                return true;
+            }
+        };
+
+        boolean success = exec.runWrite();
+
+        if (success) {
+            fireCreatedUser(user[0]);
+            return user[0];
+        }
+
+        return null;
+    }
+
+    protected void fireCreatedUser(User user) {
+        for (BackendListener listener: listeners) {
+            listener.createdUser(user, this);
+        }
+    }
+
+    public boolean deleteUser(final String identifier) {
+
+        if (!isValidIdentifier(identifier)) {
+            return false;
+        }
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_USERS_SELECT_ID_BY_GID);
+
+                stmnt.setString(1, identifier);
+                result = stmnt.executeQuery();
+
+                if (!result.next()) { // No such user
+                    return false;
+                }
+
+                int id = result.getInt(1);
+
+                reset();
+
+                // outdate the artifacts exclusively used by the user
+
+                prepareStatement(SQL_OUTDATE_ARTIFACTS_USER);
+                stmnt.setInt(1, id);
+                stmnt.setInt(2, id);
+                stmnt.execute();
+
+                reset();
+
+                // delete the collection items of the user
+
+                prepareStatement(SQL_DELETE_USER_COLLECTION_ITEMS);
+                stmnt.setInt(1, id);
+                stmnt.execute();
+
+                reset();
+
+                // delete the collections of the user
+
+                prepareStatement(SQL_USERS_DELETE_COLLECTIONS);
+                stmnt.setInt(1, id);
+                stmnt.execute();
+
+                reset();
+
+                // delete the user
+
+                prepareStatement(SQL_USERS_DELETE_ID);
+                stmnt.setInt(1, id);
+                stmnt.execute();
+
+                conn.commit();
+                return true;
+            }
+        };
+
+        boolean success = exec.runWrite();
+
+        if (success) {
+            fireDeletedUser(identifier);
+        }
+
+        return success;
+    }
+
+    protected void fireDeletedUser(String identifier) {
+        for (BackendListener listener: listeners) {
+            listener.deletedUser(identifier, this);
+        }
+    }
+
+    public User getUser(
+        final String      identifier,
+        final UserFactory factory,
+        final Object      context
+    ) {
+        if (!isValidIdentifier(identifier)) {
+            logger.debug("Invalid UUID: '" + identifier + "'");
+            return null;
+        }
+
+        final User [] user = new User[1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_USERS_SELECT_GID);
+                stmnt.setString(1, identifier);
+                result = stmnt.executeQuery();
+                if (!result.next()) { // no such user
+                    return false;
+                }
+                // omit id
+                String  name     = result.getString(2);
+                String account   = result.getString(3);
+                byte [] roleData = result.getBytes(4);
+
+                Document role = null;
+                if (roleData != null) {
+                    role = XMLUtils.fromByteArray(roleData, true);
+                }
+
+                user[0] = factory.createUser(
+                    identifier, name, account, role, context);
+                return true;
+            }
+        };
+
+        return exec.runRead() ? user[0] : null;
+    }
+
+    /**
+     * Find/Get user by account.
+     */
+    public User findUser(
+        final String      account,
+        final UserFactory factory,
+        final Object      context
+    ) {
+
+        final User [] user = new User[1];
+        logger.debug("Trying to find user by account " + account);
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_USERS_SELECT_ACCOUNT);
+                stmnt.setString(1, account);
+                result = stmnt.executeQuery();
+                if (!result.next()) { // no such user
+                    logger.debug("No user found.");
+                    return false;
+                }
+                String  identifier = result.getString(1);
+                String  name     = result.getString(2);
+                String account   = result.getString(3);
+                byte [] roleData = result.getBytes(4);
+
+                Document role = null;
+                if (roleData != null) {
+                    role = XMLUtils.fromByteArray(roleData, true);
+                }
+
+                user[0] = factory.createUser(
+                    identifier, name, account, role, context);
+                return true;
+            }
+        };
+
+        return exec.runRead() ? user[0] : null;
+    }
+
+    public User [] getUsers(
+        final UserFactory factory,
+        final Object      context
+    ) {
+        final ArrayList<User> users = new ArrayList<User>();
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_USERS_SELECT_ALL);
+                result = stmnt.executeQuery();
+
+                while (result.next()) {
+                    // omit id
+                    String  identifier = result.getString(2);
+                    String  name       = result.getString(3);
+                    String  account    = result.getString(4);
+                    byte [] roleData   = result.getBytes(5);
+
+                    Document role = XMLUtils.fromByteArray(roleData, true);
+                    User user = factory.createUser(
+                        identifier, name, account, role, context);
+                    users.add(user);
+                }
+                return true;
+            }
+        };
+
+        return exec.runRead()
+            ? users.toArray(new User[users.size()])
+            : null;
+    }
+
+    public ArtifactCollection createCollection(
+        final String                    ownerIdentifier,
+        final String                    name,
+        final ArtifactCollectionFactory factory,
+        final Document                  attribute,
+        final Object                    context
+    ) {
+        if (name == null) {
+            logger.debug("Name is null");
+            return null;
+        }
+
+        if (!isValidIdentifier(ownerIdentifier)) {
+            logger.debug("Invalid owner id: '" + ownerIdentifier + "'");
+            return null;
+        }
+
+        final ArtifactCollection [] collection = new ArtifactCollection[1];
+
+        final byte [] data = XMLUtils.toByteArray(attribute, true);
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                // fetch owner id
+                prepareStatement(SQL_USERS_SELECT_ID_BY_GID);
+                stmnt.setString(1, ownerIdentifier);
+                result = stmnt.executeQuery();
+
+                if (!result.next()) { // no such user
+                    return false;
+                }
+
+                int ownerId = result.getInt(1);
+                reset();
+
+                // fetch new collection seq number.
+                prepareStatement(SQL_COLLECTIONS_NEXT_ID);
+                result = stmnt.executeQuery();
+
+                if (!result.next()) { // no identifier generated
+                    return false;
+                }
+
+                int id = result.getInt(1);
+                reset();
+
+                String identifier = newIdentifier();
+
+                prepareStatement(SQL_COLLECTIONS_INSERT);
+
+                stmnt.setInt(1, id);
+                stmnt.setString(2, identifier);
+                stmnt.setString(3, name);
+                stmnt.setInt(4, ownerId);
+
+                // XXX: A bit odd: we don't have a collection, yet.
+                Long ttl = factory.timeToLiveUntouched(null, context);
+
+                if (ttl == null) {
+                    stmnt.setNull(5, Types.BIGINT);
+                }
+                else {
+                    stmnt.setLong(5, ttl);
+                }
+
+                if (data == null) {
+                    stmnt.setNull(6, Types.BINARY);
+                }
+                else {
+                    stmnt.setBytes(6, data);
+                }
+
+                stmnt.execute();
+                conn.commit();
+
+                reset();
+
+                // fetch creation time from database
+                // done this way to use the time system
+                // of the database.
+
+                prepareStatement(SQL_COLLECTIONS_CREATION_TIME);
+                stmnt.setInt(1, id);
+
+                result = stmnt.executeQuery();
+
+                Date creationTime = null;
+
+                if (result.next()) {
+                    Timestamp timestamp = result.getTimestamp(1);
+                    creationTime = new Date(timestamp.getTime());
+                }
+
+                collection[0] = factory.createCollection(
+                    identifier, name, creationTime, ttl, attribute, context);
+
+                if (collection[0] != null) {
+                    // XXX: Little hack to make the listeners happy
+                    collection[0].setUser(new DefaultUser(ownerIdentifier));
+                }
+
+                return true;
+            }
+        };
+
+        boolean success = exec.runWrite();
+
+        if (success) {
+            fireCreatedCollection(collection[0]);
+            return collection[0];
+        }
+        return null;
+    }
+
+    protected void fireCreatedCollection(ArtifactCollection collection) {
+        for (BackendListener listener: listeners) {
+            listener.createdCollection(collection, this);
+        }
+    }
+
+    public ArtifactCollection getCollection(
+        final String                    collectionId,
+        final ArtifactCollectionFactory collectionFactory,
+        final UserFactory               userFactory,
+        final Object                    context
+    ) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("collection id is not valid: " + collectionId);
+            return null;
+        }
+
+        final ArtifactCollection[] ac = new ArtifactCollection[1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+
+                prepareStatement(SQL_COLLECTIONS_SELECT_GID);
+                stmnt.setString(1, collectionId);
+
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such collection");
+                    return false;
+                }
+
+                String collectionName = result.getString(2);
+                String ownerId        = result.getString(3);
+                Date   creationTime   =
+                    new Date(result.getTimestamp(4).getTime());
+                Date   lastAccess     =
+                    new Date(result.getTimestamp(5).getTime());
+                Document attr         =
+                    XMLUtils.fromByteArray(result.getBytes(6), true);
+                long ttl              = result.getLong(7);
+
+                ArtifactCollection collection =
+                    collectionFactory.createCollection(
+                        collectionId,
+                        collectionName,
+                        creationTime,
+                        ttl,
+                        attr,
+                        context);
+
+                if (ownerId != null) {
+                    collection.setUser(new LazyBackendUser(
+                        ownerId, userFactory, Backend.this, context));
+                }
+
+                ac[0] = collection;
+
+                return true;
+            }
+        };
+
+        return exec.runRead() ? ac[0] : null;
+    }
+
+    public ArtifactCollection [] listCollections(
+        final String                    ownerIdentifier,
+        final Document                  data,
+        final ArtifactCollectionFactory collectionFactory,
+        final UserFactory               userFactory,
+        final Object                    context
+    ) {
+        if (ownerIdentifier != null
+        && !isValidIdentifier(ownerIdentifier)) {
+            logger.debug("Invalid owner id: '" + ownerIdentifier + "'");
+            return null;
+        }
+
+        final ArrayList<ArtifactCollection> collections =
+            new ArrayList<ArtifactCollection>();
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+
+            public boolean doIt() throws SQLException {
+
+                if (ownerIdentifier != null) {
+                    prepareStatement(SQL_COLLECTIONS_SELECT_USER);
+                    stmnt.setString(1, ownerIdentifier);
+                }
+                else {
+                    prepareStatement(SQL_COLLECTIONS_SELECT_ALL);
+                }
+
+                result = stmnt.executeQuery();
+
+                HashMap<String, LazyBackendUser> users =
+                    new HashMap<String, LazyBackendUser>();
+
+                while (result.next()) {
+                    String collectionIdentifier = result.getString(1);
+                    String collectionName       = result.getString(2);
+                    Date   creationTime         =
+                        new Date(result.getTimestamp(3).getTime());
+                    String userIdentifier       = result.getString(4);
+                    long   ttl                  = result.getLong(5);
+
+                    ArtifactCollection collection =
+                        collectionFactory.createCollection(
+                            collectionIdentifier,
+                            collectionName,
+                            creationTime,
+                            ttl,
+                            data,
+                            context);
+
+                    if (userIdentifier != null) {
+                        LazyBackendUser user = users.get(userIdentifier);
+                        if (user == null) {
+                            user = new LazyBackendUser(
+                                userIdentifier, userFactory,
+                                Backend.this, context);
+                            users.put(userIdentifier, user);
+                        }
+                        collection.setUser(user);
+                    }
+
+                    collections.add(collection);
+                }
+                return true;
+            }
+        };
+
+        return exec.runRead()
+            ? collections.toArray(new ArtifactCollection[collections.size()])
+            : null;
+    }
+
+
+    public String getMasterArtifact(final String collectionId) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("Invalid collection id: '" + collectionId + "'");
+            return null;
+        }
+        final String [] uuid = new String[1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                // Fetch masters (oldest artifact) id.
+                prepareStatement(SQL_COLLECTIONS_OLDEST_ARTIFACT);
+                stmnt.setString(1, collectionId);
+                stmnt.setMaxRows(1); //
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such collection: " + collectionId);
+                    return false;
+                }
+                uuid[0] = result.getString(1);
+                if (logger.isDebugEnabled()) {
+                    logger.debug("getMasterArtifact result.getString " +
+                        uuid[0]);
+                }
+                return true;
+            }
+        };
+        return exec.runRead() ? uuid[0] : null;
+    }
+
+    public boolean deleteCollection(final String collectionId) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("Invalid collection id: '" + collectionId + "'");
+            return false;
+        }
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                // fetch collection id
+                prepareStatement(SQL_COLLECTIONS_ID_BY_GID);
+                stmnt.setString(1, collectionId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such collection: " + collectionId);
+                    return false;
+                }
+                int id = result.getInt(1);
+                reset();
+
+                // outdate artifacts that are only in this collection
+                logger.info("Outdate Artifacts that belong to collection: " + id);
+
+                prepareStatement(SQL_OUTDATE_ARTIFACTS_COLLECTION);
+                stmnt.setInt(1, id);
+                stmnt.setInt(2, id);
+                stmnt.execute();
+                reset();
+
+                // delete the collection items
+                prepareStatement(SQL_DELETE_COLLECTION_ITEMS);
+                stmnt.setInt(1, id);
+                stmnt.execute();
+                reset();
+
+                // delete the collection
+                prepareStatement(SQL_DELETE_COLLECTION);
+                stmnt.setInt(1, id);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+        boolean success = exec.runWrite();
+
+        if (success) {
+            fireDeletedCollection(collectionId);
+        }
+
+        return success;
+    }
+
+    protected void fireDeletedCollection(String identifier) {
+        for (BackendListener listener: listeners) {
+            listener.deletedCollection(identifier, this);
+        }
+    }
+
+    public Document getCollectionAttribute(final String collectionId) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("collection id is not valid: " + collectionId);
+        }
+
+        final byte[][] data = new byte[1][1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_COLLECTION_GET_ATTRIBUTE);
+                stmnt.setString(1, collectionId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such collection.");
+                    return false;
+                }
+
+                data[0] = result.getBytes(1);
+                return true;
+            }
+        };
+
+        return exec.runRead()
+            ? XMLUtils.fromByteArray(data[0], true)
+            : null;
+    }
+
+    public boolean setCollectionAttribute(
+        final String   collectionId,
+        Document       attribute
+    ) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("collection id is not valid: " + collectionId);
+            return false;
+        }
+
+        final byte [] data = XMLUtils.toByteArray(attribute, true);
+
+        boolean success = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+
+                // set the column in collection items
+                prepareStatement(SQL_COLLECTION_SET_ATTRIBUTE);
+                if (data == null) {
+                    stmnt.setNull(1, Types.BINARY);
+                }
+                else {
+                    stmnt.setBytes(1, data);
+                }
+                stmnt.setString(2, collectionId);
+                stmnt.execute();
+                reset();
+
+                // touch the collection
+                prepareStatement(SQL_COLLECTIONS_TOUCH_BY_GID);
+                stmnt.setString(1, collectionId);
+                stmnt.execute();
+
+                conn.commit();
+                return true;
+            }
+        }.runWrite();
+
+        if (success) {
+            fireChangedCollectionAttribute(collectionId, attribute);
+        }
+
+        return success;
+    }
+
+    protected void fireChangedCollectionAttribute(
+        String   collectionId,
+        Document document
+    ) {
+        for (BackendListener listener: listeners) {
+            listener.changedCollectionAttribute(collectionId, document, this);
+        }
+    }
+
+    public Document getCollectionItemAttribute(
+        final String collectionId,
+        final String artifactId
+    ) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("collection id is not valid: " + collectionId);
+            return null;
+        }
+        if (!isValidIdentifier(artifactId)) {
+            logger.debug("artifact id is not valid: " + artifactId);
+            return null;
+        }
+
+        final byte [][] data = new byte[1][1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_COLLECTION_ITEM_GET_ATTRIBUTE);
+                stmnt.setString(1, collectionId);
+                stmnt.setString(2, artifactId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such collection item");
+                    return false;
+                }
+                data[0] = result.getBytes(1);
+                return true;
+            }
+        };
+
+        return exec.runRead()
+            ? XMLUtils.fromByteArray(data[0], true)
+            : null;
+    }
+
+    public boolean setCollectionItemAttribute(
+        final String   collectionId,
+        final String   artifactId,
+        Document       attribute
+    ) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("collection id is not valid: " + collectionId);
+            return false;
+        }
+        if (!isValidIdentifier(artifactId)) {
+            logger.debug("artifact id is not valid: " + artifactId);
+            return false;
+        }
+
+        final byte [] data = XMLUtils.toByteArray(attribute, true);
+
+        boolean success = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+
+                // set the column in collection items
+                prepareStatement(SQL_COLLECTION_ITEM_SET_ATTRIBUTE);
+                if (data == null) {
+                    stmnt.setNull(1, Types.BINARY);
+                }
+                else {
+                    stmnt.setBytes(1, data);
+                }
+                stmnt.setString(2, collectionId);
+                stmnt.setString(3, artifactId);
+                stmnt.execute();
+                reset();
+
+                // touch the collection
+                prepareStatement(SQL_COLLECTIONS_TOUCH_BY_GID);
+                stmnt.setString(1, collectionId);
+                stmnt.execute();
+
+                conn.commit();
+                return true;
+            }
+        }.runWrite();
+
+        if (success) {
+            fireChangedCollectionItemAttribute(
+                collectionId, artifactId, attribute);
+        }
+
+        return success;
+    }
+
+    protected void fireChangedCollectionItemAttribute(
+        String collectionId,
+        String artifactId,
+        Document document
+    ) {
+        for (BackendListener listener: listeners) {
+            listener.changedCollectionItemAttribute(
+                collectionId, artifactId, document, this);
+        }
+    }
+
+    public boolean addCollectionArtifact(
+        final String   collectionId,
+        final String   artifactId,
+        final Document attribute
+    ) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("Invalid collection id: '" + collectionId + "'");
+            return false;
+        }
+
+        if (!isValidIdentifier(artifactId)) {
+            logger.debug("Invalid artifact id: '" + artifactId + "'");
+            return false;
+        }
+
+        final byte [] data = XMLUtils.toByteArray(attribute, true);
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                // fetch artifact id
+                prepareStatement(SQL_GET_ID);
+                stmnt.setString(1, artifactId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such artifact: " + artifactId);
+                    return false;
+                }
+                int aid = result.getInt(1);
+                reset();
+
+                // fetch collection id
+                prepareStatement(SQL_COLLECTIONS_ID_BY_GID);
+                stmnt.setString(1, collectionId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such collection: " + collectionId);
+                }
+                int cid = result.getInt(1);
+                reset();
+
+                // check if artifact is already in collection
+                prepareStatement(SQL_COLLECTION_CHECK_ARTIFACT);
+                stmnt.setInt(1, aid);
+                stmnt.setInt(2, cid);
+                result = stmnt.executeQuery();
+                if (result.next()) {
+                    logger.debug("artifact already in collection");
+                    return false;
+                }
+                reset();
+
+                // fetch fresh id for new collection item
+                prepareStatement(SQL_COLLECTION_ITEMS_ID_NEXTVAL);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("no collection item id generated");
+                    return false;
+                }
+                int ci_id = result.getInt(1);
+                reset();
+
+                // insert new collection item
+                prepareStatement(SQL_COLLECTION_ITEMS_INSERT);
+                stmnt.setInt(1, ci_id);
+                stmnt.setInt(2, cid);
+                stmnt.setInt(3, aid);
+
+                if (data == null) {
+                    stmnt.setNull(4, Types.BINARY);
+                }
+                else {
+                    stmnt.setBytes(4, data);
+                }
+                stmnt.execute();
+                conn.commit();
+
+                return true;
+            }
+        };
+        boolean success = exec.runWrite();
+
+        if (success) {
+            fireAddedArtifactToCollection(artifactId, collectionId);
+        }
+
+        return success;
+    }
+
+    protected void fireAddedArtifactToCollection(
+        String artifactId,
+        String collectionId
+    ) {
+        for (BackendListener listener: listeners) {
+            listener.addedArtifactToCollection(
+                artifactId, collectionId, this);
+        }
+    }
+
+    public boolean removeCollectionArtifact(
+        final String collectionId,
+        final String artifactId
+    ) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("Invalid collection id: '" + collectionId + "'");
+            return false;
+        }
+
+        boolean success = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+
+                // fetch id, collection id and artitfact id
+                prepareStatement(SQL_COLLECTION_ITEM_ID_CID_AID);
+                stmnt.setString(1, collectionId);
+                stmnt.setString(2, artifactId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    logger.debug("No such collection item");
+                    return false;
+                }
+                int  id = result.getInt(1);
+                int cid = result.getInt(2);
+                int aid = result.getInt(3);
+                reset();
+
+                // outdate artifact iff it is only in this collection
+                prepareStatement(SQL_COLLECTION_ITEM_OUTDATE_ARTIFACT);
+                stmnt.setInt(1, aid);
+                stmnt.setInt(2, cid);
+                stmnt.setInt(3, aid);
+                stmnt.execute();
+                reset();
+
+                // delete collection item
+                prepareStatement(SQL_COLLECTION_ITEM_DELETE);
+                stmnt.setInt(1, id);
+                stmnt.execute();
+                reset();
+
+                // touch collection
+                prepareStatement(SQL_COLLECTIONS_TOUCH_BY_ID);
+                stmnt.setInt(1, cid);
+                stmnt.execute();
+
+                conn.commit();
+                return true;
+            }
+        }.runWrite();
+
+        if (success) {
+            fireRemovedArtifactFromCollection(artifactId, collectionId);
+        }
+
+        return success;
+    }
+
+    protected void fireRemovedArtifactFromCollection(
+        String artifactId,
+        String collectionId
+    ) {
+        for (BackendListener listener: listeners) {
+            listener.removedArtifactFromCollection(
+                artifactId, collectionId, this);
+        }
+    }
+
+    public CollectionItem [] listCollectionArtifacts(
+        final String collectionId
+    ) {
+        if (!isValidIdentifier(collectionId)) {
+            logger.debug("Invalid collection id: '" + collectionId + "'");
+            return null;
+        }
+
+        final ArrayList<CollectionItem> collectionItems =
+            new ArrayList<CollectionItem>();
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_COLLECTION_ITEMS_LIST_GID);
+                stmnt.setString(1, collectionId);
+                result = stmnt.executeQuery();
+                while (result.next()) {
+                    CollectionItem item = new DefaultCollectionItem(
+                        result.getString(1),
+                        result.getBytes(2));
+                    collectionItems.add(item);
+                }
+                return true;
+            }
+        };
+
+        return exec.runRead()
+            ? collectionItems.toArray(
+                new CollectionItem[collectionItems.size()])
+            : null;
+    }
+
+
+    public boolean setCollectionTTL(final String uuid, final Long ttl) {
+        if (!isValidIdentifier(uuid)) {
+            logger.debug("Invalid collection id: '" + uuid + "'");
+            return false;
+        }
+
+        return sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_UPDATE_COLLECTION_TTL);
+                if (ttl == null) {
+                    stmnt.setNull(1, Types.BIGINT);
+                }
+                else {
+                    stmnt.setLong(1, ttl);
+                }
+                stmnt.setString(2, uuid);
+                stmnt.execute();
+                conn.commit();
+
+                return true;
+            }
+        }.runWrite();
+    }
+
+
+    public boolean setCollectionName(final String uuid, final String name) {
+        if (!isValidIdentifier(uuid)) {
+            logger.debug("Invalid collection id: '" + uuid + "'");
+            return false;
+        }
+
+        boolean success = sqlExecutor.new Instance() {
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_UPDATE_COLLECTION_NAME);
+                stmnt.setString(1, name);
+                stmnt.setString(2, uuid);
+                stmnt.execute();
+                conn.commit();
+
+                return true;
+            }
+        }.runWrite();
+
+        if (success) {
+            fireSetCollectionName(uuid, name);
+        }
+
+        return success;
+    }
+
+    protected void fireSetCollectionName(String identifier, String name) {
+        for (BackendListener listener: listeners) {
+            listener.setCollectionName(identifier, name);
+        }
+    }
+
+    public boolean loadAllArtifacts(final ArtifactLoadedCallback alc) {
+
+        logger.debug("loadAllArtifacts");
+
+        if (factoryLookup == null) {
+            logger.error("factory lookup == null");
+            return false;
+        }
+
+        boolean success = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                // a little cache to avoid too much deserializations.
+                LRUCache<String, Artifact> alreadyLoaded =
+                    new LRUCache<String, Artifact>(200);
+
+                prepareStatement(SQL_ALL_ARTIFACTS);
+                result = stmnt.executeQuery();
+                while (result.next()) {
+                    String userId         = result.getString("u_gid");
+                    String collectionId   = result.getString("c_gid");
+                    String collectionName = result.getString("c_name");
+                    String artifactId     = result.getString("a_gid");
+                    String factoryName    = result.getString("factory");
+                    Date collectionCreated =
+                        new Date(result.getTimestamp("c_creation").getTime());
+                    Date artifactCreated =
+                        new Date(result.getTimestamp("a_creation").getTime());
+
+                    Artifact artifact = alreadyLoaded.get(artifactId);
+
+                    if (artifact != null) {
+                        alc.artifactLoaded(
+                            userId,
+                            collectionId, collectionName,
+                            collectionCreated,
+                            artifactId, artifactCreated, artifact);
+                        continue;
+                    }
+
+                    ArtifactFactory factory = factoryLookup
+                        .getArtifactFactory(factoryName);
+
+                    if (factory == null) {
+                        logger.error("factory '" + factoryName + "' not found");
+                        continue;
+                    }
+
+                    byte [] bytes = result.getBytes("data");
+
+                    artifact = factory.getSerializer().fromBytes(bytes);
+
+                    if (artifact != null) {
+                        alc.artifactLoaded(
+                            userId,
+                            collectionId, collectionName, collectionCreated,
+                            artifactId, artifactCreated, artifact);
+                    }
+
+                    alreadyLoaded.put(artifactId, artifact);
+                }
+                return true;
+            }
+        }.runRead();
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("loadAllArtifacts success: " + success);
+        }
+
+        return success;
+    }
+
+    @Override
+    public void killedArtifacts(List<String> identifiers) {
+        logger.debug("killedArtifacts");
+        for (BackendListener listener: listeners) {
+            listener.killedArtifacts(identifiers, this);
+        }
+    }
+
+    @Override
+    public void killedCollections(List<String> identifiers) {
+        logger.debug("killedCollections");
+        for (BackendListener listener: listeners) {
+            listener.killedCollections(identifiers, this);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/BackendListener.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/BackendListener.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,61 @@
+package de.intevation.artifactdatabase;
+
+import java.util.List;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.User;
+
+import org.w3c.dom.Document;
+
+public interface BackendListener
+{
+    void setup(GlobalContext globalContext);
+
+    void createdArtifact(Artifact artifact, Backend backend);
+
+    void storedArtifact(Artifact artifact, Backend backend);
+
+    void createdUser(User user, Backend backend);
+
+    void deletedUser(String identifier, Backend backend);
+
+    void createdCollection(ArtifactCollection collection, Backend backend);
+
+    void deletedCollection(String identifier, Backend backend);
+
+    void changedCollectionAttribute(
+        String   identifier,
+        Document document,
+        Backend  backend);
+
+    void changedCollectionItemAttribute(
+        String   collectionId,
+        String   artifactId,
+        Document document,
+        Backend  backend);
+
+    void addedArtifactToCollection(
+        String  artifactId,
+        String  collectionId,
+        Backend backend);
+
+    void removedArtifactFromCollection(
+        String  artifactId,
+        String  collectionId,
+        Backend backend);
+
+    void setCollectionName(
+        String collectionId,
+        String name);
+
+    void killedCollections(
+        List<String> identifiers,
+        Backend      backend);
+
+    void killedArtifacts(
+        List<String> identifiers,
+        Backend      backend);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/CollectionCallContext.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/CollectionCallContext.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.artifactdatabase;
+
+import java.util.LinkedList;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.Message;
+
+
+/**
+ * Class that implements the call context handed to ArtifactCollection specific
+ * operations.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class CollectionCallContext extends AbstractCallContext {
+
+    private static Logger log = Logger.getLogger(CollectionCallContext.class);
+
+    /**
+     * The ArtifactCollection.
+     */
+    protected ArtifactCollection collection;
+
+
+    public CollectionCallContext(
+        ArtifactDatabaseImpl artifactDatabase,
+        int                  action,
+        CallMeta             callMeta,
+        ArtifactCollection   collection)
+    {
+        super(artifactDatabase, action, callMeta);
+
+        this.collection = collection;
+    }
+
+
+    public void afterCall(int action) {
+        log.debug("CollectionCallContext.afterCall - NOT IMPLEMENTED");
+    }
+
+
+    public void afterBackground(int action) {
+        log.debug("CollectionCallContext.afterBackground - NOT IMPLEMENTED");
+    }
+
+
+    public boolean isInBackground() {
+        log.debug("CollectionCallContext.isInBackground - NOT IMPLEMENTED");
+        return false;
+    }
+
+
+    public void addBackgroundMessage(Message msg) {
+        log.debug("CollectionCallContext.addBackgroundMessage NOT IMPLEMENTED");
+    }
+
+
+    public LinkedList<Message> getBackgroundMessages() {
+        log.debug("CollectionCallContext.addBackgroundMessage NOT IMPLEMENTED");
+        return null;
+    }
+
+
+    public Long getTimeToLive() {
+        log.debug("CollectionCallContext.getTimeToLive - NOT IMPLEMENTED");
+        return null;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DBConfig.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DBConfig.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,83 @@
+package de.intevation.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.artifactdatabase.db.SQL;
+import de.intevation.artifactdatabase.db.DBConnection;
+
+public class DBConfig
+{
+    /**
+     * XPath to access the database driver within the global configuration.
+     */
+    public static final String DB_DRIVER =
+        "/artifact-database/database/driver/text()";
+    /**
+     * XPath to access the database URL within the global configuration.
+     */
+    public static final String DB_URL =
+        "/artifact-database/database/url/text()";
+    /**
+     * XPath to access the database use within the global configuration.
+     */
+    public static final String DB_USER =
+        "/artifact-database/database/user/text()";
+    /**
+     * XPath to access the database password within the global configuration.
+     */
+    public static final String DB_PASSWORD =
+        "/artifact-database/database/password/text()";
+
+    private static DBConfig instance;
+
+    private DBConnection dbConnection;
+    private SQL          sql;
+
+    private DBConfig() {
+    }
+
+    private DBConfig(DBConnection dbConnection, SQL sql) {
+        this.dbConnection = dbConnection;
+        this.sql          = sql;
+    }
+
+    public static synchronized DBConfig getInstance() {
+        if (instance == null) {
+            instance = createInstance();
+        }
+        return instance;
+    }
+
+    public SQL getSQL() {
+        return sql;
+    }
+
+    public DBConnection getDBConnection() {
+        return dbConnection;
+    }
+
+    private static DBConfig createInstance() {
+
+        String driver = Config.getStringXPath(
+            DB_DRIVER, DBConnection.DEFAULT_DRIVER);
+
+        String url = Config.getStringXPath(
+            DB_URL, DBConnection.DEFAULT_URL);
+
+        url = Config.replaceConfigDir(url);
+
+        String user = Config.getStringXPath(
+            DB_USER, DBConnection.DEFAULT_USER);
+
+        String password = Config.getStringXPath(
+            DB_PASSWORD, DBConnection.DEFAULT_PASSWORD);
+
+        DBConnection dbConnection = new DBConnection(
+            driver, url, user, password);
+
+        SQL sql = new SQL(driver);
+
+        return new DBConfig(dbConnection, sql);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DatabaseCleaner.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DatabaseCleaner.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,446 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.Config;
+import de.intevation.artifacts.common.utils.StringUtils;
+
+import de.intevation.artifacts.Artifact;
+
+import de.intevation.artifactdatabase.db.SQL;
+import de.intevation.artifactdatabase.db.DBConnection;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.Collections;
+
+import javax.sql.DataSource;
+
+import org.apache.log4j.Logger;
+
+/**
+ * The database cleaner runs in background. It sleep for a configurable
+ * while and when it wakes up it removes outdated artifacts from the
+ * database. Outdated means that the the last access to the artifact
+ * is longer aga then the time to live of this artifact.<br>
+ * Before the artifact is finally removed from the system it is
+ * revived one last time an the #endOfLife() method of the artifact
+ * is called.<br>
+ * The artifact implementations may e.g. use this to remove some extrenal
+ * resources form the system.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DatabaseCleaner
+extends      Thread
+{
+    /**
+     * Implementors of this interface are able to create a
+     * living artifact from a given byte array.
+     */
+    public interface ArtifactReviver {
+
+        /**
+         * Called to revive an artifact from a given byte array.
+         * @param factoryName The name of the factory which
+         * created this artifact.
+         * @param bytes The bytes of the serialized artifact.
+         * @return The revived artfiact.
+         */
+        Artifact reviveArtifact(String factoryName, byte [] bytes);
+
+        void killedArtifacts(List<String> identifiers);
+        void killedCollections(List<String> identifiers);
+
+    } // interface ArtifactReviver
+
+    public interface LockedIdsProvider {
+        Set<Integer> getLockedIds();
+    } // interface LockedIdsProvider
+
+    private static Logger logger = Logger.getLogger(DatabaseCleaner.class);
+
+    /**
+     * Number of artifacts to be loaded at once. Used to
+     * mitigate the problem of a massive denial of service
+     * if too many artifacts have died since last cleanup.
+     */
+    public static final int MAX_ROWS = 50;
+
+    public static final Set<Integer> EMPTY_IDS = Collections.emptySet();
+
+    /**
+     * The SQL statement to select the outdated artifacts.
+     */
+    public String SQL_OUTDATED;
+
+    public String SQL_OUTDATED_COLLECTIONS;
+    public String SQL_DELETE_COLLECTION_ITEMS;
+    public String SQL_DELETE_COLLECTION;
+
+    /**
+     * The SQL statement to delete some artifacts from the database.
+     */
+    public String SQL_DELETE_ARTIFACT;
+
+    /**
+     * XPath to figure out how long the cleaner should sleep between
+     * cleanups. This is stored in the global configuration.
+     */
+    public static final String SLEEP_XPATH =
+        "/artifact-database/cleaner/sleep-time/text()";
+
+    /**
+     * Default nap time between cleanups: 5 minutes.
+     */
+    public static final long SLEEP_DEFAULT =
+        5 * 60 * 1000L; // 5 minutes
+
+    /**
+     * The configured nap time.
+     */
+    protected long sleepTime;
+
+    /**
+     * Internal locking mechanism to prevent some race conditions.
+     */
+    protected Object sleepLock = new Object();
+
+    /**
+     * A reference to the global context.
+     */
+    protected Object context;
+
+    /**
+     * A specialized Id filter which only delete some artifacts.
+     * This is used to prevent deletion of living artifacts.
+     */
+    protected LockedIdsProvider lockedIdsProvider;
+
+    /**
+     * The reviver used to bring the dead artifact on last
+     * time back to live to call endOfLife() on them.
+     */
+    protected ArtifactReviver reviver;
+
+    protected DBConnection dbConnection;
+
+    /**
+     * Default constructor.
+     */
+    public DatabaseCleaner() {
+    }
+
+    /**
+     * Constructor to create a cleaner with a given global context
+     * and a given reviver.
+     * @param context The global context of the artifact database
+     * @param reviver The reviver to awake artifact one last time.
+     */
+    public DatabaseCleaner(Object context, ArtifactReviver reviver, DBConfig config) {
+        setDaemon(true);
+        sleepTime = getSleepTime();
+        this.context = context;
+        this.reviver = reviver;
+        this.dbConnection = config.getDBConnection();
+        setupSQL(config.getSQL());
+    }
+
+    protected void setupSQL(SQL sql) {
+        SQL_OUTDATED                = sql.get("artifacts.outdated");
+        SQL_OUTDATED_COLLECTIONS    = sql.get("collections.outdated");
+        SQL_DELETE_COLLECTION_ITEMS = sql.get("delete.collection.items");
+        SQL_DELETE_COLLECTION       = sql.get("delete.collection");
+        SQL_DELETE_ARTIFACT         = sql.get("artifacts.delete");
+    }
+
+    /**
+     * Sets the filter that prevents deletion of living artifacts.
+     * Living artifacts are artifacts which are currently active
+     * inside the artifact database. Deleting them in this state
+     * would create severe internal problems.
+     */
+    public void setLockedIdsProvider(LockedIdsProvider lockedIdsProvider) {
+        this.lockedIdsProvider = lockedIdsProvider;
+    }
+
+    /**
+     * External hook to tell the cleaner to wake up before its
+     * regular nap time is over. This is the case when the artifact
+     * database finds an artifact which is already outdated.
+     */
+    public void wakeup() {
+        synchronized (sleepLock) {
+            sleepLock.notify();
+        }
+    }
+
+    /**
+     * Fetches the sleep time from the global configuration.
+     * @return the time to sleep between database cleanups in ms.
+     */
+    protected static long getSleepTime() {
+        String sleepTimeString = Config.getStringXPath(SLEEP_XPATH);
+
+        if (sleepTimeString == null) {
+            return SLEEP_DEFAULT;
+        }
+        try {
+            // sleep at least one second
+            return Math.max(Long.parseLong(sleepTimeString), 1000L);
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("Cleaner sleep time defaults to " + SLEEP_DEFAULT);
+        }
+        return SLEEP_DEFAULT;
+    }
+
+    private static class IdIdentifier {
+
+        int     id;
+        String  identifier;
+
+        private IdIdentifier(int id, String identifier) {
+            this.id         = id;
+            this.identifier = identifier;
+        }
+    } // class IdIdentifier
+
+    private static final class IdData
+    extends IdIdentifier
+    {
+        byte [] data;
+        String  factoryName;
+
+        public IdData(
+            int     id,
+            String  factoryName,
+            byte [] data,
+            String  identifier
+        ) {
+            super(id, identifier);
+            this.factoryName = factoryName;
+            this.data        = data;
+        }
+    } // class IdData
+
+    /**
+     * Cleaning is done in two phases. First we fetch a list of ids
+     * of artifacts. If there are artifacts the cleaning is done.
+     * Second we load the artifacts one by one one and call there
+     * endOfLife() method. In this loop we remove them from database, too.
+     * Each deletion is commited to ensure that a sudden failure
+     * of the artifact database server does delete artifacts twice
+     * or does not delete them at all. After this the first step
+     * is repeated.
+     */
+    protected void cleanup() {
+        logger.info("database cleanup");
+
+        Connection        connection = null;
+        PreparedStatement fetchIds   = null;
+        PreparedStatement stmnt      = null;
+        ResultSet         result     = null;
+
+        DataSource dataSource = dbConnection.getDataSource();
+
+        Set<Integer> lockedIds = lockedIdsProvider != null
+            ? lockedIdsProvider.getLockedIds()
+            : EMPTY_IDS;
+
+        String questionMarks = lockedIds.isEmpty()
+            ? "-666" // XXX: A bit hackish.
+            : StringUtils.repeat('?', lockedIds.size(), ',');
+
+        List<String> deletedCollections = new ArrayList<String>();
+        List<String> deletedArtifacts   = new ArrayList<String>();
+
+        try {
+            connection = dataSource.getConnection();
+            connection.setAutoCommit(false);
+
+            fetchIds = connection.prepareStatement(
+                SQL_OUTDATED.replace("$LOCKED_IDS$", questionMarks));
+
+            // some dbms like derby do not support LIMIT
+            // in SQL statements.
+            fetchIds.setMaxRows(MAX_ROWS);
+
+            // Fetch ids of outdated collections
+            stmnt = connection.prepareStatement(
+                SQL_OUTDATED_COLLECTIONS.replace(
+                    "$LOCKED_IDS$", questionMarks));
+
+            // fill in the locked ids
+            int idx = 1;
+            for (Integer id: lockedIds) {
+                fetchIds.setInt(idx, id);
+                stmnt   .setInt(idx, id);
+                ++idx;
+            }
+
+            ArrayList<IdIdentifier> cs = new ArrayList<IdIdentifier>();
+            result = stmnt.executeQuery();
+            while (result.next()) {
+                cs.add(new IdIdentifier(
+                    result.getInt(1),
+                    result.getString(2)));
+            }
+
+            result.close(); result = null;
+            stmnt.close();  stmnt  = null;
+
+            // delete collection items
+            stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION_ITEMS);
+
+            for (IdIdentifier id: cs) {
+                logger.debug("Mark collection for deletion: " + id.id);
+                stmnt.setInt(1, id.id);
+                stmnt.execute();
+            }
+
+            stmnt.close(); stmnt = null;
+
+            // delete collections
+            stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION);
+
+            for (IdIdentifier id: cs) {
+                stmnt.setInt(1, id.id);
+                stmnt.execute();
+                deletedCollections.add(id.identifier);
+            }
+
+            stmnt.close(); stmnt = null;
+            connection.commit();
+
+            cs = null;
+
+            // remove artifacts
+            stmnt = connection.prepareStatement(SQL_DELETE_ARTIFACT);
+
+            for (;;) {
+                List<IdData> ids = new ArrayList<IdData>();
+
+                result = fetchIds.executeQuery();
+
+                while (result.next()) {
+                    ids.add(new IdData(
+                        result.getInt(1),
+                        result.getString(2),
+                        result.getBytes(3),
+                        result.getString(4)));
+                }
+
+                result.close(); result = null;
+
+                if (ids.isEmpty()) {
+                    break;
+                }
+
+                for (int i = ids.size()-1; i >= 0; --i) {
+                    IdData idData = ids.get(i);
+                    Artifact artifact = reviver.reviveArtifact(
+                        idData.factoryName, idData.data);
+                    idData.data = null;
+
+                    logger.debug("Prepare Artifact (id="
+                        + idData.id + ") for deletion.");
+
+                    stmnt.setInt(1, idData.id);
+                    stmnt.execute();
+                    connection.commit();
+
+                    try {
+                        if (artifact != null) {
+                            logger.debug("Call endOfLife for Artifact: "
+                                + artifact.identifier());
+
+                            artifact.endOfLife(context);
+                        }
+                    }
+                    catch (Exception e) {
+                        logger.error(e.getMessage(), e);
+                    }
+
+                    deletedArtifacts.add(idData.identifier);
+                } // for all fetched data
+            }
+        }
+        catch (SQLException sqle) {
+            logger.error(sqle.getLocalizedMessage(), sqle);
+        }
+        finally {
+            if (result != null) {
+                try { result.close(); }
+                catch (SQLException sqle) {}
+            }
+            if (stmnt != null) {
+                try { stmnt.close(); }
+                catch (SQLException sqle) {}
+            }
+            if (fetchIds != null) {
+                try { fetchIds.close(); }
+                catch (SQLException sqle) {}
+            }
+            if (connection != null) {
+                try { connection.close(); }
+                catch (SQLException sqle) {}
+            }
+        }
+
+        if (!deletedCollections.isEmpty()) {
+            reviver.killedCollections(deletedCollections);
+        }
+
+        if (!deletedArtifacts.isEmpty()) {
+            reviver.killedArtifacts(deletedArtifacts);
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "collections removed: " + deletedCollections.size());
+            logger.debug(
+                "artifacts removed: " + deletedArtifacts.size());
+        }
+    }
+
+    /**
+     * The main code of the cleaner. It sleeps for the configured
+     * nap time, cleans up the database, sleeps again and so on.
+     */
+    @Override
+    public void run() {
+        logger.info("sleep time: " + sleepTime + "ms");
+        for (;;) {
+            cleanup();
+            long startTime = System.currentTimeMillis();
+
+            try {
+                synchronized (sleepLock) {
+                    sleepLock.wait(sleepTime);
+                }
+            }
+            catch (InterruptedException ie) {
+            }
+
+            long stopTime = System.currentTimeMillis();
+
+            if (logger.isDebugEnabled()) {
+                logger.debug("Cleaner slept " + (stopTime - startTime) + "ms");
+            }
+        } // for (;;)
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifact.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifact.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,142 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+/**
+ * Trivial implementation of an artifact. Useful to be subclassed.
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultArtifact
+implements   Artifact
+{
+    private static Logger logger = Logger.getLogger(DefaultArtifact.class);
+
+    /**
+     * The identifier of the artifact.
+     */
+    protected String identifier;
+
+
+    /**
+     * Default constructor.
+     */
+    public DefaultArtifact() {
+    }
+
+
+    public void setIdentifier(String identifier) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Change identifier: "
+                + this.identifier + " -> " + identifier);
+        }
+        this.identifier = identifier;
+    }
+
+    public String identifier() {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.identifier: " + identifier);
+        }
+        return this.identifier;
+    }
+
+
+    public String hash() {
+        String hash = String.valueOf(hashCode());
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.hashCode: "
+                + identifier + " (" + hash + ")");
+        }
+        return hash;
+    }
+
+    public Document describe(Document data, CallContext context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.describe: " + identifier);
+        }
+        return XMLUtils.newDocument();
+    }
+
+    public Document advance(Document target, CallContext context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.advance: " + identifier);
+        }
+        return XMLUtils.newDocument();
+    }
+
+    public Document feed(Document target, CallContext context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.feed: " + identifier);
+        }
+        return XMLUtils.newDocument();
+    }
+
+    public void out(
+        Document     format,
+        OutputStream out,
+        CallContext  context
+    )
+    throws IOException
+    {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.out: " + identifier);
+        }
+    }
+
+    public void out(
+        String       type,
+        Document     format,
+        OutputStream out,
+        CallContext  context
+    )
+    throws IOException
+    {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.out: " + identifier);
+        }
+    }
+
+    public void setup(String identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.setup: " + identifier);
+        }
+        this.identifier = identifier;
+    }
+
+    public void endOfLife(Object context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.endOfLife: " + identifier);
+        }
+    }
+
+    public void cleanup(Object context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("DefaultArtifact.cleanup: " + identifier);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactCollection.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactCollection.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,353 @@
+/*
+ * 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.artifactdatabase;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.ArtifactCollectionFactory;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.User;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+
+/**
+ * Trivial implementation of an artifact collection. Useful to be subclassed.
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultArtifactCollection
+implements   ArtifactCollection
+{
+    /** The logger used in this class. */
+    private static Logger logger =
+        Logger.getLogger(DefaultArtifactCollection.class);
+
+    /** The identifier of the collection. */
+    protected String identifier;
+
+    /** The identifier of the collection. */
+    protected String name;
+
+    /** The owner of this collection. */
+    protected User user;
+
+    /** The attribute of this collection. */
+    protected Document attribute;
+
+    /** The artifacts stored in this collection. */
+    protected List<Artifact> artifacts;
+
+    /**
+     * The attributes used for the artifacts stored in this collection. The key
+     * of this map represents the identifier of the artifact which the attribute
+     * belong to.
+     */
+    protected Map<String, Document> attributes;
+
+    /** The creation time of this collection.*/
+    protected Date creationTime;
+
+    protected long ttl;
+
+
+    /**
+     * Default constructor.
+     */
+    public DefaultArtifactCollection() {
+    }
+
+
+    /**
+     * When created by a factory this method is called to
+     * initialize the collection.
+     * @param identifier The identifier from collection database
+     * @param factory    The factory which created this collection.
+     * @param context    The global context of the runtime system.
+     * @param data       The data which can be use to setup a collection with
+     *                   more details.
+     */
+    public void setup(
+        String                    identifier,
+        String                    name,
+        Date                      creationTime,
+        long                      ttl,
+        ArtifactCollectionFactory factory,
+        Object                    context,
+        Document                  data)
+    {
+        logger.debug("DefaultArtifactCollection.setup: " + identifier);
+
+        artifacts  = new ArrayList<Artifact>();
+        attributes = new HashMap<String, Document>();
+
+        setIdentifier(identifier);
+        setName(name);
+        setCreationTime(creationTime);
+        setTTL(ttl);
+        setAttribute(data);
+    }
+
+
+    public Document describe(CallContext context) {
+        logger.debug("DefaultArtifactCollection.describe: " + identifier);
+
+        return XMLUtils.newDocument();
+    }
+
+
+    /**
+     * Set a new identifier for this collection.
+     * @param identifier New identifier for this collection.
+     */
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+
+    /**
+     * Identify this collection.
+     * @return Returns unique string to identify this collection globally.
+     */
+    public String identifier() {
+        return identifier;
+    }
+
+
+    /**
+     * Name of this collection.
+     * @return Returns the name of this collection
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Name of this collection.
+     * @param name the name of this collection
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * Set a new owner of this collection.
+     * @param user New owner for this collection.
+     */
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+
+    /**
+     * Identify the owner of the collection.
+     * @return Returns owner of the collection.
+     */
+    public User getUser() {
+        return user;
+    }
+
+
+    /**
+     * Returns the creation time of the collection.
+     *
+     * @return the creation time of the collection.
+     */
+    public Date getCreationTime() {
+        return creationTime;
+    }
+
+
+    /**
+     * Sets the creation time of the collection.
+     *
+     * @param creationTime The new creation time.
+     */
+    public void setCreationTime(Date creationTime) {
+        this.creationTime = creationTime;
+    }
+
+
+    public long getTTL() {
+        return ttl;
+    }
+
+
+    public void setTTL(long ttl) {
+        this.ttl = ttl;
+    }
+
+
+    /**
+     * Returns the attribute of the collection.
+     *
+     * @return the attribute of the collection.
+     */
+    public Document getAttribute() {
+        return attribute;
+    }
+
+
+    /**
+     * Sets the attribute of the collection.
+     *
+     * @param attribute The attribute of this collection.
+     */
+    public void setAttribute(Document attribute) {
+        this.attribute = attribute;
+    }
+
+
+    /**
+     * Called from artifact database when an artifact is
+     * going to be removed from system.
+     * @param context The global context of the runtime system.
+     */
+    public void endOfLife(Object context) {
+        logger.debug("DefaultArtifactCollection.endOfLife");
+    }
+
+
+    /**
+     * Internal hash of this collection.
+     * @return Returns hash that should stay the same if the internal
+     *         value has not changed. Useful for caching
+     */
+    public String hash() {
+        logger.debug("DefaultArtifactCollection.hash");
+
+        return String.valueOf(hashCode());
+    }
+
+
+    /**
+     * Called from artifact database before an artifact is
+     * going to be exported as xml document.
+     * @param context The global context of the runtime system.
+     */
+    public void cleanup(Object context) {
+        logger.debug("DefaultArtifactCollection.cleanup");
+    }
+
+
+    /**
+     * Adds a new artifact to this collection.
+     *
+     * @param artifact The new artifact.
+     * @param attribute The attributes used for this artifact.
+     * @param context The CallContext.
+     */
+    public void addArtifact(
+        Artifact    artifact,
+        Document    attribute,
+        CallContext context)
+    {
+        logger.debug("DefaultArtifactCollection.addArtifact");
+
+        artifacts.add(artifact);
+        attributes.put(artifact.identifier(), attribute);
+    }
+
+
+    /**
+     * Removes the given artifact from this collection.
+     *
+     * @param artifact The artifact that should be removed.
+     * @param context The CallContext.
+     */
+    public void removeArtifact(Artifact artifact, CallContext context) {
+        logger.debug("DefaultArtifactCollection.removeArtifact");
+
+        if (artifact == null) {
+            return;
+        }
+
+        artifacts.remove(artifact);
+        attributes.remove(artifact.identifier());
+    }
+
+
+    /**
+     * Returns a list of artifacts that are stored in this collection.
+     *
+     * @param context The CallContext.
+     *
+     * @return the list of artifacts stored in this collection.
+     */
+    public Artifact[] getArtifacts(CallContext context) {
+        logger.debug("DefaultArtifactCollection.getArtifacts");
+
+        return (Artifact[]) artifacts.toArray();
+    }
+
+
+    /**
+     * Returns the attribute document for the given artifact.
+     *
+     * @param artifact The artifact.
+     * @param context The CallContext.
+     *
+     * @return a document that contains the attributes of the artifact.
+     */
+    public Document getAttribute(Artifact artifact, CallContext context) {
+        logger.debug("DefaultArtifactCollection.getAttribute");
+
+        return attributes.get(artifact.identifier());
+    }
+
+
+    /**
+     * Set the attribute for the given artifact.
+     *
+     * @param artifact The artifact of the attribute.
+     * @param document The new attribute of the artifact.
+     * @param context The CallContext.
+     */
+    public void setAttribute(
+        Artifact    artifact,
+        Document    document,
+        CallContext context)
+    {
+        logger.debug("DefaultArtifactCollection.setAttribute");
+
+        attributes.put(artifact.identifier(), document);
+    }
+
+
+    /**
+     * Produce output for this collection.
+     * @param type Specifies the output type.
+     * @param format Specifies the format of the output.
+     * @param out Stream to write the result data to.
+     * @param context The global context of the runtime system.
+     * @throws IOException Thrown if an I/O occurs.
+     */
+    public void out(
+        String       type,
+        Document     format,
+        OutputStream out,
+        CallContext  context)
+    throws IOException
+    {
+        logger.debug("DefaultArtifactCollection.out");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactCollectionFactory.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactCollectionFactory.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,194 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.ArtifactCollectionFactory;
+
+import java.util.Date;
+
+
+/**
+ * The default implementation of a ArtifactCollectionFactory.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultArtifactCollectionFactory
+implements   ArtifactCollectionFactory
+{
+    /** The logger that is used in this factory.*/
+    private static Logger logger =
+        Logger.getLogger(DefaultArtifactCollectionFactory.class);
+
+    /** XPath to access the TTL of this artifact.*/
+    public static final String XPATH_TTL = "@ttl";
+
+    /** XPath to access the name of this factory.*/
+    public static final String XPATH_NAME = "@name";
+
+    /** XPath to access the description of this artifact factory.*/
+    public static final String XPATH_DESCRIPTION = "@description";
+
+    /**
+     * XPath to access the class name of the artifacts to be build
+     * by this factory.
+     */
+    public static final String XPATH_ARTIFACTCOLLECTION = "@artifact-collection";
+
+    /**
+     * Default description of this factory if none is given by the
+     * configuration.
+     */
+    public static final String DEFAULT_DESCRIPTION =
+        "No description available";
+
+    /**
+     * Class to load if no artifact class is given in the configuration.
+     */
+    public static final String DEFAULT_ARTIFACTCOLLECTION =
+        "de.intevation.artifactdatabase.DefaultArtifact";
+
+
+    /** The name of the factory.*/
+    protected String name;
+
+    /** The description of the factory.*/
+    protected String description;
+
+    /** The class that is used to instantiate new ArtifactCollection.*/
+    protected Class clazz;
+
+    /** The time to live of the artifact collection build by this factory.*/
+    protected Long ttl;
+
+
+    /**
+     * The default constructor.
+     */
+    public DefaultArtifactCollectionFactory() {
+    }
+
+
+   /**
+    * The short name of this factory.
+    *
+    * @return the name of this factory.
+    */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Description of this factory.
+     *
+     * @return description of the factory.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the time to live of the given artifact.
+     */
+    public Long timeToLiveUntouched(
+        ArtifactCollection collection,
+        Object             context)
+    {
+        return ttl;
+    }
+
+
+    /**
+     * Create a new artifact of certain type, given a general purpose context and
+     * an identifier.
+     * @param context a context from the ArtifactDatabase.
+     * @param identifier unique identifer for the new artifact
+     * @param data  the data containing more details for the setup of an Artifact.
+     * @return a new {@linkplain de.intevation.artifacts.ArtifactCollection ArtifactCollection}
+     */
+    public ArtifactCollection createCollection(
+        String   identifier,
+        String   name,
+        Date     creationTime,
+        long     ttl,
+        Document data,
+        Object   context
+    ) {
+        try {
+            ArtifactCollection collection =
+                (ArtifactCollection) clazz.newInstance();
+
+            collection.setup(identifier,
+                name,
+                creationTime,
+                ttl,
+                this,
+                context,
+                data);
+
+            return collection;
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+
+        return null;
+    }
+
+    /**
+     * Setup the factory with a given configuration
+     * @param config the configuration
+     * @param factoryNode the ConfigurationNode of this Factory
+     */
+    public void setup(Document config, Node factoryNode) {
+        String ttlString = Config.getStringXPath(factoryNode, XPATH_TTL);
+        if (ttlString != null) {
+            try {
+                ttl = Long.valueOf(ttlString);
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("'" + ttlString + "' is not an integer.");
+            }
+        }
+
+        description = Config.getStringXPath(
+            factoryNode, XPATH_DESCRIPTION, DEFAULT_DESCRIPTION);
+
+        name = Config.getStringXPath(factoryNode, XPATH_NAME, toString());
+
+        String artifactCollection = Config.getStringXPath(
+            factoryNode, XPATH_ARTIFACTCOLLECTION, DEFAULT_ARTIFACTCOLLECTION);
+
+        try {
+            clazz = Class.forName(artifactCollection);
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+
+        if (clazz == null) {
+            clazz = DefaultArtifactCollection.class;
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactContext.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactContext.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,83 @@
+/*
+ * 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.artifactdatabase;
+
+import java.util.HashMap;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifacts.GlobalContext;
+
+/**
+ * Default implementation of the context.
+ * Besides of the configuration it hosts a map to store key/value pairs.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultArtifactContext implements GlobalContext
+{
+    /**
+     * The global configuration document of the artifact database.
+     */
+    protected Document config;
+
+    /**
+     * Custom key/value pairs to be used globally in the whole server.
+     */
+    protected HashMap map;
+
+    /**
+     * Default constructor
+     */
+    public DefaultArtifactContext() {
+        this(null);
+    }
+
+    /**
+     * Constructor to create a context with a given global
+     * configuration document and an empty map of custom
+     * key/value pairs.
+     * @param config
+     */
+    public DefaultArtifactContext(Document config) {
+        this.config = config;
+        map = new HashMap();
+    }
+
+    /**
+     * Fetch a custom value from the global key/value map using
+     * a given key.
+     * @param key The key.
+     * @return The stored value or null if no value was found under
+     * this key.
+     */
+    public synchronized Object get(Object key) {
+        return map.get(key);
+    }
+
+    /**
+     * Store a custom key/value pair in the global map.
+     * @param key The key to store
+     * @param value The value to store
+     * @return The old value registered under the key or null
+     * if none wa there before.
+     */
+    public synchronized Object put(Object key, Object value) {
+        return map.put(key, value);
+    }
+
+    /**
+     * Returns a reference to the global configuration document.
+     * @return The global configuration document.
+     */
+    public Document getConfig() {
+        return config;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactContextFactory.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactContextFactory.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.ArtifactContextFactory;
+import de.intevation.artifacts.GlobalContext;
+
+import org.w3c.dom.Document;
+
+/**
+ * Default implementation of the context factory.
+ * Creates a new @see DefaultArtifactContext.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultArtifactContextFactory
+implements   ArtifactContextFactory
+{
+    /**
+     * Default constructor.
+     */
+    public DefaultArtifactContextFactory() {
+    }
+
+    public GlobalContext createArtifactContext(Document config) {
+        return new DefaultArtifactContext(config);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactFactory.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactFactory.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,172 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.ArtifactSerializer;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * Trivial implementation of the ArtifactFactory interface.
+ * Time to live (ttl), name and description are configured
+ * via the Node given to #setup(Document, Node) with attributes
+ * of same name. The class name of the artifacts to be build by this
+ * factory is configures with the attribute 'artifact'.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultArtifactFactory
+implements   ArtifactFactory
+{
+    private static Logger logger =
+        Logger.getLogger(DefaultArtifactFactory.class);
+
+    /**
+     * XPath to access the TTL of this artifact.
+     */
+    public static final String XPATH_TTL         = "@ttl";
+    /**
+     * XPath to access the name of this factory.
+     */
+    public static final String XPATH_NAME        = "@name";
+    /**
+     * XPath to access the description of this artifact factory.
+     */
+    public static final String XPATH_DESCRIPTION = "@description";
+    /**
+     * XPath to access the class name of the artifacts to be build
+     * by this factory.
+     */
+    public static final String XPATH_ARTIFACT    = "@artifact";
+
+    /**
+     * Default description of this factory if none is given by the
+     * configuration.
+     */
+    public static final String DEFAULT_DESCRIPTION =
+        "No description available";
+
+    /**
+     * Class to load if no artifact class is given in the configuration.
+     */
+    public static final String DEFAULT_ARTIFACT =
+        "de.intevation.artifactdatabase.DefaultArtifact";
+
+    /**
+     * The Time to live of the artifacts build by this factory.
+     */
+    protected Long   ttl;
+
+    /**
+     * The name of this factory.
+     */
+    protected String name;
+
+    /**
+     * The description of this factory.
+     */
+    protected String description;
+
+    /**
+     * The class of the artifacts to be build by this factory.
+     */
+    protected Class  artifactClass;
+
+    /**
+     * Default constructor.
+     */
+    public DefaultArtifactFactory() {
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public Artifact createArtifact(
+        String        identifier,
+        GlobalContext context,
+        CallMeta      callMeta,
+        Document      data
+    ) {
+        try {
+            Artifact artifact =
+                (Artifact)artifactClass.newInstance();
+
+            artifact.setup(identifier, this, context, callMeta, data);
+
+            return artifact;
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+
+        return null;
+    }
+
+    public void setup(Document document, Node factoryNode) {
+
+        String ttlString = Config.getStringXPath(factoryNode, XPATH_TTL);
+        if (ttlString != null) {
+            try {
+                ttl = Long.valueOf(ttlString);
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("'" + ttlString + "' is not an integer.");
+            }
+        }
+
+        description = Config.getStringXPath(
+            factoryNode, XPATH_DESCRIPTION, DEFAULT_DESCRIPTION);
+
+        name = Config.getStringXPath(
+            factoryNode, XPATH_NAME, toString());
+
+        String artifact = Config.getStringXPath(
+            factoryNode, XPATH_ARTIFACT, DEFAULT_ARTIFACT);
+
+        try {
+            artifactClass = Class.forName(artifact);
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+
+        if (artifactClass == null) {
+            artifactClass = DefaultArtifact.class;
+        }
+    }
+
+    public Long timeToLiveUntouched(Artifact artifact, Object context) {
+        return ttl;
+    }
+
+    public ArtifactSerializer getSerializer() {
+        return DefaultArtifactSerializer.INSTANCE;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactSerializer.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultArtifactSerializer.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,132 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Default implementation of the ArtifactSerializer interface.
+ * It uses serialized Java objects which are gzipped and
+ * turned into bytes.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultArtifactSerializer
+implements   ArtifactSerializer
+{
+    private static Logger logger =
+        Logger.getLogger(DefaultArtifactSerializer.class);
+
+    /**
+     * Static instance to avoid repeated creation of Serializers.
+     */
+    public static final ArtifactSerializer INSTANCE =
+        new DefaultArtifactSerializer();
+
+    /**
+     * Default constructor.
+     */
+    public DefaultArtifactSerializer() {
+    }
+
+    public Artifact fromBytes(byte [] bytes) {
+
+        if (bytes == null) {
+            return null;
+        }
+
+        ObjectInputStream ois = null;
+
+        try {
+            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+            GZIPInputStream      gis = new GZIPInputStream(bis);
+                                 ois = getObjectInputStream(gis);
+
+            return (Artifact)ois.readObject();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+        finally {
+            if (ois != null) {
+                try { ois.close(); }
+                catch (IOException ioe) { }
+            }
+        }
+
+        return null;
+    }
+
+    public byte [] toBytes(Artifact artifact) {
+        try {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            GZIPOutputStream      gos = new GZIPOutputStream(bos);
+            ObjectOutputStream    oos = getObjectOutputStream(gos);
+
+            oos.writeObject(artifact);
+            oos.flush();
+            oos.close();
+
+            return bos.toByteArray();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    /**
+     * Wraps an input stream into an object input stream. You may
+     * overwrite this to get a more specialized deserializer.
+     * @param is The raw input stream
+     * @return An instance of a subclass of ObjectInputStream.
+     * @throws IOException Thrown if something went wrong during
+     * creation of the object input stream.
+     */
+    protected ObjectInputStream getObjectInputStream(InputStream is)
+    throws    IOException
+    {
+        return new ObjectInputStream(is);
+    }
+
+    /**
+     * Wraps an output stream into an object output stream. You may
+     * overwrite this to get a more specialized serializer.
+     * @param os the raw output stream.
+     * @return An instance of a subclass of ObjectOutputStream.
+     * @throws IOException Thrown if something went wrong during
+     * creation of the object output stream.
+     */
+    protected ObjectOutputStream getObjectOutputStream(OutputStream os)
+    throws    IOException
+    {
+        return new ObjectOutputStream(os);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultBackendListener.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultBackendListener.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,116 @@
+package de.intevation.artifactdatabase;
+
+import java.util.List;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.User;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+public class DefaultBackendListener
+implements   BackendListener
+{
+    private static Logger log = Logger.getLogger(DefaultBackendListener.class);
+
+    public DefaultBackendListener() {
+    }
+
+    @Override
+    public void setup(GlobalContext globalContext) {
+        log.debug("setup");
+    }
+
+    @Override
+    public void createdArtifact(Artifact artifact, Backend backend) {
+        log.debug("createdArtifact");
+    }
+
+    @Override
+    public void storedArtifact(Artifact artifact, Backend backend) {
+        log.debug("storedArtifact");
+    }
+
+    @Override
+    public void createdUser(User user, Backend backend) {
+        log.debug("createdUser");
+    }
+
+    @Override
+    public void deletedUser(String identifier, Backend backend) {
+        log.debug("deletedUser");
+    }
+
+    @Override
+    public void createdCollection(
+        ArtifactCollection collection,
+        Backend            backend
+    ) {
+        log.debug("createdCollection");
+    }
+
+    @Override
+    public void deletedCollection(String identifier, Backend backend) {
+        log.debug("deletedCollection");
+    }
+
+    @Override
+    public void changedCollectionAttribute(
+        String   identifier,
+        Document document,
+        Backend  backend
+    ) {
+        log.debug("changedCollectionAttribute");
+    }
+
+    @Override
+    public void changedCollectionItemAttribute(
+        String   collectionId,
+        String   artifactId,
+        Document document,
+        Backend  backend
+    ) {
+        log.debug("changedCollectionItemAttribute");
+    }
+
+    @Override
+    public void addedArtifactToCollection(
+        String  artifactId,
+        String  collectionId,
+        Backend backend
+    ) {
+        log.debug("addedArtifactToCollection");
+    }
+
+    @Override
+    public void removedArtifactFromCollection(
+        String  artifactId,
+        String  collectionId,
+        Backend backend
+    ) {
+        log.debug("removedArtifactFromCollection");
+    }
+
+    @Override
+    public void setCollectionName(
+        String collectionId,
+        String name
+    ) {
+        log.debug("setCollectionName");
+    }
+
+    @Override
+    public void killedCollections(List<String> identifiers, Backend backend) {
+        log.debug("killedCollections");
+    }
+
+    @Override
+    public void killedArtifacts(List<String> identifiers, Backend backend) {
+        log.debug("killedArtifacts");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultCallMeta.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultCallMeta.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,81 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.PreferredLocale;
+
+import java.util.Locale;
+
+/**
+ * Default implementation of CallMeta. It provides a list of
+ * preferred langauages and implements an intersection mechanism
+ * to figure out the best matching language given a list of server
+ * provided languages.
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultCallMeta
+implements   CallMeta
+{
+    /**
+     * The list of preferred languages.
+     */
+    protected PreferredLocale [] languages;
+
+    /**
+     * Default constructor.
+     */
+    public DefaultCallMeta() {
+    }
+
+    /**
+     * Creates new DefaultCallMeta with a given list of languages.
+     * @param languages The list of preferred languages.
+     */
+    public DefaultCallMeta(PreferredLocale [] languages) {
+        this.languages = languages;
+    }
+
+    public PreferredLocale [] getLanguages() {
+        return languages;
+    }
+
+    public Locale getPreferredLocale(Locale [] locales) {
+        if (locales == null || locales.length == 0) {
+            return null;
+        }
+
+        Locale best    = null;
+        float  quality = -Float.MAX_VALUE;
+
+        for (int i = 0; i < locales.length; ++i) {
+            Locale wish         = locales[i];
+            String wishLanguage = wish.getLanguage();
+
+            for (int j = 0; j < languages.length; ++j) {
+                PreferredLocale have        = languages[j];
+                Locale          haveLocale  = have.getLocale();
+                if (haveLocale.getLanguage().equals(wishLanguage)) {
+                    float haveQuality = have.getQuality();
+                    if (haveQuality > quality) {
+                        quality = haveQuality;
+                        best    = wish;
+                    }
+                    break; // Languages should not contain
+                           // same locale twice.
+                }
+            }
+        }
+
+        return best == null
+            ? locales[0]
+            : best;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultCollectionItem.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultCollectionItem.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.CollectionItem;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import org.w3c.dom.Document;
+
+public class DefaultCollectionItem
+implements   CollectionItem
+{
+    protected String artifactIdentifier;
+
+    protected byte [] data;
+
+    protected Document document;
+
+    public DefaultCollectionItem() {
+    }
+
+    public DefaultCollectionItem(String artifactIdentifier, byte [] attribute) {
+        this.artifactIdentifier = artifactIdentifier;
+        this.data               = attribute;
+    }
+
+    public String getArtifactIdentifier() {
+        return artifactIdentifier;
+    }
+
+    public synchronized Document getAttribute() {
+        if (document == null) {
+            if (data != null) {
+                document = XMLUtils.fromByteArray(data, true);
+            }
+        }
+        return document;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultPreferredLocale.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultPreferredLocale.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.PreferredLocale;
+
+import java.util.Locale;
+
+/**
+ * Models a pair of Locale and quality (0.0-1.0) to be used to
+ * find best matching locale between server offerings and clients requests.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultPreferredLocale
+implements   PreferredLocale
+{
+    /**
+     * The locale of this tuple pair.
+     */
+    protected Locale locale;
+    /**
+     * The quality of this tuple pair between 0.0 and 1.0.
+     */
+    protected float  quality;
+
+    /**
+     * Default constructor
+     */
+    public DefaultPreferredLocale() {
+    }
+
+    /**
+     * Constructor to build a pair of given a locale speficied by
+     * string 'lang' and an given 'quality'.
+     * @param lang The name of the locale.
+     * @param quality The quality of the locale.
+     */
+    public DefaultPreferredLocale(String lang, float quality) {
+        locale = new Locale(lang);
+        this.quality = quality;
+    }
+
+    public Locale getLocale() {
+        return locale;
+    }
+
+    public float getQuality() {
+        return quality;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultService.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultService.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.Service;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.ServiceFactory;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+/**
+ * Trivial implementation of an artifact database service. Useful to
+ * be subclassed.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultService
+implements   Service
+{
+    private static Logger logger = Logger.getLogger(DefaultService.class);
+
+    public static class Output implements Service.Output {
+
+        protected Object data;
+        protected String mimeType;
+
+        public Output() {
+        }
+
+        public Output(Object data, String mimeType) {
+            this.data     = data;
+            this.mimeType = mimeType;
+        }
+
+        @Override
+        public Object getData() {
+            return data;
+        }
+
+        @Override
+        public String getMIMEType() {
+            return mimeType;
+        }
+    } // class Output
+
+    @Override
+    public Service.Output process(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        logger.debug("Service.process");
+        return new Output(new byte[0], "application/octet-stream");
+    }
+
+    @Override
+    public void setup(ServiceFactory factory, GlobalContext globalContext) {
+        logger.debug("Service.setup");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultServiceFactory.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultServiceFactory.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,140 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.artifacts.Service;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.ServiceFactory;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * Trivial implementation of the ServiceFactory interface.
+ * Name and an description are configured by the given Node given to
+ * #setup(Document, Node) via the 'name' and 'description' attributes.
+ * The name of the class that provides the concrete serice is configured
+ * by the 'service' attribute.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class DefaultServiceFactory
+implements   ServiceFactory
+{
+    private static Logger logger =
+        Logger.getLogger(DefaultServiceFactory.class);
+
+    /**
+     * XPath to access the name of the service.
+     */
+    public static final String XPATH_NAME        = "@name";
+    /**
+     * XPath to access the description of the service.
+     */
+    public static final String XPATH_DESCRIPTION = "@description";
+    /**
+     * XPath to access the class name of the service to be build by
+     * this factory.
+     */
+    public static final String XPATH_SERVICE     = "@service";
+
+    /**
+     * Default description if no description is given in configuration.
+     */
+    public static final String DEFAULT_DESCRIPTION =
+        "No description available";
+
+    /**
+     * Loaded service class if no class name is given in the configuration.
+     */
+    public static final String DEFAULT_SERVICE =
+        "de.intevation.artifactdatabase.DefaultService";
+
+    /**
+     * The name of the service factory.
+     */
+    protected String name;
+
+    /**
+     * The description of the service factory.
+     */
+    protected String description;
+
+    /**
+     * The loaded class used to build the concrete service.
+     */
+    protected Class  serviceClass;
+
+    /**
+     * Default constructor.
+     */
+    public DefaultServiceFactory() {
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public Service createService(GlobalContext globalContext) {
+        try {
+            Service service = (Service)serviceClass.newInstance();
+
+            service.setup(this, globalContext);
+
+            return service;
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+
+        return null;
+    }
+
+    @Override
+    public void setup(Document config, Node factoryNode) {
+
+        description = Config.getStringXPath(
+            factoryNode, XPATH_DESCRIPTION, DEFAULT_DESCRIPTION);
+
+        name = Config.getStringXPath(
+            factoryNode, XPATH_NAME, toString());
+
+        String service = Config.getStringXPath(
+            factoryNode, XPATH_SERVICE, DEFAULT_SERVICE);
+
+        try {
+            serviceClass = Class.forName(service);
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+
+        if (serviceClass == null) {
+            serviceClass = DefaultService.class;
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultUser.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultUser.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,137 @@
+/*
+ * 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.artifactdatabase;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifacts.User;
+
+
+/**
+ * Trivial implementation of a user. Useful to be subclassed.
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultUser
+implements   User
+{
+    /** The identifier of the user.*/
+    protected String identifier;
+
+    /** The name of the user.*/
+    protected String name;
+
+    /** The account name of the user.*/
+    protected String account;
+
+    /** The role of the user.*/
+    protected Document role;
+
+
+    /**
+     * The default constructor.
+     */
+    public DefaultUser() {
+    }
+
+    public DefaultUser(String identifier) {
+        this.identifier = identifier;
+    }
+
+    /**
+     * A constructor that creates a new user.
+     *
+     * @param identifier The uuid of the user.
+     * @param name The name of the user.
+     * @param account The account name of the user.
+     * @param role The role of the user.
+     */
+    public DefaultUser(String identifier, String name, String account,
+                       Document role) {
+        this.identifier = identifier;
+        this.name       = name;
+        this.role       = role;
+        this.account    = account;
+    }
+
+
+    /**
+     * Returns the identifier of this user.
+     *
+     * @return the identifier of this user.
+     */
+    @Override
+    public String identifier() {
+        return identifier;
+    }
+
+
+    /**
+     * Returns the name of the user.
+     *
+     * @return the name of the user.
+     */
+    @Override
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Set the name of the user.
+     *
+     * @param name The name for this user.
+     */
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * Set the identifier of the user.
+     *
+     * @param identifier The new identifier.
+     */
+    @Override
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+
+    /**
+     * Set the role of the user.
+     *
+     * @param role The new role of the user.
+     */
+    @Override
+    public void setRole(Document role) {
+        this.role = role;
+    }
+
+
+    /**
+     * Returns the role of the user.
+     *
+     * @return the role of the user.
+     */
+    @Override
+    public Document getRole() {
+        return role;
+    }
+
+    /**
+     * Returns the account of the user.
+     *
+     * @return the account name of the user.
+     */
+    @Override
+    public String getAccount() {
+        return account;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultUserFactory.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DefaultUserFactory.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,65 @@
+/*
+ * 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.artifactdatabase;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.User;
+import de.intevation.artifacts.UserFactory;
+
+
+/**
+ * Default implementation of a UserFactory.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultUserFactory
+implements   UserFactory
+{
+    /** The logger that is used in this factory.*/
+    private static Logger logger = Logger.getLogger(DefaultUserFactory.class);
+
+
+    /**
+     * Default constructor.
+     */
+    public DefaultUserFactory() {
+    }
+
+
+    public void setup(Document config, Node factoryNode) {
+        logger.debug("DefaultUserFactory.setup");
+    }
+
+
+    /**
+     * This method creates a new DefaultUser with the given identifier, name and
+     * role.
+     *
+     * @param identifier The identifier for the new user.
+     * @param name The name for the new user.
+     * @param account The name of the new users account.
+     * @param role The role for the new user.
+     * @param context The CallContext.
+     */
+    public User createUser(
+        String   identifier,
+        String   name,
+        String   account,
+        Document role,
+        Object   context)
+    {
+        logger.debug("DefaultUserFactory.createUser: " + name);
+        return new DefaultUser(identifier, name, account, role);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,733 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.artifacts.ArtifactCollectionFactory;
+import de.intevation.artifacts.ArtifactContextFactory;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.Hook;
+import de.intevation.artifacts.ServiceFactory;
+import de.intevation.artifacts.UserFactory;
+
+import de.intevation.artifacts.common.utils.StringUtils;
+
+import de.intevation.artifactdatabase.rest.HTTPServer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Bootstrap facility for the global context and the artifact factories.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class FactoryBootstrap
+{
+    private static Logger logger = Logger.getLogger(FactoryBootstrap.class);
+
+    /**
+     * XPath to figure out the class name of the context factory from
+     * the global configuration.
+     */
+    public static final String CONTEXT_FACTORY =
+        "/artifact-database/factories/context-factory/text()";
+
+    /**
+     * The name of the default context factory.
+     */
+    public static final String DEFAULT_CONTEXT_FACTORY =
+        "de.intevation.artifactdatabase.DefaultArtifactContextFactory";
+
+    /**
+     * XPath to figure out the names of the artifact factories from
+     * the global configuration to be exposed by the artifact database.
+     */
+    public static final String ARTIFACT_FACTORIES =
+        "/artifact-database/factories/artifact-factories/artifact-factory";
+
+    /**
+     * XPath to figure out the names of the service factories from
+     * the global configuration to build the services offered by the
+     * artifact database.
+     */
+    public static final String SERVICE_FACTORIES =
+        "/artifact-database/factories/service-factories/service-factory";
+
+    /**
+     * XPath to figure out the class name of the user factory from global
+     * configuration.
+     */
+    public static final String USER_FACTORY =
+        "/artifact-database/factories/user-factory";
+
+    /**
+     * The name of the default user factory.
+     */
+    public static final String DEFAULT_USER_FACTORY =
+        "de.intevation.artifactdatabase.DefaultUserFactory";
+
+    /**
+     * XPath to figure out the class name of the collection factory from global
+     * configuration.
+     */
+    public static final String COLLECTION_FACTORY =
+        "/artifact-database/factories/collection-factory";
+
+    /**
+     * The name of the default user factory.
+     */
+    public static final String DEFAULT_COLLECTION_FACTORY =
+        "de.intevation.artifactdatabase.DefaultArtifactCollectionFactory";
+
+    /**
+     * XPath to figure out the secret used to sign the artifact exports
+     * made by the artfifact database server.
+     */
+    public static final String EXPORT_SECRET =
+        "/artifact-database/export-secret/text()";
+
+    /**
+     * XPAth that points to a configuration node for a CallContext.Listener.
+     */
+    public static final String CALLCONTEXT_LISTENER =
+        "/artifact-database/callcontext-listener";
+
+    /**
+     * XPath that points to configuration nodes for hooks.
+     */
+    public static final String HOOKS =
+        "/artifact-database/hooks/hook";
+
+    public static final String HTTP_SERVER =
+        "/artifact-database/rest-server/http-server/text()";
+
+    public static final String DEFAULT_HTTP_SERVER =
+        "de.intevation.artifactdatabase.rest.Standalone";
+
+    public static final String LIFETIME_LISTENERS =
+        "/artifact-database/lifetime-listeners/listener";
+
+    public static final String BACKEND_LISTENERS =
+        "/artifact-database/backend-listeners/listener";
+
+    /**
+     * Default export signing secret.
+     * <strong>PLEASE CHANGE THE SECRET VIA THE XPATH EXPORT_SECRET
+     * IN THE CONFIGURATION.</strong>.
+     */
+    public static final String DEFAULT_EXPORT_SECRET =
+        "!!!CHANGE ME! I'M NO SECRET!!!";
+
+    /**
+     * Reference to the global context build by the global context factory.
+     */
+    protected GlobalContext context;
+
+    /**
+     * List of the artifact factories to be exposed by the
+     * artifact database.
+     */
+    protected ArtifactFactory [] artifactFactories;
+
+    /**
+     * List of service factories which creates services that are
+     * exposed by the artifact database.
+     */
+    protected ServiceFactory [] serviceFactories;
+
+    /**
+     * The factory that is used to create and list users.
+     */
+    protected UserFactory userFactory;
+
+    /**
+     * The factory that is used to create new artifact collections.
+     */
+    protected ArtifactCollectionFactory collectionFactory;
+
+    /**
+     * The CallContext.Listener.
+     */
+    protected CallContext.Listener callContextListener;
+
+    protected List<Hook> postFeedHooks;
+
+    protected List<Hook> postAdvanceHooks;
+
+    protected List<Hook> postDescribeHooks;
+
+    protected List<LifetimeListener> lifetimeListeners;
+
+    protected List<BackendListener> backendListeners;
+
+    /**
+     * byte array holding the export signing secret.
+     */
+    protected byte [] exportSecret;
+
+    protected HTTPServer httpServer;
+
+
+    /**
+     * Default constructor
+     */
+    public FactoryBootstrap() {
+    }
+
+    void buildContext() {
+        String className = Config.getStringXPath(
+            CONTEXT_FACTORY, DEFAULT_CONTEXT_FACTORY);
+
+        ArtifactContextFactory factory = null;
+
+        try {
+            Class clazz = Class.forName(className);
+            factory = (ArtifactContextFactory)clazz.newInstance();
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+
+        if (factory == null) {
+            factory = new DefaultArtifactContextFactory();
+        }
+
+        logger.info("Using class '" + factory.getClass().getName()
+            + "' for context creation.");
+
+        context = factory.createArtifactContext(Config.getConfig());
+    }
+
+
+    /**
+     * Scans the global configuration to load the configured collection factory
+     * and sets it up.
+     */
+    protected void loadCollectionFactory() {
+
+        logger.info("loading collection factory.");
+
+        Node factory = Config.getNodeXPath(COLLECTION_FACTORY);
+
+        String className = Config.getStringXPath(
+            factory, "text()", DEFAULT_COLLECTION_FACTORY);
+
+        try {
+            Class clazz       = Class.forName(className);
+            collectionFactory = (ArtifactCollectionFactory) clazz.newInstance();
+
+            collectionFactory.setup(Config.getConfig(), factory);
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+    }
+
+    /**
+     * Scans the global configuration to load the configured
+     * artifact factories and sets them up.
+     */
+    protected void loadArtifactFactories() {
+
+        logger.info("loading artifact factories");
+
+        ArrayList loadedFactories = new ArrayList();
+
+        NodeList nodes = Config.getNodeSetXPath(ARTIFACT_FACTORIES);
+
+        if (nodes == null) {
+            logger.warn("No factories found");
+        }
+
+        Document config = Config.getConfig();
+
+        for (int i = 0, N = nodes != null ? nodes.getLength() : 0; i < N; ++i) {
+            String className = nodes.item(i).getTextContent().trim();
+
+            ArtifactFactory factory = null;
+
+            try {
+                Class clazz = Class.forName(className);
+                factory = (ArtifactFactory)clazz.newInstance();
+            }
+            catch (ClassNotFoundException cnfe) {
+                logger.error(cnfe.getLocalizedMessage(), cnfe);
+            }
+            catch (InstantiationException ie) {
+                logger.error(ie.getLocalizedMessage(), ie);
+            }
+            catch (ClassCastException cce) {
+                logger.error(cce.getLocalizedMessage(), cce);
+            }
+            catch (IllegalAccessException iae) {
+                logger.error(iae.getLocalizedMessage(), iae);
+            }
+
+            if (factory != null) {
+                factory.setup(config, nodes.item(i));
+                loadedFactories.add(factory);
+                logger.info("Registering '"
+                    + factory.getName() + "' as artifact factory.");
+            }
+        }
+
+        artifactFactories = (ArtifactFactory [])loadedFactories.toArray(
+            new ArtifactFactory[loadedFactories.size()]);
+    }
+
+    /**
+     * Scans the global configuration for the configured service factories
+     * and sets them up.
+     */
+    protected void loadServiceFactories() {
+
+        logger.info("loading service factories");
+
+        ArrayList loadedFactories = new ArrayList();
+
+        NodeList nodes = Config.getNodeSetXPath(SERVICE_FACTORIES);
+
+        if (nodes == null) {
+            logger.warn("No factories found");
+        }
+
+        Document config = Config.getConfig();
+
+        for (int i = 0, N = nodes != null ? nodes.getLength() : 0; i < N; ++i) {
+            String className = nodes.item(i).getTextContent().trim();
+
+            ServiceFactory factory = null;
+
+            try {
+                Class clazz = Class.forName(className);
+                factory = (ServiceFactory)clazz.newInstance();
+            }
+            catch (ClassNotFoundException cnfe) {
+                logger.error(cnfe.getLocalizedMessage(), cnfe);
+            }
+            catch (InstantiationException ie) {
+                logger.error(ie.getLocalizedMessage(), ie);
+            }
+            catch (ClassCastException cce) {
+                logger.error(cce.getLocalizedMessage(), cce);
+            }
+            catch (IllegalAccessException iae) {
+                logger.error(iae.getLocalizedMessage(), iae);
+            }
+
+            if (factory != null) {
+                factory.setup(config, nodes.item(i));
+                loadedFactories.add(factory);
+                logger.info( "Registering '" + factory.getName()
+                    + "' as service factory.");
+            }
+        }
+
+        serviceFactories = (ServiceFactory [])loadedFactories.toArray(
+            new ServiceFactory[loadedFactories.size()]);
+    }
+
+
+    /**
+     * Scans the global configuration for the configured user factory.
+     */
+    protected void loadUserFactory() {
+        logger.info("loading user factory");
+
+        Node factory = Config.getNodeXPath(USER_FACTORY);
+
+        String className = Config.getStringXPath(
+            factory, "text()", DEFAULT_USER_FACTORY);
+
+        try {
+            Class clazz = Class.forName(className);
+            userFactory = (UserFactory) clazz.newInstance();
+
+            userFactory.setup(Config.getConfig(), factory);
+        }
+        catch (ClassNotFoundException cnfe) {
+                logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+    }
+
+
+    protected void loadCallContextListener() {
+        logger.info("loading CallContext.Listener");
+
+        Node listener = Config.getNodeXPath(CALLCONTEXT_LISTENER);
+
+        if (listener == null) {
+            return;
+        }
+
+        String className = Config.getStringXPath(listener, "text()");
+
+        try {
+            Class clazz         = Class.forName(className);
+            callContextListener = (CallContext.Listener) clazz.newInstance();
+
+            callContextListener.setup(Config.getConfig(), listener);
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+    }
+
+    protected void loadHTTPServer() {
+        logger.info("loading HTTPServer");
+
+        String className = Config.getStringXPath(
+            HTTP_SERVER, DEFAULT_HTTP_SERVER);
+
+        logger.info("using HTTP server: " + className);
+
+        try {
+            Class clazz = Class.forName(className);
+            httpServer  = (HTTPServer)clazz.newInstance();
+
+            httpServer.setup(Config.getConfig());
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+    }
+
+    protected void loadLifetimeListeners() {
+        logger.info("loading lifetime listeners");
+
+        NodeList nodes = Config.getNodeSetXPath(LIFETIME_LISTENERS);
+
+        if (nodes == null) {
+            logger.debug("no lifetime listeners configure");
+            return;
+        }
+
+        List<LifetimeListener> ltls = new ArrayList<LifetimeListener>();
+
+        for (int i = 0, N = nodes.getLength(); i < N; ++i) {
+            Node node = nodes.item(i);
+            String className = node.getTextContent();
+            if (className == null
+            || (className = className.trim()).length() == 0) {
+                continue;
+            }
+            try {
+                Class clazz = Class.forName(className);
+                LifetimeListener listener =
+                    (LifetimeListener)clazz.newInstance();
+
+                listener.setup(Config.getConfig());
+
+                ltls.add(listener);
+            }
+            catch (ClassNotFoundException cnfe) {
+                logger.error(cnfe.getLocalizedMessage(), cnfe);
+            }
+            catch (InstantiationException ie) {
+                logger.error(ie.getLocalizedMessage(), ie);
+            }
+            catch (ClassCastException cce) {
+                logger.error(cce.getLocalizedMessage(), cce);
+            }
+            catch (IllegalAccessException iae) {
+                logger.error(iae.getLocalizedMessage(), iae);
+            }
+        }
+
+        lifetimeListeners = ltls;
+    }
+
+    protected void loadBackendListeners() {
+        logger.info("loading backend listeners");
+
+        NodeList nodes = Config.getNodeSetXPath(BACKEND_LISTENERS);
+
+        if (nodes == null) {
+            logger.debug("no backend listeners configure");
+            return;
+        }
+
+        List<BackendListener> bls = new ArrayList<BackendListener>();
+
+        for (int i = 0, N = nodes.getLength(); i < N; ++i) {
+            Node node = nodes.item(i);
+            String className = node.getTextContent();
+            if (className == null
+            || (className = className.trim()).length() == 0) {
+                continue;
+            }
+            try {
+                Class clazz = Class.forName(className);
+                BackendListener listener =
+                    (BackendListener)clazz.newInstance();
+
+                bls.add(listener);
+            }
+            catch (ClassNotFoundException cnfe) {
+                logger.error(cnfe.getLocalizedMessage(), cnfe);
+            }
+            catch (InstantiationException ie) {
+                logger.error(ie.getLocalizedMessage(), ie);
+            }
+            catch (ClassCastException cce) {
+                logger.error(cce.getLocalizedMessage(), cce);
+            }
+            catch (IllegalAccessException iae) {
+                logger.error(iae.getLocalizedMessage(), iae);
+            }
+        }
+
+        backendListeners = bls;
+    }
+
+    protected void loadHooks() {
+        logger.info("loading hooks");
+
+        postFeedHooks     = new ArrayList<Hook>();
+        postAdvanceHooks  = new ArrayList<Hook>();
+        postDescribeHooks = new ArrayList<Hook>();
+
+        NodeList nodes = Config.getNodeSetXPath(HOOKS);
+
+        if (nodes == null) {
+            logger.info("No hooks found");
+            return;
+        }
+
+        for (int i = 0, len = nodes.getLength(); i < len; i++) {
+            Node   cfg     = nodes.item(i);
+            String applies = Config.getStringXPath(cfg, "@applies");
+
+            if (applies == null || applies.length() == 0) {
+                continue;
+            }
+
+            Hook     hook  = loadHook(cfg);
+            String[] apply = applies.split(",");
+
+            for (String a: apply) {
+                a = a.trim().toLowerCase();
+
+                if (a.equals("post-feed")) {
+                    postFeedHooks.add(hook);
+                }
+                else if (a.equals("post-advance")) {
+                    postAdvanceHooks.add(hook);
+                }
+                else if (a.equals("post-describe")) {
+                    postDescribeHooks.add(hook);
+                }
+            }
+        }
+    }
+
+    protected Hook loadHook(Node hookCfg) {
+        if (hookCfg == null) {
+            return null;
+        }
+
+        Hook hook = null;
+
+        String className = Config.getStringXPath(hookCfg, "@class");
+
+        try {
+            Class clazz = Class.forName(className);
+            hook        = (Hook) clazz.newInstance();
+
+            hook.setup(hookCfg);
+        }
+        catch (ClassNotFoundException cnfe) {
+            logger.error(cnfe.getLocalizedMessage(), cnfe);
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie.getLocalizedMessage(), ie);
+        }
+        catch (ClassCastException cce) {
+            logger.error(cce.getLocalizedMessage(), cce);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae.getLocalizedMessage(), iae);
+        }
+
+        return hook;
+    }
+
+    /**
+     * Fetches the export signing secret from the global configuration.
+     * If none is found if defaults to the DEFAULT_EXORT_SECRET which
+     * is insecure.
+     */
+    protected void setupExportSecret() {
+        String secret = Config.getStringXPath(EXPORT_SECRET);
+
+        if (secret == null) {
+            logger.warn("NO EXPORT SECRET SET! USING INSECURE DEFAULT!");
+            secret = DEFAULT_EXPORT_SECRET;
+        }
+
+        exportSecret = StringUtils.getUTF8Bytes(secret);
+    }
+
+    /**
+     * Loads all the dynamic classes configured by the global configuration.
+     */
+    public void boot() {
+        setupExportSecret();
+        buildContext();
+        loadCollectionFactory();
+        loadArtifactFactories();
+        loadServiceFactories();
+        loadUserFactory();
+        loadCallContextListener();
+        loadHTTPServer();
+        loadHooks();
+        loadLifetimeListeners();
+        loadBackendListeners();
+    }
+
+    /**
+     * Returns the artifact collection factory.
+     *
+     * @return the artifact collection factory.
+     */
+    public ArtifactCollectionFactory getArtifactCollectionFactory() {
+        return collectionFactory;
+    }
+
+    /**
+     * Returns the list of ready to use artifact factories.
+     * @return The list of artifact factories.
+     */
+    public ArtifactFactory [] getArtifactFactories() {
+        return artifactFactories;
+    }
+
+    /**
+     * Returns the ready to use service factories.
+     * @return The list of service factories.
+     */
+    public ServiceFactory [] getServiceFactories() {
+        return serviceFactories;
+    }
+
+    /**
+     * Returns the user factory.
+     *
+     * @return the user factory.
+     */
+    public UserFactory getUserFactory() {
+        return userFactory;
+    }
+
+    /**
+     * Returns the global context created by the global context factory.
+     * @return The global context.
+     */
+    public GlobalContext getContext() {
+        return context;
+    }
+
+    /**
+     * Returns the signing secret to be used when ex- and importing
+     * artifacts from and into the artifact database.
+     * @return the byte array containg the signing secret.
+     */
+    public byte [] getExportSecret() {
+        return exportSecret;
+    }
+
+    /**
+     * Returns a CallContext.Listener if configured or null.
+     *
+     * @return a CallContext.Listener.
+     */
+    public CallContext.Listener getCallContextListener() {
+        return callContextListener;
+    }
+
+    public List<Hook> getPostFeedHooks() {
+        return postFeedHooks;
+    }
+
+    public List<Hook> getPostAdvanceHooks() {
+        return postAdvanceHooks;
+    }
+
+    public List<Hook> getPostDescribeHooks() {
+        return postDescribeHooks;
+    }
+
+    public HTTPServer getHTTPServer() {
+        return httpServer;
+    }
+
+    public List<LifetimeListener> getLifetimeListeners() {
+        return lifetimeListeners;
+    }
+
+    public List<BackendListener> getBackendListeners() {
+        return backendListeners;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/LazyBackendUser.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/LazyBackendUser.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,81 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.User;
+import de.intevation.artifacts.UserFactory;
+
+import org.w3c.dom.Document;
+
+public class LazyBackendUser
+implements   User
+{
+    protected UserFactory factory;
+    protected Backend     backend;
+    protected String      identifier;
+    protected User        user;
+    protected Object      context;
+
+    public LazyBackendUser(
+        String      identifier,
+        UserFactory factory,
+        Backend     backend,
+        Object      context
+    ) {
+        this.identifier = identifier;
+        this.factory    = factory;
+        this.backend    = backend;
+        this.context    = context;
+    }
+
+    protected User getUser() {
+        if (user == null) {
+            user = backend.getUser(identifier, factory, context);
+            if (user == null) {
+                throw new IllegalStateException("loading user failed");
+            }
+        }
+        return user;
+    }
+
+    @Override
+    public String identifier() {
+        return getUser().identifier();
+    }
+
+    @Override
+    public String getName() {
+        return getUser().getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getUser().setName(name);
+    }
+
+    @Override
+    public void setIdentifier(String identifier) {
+        getUser().setIdentifier(identifier);
+    }
+
+    @Override
+    public Document getRole() {
+        return getUser().getRole();
+    }
+
+    @Override
+    public void setRole(Document document) {
+        getUser().setRole(document);
+    }
+
+    @Override
+    public String getAccount() {
+        return getUser().getAccount();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/LifetimeListener.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/LifetimeListener.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,15 @@
+package de.intevation.artifactdatabase;
+
+import de.intevation.artifacts.GlobalContext;
+
+import org.w3c.dom.Document;
+
+public interface LifetimeListener
+{
+    void setup(Document document);
+
+    void systemUp(GlobalContext globalContext);
+
+    void systemDown(GlobalContext globalContext);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/ProtocolUtils.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ProtocolUtils.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,225 @@
+/*
+ * 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.artifactdatabase;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.ArtifactNamespaceContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.Output;
+import de.intevation.artifactdatabase.state.State;
+
+
+/**
+ * This class provides methods that help creating the artifact protocol
+ * documents describe, feed, advance and out.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class ProtocolUtils {
+
+    /**
+     * It should not be necessary to create instances of this class.
+     */
+    private ProtocolUtils() {}
+
+
+    /**
+     * This method creates a node that might be used for the artifact protocol.
+     *
+     * @param creator The ElementCreator that is used to create the node.
+     * @param nodeName The node name.
+     * @param attrName The names of optional attributes.
+     * @param value The values for the optional attributes.
+     *
+     * @return the created node.
+     */
+    public static Element createArtNode(
+        XMLUtils.ElementCreator creator,
+        String nodeName, String[] attrName, String[] value)
+    {
+        Element typeNode = creator.create(nodeName);
+
+        if (attrName != null && value != null) {
+            for (int i = 0; i < attrName.length; i++) {
+                if (i < value.length) {
+                    creator.addAttr(typeNode, attrName[i], value[i], true);
+                }
+                else {
+                    break;
+                }
+            }
+        }
+
+        return typeNode;
+    }
+
+
+    /**
+     * This method creates the root node for all artifact protocol documents.
+     *
+     * @param creator The ElementCreator used to create new elements.
+     *
+     * @return the root node for the artifact protocol document.
+     */
+    public static Element createRootNode(XMLUtils.ElementCreator creator) {
+        return createArtNode(creator, "result", null, null);
+    }
+
+
+    /**
+     * This method appends the three necessary nodes <i>type</i>, <i>uuid</i>
+     * and <i>hash</i> of the describe document to <i>root</i> node.
+     *
+     * @param creator The ElementCreator that is used to create new nodes.
+     * @param root The root node of the describe document.
+     * @param uuid The UUID of the artifact.
+     * @param hash The hash if the artifact.
+     */
+    public static void appendDescribeHeader(
+        XMLUtils.ElementCreator creator, Element root, String uuid, String hash)
+    {
+        root.appendChild(createArtNode(
+            creator,
+            "type",
+            new String[] {"name"},
+            new String[] {"describe"}));
+
+        root.appendChild(createArtNode(
+            creator,
+            "uuid",
+            new String[] {"value"},
+            new String[] {uuid}));
+
+        root.appendChild(createArtNode(
+            creator,
+            "hash",
+            new String[] {"value"},
+            new String[] {hash}));
+    }
+
+
+    /**
+     * This method appends a node that describes the current state to
+     * <i>root</i>.
+     *
+     * @param creator The ElementCreator used to create new elements.
+     * @param root The parent node for new elements.
+     * @param state The state to be appended.
+     */
+    public static void appendState(
+        XMLUtils.ElementCreator creator, Element root, State state)
+    {
+        root.appendChild(createArtNode(
+            creator, "state",
+            new String[] { "description", "name" },
+            new String[] { state.getDescription(), state.getID() }));
+    }
+
+
+    /**
+     * This method appends a node with reachable states to <i>root</i>.
+     *
+     * @param creator The ElementCreator used to create new elements.
+     * @param root The parent node for new elements.
+     * @param states The reachable states to be appended.
+     */
+    public static void appendReachableStates(
+        XMLUtils.ElementCreator creator,
+        Element                 root,
+        List<State>             states)
+    {
+        Element reachable = createArtNode(
+            creator, "reachable-states", null, null);
+
+        for (State s: states) {
+            appendState(creator, reachable, s);
+        }
+
+        root.appendChild(reachable);
+    }
+
+
+    /**
+     * This method appends a node for each Output in the <i>outputs</i> list to
+     * <i>out</i>. Note: an output node includes its provided facets!
+     *
+     * @param doc The document to which to add new elements.
+     * @param out The parent node for new elements.
+     * @param outputs The list of reachable outputs.
+     */
+    public static void appendOutputModes(
+        Document     doc,
+        Element      out,
+        List<Output> outputs)
+    {
+        ElementCreator creator = new ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        for (Output o: outputs) {
+            Element newOut = createArtNode(
+                creator,
+                "output",
+                new String[] {"name", "description", "mime-type", "type"},
+                new String[] {
+                    o.getName(),
+                    o.getDescription(),
+                    o.getMimeType(),
+                    o.getType() });
+
+            Element facets = createArtNode(creator, "facets", null, null);
+            appendFacets(doc, facets, o.getFacets());
+
+            newOut.appendChild(facets);
+            out.appendChild(newOut);
+        }
+    }
+
+
+    /**
+     * This method appends a node for each Facet in the <i>facets</i> list to
+     * <i>facet</i>.
+     *
+     * @param doc The document to wich to add new elements.
+     * @param facet The root node for new elements.
+     * @param facets The list of facets.
+     */
+    public static void appendFacets(
+        Document    doc,
+        Element     facet,
+        List<Facet> facets)
+    {
+        if (facets == null || facets.size() == 0) {
+            return;
+        }
+
+        ElementCreator creator = new ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        for (Facet f: facets) {
+            Node node = f.toXML(doc);
+
+            if (node != null) {
+                facet.appendChild(node);
+            }
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/ProxyArtifact.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ProxyArtifact.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,186 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+/**
+ * The proxy artifact is a wrapper around another artifact. It simply forwards
+ * the interface calls to this underlaying artifact.
+ * The reason for using proxy artifacts is enable the workflow to exchange
+ * artifacts at any time by something else without losing the concrete
+ * artifact. From the outside it always looks like there is only one
+ * distinct artifact.<br>
+ *
+ * An inner artifact is able to replace itself by indirectly hand over
+ * the replacement via the call context to the proxy artifact.<br>
+ * To do so the proxied artifact has to call
+ * <code>callContext.getContextValue(EPLACE_PROXY, replacement);</code>.
+ * After the current call (describe, feed, advance and out) of the proxied
+ * artifact is finished the proxy artifact replaces the former proxied artifact
+ * with the replacement.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class ProxyArtifact
+extends      DefaultArtifact
+{
+    /**
+     * Key to signal that the proxied artifact should be replaced.
+     */
+    public static final Object REPLACE_PROXY = new Object();
+
+    private static Logger logger = Logger.getLogger(ProxyArtifact.class);
+
+    /**
+     * The proxied artifact.
+     */
+    protected Artifact proxied;
+
+    /**
+     * Default constructor.
+     */
+    public ProxyArtifact() {
+    }
+
+    /**
+     * Constructor to create a new proxy artifact around a given artifact.
+     * @param proxied The artifact to be proxied.
+     */
+    public ProxyArtifact(Artifact proxied) {
+        this.proxied = proxied;
+    }
+
+    /**
+     * The currently proxied artifact.
+     * @return The proxied artifact.
+     */
+    public Artifact getProxied() {
+        return proxied;
+    }
+
+    /**
+     * Explicitly set the proxied artifacts.
+     * @param proxied
+     */
+    public void setProxied(Artifact proxied) {
+        this.proxied = proxied;
+    }
+
+    @Override
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+
+        if (proxied != null)
+            proxied.setIdentifier(identifier);
+    }
+
+    /**
+     * Method to check if the current proxied artifact should be replaced
+     * by a new one coming from the call context.
+     * @param callContext
+     */
+    protected void checkReplacement(CallContext callContext) {
+        Object replacement = callContext.getContextValue(REPLACE_PROXY);
+        if (replacement instanceof Artifact) {
+            setProxied((Artifact)replacement);
+        }
+    }
+
+    @Override
+    public String hash() {
+        return proxied != null
+            ? proxied.hash()
+            : super.hash();
+    }
+
+    @Override
+    public Document describe(Document data, CallContext context) {
+        try {
+            return proxied != null
+                ? proxied.describe(data, context)
+                : super.describe(data, context);
+        }
+        finally {
+            checkReplacement(context);
+        }
+    }
+
+    @Override
+    public Document advance(Document target, CallContext context) {
+        try {
+            return proxied != null
+                ? proxied.advance(target, context)
+                : super.advance(target, context);
+        }
+        finally {
+            checkReplacement(context);
+        }
+    }
+
+    @Override
+    public Document feed(Document target, CallContext context) {
+        try {
+            return proxied != null
+                ? proxied.feed(target, context)
+                : super.feed(target, context);
+        }
+        finally {
+            checkReplacement(context);
+        }
+    }
+
+    @Override
+    public void out(
+        Document     format,
+        OutputStream out,
+        CallContext  context
+    )
+    throws IOException
+    {
+        try {
+            if (proxied != null) {
+                proxied.out(format, out, context);
+            }
+            else {
+                super.out(format, out, context);
+            }
+        }
+        finally {
+            checkReplacement(context);
+        }
+    }
+
+    @Override
+    public void endOfLife(Object context) {
+        if (proxied != null) {
+            proxied.endOfLife(context);
+        }
+        else {
+            super.endOfLife(context);
+        }
+    }
+
+    @Override
+    public void cleanup(Object context) {
+        if (proxied != null)
+            proxied.cleanup(context);
+        else
+            super.cleanup(context);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/XMLService.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/XMLService.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,51 @@
+/*
+ * 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.artifactdatabase;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.Service;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+/**
+ * Trivial implementation of an artifact database service. Useful to
+ * be subclassed.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class XMLService
+extends      DefaultService
+{
+    private static Logger logger = Logger.getLogger(XMLService.class);
+
+    @Override
+    public Service.Output process(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        return new Output(
+            processXML(data, globalContext, callMeta),
+            "application/xml");
+    }
+
+    public Document processXML(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        return XMLUtils.newDocument();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/data/DefaultStateData.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/data/DefaultStateData.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,131 @@
+/*
+ * 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.artifactdatabase.data;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultStateData implements StateData {
+
+    /** The name of the data. */
+    protected String name;
+
+    /** The description of the data. */
+    protected String description;
+
+    /** The type of the data. */
+    protected String type;
+
+    /** The value. */
+    protected Object value;
+
+    public DefaultStateData() {
+    }
+
+    /**
+     * The default constructor. It creates empty StateData objects with no
+     * value.
+     *
+     * @param name The name.
+     * @param description The description.
+     * @param type The type.
+     */
+    public DefaultStateData(String name, String description, String type) {
+        this.name        = name;
+        this.description = description;
+        this.type        = type;
+    }
+
+    public void set(StateData other) {
+        name        = other.getName();
+        description = other.getDescription();
+        type        = other.getType();
+        value       = other.getValue();
+    }
+
+
+    /**
+     * A constructor that takes the name of the data, its value and the
+     * describing parameters description and type.
+     *
+     * @param name The name of the data item.
+     * @param description The description.
+     * @param type The type.
+     * @param value The value of the data item.
+     */
+    public DefaultStateData(
+        String name,
+        String description,
+        String type,
+        String value)
+    {
+        this.name        = name;
+        this.description = description;
+        this.type        = type;
+        this.value       = value;
+    }
+
+
+    /**
+     * Returns the name of the data object.
+     *
+     * @return the name.
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Returns the description of the data object.
+     *
+     * @return the description of the data object.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the data object as string.
+     *
+     * @return the type as string.
+     */
+    public String getType() {
+        return type;
+    }
+
+
+    /**
+     * Returns the value of the data object.
+     *
+     * @return the value.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+
+    /**
+     * Set the value of this data object.
+     *
+     * @param value The new value for this data object.
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    @Override
+    public StateData deepCopy() {
+        DefaultStateData copy = new DefaultStateData();
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/data/StateData.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/data/StateData.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.artifactdatabase.data;
+
+import java.io.Serializable;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface StateData extends Serializable {
+
+    /**
+     * Returns the name of the data object.
+     *
+     * @return the name.
+     */
+    public String getName();
+
+
+    /**
+     * Returns the description of the data object.
+     *
+     * @return the description of the data object.
+     */
+    public String getDescription();
+
+
+    /**
+     * Returns the type of the data object as string.
+     *
+     * @return the type as string.
+     */
+    public String getType();
+
+
+    /**
+     * Returns the value of the data object.
+     *
+     * @return the value.
+     */
+    public Object getValue();
+
+
+    /**
+     * Set the value of this data object.
+     *
+     * @param value The new value for this data object.
+     */
+    public void setValue(Object value);
+
+    public StateData deepCopy();
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/DBConnection.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/DBConnection.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,121 @@
+package de.intevation.artifactdatabase.db;
+
+import javax.sql.DataSource;
+
+import java.io.File;
+
+import org.apache.commons.pool.ObjectPool;
+
+import org.apache.commons.pool.impl.GenericObjectPool;
+
+import org.apache.commons.dbcp.DriverManagerConnectionFactory;
+import org.apache.commons.dbcp.PoolableConnectionFactory;
+import org.apache.commons.dbcp.PoolingDataSource;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import org.apache.log4j.Logger;
+
+public class DBConnection
+{
+    private static Logger log = Logger.getLogger(DBConnection.class);
+
+    public static final String DEFAULT_DRIVER        = "org.h2.Driver";
+    public static final String DEFAULT_USER          = "";
+    public static final String DEFAULT_PASSWORD      = "";
+    public static final String DEFAULT_DATABASE_FILE = "artifacts.db";
+    public static final String DEFAULT_URL           = getDefaultURL();
+
+    public static final String getDefaultURL() {
+        File configDir = Config.getConfigDirectory();
+        File databaseFile = new File(configDir, DEFAULT_DATABASE_FILE);
+        return "jdbc:h2:" + databaseFile;
+    }
+
+    protected DataSource dataSource;
+
+    protected String driver;
+    protected String url;
+    protected String user;
+    protected String password;
+
+    public DBConnection() {
+    }
+
+    public DBConnection(
+        String driver,
+        String url,
+        String user,
+        String password
+    ) {
+        this.driver   = driver;
+        this.url      = url;
+        this.user     = user;
+        this.password = password;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getDriver() {
+        return driver;
+    }
+
+    public void setDriver(String driver) {
+        this.driver = driver;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public synchronized DataSource getDataSource() {
+        if (dataSource == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("create new datasource:");
+                log.debug(" driver: " + driver);
+                log.debug(" url   : " + url);
+                log.debug(" user  : " + user);
+            }
+
+            try {
+                synchronized (DBConnection.class) {
+                    Class.forName(driver);
+                }
+            }
+            catch (ClassNotFoundException cnfe) {
+                log.error("cannot load driver", cnfe);
+                return null;
+            }
+
+            DriverManagerConnectionFactory dmcf =
+                new DriverManagerConnectionFactory(url, user, password);
+
+            ObjectPool cp = new GenericObjectPool();
+
+            PoolableConnectionFactory pcf = new PoolableConnectionFactory(
+                dmcf, cp, null, null, false, false);
+
+            dataSource = new PoolingDataSource(cp);
+        }
+        return dataSource;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQL.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQL.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,114 @@
+package de.intevation.artifactdatabase.db;
+
+import java.util.Properties;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.log4j.Logger;
+
+public class SQL {
+
+    private static Logger logger = Logger.getLogger(SQL.class);
+
+    protected Properties statements;
+
+    public SQL() {
+    }
+
+    public SQL(String driver) {
+        this(SQL.class, driver);
+    }
+
+    public SQL(Class clazz, String driver) {
+        this(clazz, "/sql", driver);
+    }
+
+    public SQL(Class clazz, String resourcePath, String driver) {
+        statements = loadStatements(clazz, resourcePath, driver);
+    }
+
+    public static final String driverToProperties(String driver) {
+        return driver.replace('.', '-').toLowerCase() + ".properties";
+    }
+
+    /**
+     * Returns key/value pairs of SQL statements for the used database
+     * backend.
+     * The concrete set of SQL statements is determined by the
+     * used JDBC database driver which is configured in conf.xml.
+     * The class name of the driver is transformed by replacing
+     * all '.' with '_' and lower case the resulting string.
+     * The transformed string is used to load a properties file
+     * in '/sql/' which should contain the statements.
+     * Example:<br>
+     * <code>org.postgresql.Driver</code> results in loading of
+     * <code>/sql/org-postgresql-driver.properties</code>.
+     * @return The key/value pairs of SQL statements.
+     */
+    protected Properties loadStatements(
+        Class  clazz,
+        String resourcePath,
+        String driver
+    ) {
+        logger.debug("loadStatements");
+
+        Properties properties = new Properties();
+
+        String resDriver = driverToProperties(driver);
+
+        InputStream in = null;
+        try {
+            String res = resourcePath + "/" + resDriver;
+
+            in = clazz.getResourceAsStream(res);
+
+            if (in == null) {
+                logger.warn("No SQL file for driver '" + driver + "' found.");
+                resDriver = driverToProperties(DBConnection.DEFAULT_DRIVER);
+                res = resourcePath + "/" + resDriver;
+
+                in = clazz.getResourceAsStream(res);
+                if (in == null) {
+                    logger.error("No SQL file for driver '" +
+                        DBConnection.DEFAULT_DRIVER + "' found.");
+                }
+            }
+            else {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("found resource: " + res);
+                }
+            }
+
+            if (in != null) {
+                properties.load(in);
+            }
+        }
+        catch (IOException ioe) {
+            logger.error(ioe);
+        }
+
+        return properties;
+    }
+
+    public String get(String key) {
+        boolean debug = logger.isDebugEnabled();
+        if (debug) {
+            logger.debug("looking for SQL " + key);
+            logger.debug("statements != null: " + (statements != null));
+        }
+
+        String sql = statements.getProperty(key);
+
+        if (sql == null) {
+            logger.error("cannot find SQL for key '" + key + "'");
+        }
+
+        if (debug) {
+            logger.debug("-> '" + sql + "'");
+        }
+
+        return sql;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQLExecutor.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQLExecutor.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,111 @@
+package de.intevation.artifactdatabase.db;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.apache.log4j.Logger;
+
+public class SQLExecutor
+{
+    private static Logger logger = Logger.getLogger(SQLExecutor.class);
+
+    public class Instance {
+
+        public Connection        conn;
+        public PreparedStatement stmnt;
+        public ResultSet         result;
+
+        public Instance() {
+        }
+
+        public void reset() throws SQLException {
+            if (result != null) {
+                result.close();
+                result = null;
+            }
+            if (stmnt != null) {
+                result = null;
+                stmnt.close();
+            }
+        }
+
+        public PreparedStatement prepareStatement(String query)
+        throws SQLException {
+            return stmnt = conn.prepareStatement(query);
+        }
+
+        public void close() {
+            if (result != null) {
+                try { result.close(); }
+                catch (SQLException sqle) {}
+            }
+            if (stmnt != null) {
+                try { stmnt.close(); }
+                catch (SQLException sqle) {}
+            }
+            if (conn != null) {
+                try { conn.close(); }
+                catch (SQLException sqle) {}
+            }
+        }
+
+        public boolean runWrite() {
+            DataSource dataSource = dbConnection.getDataSource();
+            try {
+                conn = dataSource.getConnection();
+                try {
+                    conn.setAutoCommit(false);
+                    return doIt();
+                }
+                catch (SQLException sqle) {
+                    conn.rollback();
+                    throw sqle;
+                }
+            }
+            catch (SQLException sqle) {
+                logger.error(sqle.getLocalizedMessage(), sqle);
+            }
+            finally {
+                close();
+            }
+            return false;
+        }
+
+        public boolean runRead() {
+            DataSource dataSource = dbConnection.getDataSource();
+            try {
+                conn = dataSource.getConnection();
+                return doIt();
+            }
+            catch (SQLException sqle) {
+                logger.error(sqle.getLocalizedMessage(), sqle);
+            }
+            finally {
+                close();
+            }
+            return false;
+        }
+
+        public boolean doIt() throws SQLException {
+            return true;
+        }
+    } // class Instance
+
+    protected DBConnection dbConnection;
+
+    public SQLExecutor() {
+    }
+
+    public SQLExecutor(DBConnection dbConnection) {
+        this.dbConnection = dbConnection;
+    }
+
+    public DBConnection getDBConnection() {
+        return dbConnection;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/h2/CollectionAccessUpdateTrigger.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/h2/CollectionAccessUpdateTrigger.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,63 @@
+package de.intevation.artifactdatabase.h2;
+
+import org.h2.api.Trigger;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+
+import de.intevation.artifactdatabase.DBConfig;
+
+import de.intevation.artifactdatabase.db.SQL;
+
+import org.apache.log4j.Logger;
+
+public class CollectionAccessUpdateTrigger
+implements   Trigger
+{
+    private static Logger logger =
+        Logger.getLogger(CollectionAccessUpdateTrigger.class);
+
+    public String COLLECTIONS_TOUCH_TRIGGER_FUNCTION;
+
+    public void init(
+        Connection conn,
+        String     schemaName,
+        String     triggerName,
+        String     tableName,
+        boolean    before,
+        int        type
+    )
+    throws SQLException {
+        logger.debug("CollectionAccessUpdateTrigger.init");
+        setupSQL(DBConfig.getInstance().getSQL());
+    }
+
+    protected void setupSQL(SQL sql) {
+        COLLECTIONS_TOUCH_TRIGGER_FUNCTION =
+            sql.get("collections.touch.trigger.function");
+    }
+
+    public void fire(
+        Connection conn,
+        Object []  oldRow,
+        Object []  newRow
+    )
+    throws SQLException {
+        logger.debug("CollectionAccessUpdateTrigger.fire");
+        PreparedStatement stmnt = conn.prepareStatement(
+            COLLECTIONS_TOUCH_TRIGGER_FUNCTION);
+        stmnt.setObject(1, newRow[0]);
+        stmnt.execute();
+        stmnt.close();
+    }
+
+    public void close() throws SQLException {
+        logger.debug("CollectionAccessUpdateTrigger.close");
+    }
+
+    public void remove() throws SQLException {
+        logger.debug("CollectionAccessUpdateTrigger.remove");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/package.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/package.html	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+</head>
+<body>
+The reference implementation of an artifact database. It starts
+an HTTP server and publishes the interface of the artifact database
+via REST.
+</body>
+</html>
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ArtifactOutResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ArtifactOutResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.CallMeta;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Request;
+
+import org.w3c.dom.Document;
+
+/**
+ * Resource to serve the out()-outputs of artifacts.
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class ArtifactOutResource
+extends      BaseOutResource
+{
+    /**
+     * server URL where to find the resource.
+     */
+    public static final String PATH = "/artifact/{uuid}/{type}";
+
+    private static Logger logger = Logger.getLogger(ArtifactOutResource.class);
+
+
+    /**
+     * Returns the identifier of the collection.
+     *
+     * @return the identifier of the collection.
+     */
+    protected String getIdentifier() {
+        Request request = getRequest();
+
+        return (String) request.getAttributes().get("uuid");
+    }
+
+
+    protected String getType() {
+        Request request = getRequest();
+
+        return (String) request.getAttributes().get("type");
+    }
+
+
+    /**
+     * Call the ArtifactDatabase.out method.
+     */
+    protected ArtifactDatabase.DeferredOutput doOut(
+        String           identifier,
+        String           type,
+        Document         input,
+        ArtifactDatabase db,
+        CallMeta         meta)
+    throws ArtifactDatabaseException
+    {
+        logger.debug("ArtifactOutResource.doOut");
+
+        return db.out(identifier, type, input, meta);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ArtifactResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ArtifactResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,204 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Request;
+import org.restlet.Response;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+
+import org.restlet.resource.ResourceException;
+
+import org.w3c.dom.Document;
+
+/**
+ * Resource to expose the core artifact methods
+ * (describe, feed and advance) via REST.
+ *
+ * <ul>
+ * <li>describe() is modelled via GET.</li>
+ * <li>advance() and feed() are modelled via POST.</li>
+ * </ul>
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class ArtifactResource
+extends      BaseResource
+{
+    private static Logger logger = Logger.getLogger(ArtifactResource.class);
+
+    /**
+     * XPath to figure out the type of action (feed, advance) via the
+     * incoming POST request.
+     */
+    public static final String XPATH_ACTION = "/art:action/art:type/@name";
+
+    /**
+     * server URL where to reach the resource.
+     */
+    public static final String PATH = "/artifact/{uuid}";
+
+    /**
+     * Error message if no action was given.
+     */
+    public static final String NO_ACTION_MESSAGE      = "no action given";
+
+    /**
+     * Error message if a unknown action was given.
+     */
+    public static final String NO_SUCH_ACTION_MESSAGE = "no such action";
+
+    /**
+     * Error message if the requested artifact was not found in
+     * the artifact database.
+     */
+    public static final String NO_ARTIFACT_FOUND = "Artifact not found";
+
+    /**
+     * Action name 'advance'.
+     */
+    public static final String ADVANCE  = "advance";
+    /**
+     * Action name 'feed'.
+     */
+    public static final String FEED     = "feed";
+    /**
+     * Action name 'describe'.
+     */
+    public static final String DESCRIBE = "describe";
+
+    @Override
+    protected Representation innerGet()
+    throws                   ResourceException
+    {
+        Request request = getRequest();
+
+        String identifier = (String)request.getAttributes().get("uuid");
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("looking for artifact id '" + identifier + "'");
+        }
+
+        ArtifactDatabase db = (ArtifactDatabase)getContext()
+            .getAttributes().get("database");
+
+        try {
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.describe(identifier, null, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+
+    /**
+     * Method to figure out which POST action (feed or advance) was
+     * triggered and perform this operation on the artifact specified
+     * by 'identifier' and found in the artifact database 'db'.
+     *
+     * @param identifier The identifier of the artifact.
+     * @param action The action to be performed.
+     * @param source The input document to further parameterize the
+     * operation.
+     * @param db The artifact database where to find the artifact.
+     * @return The representation produced by the performed action.
+     */
+    protected Representation dispatch(
+        String           identifier,
+        String           action,
+        Document         source,
+        ArtifactDatabase db
+    ) {
+        Document out = null;
+
+        try {
+            if (action.equals(FEED)) {
+                out = db.feed(identifier, source, getCallMeta());
+            }
+            else if (action.equals(ADVANCE)) {
+                out = db.advance(identifier, source, getCallMeta());
+            }
+            else if (action.equals(DESCRIBE)) {
+                out = db.describe(identifier, source, getCallMeta());
+            }
+            else {
+                throw new ArtifactDatabaseException(NO_SUCH_ACTION_MESSAGE);
+            }
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+
+        return new DomRepresentation(MediaType.APPLICATION_XML, out);
+    }
+
+    @Override
+    protected Representation innerPost(Representation requestRepr) {
+
+        Document inputDocument = null;
+        try {
+            DomRepresentation input = new DomRepresentation(requestRepr);
+            input.setNamespaceAware(true);
+            inputDocument = input.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getMessage());
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        String action = XMLUtils.xpathString(
+            inputDocument,
+            XPATH_ACTION,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (action == null || action.length() == 0) {
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, NO_ACTION_MESSAGE);
+            return new EmptyRepresentation();
+        }
+
+        Request request = getRequest();
+
+        String identifier = (String)request.getAttributes().get("uuid");
+
+        ArtifactDatabase db = (ArtifactDatabase)getContext()
+            .getAttributes().get("database");
+
+        return dispatch(identifier, action, inputDocument, db);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/BaseOutResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/BaseOutResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,150 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.CallMeta;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Request;
+import org.restlet.Response;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+
+import org.restlet.resource.ResourceException;
+
+import org.w3c.dom.Document;
+
+
+/**
+ * Base Resource to serve the out()-outputs of collections and artifacts.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public abstract class BaseOutResource
+extends               BaseResource
+{
+    /** The logger used in this class.*/
+    private static Logger logger = Logger.getLogger(BaseOutResource.class);
+
+    /** XPath to figure out the MIME type of the requested result.*/
+    public static final String XPATH_MIME_TYPE =
+        "/art:action/art:out/art:mime-type/@value";
+
+    /** Default result MIME type: octet stream.*/
+    public static final MediaType DEFAULT_MIME_TYPE =
+        MediaType.APPLICATION_OCTET_STREAM;
+
+
+    @Override
+    protected Representation innerPost(Representation requestRepr)
+    throws    ResourceException
+    {
+        Document inputDocument = null;
+
+        try {
+            DomRepresentation input = new DomRepresentation(requestRepr);
+            input.setNamespaceAware(true);
+            inputDocument = input.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getMessage());
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        Request request = getRequest();
+
+        String identifier = getIdentifier();
+        String outType    = getType();
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("looking for artifact id '" + identifier + "'");
+        }
+
+        String mimeTypeString = XMLUtils.xpathString(
+            inputDocument,
+            XPATH_MIME_TYPE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        MediaType mimeType = DEFAULT_MIME_TYPE;
+
+        if (mimeTypeString != null && mimeTypeString.length() != 0) {
+            try {
+                mimeType = MediaType.valueOf(mimeTypeString);
+            }
+            catch (Exception e) {
+                logger.error(e.getLocalizedMessage());
+            }
+        }
+
+        try {
+            return new OutRepresentation(
+                mimeType,
+                doOut(identifier, outType, inputDocument, db, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+
+    /**
+     * Returns the identifier of the artifact or collection.
+     *
+     * @return the identifier.
+     */
+    protected abstract String getIdentifier();
+
+
+    /**
+     * Returns the concrete output type of the artifact or collection.
+     *
+     * @return the output type.
+     */
+    protected abstract String getType();
+
+    /**
+     * This method is called to process the operation on artifacts or
+     * collections.
+     *
+     * @param identifier The identifier of the artifact or collection.
+     * @param type The output type.
+     * @param input The input document of the request.
+     * @param db The artifact database.
+     * @param meta The CallMeta object.
+     *
+     * @return the result of the operation.
+     */
+    protected abstract ArtifactDatabase.DeferredOutput doOut(
+        String           identifier,
+        String           type,
+        Document         input,
+        ArtifactDatabase db,
+        CallMeta         meta)
+    throws ArtifactDatabaseException;
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/BaseResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/BaseResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,161 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifactdatabase.DefaultCallMeta;
+import de.intevation.artifactdatabase.DefaultPreferredLocale;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.PreferredLocale;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.ClientInfo;
+import org.restlet.data.Language;
+import org.restlet.data.Preference;
+
+import org.restlet.representation.Representation;
+
+import org.restlet.resource.ResourceException;
+import org.restlet.resource.ServerResource;
+
+/**
+ * Base class for the resources of REST interface of the artifact database.
+ * Primarily used to unify the logging.
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class BaseResource
+extends      ServerResource
+{
+    private static Logger logger = Logger.getLogger(BaseResource.class);
+
+    /**
+     * Default constructor.
+     */
+    public BaseResource() {
+    }
+
+    /**
+     * Overrides the post method of ServerResource to handle some
+     * exceptions and to the required logging.
+     * The call bridges to #innerPost(Representation) which
+     * should be overwitten by the subclasses to do the real
+     * request processing.
+     * @param requestRepr The incoming represention of the HTTP request.
+     * @return The representation produced by #innerPost(Representation).
+     * @throws ResourceException Thrown if something went wrong during
+     * request processing.
+     */
+    @Override
+    protected Representation post(Representation requestRepr)
+    throws    ResourceException
+    {
+        try {
+            return innerPost(requestRepr);
+        }
+        catch (ResourceException re) {
+            throw re;
+        }
+        catch (RuntimeException re) {
+            logger.error(re.getLocalizedMessage(), re);
+            throw re;
+        }
+    }
+
+    /**
+     * Trivial implementation of innerPost() which is called by
+     * #post(Representation) which simply calls super.post(Representation).
+     * This should be overwritten by subclasses which need POST support.
+     * @param requestRepr The incoming representation of the request.
+     * @return The representation produced by super.post(Representation).
+     * @throws ResourceException Thrown if something went wrong during
+     * request processing.
+     */
+    protected Representation innerPost(Representation requestRepr)
+    throws    ResourceException
+    {
+        return super.post(requestRepr);
+    }
+
+    /**
+     * Wrapper around get() of the super class to handle some exceptions
+     * and do the corresponing logging. The call is bridged to #innerGet()
+     * which should be overwritten by subclasses.
+     * @return The representation produced by #innerGet()
+     * @throws ResourceException Thrown if something went wrong during
+     * request processing.
+     */
+    @Override
+    protected Representation get()
+    throws    ResourceException
+    {
+        try {
+            return innerGet();
+        }
+        catch (ResourceException re) {
+            throw re;
+        }
+        catch (RuntimeException re) {
+            logger.error(re.getLocalizedMessage(), re);
+            throw re;
+        }
+    }
+
+    /**
+     * Trivial implementaion of innerGet() which simply calls
+     * super.get() to produce some output representation. This method
+     * should be overwritten by subclasses which need GET support.
+     * @return The representation produced by super.get().
+     * @throws ResourceException Thrown if something went wrong during
+     * request processing.
+     */
+    protected Representation innerGet()
+    throws    ResourceException
+    {
+        return super.get();
+    }
+
+    /**
+     * Returns meta information (preferred languages et. al.)
+     * of the current HTTP request.
+     * @return the meta information
+     */
+    protected CallMeta getCallMeta() {
+        ClientInfo clientInfo = getClientInfo();
+
+        List<Preference<Language>> pl = clientInfo.getAcceptedLanguages();
+
+        PreferredLocale [] languages = new PreferredLocale[pl.size()];
+
+        int index = 0;
+
+        for (Preference<Language> p: pl) {
+            String lang    = p.getMetadata().getName();
+            float  quality = p.getQuality();
+            languages[index++] = new DefaultPreferredLocale(lang, quality);
+        }
+
+        return new DefaultCallMeta(languages);
+    }
+
+
+    /**
+     * Returns the artifact database stored in the context of the REST
+     * application.
+     *
+     * @return the artifact database.
+     */
+    protected ArtifactDatabase getArtifactDatabase() {
+        return (ArtifactDatabase) getContext().getAttributes().get("database");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ByteArrayRepresentation.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ByteArrayRepresentation.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,65 @@
+package de.intevation.artifactdatabase.rest;
+
+import org.restlet.representation.Representation;
+
+import java.io.Reader;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.Writer;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.ByteArrayInputStream;
+
+import java.nio.ByteBuffer;
+
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+import org.restlet.data.MediaType;
+
+public class ByteArrayRepresentation
+extends      Representation
+{
+    protected byte [] data;
+
+    public ByteArrayRepresentation(MediaType mediaType, byte [] data) {
+        super(mediaType);
+        this.data = data;
+    }
+
+    @Override
+    public long getSize() {
+        return data.length;
+    }
+
+    @Override
+    public ReadableByteChannel getChannel() throws IOException {
+        return null;
+    }
+
+    @Override
+    public Reader getReader() throws IOException {
+        return new InputStreamReader(getStream());
+    }
+
+    @Override
+    public InputStream getStream() throws IOException {
+        return new ByteArrayInputStream(data);
+    }
+
+    @Override
+    public void write(Writer writer) throws IOException {
+        writer.append(ByteBuffer.wrap(data).asCharBuffer());
+    }
+
+    @Override
+    public void write(WritableByteChannel writableChannel) throws IOException {
+        writableChannel.write(ByteBuffer.wrap(data));
+    }
+
+    @Override
+    public void write(OutputStream outputStream) throws IOException {
+        outputStream.write(data);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CollectionOutResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CollectionOutResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.CallMeta;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Request;
+
+import org.w3c.dom.Document;
+
+
+/**
+ * Resource to serve the out()-outputs of collections.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class CollectionOutResource
+extends      BaseOutResource
+{
+    /** The logger used in this class.*/
+    private static Logger logger = Logger.getLogger(CollectionOutResource.class);
+
+    /** server URL where to find the resource.*/
+    public static final String PATH = "/collection/{uuid}/{type}";
+
+
+    /**
+     * Returns the identifier of the collection.
+     *
+     * @return the identifier of the collection.
+     */
+    protected String getIdentifier() {
+        Request request = getRequest();
+
+        return (String) request.getAttributes().get("uuid");
+    }
+
+
+    protected String getType() {
+        Request request = getRequest();
+
+        return (String) request.getAttributes().get("type");
+    }
+
+
+    /**
+     * Call the ArtifactDatabase.outCollection method.
+     */
+    protected ArtifactDatabase.DeferredOutput doOut(
+        String           identifier,
+        String           type,
+        Document         input,
+        ArtifactDatabase db,
+        CallMeta         meta)
+    throws ArtifactDatabaseException
+    {
+        logger.debug("CollectionOutResource.doOut");
+
+        return db.outCollection(identifier, type, input, meta);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CollectionResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CollectionResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,276 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifactdatabase.ArtifactDatabaseImpl;
+
+import java.io.IOException;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.xml.DomRepresentation;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.Request;
+import org.restlet.Response;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class CollectionResource
+extends      BaseResource
+{
+    /** The logger that is used in this class.*/
+    private static Logger logger = Logger.getLogger(CollectionResource.class);
+
+    /** server URL where to reach the resource.*/
+    public static final String PATH = "/collection/{uuid}";
+
+    /**
+     * XPath to figure out the type of action (feed, advance) via the
+     * incoming POST request.
+     */
+    public static final String XPATH_ACTION = "/art:action/art:type/@name";
+
+    /**
+     * XPath to figure out the identifier of the artifact described in the
+     * action.
+     */
+    public static final String XPATH_ARTIFACT =
+        "/art:action/art:type/art:artifact/@uuid";
+
+    /** Error message if no action was given.*/
+    public static final String NO_ACTION_MSG = "no action given";
+
+    /** Error message if a unknown action was given.*/
+    public static final String NO_SUCH_ACTION_MSG = "no such action";
+
+    /** Action name for deleting a collection.*/
+    public static final String ACTION_DELETE = "delete";
+
+    /** Action name for describing the collection.*/
+    public static final String ACTION_DESCRIBE = "describe";
+
+    /** Action name for retrieving the attribute of a collection.*/
+    public static final String ACTION_GET_ATTRIBUTE = "getattribute";
+
+    /** Action name for retrieving the attributes of an artifact stored in the
+     * collection.*/
+    public static final String ACTION_GET_ITEM_ATTRIBUTE = "getitemattribute";
+
+    /** Action name for setting the attribute of a collection.*/
+    public static final String ACTION_SET_ATTRIBUTE = "setattribute";
+
+    /** Action name for setting the attribute for an artifact stored in the
+     * collection.*/
+    public static final String ACTION_SET_ITEM_ATTRIBUTE = "setitemattribute";
+
+    /** Action name for adding a new artifact to the collection.*/
+    public static final String ACTION_ADD_ARTIFACT = "addartifact";
+
+    /** Action name for removing an artifact from the collection.*/
+    public static final String ACTION_REMOVE_ARTIFACT = "removeartifact";
+
+    /** Action name for listing the artifacts of the collection.*/
+    public static final String ACTION_LIST_ARTIFACTS = "listartifacts";
+
+    /** Action name for setting the ttl of a collection.*/
+    public static final String ACTION_SET_TTL = "settimetolive";
+
+    /** Action name for setting the name of a collection.*/
+    public static final String ACTION_SET_NAME = "setname";
+
+
+    /**
+     * Method to figure out which POST action was triggered and perform this
+     * operation on the collection specified by 'identifier' and found in the
+     * artifact database 'db'.
+     *
+     * @param identifier The identifier of the collection.
+     * @param action The action to be performed.
+     * @param source The input document to further parameterize the operation.
+     * @param db The artifact database where to find the collection.
+     *
+     * @return The representation produced by the performed action.
+     */
+    protected Representation dispatch(
+        String           identifier,
+        String           action,
+        Document         source,
+        ArtifactDatabase db
+    ) {
+        Document out = null;
+
+        try {
+            CallMeta meta = getCallMeta();
+
+            if (action.equals(ACTION_DELETE)) {
+                logger.info("Delete collection '" + identifier + "'");
+                out = db.deleteCollection(identifier, getCallMeta());
+            }
+            else if (action.equals(ACTION_DESCRIBE)) {
+                logger.info("Describe collection '" + identifier + "'");
+
+                out = db.describeCollection(identifier, meta);
+            }
+            else if (action.equals(ACTION_ADD_ARTIFACT)) {
+                String art = getArtifactIdentifier(source);
+
+                logger.info("Add artifact '" + art + "' to collection.");
+                out = db.addCollectionArtifact(identifier, art, source, meta);
+            }
+            else if (action.equals(ACTION_REMOVE_ARTIFACT)) {
+                String art = getArtifactIdentifier(source);
+
+                logger.info("Remove artifact '" + art + "' from collection.");
+                out = db.removeCollectionArtifact(identifier, art, meta);
+            }
+            else if (action.equals(ACTION_LIST_ARTIFACTS)) {
+                logger.info("List artifacts of collection '" + identifier +"'");
+                out = db.listCollectionArtifacts(identifier, meta);
+            }
+            else if (action.equals(ACTION_SET_ATTRIBUTE)) {
+                String art = getArtifactIdentifier(source);
+
+                logger.info("Set attribute for collection '" + identifier + "'");
+
+                Document attr = getCollectionAttribute(source);
+
+                out = db.setCollectionAttribute(identifier, meta, attr);
+            }
+            else if (action.equals(ACTION_SET_ITEM_ATTRIBUTE)) {
+                String art = getArtifactIdentifier(source);
+
+                logger.info("Set attribute for artifact '" + art + "'");
+                out = db.setCollectionItemAttribute(identifier, art, source, meta);
+            }
+            else if (action.equals(ACTION_GET_ATTRIBUTE)) {
+                String art = getArtifactIdentifier(source);
+
+                logger.info("Retrieve attribute of collection '" + identifier + "'");
+                out = db.getCollectionAttribute(identifier, meta);
+            }
+            else if (action.equals(ACTION_GET_ITEM_ATTRIBUTE)) {
+                String art = getArtifactIdentifier(source);
+
+                logger.info("Retrieve attribute of artifact '" + art + "'");
+                out = db.getCollectionItemAttribute(identifier, art, meta);
+            }
+            else if (action.equals(ACTION_SET_TTL)) {
+                out = db.setCollectionTTL(identifier, source, meta);
+            }
+            else if (action.equals(ACTION_SET_NAME)) {
+                out = db.setCollectionName(identifier, source, meta);
+            }
+            else {
+                throw new ArtifactDatabaseException(NO_SUCH_ACTION_MSG);
+            }
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+
+        return new DomRepresentation(MediaType.APPLICATION_XML, out);
+    }
+
+
+    @Override
+    protected Representation innerPost(Representation requestRepr) {
+        Document input = null;
+        try {
+            DomRepresentation in = new DomRepresentation(requestRepr);
+            in.setNamespaceAware(true);
+            input = in.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        String action = XMLUtils.xpathString(
+            input, XPATH_ACTION, ArtifactNamespaceContext.INSTANCE);
+
+        if (action == null || action.length() == 0) {
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, NO_ACTION_MSG);
+            return new EmptyRepresentation();
+        }
+
+        Request request = getRequest();
+
+        String identifier = (String) request.getAttributes().get("uuid");
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        return dispatch(identifier, action, input, db);
+    }
+
+
+    /**
+     * Retrieves the identifier of the artifact used in the action.
+     *
+     * @param source The incoming document that describes the operation.
+     *
+     * @return the uuid of the artifact described in the document.
+     */
+    protected String getArtifactIdentifier(Document source) {
+        return XMLUtils.xpathString(
+            source, XPATH_ARTIFACT, ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
+     * Returns the attribute for a collection of the incoming request document.
+     *
+     * @param request The request document.
+     *
+     * @return the contained attribute as document.
+     */
+    protected Document getCollectionAttribute(Document request) {
+        Node attr = (Node) XMLUtils.xpath(
+            request,
+            ArtifactDatabaseImpl.XPATH_COLLECTION_ATTRIBUTE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        Document newAttr = XMLUtils.newDocument();
+
+        if (attr == null) {
+            logger.error("Collection attribute document not found!");
+            return newAttr;
+        }
+
+        newAttr.appendChild(newAttr.importNode(attr, true));
+
+        return newAttr;
+    }
+}
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CreateCollectionResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CreateCollectionResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,87 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.xml.DomRepresentation;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ResourceException;
+import org.restlet.Response;
+import org.restlet.Request;
+
+import org.w3c.dom.Document;
+
+/**
+ * Resource to create a new collections within the artifact database.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class CreateCollectionResource
+extends      BaseResource
+{
+    /** The logger used in this class.*/
+    private static Logger logger =
+        Logger.getLogger(CreateCollectionResource.class);
+
+    /** The URL part for this resource.*/
+    public static final String PATH = "/create-collection/{ownerid}";
+
+
+    @Override
+    protected Representation innerPost(Representation requestRepr)
+    throws    ResourceException
+    {
+        Document input = null;
+
+        try {
+            DomRepresentation in = new DomRepresentation(requestRepr);
+            in.setNamespaceAware(true);
+            input = in.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        Request request     = getRequest();
+
+        String ownerId      = (String) request.getAttributes().get("ownerid");
+
+        logger.info("Create new collection owned by: " + ownerId);
+
+        try {
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.createCollection(ownerId, input, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CreateResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CreateResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,115 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Response;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+
+import org.restlet.resource.ResourceException;
+
+import org.w3c.dom.Document;
+
+/**
+ * Resource to create a new artifact within artifact database.
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class CreateResource
+extends      BaseResource
+{
+    private static Logger logger = Logger.getLogger(CreateResource.class);
+
+    /**
+     * server URL where to reach the resource.
+     */
+    public static final String PATH = "/create";
+
+    /**
+     * XPATH to figure out the name of the factory which should be used
+     * to create the new artifact.
+     */
+    public static final String XPATH_FACTORY = "/art:action/art:factory/@name";
+
+    /**
+     * Error message if no factory was given.
+     */
+    public static final String NO_FACTORY_MESSAGE = "No factory given";
+
+    /**
+     * Error message if no artifact was created.
+     */
+    public static final String NO_ARTIFACT_CREATED = "No artifact created";
+
+    @Override
+    protected Representation innerPost(Representation requestRepr)
+    throws ResourceException
+    {
+        Document inputDocument = null;
+        try {
+            DomRepresentation input = new DomRepresentation(requestRepr);
+            input.setNamespaceAware(true);
+            inputDocument = input.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getMessage());
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        String factory = XMLUtils.xpathString(
+            inputDocument,
+            XPATH_FACTORY,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (factory == null || factory.length() == 0) {
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, NO_FACTORY_MESSAGE);
+            return new EmptyRepresentation();
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Create artifact with factory '" + factory + "'");
+        }
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        try {
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.createArtifactWithFactory(factory,
+                                             getCallMeta(),
+                                             inputDocument));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CreateUserResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/CreateUserResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Response;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.xml.DomRepresentation;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ResourceException;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+
+/**
+ * Resource to create a new users within the artifact database.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class CreateUserResource
+extends      BaseResource
+{
+    /** The logger used in this class.*/
+    private static Logger logger = Logger.getLogger(CreateUserResource.class);
+
+    /** The URL part for this resource.*/
+    public static final String PATH = "/create-user";
+
+
+    @Override
+    protected Representation innerPost(Representation requestRepr)
+    throws    ResourceException
+    {
+        Document input = null;
+
+        try {
+            DomRepresentation in = new DomRepresentation(requestRepr);
+            in.setNamespaceAware(true);
+            input = in.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        logger.debug("Create user");
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        try {
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.createUser(input, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ExportResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ExportResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,74 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Request;
+import org.restlet.Response;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+
+import org.restlet.resource.ResourceException;
+
+/**
+ * Resource to produce an external XML representation of a given
+ * artifact to be import by ImportResource later on.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class ExportResource
+extends      BaseResource
+{
+    private static Logger logger = Logger.getLogger(ExportResource.class);
+
+    /**
+     * server URL where to reach the resource.
+     */
+    public static final String PATH = "/export/{uuid}";
+
+    @Override
+    protected Representation innerGet()
+    throws                   ResourceException
+    {
+        Request request = getRequest();
+
+        String identifier = (String)request.getAttributes().get("uuid");
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("looking for artifact id '" + identifier + "'");
+        }
+
+        ArtifactDatabase db = (ArtifactDatabase)getContext()
+            .getAttributes().get("database");
+
+        try {
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.exportArtifact(identifier, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/FactoriesResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/FactoriesResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.Representation;
+
+import org.restlet.resource.ResourceException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Resource to list the available factories.
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class FactoriesResource
+extends      BaseResource
+{
+    private static Logger logger = Logger.getLogger(FactoriesResource.class);
+
+    /**
+     * server URL where to reach the resource.
+     */
+    public static final String PATH = "/factories";
+
+    @Override
+    protected Representation innerGet()
+    throws                   ResourceException
+    {
+        Document document = XMLUtils.newDocument();
+
+        ElementCreator ec = new ElementCreator(
+            document,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        ArtifactDatabase db = (ArtifactDatabase)getContext()
+            .getAttributes().get("database");
+
+        Element root = ec.create("result");
+        document.appendChild(root);
+
+        Element type = ec.create("type");
+        ec.addAttr(type, "name", "factory-list");
+        root.appendChild(type);
+
+        Element factories = ec.create("factories");
+        root.appendChild(factories);
+
+        String [][] factoryNames = db.artifactFactoryNamesAndDescriptions();
+
+        for (int i = 0; i < factoryNames.length; ++i) {
+            String [] nd = factoryNames[i];
+            Element factoryElement = ec.create("factory");
+            ec.addAttr(factoryElement, "name", nd[0]);
+            ec.addAttr(factoryElement, "description", nd[1]);
+            factories.appendChild(factoryElement);
+        }
+
+        document.normalizeDocument();
+
+        return new DomRepresentation(
+            MediaType.APPLICATION_XML, document);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/FindUserResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/FindUserResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.xml.DomRepresentation;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ResourceException;
+import org.restlet.Response;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+/**
+ * A Rest resource that finds the user provided by the artifact database.
+ *
+ */
+public class FindUserResource
+extends      BaseResource
+{
+    /** The logger that is used in this class.*/
+    private static Logger logger = Logger.getLogger(FindUserResource.class);
+
+    /** server URL where to reach the resource.*/
+    public static final String PATH = "/find-user";
+
+
+    @Override
+    protected Representation innerPost(Representation requestRepr)
+    throws    ResourceException
+    {
+        Document input = null;
+
+        try {
+            DomRepresentation in = new DomRepresentation(requestRepr);
+            in.setNamespaceAware(true);
+            input = in.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getLocalizedMessage(), ioe);
+
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        try {
+            logger.info(PATH);
+
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.findUser(input, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,13 @@
+package de.intevation.artifactdatabase.rest;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifacts.ArtifactDatabase;
+
+public interface HTTPServer
+{
+    void setup(Document document);
+
+    void startAsServer(ArtifactDatabase database);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ImportResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ImportResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,82 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Request;
+import org.restlet.Response;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+
+import org.w3c.dom.Document;
+
+/**
+ * Resource to import an XML document containg an artifact produced by
+ * the ExportResource.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class ImportResource
+extends      BaseResource
+{
+    private static Logger logger = Logger.getLogger(ImportResource.class);
+
+    /**
+     * server URL where to reach the resource.
+     */
+    public static final String PATH = "/import";
+
+    @Override
+    protected Representation innerPost(Representation requestRepr) {
+
+        Document inputDocument = null;
+        try {
+            DomRepresentation input = new DomRepresentation(requestRepr);
+            input.setNamespaceAware(true);
+            inputDocument = input.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getMessage());
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        Request request = getRequest();
+
+        ArtifactDatabase db = (ArtifactDatabase)getContext()
+            .getAttributes().get("database");
+
+        try {
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.importArtifact(inputDocument, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/JettyServer.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/JettyServer.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,44 @@
+package de.intevation.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+
+import org.restlet.Component;
+import org.restlet.Server;
+
+import org.restlet.ext.jetty.HttpServerHelper;
+
+import org.apache.log4j.Logger;
+
+public class JettyServer
+extends      Standalone
+{
+    private static Logger logger = Logger.getLogger(JettyServer.class);
+
+    @Override
+    public void startAsServer(ArtifactDatabase db) {
+
+        Component component = new Component();
+
+        RestApp app = new RestApp(db);
+
+        Server server = createServer();
+
+        // TODO: Do more sophisticated Jetty server configuration here.
+
+        component.getServers().add(server);
+
+        component.getDefaultHost().attach(app);
+
+        logServerStart();
+
+        HttpServerHelper serverHelper = new HttpServerHelper(server);
+
+        try {
+            serverHelper.start();
+        }
+        catch (Exception e) {
+            logger.error(e.getLocalizedMessage(), e);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ListCollectionsResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ListCollectionsResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,69 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.xml.DomRepresentation;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.Request;
+import org.restlet.resource.ResourceException;
+import org.restlet.Response;
+
+
+/**
+ * A Rest resource that lists the collections of a specific user provided by
+ * the artifact database.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class ListCollectionsResource
+extends      BaseResource
+{
+   /** The logger that is used in this class.*/
+    private static Logger logger =
+        Logger.getLogger(ListCollectionsResource.class);
+
+    /** server URL where to reach the resource.*/
+    public static final String PATH = "/list-collections/{ownerid}";
+
+
+    @Override
+    protected Representation innerGet()
+    throws                   ResourceException
+    {
+        Request request     = getRequest();
+
+        String ownerId      = (String) request.getAttributes().get("ownerid");
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        try {
+            logger.info("List collections owned by " + ownerId);
+
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.listCollections(ownerId, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ListUsersResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ListUsersResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.xml.DomRepresentation;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ResourceException;
+import org.restlet.Response;
+
+/**
+ * A Rest resource that lists the users provided by the artifact database.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class ListUsersResource
+extends      BaseResource
+{
+    /** The logger that is used in this class.*/
+    private static Logger logger = Logger.getLogger(ListUsersResource.class);
+
+    /** server URL where to reach the resource.*/
+    public static final String PATH = "/list-users";
+
+
+    @Override
+    protected Representation innerGet()
+    throws                   ResourceException
+    {
+        ArtifactDatabase db = getArtifactDatabase();
+
+        try {
+            logger.info(PATH);
+
+            return new DomRepresentation(
+                MediaType.APPLICATION_XML,
+                db.listUsers(getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_NOT_FOUND, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/OutRepresentation.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/OutRepresentation.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase.DeferredOutput;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.restlet.data.MediaType;
+
+import org.restlet.representation.OutputRepresentation;
+
+/**
+ * Special representation to serve the out()-outputs
+ * via DeferredOutput efficently .
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class OutRepresentation
+extends      OutputRepresentation
+{
+    /**
+     * The deferred output fetched from ArtifactDatabase.out().
+     */
+    protected DeferredOutput out;
+
+    /**
+     * Constructor to create representation with a given MIME type and
+     * a deferred output.
+     * @param mediaType The MIME type of this representation.
+     * @param out The deferred output from the ArtifactDatabase.out() call.
+     */
+    public OutRepresentation(MediaType mediaType, DeferredOutput out) {
+        super(mediaType);
+        this.out = out;
+    }
+
+    /**
+     * Overwrites the write(OutputStream) of OutRepresentation to serve
+     * the data from the deferred output.
+     * @param output the stream where to write the data into.
+     * @throws IOException Thrown if an exception occurred while writing
+     * the data to the output stream.
+     */
+    public void write(OutputStream output) throws IOException {
+        out.write(output);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,97 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+
+import java.util.concurrent.ConcurrentMap;
+
+import org.restlet.Application;
+import org.restlet.Context;
+import org.restlet.Restlet;
+
+import org.restlet.routing.Router;
+
+/**
+ * This is the core REST application that binds the serveral resources
+ * used to manage the artifact database to the HTTP server provided
+ * by the Restlet framework.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation.de">Sascha L. Teichmann</a>
+ */
+public class RestApp
+extends      Application
+{
+    /**
+     * The central artifact database instance to work with.
+     */
+    protected ArtifactDatabase database;
+
+    /**
+     * Default constructor
+     */
+    public RestApp() {
+    }
+
+    public RestApp(Context context, ArtifactDatabase database) {
+        super(context);
+        this.database = database;
+    }
+
+    /**
+     * Constructor to create REST appliction bound to a specific
+     * artifact database.
+     *
+     * @param database The artifact database to be used.
+     */
+    public RestApp(ArtifactDatabase database) {
+        this.database = database;
+    }
+
+    /**
+     * Overwrites the createRoot() method of Application to
+     * build the resource tree to form the exposed server URLs.
+     *
+     * @return The root of the URL tree exposed by the HTTP server.
+     */
+    @Override
+    public Restlet createRoot() {
+
+        Context context = getContext();
+
+        ConcurrentMap map = context.getAttributes();
+        map.put("database", database);
+
+        Router router = new Router(context);
+
+        router.attach(ServicesResource.PATH,    ServicesResource.class);
+        router.attach(ServiceResource.PATH,     ServiceResource.class);
+        router.attach(FactoriesResource.PATH,   FactoriesResource.class);
+        router.attach(CreateResource.PATH,      CreateResource.class);
+        router.attach(ArtifactResource.PATH,    ArtifactResource.class);
+        router.attach(ArtifactOutResource.PATH, ArtifactOutResource.class);
+        router.attach(ExportResource.PATH,      ExportResource.class);
+        router.attach(ImportResource.PATH,      ImportResource.class);
+        router.attach(CreateUserResource.PATH,  CreateUserResource.class);
+        router.attach(ListUsersResource.PATH,   ListUsersResource.class);
+        router.attach(UserResource.PATH,        UserResource.class);
+        router.attach(FindUserResource.PATH,    FindUserResource.class);
+        router.attach(
+            CreateCollectionResource.PATH, CreateCollectionResource.class);
+        router.attach(
+            ListCollectionsResource.PATH, ListCollectionsResource.class);
+        router.attach(
+            CollectionResource.PATH, CollectionResource.class);
+        router.attach(
+            CollectionOutResource.PATH, CollectionOutResource.class);
+
+        return router;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ServiceResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ServiceResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifacts.Service;
+
+/**
+ * Resource to process incoming XML documents with a given service.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class ServiceResource
+extends      BaseResource
+{
+    private static Logger logger = Logger.getLogger(ServiceResource.class);
+
+    /**
+     * server URL where to reach the resource.
+     */
+    public static final String PATH = "/service/{service}";
+
+    /**
+     * Error message if no corresponing service is provided by
+     * the artifact database.
+     */
+    public static final String NO_SUCH_ACTION_MESSAGE = "no such service";
+
+    @Override
+    protected Representation innerPost(Representation requestRepr) {
+
+        Document inputDocument = null;
+        try {
+            DomRepresentation input = new DomRepresentation(requestRepr);
+            input.setNamespaceAware(true);
+            inputDocument = input.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getMessage());
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        Request request = getRequest();
+
+        String service = (String)request.getAttributes().get("service");
+
+        ArtifactDatabase db = (ArtifactDatabase)getContext()
+            .getAttributes().get("database");
+
+        try {
+            return guessRepresentation(
+                db.process(service, inputDocument, getCallMeta()));
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+    }
+
+    protected static Representation guessRepresentation(Service.Output output) {
+
+        MediaType mediaType = new MediaType(output.getMIMEType());
+        Object    data      = output.getData();
+
+        if (data instanceof Document) {
+            return new DomRepresentation(mediaType, (Document)data);
+        }
+
+        if (data instanceof byte []) {
+            return new ByteArrayRepresentation(mediaType, (byte [])data);
+        }
+
+        return new EmptyRepresentation();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ServicesResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/ServicesResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,85 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+
+import org.restlet.ext.xml.DomRepresentation;
+
+import org.restlet.representation.Representation;
+
+import org.restlet.resource.ResourceException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Resource to list the available service offered by the artifact database.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class ServicesResource
+extends      BaseResource
+{
+    private static Logger logger = Logger.getLogger(ServicesResource.class);
+
+    /**
+     * server URL where to reach the resource.
+     */
+    public static final String PATH = "/services";
+
+    @Override
+    protected Representation innerGet()
+    throws                   ResourceException
+    {
+        Document document = XMLUtils.newDocument();
+
+        ElementCreator ec = new ElementCreator(
+            document,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        ArtifactDatabase db = (ArtifactDatabase)getContext()
+            .getAttributes().get("database");
+
+        Element root = ec.create("result");
+        document.appendChild(root);
+
+        Element type = ec.create("type");
+        ec.addAttr(type, "name", "service-list");
+        root.appendChild(type);
+
+        Element factories = ec.create("services");
+        root.appendChild(factories);
+
+        String [][] factoryNames = db.serviceNamesAndDescriptions();
+
+        for (int i = 0; i < factoryNames.length; ++i) {
+            String [] nd = factoryNames[i];
+            Element factoryElement = ec.create("service");
+            ec.addAttr(factoryElement, "name", nd[0]);
+            ec.addAttr(factoryElement, "description", nd[1]);
+            factories.appendChild(factoryElement);
+        }
+
+        document.normalizeDocument();
+
+        return new DomRepresentation(
+            MediaType.APPLICATION_XML, document);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,143 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.ArtifactDatabase;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.Component;
+import org.restlet.Server;
+
+import org.restlet.data.Protocol;
+
+import org.w3c.dom.Document;
+
+/**
+ * Starts an HTTP server bound to a RestApp.
+ * The server (binding interface and port) is configure via the
+ * global configuration.
+ *
+ * @author <a href="mailto:sascha.teichmann at intevation">Sascha L. Teichmann</a>
+ */
+public class Standalone
+implements   HTTPServer
+{
+    private static Logger logger = Logger.getLogger(Standalone.class);
+
+    /**
+     * XPath to figure out the port where to listen from the
+     * global configuration.
+     */
+    public static final String REST_PORT =
+        "/artifact-database/rest-server/port/text()";
+
+    /**
+     * XPath to figure out from global configuration
+     * which network interface to use to bind the HTTP server.
+     */
+    public static final String LISTEN_INTERFACE =
+        "/artifact-database/rest-server/listen/text()";
+
+    /**
+     * The default port of the HTTP server: 8181
+     */
+    public static final int DEFAULT_PORT = 8181;
+
+    public static final String MAX_THREADS =
+        "/artifact-database/rest-server/max-threads/text()";
+
+    public static final String MAX_THREADS_DEFAULT =
+        "1024";
+
+    protected int     port;
+
+    protected String  listen;
+
+    protected String  maxThreads;
+
+    public Standalone() {
+    }
+
+    @Override
+    public void setup(Document document) {
+        String portString = XMLUtils.xpathString(document, REST_PORT, null);
+
+        port = DEFAULT_PORT;
+
+        if (portString != null) {
+            try {
+                port = Integer.parseInt(portString);
+                if (port < 0) {
+                    throw new NumberFormatException();
+                }
+            }
+            catch (NumberFormatException nfe) {
+                logger.error("rest port is not a positive integer value.", nfe);
+                return;
+            }
+        }
+
+        listen     = XMLUtils.xpathString(document, LISTEN_INTERFACE, null);
+        maxThreads = XMLUtils.xpathString(document, MAX_THREADS, null);
+    }
+
+    protected Server createServer() {
+        return listen != null && listen.length() > 0
+            ? new Server(Protocol.HTTP, listen, port)
+            : new Server(Protocol.HTTP, port);
+    }
+
+    protected void logServerStart() {
+        logger.info("Starting " + getClass().getName() + " HTTP server on "
+            + (listen != null ? listen : "*")
+            + ":" + port);
+    }
+
+    /**
+     * Builds a RestApp wrapped around the given artifact database,
+     * and bind this application to HTTP server. The HTTP server
+     * is configured by the global configuration. If no port is
+     * given by the configuration the default port is used. If
+     * no interface is given the HTTP server is reachable from
+     * all interfaces.
+     * @param db The artifact database to be exposed via the
+     * REST application.
+     */
+    @Override
+    public void startAsServer(ArtifactDatabase db) {
+
+        RestApp app = new RestApp(db);
+
+        Component component = new Component();
+
+        Server server = createServer();
+
+        component.getServers().add(server);
+
+        server.getContext().getParameters().add(
+            "maxThreads", maxThreads != null && maxThreads.length() > 0
+                ? maxThreads
+                : MAX_THREADS_DEFAULT);
+
+        component.getDefaultHost().attach(app);
+
+        logServerStart();
+
+        try {
+            component.start();
+        }
+        catch (Exception e) {
+            logger.error(e.getLocalizedMessage(), e);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/UserResource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/UserResource.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,137 @@
+/*
+ * 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.artifactdatabase.rest;
+
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.xml.DomRepresentation;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.Request;
+import org.restlet.Response;
+
+import org.w3c.dom.Document;
+
+/**
+ * A resource that handles actions to a specific user.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation">Ingo Weinzierl</a>
+ */
+public class UserResource
+extends      BaseResource
+{
+    /** The logger that is used in this class. */
+    private static Logger logger = Logger.getLogger(UserResource.class);
+
+    /** server URL where to reach the resource. */
+    public static final String PATH = "/user/{uuid}";
+
+    /**
+     * XPath to figure out the type of action (feed, advance) via the
+     * incoming POST request.
+     */
+    public static final String XPATH_ACTION = "/art:action/art:type/@name";
+
+    /** Error message if no action was given. */
+    public static final String NO_ACTION_MSG = "no action given";
+
+    /** Error message if a unknown action was given. */
+    public static final String NO_SUCH_ACTION_MSG = "no such action";
+
+    /** Action name for deleting users. */
+    public static final String ACTION_DELETE = "delete";
+
+
+    @Override
+    protected Representation innerPost(Representation requestRepr) {
+        Document inputDocument = null;
+
+        try {
+            DomRepresentation input = new DomRepresentation(requestRepr);
+            input.setNamespaceAware(true);
+            inputDocument = input.getDocument();
+        }
+        catch (IOException ioe) {
+            logger.error(ioe.getMessage());
+            Response response = getResponse();
+            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe);
+            return new EmptyRepresentation();
+        }
+
+        String action = XMLUtils.xpathString(
+            inputDocument,
+            XPATH_ACTION,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (action == null || action.length() == 0) {
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, NO_ACTION_MSG);
+            return new EmptyRepresentation();
+        }
+
+        Request request = getRequest();
+
+        String identifier = (String)request.getAttributes().get("uuid");
+
+        ArtifactDatabase db = getArtifactDatabase();
+
+        return dispatch(identifier, action, inputDocument, db);
+    }
+
+    /**
+     * Method to figure out which POST action (feed or advance) was
+     * triggered and perform this operation on the artifact specified
+     * by 'identifier' and found in the artifact database 'db'
+     * @param identifier The identifier of the artifact.
+     * @param action The action to be performed.
+     * @param source The input document to further parameterize the
+     * operation.
+     * @param db The artifact database where to find the artifact.
+     * @return The representation produced by the performed action.
+     */
+    protected Representation dispatch(
+        String           identifier,
+        String           action,
+        Document         source,
+        ArtifactDatabase db)
+    {
+        Document out = null;
+
+        logger.info("Action: " + action + " | User: " + identifier);
+
+        try {
+            if (action.equals(ACTION_DELETE)) {
+                out = db.deleteUser(identifier, getCallMeta());
+            }
+            else {
+                throw new ArtifactDatabaseException(NO_SUCH_ACTION_MSG);
+            }
+        }
+        catch (ArtifactDatabaseException adbe) {
+            logger.warn(adbe.getLocalizedMessage(), adbe);
+            Response response = getResponse();
+            response.setStatus(
+                Status.CLIENT_ERROR_BAD_REQUEST, adbe.getMessage());
+            return new EmptyRepresentation();
+        }
+
+        return new DomRepresentation(MediaType.APPLICATION_XML, out);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/package.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/package.html	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,6 @@
+</head>
+<body>
+The REST interface of the artfifact database.  This package contains classes
+that offer the URL resources to manage the artifacts via REST.
+</body>
+</html>
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/AbstractState.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/AbstractState.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,406 @@
+/*
+ * 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.artifactdatabase.state;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.utils.Config;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifactdatabase.data.StateData;
+
+
+/**
+ * An abstract implementation of a {@link State}. It implements some basic
+ * methods that return the id, description and data. The methods
+ * <code>describe()</code> and <code>setup()</code> depend on the concrete class
+ * and need to be implemented by those.
+ */
+public abstract class AbstractState implements State {
+
+    /** The XPath to the ID of the state relative to the state node in the
+     * configuration. */
+    public static final String XPATH_ID = "@id";
+
+    /** The XPath to the description of the state relative to the state node in
+     * the configuration. */
+    public static final String XPATH_DESCRIPTION = "@description";
+
+    /** The XPath that points to the help text.*/
+    public static final String XPATH_HELP_TEXT = "@helpText";
+
+    /** The XPath to the output nodes of the state configuration. */
+    public static final String XPATH_OUTPUT_MODES = "outputmodes/outputmode";
+
+    /** The XPath to the list of facets relative to the output mode it belongs
+     * to. */
+    public static final String XPATH_FACETS = "facets/facet";
+
+    public static final String XPATH_HELP_URL = "/artifact-database/help-url/text()";
+
+    public static final String HELP_URL = "${help.url}";
+
+
+    /** The logger that is used in this class. */
+    private static Logger logger = Logger.getLogger(AbstractState.class);
+
+
+    /** The ID of the state. */
+    protected String id;
+
+    /** The description of the state. */
+    protected String description;
+
+    /** The help text for this state.*/
+    protected String helpText;
+
+    /** The data provided by this state. */
+    protected Map<String, StateData> data;
+
+    /** A list of output modes which are available for this state. */
+    protected List<Output> outputs;
+
+    private static String helpUrl;
+
+
+    public AbstractState() {
+        outputs = new ArrayList<Output>();
+    }
+
+    public static synchronized final String getHelpUrl() {
+        if (helpUrl == null) {
+            helpUrl = Config.getStringXPath(XPATH_HELP_URL, HELP_URL);
+        }
+        return helpUrl;
+    }
+
+    public static String replaceHelpUrl(String string) {
+        return string.replace(HELP_URL, getHelpUrl());
+    }
+
+
+    /**
+     * The default constructor.
+     *
+     * @param id The ID of the state.
+     * @param description The description of the state.
+     */
+    public AbstractState(String id, String description) {
+        super();
+
+        this.id          = id;
+        this.description = description;
+    }
+
+
+    public AbstractState(String id, String description, String helpText) {
+        this(id, description);
+        this.helpText = replaceHelpUrl(helpText);
+    }
+
+
+    /**
+     * Returns the ID of the state.
+     *
+     * @return the ID of the state.
+     */
+    public String getID() {
+        return id;
+    }
+
+
+    /**
+     * Set the ID of the state.
+     *
+     * @param id The ID of the state.
+     */
+    public void setID(String id) {
+        this.id = id;
+    }
+
+
+    /**
+     * Returns the description of the state.
+     *
+     * @return the description of the state.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Set the description of the state.
+     *
+     * @param description The description of the state.
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * Returns the help text of this state.
+     *
+     * @return the help text.
+     */
+    public String getHelpText() {
+        return helpText;
+    }
+
+
+    /**
+     * Set the help text for this state.
+     *
+     * @param helpText The help text.
+     */
+    public void setHelpText(String helpText) {
+        this.helpText = replaceHelpUrl(helpText);
+    }
+
+
+    /**
+     * Returns the data of the state.
+     *
+     * @return the data of the state.
+     */
+    public Map<String, StateData> getData() {
+        return data;
+    }
+
+
+    /**
+     * Returns a specific data object of the state.
+     *
+     * @param name The name of the data object.
+     *
+     * @return a data object of the state or null if no such data object exists.
+     */
+    public StateData getData(String name) {
+        if (data != null) {
+            return data.get(name);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Add new data to the state. NOTE: If there is already an object existing
+     * with the key <i>name</i>, this object is overwritten by the new value.
+     *
+     * @param name The name of the data object.
+     * @param data The data object.
+     */
+    public void addData(String name, StateData data) {
+        if (this.data == null) {
+            this.data = new HashMap<String, StateData>();
+        }
+
+        this.data.put(name, data);
+    }
+
+
+    /**
+     * Returns the list of possible outputs of this state. The list is empty
+     * if no output is available for this state.
+     *
+     * @return a list of possible outputs of this state.
+     */
+    public List<Output> getOutputs() {
+        return outputs;
+    }
+
+
+    /**
+     * Initialize the state based on the state node in the configuration.
+     *
+     * @param config The state configuration node.
+     */
+    public void setup(Node config) {
+        logger.info("AbstractState.setup");
+
+        id = (String) XMLUtils.xpath(config, XPATH_ID, XPathConstants.STRING);
+
+        description = (String) XMLUtils.xpath(
+            config, XPATH_DESCRIPTION, XPathConstants.STRING);
+
+        helpText = (String) XMLUtils.xpath(
+            config, XPATH_HELP_TEXT, XPathConstants.STRING);
+
+        if (helpUrl != null) {
+            helpUrl = replaceHelpUrl(helpUrl);
+        }
+
+        setupOutputs(config);
+    }
+
+
+    /**
+     * This default implementation does nothing at all.
+     *
+     * @param orig
+     * @param owner
+     * @param context
+     * @param callMeta
+     */
+    public void initialize(
+        Artifact orig,
+        Artifact owner,
+        Object   context,
+        CallMeta callMeta
+    ) {
+        // do nothing.
+    }
+
+
+    /**
+     * This method tries reading the available output nodes configured in the
+     * state configuration and adds possible Outputs to the outputs list.
+     *
+     * @param config The state configuration node.
+     */
+    protected void setupOutputs(Node config) {
+        NodeList outs = (NodeList) XMLUtils.xpath(
+            config,
+            XPATH_OUTPUT_MODES,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (outs == null || outs.getLength() == 0) {
+            return;
+        }
+
+        int size = outs.getLength();
+
+        for (int i = 0; i < size; i++) {
+            addOutput(buildOutput(outs.item(i)));
+        }
+    }
+
+    /**
+     * This methods allows subclasses to manually add outputs
+     *
+     * @param out The output to add
+     */
+    protected void addOutput(Output out) {
+        outputs.add(out);
+    }
+
+    /**
+     * A helper method that creates an Output object based on the <i>out</i>
+     * node.
+     *
+     * @param out The output node configuration.
+     *
+     * @return an Output object.
+     */
+    protected Output buildOutput(Node out) {
+        String name = XMLUtils.xpathString(
+            out, "@name", ArtifactNamespaceContext.INSTANCE);
+
+        String desc = XMLUtils.xpathString(
+            out, "@description", ArtifactNamespaceContext.INSTANCE);
+
+        String mimetype = XMLUtils.xpathString(
+            out, "@mime-type", ArtifactNamespaceContext.INSTANCE);
+
+        String type = XMLUtils.xpathString(
+            out, "@type", ArtifactNamespaceContext.INSTANCE);
+
+        if (name == null) {
+            return null;
+        }
+
+        NodeList facets = (NodeList) XMLUtils.xpath(
+            out,
+            XPATH_FACETS,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (facets == null || facets.getLength() == 0) {
+            return new DefaultOutput(name, desc, mimetype, type);
+        }
+
+        int num = facets.getLength();
+
+        List<Facet> facetList = new ArrayList<Facet>(num);
+
+        for (int i = 0; i < num; i++) {
+            Facet facet = buildFacet(facets.item(i));
+
+            if (facet != null) {
+                facetList.add(facet);
+            }
+        }
+
+        return new DefaultOutput(name, desc, mimetype, facetList, type);
+    }
+
+
+    /**
+     * A helper method that creates a Facet object based on the <i>facet</i>
+     * node.
+     *
+     * @param facet The facet node.
+     *
+     * @return a Facet object or null if no valid Facet was found.
+     */
+    protected Facet buildFacet(Node facet) {
+        String name = XMLUtils.xpathString(
+            facet, "@name", ArtifactNamespaceContext.INSTANCE);
+
+        String desc = XMLUtils.xpathString(
+            facet, "@description", ArtifactNamespaceContext.INSTANCE);
+
+        return name != null ? new DefaultFacet(name, desc) : null;
+    }
+
+
+    /**
+     * Describes the UI of the state. This method needs to be implemented by
+     * concrete subclasses.
+     *
+     * @param artifact A reference to the artifact this state belongs to.
+     * @param document Describe doucment.
+     * @param rootNode Parent node for all new elements.
+     * @param context The CallContext.
+     * @param uuid The uuid of an artifact.
+     */
+    public abstract Element describe(
+        Artifact    artifact,
+        Document    document,
+        Node        rootNode,
+        CallContext context,
+        String      uuid
+    );
+
+
+    @Override
+    public void endOfLife(Artifact artifact, Object context) {
+        // nothing to do here
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/ArtifactAndFacet.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/ArtifactAndFacet.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,97 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.List;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.DataProvider;
+
+
+/**
+ * A bundle of a "native" Facet and its Artifact.
+ */
+public class ArtifactAndFacet implements DataProvider {
+    /** The Artifact. */
+    protected Artifact artifact;
+
+    /** The (native) facet. */
+    protected Facet    facet;
+
+    /** An alternative facet description that might be set from outside. */
+    protected String facetDescription;
+
+
+    /** Trivial constructor. */
+    public ArtifactAndFacet(
+        Artifact a,
+        Facet f
+    ) {
+        this.artifact   = a;
+        this.facet      = f;
+    }
+
+
+    /** Get data (to plot). */
+    public Object getData(CallContext context) {
+        return facet.getData(artifact, context);
+    }
+
+
+    /** Get data (for other facet). */
+    @Override
+    public Object provideData(Object key, Object param, CallContext context) {
+        return facet.provideBlackboardData(artifact, key, param, context);
+    }
+
+
+    /** (Maybe) Register on blackboard (depending on facet). */
+    @Override
+    public void register(CallContext context) {
+        List keys = facet.getDataProviderKeys(this.artifact, context);
+        if (keys == null) {
+            return;
+        }
+        for (Object key: keys) {
+            context.registerDataProvider(key, this);
+        }
+    }
+
+
+    /** Access the artifact. */
+    public Artifact getArtifact() {
+        return artifact;
+    }
+
+
+    /** Access the (native) facet. */
+    public Facet getFacet() {
+        return facet;
+    }
+
+
+    /** Shortcut to facets name. */
+    public String getFacetName() {
+        return facet.getName();
+    }
+
+
+    /**
+     * Returns the description for a facet. The return value depends on the
+     * internal <i>facetDescription</i> instance variable. If this has been set
+     * by setFacetDescription, this value is returned, otherwise the return
+     * value of facet.getDescription().
+     */
+    public String getFacetDescription() {
+        if (facetDescription == null) {
+            return facet.getDescription();
+        }
+
+        return facetDescription;
+    }
+
+
+    public void setFacetDescription(String facetDescription) {
+        this.facetDescription = facetDescription;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Attribute.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Attribute.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,43 @@
+package de.intevation.artifactdatabase.state;
+
+import java.io.Serializable;
+
+import org.w3c.dom.Node;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface Attribute extends Serializable {
+
+    /**
+     * Returns the name of this Attribute.
+     *
+     * @return the name of this Attribute.
+     */
+    String getName();
+
+    /**
+     * Returns the value of this Attribute.
+     *
+     * @return the value of this Attribute.
+     */
+    Object getValue();
+
+    /**
+     * Sets the value of this Attribute.
+     *
+     * @param value The new value.
+     */
+    void setValue(Object value);
+
+    /**
+     * Transforms this Attribute into XML.
+     *
+     * @param parent The parent node.
+     *
+     * @return the Node that represents this Attribute.
+     */
+    Node toXML(Node parent);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultAttribute.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultAttribute.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,54 @@
+package de.intevation.artifactdatabase.state;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultAttribute implements Attribute {
+
+    protected String name;
+
+    protected Object value;
+
+
+    public DefaultAttribute(String name, Object value) {
+        this.name  = name;
+        this.value = value;
+    }
+
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+
+    @Override
+    public Object getValue() {
+        return value;
+    }
+
+
+    @Override
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+
+    @Override
+    public Node toXML(Node parent) {
+        Document owner = parent.getOwnerDocument();
+        Element   attr = owner.createElement(getName());
+
+        parent.appendChild(attr);
+
+        attr.setTextContent(String.valueOf(getValue()));
+
+        return attr;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultFacet.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultFacet.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,168 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+
+/**
+ * The default implementation of a Facet.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultFacet implements Facet {
+
+    /** The index of this facet. */
+    protected int index;
+
+    /** The name of this facet. */
+    protected String name;
+
+    /** The description of this facet. */
+    protected String description;
+
+
+    /** Trivial, empty constructor. */
+    public DefaultFacet() {
+    }
+
+
+    /**
+     * The default constructor to create new Facet objects.
+     *
+     * @param name The name of this new facet.
+     * @param description The description of this new facet.
+     */
+    public DefaultFacet(String name, String description) {
+        this(0, name, description);
+    }
+
+
+    /**
+     * The default constructor to create new Facet objects.
+     *
+     * @param index The index of this new facet.
+     * @param name The name of this new facet.
+     * @param description The description of this new facet.
+     */
+    public DefaultFacet(int index, String name, String description) {
+        this.index       = index;
+        this.name        = name;
+        this.description = description;
+    }
+
+
+    /** Get index. */
+    public int getIndex() {
+        return index;
+    }
+
+
+    /** Returns the name ('type'). */
+    public String getName() {
+        return name;
+    }
+
+
+    /** Returns the description (e.g. displayed in gui). */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * @return null
+     */
+    public Object getData(Artifact artifact, CallContext context) {
+        return null;
+    }
+
+
+    /**
+     * (Do not) provide data.
+     * Override to allow other facets to access your data.
+     * @return always null.
+     */
+    public Object provideBlackboardData(
+        Artifact artifact,
+        Object key,
+        Object param,
+        CallContext context
+    ) {
+        return null;
+    }
+
+
+    /*
+     * Return list of keys (objects) for which this facet can provide data
+     * ("external parameterization"), for other facets, via blackboard.
+     * These are the keys that are independent from the current call (thus
+     * 'static').
+     * @param artifact that this facet belongs to.
+     */
+    public List getStaticDataProviderKeys(Artifact artifact) {
+        return null;
+    }
+
+    /**
+     * Return list of keys (objects) for which this facet can provide data
+     * ("external parameterization"), for other facets, via blackboard.
+     * @param artifact that this facet belongs to.
+     */
+    public List getDataProviderKeys(Artifact artifact, CallContext context) {
+        return getStaticDataProviderKeys(artifact);
+    }
+
+
+    /** Create a xml represantation. */
+    public Node toXML(Document doc) {
+        ElementCreator ec = new ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element facet = ec.create("facet");
+        ec.addAttr(facet, "description", description, true);
+        ec.addAttr(facet, "name", name, true);
+        ec.addAttr(facet, "index", String.valueOf(index), true);
+
+        return facet;
+    }
+
+
+    /** Create a string representation. */
+    public String toString() {
+        return new StringBuilder("name = '")
+            .append(name).append("', index = ")
+            .append(index).append(", description = '")
+            .append(description).append("'")
+            .toString();
+    }
+
+
+    /**
+     * Copies name, index and description of other facet.
+     */
+    public void set(Facet other) {
+        index       = other.getIndex();
+        name        = other.getName();
+        description = other.getDescription();
+    }
+
+
+    /** Create a deep copy of this facet. */
+    public Facet deepCopy() {
+        DefaultFacet copy = new DefaultFacet();
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultOutput.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultOutput.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,164 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The default implementation of an Output.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultOutput implements Output {
+
+    protected String name;
+
+    protected String description;
+
+    protected String mimeType;
+
+    protected String type;
+
+    protected List<Facet> facets;
+
+    protected Settings settings;
+
+
+    /**
+     * The default constructor that instantiates a new DefaultOutput object.
+     *
+     * @param name The name of this output.
+     * @param description The description of this output.
+     * @param mimeType The mimetype of this output.
+     */
+    public DefaultOutput(String name, String description, String mimeType) {
+        this.name        = name;
+        this.description = description;
+        this.mimeType    = mimeType;
+        this.type        = "";
+        this.facets      = new ArrayList<Facet>();
+    }
+
+
+    public DefaultOutput(
+        String      name,
+        String      description,
+        String      mimeType,
+        String      type)
+    {
+        this(name, description, mimeType);
+
+        this.facets = new ArrayList<Facet>();
+        this.type   = type;
+    }
+
+
+    public DefaultOutput(
+        String      name,
+        String      description,
+        String      mimeType,
+        List<Facet> facets)
+    {
+        this(name, description, mimeType);
+
+        this.type   = "";
+        this.facets = facets;
+    }
+
+
+    /**
+     * This constructor builds a new Output object that contains facets as well.
+     *
+     * @param name The name of this output.
+     * @param description The description of this output.
+     * @param mimeType The mimetype of this output.
+     * @param facets The list of facets supported by this output.
+     * @param type The type of the Output e.g. chart
+     */
+    public DefaultOutput(
+        String      name,
+        String      description,
+        String      mimeType,
+        List<Facet> facets,
+        String      type)
+    {
+        this(name, description, mimeType, facets);
+
+        this.type = type;
+    }
+
+
+    /**
+     * Returns the name of this output.
+     *
+     * @return the name of this output.
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Returns the description of this output.
+     *
+     * @return the description of this output.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the mimetype of this output.
+     *
+     * @return the mimetype of this output.
+     */
+    public String getMimeType() {
+        return mimeType;
+    }
+
+
+    public String getType() {
+        return type;
+    }
+
+
+    /**
+     * Returns the list of facets supported by this output.
+     *
+     * @return the list of facets supported by this output.
+     */
+    public List<Facet> getFacets() {
+        return facets;
+    }
+
+
+    public void addFacet(Facet facet) {
+        if (facet != null && !facets.contains(facet)) {
+            facets.add(facet);
+        }
+    }
+
+
+    public void addFacets(List<Facet> facets) {
+        this.facets.addAll(facets);
+    }
+
+
+    @Override
+    public void setFacets(List<Facet> facets) {
+        this.facets = facets;
+    }
+
+
+    @Override
+    public void setSettings(Settings settings) {
+        this.settings = settings;
+    }
+
+
+    @Override
+    public Settings getSettings() {
+        return settings;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultSection.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultSection.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,112 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Attributes keep the order in which they were inserted.
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultSection implements Section {
+
+    protected String id;
+
+    protected List<Section> subsections;
+
+    /** Attribute-map. */
+    protected Map<String, Attribute> attributes;
+
+
+    /**
+     * Creates a new DefaultSection instance. <b>Note, that the <i>id</i> is used
+     * as Node name of the new Element that is created in toXML().</b>
+     */
+    public DefaultSection(String id) {
+        this.id          = id;
+        // Use LinkedHashMap to keep insertion order.
+        this.attributes  = new LinkedHashMap<String, Attribute>();
+        this.subsections = new ArrayList<Section>();
+    }
+
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+
+    @Override
+    public void addSubsection(Section subsection) {
+        if (subsection != null) {
+            subsections.add(subsection);
+        }
+    }
+
+
+    @Override
+    public int getSubsectionCount() {
+        return subsections.size();
+    }
+
+
+    @Override
+    public Section getSubsection(int pos) {
+        if (pos >= 0 && pos < getSubsectionCount()) {
+            return subsections.get(pos);
+        }
+
+        return null;
+    }
+
+
+    /** Adding attribute to end of list. */
+    @Override
+    public void addAttribute(String key, Attribute attribute) {
+        if (key != null && key.length() > 0 && attribute != null) {
+            attributes.put(key, attribute);
+        }
+    }
+
+
+    @Override
+    public Attribute getAttribute(String key) {
+        if (key == null || key.length() == 0) {
+            return null;
+        }
+
+        return attributes.get(key);
+    }
+
+
+    @Override
+    public Set<String> getKeys() {
+        return attributes.keySet();
+    }
+
+
+    @Override
+    public void toXML(Node parent) {
+        Document owner     = parent.getOwnerDocument();
+        Element  sectionEl = owner.createElement(getId());
+
+        parent.appendChild(sectionEl);
+
+        for (String key: getKeys()) {
+            Attribute attr = getAttribute(key);
+            attr.toXML(sectionEl);
+        }
+
+        for (int i = 0, n = getSubsectionCount(); i < n; i++) {
+            Section subsection = getSubsection(i);
+            subsection.toXML(sectionEl);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultSettings.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/DefaultSettings.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,62 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultSettings implements Settings {
+
+    protected List<Section> sections;
+
+    public DefaultSettings() {
+        sections = new ArrayList<Section>();
+    }
+
+    @Override
+    public void addSection(Section section) {
+        if (section != null) {
+            sections.add(section);
+        }
+    }
+
+    @Override
+    public int getSectionCount() {
+        return sections.size();
+    }
+
+    @Override
+    public Section getSection(int pos) {
+        if (pos >= 0 && pos < getSectionCount()) {
+            return sections.get(pos);
+        }
+
+        return null;
+    }
+
+    @Override
+    public void removeSection(Section section) {
+        if (section != null) {
+            sections.remove(section);
+        }
+    }
+
+    @Override
+    public void toXML(Node parent) {
+        Document owner    = parent.getOwnerDocument();
+        Element  settings = owner.createElement("settings");
+
+        parent.appendChild(settings);
+
+        for (Section section: sections) {
+            section.toXML(settings);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Facet.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Facet.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,90 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.List;
+
+import java.io.Serializable;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface Facet extends Serializable {
+
+    /**
+     * Returns the index of this facet.
+     *
+     * @return the index of this facet.
+     */
+    int getIndex();
+
+    /**
+     * Returns the name of this facet.
+     *
+     * @return the name of this facet.
+     */
+    String getName();
+
+
+    /**
+     * Returns the description of this facet.
+     *
+     * @return the description of this facet.
+     */
+    String getDescription();
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact The owner artifact.
+     * @param context The CallContext.
+     *
+     * @return the data.
+     */
+    Object getData(Artifact artifact, CallContext context);
+
+
+    /**
+     * Get keys for which this Facet can provide data (for other facets, not
+     * for plot).
+     * @param artifact Artifact that this facet belongs to.
+     * @return list of keys
+     */
+    List getDataProviderKeys(Artifact artifact, CallContext context);
+
+
+    /**
+     * Provide data to other facet.
+     *
+     * @param art  The artifact that this facet belongs to.
+     * @param key  the key of the requested service.
+     * @param prm  optional parameters.
+     * @param ctxt the callcontext.
+     *
+     * @return the data
+     */
+    Object provideBlackboardData(
+        Artifact art,
+        Object key,
+        Object prm,
+        CallContext ctxt);
+
+
+    /**
+     * Write the internal representation of a facet to a node.
+     *
+     * @param doc A Document.
+     *
+     * @return the representation as Node.
+     */
+    Node toXML(Document doc);
+
+    Facet deepCopy();
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/FacetActivity.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/FacetActivity.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,111 @@
+package de.intevation.artifactdatabase.state;
+
+import de.intevation.artifacts.Artifact;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * System used in practice used by AttributeWriter in flys-artifacts to decide
+ * whether a facet is initially active.
+ * Provides a singleton Registry into which FacetActivities can be registered
+ * under a key (in practice the artifacts name.  This Registry is queried for
+ * new Facets in order to find whether they are active or inactive.
+ */
+public interface FacetActivity
+{
+    /** Static 'activity' that lets all facets be active. */
+    public static final FacetActivity ACTIVE = new FacetActivity() {
+        @Override
+        public Boolean isInitialActive(
+            Artifact artifact,
+            Facet    facet,
+            String   output
+        ) {
+            return Boolean.TRUE;
+        }
+    };
+
+    /** Static 'activity' that lets all facets be inactive. */
+    public static final FacetActivity INACTIVE = new FacetActivity() {
+        @Override
+        public Boolean isInitialActive(
+            Artifact artifact,
+            Facet    facet,
+            String   output
+        ) {
+            return Boolean.FALSE;
+        }
+    };
+
+    Boolean isInitialActive(Artifact artifact, Facet facet, String output);
+
+    /** Singleton registry, that maps artifact names to the activities, which
+     * decide whether or not a facet should be (initially) active. */
+    public static final class Registry {
+
+        /** The logger for this class. */
+        private static Logger logger = Logger.getLogger(Registry.class);
+
+        /** Singleton instance. */
+        private static final Registry INSTANCE = new Registry();
+
+        /** Map of keys (artifact names) to the activities. */
+        private Map<String, List<FacetActivity>> activities;
+
+        /** Private singleton constructor for the Facet-Activity-Registry. */
+        private Registry() {
+            activities = new HashMap<String, List<FacetActivity>>();
+        }
+
+        /** Access Singleton instance. */
+        public static Registry getInstance() {
+            return INSTANCE;
+        }
+
+        /** Queries whether a given facet should be active or not. */
+        public synchronized boolean isInitialActive(
+            String   key,
+            Artifact artifact,
+            Facet    facet,
+            String   output
+        ) {
+            List<FacetActivity> activityList = activities.get(key);
+            if (activityList == null) {
+                logger.debug("FacetActivity.Registry: No activity " +
+                             "registered for " + key);
+                return true;
+            }
+            if (activityList.size() != 1) {
+                logger.warn("FacetActivity.Registry: More than one " +
+                            "FacetActivity registered for " + key);
+            }
+            for (FacetActivity activity: activityList) {
+                Boolean isActive =
+                    activity.isInitialActive(artifact, facet, output);
+                // Nice. Only, in practice they never return NULL.
+                if (isActive != null) {
+                    return isActive;
+                }
+            }
+            return true;
+        }
+
+
+        /** Add a FacetActivity under given key (usually artifacts name). */
+        public synchronized void register(String key, FacetActivity activity) {
+            List<FacetActivity> activityList = activities.get(key);
+            if (activityList == null) {
+                activityList = new ArrayList<FacetActivity>(3);
+                activities.put(key, activityList);
+            }
+            activityList.add(activity);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Output.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Output.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,80 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.List;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface Output {
+
+    /**
+     * Retrieve the name of this output mode.
+     *
+     * @return the name of this output mode.
+     */
+    public String getName();
+
+    /**
+     * Retrieve the description of an output.
+     *
+     * @return the description.
+     */
+    public String getDescription();
+
+    /**
+     * Retrieve the mimetype used for the output.
+     *
+     * @return the mimetype.
+     */
+    public String getMimeType();
+
+
+    /**
+     * Returns the type of this output.
+     *
+     * @return the type.
+     */
+    public String getType();
+
+    /**
+     * Retrieve the facets of this output.
+     *
+     * @return the facets of this output.
+     */
+    public List<Facet> getFacets();
+
+    /**
+     * Add a new facet to this output.
+     *
+     * @param facet The new facet.
+     */
+    public void addFacet(Facet facet);
+
+    /**
+     * Add a list of facet to this output.
+     *
+     * @param facets A list of facets.
+     */
+    public void addFacets(List<Facet> facets);
+
+    /**
+     * Replaces the old list of facets with a new one.
+     *
+     * @param facets A list of new facets.
+     */
+    public void setFacets(List<Facet> facets);
+
+    /**
+     * Returns a Settings object for this Output.
+     */
+    public Settings getSettings();
+
+    /**
+     * Sets the Settings for this Output.
+     *
+     * @param settings the Settings for this Output.
+     */
+    public void setSettings(Settings settings);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Section.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Section.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,76 @@
+package de.intevation.artifactdatabase.state;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import org.w3c.dom.Node;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface Section extends Serializable {
+
+    /**
+     * Returns an ID for this Section.
+     *
+     * @return an ID for this Section.
+     */
+    String getId();
+
+    /**
+     * Adds a new subsection to this Section object.
+     *
+     * @param subsection the new Section.
+     */
+    void addSubsection(Section subsection);
+
+    /**
+     * Returns the number of subsections in this Section.
+     *
+     * @return the number of subsections.
+     */
+    int getSubsectionCount();
+
+    /**
+     * Returns a subsection at position <i>pos</i>.
+     *
+     * @param pos The position of the target subsection.
+     *
+     * @return the subsection at position <i>pos</i>.
+     */
+    Section getSubsection(int pos);
+
+    /**
+     * Adds a new Attribute to this Section.
+     *
+     * @param key The key that is used to store/retrieve the Attribute.
+     * @param attribute The new Attribute.
+     */
+    void addAttribute(String key, Attribute attribute);
+
+    /**
+     * Returns an Attribute for the specified <i>key</i>.
+     *
+     * @param key The key that is used to retrieve the target Attribute.
+     *
+     * @return the Attribute specified by <i>key</i>.
+     */
+    Attribute getAttribute(String key);
+
+    /**
+     * Returns all keys of all Attributes currently stored in this Section.
+     *
+     * @return all keys of all Attributes.
+     */
+    Set<String> getKeys();
+
+    /**
+     * Transforms this Section into XML using Attribute.toXML() for each
+     * Attribute and Section.toXML() for each subsection stored in this Section.
+     *
+     * @param parent The parent node.
+     */
+    void toXML(Node parent);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Settings.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/Settings.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,53 @@
+package de.intevation.artifactdatabase.state;
+
+import java.io.Serializable;
+
+import org.w3c.dom.Node;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface Settings extends Serializable {
+
+    /**
+     * Adds a new Section to this Settings object.
+     *
+     * @param section the new Section.
+     */
+    void addSection(Section section);
+
+    /**
+     * Returns the number of Sections in this Settings object.
+     *
+     * @return the number of sections.
+     */
+    int getSectionCount();
+
+    /**
+     * Returns the section at position <i>pos</i>.
+     *
+     * @param pos the position of the target Section.
+     *
+     * @return the Section at position <i>pos</i> or null if no Section is
+     * existing at <i>pos</i>.
+     */
+    Section getSection(int pos);
+
+    /**
+     * Removes a Section if it is existing in this Settings.
+     *
+     * @param section The section that should be removed.
+     */
+    void removeSection(Section section);
+
+    /**
+     * Transforms this Settings object into a XML representation. Therefore,
+     * each Section object's <i>toXML</i> method is called to append its XML
+     * representation to the final document.
+     *
+     * @param parent The parent node.
+     */
+    void toXML(Node parent);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/State.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/State.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,146 @@
+/*
+ * 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.artifactdatabase.state;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.data.StateData;
+
+
+/**
+ * This interface describes the basic methods a concrete state class needs to
+ * implement.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface State extends Serializable {
+
+    /**
+     * Return the id of the state.
+     *
+     * @return the id.
+     */
+    public String getID();
+
+
+    /**
+     * Return the description of the state.
+     *
+     * @return the description of the state.
+     */
+    public String getDescription();
+
+
+    /**
+     * Returns the help text configured for the state.
+     *
+     * @return the help text configured for the state.
+     */
+    public String getHelpText();
+
+
+    /**
+     * Returns the data provided by this state.
+     *
+     * @return the data stored in this state.
+     */
+    public Map<String, StateData> getData();
+
+
+    /**
+     * Returns a single desired StateData object based on its name.
+     *
+     * @param name The name of the desired StateData object.
+     *
+     * @return the desired StateData object.
+     */
+    public StateData getData(String name);
+
+
+    /**
+     * This method should be used to add a new {@link StateData} object to the
+     * data pool of the state.
+     *
+     * @param name The name of the data object.
+     * @param data The data object.
+     */
+    public void addData(String name, StateData data);
+
+
+    /**
+     * Returns the list of possible outputs of this state. The list is empty
+     * if no output is available for this state.
+     *
+     * @return a list of possible outputs of this state.
+     */
+    public List<Output> getOutputs();
+
+
+    /**
+     * Initialize the state based on the state node in the configuration.
+     *
+     * @param config The state configuration node.
+     */
+    public void setup(Node config);
+
+
+    /**
+     * Initializes the internal state of this State based on an other State.
+     *
+     * @param orig The owner Artifact or the original State.
+     * @param owner The owner Artifact of this State.
+     * @param context The context object.
+     * @param callMeta The CallMeta of the current call.
+     */
+    public void initialize(
+        Artifact orig,
+        Artifact owner,
+        Object   context,
+        CallMeta callMeta);
+
+
+    /**
+     * This method is called when an artifacts retrieves a describe request. It
+     * creates the user interface description of the current state.
+     *
+     * @param artifact A reference to the artifact this state belongs to.
+     * @param document Describe doucment.
+     * @param rootNode Parent node for all new elements.
+     * @param context The CallContext.
+     * @param uuid The uuid of an artifact.
+     */
+    public Element describe(
+        Artifact    artifact,
+        Document    document,
+        Node        rootNode,
+        CallContext context,
+        String      uuid
+    );
+
+
+    /**
+     * This method should be called by an Artifact that removes this State
+     * (current State and previous States). E.g. this might be interesting to
+     * remove generated files or stuff like that.
+     *
+     * @param artifact A parent Artifact.
+     * @param context The CallContext.
+     */
+    public void endOfLife(Artifact artifact, Object context);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/StateEngine.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/state/StateEngine.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,172 @@
+package de.intevation.artifactdatabase.state;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.data.StateData;
+
+
+/**
+ * The StateEngine stores all states and associated information about
+ * outputs and facets for each Artifact.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class StateEngine {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(StateEngine.class);
+
+    /**
+     * A map that contains the states of the artifacts. The key of this map is
+     * the name of an artifact, its value is a list of all states the artifact
+     * can reach.
+     */
+    protected Map<String, List<State>> states;
+
+
+    /**
+     * A map that contains all existing states. The key of this map is the ID of
+     * the state, its value is the state itself.
+     */
+    protected Map<String, State> allStates;
+
+
+    /**
+     * The default constructor.
+     */
+    public StateEngine() {
+        states    = new HashMap<String, List<State>>();
+        allStates = new HashMap<String, State>();
+    }
+
+
+    /**
+     * This method adds a state into the map <i>allStates</i>.
+     *
+     * @param state The state to add.
+     */
+    protected void addState(State state) {
+        allStates.put(state.getID(), state);
+    }
+
+
+    /**
+     * Returns the state based on its ID.
+     *
+     * @param stateId The ID of the desired state.
+     *
+     * @return the state.
+     */
+    public State getState(String stateId) {
+        return allStates.get(stateId);
+    }
+
+
+    public StateData getStateData(String artifact, String dataName) {
+        List<State> artifactStates = getStates(artifact);
+
+        if (artifactStates == null || artifactStates.size() == 0) {
+            logger.warn("No States for Artifact '" + artifact + "' existing.");
+            return null;
+        }
+
+        for (State state: artifactStates) {
+            StateData sd = state.getData(dataName);
+
+            if (sd != null) {
+                return sd;
+            }
+        }
+
+        logger.warn(
+            "No StateData for Artifact '" + artifact +
+            "' with name '" + dataName + "' existing.");
+
+        return null;
+    }
+
+
+    /**
+     * Add new states for a specific artifact.
+     *
+     * @param artifact The name of the artifact.
+     * @param states A list of states that the artifact can reach.
+     *
+     * @return true, if the states were added, otherwise false.
+     */
+    public boolean addStates(String artifact, List<State> states) {
+        List tmp = this.states.get(artifact);
+
+        if (tmp != null) {
+            logger.info(
+                "States for the artifact '" + artifact + "' already stored.");
+
+            return false;
+        }
+
+        // add the state to the map with all existing states
+        for (State s: states) {
+            addState(s);
+        }
+
+        logger.debug("Add new states for the artifact '" + artifact + "'");
+        return this.states.put(artifact, states) != null;
+    }
+
+
+    /**
+     * Returns the state list of an artifact specified by its name.
+     *
+     * @param artifact The name of the artifact (e.g. "winfo").
+     *
+     * @return the list of states of this artifact or <i>null</i> if no states
+     * are existing for this <i>artifact</i>.
+     */
+    public List<State> getStates(String artifact) {
+        return states.get(artifact);
+    }
+
+
+    /**
+     * Return mapping of output to facets for an artifact in its states.
+     */
+    public Map<String, List<String>> getCompatibleFacets(List<String> aStates) {
+        Map<String, List<String>> compatibilityMatrix =
+            new HashMap<String, List<String>>();
+
+        // For all states that the artifact had seen, add outputs facets.
+        logger.debug("Searching in " + aStates);
+        for (String stateId: aStates) {
+
+            State state = allStates.get(stateId);
+            if (state == null) {
+                logger.debug("No state found for id " + stateId);
+                continue;
+            }
+
+            for (Output output: state.getOutputs()) {
+                List<Facet> outFacets = output.getFacets();
+                logger.debug("Facets for output " + output.getName() + " :" + outFacets);
+
+                List<String> oldFacets = compatibilityMatrix.get(output.getName());
+
+                if (oldFacets == null) {
+                    oldFacets = new ArrayList<String>();
+                }
+
+                for (Facet facet: outFacets) {
+                    oldFacets.add(facet.getName());
+                }
+
+                compatibilityMatrix.put(output.getName(), oldFacets);
+            }
+        }
+        return compatibilityMatrix;
+    }
+}
+// vim:set ts=4 sw=4 et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/transition/Transition.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/transition/Transition.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,58 @@
+package de.intevation.artifactdatabase.transition;
+
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.Artifact;
+
+import de.intevation.artifactdatabase.state.State;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public interface Transition {
+
+    /**
+     * Initializes the transition.
+     *
+     * @param config The configuration node for the transition.
+     */
+    public void init(Node config);
+
+    /**
+     * Return the ID of the start State.
+     */
+    public String getFrom();
+
+    /**
+     * Return the ID of the target State.
+     */
+    public String getTo();
+
+    /**
+     * Set the ID of the current State.
+     *
+     * @param from The ID of the current state.
+     */
+    public void setFrom(String from);
+
+    /**
+     * Set the ID of the target State.
+     *
+     * @param to The ID of the target state.
+     */
+    public void setTo(String to);
+
+    /**
+     * Determines if its valid to step from state <i>a</i> of an artifact
+     * <i>artifact</i> to state <i>b</i>.
+     *
+     * @param artifact The owner artifact of state a and b.
+     * @param a The current state.
+     * @param b The target state.
+     *
+     * @return true, if it is valid to step from a to b, otherwise false.
+     */
+    public boolean isValid(Artifact artifact, State a, State b);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 783cc1b6b615 -r d0ac790a6c89 artifact-database/src/main/java/org/dive4elements/artifactdatabase/transition/TransitionEngine.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/transition/TransitionEngine.java	Thu Apr 25 10:57:18 2013 +0200
@@ -0,0 +1,141 @@
+package de.intevation.artifactdatabase.transition;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+
+import de.intevation.artifactdatabase.state.State;
+import de.intevation.artifactdatabase.state.StateEngine;
+
+
+/**
+ * The TransitionEngine stores all transitions for each Artifact and should be
+ * used to determine, if an Artifact is able to advance from one to another
+ * state.
+ *
+ * @author <a href="mailto:ingo.weinzierl at intevation.de">Ingo Weinzierl</a>
+ */
+public class TransitionEngine {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(TransitionEngine.class);
+
+    /**
+     * A map that contains the transitions of the artifacts. The key is the name
+     * of the artifact, its value is a list of all transitions of this artifact.
+     */
+    protected Map<String, List> transitions;
+
+
+    /**
+     * The default constructor.
+     */
+    public TransitionEngine() {
+        transitions = new HashMap<String, List>();
+    }
+
+
+    /**
+     * Add new transitions for a specific artifact.
+     *
+     * @param stateId the name of the Artifact.
+     * @param transition the list of transition of the artifact.
+     *
+     * @return true, if the transitions were added, otherwise false.
+     */
+    public boolean addTransition(String stateId, Transition transition) {
+        List tmp = transitions.get(stateId);
+
+        if (tmp == null) {
+            tmp = new ArrayList<Transition>();
+        }
+
+        tmp.add(transition);
+
+        logger.debug("Add new transitions for state '" + stateId + "'");
+
+        return transitions.put(stateId, tmp) != null;
+    }
+
+
+    /**
+     * This method returns all existing transitions of a state.
+     *
+     * @param state The state
+     *
+     * @return the existing transition of <i>state</i>.
+     */
+    public List<Transition> getTransitions(State state) {
+        return transitions.get(state.getID());
+    }
+
+
+    /**
+     * This method returns the reachable states of <i>state</i>.
+     *
+     * @param state The current state.
+     * @param engine The state engine.
+     *
+     * @return a list of reachable states.
+     */
+    public List<State> getReachableStates(
+        Artifact    artifact,
+        State       state,
+        StateEngine engine) {
+        List<Transition> transitions = getTransitions(state);
+        List<State>      reachable   = new ArrayList<State>();
+
+        if (transitions == null) {
+            return reachable;
+        }
+
+        for (Transition t: transitions) {
+            State target = engine.getState(t.getTo());
+
+            if (t.isValid(artifact, state, target)) {
+                reachable.add(target);
+            }
+        }
+
+        return reachable;
+    }
+
+
+    /**
+     * Determines if a state with a given identifier is reachable from a current
+     * state.
+     *
+     * @param artifact The owner artifact of state <i>state</i>.
+     * @param targetId The identifier of the target state.
+     * @param state The start state.
+     * @param stateEngine The StateEngine.
+     *
+     * @return true, if the target state is reachable, otherwise false.
+     */
+    public boolean isStateReachable(
+        Artifact    artifact,
+        String      targetId,
+        State       state,
+        StateEngine stateEngine)
+    {
+        List<State> reachable = getReachableStates(artifact, state,stateEngine);
+
+        if (reachable == null || reachable.size() == 0) {
+            return false;
+        }
+
+        for (State s: reachable) {
+            if (targetId.equals(s.getID())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :


More information about the Dive4elements-commits mailing list