Skip to content

Commit

Permalink
HHH-7187 - Enhanced default revision entity
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz-antoniak authored and stliu committed Apr 19, 2012
1 parent 775b6da commit c482255
Show file tree
Hide file tree
Showing 47 changed files with 283 additions and 439 deletions.
Expand Up @@ -70,6 +70,9 @@ public class GlobalConfiguration {
// Suffix to be used for modified flags columns
private String modifiedFlagSuffix;

// Use enhanced default revision entity (only for internal use)
private final boolean useEnhancedRevisionEntity;

/*
Which operator to use in correlated subqueries (when we want a property to be equal to the result of
a correlated subquery, for example: e.p <operator> (select max(e2.p) where e2.p2 = e.p2 ...).
Expand Down Expand Up @@ -109,6 +112,12 @@ public GlobalConfiguration(Properties properties) {
"false");
trackEntitiesChangedInRevisionEnabled = Boolean.parseBoolean(trackEntitiesChangedInRevisionEnabledStr);

String useEnhancedRevisionEntityStr = getProperty(properties,
"org.hibernate.envers.use_enhanced_revision_entity",
"org.hibernate.envers.use_enhanced_revision_entity",
"false");
useEnhancedRevisionEntity = Boolean.parseBoolean(useEnhancedRevisionEntityStr);

hasGlobalSettingForWithModifiedFlag =
properties.getProperty(GLOBAL_WITH_MODIFIED_FLAG_PROPERTY) != null;
String usingModifiedFlagStr = getProperty(properties,
Expand Down Expand Up @@ -181,4 +190,8 @@ public boolean isGlobalWithModifiedFlag() {
public String getModifiedFlagSuffix() {
return modifiedFlagSuffix;
}

public boolean isUseEnhancedRevisionEntity() {
return useEnhancedRevisionEntity;
}
}
Expand Up @@ -75,7 +75,11 @@ public class RevisionInfoConfiguration {

public RevisionInfoConfiguration(GlobalConfiguration globalCfg) {
this.globalCfg = globalCfg;
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
if (globalCfg.isUseEnhancedRevisionEntity()) {
revisionInfoEntityName = "org.hibernate.envers.enhanced.DefaultRevisionEntity";
} else {
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
}
revisionInfoIdData = new PropertyData("id", "id", "field", null);
revisionInfoTimestampData = new PropertyData("timestamp", "timestamp", "field", null);
modifiedEntityNamesData = new PropertyData("modifiedEntityNames", "modifiedEntityNames", "field", null);
Expand All @@ -93,7 +97,7 @@ private Document generateDefaultRevisionInfoXmlMapping() {
class_mapping.addAttribute("table", "REVINFO");

Element idProperty = MetadataTools.addNativelyGeneratedId(class_mapping, revisionInfoIdData.getName(),
revisionPropType);
revisionPropType, globalCfg.isUseEnhancedRevisionEntity());
MetadataTools.addColumn(idProperty, "REV", null, null, null, null, null, null, false);

Element timestampProperty = MetadataTools.addProperty(class_mapping, revisionInfoTimestampData.getName(),
Expand Down Expand Up @@ -291,9 +295,10 @@ public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionMa
revisionInfoClass = pc.getMappedClass();
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(revisionEntity.value());
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() ||
DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass) ||
modifiedEntityNamesFound.isSet()) {
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()
|| (!globalCfg.isUseEnhancedRevisionEntity() && DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass))
|| (globalCfg.isUseEnhancedRevisionEntity() && org.hibernate.envers.enhanced.DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass))
|| modifiedEntityNamesFound.isSet()) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName,
Expand All @@ -314,12 +319,14 @@ revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestamp

if (revisionInfoGenerator == null) {
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
revisionInfoClass = DefaultTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = DefaultTrackingModifiedEntitiesRevisionEntity.class.getName();
revisionInfoClass = globalCfg.isUseEnhancedRevisionEntity() ? org.hibernate.envers.enhanced.DefaultTrackingModifiedEntitiesRevisionEntity.class
: DefaultTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = revisionInfoClass.getName();
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
} else {
revisionInfoClass = DefaultRevisionEntity.class;
revisionInfoClass = globalCfg.isUseEnhancedRevisionEntity() ? org.hibernate.envers.enhanced.DefaultRevisionEntity.class
: DefaultRevisionEntity.class;
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
}
Expand Down
Expand Up @@ -40,14 +40,23 @@
*/
public class MetadataTools {

public static Element addNativelyGeneratedId(Element parent, String name, String type) {
public static Element addNativelyGeneratedId(Element parent, String name, String type,
boolean useEnhancedRevisionEntity) {
Element id_mapping = parent.addElement("id");
id_mapping.addAttribute("name", name).addAttribute("type", type);

Element generator_mapping = id_mapping.addElement("generator");
generator_mapping.addAttribute("class", "native");
/*generator_mapping.addAttribute("class", "sequence");
generator_mapping.addElement("param").addAttribute("name", "sequence").setText("custom");*/
if (useEnhancedRevisionEntity) {
generator_mapping.addAttribute("class", "org.hibernate.id.enhanced.SequenceStyleGenerator");
generator_mapping.addElement("param").addAttribute("name", "sequence_name").setText("REVISION_GENERATOR");
generator_mapping.addElement("param").addAttribute("name", "table_name").setText("REVISION_GENERATOR");
generator_mapping.addElement("param").addAttribute("name", "initial_value").setText("1");
generator_mapping.addElement("param").addAttribute("name", "increment_size").setText("1");
} else {
generator_mapping.addAttribute("class", "native");
}
// generator_mapping.addAttribute("class", "sequence");
// generator_mapping.addElement("param").addAttribute("name", "sequence").setText("custom");

return id_mapping;
}
Expand Down
@@ -0,0 +1,105 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.enhanced;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.Date;

/**
* @author Adam Warski (adam at warski dot org)
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
public class DefaultRevisionEntity implements Serializable {
private static final long serialVersionUID = 4159156677698841902L;

@Id
@GeneratedValue(generator = "RevisionNumberSequenceGenerator")
@GenericGenerator(name = "RevisionNumberSequenceGenerator",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {@Parameter(name = "table_name", value = "REVISION_GENERATOR"),
@Parameter(name = "sequence_name", value = "REVISION_GENERATOR"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1")
}
)
@RevisionNumber
private int id;

@RevisionTimestamp
private long timestamp;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

@Transient
public Date getRevisionDate() {
return new Date(timestamp);
}

public long getTimestamp() {
return timestamp;
}

public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}

public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultRevisionEntity)) return false;

DefaultRevisionEntity that = (DefaultRevisionEntity) o;

if (id != that.id) return false;
if (timestamp != that.timestamp) return false;

return true;
}

public int hashCode() {
int result = id;
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
return result;
}

public String toString() {
return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
}
}
@@ -0,0 +1,79 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.enhanced;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.envers.ModifiedEntityNames;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

/**
* Extension of standard {@link DefaultRevisionEntity} that allows tracking entity names changed in each revision.
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN)
@ModifiedEntityNames
private Set<String> modifiedEntityNames = new HashSet<String>();

public Set<String> getModifiedEntityNames() {
return modifiedEntityNames;
}

public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
this.modifiedEntityNames = modifiedEntityNames;
}

public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity)) return false;
if (!super.equals(o)) return false;

DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;

if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames)
: that.modifiedEntityNames != null) return false;

return true;
}

public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
return result;
}

public String toString() {
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
}
}
Expand Up @@ -27,9 +27,6 @@
import java.util.Properties;
import javax.persistence.EntityManager;

import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.envers.test.entities.reventity.OracleRevisionEntity;
import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.OracleTrackingModifiedEntitiesRevisionEntity;
import org.junit.Before;

import org.hibernate.cfg.Environment;
Expand Down Expand Up @@ -61,16 +58,6 @@ public abstract class AbstractEntityTest extends AbstractEnversTest {

public abstract void configure(Ejb3Configuration cfg);

protected void revisionEntityForDialect(Ejb3Configuration cfg, Dialect dialect, Properties configurationProperties) {
if (dialect instanceof Oracle8iDialect) {
if (Boolean.parseBoolean(configurationProperties.getProperty("org.hibernate.envers.track_entities_changed_in_revision"))) {
cfg.addAnnotatedClass(OracleTrackingModifiedEntitiesRevisionEntity.class);
} else {
cfg.addAnnotatedClass(OracleRevisionEntity.class);
}
}
}

public void addConfigurationProperties(Properties configuration) { }

protected static Dialect getDialect() {
Expand Down Expand Up @@ -110,6 +97,8 @@ protected void init(boolean audited, String auditStrategy) throws IOException {
}
if ( createSchema() ) {
configurationProperties.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
configurationProperties.setProperty( Environment.USE_NEW_ID_GENERATOR_MAPPINGS, "true" );
configurationProperties.setProperty("org.hibernate.envers.use_enhanced_revision_entity", "true");
}
if (auditStrategy != null && !"".equals(auditStrategy)) {
configurationProperties.setProperty("org.hibernate.envers.audit_strategy", auditStrategy);
Expand All @@ -119,7 +108,6 @@ protected void init(boolean audited, String auditStrategy) throws IOException {

cfg = new Ejb3Configuration();
configure(cfg);
revisionEntityForDialect(cfg, getDialect(), configurationProperties);
cfg.configure(configurationProperties);

emf = (EntityManagerFactoryImpl) cfg.buildEntityManagerFactory( createBootstrapRegistryBuilder() );
Expand Down
Expand Up @@ -4,6 +4,7 @@
import java.net.URISyntaxException;
import java.net.URL;

import org.hibernate.cfg.Environment;
import org.junit.Before;

import org.hibernate.MappingException;
Expand Down Expand Up @@ -41,6 +42,8 @@ public void init() throws URISyntaxException {
if (auditStrategy != null && !"".equals(auditStrategy)) {
config.setProperty("org.hibernate.envers.audit_strategy", auditStrategy);
}
config.setProperty( Environment.USE_NEW_ID_GENERATOR_MAPPINGS, "true" );
config.setProperty("org.hibernate.envers.use_enhanced_revision_entity", "true");
addProperties(config);

this.initMappings();
Expand Down

0 comments on commit c482255

Please sign in to comment.