view artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java @ 41:5e4bc24ea438

Made serilization more flexible. DB update required!!! Fixed problem with touching artifacts in database. artifacts/trunk@119 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 23 Sep 2009 16:55:12 +0000
parents 93edc04f3a10
children f2648672c9c4
line wrap: on
line source
package de.intevation.artifactdatabase;

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 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.Artifact;
import de.intevation.artifacts.ArtifactFactory;
import de.intevation.artifacts.ArtifactSerializer;

import org.apache.log4j.Logger;

/**
 *  @author Sascha L. Teichmann
 */
public class Backend
implements   DatabaseCleaner.ArtifactReviver
{
    private static Logger logger = Logger.getLogger(Backend.class);

    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");

    protected DatabaseCleaner cleaner;

    protected FactoryLookup   factoryLookup;

    public interface FactoryLookup {

        ArtifactFactory getArtifactFactory(String factoryName);

    } // interface FactoryLookup

    public final class PersistentArtifact
    extends            Id
    {
        private Artifact           artifact;
        private ArtifactSerializer serializer;

        public PersistentArtifact(
            Artifact           artifact, 
            ArtifactSerializer serializer,
            int                id
        ) {
            super(id);
            this.artifact   = artifact;
            this.serializer = serializer;
        }

        public Artifact getArtifact() {
            return artifact;
        }

        public ArtifactSerializer getSerializer() {
            return serializer;
        }

        public void store() {
            if (logger.isDebugEnabled()) {
                logger.debug("storing artifact id = " + getId());
            }
            Backend.this.store(this);
        }

        public void touch() {
            if (logger.isDebugEnabled()) {
                logger.debug("touching artifact id = " + getId());
            }
            Backend.this.touch(this);
        }
    } // class ArtifactWithId

    public Backend() {
    }

    public Backend(DatabaseCleaner cleaner) {
        this.cleaner = cleaner;
    }

    public void setFactoryLookup(FactoryLookup factoryLookup) {
        this.factoryLookup = factoryLookup;
    }

    public void setCleaner(DatabaseCleaner cleaner) {
        this.cleaner = cleaner;
    }

    public String newIdentifier() {
        UUID uuid = UUID.randomUUID();
        // TODO: check database for collisions.
        return uuid.toString();
    }

    public PersistentArtifact storeInitially(
        Artifact        artifact,
        ArtifactFactory factory,
        Long            ttl
    ) 
    throws Exception
    {
        return new PersistentArtifact(
            artifact,
            factory.getSerializer(),
            insertDatabase(artifact, factory, ttl));
    }
    
    public PersistentArtifact getArtifact(String identifer) {

        try {
            UUID.fromString(identifer);
        }
        catch (IllegalArgumentException iae) {
            logger.warn(iae.getLocalizedMessage());
            return null;
        }

        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, identifer);

            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;
                }
            }

            String factoryName = load_result.getString(4);

            if (factoryLookup == null) {
                logger.error("factory lookup == null");
                return null;
            }

            ArtifactFactory factory = factoryLookup
                .getArtifactFactory(factoryName);

            if (factory == null) {
                logger.error("factory '" + factoryName + "' not found");
                return null;
            }

            ArtifactSerializer serializer =
                factory.getSerializer();

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

            Artifact artifact = serializer.fromBytes(bytes);

            return artifact == null
                ? null
                : new PersistentArtifact(artifact, serializer, id);
        }
        catch (SQLException sqle) {
            logger.error(sqle.getLocalizedMessage(), sqle);
        }
        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;
    }

    protected void artifactOutdated(int id) {
        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);
    }

    protected int insertDatabase(
        Artifact        artifact, 
        ArtifactFactory factory,
        Long            ttl
    ) {
        String uuid = artifact.identifier();

        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);
                if (ttl == null) {
                    stmnt_insert.setNull(3, Types.BIGINT);
                }
                else {
                    stmnt_insert.setLong(3, ttl.longValue());
                }

                stmnt_insert.setString(4, factory.getName());

                stmnt_insert.setBytes(
                    5,
                    factory.getSerializer().toBytes(artifact));

                stmnt_insert.execute();

                connection.commit();

                return id;
            }
            catch (SQLException sqle) {
                connection.rollback();
                throw sqle;
            }
        }
        catch (SQLException sqle) {
            logger.error(sqle.getLocalizedMessage(), sqle);
        }
        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(PersistentArtifact artifact) {

        try {
            Connection        connection  = null;
            PreparedStatement stmnt_touch = null;
            DataSource        dataSource  = DBConnection.getDataSource();
            try {
                connection = dataSource.getConnection();
                try {
                    connection.setAutoCommit(false);
                    stmnt_touch = connection.prepareStatement(SQL_TOUCH);
                    stmnt_touch.setInt(1, artifact.getId());
                    stmnt_touch.execute();
                    connection.commit();
                }
                catch (SQLException sqle) {
                    connection.rollback();
                }
            }
            catch (SQLException sqle) {
                logger.error(sqle.getLocalizedMessage(), sqle);
            }
            finally {
                if (stmnt_touch != null) {
                    try { stmnt_touch.close(); }
                    catch (SQLException sqle) {}
                }
                if (connection != null) {
                    try { connection.close(); }
                    catch (SQLException sqle) {}
                }
            }
        }
        catch (Exception e) {
            logger.error(e.getLocalizedMessage(), e);
        }
    }

    public void store(PersistentArtifact artifact) {

        try {
            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(2, artifact.getId());

                    byte [] bytes = artifact
                        .getSerializer()
                        .toBytes(artifact.getArtifact());

                    stmnt_update.setBytes(1, bytes);
                    stmnt_update.execute();
                    connection.commit();
                }
                catch (SQLException sqle) {
                    connection.rollback();
                }
            }
            catch (SQLException sqle) {
                logger.error(sqle.getLocalizedMessage(), sqle);
            }
            finally {
                if (stmnt_update != null) {
                    try { stmnt_update.close(); }
                    catch (SQLException sqle) {}
                }
                if (connection != null) {
                    try { connection.close(); }
                    catch (SQLException sqle) {}
                }
            }
        }
        catch (Exception e) {
            logger.error(e.getLocalizedMessage(), e);
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:

http://dive4elements.wald.intevation.org