sascha@13: package de.intevation.artifactdatabase; sascha@13: sascha@14: import java.util.UUID; sascha@14: sascha@14: import java.sql.Connection; sascha@14: import java.sql.SQLException; sascha@14: import java.sql.PreparedStatement; sascha@14: import java.sql.Types; sascha@14: import java.sql.ResultSet; sascha@14: sascha@14: import javax.sql.DataSource; sascha@14: sascha@14: import java.io.IOException; sascha@15: import java.io.ByteArrayInputStream; sascha@14: import java.io.ByteArrayOutputStream; sascha@14: import java.io.ObjectOutputStream; sascha@15: import java.io.ObjectInputStream; sascha@14: sascha@14: import java.util.zip.GZIPOutputStream; sascha@15: import java.util.zip.GZIPInputStream; sascha@14: sascha@13: import de.intevation.artifacts.Artifact; sascha@41: import de.intevation.artifacts.ArtifactFactory; sascha@41: import de.intevation.artifacts.ArtifactSerializer; sascha@13: sascha@17: import org.apache.log4j.Logger; sascha@17: sascha@13: /** sascha@13: * @author Sascha L. Teichmann sascha@13: */ sascha@13: public class Backend sascha@41: implements DatabaseCleaner.ArtifactReviver sascha@13: { sascha@17: private static Logger logger = Logger.getLogger(Backend.class); sascha@17: sascha@14: public static final String SQL_NEXT_ID = sascha@14: SQL.get("artifacts.id.nextval"); sascha@14: sascha@14: public static final String SQL_INSERT = sascha@14: SQL.get("artifacts.insert"); sascha@14: sascha@14: public static final String SQL_UPDATE = sascha@14: SQL.get("artifacts.update"); sascha@14: sascha@14: public static final String SQL_TOUCH = sascha@14: SQL.get("artifacts.touch"); sascha@14: sascha@15: public static final String SQL_LOAD_BY_GID = sascha@15: SQL.get("artifacts.select.gid"); sascha@15: sascha@30: protected DatabaseCleaner cleaner; sascha@30: sascha@41: protected FactoryLookup factoryLookup; sascha@41: sascha@41: public interface FactoryLookup { sascha@41: sascha@41: ArtifactFactory getArtifactFactory(String factoryName); sascha@41: sascha@41: } // interface FactoryLookup sascha@41: sascha@32: public final class PersistentArtifact sascha@32: extends Id sascha@14: { sascha@41: private Artifact artifact; sascha@41: private ArtifactSerializer serializer; sascha@14: sascha@41: public PersistentArtifact( sascha@41: Artifact artifact, sascha@41: ArtifactSerializer serializer, sascha@41: int id sascha@41: ) { sascha@32: super(id); sascha@41: this.artifact = artifact; sascha@41: this.serializer = serializer; sascha@14: } sascha@14: sascha@32: public Artifact getArtifact() { sascha@32: return artifact; sascha@14: } sascha@14: sascha@41: public ArtifactSerializer getSerializer() { sascha@41: return serializer; sascha@41: } sascha@41: sascha@32: public void store() { sascha@38: if (logger.isDebugEnabled()) { sascha@38: logger.debug("storing artifact id = " + getId()); sascha@38: } sascha@32: Backend.this.store(this); sascha@14: } sascha@14: sascha@32: public void touch() { sascha@38: if (logger.isDebugEnabled()) { sascha@38: logger.debug("touching artifact id = " + getId()); sascha@38: } sascha@32: Backend.this.touch(this); sascha@14: } sascha@32: } // class ArtifactWithId sascha@14: sascha@13: public Backend() { sascha@13: } sascha@13: sascha@30: public Backend(DatabaseCleaner cleaner) { sascha@30: this.cleaner = cleaner; sascha@30: } sascha@30: sascha@41: public void setFactoryLookup(FactoryLookup factoryLookup) { sascha@41: this.factoryLookup = factoryLookup; sascha@41: } sascha@41: sascha@32: public void setCleaner(DatabaseCleaner cleaner) { sascha@32: this.cleaner = cleaner; sascha@32: } sascha@32: sascha@32: public String newIdentifier() { sascha@32: UUID uuid = UUID.randomUUID(); sascha@32: // TODO: check database for collisions. sascha@32: return uuid.toString(); sascha@32: } sascha@32: sascha@32: public PersistentArtifact storeInitially( sascha@41: Artifact artifact, sascha@41: ArtifactFactory factory, sascha@41: Long ttl sascha@32: ) sascha@32: throws Exception sascha@32: { sascha@32: return new PersistentArtifact( sascha@32: artifact, sascha@41: factory.getSerializer(), sascha@41: insertDatabase(artifact, factory, ttl)); sascha@32: } sascha@32: sascha@32: public PersistentArtifact getArtifact(String identifer) { sascha@15: sascha@15: try { sascha@32: UUID.fromString(identifer); sascha@15: } sascha@15: catch (IllegalArgumentException iae) { sascha@17: logger.warn(iae.getLocalizedMessage()); sascha@15: return null; sascha@15: } sascha@15: sascha@15: Connection connection = null; sascha@15: PreparedStatement stmnt_load = null; sascha@15: ResultSet load_result = null; sascha@15: sascha@15: DataSource dataSource = DBConnection.getDataSource(); sascha@15: try { sascha@15: connection = dataSource.getConnection(); sascha@15: stmnt_load = connection.prepareStatement(SQL_LOAD_BY_GID); sascha@32: stmnt_load.setString(1, identifer); sascha@15: sascha@15: load_result = stmnt_load.executeQuery(); sascha@15: sascha@15: if (!load_result.next()) { sascha@15: return null; sascha@15: } sascha@15: sascha@15: int id = load_result.getInt(1); sascha@15: long ttl = load_result.getLong(3); sascha@15: sascha@15: if (!load_result.wasNull()) { // real time to life sascha@15: long last_access = load_result.getTimestamp(2).getTime(); tim@34: if (last_access + ttl < System.currentTimeMillis()) { sascha@15: artifactOutdated(id); sascha@15: return null; sascha@15: } sascha@15: } sascha@15: sascha@41: String factoryName = load_result.getString(4); sascha@15: sascha@41: if (factoryLookup == null) { sascha@41: logger.error("factory lookup == null"); sascha@41: return null; sascha@41: } sascha@41: sascha@41: ArtifactFactory factory = factoryLookup sascha@41: .getArtifactFactory(factoryName); sascha@41: sascha@41: if (factory == null) { sascha@41: logger.error("factory '" + factoryName + "' not found"); sascha@41: return null; sascha@41: } sascha@41: sascha@41: ArtifactSerializer serializer = sascha@41: factory.getSerializer(); sascha@41: sascha@41: byte [] bytes = load_result.getBytes(5); sascha@41: sascha@41: Artifact artifact = serializer.fromBytes(bytes); sascha@15: sascha@32: return artifact == null sascha@32: ? null sascha@41: : new PersistentArtifact(artifact, serializer, id); sascha@15: } sascha@15: catch (SQLException sqle) { sascha@17: logger.error(sqle.getLocalizedMessage(), sqle); sascha@15: } sascha@15: finally { sascha@15: if (load_result != null) { sascha@15: try { load_result.close(); } sascha@15: catch (SQLException sqle) {} sascha@15: } sascha@15: if (stmnt_load != null) { sascha@15: try { load_result.close(); } sascha@15: catch (SQLException sqle) {} sascha@15: } sascha@15: if (connection != null) { sascha@15: try { connection.close(); } sascha@15: catch (SQLException sqle) {} sascha@15: } sascha@15: } sascha@15: return null; sascha@15: } sascha@15: sascha@15: protected void artifactOutdated(int id) { sascha@17: logger.info("artifactOutdated: id = " + id); sascha@30: if (cleaner != null) { sascha@30: cleaner.wakeup(); sascha@30: } sascha@15: } sascha@15: sascha@41: public Artifact reviveArtifact(String factoryName, byte [] bytes) { sascha@41: if (factoryLookup == null) { sascha@41: logger.error("reviveArtifact: factory lookup == null"); sascha@41: return null; sascha@41: } sascha@41: ArtifactFactory factory = factoryLookup sascha@41: .getArtifactFactory(factoryName); sascha@32: sascha@41: if (factory == null) { sascha@41: logger.error("reviveArtifact: no factory '" + factoryName + "' found"); sascha@41: return null; sascha@41: } sascha@41: sascha@41: ArtifactSerializer serializer = factory.getSerializer(); sascha@41: sascha@41: return serializer.fromBytes(bytes); sascha@41: } sascha@41: sascha@41: protected int insertDatabase( sascha@41: Artifact artifact, sascha@41: ArtifactFactory factory, sascha@41: Long ttl sascha@41: ) { sascha@32: String uuid = artifact.identifier(); sascha@32: sascha@14: Connection connection = null; sascha@14: PreparedStatement stmnt_next_id = null; sascha@14: PreparedStatement stmnt_insert = null; sascha@14: ResultSet res_id = null; sascha@14: sascha@14: DataSource dataSource = DBConnection.getDataSource(); sascha@14: try { sascha@14: connection = dataSource.getConnection(); sascha@14: try { sascha@14: connection.setAutoCommit(false); sascha@14: sascha@14: stmnt_next_id = connection.prepareStatement(SQL_NEXT_ID); sascha@14: stmnt_insert = connection.prepareStatement(SQL_INSERT); sascha@14: sascha@14: res_id = stmnt_next_id.executeQuery(); sascha@14: sascha@14: if (!res_id.next()) { sascha@14: throw new RuntimeException("No id generated"); sascha@14: } sascha@14: sascha@14: int id = res_id.getInt(1); sascha@14: sascha@14: stmnt_insert.setInt(1, id); sascha@32: stmnt_insert.setString(2, uuid); sascha@14: if (ttl == null) { sascha@14: stmnt_insert.setNull(3, Types.BIGINT); sascha@14: } sascha@14: else { sascha@14: stmnt_insert.setLong(3, ttl.longValue()); sascha@14: } sascha@14: sascha@41: stmnt_insert.setString(4, factory.getName()); sascha@41: sascha@41: stmnt_insert.setBytes( sascha@41: 5, sascha@41: factory.getSerializer().toBytes(artifact)); sascha@32: sascha@14: stmnt_insert.execute(); sascha@14: sascha@14: connection.commit(); sascha@14: sascha@14: return id; sascha@14: } sascha@14: catch (SQLException sqle) { sascha@14: connection.rollback(); sascha@14: throw sqle; sascha@14: } sascha@14: } sascha@14: catch (SQLException sqle) { sascha@17: logger.error(sqle.getLocalizedMessage(), sqle); sascha@14: } sascha@14: finally { sascha@14: if (res_id != null) { sascha@14: try { res_id.close(); } sascha@14: catch (SQLException sqle) {} sascha@14: } sascha@14: if (stmnt_insert != null) { sascha@14: try { stmnt_insert.close(); } sascha@14: catch (SQLException sqle) {} sascha@14: } sascha@14: if (stmnt_next_id != null) { sascha@14: try { stmnt_next_id.close(); } sascha@14: catch (SQLException sqle) {} sascha@14: } sascha@14: if (connection != null) { sascha@14: try { connection.close(); } sascha@14: catch (SQLException sqle) {} sascha@14: } sascha@14: } sascha@14: throw new RuntimeException("failed insert artifact into database"); sascha@14: } sascha@14: sascha@32: public void touch(PersistentArtifact artifact) { sascha@26: sascha@14: try { sascha@26: Connection connection = null; sascha@26: PreparedStatement stmnt_touch = null; sascha@26: DataSource dataSource = DBConnection.getDataSource(); sascha@14: try { sascha@26: connection = dataSource.getConnection(); sascha@26: try { sascha@26: connection.setAutoCommit(false); sascha@41: stmnt_touch = connection.prepareStatement(SQL_TOUCH); sascha@32: stmnt_touch.setInt(1, artifact.getId()); sascha@26: stmnt_touch.execute(); sascha@26: connection.commit(); sascha@26: } sascha@26: catch (SQLException sqle) { sascha@26: connection.rollback(); sascha@26: } sascha@14: } sascha@14: catch (SQLException sqle) { sascha@26: logger.error(sqle.getLocalizedMessage(), sqle); sascha@26: } sascha@26: finally { sascha@26: if (stmnt_touch != null) { sascha@26: try { stmnt_touch.close(); } sascha@26: catch (SQLException sqle) {} sascha@26: } sascha@26: if (connection != null) { sascha@26: try { connection.close(); } sascha@26: catch (SQLException sqle) {} sascha@26: } sascha@14: } sascha@14: } sascha@26: catch (Exception e) { sascha@26: logger.error(e.getLocalizedMessage(), e); sascha@14: } sascha@14: } sascha@14: sascha@32: public void store(PersistentArtifact artifact) { sascha@26: sascha@14: try { sascha@26: Connection connection = null; sascha@26: PreparedStatement stmnt_update = null; sascha@26: DataSource dataSource = DBConnection.getDataSource(); sascha@14: try { sascha@26: connection = dataSource.getConnection(); sascha@26: try { sascha@26: connection.setAutoCommit(false); sascha@26: stmnt_update = connection.prepareStatement(SQL_UPDATE); sascha@32: stmnt_update.setInt(2, artifact.getId()); sascha@26: sascha@41: byte [] bytes = artifact sascha@41: .getSerializer() sascha@41: .toBytes(artifact.getArtifact()); sascha@26: sascha@26: stmnt_update.setBytes(1, bytes); sascha@26: stmnt_update.execute(); sascha@26: connection.commit(); sascha@26: } sascha@26: catch (SQLException sqle) { sascha@26: connection.rollback(); sascha@26: } sascha@14: } sascha@14: catch (SQLException sqle) { sascha@26: logger.error(sqle.getLocalizedMessage(), sqle); sascha@26: } sascha@26: finally { sascha@26: if (stmnt_update != null) { sascha@26: try { stmnt_update.close(); } sascha@26: catch (SQLException sqle) {} sascha@26: } sascha@26: if (connection != null) { sascha@26: try { connection.close(); } sascha@26: catch (SQLException sqle) {} sascha@26: } sascha@14: } sascha@14: } sascha@26: catch (Exception e) { sascha@26: logger.error(e.getLocalizedMessage(), e); sascha@14: } sascha@14: } sascha@13: } sascha@13: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: