[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