view artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java @ 15:9ad6ec2d09c3

Implemented restoring artifacts from database. artifacts/trunk@30 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 07 Sep 2009 10:06:23 +0000
parents 0d16d1bb2df0
children 5a6b6a3debc7
line wrap: on
line source
package de.intevation.artifactdatabase;

import org.w3c.dom.Document;

import java.util.UUID;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.sql.ResultSet;
import java.sql.Timestamp;

import javax.sql.DataSource;

import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;

import java.util.zip.GZIPOutputStream;
import java.util.zip.GZIPInputStream;

import de.intevation.artifacts.ArtifactFactory;
import de.intevation.artifacts.Artifact;

/**
 *  @author Sascha L. Teichmann
 */
public class Backend
{
    public static final String SQL_NEXT_ID =
        SQL.get("artifacts.id.nextval");

    public static final String SQL_INSERT =
        SQL.get("artifacts.insert");

    public static final String SQL_UPDATE =
        SQL.get("artifacts.update");

    public static final String SQL_TOUCH =
        SQL.get("artifacts.touch");

    public static final String SQL_LOAD_BY_GID =
        SQL.get("artifacts.select.gid");

    /**
     * Used to wrap the calls to invole database actions.
     */
    public class ArtifactProxy
    implements   Artifact
    {
        protected Artifact original;
        protected int      id;
        protected boolean  unwritten;

        public ArtifactProxy() {
        }

        public ArtifactProxy(Artifact original, int id, boolean unwritten) {
            this.original  = original;
            this.id        = id;
            this.unwritten = unwritten;
        }

        public Artifact getOriginal() {
            return original;
        }

        public int getId() {
            return id;
        }

        public boolean isUnwritten() {
            return unwritten;
        }

        public String identifier() {
            return original.identifier();
        }

        public String hash() {
            return original.hash();
        }

        public Document describe(Object context) {
            try {
                return original.describe(context);
            }
            finally {
                touch(this);
            }
        }

        public Document advance(Document target, Object context) {
            try {
                return original.advance(target, context);
            }
            finally {
                store(this);
            }
        }

        public Document feed(Document data, Object context) {
            try {
                return original.feed(data, context);
            }
            finally {
                store(this);
            }
        }

        public byte [] out(Document format, Object context) {
            try {
                return original.out(format, context);
            }
            finally {
                touch(this);
            }
        }

        public void setup(String identifier, Object context) {
            original.setup(identifier, context);
        }

        public void endOfLife(Object context) {
            original.endOfLife(context);
        }

        public byte [] toBytes() {
            try {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                GZIPOutputStream      gos = new GZIPOutputStream(bos);
                ObjectOutputStream    oos = new ObjectOutputStream(gos);

                oos.writeObject(original);
                oos.flush();

                return bos.toByteArray();
            }
            catch (IOException ioe) {
                throw new RuntimeException(ioe);
            }
        }
    } // class ArtifactProxy

    public Backend() {
    }

    public Artifact getArtifact(String idenitfier) {
        UUID uuid;

        try {
            uuid = UUID.fromString(idenitfier);
        }
        catch (IllegalArgumentException iae) {
            return null;
        }

        return getArtifactByUUID(uuid);
    }

    public Artifact createArtifactWithFactory(
        ArtifactFactory factory, Object context
    ) {
        UUID uuid = UUID.randomUUID();
        Artifact artifact = factory.createArtifact(
            uuid.toString(), context);

        Long ttl = factory.timeToLiveUntouched(
            artifact, context);

        int id = insertDatabase(uuid, ttl);

        return new ArtifactProxy(artifact, id, true);
    }

    protected Artifact getArtifactByUUID(UUID uuid) {

        Connection        connection  = null;
        PreparedStatement stmnt_load  = null;
        ResultSet         load_result = null;

        DataSource dataSource = DBConnection.getDataSource();
        try {
            connection = dataSource.getConnection();
            stmnt_load = connection.prepareStatement(SQL_LOAD_BY_GID);
            stmnt_load.setString(1, uuid.toString());

            load_result = stmnt_load.executeQuery();

            if (!load_result.next()) {
                return null;
            }

            int  id  = load_result.getInt(1);
            long ttl = load_result.getLong(3);

            if (!load_result.wasNull()) { // real time to life
                long last_access = load_result.getTimestamp(2).getTime();
                if (last_access + ttl > System.currentTimeMillis()) {
                    artifactOutdated(id);
                    return null;
                }
            }

            byte [] bytes = load_result.getBytes(4);

            if (bytes == null) {
                return null;
            }

            Artifact original = restoreArtifact(bytes);
            if (original == null) {
                return null;
            }

            return new ArtifactProxy(original, id, false);
        }
        catch (SQLException sqle) {
            sqle.printStackTrace(System.err);
        }
        finally {
            if (load_result != null) {
                try { load_result.close(); }
                catch (SQLException sqle) {}
            }
            if (stmnt_load != null) {
                try { load_result.close(); }
                catch (SQLException sqle) {}
            }
            if (connection != null) {
                try { connection.close(); } 
                catch (SQLException sqle) {}
            }
        }
        return null;
    }

    public static Artifact restoreArtifact(byte [] bytes) {

        ObjectInputStream ois = null;

        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            GZIPInputStream      gis = new GZIPInputStream(bis);
                                 ois = new ObjectInputStream(gis);

            return (Artifact)ois.readObject();
        }
        catch (IOException ioe) {
            ioe.printStackTrace(System.err);
        }
        catch (ClassNotFoundException cnfe) {
            cnfe.printStackTrace(System.err);
        }
        catch (ClassCastException cce) {
            cce.printStackTrace(System.err);
        }
        finally {
            if (ois != null) {
                try { ois.close(); }
                catch (IOException ioe) { }
            }
        }

        return null;
    }

    protected void artifactOutdated(int id) {
        System.err.println("artifactOutdated: id = " + id);
    }

    protected int insertDatabase(UUID uuid, Long ttl) {
        Connection        connection    = null;
        PreparedStatement stmnt_next_id = null;
        PreparedStatement stmnt_insert  = null;
        ResultSet         res_id        = null;

        DataSource dataSource = DBConnection.getDataSource();
        try {
            connection = dataSource.getConnection();
            try {
                connection.setAutoCommit(false);

                stmnt_next_id = connection.prepareStatement(SQL_NEXT_ID);
                stmnt_insert  = connection.prepareStatement(SQL_INSERT);

                res_id = stmnt_next_id.executeQuery();

                if (!res_id.next()) {
                    throw new RuntimeException("No id generated");
                }

                int id = res_id.getInt(1);

                stmnt_insert.setInt(1, id);
                stmnt_insert.setString(2, uuid.toString());
                if (ttl == null) {
                    stmnt_insert.setNull(3, Types.BIGINT);
                }
                else {
                    stmnt_insert.setLong(3, ttl.longValue());
                }

                stmnt_insert.execute();

                connection.commit();

                return id;
            }
            catch (SQLException sqle) {
                connection.rollback();
                throw sqle;
            }
        }
        catch (SQLException sqle) {
            sqle.printStackTrace(System.err);
        }
        finally {
            if (res_id != null) {
                try { res_id.close(); }
                catch (SQLException sqle) {}
            }
            if (stmnt_insert != null) {
                try { stmnt_insert.close(); }
                catch (SQLException sqle) {}
            }
            if (stmnt_next_id != null) {
                try { stmnt_next_id.close(); }
                catch (SQLException sqle) {}
            }
            if (connection != null) {
                try { connection.close(); }
                catch (SQLException sqle) {}
            }
        }
        throw new RuntimeException("failed insert artifact into database");
    }

    public void touch(ArtifactProxy proxy) {
        System.err.println("touch: " + proxy);
        if (proxy.isUnwritten()) {
            store(proxy);
            return;
        }
        Connection        connection  = null;
        PreparedStatement stmnt_touch = null;
        DataSource        dataSource  = DBConnection.getDataSource();
        try {
            connection = dataSource.getConnection();
            try {
                connection.setAutoCommit(false);
                stmnt_touch = connection.prepareStatement(SQL_UPDATE);
                stmnt_touch.setInt(1, proxy.getId());
                stmnt_touch.execute();
                connection.commit();
            }
            catch (SQLException sqle) {
                connection.rollback();
            }
        }
        catch (SQLException sqle) {
            sqle.printStackTrace(System.err);
        }
        finally {
            if (stmnt_touch != null) {
                try { stmnt_touch.close(); }
                catch (SQLException sqle) {}
            }
            if (connection != null) {
                try { connection.close(); }
                catch (SQLException sqle) {}
            }
        }
    }

    public void store(ArtifactProxy proxy) {
        System.err.println("store: " + proxy);
        Connection        connection   = null;
        PreparedStatement stmnt_update = null;
        DataSource        dataSource   = DBConnection.getDataSource();
        try {
            connection = dataSource.getConnection();
            try {
                connection.setAutoCommit(false);
                stmnt_update = connection.prepareStatement(SQL_UPDATE);
                stmnt_update.setInt(1, proxy.getId());
                stmnt_update.setBytes(2, proxy.toBytes());
                stmnt_update.execute();
                connection.commit();
            }
            catch (SQLException sqle) {
                connection.rollback();
            }
        }
        catch (SQLException sqle) {
            sqle.printStackTrace(System.err);
        }
        finally {
            if (stmnt_update != null) {
                try { stmnt_update.close(); }
                catch (SQLException sqle) {}
            }
            if (connection != null) {
                try { connection.close(); }
                catch (SQLException sqle) {}
            }
        }
    }

}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:

http://dive4elements.wald.intevation.org