diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java @ 3318:dbe2f85bf160

merged flys-artifacts/2.8
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:35 +0200
parents 5642a83420f2
children cbe2febe30cc
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java	Fri Sep 28 12:14:35 2012 +0200
@@ -0,0 +1,1074 @@
+package de.intevation.flys.artifacts.datacage;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Date;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Types;
+import java.sql.Timestamp;
+
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.ArtifactCollection;
+import de.intevation.artifacts.User;
+
+import de.intevation.artifactdatabase.db.SQL;
+import de.intevation.artifactdatabase.db.SQLExecutor;
+
+import de.intevation.artifactdatabase.LifetimeListener;
+import de.intevation.artifactdatabase.Backend;
+
+import de.intevation.artifactdatabase.data.StateData;
+
+import de.intevation.artifactdatabase.state.Output;
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.artifacts.common.utils.LRUCache;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+public class Datacage
+implements   LifetimeListener
+{
+    private static Logger log = Logger.getLogger(Datacage.class);
+
+    public static final String DATACAGE_KEY =
+        "global.datacage.instance";
+
+    public static final String ARTEFACT_DATABASE_KEY =
+        "global.artifact.database";
+
+    private String SQL_DELETE_ALL_USERS      = "delete.all.users";
+    private String SQL_DELETE_ALL_ARTIFACTS  = "delete.all.artifacts";
+    private String SQL_USER_ID_NEXTVAL       = "user.id.nextval";
+    private String SQL_USER_BY_GID           = "user.by.gid";
+    private String SQL_INSERT_USER           = "insert.user";
+    private String SQL_COLLECTION_BY_GID     = "collection.by.gid";
+    private String SQL_COLLECTION_ID_NEXTVAL = "collection.id.nextval";
+    private String SQL_INSERT_COLLECTION     = "insert.collection";
+    private String SQL_ARTIFACT_BY_GID       = "artifact.by.gid";
+    private String SQL_COLLECTION_ITEM_ID_NEXTVAL =
+        "collection.item.id.nextval";
+    private String SQL_INSERT_COLLECTION_ITEM = "insert.collection.item";
+    private String SQL_ARTIFACT_ID_NEXTVAL    = "artifact.id.nextval";
+    private String SQL_INSERT_ARTIFACT        = "insert.artifact";
+    private String SQL_ARTIFACT_DATA_ID_NEXTVAL = "artifact.data.id.nextval";
+    private String SQL_INSERT_ARTIFACT_DATA   = "insert.artifact.data";
+    private String SQL_OUT_ID_NEXTVALUE       = "out.id.nextval";
+    private String SQL_INSERT_OUT             = "insert.out";
+    private String SQL_FACET_ID_NEXTVAL       = "facet.id.nextval";
+    private String SQL_INSERT_FACET           = "insert.facet";
+    private String SQL_UPDATE_COLLECTION_NAME = "update.collection.name";
+    private String SQL_DELETE_ARTIFACT_FROM_COLLECTION =
+        "delete.artifact.from.collection";
+    private String SQL_DELETE_COLLECTION_BY_GID =
+        "delete.collection.by.gid";
+    private String SQL_DELETE_USER_BY_GID = "delete.user.by.gid";
+    private String SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID =
+        "delete.artifact.data.by.artifact.id";
+    private String SQL_DELETE_OUTS_BY_ARTIFACT_ID =
+        "delete.outs.by.artifact.id";
+    private String SQL_DELETE_FACETS_BY_ARTIFACT_ID =
+        "delete.facets.by.artifact.id";
+    private String SQL_DELETE_ARTIFACT_BY_GID =
+        "delete.artifact.by.gid";
+
+    protected SQLExecutor sqlExecutor;
+
+    public class InitialScan
+    implements   ArtifactDatabase.ArtifactLoadedCallback
+    {
+        protected LRUCache<String, Integer> users;
+        protected LRUCache<String, Integer> collections;
+        protected LRUCache<String, Integer> artifacts;
+
+        protected GlobalContext context;
+
+        public InitialScan() {
+            users       = new LRUCache<String, Integer>();
+            collections = new LRUCache<String, Integer>();
+            artifacts   = new LRUCache<String, Integer>();
+        }
+
+        public InitialScan(GlobalContext context) {
+            this();
+            this.context = context;
+        }
+
+        @Override
+        public void artifactLoaded(
+            String   userId,
+            String   collectionId,
+            String   collectionName,
+            Date     collectionCreated,
+            String   artifactId,
+            Date     artifactCreated,
+            Artifact artifact
+        ) {
+            if (!(artifact instanceof FLYSArtifact)) {
+                log.warn("ignoring none FLYS artifacts");
+                return;
+            }
+
+            FLYSArtifact flysArtifact = (FLYSArtifact)artifact;
+
+            Integer uId = getUserId(userId);
+            Integer cId = getCollectionId(
+                collectionId, uId, collectionName, collectionCreated);
+
+            storeArtifact(artifactId, cId, flysArtifact, artifactCreated);
+        }
+
+        protected Integer getId(
+            LRUCache<String, Integer> cache,
+            final String              idString,
+            final String              selectById
+        ) {
+            Integer id = cache.get(idString);
+            if (id != null) {
+                return id;
+            }
+
+            final Integer [] res = new Integer[1];
+
+            SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+                @Override
+                public boolean doIt() throws SQLException {
+                    prepareStatement(selectById);
+                    stmnt.setString(1, idString);
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        return false;
+                    }
+                    res[0] = result.getInt(1);
+                    return true;
+                }
+            };
+
+            if (exec.runRead()) {
+                cache.put(idString, res[0]);
+                return res[0];
+            }
+
+            return null;
+        }
+
+        protected void storeArtifact(
+            final String       artifactId,
+            Integer            collectionId,
+            final FLYSArtifact artifact,
+            final Date         artifactCreated
+        ) {
+            Integer aId = getId(artifacts, artifactId, SQL_ARTIFACT_BY_GID);
+
+            if (aId != null) {
+                // We've already stored it. Just create the collection item.
+                storeCollectionItem(collectionId, aId);
+                return;
+            }
+            // We need to write it to database
+
+            final Integer [] res = new Integer[1];
+
+            SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+                @Override
+                public boolean doIt() throws SQLException {
+                    prepareStatement(SQL_ARTIFACT_ID_NEXTVAL);
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        return false;
+                    }
+                    res[0] = result.getInt(1);
+                    reset();
+                    prepareStatement(SQL_INSERT_ARTIFACT);
+                    stmnt.setInt   (1, res[0]);
+                    stmnt.setString(2, artifactId);
+                    stmnt.setString(3, artifact.getCurrentStateId());
+                    Timestamp timestamp = new Timestamp(artifactCreated != null
+                        ? artifactCreated.getTime()
+                        : System.currentTimeMillis());
+                    stmnt.setTimestamp(4, timestamp);
+                    stmnt.execute();
+                    conn.commit();
+                    return true;
+                }
+            };
+
+            if (!exec.runWrite()) {
+                log.error("storing of artifact failed.");
+                return;
+            }
+
+            artifacts.put(artifactId, aId = res[0]);
+
+            storeCollectionItem(collectionId, aId);
+
+            storeData(aId, artifact);
+
+            storeOuts(aId, artifact, context);
+        }
+
+
+        protected void storeCollectionItem(
+            final Integer collectionId,
+            final Integer artifactId
+        ) {
+            SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+                @Override
+                public boolean doIt() throws SQLException {
+                    prepareStatement(SQL_COLLECTION_ITEM_ID_NEXTVAL);
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        return false;
+                    }
+                    int ciId = result.getInt(1);
+                    reset();
+                    prepareStatement(SQL_INSERT_COLLECTION_ITEM);
+                    stmnt.setInt(1, ciId);
+                    stmnt.setInt(2, collectionId);
+                    stmnt.setInt(3, artifactId);
+                    stmnt.execute();
+                    conn.commit();
+                    return true;
+                }
+            };
+
+            if (!exec.runWrite()) {
+                log.error("storing of collection item failed.");
+            }
+        }
+
+        protected Integer getCollectionId(
+            final String  collectionId,
+            final Integer ownerId,
+            final String  collectionName,
+            final Date    collectionCreated
+        ) {
+            Integer c = getId(collections, collectionId, SQL_COLLECTION_BY_GID);
+
+            if (c != null) {
+                return c;
+            }
+
+            final Integer [] res = new Integer[1];
+
+            SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+                @Override
+                public boolean doIt() throws SQLException {
+                    prepareStatement(SQL_COLLECTION_ID_NEXTVAL);
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        return false;
+                    }
+                    res[0] = result.getInt(1);
+                    reset();
+                    prepareStatement(SQL_INSERT_COLLECTION);
+                    stmnt.setInt   (1, res[0]);
+                    stmnt.setString(2, collectionId);
+                    stmnt.setInt   (3, ownerId);
+                    setString(stmnt, 4, collectionName);
+                    Timestamp timestamp = new Timestamp(collectionCreated != null
+                        ? collectionCreated.getTime()
+                        : System.currentTimeMillis());
+                    stmnt.setTimestamp(5, timestamp);
+                    stmnt.execute();
+                    conn.commit();
+                    return true;
+                }
+            };
+
+            if (exec.runWrite()) {
+                collections.put(collectionId, res[0]);
+                return res[0];
+            }
+
+            return null;
+        }
+
+        protected Integer getUserId(final String userId) {
+
+            Integer u = getId(users, userId, SQL_USER_BY_GID);
+
+            if (u != null) {
+                return u;
+            }
+
+            final Integer [] res = new Integer[1];
+
+            SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+                @Override
+                public boolean doIt() throws SQLException {
+                    prepareStatement(SQL_USER_ID_NEXTVAL);
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        return false;
+                    }
+                    res[0] = result.getInt(1);
+                    reset();
+                    prepareStatement(SQL_INSERT_USER);
+                    stmnt.setInt   (1, res[0]);
+                    stmnt.setString(2, userId);
+                    stmnt.execute();
+                    conn.commit();
+                    return true;
+                }
+            };
+
+            if (exec.runWrite()) {
+                users.put(userId, res[0]);
+                return res[0];
+            }
+
+            return null;
+        }
+
+        public boolean scan(ArtifactDatabase adb) {
+            log.debug("scan");
+            try {
+                adb.loadAllArtifacts(this);
+            }
+            catch (ArtifactDatabaseException ade) {
+                log.error(ade);
+                return false;
+            }
+            return true;
+        }
+    } // class InitialScan
+
+
+    public Datacage() {
+    }
+
+    @Override
+    public void setup(Document document) {
+        log.debug("setup");
+        DBConfig config = DBConfig.getInstance();
+        setupSQL(config.getSQL());
+        sqlExecutor = new SQLExecutor(config.getDBConnection());
+    }
+
+    protected void setupSQL(SQL sql) {
+        SQL_DELETE_ALL_USERS      = sql.get(SQL_DELETE_ALL_USERS);
+        SQL_DELETE_ALL_ARTIFACTS  = sql.get(SQL_DELETE_ALL_ARTIFACTS);
+        SQL_USER_ID_NEXTVAL       = sql.get(SQL_USER_ID_NEXTVAL);
+        SQL_USER_BY_GID           = sql.get(SQL_USER_BY_GID);
+        SQL_INSERT_USER           = sql.get(SQL_INSERT_USER);
+        SQL_COLLECTION_BY_GID     = sql.get(SQL_COLLECTION_BY_GID);
+        SQL_COLLECTION_ID_NEXTVAL = sql.get(SQL_COLLECTION_ID_NEXTVAL);
+        SQL_INSERT_COLLECTION     = sql.get(SQL_INSERT_COLLECTION);
+        SQL_ARTIFACT_BY_GID       = sql.get(SQL_ARTIFACT_BY_GID);
+        SQL_COLLECTION_ITEM_ID_NEXTVAL =
+            sql.get(SQL_COLLECTION_ITEM_ID_NEXTVAL);
+        SQL_INSERT_COLLECTION_ITEM =
+            sql.get(SQL_INSERT_COLLECTION_ITEM);
+        SQL_ARTIFACT_ID_NEXTVAL = sql.get(SQL_ARTIFACT_ID_NEXTVAL);
+        SQL_INSERT_ARTIFACT     = sql.get(SQL_INSERT_ARTIFACT);
+        SQL_ARTIFACT_DATA_ID_NEXTVAL = sql.get(SQL_ARTIFACT_DATA_ID_NEXTVAL);
+        SQL_INSERT_ARTIFACT_DATA = sql.get(SQL_INSERT_ARTIFACT_DATA);
+        SQL_OUT_ID_NEXTVALUE     = sql.get(SQL_OUT_ID_NEXTVALUE);
+        SQL_INSERT_OUT           = sql.get(SQL_INSERT_OUT);
+        SQL_FACET_ID_NEXTVAL     = sql.get(SQL_FACET_ID_NEXTVAL);
+        SQL_INSERT_FACET         = sql.get(SQL_INSERT_FACET);
+        SQL_UPDATE_COLLECTION_NAME = sql.get(SQL_UPDATE_COLLECTION_NAME);
+        SQL_DELETE_ARTIFACT_FROM_COLLECTION =
+            sql.get(SQL_DELETE_ARTIFACT_FROM_COLLECTION);
+        SQL_DELETE_COLLECTION_BY_GID = sql.get(SQL_DELETE_COLLECTION_BY_GID);
+        SQL_DELETE_USER_BY_GID       = sql.get(SQL_DELETE_USER_BY_GID);
+        SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID =
+            sql.get(SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID);
+        SQL_DELETE_OUTS_BY_ARTIFACT_ID =
+            sql.get(SQL_DELETE_OUTS_BY_ARTIFACT_ID);
+        SQL_DELETE_FACETS_BY_ARTIFACT_ID =
+            sql.get(SQL_DELETE_FACETS_BY_ARTIFACT_ID);
+        SQL_DELETE_ARTIFACT_BY_GID =
+            sql.get(SQL_DELETE_ARTIFACT_BY_GID);
+    }
+
+    protected static final int numFacets(List<Output> outs) {
+        int sum = 0;
+        for (Output out: outs) {
+            sum += out.getFacets().size();
+        }
+        return sum;
+    }
+
+    protected static final void setString(
+        PreparedStatement stmnt,
+        int               index,
+        Object            value
+    )
+    throws SQLException
+    {
+        if (value == null) {
+            stmnt.setNull(index, Types.VARCHAR);
+        }
+        else {
+            stmnt.setString(index, value.toString());
+        }
+    }
+
+    @Override
+    public void systemUp(GlobalContext context) {
+        log.debug("systemUp entered");
+        initialScan(context);
+        context.put(DATACAGE_KEY, this);
+        log.debug("systemUp leaved");
+    }
+
+    protected void initialScan(GlobalContext context) {
+        log.debug("initialScan");
+
+        Object adbObject = context.get(ARTEFACT_DATABASE_KEY);
+
+        if (!(adbObject instanceof ArtifactDatabase)) {
+            log.error("missing artefact database. Cannot scan");
+            return;
+        }
+
+        ArtifactDatabase adb = (ArtifactDatabase)adbObject;
+
+        if (!cleanDatabase()) {
+            log.error("cleaning database failed");
+            return;
+        }
+
+        InitialScan is = new InitialScan(context);
+
+        if (!is.scan(adb)) {
+            log.error("initial scan failed");
+            return;
+        }
+
+    }
+
+    protected boolean cleanDatabase() {
+
+        log.debug("cleanDatabase");
+
+        boolean success = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_DELETE_ALL_USERS);
+                stmnt.execute();
+                prepareStatement(SQL_DELETE_ALL_ARTIFACTS);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        }.runWrite();
+
+        log.debug("after runWrite(): " + success);
+
+        return success;
+    }
+
+
+    @Override
+    public void systemDown(GlobalContext context) {
+        log.debug("systemDown");
+    }
+
+    public void setup(GlobalContext globalContext) {
+        log.debug("setup");
+    }
+
+    public void createdArtifact(
+        Artifact      artifact,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("createdArtifact");
+
+        if (artifact == null) {
+            log.warn("artifact to create is null");
+            return;
+        }
+
+        if (!(artifact instanceof FLYSArtifact)) {
+            log.warn("need FLYSArtifact here (have " + artifact.getClass() + ")");
+            return;
+        }
+
+        final FLYSArtifact flys = (FLYSArtifact)artifact;
+
+        final int [] res = new int[1];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_ARTIFACT_ID_NEXTVAL);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    log.error("id generation for artifact failed");
+                    return false;
+                }
+                res[0] = result.getInt(1);
+                reset();
+                prepareStatement(SQL_INSERT_ARTIFACT);
+                stmnt.setInt      (1, res[0]);
+                stmnt.setString   (2, flys.identifier());
+                stmnt.setString   (3, flys.getCurrentStateId());
+                stmnt.setTimestamp(4,
+                    new Timestamp(System.currentTimeMillis()));
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("storing of artifact failed.");
+            return;
+        }
+
+        storeData(res[0], flys);
+        storeOuts(res[0], flys, context);
+    }
+
+    public void storedArtifact(
+        Artifact      artifact,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("storedArtifact");
+        if (!(artifact instanceof FLYSArtifact)) {
+            log.warn("need FLYSArtifact here but have a " + artifact.getClass());
+            return;
+        }
+
+        final FLYSArtifact flys = (FLYSArtifact)artifact;
+
+        final Integer [] res = new Integer[1];
+
+        // check first if artifact already exists
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_ARTIFACT_BY_GID);
+                stmnt.setString(1, flys.identifier());
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    // new artifact
+                    return true;
+                }
+                res[0] = result.getInt(1);
+                return true;
+            }
+        };
+
+        if (!exec.runRead()) {
+            log.error("querying artifact failed");
+            return;
+        }
+
+        if (res[0] == null) { // new artifact
+            createdArtifact(artifact, backend, context);
+            return;
+        }
+
+        // artifact already exists -> delete old data
+        exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID);
+                stmnt.setInt(1, res[0]);
+                stmnt.execute();
+                prepareStatement(SQL_DELETE_FACETS_BY_ARTIFACT_ID);
+                stmnt.setInt(1, res[0]);
+                stmnt.execute();
+                prepareStatement(SQL_DELETE_OUTS_BY_ARTIFACT_ID);
+                stmnt.setInt(1, res[0]);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("deleting old artifact data failed");
+            return;
+        }
+
+        // write new data
+        storeData(res[0], flys);
+        storeOuts(res[0], flys, context);
+    }
+
+    public void createdUser(
+        final User    user,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("createdUser");
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_USER_ID_NEXTVAL);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    log.error("id generation for user failed");
+                    return false;
+                }
+                int uId = result.getInt(1);
+                reset();
+                prepareStatement(SQL_INSERT_USER);
+                stmnt.setInt(1, uId);
+                stmnt.setString(2, user.identifier());
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("create user failed");
+        }
+    }
+
+    public void deletedUser(
+        final String  identifier,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("deletedUser");
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_DELETE_USER_BY_GID);
+                stmnt.setString(1, identifier);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("delete user failed");
+        }
+    }
+
+    public void createdCollection(
+        final ArtifactCollection collection,
+        Backend                  backend,
+        GlobalContext            context
+    ) {
+        log.debug("createdCollection");
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                String userId = collection.getUser().identifier();
+                prepareStatement(SQL_USER_BY_GID);
+                stmnt.setString(1, userId);
+                result = stmnt.executeQuery();
+                int uId;
+                if (result.next()) {
+                    uId = result.getInt(1);
+                    reset();
+                }
+                else {
+                    // need to create user first
+                    reset();
+                    prepareStatement(SQL_USER_ID_NEXTVAL);
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        log.error("id generation for user failed");
+                        return false;
+                    }
+                    uId = result.getInt(1);
+                    reset();
+                    prepareStatement(SQL_INSERT_USER);
+                    stmnt.setInt(1, uId);
+                    stmnt.setString(2, userId);
+                    stmnt.execute();
+                    conn.commit();
+                    reset();
+                }
+
+                prepareStatement(SQL_COLLECTION_ID_NEXTVAL);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    log.error("id generation for collection failed");
+                    return false;
+                }
+                int cId = result.getInt(1);
+                reset();
+
+                String identifier = collection.identifier();
+                String name       = collection.getName();
+
+                prepareStatement(SQL_INSERT_COLLECTION);
+                stmnt.setInt(1, cId);
+                stmnt.setString(2, identifier);
+                stmnt.setInt(3, uId);
+                setString(stmnt, 4, name);
+                stmnt.setTimestamp(5,
+                    new Timestamp(System.currentTimeMillis()));
+                stmnt.execute();
+
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("create collection failed");
+        }
+    }
+
+    public void deletedCollection(
+        final String  identifier,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("deletedCollection");
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_DELETE_COLLECTION_BY_GID);
+                stmnt.setString(1, identifier);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("delete collection failed");
+        }
+    }
+
+    public void changedCollectionAttribute(
+        String        identifier,
+        Document      document,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("changedCollectionAttribute");
+    }
+
+    public void changedCollectionItemAttribute(
+        String        collectionId,
+        String        artifactId,
+        Document      document,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("changedCollectionItemAttribute");
+    }
+
+    public void addedArtifactToCollection(
+        final String  artifactId,
+        final String  collectionId,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("addedArtifactToCollection");
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_ARTIFACT_BY_GID);
+                stmnt.setString(1, artifactId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    return false;
+                }
+                int aId = result.getInt(1);
+                reset();
+
+                prepareStatement(SQL_COLLECTION_BY_GID);
+                stmnt.setString(1, collectionId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    return false;
+                }
+                int cId = result.getInt(1);
+                reset();
+
+                prepareStatement(SQL_COLLECTION_ITEM_ID_NEXTVAL);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    return false;
+                }
+                int ciId = result.getInt(1);
+                reset();
+
+                prepareStatement(SQL_INSERT_COLLECTION_ITEM);
+                stmnt.setInt(1, ciId);
+                stmnt.setInt(2, cId);
+                stmnt.setInt(3, aId);
+                stmnt.execute();
+
+                conn.commit();
+                return true;
+            }
+        };
+        if (!exec.runWrite()) {
+            log.error("added artifact to collection failed");
+        }
+    }
+
+    public void removedArtifactFromCollection(
+        final String  artifactId,
+        final String  collectionId,
+        Backend       backend,
+        GlobalContext context
+    ) {
+        log.debug("removedArtifactFromCollection");
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_ARTIFACT_BY_GID);
+                stmnt.setString(1, artifactId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    return false;
+                }
+                int aId = result.getInt(1);
+                reset();
+                prepareStatement(SQL_COLLECTION_BY_GID);
+                stmnt.setString(1, collectionId);
+                result = stmnt.executeQuery();
+                if (!result.next()) {
+                    return false;
+                }
+                int cId = result.getInt(1);
+                reset();
+                prepareStatement(SQL_DELETE_ARTIFACT_FROM_COLLECTION);
+                stmnt.setInt(1, cId);
+                stmnt.setInt(2, aId);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+        if (!exec.runWrite()) {
+            log.error("removing artifact from collection failed");
+        }
+    }
+
+    public void setCollectionName(
+        final String  collectionId,
+        final String  name,
+        GlobalContext context
+    ) {
+        log.debug("setCollectionName");
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_UPDATE_COLLECTION_NAME);
+                stmnt.setString(1, name);
+                stmnt.setString(2, collectionId);
+                stmnt.execute();
+                conn.commit();
+                return true;
+            }
+        };
+        if (!exec.runWrite()) {
+            log.error("changing name failed");
+        }
+    }
+
+    protected void storeData(
+        final int     artifactId,
+        FLYSArtifact  artifact
+    ) {
+        final Collection<StateData> data = artifact.getAllData();
+
+        if (data.isEmpty()) {
+            return;
+        }
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                int [] ids = new int[data.size()];
+                prepareStatement(SQL_ARTIFACT_DATA_ID_NEXTVAL);
+
+                for (int i = 0; i < ids.length; ++i) {
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        log.error("generating id for artifact data failed");
+                        return false;
+                    }
+                    ids[i] = result.getInt(1);
+                    result.close(); result = null;
+                }
+                reset();
+                prepareStatement(SQL_INSERT_ARTIFACT_DATA);
+
+                int i = 0;
+                for (StateData sd: data) {
+                    int id = ids[i++];
+                    stmnt.setInt(1, id);
+                    stmnt.setInt(2, artifactId);
+                    // XXX: Where come the nulls from?
+                    String type = sd.getType();
+                    if (type == null) type = "String";
+                    stmnt.setString(3, type);
+                    stmnt.setString(4, sd.getName());
+                    setString(stmnt, 5, sd.getValue());
+                    stmnt.execute();
+                }
+
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("storing artifact data failed");
+        }
+    }
+
+    protected void storeOuts(
+        final int          artifactId,
+        final FLYSArtifact artifact,
+        GlobalContext      context
+    ) {
+        final List<Output> outs = artifact.getOutputs(context);
+
+        if (outs.isEmpty()) {
+            return;
+        }
+
+        final int [] outIds = new int[outs.size()];
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_OUT_ID_NEXTVALUE);
+                for (int i = 0; i < outIds.length; ++i) {
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        log.error("generation of out ids failed");
+                        return false;
+                    }
+                    outIds[i] = result.getInt(1);
+                    result.close(); result = null;
+                }
+                reset();
+                prepareStatement(SQL_INSERT_OUT);
+                for (int i = 0; i < outIds.length; ++i) {
+                    Output out = outs.get(i);
+                    stmnt.setInt(1, outIds[i]);
+                    stmnt.setInt(2, artifactId);
+                    stmnt.setString(3, out.getName());
+                    setString(stmnt, 4, out.getDescription());
+                    setString(stmnt, 5, out.getType());
+                    stmnt.execute();
+                }
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("storing artifact outs failed");
+            return;
+        }
+
+        final int FACETS = numFacets(outs);
+
+        if (FACETS == 0) {
+            return;
+        }
+
+        exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                int [] facetIds = new int[FACETS];
+                prepareStatement(SQL_FACET_ID_NEXTVAL);
+                for (int i = 0; i < facetIds.length; ++i) {
+                    result = stmnt.executeQuery();
+                    if (!result.next()) {
+                        log.error("generation of facet ids failed");
+                        return false;
+                    }
+                    facetIds[i] = result.getInt(1);
+                    result.close(); result = null;
+                }
+                reset();
+                prepareStatement(SQL_INSERT_FACET);
+                int index = 0;
+                for (int i = 0, N = outs.size(); i < N; ++i) {
+                    Output out = outs.get(i);
+                    int outId = outIds[i];
+                    for (Facet facet: out.getFacets()) {
+                        stmnt.setInt(1, facetIds[index]);
+                        stmnt.setInt(2, outId);
+                        stmnt.setString(3, facet.getName());
+                        stmnt.setInt(4, facet.getIndex());
+                        stmnt.setString(5, "XXX"); // TODO: handle states
+                        setString(stmnt, 6, facet.getDescription());
+                        stmnt.execute();
+                        ++index;
+                    }
+                }
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("storing facets failed");
+        }
+    }
+
+    public void killedCollections(
+        final List<String> identifiers,
+        GlobalContext      context
+    ) {
+        log.debug("killedCollections");
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_DELETE_COLLECTION_BY_GID);
+                for (String identifier: identifiers) {
+                    stmnt.setString(1, identifier);
+                    stmnt.execute();
+                }
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("killing collections failed");
+        }
+    }
+
+    public void killedArtifacts(
+        final List<String> identifiers,
+        GlobalContext      context
+    ) {
+        log.debug("killedArtifacts");
+
+        SQLExecutor.Instance exec = sqlExecutor.new Instance() {
+            @Override
+            public boolean doIt() throws SQLException {
+                prepareStatement(SQL_DELETE_ARTIFACT_BY_GID);
+                for (String identifier: identifiers) {
+                    stmnt.setString(1, identifier);
+                    stmnt.execute();
+                }
+                conn.commit();
+                return true;
+            }
+        };
+
+        if (!exec.runWrite()) {
+            log.error("killing artifacts failed");
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org