package org.genedb.db.audit;
import org.gmod.schema.cfg.ChadoAnnotationConfiguration;
import org.gmod.schema.mapped.Feature;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class HibernateChangeSet implements ChangeSet {
private static final Logger logger = Logger.getLogger(HibernateChangeSet.class);
private Session session;
private String key;
private long ceilingAuditId;
public HibernateChangeSet(Session session, String key, long ceilingAuditId) {
this.session = session;
this.ceilingAuditId = ceilingAuditId;
this.key = key;
}
private ChadoAnnotationConfiguration chadoAnnotationConfiguration;
public void setChadoAnnotationConfiguration(
ChadoAnnotationConfiguration chadoAnnotationConfiguration) {
this.chadoAnnotationConfiguration = chadoAnnotationConfiguration;
}
static class ChangeRecord implements Comparable<ChangeRecord> {
private enum Type {INSERT, UPDATE, DELETE}
Type type;
int auditId;
int featureId;
int featureTypeId;
ChangeRecord(Type type, int auditId, int featureId, int featureTypeId) {
this.type = type;
this.auditId = auditId;
this.featureId = featureId;
this.featureTypeId = featureTypeId;
}
@Override
public int compareTo(ChangeRecord other) {
return this.auditId - other.auditId;
}
}
private Map<Integer, ChangeRecord> inserts = new TreeMap<Integer, ChangeRecord>();
private Map<Integer, ChangeRecord> updates = new TreeMap<Integer, ChangeRecord>();
private Map<Integer, ChangeRecord> deletes = new TreeMap<Integer, ChangeRecord>();
void insertedFeature(int auditId, int featureId, int typeId) {
ChangeRecord cr = new ChangeRecord(ChangeRecord.Type.INSERT,
auditId, featureId, typeId);
assert !inserts.containsKey(featureId);
assert !updates.containsKey(featureId);
assert !deletes.containsKey(featureId);
inserts.put(featureId, cr);
}
void updatedFeature(int auditId, int featureId, int typeId) {
ChangeRecord cr = new ChangeRecord(ChangeRecord.Type.UPDATE,
auditId, featureId, typeId);
inserts.remove(featureId);
updates.put(featureId, cr);
deletes.remove(featureId);
}
void deletedFeature(int auditId, int featureId, int typeId) {
if (inserts.containsKey(featureId)) {
// If a feature has been inserted then deleted in the same
// change set, remove all record of it.
inserts.remove(featureId);
updates.remove(featureId);
assert !deletes.containsKey(featureId);
return;
}
ChangeRecord cr = new ChangeRecord(ChangeRecord.Type.DELETE,
auditId, featureId, typeId);
updates.remove(featureId);
deletes.put(featureId, cr);
}
@Override
public void commit() throws SQLException {
int n = session.createSQLQuery(
"update audit.checkpoint set audit_id = :ceiling where key = :key"
).setLong("ceiling", ceilingAuditId)
.setString("key", key)
.executeUpdate();
if (n < 1) {
logger.info(String.format("No existing audit.checkpoint record for key '%s'", key));
session.createSQLQuery(
"insert into audit.checkpoint (key, audit_id) values (:key, :ceiling)"
).setLong("ceiling", ceilingAuditId)
.setString("key", key)
.executeUpdate();
}
}
private Collection<Integer> featureIdsFromChangeRecordsFilteredByClass(Iterable<ChangeRecord> crs,
Class<? extends Feature> featureClass) {
Collection<Integer> typeIds = chadoAnnotationConfiguration.getTypeIdsByClass(featureClass);
Set<Integer> newFeatureIds = new HashSet<Integer>();
for (ChangeRecord cr: crs) {
if (typeIds.contains(cr.featureTypeId)) {
newFeatureIds.add(cr.featureId);
}
}
return newFeatureIds;
}
@Override
public Collection<Integer> newFeatureIds(Class<? extends Feature> featureClass) {
return featureIdsFromChangeRecordsFilteredByClass(inserts.values(), featureClass);
}
@Override
public Collection<Integer> changedFeatureIds(Class<? extends Feature> featureClass) {
return featureIdsFromChangeRecordsFilteredByClass(updates.values(), featureClass);
}
@Override
public Collection<Integer> deletedFeatureIds(Class<? extends Feature> featureClass) {
return featureIdsFromChangeRecordsFilteredByClass(deletes.values(), featureClass);
}
}