HHH-5560 - Rename Envers ValidAuditTimeStrategy to ValidityAuditTimeStrategy
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@20717 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
5823732c45
commit
dd8fe46f58
|
@ -35,7 +35,7 @@ import java.util.Properties;
|
|||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.envers.strategy.DefaultAuditStrategy;
|
||||
import org.hibernate.envers.strategy.ValidTimeAuditStrategy;
|
||||
import org.hibernate.envers.strategy.ValidityAuditStrategy;
|
||||
|
||||
/**
|
||||
* Configuration of versions entities - names of fields, entities and tables created to store versioning information.
|
||||
|
@ -93,7 +93,7 @@ public class AuditEntitiesConfiguration {
|
|||
revisionTypePropType = "byte";
|
||||
|
||||
revisionEndFieldName = getProperty(properties,
|
||||
"org.hibernate.envers.audit_strategy_valid_time_end_name",
|
||||
"org.hibernate.envers.audit_strategy_validity_end_rev_field_name",
|
||||
"org.hibernate.envers.audit_strategy_valid_time_end_name",
|
||||
"REVEND");
|
||||
|
||||
|
|
|
@ -28,9 +28,11 @@ import java.util.Iterator;
|
|||
import java.util.Map;
|
||||
|
||||
import org.dom4j.Element;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.envers.RelationTargetAuditMode;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.metadata.reader.ClassAuditingData;
|
||||
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||
import org.hibernate.envers.entities.EntityConfiguration;
|
||||
|
@ -40,15 +42,20 @@ import org.hibernate.envers.entities.mapper.ExtendedPropertyMapper;
|
|||
import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
|
||||
import org.hibernate.envers.entities.mapper.SubclassPropertyMapper;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.envers.strategy.ValidTimeAuditStrategy;
|
||||
import org.hibernate.envers.strategy.ValidityAuditStrategy;
|
||||
import org.hibernate.envers.tools.StringTools;
|
||||
import org.hibernate.envers.tools.Triple;
|
||||
import org.hibernate.envers.RelationTargetAuditMode;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.mapping.*;
|
||||
import org.hibernate.type.*;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Join;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.ManyToOneType;
|
||||
import org.hibernate.type.OneToOneType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -139,7 +146,7 @@ public final class AuditMetadataGenerator {
|
|||
|
||||
private void addEndRevision(Element any_mapping) {
|
||||
// Add the end-revision field, if the appropriate strategy is used.
|
||||
if (ValidTimeAuditStrategy.class.getName().equals(verEntCfg.getAuditStrategyName())) {
|
||||
if (auditStrategy instanceof ValidityAuditStrategy) {
|
||||
Element end_rev_mapping = (Element) revisionInfoRelationMapping.clone();
|
||||
end_rev_mapping.setName("many-to-one");
|
||||
end_rev_mapping.addAttribute("name", verEntCfg.getRevisionEndFieldName());
|
||||
|
|
|
@ -61,7 +61,7 @@ public final class OneAuditEntityQueryGenerator implements RelationQueryGenerato
|
|||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
|
|
|
@ -62,7 +62,7 @@ public final class OneEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
|
|
|
@ -70,7 +70,7 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
|
@ -80,7 +80,7 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* f.revision = (SELECT max(f2.revision) FROM versionsIndexEntity f2
|
||||
* WHERE f2.revision <= :revision AND f2.id_ref_ed = f.id_ref_ed)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* f.revision <= :revision and (f.endRevision > :revision or f.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
|
@ -90,7 +90,7 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
and (
|
||||
|
|
|
@ -68,7 +68,7 @@ public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGen
|
|||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
|
|
|
@ -68,7 +68,7 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
|
@ -78,7 +78,7 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
* (only non-deleted entities and associations)
|
||||
|
|
|
@ -67,7 +67,7 @@ public class EntitiesAtRevisionQuery extends AbstractAuditQuery {
|
|||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* --> for ValidityAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
|
|
|
@ -49,7 +49,7 @@ public interface AuditStrategy {
|
|||
* <li>For {@link DefaultAuditStrategy} a subquery is created:
|
||||
* <p><code>e.revision = (SELECT max(...) ...)</code></p>
|
||||
* </li>
|
||||
* <li>for {@link ValidTimeAuditStrategy} the revision-end column is used:
|
||||
* <li>for {@link ValidityAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
|
@ -57,13 +57,13 @@ public interface AuditStrategy {
|
|||
* @param globalCfg the {@link GlobalConfiguration}
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||
* @param idData id-information for the two-entity relation (only used for {@link DefaultAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param alias1 an alias used for subquery (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param alias2 an alias used for subquery (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param alias1 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||
* @param alias2 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||
*/
|
||||
void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData,
|
||||
|
@ -76,20 +76,20 @@ public interface AuditStrategy {
|
|||
* <li>For {@link DefaultAuditStrategy} a subquery is created:
|
||||
* <p><code>e.revision = (SELECT max(...) ...)</code></p>
|
||||
* </li>
|
||||
* <li>for {@link ValidTimeAuditStrategy} the revision-end column is used:
|
||||
* <li>for {@link ValidityAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||
* @param referencingIdData id-information for the middle-entity association (only used for {@link DefaultAuditStrategy})
|
||||
* @param versionsMiddleEntityName name of the middle-entity
|
||||
* @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param componentDatas information about the middle-entity relation
|
||||
*/
|
||||
void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
|
|
|
@ -1,135 +1,25 @@
|
|||
package org.hibernate.envers.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Audit strategy which additionally manages the end-revision number: updates the end-revision field on the last
|
||||
* revision that was persisted before the current one.
|
||||
* Deprecated Audit strategy class.
|
||||
*
|
||||
* @author Stephanie Pau
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*
|
||||
* @deprecated use {@link ValidityAuditStrategy} instead.
|
||||
*/
|
||||
public class ValidTimeAuditStrategy implements AuditStrategy {
|
||||
public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
|
||||
Object revision) {
|
||||
AuditEntitiesConfiguration audEntCfg = auditCfg.getAuditEntCfg();
|
||||
String auditedEntityName = audEntCfg.getAuditEntityName(entityName);
|
||||
public class ValidTimeAuditStrategy extends ValidityAuditStrategy {
|
||||
|
||||
// Update the end date of the previous row if this operation is expected to have a previous row
|
||||
if (getRevisionType(auditCfg, data) != RevisionType.ADD) {
|
||||
/*
|
||||
Constructing a query:
|
||||
select e from audited_ent e where e.end_rev is null and e.id = :id
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(ValidTimeAuditStrategy.class);
|
||||
|
||||
QueryBuilder qb = new QueryBuilder(auditedEntityName, "e");
|
||||
|
||||
// e.id = :id
|
||||
IdMapper idMapper = auditCfg.getEntCfg().get(entityName).getIdMapper();
|
||||
idMapper.addIdEqualsToQuery(qb.getRootParameters(), id, auditCfg.getAuditEntCfg().getOriginalIdPropName(), true);
|
||||
|
||||
updateLastRevision(session, auditCfg, qb, id, auditedEntityName, revision);
|
||||
}
|
||||
|
||||
// Save the audit data
|
||||
session.save(auditedEntityName, data);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public void performCollectionChange(Session session, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
||||
// Update the end date of the previous row if this operation is expected to have a previous row
|
||||
if (getRevisionType(auditCfg, persistentCollectionChangeData.getData()) != RevisionType.ADD) {
|
||||
/*
|
||||
Constructing a query (there are multiple id fields):
|
||||
select e from audited_middle_ent e where e.end_rev is null and e.id1 = :id1 and e.id2 = :id2 ...
|
||||
*/
|
||||
|
||||
QueryBuilder qb = new QueryBuilder(persistentCollectionChangeData.getEntityName(), "e");
|
||||
|
||||
// Adding a parameter for each id component, except the rev number
|
||||
String originalIdPropName = auditCfg.getAuditEntCfg().getOriginalIdPropName();
|
||||
Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
|
||||
originalIdPropName);
|
||||
for (Map.Entry<String, Object> originalIdEntry : originalId.entrySet()) {
|
||||
if (!auditCfg.getAuditEntCfg().getRevisionFieldName().equals(originalIdEntry.getKey())) {
|
||||
qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(),
|
||||
true, "=", originalIdEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
updateLastRevision(session, auditCfg, qb, originalId, persistentCollectionChangeData.getEntityName(), revision);
|
||||
}
|
||||
|
||||
// Save the audit data
|
||||
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
|
||||
}
|
||||
|
||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||
String revisionProperty,String revisionEndProperty, boolean addAlias,
|
||||
MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
|
||||
String alias1, String alias2) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
||||
}
|
||||
|
||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
||||
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
||||
}
|
||||
|
||||
private void addRevisionRestriction(Parameters rootParameters,
|
||||
String revisionProperty, String revisionEndProperty, boolean addAlias) {
|
||||
|
||||
// e.revision <= _revision and (e.endRevision > _revision or e.endRevision is null)
|
||||
Parameters subParm = rootParameters.addSubParameters("or");
|
||||
rootParameters.addWhereWithNamedParam(revisionProperty, addAlias, "<=", "revision");
|
||||
subParm.addWhereWithNamedParam(revisionEndProperty + ".id", addAlias, ">", "revision");
|
||||
subParm.addWhere(revisionEndProperty, addAlias, "is", "null", false);
|
||||
/**
|
||||
* Default constructor. Log a warn message that this class is deprecated.
|
||||
*/
|
||||
public ValidTimeAuditStrategy() {
|
||||
log.warn("ValidTimeAuditStrategy is deprecated, please use ValidityAuditStrategy instead");
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private RevisionType getRevisionType(AuditConfiguration auditCfg, Object data) {
|
||||
return (RevisionType) ((Map<String, Object>) data).get(auditCfg.getAuditEntCfg().getRevisionTypePropName());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private void updateLastRevision(Session session, AuditConfiguration auditCfg, QueryBuilder qb,
|
||||
Object id, String auditedEntityName, Object revision) {
|
||||
String revisionEndFieldName = auditCfg.getAuditEntCfg().getRevisionEndFieldName();
|
||||
|
||||
// e.end_rev is null
|
||||
qb.getRootParameters().addWhere(revisionEndFieldName, true, "is", "null", false);
|
||||
|
||||
List l = qb.toQuery(session).list();
|
||||
|
||||
// There should be one entry
|
||||
if (l.size() == 1) {
|
||||
// Setting the end revision to be the current rev
|
||||
Object previousData = l.get(0);
|
||||
((Map<String, Object>) previousData).put(revisionEndFieldName, revision);
|
||||
|
||||
// Saving the previous version
|
||||
session.save(auditedEntityName, previousData);
|
||||
} else {
|
||||
throw new RuntimeException("Cannot find previous revision for entity " + auditedEntityName + " and id " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
package org.hibernate.envers.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
* Audit strategy which persists and retrieves audit information using a validity algorithm, based on the
|
||||
* start-revision and end-revision of a row in the audit tables.
|
||||
* <p>This algorithm works as follows:
|
||||
* <ul>
|
||||
* <li>For a <strong>new row</strong> that is persisted in an audit table, only the <strong>start-revision</strong> column of that row is set</li>
|
||||
* <li>At the same time the <strong>end-revision</strong> field of the <strong>previous</strong> audit row is set to this revision</li>
|
||||
* <li>Queries are retrieved using 'between start and end revision', instead of a subquery.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This has a few important consequences that need to be judged against against each other:
|
||||
* <ul>
|
||||
* <li>Persisting audit information is a bit slower, because an extra row is updated</li>
|
||||
* <li>Retrieving audit information is a lot faster</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @author Stephanie Pau
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class ValidityAuditStrategy implements AuditStrategy {
|
||||
public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
|
||||
Object revision) {
|
||||
AuditEntitiesConfiguration audEntCfg = auditCfg.getAuditEntCfg();
|
||||
String auditedEntityName = audEntCfg.getAuditEntityName(entityName);
|
||||
|
||||
// Update the end date of the previous row if this operation is expected to have a previous row
|
||||
if (getRevisionType(auditCfg, data) != RevisionType.ADD) {
|
||||
/*
|
||||
Constructing a query:
|
||||
select e from audited_ent e where e.end_rev is null and e.id = :id
|
||||
*/
|
||||
|
||||
QueryBuilder qb = new QueryBuilder(auditedEntityName, "e");
|
||||
|
||||
// e.id = :id
|
||||
IdMapper idMapper = auditCfg.getEntCfg().get(entityName).getIdMapper();
|
||||
idMapper.addIdEqualsToQuery(qb.getRootParameters(), id, auditCfg.getAuditEntCfg().getOriginalIdPropName(), true);
|
||||
|
||||
updateLastRevision(session, auditCfg, qb, id, auditedEntityName, revision);
|
||||
}
|
||||
|
||||
// Save the audit data
|
||||
session.save(auditedEntityName, data);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public void performCollectionChange(Session session, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
||||
// Update the end date of the previous row if this operation is expected to have a previous row
|
||||
if (getRevisionType(auditCfg, persistentCollectionChangeData.getData()) != RevisionType.ADD) {
|
||||
/*
|
||||
Constructing a query (there are multiple id fields):
|
||||
select e from audited_middle_ent e where e.end_rev is null and e.id1 = :id1 and e.id2 = :id2 ...
|
||||
*/
|
||||
|
||||
QueryBuilder qb = new QueryBuilder(persistentCollectionChangeData.getEntityName(), "e");
|
||||
|
||||
// Adding a parameter for each id component, except the rev number
|
||||
String originalIdPropName = auditCfg.getAuditEntCfg().getOriginalIdPropName();
|
||||
Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
|
||||
originalIdPropName);
|
||||
for (Map.Entry<String, Object> originalIdEntry : originalId.entrySet()) {
|
||||
if (!auditCfg.getAuditEntCfg().getRevisionFieldName().equals(originalIdEntry.getKey())) {
|
||||
qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(),
|
||||
true, "=", originalIdEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
updateLastRevision(session, auditCfg, qb, originalId, persistentCollectionChangeData.getEntityName(), revision);
|
||||
}
|
||||
|
||||
// Save the audit data
|
||||
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
|
||||
}
|
||||
|
||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||
String revisionProperty,String revisionEndProperty, boolean addAlias,
|
||||
MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
|
||||
String alias1, String alias2) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
||||
}
|
||||
|
||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
||||
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
||||
}
|
||||
|
||||
private void addRevisionRestriction(Parameters rootParameters,
|
||||
String revisionProperty, String revisionEndProperty, boolean addAlias) {
|
||||
|
||||
// e.revision <= _revision and (e.endRevision > _revision or e.endRevision is null)
|
||||
Parameters subParm = rootParameters.addSubParameters("or");
|
||||
rootParameters.addWhereWithNamedParam(revisionProperty, addAlias, "<=", "revision");
|
||||
subParm.addWhereWithNamedParam(revisionEndProperty + ".id", addAlias, ">", "revision");
|
||||
subParm.addWhere(revisionEndProperty, addAlias, "is", "null", false);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private RevisionType getRevisionType(AuditConfiguration auditCfg, Object data) {
|
||||
return (RevisionType) ((Map<String, Object>) data).get(auditCfg.getAuditEntCfg().getRevisionTypePropName());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private void updateLastRevision(Session session, AuditConfiguration auditCfg, QueryBuilder qb,
|
||||
Object id, String auditedEntityName, Object revision) {
|
||||
String revisionEndFieldName = auditCfg.getAuditEntCfg().getRevisionEndFieldName();
|
||||
|
||||
// e.end_rev is null
|
||||
qb.getRootParameters().addWhere(revisionEndFieldName, true, "is", "null", false);
|
||||
|
||||
List<Object> l = qb.toQuery(session).list();
|
||||
|
||||
// There should be one entry
|
||||
if (l.size() == 1) {
|
||||
// Setting the end revision to be the current rev
|
||||
Object previousData = l.get(0);
|
||||
((Map<String, Object>) previousData).put(revisionEndFieldName, revision);
|
||||
|
||||
// Saving the previous version
|
||||
session.save(auditedEntityName, previousData);
|
||||
} else {
|
||||
throw new RuntimeException("Cannot find previous revision for entity " + auditedEntityName + " and id " + id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
<!--<property name="connection.username">root</property>-->
|
||||
<!--<property name="connection.password"></property>-->
|
||||
|
||||
<!--<property name="org.hibernate.envers.audit_strategy">org.hibernate.envers.strategy.ValidTimeAuditStrategy</property>-->
|
||||
<!--<property name="org.hibernate.envers.audit_strategy">org.hibernate.envers.strategy.ValidityAuditStrategy</property>-->
|
||||
|
||||
<!--<property name="hibernate.jdbc.batch_size">100</property>-->
|
||||
|
||||
|
|
|
@ -84,8 +84,8 @@
|
|||
&packages;
|
||||
</packages>
|
||||
</test>
|
||||
<test name="ValidTimeAuditStrategy">
|
||||
<parameter name="auditStrategy" value="org.hibernate.envers.strategy.ValidTimeAuditStrategy" />
|
||||
<test name="ValidityAuditStrategy">
|
||||
<parameter name="auditStrategy" value="org.hibernate.envers.strategy.ValidityAuditStrategy" />
|
||||
<packages>
|
||||
&packages;
|
||||
</packages>
|
||||
|
|
Loading…
Reference in New Issue