sascha@13: package de.intevation.artifactdatabase; sascha@13: sascha@14: import org.w3c.dom.Document; sascha@14: 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.ArtifactFactory; sascha@13: import de.intevation.artifacts.Artifact; 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@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@14: /** sascha@14: * Used to wrap the calls to invole database actions. sascha@14: */ sascha@14: public class ArtifactProxy sascha@14: implements Artifact sascha@14: { sascha@14: protected Artifact original; sascha@14: protected int id; sascha@14: protected boolean unwritten; sascha@14: sascha@14: public ArtifactProxy() { sascha@14: } sascha@14: sascha@14: public ArtifactProxy(Artifact original, int id, boolean unwritten) { sascha@14: this.original = original; sascha@14: this.id = id; sascha@14: this.unwritten = unwritten; sascha@14: } sascha@14: sascha@14: public Artifact getOriginal() { sascha@14: return original; sascha@14: } sascha@14: sascha@14: public int getId() { sascha@14: return id; sascha@14: } sascha@14: sascha@14: public boolean isUnwritten() { sascha@14: return unwritten; sascha@14: } sascha@14: sascha@14: public String identifier() { sascha@14: return original.identifier(); sascha@14: } sascha@14: sascha@14: public String hash() { sascha@14: return original.hash(); sascha@14: } sascha@14: sascha@14: public Document describe(Object context) { sascha@14: try { sascha@14: return original.describe(context); sascha@14: } sascha@14: finally { sascha@14: touch(this); sascha@14: } sascha@14: } sascha@14: sascha@14: public Document advance(Document target, Object context) { sascha@14: try { sascha@14: return original.advance(target, context); sascha@14: } sascha@14: finally { sascha@14: store(this); sascha@14: } sascha@14: } sascha@14: sascha@14: public Document feed(Document data, Object context) { sascha@14: try { sascha@14: return original.feed(data, context); sascha@14: } sascha@14: finally { sascha@14: store(this); sascha@14: } sascha@14: } sascha@14: sascha@14: public byte [] out(Document format, Object context) { sascha@14: try { sascha@14: return original.out(format, context); sascha@14: } sascha@14: finally { sascha@14: touch(this); sascha@14: } sascha@14: } sascha@14: sascha@14: public void setup(String identifier, Object context) { sascha@14: original.setup(identifier, context); sascha@14: } sascha@14: sascha@14: public void endOfLife(Object context) { sascha@14: original.endOfLife(context); sascha@14: } sascha@14: sascha@14: public byte [] toBytes() { sascha@14: try { sascha@14: ByteArrayOutputStream bos = new ByteArrayOutputStream(); sascha@14: GZIPOutputStream gos = new GZIPOutputStream(bos); sascha@14: ObjectOutputStream oos = new ObjectOutputStream(gos); sascha@14: sascha@14: oos.writeObject(original); sascha@14: oos.flush(); sascha@14: sascha@14: return bos.toByteArray(); sascha@14: } sascha@14: catch (IOException ioe) { sascha@17: logger.error(ioe.getLocalizedMessage(), ioe); sascha@14: throw new RuntimeException(ioe); sascha@14: } sascha@14: } sascha@14: } // class ArtifactProxy sascha@14: sascha@13: public Backend() { sascha@13: } sascha@13: sascha@13: public Artifact getArtifact(String idenitfier) { sascha@15: UUID uuid; sascha@15: sascha@15: try { sascha@15: uuid = UUID.fromString(idenitfier); sascha@15: } sascha@15: catch (IllegalArgumentException iae) { sascha@17: logger.warn(iae.getLocalizedMessage()); sascha@15: return null; sascha@15: } sascha@15: sascha@15: return getArtifactByUUID(uuid); sascha@13: } sascha@13: sascha@13: public Artifact createArtifactWithFactory( sascha@13: ArtifactFactory factory, Object context sascha@13: ) { sascha@14: UUID uuid = UUID.randomUUID(); sascha@14: Artifact artifact = factory.createArtifact( sascha@14: uuid.toString(), context); sascha@14: sascha@14: Long ttl = factory.timeToLiveUntouched( sascha@14: artifact, context); sascha@14: sascha@14: int id = insertDatabase(uuid, ttl); sascha@14: sascha@14: return new ArtifactProxy(artifact, id, true); sascha@13: } sascha@14: sascha@15: protected Artifact getArtifactByUUID(UUID uuid) { 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@15: stmnt_load.setString(1, uuid.toString()); 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(); sascha@15: if (last_access + ttl > System.currentTimeMillis()) { sascha@15: artifactOutdated(id); sascha@15: return null; sascha@15: } sascha@15: } sascha@15: sascha@15: byte [] bytes = load_result.getBytes(4); sascha@15: sascha@15: if (bytes == null) { sascha@15: return null; sascha@15: } sascha@15: sascha@15: Artifact original = restoreArtifact(bytes); sascha@15: if (original == null) { sascha@15: return null; sascha@15: } sascha@15: sascha@15: return new ArtifactProxy(original, id, false); 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: public static Artifact restoreArtifact(byte [] bytes) { sascha@15: sascha@15: ObjectInputStream ois = null; sascha@15: sascha@15: try { sascha@15: ByteArrayInputStream bis = new ByteArrayInputStream(bytes); sascha@15: GZIPInputStream gis = new GZIPInputStream(bis); sascha@15: ois = new ObjectInputStream(gis); sascha@15: sascha@15: return (Artifact)ois.readObject(); sascha@15: } sascha@15: catch (IOException ioe) { sascha@17: logger.error(ioe.getLocalizedMessage(), ioe); sascha@15: } sascha@15: catch (ClassNotFoundException cnfe) { sascha@17: logger.error(cnfe.getLocalizedMessage(), cnfe); sascha@15: } sascha@15: catch (ClassCastException cce) { sascha@17: logger.error(cce.getLocalizedMessage(), cce); sascha@15: } sascha@15: finally { sascha@15: if (ois != null) { sascha@15: try { ois.close(); } sascha@15: catch (IOException ioe) { } sascha@15: } 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@15: } sascha@15: sascha@14: protected int insertDatabase(UUID uuid, Long ttl) { 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@14: stmnt_insert.setString(2, uuid.toString()); 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@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@14: public void touch(ArtifactProxy proxy) { sascha@17: logger.info("touch: " + proxy); sascha@14: if (proxy.isUnwritten()) { sascha@14: store(proxy); sascha@14: return; sascha@14: } sascha@14: Connection connection = null; sascha@14: PreparedStatement stmnt_touch = null; sascha@14: DataSource dataSource = DBConnection.getDataSource(); sascha@14: try { sascha@14: connection = dataSource.getConnection(); sascha@14: try { sascha@14: connection.setAutoCommit(false); sascha@14: stmnt_touch = connection.prepareStatement(SQL_UPDATE); sascha@14: stmnt_touch.setInt(1, proxy.getId()); sascha@14: stmnt_touch.execute(); sascha@14: connection.commit(); sascha@14: } sascha@14: catch (SQLException sqle) { sascha@14: connection.rollback(); sascha@14: } sascha@14: } sascha@14: catch (SQLException sqle) { sascha@17: logger.error(sqle.getLocalizedMessage(), sqle); sascha@14: } sascha@14: finally { sascha@14: if (stmnt_touch != null) { sascha@14: try { stmnt_touch.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: } sascha@14: sascha@14: public void store(ArtifactProxy proxy) { sascha@17: logger.info("store: " + proxy); sascha@14: Connection connection = null; sascha@14: PreparedStatement stmnt_update = null; sascha@14: DataSource dataSource = DBConnection.getDataSource(); sascha@14: try { sascha@14: connection = dataSource.getConnection(); sascha@14: try { sascha@14: connection.setAutoCommit(false); sascha@14: stmnt_update = connection.prepareStatement(SQL_UPDATE); sascha@14: stmnt_update.setInt(1, proxy.getId()); sascha@14: stmnt_update.setBytes(2, proxy.toBytes()); sascha@14: stmnt_update.execute(); sascha@14: connection.commit(); sascha@14: } sascha@14: catch (SQLException sqle) { sascha@14: connection.rollback(); sascha@14: } sascha@14: } sascha@14: catch (SQLException sqle) { sascha@17: logger.error(sqle.getLocalizedMessage(), sqle); sascha@14: } sascha@14: finally { sascha@14: if (stmnt_update != null) { sascha@14: try { stmnt_update.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: } sascha@14: sascha@13: } sascha@13: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: