HHH-8159 - Apply fixups indicated by analysis tools
This commit is contained in:
parent
ad1d1ab8b4
commit
364a47f2c7
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,11 +22,12 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
import javax.persistence.JoinColumn;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
@ -34,25 +35,25 @@ import javax.persistence.JoinColumn;
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||||
public @interface AuditJoinTable {
|
public @interface AuditJoinTable {
|
||||||
/**
|
/**
|
||||||
* @return Name of the join table. Defaults to a concatenation of the names of the primary table of the entity
|
* Name of the join table. Defaults to a concatenation of the names of the primary table of the entity
|
||||||
* owning the association and of the primary table of the entity referenced by the association.
|
* owning the association and of the primary table of the entity referenced by the association.
|
||||||
*/
|
*/
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The schema of the join table. Defaults to the schema of the entity owning the association.
|
* The schema of the join table. Defaults to the schema of the entity owning the association.
|
||||||
*/
|
*/
|
||||||
String schema() default "";
|
String schema() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The catalog of the join table. Defaults to the catalog of the entity owning the association.
|
* The catalog of the join table. Defaults to the catalog of the entity owning the association.
|
||||||
*/
|
*/
|
||||||
String catalog() default "";
|
String catalog() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The foreign key columns of the join table which reference the primary table of the entity that does not
|
* The foreign key columns of the join table which reference the primary table of the entity that does not
|
||||||
* own the association (i.e. the inverse side of the association).
|
* own the association (i.e. the inverse side of the association).
|
||||||
*/
|
*/
|
||||||
JoinColumn[] inverseJoinColumns() default {};
|
JoinColumn[] inverseJoinColumns() default {};
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
@ -11,7 +12,7 @@ import java.lang.annotation.Target;
|
||||||
* the many side. Then, Envers won't use a join table to audit this relation, but will store changes as in a normal
|
* the many side. Then, Envers won't use a join table to audit this relation, but will store changes as in a normal
|
||||||
* bi-directional relation.
|
* bi-directional relation.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p/>
|
||||||
* <p>
|
* <p>
|
||||||
* This annotation is <b>experimental</b> and may change in future releases.
|
* This annotation is <b>experimental</b> and may change in future releases.
|
||||||
* </p>
|
* </p>
|
||||||
|
@ -21,16 +22,17 @@ import java.lang.annotation.Target;
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||||
public @interface AuditMappedBy {
|
public @interface AuditMappedBy {
|
||||||
/**
|
/**
|
||||||
* @return Name of the property in the related entity which maps back to this entity. The property should be
|
* Name of the property in the related entity which maps back to this entity. The property should be
|
||||||
* mapped with {@code @ManyToOne} and {@code @Column(insertable=false, updatable=false)}.
|
* mapped with {@code @ManyToOne} and {@code @Column(insertable=false, updatable=false)}.
|
||||||
*/
|
*/
|
||||||
String mappedBy();
|
String mappedBy();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Name of the property in the related entity which maps to the position column. Should be specified only
|
* Name of the property in the related entity which maps to the position column. Should be specified only
|
||||||
* for indexed collection, when @{@link org.hibernate.annotations.IndexColumn} is used on the collection.
|
* for indexed collection, when @{@link org.hibernate.annotations.IndexColumn} or
|
||||||
* The property should be mapped with {@code @Column(insertable=false, updatable=false)}.
|
* {@link javax.persistence.OrderColumn} is used on the collection. The property should be mapped with
|
||||||
*/
|
* {@code @Column(insertable=false, updatable=false)}.
|
||||||
String positionMappedBy() default "";
|
*/
|
||||||
|
String positionMappedBy() default "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
import javax.persistence.MappedSuperclass;
|
|
||||||
|
|
||||||
import static java.lang.annotation.ElementType.FIELD;
|
import static java.lang.annotation.ElementType.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
@ -10,43 +33,44 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@code AuditingOverride} annotation is used to override the auditing
|
* The {@code AuditingOverride} annotation is used to override the auditing
|
||||||
* behavior of a superclass or single property inherited from {@link MappedSuperclass}
|
* behavior of a superclass or single property inherited from {@link javax.persistence.MappedSuperclass}
|
||||||
* type, or attribute inside an embedded component.
|
* type, or attribute inside an embedded component.
|
||||||
*
|
*
|
||||||
* @author Erik-Berndt Scheper
|
* @author Erik-Berndt Scheper
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*
|
||||||
* @see javax.persistence.Embedded
|
* @see javax.persistence.Embedded
|
||||||
* @see javax.persistence.Embeddable
|
* @see javax.persistence.Embeddable
|
||||||
* @see javax.persistence.MappedSuperclass
|
* @see javax.persistence.MappedSuperclass
|
||||||
* @see javax.persistence.AssociationOverride
|
* @see javax.persistence.AssociationOverride
|
||||||
* @see AuditJoinTable
|
* @see AuditJoinTable
|
||||||
*/
|
*/
|
||||||
@Target({ TYPE, METHOD, FIELD })
|
@Target({TYPE, METHOD, FIELD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface AuditOverride {
|
public @interface AuditOverride {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Name of the field (or property) whose mapping is being overridden. Allows empty value if
|
* Name of the field (or property) whose mapping is being overridden. Allows empty value if
|
||||||
* {@link AuditOverride} is used to change auditing behavior of all attributes inherited from
|
* {@link AuditOverride} is used to change auditing behavior of all attributes inherited from
|
||||||
* {@link MappedSuperclass} type.
|
* {@link javax.persistence.MappedSuperclass} type.
|
||||||
*/
|
*/
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Indicates if the field (or property) is audited; defaults to {@code true}.
|
* Indicates if the field (or property) is audited; defaults to {@code true}.
|
||||||
*/
|
*/
|
||||||
boolean isAudited() default true;
|
boolean isAudited() default true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return New {@link AuditJoinTable} used for this field (or property). Its value
|
* New {@link AuditJoinTable} used for this field (or property). Its value
|
||||||
* is ignored if {@link #isAudited()} equals to {@code false}.
|
* is ignored if {@link #isAudited()} equals to {@code false}.
|
||||||
*/
|
*/
|
||||||
AuditJoinTable auditJoinTable() default @AuditJoinTable;
|
AuditJoinTable auditJoinTable() default @AuditJoinTable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Specifies class which field (or property) mapping is being overridden. <strong>Required</strong> if
|
* Specifies class which field (or property) mapping is being overridden. <strong>Required</strong> if
|
||||||
* {@link AuditOverride} is used to change auditing behavior of attributes inherited from {@link MappedSuperclass}
|
* {@link AuditOverride} is used to change auditing behavior of attributes inherited from
|
||||||
* type.
|
* {@link javax.persistence.MappedSuperclass} type.
|
||||||
*/
|
*/
|
||||||
Class forClass() default void.class;
|
Class forClass() default void.class;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@ -21,11 +45,11 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
* @see AuditJoinTable
|
* @see AuditJoinTable
|
||||||
* @see AuditOverride
|
* @see AuditOverride
|
||||||
*/
|
*/
|
||||||
@Target({ TYPE, METHOD, FIELD })
|
@Target({TYPE, METHOD, FIELD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface AuditOverrides {
|
public @interface AuditOverrides {
|
||||||
/**
|
/**
|
||||||
* @return An array of {@link AuditOverride} values, to define the new auditing
|
* An array of {@link AuditOverride} values, to define the new auditing
|
||||||
* behavior.
|
* behavior.
|
||||||
*/
|
*/
|
||||||
AuditOverride[] value();
|
AuditOverride[] value();
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -40,207 +40,241 @@ import org.hibernate.envers.query.AuditQueryCreator;
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public interface AuditReader {
|
public interface AuditReader {
|
||||||
/**
|
/**
|
||||||
* Find an entity by primary key at the given revision.
|
* Find an entity by primary key at the given revision.
|
||||||
* @param cls Class of the entity.
|
*
|
||||||
* @param primaryKey Primary key of the entity.
|
* @param cls Class of the entity.
|
||||||
* @param revision Revision in which to get the entity.
|
* @param primaryKey Primary key of the entity.
|
||||||
* @return The found entity instance at the given revision (its properties may be partially filled
|
* @param revision Revision in which to get the entity.
|
||||||
* if not all properties are audited) or null, if an entity with that id didn't exist at that
|
* @param <T> The type of the entity to find
|
||||||
* revision.
|
*
|
||||||
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
|
* @return The found entity instance at the given revision (its properties may be partially filled
|
||||||
* @throws NotAuditedException When entities of the given class are not audited.
|
* if not all properties are audited) or null, if an entity with that id didn't exist at that
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
* revision.
|
||||||
*/
|
*
|
||||||
<T> T find(Class<T> cls, Object primaryKey, Number revision) throws
|
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
|
||||||
IllegalArgumentException, NotAuditedException, IllegalStateException;
|
* @throws NotAuditedException When entities of the given class are not audited.
|
||||||
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
/**
|
*/
|
||||||
* Find an entity by primary key at the given revision with the specified entityName.
|
<T> T find(Class<T> cls, Object primaryKey, Number revision) throws
|
||||||
* @param cls Class of the entity.
|
IllegalArgumentException, NotAuditedException, IllegalStateException;
|
||||||
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
|
|
||||||
* @param primaryKey Primary key of the entity.
|
/**
|
||||||
* @param revision Revision in which to get the entity.
|
* Find an entity by primary key at the given revision with the specified entityName.
|
||||||
* @return The found entity instance at the given revision (its properties may be partially filled
|
*
|
||||||
* if not all properties are audited) or null, if an entity with that id didn't exist at that
|
* @param cls Class of the entity.
|
||||||
* revision.
|
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
|
||||||
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
|
* @param primaryKey Primary key of the entity.
|
||||||
* @throws NotAuditedException When entities of the given class are not audited.
|
* @param revision Revision in which to get the entity.
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
* @param <T> The type of the entity to find
|
||||||
*/
|
*
|
||||||
<T> T find(Class<T> cls, String entityName, Object primaryKey,
|
* @return The found entity instance at the given revision (its properties may be partially filled
|
||||||
|
* if not all properties are audited) or null, if an entity with that id didn't exist at that
|
||||||
|
* revision.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
|
||||||
|
* @throws NotAuditedException When entities of the given class are not audited.
|
||||||
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
*/
|
||||||
|
<T> T find(
|
||||||
|
Class<T> cls, String entityName, Object primaryKey,
|
||||||
Number revision) throws IllegalArgumentException,
|
Number revision) throws IllegalArgumentException,
|
||||||
NotAuditedException, IllegalStateException;
|
NotAuditedException, IllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find an entity by primary key at the given revision with the specified entityName,
|
* Find an entity by primary key at the given revision with the specified entityName,
|
||||||
* possibly including deleted entities in the search.
|
* possibly including deleted entities in the search.
|
||||||
* @param cls Class of the entity.
|
*
|
||||||
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
|
* @param cls Class of the entity.
|
||||||
* @param primaryKey Primary key of the entity.
|
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
|
||||||
* @param revision Revision in which to get the entity.
|
* @param primaryKey Primary key of the entity.
|
||||||
* @param includeDeletions Whether to include deleted entities in the search.
|
* @param revision Revision in which to get the entity.
|
||||||
* @return The found entity instance at the given revision (its properties may be partially filled
|
* @param includeDeletions Whether to include deleted entities in the search.
|
||||||
* if not all properties are audited) or null, if an entity with that id didn't exist at that
|
* @param <T> The type of the entity to find
|
||||||
* revision.
|
*
|
||||||
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
|
* @return The found entity instance at the given revision (its properties may be partially filled
|
||||||
* @throws NotAuditedException When entities of the given class are not audited.
|
* if not all properties are audited) or null, if an entity with that id didn't exist at that
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
* revision.
|
||||||
*/
|
*
|
||||||
<T> T find(Class<T> cls, String entityName, Object primaryKey,
|
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
|
||||||
|
* @throws NotAuditedException When entities of the given class are not audited.
|
||||||
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
*/
|
||||||
|
<T> T find(
|
||||||
|
Class<T> cls, String entityName, Object primaryKey,
|
||||||
Number revision, boolean includeDeletions) throws IllegalArgumentException,
|
Number revision, boolean includeDeletions) throws IllegalArgumentException,
|
||||||
NotAuditedException, IllegalStateException;
|
NotAuditedException, IllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of revision numbers, at which an entity was modified.
|
* Get a list of revision numbers, at which an entity was modified.
|
||||||
* @param cls Class of the entity.
|
*
|
||||||
* @param primaryKey Primary key of the entity.
|
* @param cls Class of the entity.
|
||||||
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
* @param primaryKey Primary key of the entity.
|
||||||
* revisions come first).
|
*
|
||||||
* @throws NotAuditedException When entities of the given class are not audited.
|
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
||||||
* @throws IllegalArgumentException If cls or primaryKey is null.
|
* revisions come first).
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
*
|
||||||
*/
|
* @throws NotAuditedException When entities of the given class are not audited.
|
||||||
List<Number> getRevisions(Class<?> cls, Object primaryKey)
|
* @throws IllegalArgumentException If cls or primaryKey is null.
|
||||||
throws IllegalArgumentException, NotAuditedException, IllegalStateException;
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
*/
|
||||||
/**
|
List<Number> getRevisions(Class<?> cls, Object primaryKey)
|
||||||
* Get a list of revision numbers, at which an entity was modified, looking by entityName.
|
throws IllegalArgumentException, NotAuditedException, IllegalStateException;
|
||||||
* @param cls Class of the entity.
|
|
||||||
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
|
/**
|
||||||
* @param primaryKey Primary key of the entity.
|
* Get a list of revision numbers, at which an entity was modified, looking by entityName.
|
||||||
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
*
|
||||||
* revisions come first).
|
* @param cls Class of the entity.
|
||||||
* @throws NotAuditedException When entities of the given class are not audited.
|
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
|
||||||
* @throws IllegalArgumentException If cls or primaryKey is null.
|
* @param primaryKey Primary key of the entity.
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
*
|
||||||
*/
|
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
||||||
List<Number> getRevisions(Class<?> cls, String entityName, Object primaryKey)
|
* revisions come first).
|
||||||
|
*
|
||||||
|
* @throws NotAuditedException When entities of the given class are not audited.
|
||||||
|
* @throws IllegalArgumentException If cls or primaryKey is null.
|
||||||
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
*/
|
||||||
|
List<Number> getRevisions(Class<?> cls, String entityName, Object primaryKey)
|
||||||
throws IllegalArgumentException, NotAuditedException,
|
throws IllegalArgumentException, NotAuditedException,
|
||||||
IllegalStateException;
|
IllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the date, at which a revision was created.
|
* Get the date, at which a revision was created.
|
||||||
* @param revision Number of the revision for which to get the date.
|
*
|
||||||
* @return Date of commiting the given revision.
|
* @param revision Number of the revision for which to get the date.
|
||||||
* @throws IllegalArgumentException If revision is less or equal to 0.
|
*
|
||||||
* @throws RevisionDoesNotExistException If the revision does not exist.
|
* @return Date of commiting the given revision.
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
*
|
||||||
*/
|
* @throws IllegalArgumentException If revision is less or equal to 0.
|
||||||
Date getRevisionDate(Number revision) throws IllegalArgumentException, RevisionDoesNotExistException,
|
* @throws RevisionDoesNotExistException If the revision does not exist.
|
||||||
IllegalStateException;
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the revision number, that corresponds to the given date. More precisely, returns
|
|
||||||
* the number of the highest revision, which was created on or before the given date. So:
|
|
||||||
* <code>getRevisionDate(getRevisionNumberForDate(date)) <= date</code> and
|
|
||||||
* <code>getRevisionDate(getRevisionNumberForDate(date)+1) > date</code>.
|
|
||||||
* @param date Date for which to get the revision.
|
|
||||||
* @return Revision number corresponding to the given date.
|
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
|
||||||
* @throws RevisionDoesNotExistException If the given date is before the first revision.
|
|
||||||
* @throws IllegalArgumentException If <code>date</code> is <code>null</code>.
|
|
||||||
*/
|
|
||||||
Number getRevisionNumberForDate(Date date) throws IllegalStateException, RevisionDoesNotExistException,
|
|
||||||
IllegalArgumentException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper method; should be used only if a custom revision entity is used. See also {@link RevisionEntity}.
|
|
||||||
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
|
|
||||||
* @param revision Number of the revision for which to get the data.
|
|
||||||
* @return Entity containing data for the given revision.
|
|
||||||
* @throws IllegalArgumentException If revision is less or equal to 0 or if the class of the revision entity
|
|
||||||
* is invalid.
|
|
||||||
* @throws RevisionDoesNotExistException If the revision does not exist.
|
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
|
||||||
*/
|
|
||||||
<T> T findRevision(Class<T> revisionEntityClass, Number revision) throws IllegalArgumentException,
|
|
||||||
RevisionDoesNotExistException, IllegalStateException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a map of revisions using the revision numbers specified.
|
|
||||||
*
|
|
||||||
* @param revisionEntityClass
|
|
||||||
* Class of the revision entity. Should be annotated with
|
|
||||||
* {@link RevisionEntity}.
|
|
||||||
* @param revisions
|
|
||||||
* Revision numbers of the revision for which to get the data.
|
|
||||||
* @return A map of revision number and the given revision entity.
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
* If a revision number is less or equal to 0 or if the class of
|
|
||||||
* the revision entity is invalid.
|
|
||||||
* @throws IllegalStateException
|
|
||||||
* If the associated entity manager is closed.
|
|
||||||
*/
|
*/
|
||||||
<T> Map<Number, T> findRevisions(Class<T> revisionEntityClass,
|
Date getRevisionDate(Number revision) throws IllegalArgumentException, RevisionDoesNotExistException,
|
||||||
|
IllegalStateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the revision number, that corresponds to the given date. More precisely, returns
|
||||||
|
* the number of the highest revision, which was created on or before the given date. So:
|
||||||
|
* <code>getRevisionDate(getRevisionNumberForDate(date)) <= date</code> and
|
||||||
|
* <code>getRevisionDate(getRevisionNumberForDate(date)+1) > date</code>.
|
||||||
|
*
|
||||||
|
* @param date Date for which to get the revision.
|
||||||
|
*
|
||||||
|
* @return Revision number corresponding to the given date.
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
* @throws RevisionDoesNotExistException If the given date is before the first revision.
|
||||||
|
* @throws IllegalArgumentException If <code>date</code> is <code>null</code>.
|
||||||
|
*/
|
||||||
|
Number getRevisionNumberForDate(Date date) throws IllegalStateException, RevisionDoesNotExistException,
|
||||||
|
IllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper method; should be used only if a custom revision entity is used. See also {@link RevisionEntity}.
|
||||||
|
*
|
||||||
|
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
|
||||||
|
* @param revision Number of the revision for which to get the data.
|
||||||
|
* @param <T> The type of the revision entity to find
|
||||||
|
*
|
||||||
|
* @return Entity containing data for the given revision.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException If revision is less or equal to 0 or if the class of the revision entity
|
||||||
|
* is invalid.
|
||||||
|
* @throws RevisionDoesNotExistException If the revision does not exist.
|
||||||
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
*/
|
||||||
|
<T> T findRevision(Class<T> revisionEntityClass, Number revision) throws IllegalArgumentException,
|
||||||
|
RevisionDoesNotExistException, IllegalStateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a map of revisions using the revision numbers specified.
|
||||||
|
*
|
||||||
|
* @param revisionEntityClass Class of the revision entity. Should be annotated with
|
||||||
|
* {@link RevisionEntity}.
|
||||||
|
* @param revisions Revision numbers of the revision for which to get the data.
|
||||||
|
* @param <T> The type of the revision entity to find
|
||||||
|
*
|
||||||
|
* @return A map of revision number and the given revision entity.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException If a revision number is less or equal to 0 or if the class of
|
||||||
|
* the revision entity is invalid.
|
||||||
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
*/
|
||||||
|
<T> Map<Number, T> findRevisions(
|
||||||
|
Class<T> revisionEntityClass,
|
||||||
Set<Number> revisions) throws IllegalArgumentException,
|
Set<Number> revisions) throws IllegalArgumentException,
|
||||||
IllegalStateException;
|
IllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an instance of the current revision entity, to which any entries in the audit tables will be bound.
|
* Gets an instance of the current revision entity, to which any entries in the audit tables will be bound.
|
||||||
* Please note the if {@code persist} is {@code false}, and no audited entities are modified in this session,
|
* Please note the if {@code persist} is {@code false}, and no audited entities are modified in this session,
|
||||||
* then the obtained revision entity instance won't be persisted. If {@code persist} is {@code true}, the revision
|
* then the obtained revision entity instance won't be persisted. If {@code persist} is {@code true}, the revision
|
||||||
* entity instance will always be persisted, regardless of whether audited entities are changed or not.
|
* entity instance will always be persisted, regardless of whether audited entities are changed or not.
|
||||||
|
*
|
||||||
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
|
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
|
||||||
* @param persist If the revision entity is not yet persisted, should it become persisted. This way, the primary
|
* @param persist If the revision entity is not yet persisted, should it become persisted. This way, the primary
|
||||||
* identifier (id) will be filled (if it's assigned by the DB) and available, but the revision entity will be
|
* identifier (id) will be filled (if it's assigned by the DB) and available, but the revision entity will be
|
||||||
* persisted even if there are no changes to audited entities. Otherwise, the revision number (id) can be
|
* persisted even if there are no changes to audited entities. Otherwise, the revision number (id) can be
|
||||||
* {@code null}.
|
* {@code null}.
|
||||||
|
* @param <T> The type of the revision entity to find
|
||||||
|
*
|
||||||
* @return The current revision entity, to which any entries in the audit tables will be bound.
|
* @return The current revision entity, to which any entries in the audit tables will be bound.
|
||||||
*/
|
*/
|
||||||
<T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist);
|
<T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Creates an audit query
|
||||||
* @return A query creator, associated with this AuditReader instance, with which queries can be
|
*
|
||||||
* created and later executed. Shouldn't be used after the associated Session or EntityManager
|
* @return A query creator, associated with this AuditReader instance, with which queries can be
|
||||||
* is closed.
|
* created and later executed. Shouldn't be used after the associated Session or EntityManager
|
||||||
*/
|
* is closed.
|
||||||
AuditQueryCreator createQuery();
|
*/
|
||||||
|
AuditQueryCreator createQuery();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the entityClass was configured to be audited. Calling
|
* Checks if the entityClass was configured to be audited. Calling
|
||||||
* isEntityNameAudited() with the string of the class name will return the
|
* isEntityNameAudited() with the string of the class name will return the
|
||||||
* same value.
|
* same value.
|
||||||
*
|
*
|
||||||
* @param entityClass
|
* @param entityClass Class of the entity asking for audit support
|
||||||
* Class of the entity asking for audit support
|
*
|
||||||
* @return true if the entityClass is audited.
|
* @return true if the entityClass is audited.
|
||||||
*/
|
*/
|
||||||
boolean isEntityClassAudited(Class<?> entityClass);
|
boolean isEntityClassAudited(Class<?> entityClass);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the entityName was configured to be audited.
|
* Checks if the entityName was configured to be audited.
|
||||||
*
|
*
|
||||||
* @param entityName EntityName of the entity asking for audit support.
|
* @param entityName EntityName of the entity asking for audit support.
|
||||||
|
*
|
||||||
* @return true if the entityName is audited.
|
* @return true if the entityName is audited.
|
||||||
*/
|
*/
|
||||||
boolean isEntityNameAudited(String entityName);
|
boolean isEntityNameAudited(String entityName);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @param entity that was obtained previously from the same AuditReader.
|
||||||
* @param entity
|
*
|
||||||
* that was obtained previously from the same AuditReader.
|
|
||||||
*
|
|
||||||
* @return the entityName for the given entity, null in case the entity is
|
* @return the entityName for the given entity, null in case the entity is
|
||||||
* not associated with this AuditReader instance.
|
* not associated with this AuditReader instance.
|
||||||
*/
|
*/
|
||||||
String getEntityName(Object primaryKey, Number revision, Object entity)
|
String getEntityName(Object primaryKey, Number revision, Object entity)
|
||||||
throws HibernateException;
|
throws HibernateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Basic implementation of {@link CrossTypeRevisionChangesReader} interface. Raises an exception if the default
|
* @return Basic implementation of {@link CrossTypeRevisionChangesReader} interface. Raises an exception if the default
|
||||||
* mechanism of tracking entity names modified during revisions has not been enabled.
|
* mechanism of tracking entity names modified during revisions has not been enabled.
|
||||||
* @throws AuditException If none of the following conditions is satisfied:
|
*
|
||||||
* <ul>
|
* @throws AuditException If none of the following conditions is satisfied:
|
||||||
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
|
* <ul>
|
||||||
* parameter is set to <code>true</code>.</li>
|
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
|
||||||
* <li>Custom revision entity (annotated with {@link RevisionEntity})
|
* parameter is set to <code>true</code>.</li>
|
||||||
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
|
* <li>Custom revision entity (annotated with {@link RevisionEntity})
|
||||||
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
|
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
|
||||||
* marked with {@link ModifiedEntityNames} interface.</li>
|
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
|
||||||
* </ul>
|
* marked with {@link ModifiedEntityNames} interface.</li>
|
||||||
*/
|
* </ul>
|
||||||
public CrossTypeRevisionChangesReader getCrossTypeRevisionChangesReader() throws AuditException;
|
*/
|
||||||
|
public CrossTypeRevisionChangesReader getCrossTypeRevisionChangesReader() throws AuditException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,20 +38,25 @@ import org.hibernate.event.spi.PostInsertEventListener;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class AuditReaderFactory {
|
public class AuditReaderFactory {
|
||||||
private AuditReaderFactory() { }
|
private AuditReaderFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an audit reader associated with an open session.
|
* Create an audit reader associated with an open session.
|
||||||
* @param session An open session.
|
*
|
||||||
* @return An audit reader associated with the given sesison. It shouldn't be used
|
* @param session An open session.
|
||||||
* after the session is closed.
|
*
|
||||||
* @throws AuditException When the given required listeners aren't installed.
|
* @return An audit reader associated with the given sesison. It shouldn't be used
|
||||||
*/
|
* after the session is closed.
|
||||||
public static AuditReader get(Session session) throws AuditException {
|
*
|
||||||
SessionImplementor sessionImpl;
|
* @throws AuditException When the given required listeners aren't installed.
|
||||||
if (!(session instanceof SessionImplementor)) {
|
*/
|
||||||
|
public static AuditReader get(Session session) throws AuditException {
|
||||||
|
SessionImplementor sessionImpl;
|
||||||
|
if ( !(session instanceof SessionImplementor) ) {
|
||||||
sessionImpl = (SessionImplementor) session.getSessionFactory().getCurrentSession();
|
sessionImpl = (SessionImplementor) session.getSessionFactory().getCurrentSession();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
sessionImpl = (SessionImplementor) session;
|
sessionImpl = (SessionImplementor) session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,37 +66,41 @@ public class AuditReaderFactory {
|
||||||
.getServiceRegistry()
|
.getServiceRegistry()
|
||||||
.getService( EventListenerRegistry.class );
|
.getService( EventListenerRegistry.class );
|
||||||
|
|
||||||
for ( PostInsertEventListener listener : listenerRegistry.getEventListenerGroup( EventType.POST_INSERT ).listeners() ) {
|
for ( PostInsertEventListener listener : listenerRegistry.getEventListenerGroup( EventType.POST_INSERT )
|
||||||
|
.listeners() ) {
|
||||||
if ( listener instanceof EnversListener ) {
|
if ( listener instanceof EnversListener ) {
|
||||||
// todo : slightly different from original code in that I am not checking the other listener groups...
|
// todo : slightly different from original code in that I am not checking the other listener groups...
|
||||||
return new AuditReaderImpl(
|
return new AuditReaderImpl(
|
||||||
( (EnversListener) listener ).getAuditConfiguration(),
|
((EnversListener) listener).getAuditConfiguration(),
|
||||||
session,
|
session,
|
||||||
sessionImpl
|
sessionImpl
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new AuditException( "Envers listeners were not properly registered" );
|
throw new AuditException( "Envers listeners were not properly registered" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an audit reader associated with an open entity manager.
|
* Create an audit reader associated with an open entity manager.
|
||||||
* @param entityManager An open entity manager.
|
*
|
||||||
* @return An audit reader associated with the given entity manager. It shouldn't be used
|
* @param entityManager An open entity manager.
|
||||||
* after the entity manager is closed.
|
*
|
||||||
* @throws AuditException When the given entity manager is not based on Hibernate, or if the required
|
* @return An audit reader associated with the given entity manager. It shouldn't be used
|
||||||
* listeners aren't installed.
|
* after the entity manager is closed.
|
||||||
*/
|
*
|
||||||
public static AuditReader get(EntityManager entityManager) throws AuditException {
|
* @throws AuditException When the given entity manager is not based on Hibernate, or if the required
|
||||||
if (entityManager.getDelegate() instanceof Session) {
|
* listeners aren't installed.
|
||||||
return get((Session) entityManager.getDelegate());
|
*/
|
||||||
}
|
public static AuditReader get(EntityManager entityManager) throws AuditException {
|
||||||
|
if ( entityManager.getDelegate() instanceof Session ) {
|
||||||
|
return get( (Session) entityManager.getDelegate() );
|
||||||
|
}
|
||||||
|
|
||||||
if (entityManager.getDelegate() instanceof EntityManager) {
|
if ( entityManager.getDelegate() instanceof EntityManager ) {
|
||||||
return get((EntityManager) entityManager.getDelegate());
|
return get( (EntityManager) entityManager.getDelegate() );
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new AuditException("Hibernate EntityManager not present!");
|
throw new AuditException( "Hibernate EntityManager not present!" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
@ -33,15 +34,18 @@ import java.lang.annotation.Target;
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
public @interface AuditTable {
|
public @interface AuditTable {
|
||||||
String value();
|
/**
|
||||||
|
* The name of the table
|
||||||
|
*/
|
||||||
|
String value();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The schema of the table. Defaults to the schema of the annotated entity.
|
* The schema of the table. Defaults to the schema of the annotated entity.
|
||||||
*/
|
*/
|
||||||
String schema() default "";
|
String schema() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The catalog of the table. Defaults to the catalog of the annotated entity.
|
* The catalog of the table. Defaults to the catalog of the annotated entity.
|
||||||
*/
|
*/
|
||||||
String catalog() default "";
|
String catalog() default "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
@ -30,6 +31,7 @@ import java.lang.annotation.Target;
|
||||||
/**
|
/**
|
||||||
* When applied to a class, indicates that all of its properties should be audited.
|
* When applied to a class, indicates that all of its properties should be audited.
|
||||||
* When applied to a field, indicates that this field should be audited.
|
* When applied to a field, indicates that this field should be audited.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Tomasz Bech
|
* @author Tomasz Bech
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
@ -38,33 +40,37 @@ import java.lang.annotation.Target;
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
|
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
|
||||||
public @interface Audited {
|
public @interface Audited {
|
||||||
ModificationStore modStore() default ModificationStore.FULL;
|
/**
|
||||||
|
* Specifies modification store to use
|
||||||
|
*/
|
||||||
|
ModificationStore modStore() default ModificationStore.FULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Specifies if the entity that is the target of the relation should be audited or not. If not, then when
|
* Specifies if the entity that is the target of the relation should be audited or not. If not, then when
|
||||||
* reading a historic version an audited entity, the relation will always point to the "current" entity.
|
* reading a historic version an audited entity, the relation will always point to the "current" entity.
|
||||||
* This is useful for dictionary-like entities, which don't change and don't need to be audited.
|
* This is useful for dictionary-like entities, which don't change and don't need to be audited.
|
||||||
*/
|
*/
|
||||||
RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED;
|
RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Specifies the superclasses for which properties should be audited, even if the superclasses are not
|
* Specifies the superclasses for which properties should be audited, even if the superclasses are not
|
||||||
* annotated with {@link Audited}. Causes all properties of the listed classes to be audited, just as if the
|
* annotated with {@link Audited}. Causes all properties of the listed classes to be audited, just as if the
|
||||||
* classes had {@link Audited} annotation applied on the class level.
|
* classes had {@link Audited} annotation applied on the class level.
|
||||||
*
|
* <p/>
|
||||||
* The scope of this functionality is limited to the class hierarchy of the annotated entity.
|
* The scope of this functionality is limited to the class hierarchy of the annotated entity.
|
||||||
*
|
* <p/>
|
||||||
* If a parent type lists any of its parent types using this attribute, all properties in the specified classes
|
* If a parent type lists any of its parent types using this attribute, all properties in the specified classes
|
||||||
* will also be audited.
|
* will also be audited.
|
||||||
*
|
*
|
||||||
* @deprecated Use {@code @AuditOverride(forClass=SomeEntity.class)} instead.
|
* @deprecated Use {@code @AuditOverride(forClass=SomeEntity.class)} instead.
|
||||||
*/
|
*/
|
||||||
Class[] auditParents() default {};
|
@Deprecated
|
||||||
|
Class[] auditParents() default {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Should a modification flag be stored for each property in the annotated class or for the annotated
|
* Should a modification flag be stored for each property in the annotated class or for the annotated
|
||||||
* property. The flag stores information if a property has been changed at a given revision.
|
* property. The flag stores information if a property has been changed at a given revision.
|
||||||
* This can be used for example in queries.
|
* This can be used for example in queries.
|
||||||
*/
|
*/
|
||||||
boolean withModifiedFlag() default false;
|
boolean withModifiedFlag() default false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -10,52 +33,67 @@ import org.hibernate.envers.tools.Pair;
|
||||||
* Queries that allow retrieving snapshots of all entities (regardless of their particular type) changed in the given
|
* Queries that allow retrieving snapshots of all entities (regardless of their particular type) changed in the given
|
||||||
* revision. Note that this API can be legally used only when default mechanism of tracking modified entity names
|
* revision. Note that this API can be legally used only when default mechanism of tracking modified entity names
|
||||||
* is enabled.
|
* is enabled.
|
||||||
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public interface CrossTypeRevisionChangesReader {
|
public interface CrossTypeRevisionChangesReader {
|
||||||
/**
|
/**
|
||||||
* Find all entities changed (added, updated and removed) in a given revision. Executes <i>n+1</i> SQL queries,
|
* Find all entities changed (added, updated and removed) in a given revision. Executes <i>n+1</i> SQL queries,
|
||||||
* where <i>n</i> is a number of different entity classes modified within specified revision.
|
* where <i>n</i> is a number of different entity classes modified within specified revision.
|
||||||
* @param revision Revision number.
|
*
|
||||||
* @return Snapshots of all audited entities changed in a given revision.
|
* @param revision Revision number.
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
*
|
||||||
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
|
* @return Snapshots of all audited entities changed in a given revision.
|
||||||
*/
|
*
|
||||||
public List<Object> findEntities(Number revision) throws IllegalStateException, IllegalArgumentException;
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
|
||||||
|
*/
|
||||||
|
public List<Object> findEntities(Number revision) throws IllegalStateException, IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all entities changed (added, updated or removed) in a given revision. Executes <i>n+1</i> SQL queries,
|
* Find all entities changed (added, updated or removed) in a given revision. Executes <i>n+1</i> SQL queries,
|
||||||
* where <i>n</i> is a number of different entity classes modified within specified revision.
|
* where <i>n</i> is a number of different entity classes modified within specified revision.
|
||||||
* @param revision Revision number.
|
*
|
||||||
* @param revisionType Type of modification.
|
* @param revision Revision number.
|
||||||
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
|
* @param revisionType Type of modification.
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
*
|
||||||
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
|
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
|
||||||
*/
|
*
|
||||||
public List<Object> findEntities(Number revision, RevisionType revisionType) throws IllegalStateException,
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
IllegalArgumentException;
|
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
|
||||||
|
*/
|
||||||
|
public List<Object> findEntities(Number revision, RevisionType revisionType) throws IllegalStateException,
|
||||||
|
IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all entities changed (added, updated and removed) in a given revision grouped by modification type.
|
* Find all entities changed (added, updated and removed) in a given revision grouped by modification type.
|
||||||
* Executes <i>mn+1</i> SQL queries, where:
|
* Executes <i>mn+1</i> SQL queries, where:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><i>n</i> - number of different entity classes modified within specified revision.
|
* <li><i>n</i> - number of different entity classes modified within specified revision.
|
||||||
* <li><i>m</i> - number of different revision types. See {@link RevisionType} enum.
|
* <li><i>m</i> - number of different revision types. See {@link RevisionType} enum.
|
||||||
* </ul>
|
* </ul>
|
||||||
* @param revision Revision number.
|
*
|
||||||
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
|
* @param revision Revision number.
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
*
|
||||||
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
|
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
|
||||||
*/
|
*
|
||||||
public Map<RevisionType, List<Object>> findEntitiesGroupByRevisionType(Number revision) throws IllegalStateException,
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
IllegalArgumentException;
|
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
|
||||||
|
*/
|
||||||
|
public Map<RevisionType, List<Object>> findEntitiesGroupByRevisionType(Number revision)
|
||||||
|
throws IllegalStateException,
|
||||||
|
IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns set of entity names and corresponding Java classes modified in a given revision.
|
* Returns set of entity names and corresponding Java classes modified in a given revision.
|
||||||
* @param revision Revision number.
|
*
|
||||||
* @return Set of entity names and corresponding Java classes modified in a given revision.
|
* @param revision Revision number.
|
||||||
* @throws IllegalStateException If the associated entity manager is closed.
|
*
|
||||||
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
|
* @return Set of entity names and corresponding Java classes modified in a given revision.
|
||||||
*/
|
*
|
||||||
public Set<Pair<String, Class>> findEntityTypes(Number revision) throws IllegalStateException, IllegalArgumentException;
|
* @throws IllegalStateException If the associated entity manager is closed.
|
||||||
|
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
|
||||||
|
*/
|
||||||
|
public Set<Pair<String, Class>> findEntityTypes(Number revision)
|
||||||
|
throws IllegalStateException, IllegalArgumentException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,13 +22,14 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.MappedSuperclass;
|
import javax.persistence.MappedSuperclass;
|
||||||
import javax.persistence.Transient;
|
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 Adam Warski (adam at warski dot org)
|
||||||
|
@ -36,56 +37,61 @@ import javax.persistence.Transient;
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class DefaultRevisionEntity implements Serializable {
|
public class DefaultRevisionEntity implements Serializable {
|
||||||
private static final long serialVersionUID = 8530213963961662300L;
|
private static final long serialVersionUID = 8530213963961662300L;
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
@RevisionNumber
|
|
||||||
private int id;
|
|
||||||
|
|
||||||
@RevisionTimestamp
|
@Id
|
||||||
private long timestamp;
|
@GeneratedValue
|
||||||
|
@RevisionNumber
|
||||||
|
private int id;
|
||||||
|
|
||||||
public int getId() {
|
@RevisionTimestamp
|
||||||
return id;
|
private long timestamp;
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(int id) {
|
public int getId() {
|
||||||
this.id = id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient
|
public void setId(int id) {
|
||||||
public Date getRevisionDate() {
|
this.id = id;
|
||||||
return new Date(timestamp);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimestamp() {
|
@Transient
|
||||||
return timestamp;
|
public Date getRevisionDate() {
|
||||||
}
|
return new Date( timestamp );
|
||||||
|
}
|
||||||
|
|
||||||
public void setTimestamp(long timestamp) {
|
public long getTimestamp() {
|
||||||
this.timestamp = timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public void setTimestamp(long timestamp) {
|
||||||
if (this == o) return true;
|
this.timestamp = timestamp;
|
||||||
if (!(o instanceof DefaultRevisionEntity)) return false;
|
}
|
||||||
|
|
||||||
DefaultRevisionEntity that = (DefaultRevisionEntity) o;
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( !(o instanceof DefaultRevisionEntity) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (id != that.id) return false;
|
final DefaultRevisionEntity that = (DefaultRevisionEntity) o;
|
||||||
if (timestamp != that.timestamp) return false;
|
return id == that.id
|
||||||
|
&& timestamp == that.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
@Override
|
||||||
}
|
public int hashCode() {
|
||||||
|
int result;
|
||||||
|
result = id;
|
||||||
|
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
@Override
|
||||||
int result;
|
public String toString() {
|
||||||
result = id;
|
return "DefaultRevisionEntity(id = " + id
|
||||||
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
|
+ ", revisionDate = " + DateFormat.getDateTimeInstance().format( getRevisionDate() ) + ")";
|
||||||
return result;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.JoinTable;
|
import javax.persistence.JoinTable;
|
||||||
import javax.persistence.MappedSuperclass;
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.annotations.Fetch;
|
import org.hibernate.annotations.Fetch;
|
||||||
import org.hibernate.annotations.FetchMode;
|
import org.hibernate.annotations.FetchMode;
|
||||||
|
@ -16,45 +39,57 @@ import org.hibernate.annotations.FetchMode;
|
||||||
* Extension of standard {@link DefaultRevisionEntity} that allows tracking entity names changed in each revision.
|
* 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}
|
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
|
||||||
* parameter is set to {@code true}.
|
* parameter is set to {@code true}.
|
||||||
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
|
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
||||||
@Column(name = "ENTITYNAME")
|
@Column(name = "ENTITYNAME")
|
||||||
@Fetch(FetchMode.JOIN)
|
@Fetch(FetchMode.JOIN)
|
||||||
@ModifiedEntityNames
|
@ModifiedEntityNames
|
||||||
private Set<String> modifiedEntityNames = new HashSet<String>();
|
private Set<String> modifiedEntityNames = new HashSet<String>();
|
||||||
|
|
||||||
public Set<String> getModifiedEntityNames() {
|
public Set<String> getModifiedEntityNames() {
|
||||||
return modifiedEntityNames;
|
return modifiedEntityNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
||||||
this.modifiedEntityNames = modifiedEntityNames;
|
this.modifiedEntityNames = modifiedEntityNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
@Override
|
||||||
if (this == o) return true;
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity)) return false;
|
if ( this == o ) {
|
||||||
if (!super.equals(o)) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if ( !(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !super.equals( o ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
|
final DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
|
||||||
|
|
||||||
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames)
|
if ( modifiedEntityNames != null ? !modifiedEntityNames.equals( that.modifiedEntityNames )
|
||||||
: that.modifiedEntityNames != null) return false;
|
: that.modifiedEntityNames != null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
@Override
|
||||||
int result = super.hashCode();
|
public int hashCode() {
|
||||||
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
|
int result = super.hashCode();
|
||||||
return result;
|
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
@Override
|
||||||
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
|
public String toString() {
|
||||||
}
|
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -5,19 +28,22 @@ import java.io.Serializable;
|
||||||
/**
|
/**
|
||||||
* Extension of standard {@link RevisionListener} that notifies whenever an entity instance has been
|
* Extension of standard {@link RevisionListener} that notifies whenever an entity instance has been
|
||||||
* added, modified or removed within current revision boundaries.
|
* added, modified or removed within current revision boundaries.
|
||||||
* @see RevisionListener
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
* @see RevisionListener
|
||||||
*/
|
*/
|
||||||
public interface EntityTrackingRevisionListener extends RevisionListener {
|
public interface EntityTrackingRevisionListener extends RevisionListener {
|
||||||
/**
|
/**
|
||||||
* Called after audited entity data has been persisted.
|
* Called after audited entity data has been persisted.
|
||||||
* @param entityClass Audited entity class.
|
*
|
||||||
* @param entityName Name of the audited entity. May be useful when Java class is mapped multiple times,
|
* @param entityClass Audited entity class.
|
||||||
* potentially to different tables.
|
* @param entityName Name of the audited entity. May be useful when Java class is mapped multiple times,
|
||||||
* @param entityId Identifier of modified entity.
|
* potentially to different tables.
|
||||||
* @param revisionType Modification type (addition, update or removal).
|
* @param entityId Identifier of modified entity.
|
||||||
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}.
|
* @param revisionType Modification type (addition, update or removal).
|
||||||
*/
|
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}.
|
||||||
void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
|
*/
|
||||||
Object revisionEntity);
|
void entityChanged(
|
||||||
|
Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
|
||||||
|
Object revisionEntity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -28,5 +28,5 @@ package org.hibernate.envers;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public enum ModificationStore {
|
public enum ModificationStore {
|
||||||
FULL
|
FULL
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
|
@ -8,6 +31,7 @@ import java.lang.annotation.Target;
|
||||||
/**
|
/**
|
||||||
* Marks a property which holds entity names that have been modified during each revision.
|
* Marks a property which holds entity names that have been modified during each revision.
|
||||||
* This annotation expects field of <code>{@literal Set<String>}</code> type.
|
* This annotation expects field of <code>{@literal Set<String>}</code> type.
|
||||||
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
@ -29,6 +30,7 @@ import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When applied to a field, indicates that this field should not be audited.
|
* When applied to a field, indicates that this field should not be audited.
|
||||||
|
*
|
||||||
* @author Sebastian Komander
|
* @author Sebastian Komander
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
|
|
@ -34,15 +34,15 @@ import java.lang.annotation.Target;
|
||||||
* and a long-valued property annotated with {@link RevisionTimestamp}. The {@link DefaultRevisionEntity}
|
* and a long-valued property annotated with {@link RevisionTimestamp}. The {@link DefaultRevisionEntity}
|
||||||
* already has those two fields, so you may extend it, but you may also write your own revision entity
|
* already has those two fields, so you may extend it, but you may also write your own revision entity
|
||||||
* from scratch.
|
* from scratch.
|
||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
public @interface RevisionEntity {
|
public @interface RevisionEntity {
|
||||||
/**
|
/**
|
||||||
* @return The optional listener that will be used to fill in the custom revision entity.
|
* The optional listener that will be used to fill in the custom revision entity.
|
||||||
* May also be specified using the {@code org.hibernate.envers.revision_listener} configuration property.
|
* May also be specified using the {@code org.hibernate.envers.revision_listener} configuration property.
|
||||||
*/
|
*/
|
||||||
Class<? extends RevisionListener> value() default RevisionListener.class;
|
Class<? extends RevisionListener> value() default RevisionListener.class;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -27,13 +27,15 @@ package org.hibernate.envers;
|
||||||
/**
|
/**
|
||||||
* An implementation of this class, having a no-arg constructor, should be passed as an argument to the
|
* An implementation of this class, having a no-arg constructor, should be passed as an argument to the
|
||||||
* {@link RevisionEntity} annotation.
|
* {@link RevisionEntity} annotation.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public interface RevisionListener {
|
public interface RevisionListener {
|
||||||
/**
|
/**
|
||||||
* Called when a new revision is created.
|
* Called when a new revision is created.
|
||||||
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}, which will be persisted
|
*
|
||||||
* after this method returns. All properties on this entity that are to be persisted should be set by this method.
|
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}, which will be persisted
|
||||||
*/
|
* after this method returns. All properties on this entity that are to be persisted should be set by this method.
|
||||||
void newRevision(Object revisionEntity);
|
*/
|
||||||
|
void newRevision(Object revisionEntity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import java.lang.annotation.Target;
|
||||||
* {@link RevisionListener}. Values of this property should form a strictly-increasing sequence
|
* {@link RevisionListener}. Values of this property should form a strictly-increasing sequence
|
||||||
* of numbers. The value of this property won't be set by Envers. In most cases, this should be
|
* of numbers. The value of this property won't be set by Envers. In most cases, this should be
|
||||||
* an auto-generated database-assigned primary id.
|
* an auto-generated database-assigned primary id.
|
||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Sanne Grinovero
|
* @author Sanne Grinovero
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,7 +31,7 @@ import java.lang.annotation.Target;
|
||||||
/**
|
/**
|
||||||
* Marks a property which will hold the timestamp of the revision in a revision entity, see
|
* Marks a property which will hold the timestamp of the revision in a revision entity, see
|
||||||
* {@link RevisionListener}. The value of this property will be automatically set by Envers.
|
* {@link RevisionListener}. The value of this property will be automatically set by Envers.
|
||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Sanne Grinovero
|
* @author Sanne Grinovero
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -26,43 +26,51 @@ package org.hibernate.envers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of the revision.
|
* Type of the revision.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public enum RevisionType {
|
public enum RevisionType {
|
||||||
/**
|
/**
|
||||||
* Indicates that the entity was added (persisted) at that revision.
|
* Indicates that the entity was added (persisted) at that revision.
|
||||||
*/
|
*/
|
||||||
ADD((byte) 0),
|
ADD( (byte) 0 ),
|
||||||
/**
|
/**
|
||||||
* Indicates that the entity was modified (one or more of its fields) at that revision.
|
* Indicates that the entity was modified (one or more of its fields) at that revision.
|
||||||
*/
|
*/
|
||||||
MOD((byte) 1),
|
MOD( (byte) 1 ),
|
||||||
/**
|
/**
|
||||||
* Indicates that the entity was deleted (removed) at that revision.
|
* Indicates that the entity was deleted (removed) at that revision.
|
||||||
*/
|
*/
|
||||||
DEL((byte) 2);
|
DEL( (byte) 2 );
|
||||||
|
|
||||||
private Byte representation;
|
private Byte representation;
|
||||||
|
|
||||||
RevisionType(byte representation) {
|
RevisionType(byte representation) {
|
||||||
this.representation = representation;
|
this.representation = representation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Byte getRepresentation() {
|
public Byte getRepresentation() {
|
||||||
return representation;
|
return representation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RevisionType fromRepresentation(Object representation) {
|
public static RevisionType fromRepresentation(Object representation) {
|
||||||
if (representation == null || !(representation instanceof Byte)) {
|
if ( representation == null || !(representation instanceof Byte) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ((Byte) representation) {
|
switch ( (Byte) representation ) {
|
||||||
case 0: return ADD;
|
case 0: {
|
||||||
case 1: return MOD;
|
return ADD;
|
||||||
case 2: return DEL;
|
}
|
||||||
}
|
case 1: {
|
||||||
|
return MOD;
|
||||||
throw new IllegalArgumentException("Unknown representation: " + representation);
|
}
|
||||||
}
|
case 2: {
|
||||||
|
return DEL;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new IllegalArgumentException( "Unknown representation: " + representation );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
@ -33,7 +34,7 @@ import java.lang.annotation.Target;
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface SecondaryAuditTable {
|
public @interface SecondaryAuditTable {
|
||||||
String secondaryTableName();
|
String secondaryTableName();
|
||||||
|
|
||||||
String secondaryAuditTableName();
|
String secondaryAuditTableName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
@ -33,5 +34,5 @@ import java.lang.annotation.Target;
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface SecondaryAuditTables {
|
public @interface SecondaryAuditTables {
|
||||||
SecondaryAuditTable[] value();
|
SecondaryAuditTable[] value();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration;
|
package org.hibernate.envers.configuration;
|
||||||
|
|
||||||
import org.hibernate.envers.strategy.DefaultAuditStrategy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration property names.
|
* Configuration property names.
|
||||||
*
|
*
|
||||||
|
@ -69,7 +90,7 @@ public interface EnversSettings {
|
||||||
public static final String AUDIT_TABLE_SUFFIX = "org.hibernate.envers.audit_table_suffix";
|
public static final String AUDIT_TABLE_SUFFIX = "org.hibernate.envers.audit_table_suffix";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Audit strategy. Defaults to {@link DefaultAuditStrategy}.
|
* Audit strategy. Defaults to {@link org.hibernate.envers.strategy.DefaultAuditStrategy}.
|
||||||
*/
|
*/
|
||||||
public static final String AUDIT_STRATEGY = "org.hibernate.envers.audit_strategy";
|
public static final String AUDIT_STRATEGY = "org.hibernate.envers.audit_strategy";
|
||||||
|
|
||||||
|
@ -99,7 +120,7 @@ public interface EnversSettings {
|
||||||
* Defaults to {@literal REVEND_TSTMP}.
|
* Defaults to {@literal REVEND_TSTMP}.
|
||||||
*/
|
*/
|
||||||
public static final String AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME = "org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name";
|
public static final String AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME = "org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of column used for storing ordinal of the change in sets of embeddable elements. Defaults to {@literal SETORDINAL}.
|
* Name of column used for storing ordinal of the change in sets of embeddable elements. Defaults to {@literal SETORDINAL}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -59,7 +59,7 @@ public class AuditEntitiesConfiguration {
|
||||||
|
|
||||||
private final boolean revisionEndTimestampEnabled;
|
private final boolean revisionEndTimestampEnabled;
|
||||||
private final String revisionEndTimestampFieldName;
|
private final String revisionEndTimestampFieldName;
|
||||||
|
|
||||||
private final String embeddableSetOrdinalPropertyName;
|
private final String embeddableSetOrdinalPropertyName;
|
||||||
|
|
||||||
public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {
|
public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {
|
||||||
|
|
|
@ -1,4 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal;
|
package org.hibernate.envers.configuration.internal;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -15,84 +39,100 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class holding auditing meta-data for all persistent classes.
|
* A helper class holding auditing meta-data for all persistent classes.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class ClassesAuditingData {
|
public class ClassesAuditingData {
|
||||||
|
private static final EnversMessageLogger LOG = Logger.getMessageLogger(
|
||||||
|
EnversMessageLogger.class,
|
||||||
|
ClassesAuditingData.class.getName()
|
||||||
|
);
|
||||||
|
|
||||||
public static final EnversMessageLogger LOG = Logger.getMessageLogger(EnversMessageLogger.class, ClassesAuditingData.class.getName());
|
private final Map<String, ClassAuditingData> entityNameToAuditingData = new HashMap<String, ClassAuditingData>();
|
||||||
|
private final Map<PersistentClass, ClassAuditingData> persistentClassToAuditingData = new LinkedHashMap<PersistentClass, ClassAuditingData>();
|
||||||
|
|
||||||
private final Map<String, ClassAuditingData> entityNameToAuditingData = new HashMap<String, ClassAuditingData>();
|
/**
|
||||||
private final Map<PersistentClass, ClassAuditingData> persistentClassToAuditingData = new LinkedHashMap<PersistentClass, ClassAuditingData>();
|
* Stores information about auditing meta-data for the given class.
|
||||||
|
*
|
||||||
|
* @param pc Persistent class.
|
||||||
|
* @param cad Auditing meta-data for the given class.
|
||||||
|
*/
|
||||||
|
public void addClassAuditingData(PersistentClass pc, ClassAuditingData cad) {
|
||||||
|
entityNameToAuditingData.put( pc.getEntityName(), cad );
|
||||||
|
persistentClassToAuditingData.put( pc, cad );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores information about auditing meta-data for the given class.
|
* @return A collection of all auditing meta-data for persistent classes.
|
||||||
* @param pc Persistent class.
|
*/
|
||||||
* @param cad Auditing meta-data for the given class.
|
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
|
||||||
*/
|
return persistentClassToAuditingData.entrySet();
|
||||||
public void addClassAuditingData(PersistentClass pc, ClassAuditingData cad) {
|
}
|
||||||
entityNameToAuditingData.put(pc.getEntityName(), cad);
|
|
||||||
persistentClassToAuditingData.put(pc, cad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A collection of all auditing meta-data for persistent classes.
|
* @param entityName Name of the entity.
|
||||||
*/
|
*
|
||||||
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
|
* @return Auditing meta-data for the given entity.
|
||||||
return persistentClassToAuditingData.entrySet();
|
*/
|
||||||
}
|
public ClassAuditingData getClassAuditingData(String entityName) {
|
||||||
|
return entityNameToAuditingData.get( entityName );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param entityName Name of the entity.
|
* After all meta-data is read, updates calculated fields. This includes:
|
||||||
* @return Auditing meta-data for the given entity.
|
* <ul>
|
||||||
*/
|
* <li>setting {@code forceInsertable} to {@code true} for properties specified by {@code @AuditMappedBy}</li>
|
||||||
public ClassAuditingData getClassAuditingData(String entityName) {
|
* </ul>
|
||||||
return entityNameToAuditingData.get(entityName);
|
*/
|
||||||
}
|
public void updateCalculatedFields() {
|
||||||
|
for ( Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet() ) {
|
||||||
|
final PersistentClass pc = classAuditingDataEntry.getKey();
|
||||||
|
final ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
|
||||||
|
for ( String propertyName : classAuditingData.getPropertyNames() ) {
|
||||||
|
final PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData( propertyName );
|
||||||
|
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
|
||||||
|
if ( propertyAuditingData.getAuditMappedBy() != null ) {
|
||||||
|
final String referencedEntityName = MappingTools.getReferencedEntityName(
|
||||||
|
pc.getProperty( propertyName ).getValue()
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
final ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get( referencedEntityName );
|
||||||
* After all meta-data is read, updates calculated fields. This includes:
|
|
||||||
* <ul>
|
|
||||||
* <li>setting {@code forceInsertable} to {@code true} for properties specified by {@code @AuditMappedBy}</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public void updateCalculatedFields() {
|
|
||||||
for (Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet()) {
|
|
||||||
PersistentClass pc = classAuditingDataEntry.getKey();
|
|
||||||
ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
|
|
||||||
for (String propertyName : classAuditingData.getPropertyNames()) {
|
|
||||||
PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData(propertyName);
|
|
||||||
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
|
|
||||||
if (propertyAuditingData.getAuditMappedBy() != null) {
|
|
||||||
String referencedEntityName = MappingTools.getReferencedEntityName(pc.getProperty(propertyName).getValue());
|
|
||||||
|
|
||||||
ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get(referencedEntityName);
|
forcePropertyInsertable(
|
||||||
|
referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
|
||||||
|
pc.getEntityName(), referencedEntityName
|
||||||
|
);
|
||||||
|
|
||||||
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
|
forcePropertyInsertable(
|
||||||
pc.getEntityName(), referencedEntityName);
|
referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
|
||||||
|
pc.getEntityName(), referencedEntityName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
|
private void forcePropertyInsertable(
|
||||||
pc.getEntityName(), referencedEntityName);
|
ClassAuditingData classAuditingData, String propertyName,
|
||||||
}
|
String entityName, String referencedEntityName) {
|
||||||
}
|
if ( propertyName != null ) {
|
||||||
}
|
if ( classAuditingData.getPropertyAuditingData( propertyName ) == null ) {
|
||||||
}
|
throw new MappingException(
|
||||||
|
"@AuditMappedBy points to a property that doesn't exist: " +
|
||||||
|
referencedEntityName + "." + propertyName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void forcePropertyInsertable(ClassAuditingData classAuditingData, String propertyName,
|
LOG.debugf(
|
||||||
String entityName, String referencedEntityName) {
|
"Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
|
||||||
if (propertyName != null) {
|
referencedEntityName,
|
||||||
if (classAuditingData.getPropertyAuditingData(propertyName) == null) {
|
propertyName,
|
||||||
throw new MappingException("@AuditMappedBy points to a property that doesn't exist: " +
|
entityName
|
||||||
referencedEntityName + "." + propertyName);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
LOG.debugf("Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
|
classAuditingData
|
||||||
referencedEntityName,
|
.getPropertyAuditingData( propertyName )
|
||||||
propertyName,
|
.setForceInsertable( true );
|
||||||
entityName);
|
}
|
||||||
|
}
|
||||||
classAuditingData
|
|
||||||
.getPropertyAuditingData(propertyName)
|
|
||||||
.setForceInsertable(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -57,108 +57,118 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class EntitiesConfigurator {
|
public class EntitiesConfigurator {
|
||||||
public EntitiesConfigurations configure(Configuration cfg, ReflectionManager reflectionManager,
|
public EntitiesConfigurations configure(
|
||||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
Configuration cfg, ReflectionManager reflectionManager,
|
||||||
AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
|
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||||
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
|
AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
|
||||||
// Creating a name register to capture all audit entity names created.
|
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
|
||||||
AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister();
|
// Creating a name register to capture all audit entity names created.
|
||||||
DOMWriter writer = new DOMWriter();
|
final AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister();
|
||||||
|
final DOMWriter writer = new DOMWriter();
|
||||||
|
|
||||||
// Sorting the persistent class topologically - superclass always before subclass
|
// Sorting the persistent class topologically - superclass always before subclass
|
||||||
Iterator<PersistentClass> classes = GraphTopologicalSort.sort(new PersistentClassGraphDefiner(cfg)).iterator();
|
final Iterator<PersistentClass> classes = GraphTopologicalSort.sort( new PersistentClassGraphDefiner( cfg ) )
|
||||||
|
.iterator();
|
||||||
|
|
||||||
ClassesAuditingData classesAuditingData = new ClassesAuditingData();
|
final ClassesAuditingData classesAuditingData = new ClassesAuditingData();
|
||||||
Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
|
final Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
|
||||||
|
|
||||||
// Reading metadata from annotations
|
// Reading metadata from annotations
|
||||||
while (classes.hasNext()) {
|
while ( classes.hasNext() ) {
|
||||||
PersistentClass pc = classes.next();
|
final PersistentClass pc = classes.next();
|
||||||
|
|
||||||
// Collecting information from annotations on the persistent class pc
|
// Collecting information from annotations on the persistent class pc
|
||||||
AnnotationsMetadataReader annotationsMetadataReader =
|
final AnnotationsMetadataReader annotationsMetadataReader =
|
||||||
new AnnotationsMetadataReader(globalCfg, reflectionManager, pc);
|
new AnnotationsMetadataReader( globalCfg, reflectionManager, pc );
|
||||||
ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
|
final ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
|
||||||
|
|
||||||
classesAuditingData.addClassAuditingData(pc, auditData);
|
classesAuditingData.addClassAuditingData( pc, auditData );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that all information is read we can update the calculated fields.
|
// Now that all information is read we can update the calculated fields.
|
||||||
classesAuditingData.updateCalculatedFields();
|
classesAuditingData.updateCalculatedFields();
|
||||||
|
|
||||||
AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(cfg, globalCfg, verEntCfg, auditStrategy,
|
final AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(
|
||||||
classLoaderService, revisionInfoRelationMapping, auditEntityNameRegister);
|
cfg, globalCfg, verEntCfg, auditStrategy,
|
||||||
|
classLoaderService, revisionInfoRelationMapping, auditEntityNameRegister
|
||||||
|
);
|
||||||
|
|
||||||
// First pass
|
// First pass
|
||||||
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData()) {
|
for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
|
||||||
PersistentClass pc = pcDatasEntry.getKey();
|
final PersistentClass pc = pcDatasEntry.getKey();
|
||||||
ClassAuditingData auditData = pcDatasEntry.getValue();
|
final ClassAuditingData auditData = pcDatasEntry.getValue();
|
||||||
|
|
||||||
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
|
final EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
|
||||||
if (auditData.isAudited()) {
|
if ( auditData.isAudited() ) {
|
||||||
if (!StringTools.isEmpty(auditData.getAuditTable().value())) {
|
if ( !StringTools.isEmpty( auditData.getAuditTable().value() ) ) {
|
||||||
verEntCfg.addCustomAuditTableName(pc.getEntityName(), auditData.getAuditTable().value());
|
verEntCfg.addCustomAuditTableName( pc.getEntityName(), auditData.getAuditTable().value() );
|
||||||
}
|
}
|
||||||
|
|
||||||
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, true);
|
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, true );
|
||||||
} else {
|
}
|
||||||
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, false);
|
else {
|
||||||
|
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlMappings.put(pc, xmlMappingData);
|
xmlMappings.put( pc, xmlMappingData );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second pass
|
// Second pass
|
||||||
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData()) {
|
for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
|
||||||
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey());
|
final EntityXmlMappingData xmlMappingData = xmlMappings.get( pcDatasEntry.getKey() );
|
||||||
|
|
||||||
if (pcDatasEntry.getValue().isAudited()) {
|
if ( pcDatasEntry.getValue().isAudited() ) {
|
||||||
auditMetaGen.generateSecondPass(pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData);
|
auditMetaGen.generateSecondPass( pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData );
|
||||||
try {
|
try {
|
||||||
cfg.addDocument(writer.write(xmlMappingData.getMainXmlMapping()));
|
cfg.addDocument( writer.write( xmlMappingData.getMainXmlMapping() ) );
|
||||||
//writeDocument(xmlMappingData.getMainXmlMapping());
|
//writeDocument(xmlMappingData.getMainXmlMapping());
|
||||||
|
|
||||||
for (Document additionalMapping : xmlMappingData.getAdditionalXmlMappings()) {
|
for ( Document additionalMapping : xmlMappingData.getAdditionalXmlMappings() ) {
|
||||||
cfg.addDocument(writer.write(additionalMapping));
|
cfg.addDocument( writer.write( additionalMapping ) );
|
||||||
//writeDocument(additionalMapping);
|
//writeDocument(additionalMapping);
|
||||||
}
|
}
|
||||||
} catch (DocumentException e) {
|
}
|
||||||
throw new MappingException(e);
|
catch (DocumentException e) {
|
||||||
}
|
throw new MappingException( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only if there are any versioned classes
|
// Only if there are any versioned classes
|
||||||
if (auditMetaGen.getEntitiesConfigurations().size() > 0) {
|
if ( auditMetaGen.getEntitiesConfigurations().size() > 0 ) {
|
||||||
try {
|
try {
|
||||||
if (revisionInfoXmlMapping != null) {
|
if ( revisionInfoXmlMapping != null ) {
|
||||||
//writeDocument(revisionInfoXmlMapping);
|
//writeDocument(revisionInfoXmlMapping);
|
||||||
cfg.addDocument(writer.write(revisionInfoXmlMapping));
|
cfg.addDocument( writer.write( revisionInfoXmlMapping ) );
|
||||||
}
|
}
|
||||||
} catch (DocumentException e) {
|
}
|
||||||
throw new MappingException(e);
|
catch (DocumentException e) {
|
||||||
}
|
throw new MappingException( e );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations(),
|
return new EntitiesConfigurations(
|
||||||
auditMetaGen.getNotAuditedEntitiesConfigurations());
|
auditMetaGen.getEntitiesConfigurations(),
|
||||||
}
|
auditMetaGen.getNotAuditedEntitiesConfigurations()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"UnusedDeclaration"})
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
private void writeDocument(Document e) {
|
private void writeDocument(Document e) {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
Writer w = new PrintWriter(baos);
|
final Writer w = new PrintWriter( baos );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
XMLWriter xw = new XMLWriter(w, new OutputFormat(" ", true));
|
final XMLWriter xw = new XMLWriter( w, new OutputFormat( " ", true ) );
|
||||||
xw.write(e);
|
xw.write( e );
|
||||||
w.flush();
|
w.flush();
|
||||||
} catch (IOException e1) {
|
}
|
||||||
e1.printStackTrace();
|
catch (IOException e1) {
|
||||||
}
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println("-----------");
|
System.out.println( "-----------" );
|
||||||
System.out.println(baos.toString());
|
System.out.println( baos.toString() );
|
||||||
System.out.println("-----------");
|
System.out.println( "-----------" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -116,13 +116,16 @@ public class GlobalConfiguration {
|
||||||
EnversSettings.MODIFIED_FLAG_SUFFIX, properties, "_MOD"
|
EnversSettings.MODIFIED_FLAG_SUFFIX, properties, "_MOD"
|
||||||
);
|
);
|
||||||
|
|
||||||
String revisionListenerClassName = properties.getProperty( EnversSettings.REVISION_LISTENER, null );
|
final String revisionListenerClassName = properties.getProperty( EnversSettings.REVISION_LISTENER, null );
|
||||||
if ( revisionListenerClassName != null ) {
|
if ( revisionListenerClassName != null ) {
|
||||||
try {
|
try {
|
||||||
revisionListenerClass = ReflectionTools.loadClass( revisionListenerClassName, classLoaderService );
|
revisionListenerClass = ReflectionTools.loadClass( revisionListenerClassName, classLoaderService );
|
||||||
}
|
}
|
||||||
catch ( ClassLoadingException e ) {
|
catch (ClassLoadingException e) {
|
||||||
throw new MappingException( "Revision listener class not found: " + revisionListenerClassName + ".", e );
|
throw new MappingException(
|
||||||
|
"Revision listener class not found: " + revisionListenerClassName + ".",
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal;
|
package org.hibernate.envers.configuration.internal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -34,43 +35,48 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
/**
|
/**
|
||||||
* Defines a graph, where the vertexes are all persistent classes, and there is an edge from
|
* Defines a graph, where the vertexes are all persistent classes, and there is an edge from
|
||||||
* p.c. A to p.c. B iff A is a superclass of B.
|
* p.c. A to p.c. B iff A is a superclass of B.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass, String> {
|
public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass, String> {
|
||||||
private Configuration cfg;
|
private Configuration cfg;
|
||||||
|
|
||||||
public PersistentClassGraphDefiner(Configuration cfg) {
|
public PersistentClassGraphDefiner(Configuration cfg) {
|
||||||
this.cfg = cfg;
|
this.cfg = cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRepresentation(PersistentClass pc) {
|
@Override
|
||||||
return pc.getEntityName();
|
public String getRepresentation(PersistentClass pc) {
|
||||||
}
|
return pc.getEntityName();
|
||||||
|
}
|
||||||
|
|
||||||
public PersistentClass getValue(String entityName) {
|
@Override
|
||||||
return cfg.getClassMapping(entityName);
|
public PersistentClass getValue(String entityName) {
|
||||||
}
|
return cfg.getClassMapping( entityName );
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
|
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
|
||||||
while (subclassIterator.hasNext()) {
|
while ( subclassIterator.hasNext() ) {
|
||||||
PersistentClass subclass = subclassIterator.next();
|
final PersistentClass subclass = subclassIterator.next();
|
||||||
neighbours.add(subclass);
|
neighbours.add( subclass );
|
||||||
addNeighbours(neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator());
|
addNeighbours( neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@Override
|
||||||
public List<PersistentClass> getNeighbours(PersistentClass pc) {
|
@SuppressWarnings({"unchecked"})
|
||||||
List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
|
public List<PersistentClass> getNeighbours(PersistentClass pc) {
|
||||||
|
final List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
|
||||||
|
|
||||||
addNeighbours(neighbours, (Iterator<PersistentClass>) pc.getSubclassIterator());
|
addNeighbours( neighbours, (Iterator<PersistentClass>) pc.getSubclassIterator() );
|
||||||
|
|
||||||
return neighbours;
|
return neighbours;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@Override
|
||||||
public List<PersistentClass> getValues() {
|
@SuppressWarnings({"unchecked"})
|
||||||
return Tools.iteratorToList( cfg.getClassMappings() );
|
public List<PersistentClass> getValues() {
|
||||||
}
|
return Tools.iteratorToList( cfg.getClassMappings() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,10 +22,11 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal;
|
package org.hibernate.envers.configuration.internal;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.persistence.Column;
|
|
||||||
|
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
|
@ -65,301 +66,394 @@ import org.hibernate.type.Type;
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public class RevisionInfoConfiguration {
|
public class RevisionInfoConfiguration {
|
||||||
private String revisionInfoEntityName;
|
private String revisionInfoEntityName;
|
||||||
private PropertyData revisionInfoIdData;
|
private PropertyData revisionInfoIdData;
|
||||||
private PropertyData revisionInfoTimestampData;
|
private PropertyData revisionInfoTimestampData;
|
||||||
private PropertyData modifiedEntityNamesData;
|
private PropertyData modifiedEntityNamesData;
|
||||||
private Type revisionInfoTimestampType;
|
private Type revisionInfoTimestampType;
|
||||||
private GlobalConfiguration globalCfg;
|
private GlobalConfiguration globalCfg;
|
||||||
|
|
||||||
private String revisionPropType;
|
private String revisionPropType;
|
||||||
private String revisionPropSqlType;
|
private String revisionPropSqlType;
|
||||||
|
|
||||||
public RevisionInfoConfiguration(GlobalConfiguration globalCfg) {
|
public RevisionInfoConfiguration(GlobalConfiguration globalCfg) {
|
||||||
this.globalCfg = globalCfg;
|
this.globalCfg = globalCfg;
|
||||||
if (globalCfg.isUseRevisionEntityWithNativeId()) {
|
if ( globalCfg.isUseRevisionEntityWithNativeId() ) {
|
||||||
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
|
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
|
||||||
} else {
|
}
|
||||||
revisionInfoEntityName = "org.hibernate.envers.enhanced.SequenceIdRevisionEntity";
|
else {
|
||||||
}
|
revisionInfoEntityName = "org.hibernate.envers.enhanced.SequenceIdRevisionEntity";
|
||||||
revisionInfoIdData = new PropertyData("id", "id", "field", null);
|
}
|
||||||
revisionInfoTimestampData = new PropertyData("timestamp", "timestamp", "field", null);
|
revisionInfoIdData = new PropertyData( "id", "id", "field", null );
|
||||||
modifiedEntityNamesData = new PropertyData("modifiedEntityNames", "modifiedEntityNames", "field", null);
|
revisionInfoTimestampData = new PropertyData( "timestamp", "timestamp", "field", null );
|
||||||
revisionInfoTimestampType = new LongType();
|
modifiedEntityNamesData = new PropertyData( "modifiedEntityNames", "modifiedEntityNames", "field", null );
|
||||||
|
revisionInfoTimestampType = new LongType();
|
||||||
|
|
||||||
revisionPropType = "integer";
|
revisionPropType = "integer";
|
||||||
}
|
}
|
||||||
|
|
||||||
private Document generateDefaultRevisionInfoXmlMapping() {
|
private Document generateDefaultRevisionInfoXmlMapping() {
|
||||||
Document document = XMLHelper.getDocumentFactory().createDocument();
|
final Document document = XMLHelper.getDocumentFactory().createDocument();
|
||||||
|
|
||||||
Element class_mapping = MetadataTools.createEntity(document, new AuditTableData(null, null, globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName()), null, null);
|
final Element classMapping = MetadataTools.createEntity(
|
||||||
|
document,
|
||||||
|
new AuditTableData( null, null, globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName() ),
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
class_mapping.addAttribute("name", revisionInfoEntityName);
|
classMapping.addAttribute( "name", revisionInfoEntityName );
|
||||||
class_mapping.addAttribute("table", "REVINFO");
|
classMapping.addAttribute( "table", "REVINFO" );
|
||||||
|
|
||||||
Element idProperty = MetadataTools.addNativelyGeneratedId(class_mapping, revisionInfoIdData.getName(),
|
final Element idProperty = MetadataTools.addNativelyGeneratedId(
|
||||||
revisionPropType, globalCfg.isUseRevisionEntityWithNativeId());
|
classMapping,
|
||||||
MetadataTools.addColumn(idProperty, "REV", null, null, null, null, null, null, false);
|
revisionInfoIdData.getName(),
|
||||||
|
revisionPropType,
|
||||||
|
globalCfg.isUseRevisionEntityWithNativeId()
|
||||||
|
);
|
||||||
|
MetadataTools.addColumn( idProperty, "REV", null, null, null, null, null, null, false );
|
||||||
|
|
||||||
Element timestampProperty = MetadataTools.addProperty(class_mapping, revisionInfoTimestampData.getName(),
|
final Element timestampProperty = MetadataTools.addProperty(
|
||||||
revisionInfoTimestampType.getName(), true, false);
|
classMapping,
|
||||||
MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, null, null, null, null, null, false);
|
revisionInfoTimestampData.getName(),
|
||||||
|
revisionInfoTimestampType.getName(),
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
MetadataTools.addColumn( timestampProperty, "REVTSTMP", null, null, null, null, null, null, false );
|
||||||
|
|
||||||
if (globalCfg.isTrackEntitiesChangedInRevision()) {
|
if ( globalCfg.isTrackEntitiesChangedInRevision() ) {
|
||||||
generateEntityNamesTrackingTableMapping(class_mapping, "modifiedEntityNames",
|
generateEntityNamesTrackingTableMapping(
|
||||||
globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName(),
|
classMapping,
|
||||||
"REVCHANGES", "REV", "ENTITYNAME", "string");
|
"modifiedEntityNames",
|
||||||
}
|
globalCfg.getDefaultSchemaName(),
|
||||||
|
globalCfg.getDefaultCatalogName(),
|
||||||
|
"REVCHANGES",
|
||||||
|
"REV",
|
||||||
|
"ENTITYNAME",
|
||||||
|
"string"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates mapping that represents a set of primitive types.<br />
|
* Generates mapping that represents a set of primitive types.<br />
|
||||||
* <code>
|
* <code>
|
||||||
* <set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog"
|
* <set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog"
|
||||||
* cascade="persist, delete" lazy="false" fetch="join"><br />
|
* cascade="persist, delete" lazy="false" fetch="join"><br />
|
||||||
* <key column="joinTablePrimaryKeyColumnName" /><br />
|
* <key column="joinTablePrimaryKeyColumnName" /><br />
|
||||||
* <element type="joinTableValueColumnType"><br />
|
* <element type="joinTableValueColumnType"><br />
|
||||||
* <column name="joinTableValueColumnName" /><br />
|
* <column name="joinTableValueColumnName" /><br />
|
||||||
* </element><br />
|
* </element><br />
|
||||||
* </set>
|
* </set>
|
||||||
* </code>
|
* </code>
|
||||||
*/
|
*/
|
||||||
private void generateEntityNamesTrackingTableMapping(Element class_mapping, String propertyName,
|
private void generateEntityNamesTrackingTableMapping(
|
||||||
String joinTableSchema, String joinTableCatalog, String joinTableName,
|
Element classMapping,
|
||||||
String joinTablePrimaryKeyColumnName, String joinTableValueColumnName,
|
String propertyName,
|
||||||
String joinTableValueColumnType) {
|
String joinTableSchema,
|
||||||
Element set = class_mapping.addElement("set");
|
String joinTableCatalog,
|
||||||
set.addAttribute("name", propertyName);
|
String joinTableName,
|
||||||
set.addAttribute("table", joinTableName);
|
String joinTablePrimaryKeyColumnName,
|
||||||
set.addAttribute("schema", joinTableSchema);
|
String joinTableValueColumnName,
|
||||||
set.addAttribute("catalog", joinTableCatalog);
|
String joinTableValueColumnType) {
|
||||||
set.addAttribute("cascade", "persist, delete");
|
final Element set = classMapping.addElement( "set" );
|
||||||
set.addAttribute("fetch", "join");
|
set.addAttribute( "name", propertyName );
|
||||||
set.addAttribute("lazy", "false");
|
set.addAttribute( "table", joinTableName );
|
||||||
Element key = set.addElement("key");
|
set.addAttribute( "schema", joinTableSchema );
|
||||||
key.addAttribute("column", joinTablePrimaryKeyColumnName);
|
set.addAttribute( "catalog", joinTableCatalog );
|
||||||
Element element = set.addElement("element");
|
set.addAttribute( "cascade", "persist, delete" );
|
||||||
element.addAttribute("type", joinTableValueColumnType);
|
set.addAttribute( "fetch", "join" );
|
||||||
Element column = element.addElement("column");
|
set.addAttribute( "lazy", "false" );
|
||||||
column.addAttribute("name", joinTableValueColumnName);
|
final Element key = set.addElement( "key" );
|
||||||
}
|
key.addAttribute( "column", joinTablePrimaryKeyColumnName );
|
||||||
|
final Element element = set.addElement( "element" );
|
||||||
|
element.addAttribute( "type", joinTableValueColumnType );
|
||||||
|
final Element column = element.addElement( "column" );
|
||||||
|
column.addAttribute( "name", joinTableValueColumnName );
|
||||||
|
}
|
||||||
|
|
||||||
private Element generateRevisionInfoRelationMapping() {
|
private Element generateRevisionInfoRelationMapping() {
|
||||||
Document document = XMLHelper.getDocumentFactory().createDocument();
|
final Document document = XMLHelper.getDocumentFactory().createDocument();
|
||||||
Element rev_rel_mapping = document.addElement("key-many-to-one");
|
final Element revRelMapping = document.addElement( "key-many-to-one" );
|
||||||
rev_rel_mapping.addAttribute("type", revisionPropType);
|
revRelMapping.addAttribute( "type", revisionPropType );
|
||||||
rev_rel_mapping.addAttribute("class", revisionInfoEntityName);
|
revRelMapping.addAttribute( "class", revisionInfoEntityName );
|
||||||
|
|
||||||
if (revisionPropSqlType != null) {
|
if ( revisionPropSqlType != null ) {
|
||||||
// Putting a fake name to make Hibernate happy. It will be replaced later anyway.
|
// Putting a fake name to make Hibernate happy. It will be replaced later anyway.
|
||||||
MetadataTools.addColumn(rev_rel_mapping, "*" , null, null, null, revisionPropSqlType, null, null, false);
|
MetadataTools.addColumn( revRelMapping, "*", null, null, null, revisionPropSqlType, null, null, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
return rev_rel_mapping;
|
return revRelMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void searchForRevisionInfoCfgInProperties(XClass clazz, ReflectionManager reflectionManager,
|
private void searchForRevisionInfoCfgInProperties(
|
||||||
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
|
XClass clazz,
|
||||||
MutableBoolean modifiedEntityNamesFound, String accessType) {
|
ReflectionManager reflectionManager,
|
||||||
for (XProperty property : clazz.getDeclaredProperties(accessType)) {
|
MutableBoolean revisionNumberFound,
|
||||||
RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
|
MutableBoolean revisionTimestampFound,
|
||||||
RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class);
|
MutableBoolean modifiedEntityNamesFound,
|
||||||
ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class);
|
String accessType) {
|
||||||
|
for ( XProperty property : clazz.getDeclaredProperties( accessType ) ) {
|
||||||
|
final RevisionNumber revisionNumber = property.getAnnotation( RevisionNumber.class );
|
||||||
|
final RevisionTimestamp revisionTimestamp = property.getAnnotation( RevisionTimestamp.class );
|
||||||
|
final ModifiedEntityNames modifiedEntityNames = property.getAnnotation( ModifiedEntityNames.class );
|
||||||
|
|
||||||
if (revisionNumber != null) {
|
if ( revisionNumber != null ) {
|
||||||
if (revisionNumberFound.isSet()) {
|
if ( revisionNumberFound.isSet() ) {
|
||||||
throw new MappingException("Only one property may be annotated with @RevisionNumber!");
|
throw new MappingException( "Only one property may be annotated with @RevisionNumber!" );
|
||||||
}
|
}
|
||||||
|
|
||||||
XClass revisionNumberClass = property.getType();
|
final XClass revisionNumberClass = property.getType();
|
||||||
if (reflectionManager.equals(revisionNumberClass, Integer.class) ||
|
if ( reflectionManager.equals( revisionNumberClass, Integer.class ) ||
|
||||||
reflectionManager.equals(revisionNumberClass, Integer.TYPE)) {
|
reflectionManager.equals( revisionNumberClass, Integer.TYPE ) ) {
|
||||||
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null);
|
revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
|
||||||
revisionNumberFound.set();
|
revisionNumberFound.set();
|
||||||
} else if (reflectionManager.equals(revisionNumberClass, Long.class) ||
|
}
|
||||||
reflectionManager.equals(revisionNumberClass, Long.TYPE)) {
|
else if ( reflectionManager.equals( revisionNumberClass, Long.class ) ||
|
||||||
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null);
|
reflectionManager.equals( revisionNumberClass, Long.TYPE ) ) {
|
||||||
revisionNumberFound.set();
|
revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
|
||||||
|
revisionNumberFound.set();
|
||||||
|
|
||||||
// The default is integer
|
// The default is integer
|
||||||
revisionPropType = "long";
|
revisionPropType = "long";
|
||||||
} else {
|
}
|
||||||
throw new MappingException("The field annotated with @RevisionNumber must be of type " +
|
else {
|
||||||
"int, Integer, long or Long");
|
throw new MappingException(
|
||||||
}
|
"The field annotated with @RevisionNumber must be of type " +
|
||||||
|
"int, Integer, long or Long"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Getting the @Column definition of the revision number property, to later use that info to
|
// Getting the @Column definition of the revision number property, to later use that info to
|
||||||
// generate the same mapping for the relation from an audit table's revision number to the
|
// generate the same mapping for the relation from an audit table's revision number to the
|
||||||
// revision entity revision number.
|
// revision entity revision number.
|
||||||
Column revisionPropColumn = property.getAnnotation(Column.class);
|
final Column revisionPropColumn = property.getAnnotation( Column.class );
|
||||||
if (revisionPropColumn != null) {
|
if ( revisionPropColumn != null ) {
|
||||||
revisionPropSqlType = revisionPropColumn.columnDefinition();
|
revisionPropSqlType = revisionPropColumn.columnDefinition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (revisionTimestamp != null) {
|
if ( revisionTimestamp != null ) {
|
||||||
if (revisionTimestampFound.isSet()) {
|
if ( revisionTimestampFound.isSet() ) {
|
||||||
throw new MappingException("Only one property may be annotated with @RevisionTimestamp!");
|
throw new MappingException( "Only one property may be annotated with @RevisionTimestamp!" );
|
||||||
}
|
}
|
||||||
|
|
||||||
XClass revisionTimestampClass = property.getType();
|
final XClass revisionTimestampClass = property.getType();
|
||||||
if (reflectionManager.equals(revisionTimestampClass, Long.class) ||
|
if ( reflectionManager.equals( revisionTimestampClass, Long.class ) ||
|
||||||
reflectionManager.equals(revisionTimestampClass, Long.TYPE) ||
|
reflectionManager.equals( revisionTimestampClass, Long.TYPE ) ||
|
||||||
reflectionManager.equals(revisionTimestampClass, Date.class) ||
|
reflectionManager.equals( revisionTimestampClass, Date.class ) ||
|
||||||
reflectionManager.equals(revisionTimestampClass, java.sql.Date.class)) {
|
reflectionManager.equals( revisionTimestampClass, java.sql.Date.class ) ) {
|
||||||
revisionInfoTimestampData = new PropertyData(property.getName(), property.getName(), accessType, null);
|
revisionInfoTimestampData = new PropertyData(
|
||||||
revisionTimestampFound.set();
|
property.getName(),
|
||||||
} else {
|
property.getName(),
|
||||||
throw new MappingException("The field annotated with @RevisionTimestamp must be of type " +
|
accessType,
|
||||||
"long, Long, java.util.Date or java.sql.Date");
|
null
|
||||||
}
|
);
|
||||||
}
|
revisionTimestampFound.set();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new MappingException(
|
||||||
|
"The field annotated with @RevisionTimestamp must be of type " +
|
||||||
|
"long, Long, java.util.Date or java.sql.Date"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (modifiedEntityNames != null) {
|
if ( modifiedEntityNames != null ) {
|
||||||
if (modifiedEntityNamesFound.isSet()) {
|
if ( modifiedEntityNamesFound.isSet() ) {
|
||||||
throw new MappingException("Only one property may be annotated with @ModifiedEntityNames!");
|
throw new MappingException( "Only one property may be annotated with @ModifiedEntityNames!" );
|
||||||
}
|
}
|
||||||
XClass modifiedEntityNamesClass = property.getType();
|
final XClass modifiedEntityNamesClass = property.getType();
|
||||||
if (reflectionManager.equals(modifiedEntityNamesClass, Set.class) &&
|
if ( reflectionManager.equals( modifiedEntityNamesClass, Set.class ) &&
|
||||||
reflectionManager.equals(property.getElementClass(), String.class)) {
|
reflectionManager.equals( property.getElementClass(), String.class ) ) {
|
||||||
modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null);
|
modifiedEntityNamesData = new PropertyData(
|
||||||
modifiedEntityNamesFound.set();
|
property.getName(),
|
||||||
} else {
|
property.getName(),
|
||||||
throw new MappingException("The field annotated with @ModifiedEntityNames must be of Set<String> type.");
|
accessType,
|
||||||
}
|
null
|
||||||
}
|
);
|
||||||
}
|
modifiedEntityNamesFound.set();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
throw new MappingException(
|
||||||
|
"The field annotated with @ModifiedEntityNames must be of Set<String> type."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void searchForRevisionInfoCfg(XClass clazz, ReflectionManager reflectionManager,
|
private void searchForRevisionInfoCfg(
|
||||||
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
|
XClass clazz, ReflectionManager reflectionManager,
|
||||||
MutableBoolean modifiedEntityNamesFound) {
|
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
|
||||||
XClass superclazz = clazz.getSuperclass();
|
MutableBoolean modifiedEntityNamesFound) {
|
||||||
if (!"java.lang.Object".equals(superclazz.getName())) {
|
final XClass superclazz = clazz.getSuperclass();
|
||||||
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
|
if ( !"java.lang.Object".equals( superclazz.getName() ) ) {
|
||||||
}
|
searchForRevisionInfoCfg(
|
||||||
|
superclazz,
|
||||||
|
reflectionManager,
|
||||||
|
revisionNumberFound,
|
||||||
|
revisionTimestampFound,
|
||||||
|
modifiedEntityNamesFound
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
searchForRevisionInfoCfgInProperties(
|
||||||
modifiedEntityNamesFound, "field");
|
clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
||||||
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
modifiedEntityNamesFound, "field"
|
||||||
modifiedEntityNamesFound, "property");
|
);
|
||||||
}
|
searchForRevisionInfoCfgInProperties(
|
||||||
|
clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
||||||
|
modifiedEntityNamesFound, "property"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
|
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
|
||||||
Iterator<PersistentClass> classes = cfg.getClassMappings();
|
boolean revisionEntityFound = false;
|
||||||
boolean revisionEntityFound = false;
|
RevisionInfoGenerator revisionInfoGenerator = null;
|
||||||
RevisionInfoGenerator revisionInfoGenerator = null;
|
Class<?> revisionInfoClass = null;
|
||||||
|
|
||||||
Class<?> revisionInfoClass = null;
|
final Iterator<PersistentClass> classes = cfg.getClassMappings();
|
||||||
|
while ( classes.hasNext() ) {
|
||||||
|
PersistentClass pc = classes.next();
|
||||||
|
XClass clazz;
|
||||||
|
try {
|
||||||
|
clazz = reflectionManager.classForName( pc.getClassName(), this.getClass() );
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new MappingException( e );
|
||||||
|
}
|
||||||
|
|
||||||
while (classes.hasNext()) {
|
final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
|
||||||
PersistentClass pc = classes.next();
|
if ( revisionEntity != null ) {
|
||||||
XClass clazz;
|
if ( revisionEntityFound ) {
|
||||||
try {
|
throw new MappingException( "Only one entity may be annotated with @RevisionEntity!" );
|
||||||
clazz = reflectionManager.classForName(pc.getClassName(), this.getClass());
|
}
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new MappingException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
RevisionEntity revisionEntity = clazz.getAnnotation(RevisionEntity.class);
|
// Checking if custom revision entity isn't audited
|
||||||
if (revisionEntity != null) {
|
if ( clazz.getAnnotation( Audited.class ) != null ) {
|
||||||
if (revisionEntityFound) {
|
throw new MappingException( "An entity annotated with @RevisionEntity cannot be audited!" );
|
||||||
throw new MappingException("Only one entity may be annotated with @RevisionEntity!");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Checking if custom revision entity isn't audited
|
revisionEntityFound = true;
|
||||||
if (clazz.getAnnotation(Audited.class) != null) {
|
|
||||||
throw new MappingException("An entity annotated with @RevisionEntity cannot be audited!");
|
|
||||||
}
|
|
||||||
|
|
||||||
revisionEntityFound = true;
|
final MutableBoolean revisionNumberFound = new MutableBoolean();
|
||||||
|
final MutableBoolean revisionTimestampFound = new MutableBoolean();
|
||||||
|
final MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
|
||||||
|
|
||||||
MutableBoolean revisionNumberFound = new MutableBoolean();
|
searchForRevisionInfoCfg(
|
||||||
MutableBoolean revisionTimestampFound = new MutableBoolean();
|
clazz,
|
||||||
MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
|
reflectionManager,
|
||||||
|
revisionNumberFound,
|
||||||
|
revisionTimestampFound,
|
||||||
|
modifiedEntityNamesFound
|
||||||
|
);
|
||||||
|
|
||||||
searchForRevisionInfoCfg(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
|
if ( !revisionNumberFound.isSet() ) {
|
||||||
|
throw new MappingException(
|
||||||
|
"An entity annotated with @RevisionEntity must have a field annotated " +
|
||||||
|
"with @RevisionNumber!"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!revisionNumberFound.isSet()) {
|
if ( !revisionTimestampFound.isSet() ) {
|
||||||
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
|
throw new MappingException(
|
||||||
"with @RevisionNumber!");
|
"An entity annotated with @RevisionEntity must have a field annotated " +
|
||||||
}
|
"with @RevisionTimestamp!"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!revisionTimestampFound.isSet()) {
|
revisionInfoEntityName = pc.getEntityName();
|
||||||
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
|
revisionInfoClass = pc.getMappedClass();
|
||||||
"with @RevisionTimestamp!");
|
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( revisionEntity.value() );
|
||||||
}
|
revisionInfoTimestampType = pc.getProperty( revisionInfoTimestampData.getName() ).getType();
|
||||||
|
if ( globalCfg.isTrackEntitiesChangedInRevision()
|
||||||
|
|| (globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class
|
||||||
|
.isAssignableFrom( revisionInfoClass ))
|
||||||
|
|| (!globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.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,
|
||||||
|
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
|
||||||
|
modifiedEntityNamesData
|
||||||
|
);
|
||||||
|
globalCfg.setTrackEntitiesChangedInRevision( true );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
|
||||||
|
revisionInfoEntityName, revisionInfoClass,
|
||||||
|
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
revisionInfoEntityName = pc.getEntityName();
|
// In case of a custom revision info generator, the mapping will be null.
|
||||||
revisionInfoClass = pc.getMappedClass();
|
Document revisionInfoXmlMapping = null;
|
||||||
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(revisionEntity.value());
|
|
||||||
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
|
|
||||||
if (globalCfg.isTrackEntitiesChangedInRevision()
|
|
||||||
|| (globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass))
|
|
||||||
|| (!globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.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,
|
|
||||||
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
|
|
||||||
modifiedEntityNamesData);
|
|
||||||
globalCfg.setTrackEntitiesChangedInRevision(true);
|
|
||||||
} else {
|
|
||||||
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
|
||||||
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case of a custom revision info generator, the mapping will be null.
|
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( RevisionListener.class );
|
||||||
Document revisionInfoXmlMapping = null;
|
|
||||||
|
|
||||||
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(RevisionListener.class);
|
if ( revisionInfoGenerator == null ) {
|
||||||
|
if ( globalCfg.isTrackEntitiesChangedInRevision() ) {
|
||||||
|
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ?
|
||||||
|
DefaultTrackingModifiedEntitiesRevisionEntity.class
|
||||||
|
:
|
||||||
|
SequenceIdTrackingModifiedEntitiesRevisionEntity.class;
|
||||||
|
revisionInfoEntityName = revisionInfoClass.getName();
|
||||||
|
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
|
||||||
|
revisionInfoEntityName, revisionInfoClass,
|
||||||
|
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultRevisionEntity.class
|
||||||
|
: SequenceIdRevisionEntity.class;
|
||||||
|
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
|
||||||
|
revisionInfoEntityName, revisionInfoClass,
|
||||||
|
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
|
||||||
|
}
|
||||||
|
|
||||||
if (revisionInfoGenerator == null) {
|
return new RevisionInfoConfigurationResult(
|
||||||
if (globalCfg.isTrackEntitiesChangedInRevision()) {
|
revisionInfoGenerator, revisionInfoXmlMapping,
|
||||||
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultTrackingModifiedEntitiesRevisionEntity.class
|
new RevisionInfoQueryCreator(
|
||||||
: SequenceIdTrackingModifiedEntitiesRevisionEntity.class;
|
revisionInfoEntityName, revisionInfoIdData.getName(),
|
||||||
revisionInfoEntityName = revisionInfoClass.getName();
|
revisionInfoTimestampData.getName(), isTimestampAsDate()
|
||||||
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
),
|
||||||
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
|
generateRevisionInfoRelationMapping(),
|
||||||
} else {
|
new RevisionInfoNumberReader( revisionInfoClass, revisionInfoIdData ),
|
||||||
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultRevisionEntity.class
|
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(
|
||||||
: SequenceIdRevisionEntity.class;
|
revisionInfoClass,
|
||||||
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
modifiedEntityNamesData
|
||||||
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
|
)
|
||||||
}
|
: null,
|
||||||
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
|
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return new RevisionInfoConfigurationResult(
|
private boolean isTimestampAsDate() {
|
||||||
revisionInfoGenerator, revisionInfoXmlMapping,
|
final String typename = revisionInfoTimestampType.getName();
|
||||||
new RevisionInfoQueryCreator(revisionInfoEntityName, revisionInfoIdData.getName(),
|
return "date".equals( typename ) || "time".equals( typename ) || "timestamp".equals( typename );
|
||||||
revisionInfoTimestampData.getName(), isTimestampAsDate()),
|
}
|
||||||
generateRevisionInfoRelationMapping(),
|
|
||||||
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData),
|
|
||||||
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData)
|
|
||||||
: null,
|
|
||||||
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTimestampAsDate() {
|
/**
|
||||||
String typename = revisionInfoTimestampType.getName();
|
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
|
||||||
return "date".equals(typename) || "time".equals(typename) || "timestamp".equals(typename);
|
* parameter has not been set.
|
||||||
}
|
*
|
||||||
|
* @return Revision listener.
|
||||||
/**
|
*/
|
||||||
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
|
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) {
|
||||||
* parameter has not been set.
|
if ( globalCfg.getRevisionListenerClass() != null ) {
|
||||||
* @return Revision listener.
|
return globalCfg.getRevisionListenerClass();
|
||||||
*/
|
}
|
||||||
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) {
|
return defaultListener;
|
||||||
if (globalCfg.getRevisionListenerClass() != null) {
|
}
|
||||||
return globalCfg.getRevisionListenerClass();
|
|
||||||
}
|
|
||||||
return defaultListener;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal;
|
package org.hibernate.envers.configuration.internal;
|
||||||
|
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
|
@ -23,11 +46,12 @@ public class RevisionInfoConfigurationResult {
|
||||||
private final Class<?> revisionInfoClass;
|
private final Class<?> revisionInfoClass;
|
||||||
private final PropertyData revisionInfoTimestampData;
|
private final PropertyData revisionInfoTimestampData;
|
||||||
|
|
||||||
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
|
RevisionInfoConfigurationResult(
|
||||||
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
|
RevisionInfoGenerator revisionInfoGenerator,
|
||||||
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
|
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
|
||||||
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
|
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
|
||||||
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
|
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
|
||||||
|
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
|
||||||
this.revisionInfoGenerator = revisionInfoGenerator;
|
this.revisionInfoGenerator = revisionInfoGenerator;
|
||||||
this.revisionInfoXmlMapping = revisionInfoXmlMapping;
|
this.revisionInfoXmlMapping = revisionInfoXmlMapping;
|
||||||
this.revisionInfoQueryCreator = revisionInfoQueryCreator;
|
this.revisionInfoQueryCreator = revisionInfoQueryCreator;
|
||||||
|
|
|
@ -1,4 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -6,46 +30,49 @@ import org.hibernate.MappingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A register of all audit entity names used so far.
|
* A register of all audit entity names used so far.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class AuditEntityNameRegister {
|
public class AuditEntityNameRegister {
|
||||||
private final Set<String> auditEntityNames = new HashSet<String>();
|
private final Set<String> auditEntityNames = new HashSet<String>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param auditEntityName Name of the audit entity.
|
* @param auditEntityName Name of the audit entity.
|
||||||
* @return True if the given audit entity name is already used.
|
|
||||||
*/
|
|
||||||
private boolean check(String auditEntityName) {
|
|
||||||
return auditEntityNames.contains(auditEntityName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register an audit entity name. If the name is already registered, an exception is thrown.
|
|
||||||
* @param auditEntityName Name of the audit entity.
|
|
||||||
*/
|
|
||||||
public void register(String auditEntityName) {
|
|
||||||
if (auditEntityNames.contains(auditEntityName)) {
|
|
||||||
throw new MappingException("The audit entity name '" + auditEntityName + "' is already registered.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auditEntityNames.add(auditEntityName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a unique (not yet registered) audit entity name by appending consecutive numbers to the base
|
|
||||||
* name. If the base name is not yet used, it is returned unmodified.
|
|
||||||
*
|
*
|
||||||
* @param baseAuditEntityName The base entity name.
|
* @return True if the given audit entity name is already used.
|
||||||
*
|
*/
|
||||||
* @return A unique audit entity name
|
private boolean check(String auditEntityName) {
|
||||||
*/
|
return auditEntityNames.contains( auditEntityName );
|
||||||
public String createUnique(final String baseAuditEntityName) {
|
}
|
||||||
String auditEntityName = baseAuditEntityName;
|
|
||||||
int count = 1;
|
|
||||||
while (check(auditEntityName)) {
|
|
||||||
auditEntityName = baseAuditEntityName + count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return auditEntityName;
|
/**
|
||||||
}
|
* Register an audit entity name. If the name is already registered, an exception is thrown.
|
||||||
|
*
|
||||||
|
* @param auditEntityName Name of the audit entity.
|
||||||
|
*/
|
||||||
|
public void register(String auditEntityName) {
|
||||||
|
if ( auditEntityNames.contains( auditEntityName ) ) {
|
||||||
|
throw new MappingException( "The audit entity name '" + auditEntityName + "' is already registered." );
|
||||||
|
}
|
||||||
|
|
||||||
|
auditEntityNames.add( auditEntityName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a unique (not yet registered) audit entity name by appending consecutive numbers to the base
|
||||||
|
* name. If the base name is not yet used, it is returned unmodified.
|
||||||
|
*
|
||||||
|
* @param baseAuditEntityName The base entity name.
|
||||||
|
*
|
||||||
|
* @return A unique audit entity name
|
||||||
|
*/
|
||||||
|
public String createUnique(final String baseAuditEntityName) {
|
||||||
|
String auditEntityName = baseAuditEntityName;
|
||||||
|
int count = 1;
|
||||||
|
while ( check( auditEntityName ) ) {
|
||||||
|
auditEntityName = baseAuditEntityName + count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return auditEntityName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -21,41 +21,41 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.hibernate.envers.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds information necessary to create an audit table: its name, schema and catalog, as well as the audit
|
* Holds information necessary to create an audit table: its name, schema and catalog, as well as the audit
|
||||||
* entity name.
|
* entity name.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class AuditTableData {
|
public class AuditTableData {
|
||||||
private final String auditEntityName;
|
private final String auditEntityName;
|
||||||
private final String auditTableName;
|
private final String auditTableName;
|
||||||
private final String schema;
|
private final String schema;
|
||||||
private final String catalog;
|
private final String catalog;
|
||||||
|
|
||||||
public AuditTableData(String auditEntityName, String auditTableName, String schema, String catalog) {
|
public AuditTableData(String auditEntityName, String auditTableName, String schema, String catalog) {
|
||||||
this.auditEntityName = auditEntityName;
|
this.auditEntityName = auditEntityName;
|
||||||
this.auditTableName = auditTableName;
|
this.auditTableName = auditTableName;
|
||||||
this.schema = schema;
|
this.schema = schema;
|
||||||
this.catalog = catalog;
|
this.catalog = catalog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuditEntityName() {
|
public String getAuditEntityName() {
|
||||||
return auditEntityName;
|
return auditEntityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuditTableName() {
|
public String getAuditTableName() {
|
||||||
return auditTableName;
|
return auditTableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSchema() {
|
public String getSchema() {
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCatalog() {
|
public String getCatalog() {
|
||||||
return catalog;
|
return catalog;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -40,47 +40,54 @@ import org.hibernate.usertype.DynamicParameterizedType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates metadata for basic properties: immutable types (including enums).
|
* Generates metadata for basic properties: immutable types (including enums).
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class BasicMetadataGenerator {
|
public final class BasicMetadataGenerator {
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({"unchecked"})
|
||||||
boolean addBasic(Element parent, PropertyAuditingData propertyAuditingData,
|
boolean addBasic(
|
||||||
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
Element parent, PropertyAuditingData propertyAuditingData,
|
||||||
Type type = value.getType();
|
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
||||||
|
final Type type = value.getType();
|
||||||
|
|
||||||
if ( type instanceof BasicType || type instanceof SerializableToBlobType ||
|
if ( type instanceof BasicType
|
||||||
"org.hibernate.type.PrimitiveByteArrayBlobType".equals( type.getClass().getName() ) ) {
|
|| type instanceof SerializableToBlobType
|
||||||
|
|| "org.hibernate.type.PrimitiveByteArrayBlobType".equals( type.getClass().getName() ) ) {
|
||||||
if ( parent != null ) {
|
if ( parent != null ) {
|
||||||
boolean addNestedType = ( value instanceof SimpleValue ) && ( (SimpleValue) value ).getTypeParameters() != null;
|
final boolean addNestedType = (value instanceof SimpleValue)
|
||||||
|
&& ((SimpleValue) value).getTypeParameters() != null;
|
||||||
|
|
||||||
String typeName = type.getName();
|
String typeName = type.getName();
|
||||||
if ( typeName == null ) {
|
if ( typeName == null ) {
|
||||||
typeName = type.getClass().getName();
|
typeName = type.getClass().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
Element prop_mapping = MetadataTools.addProperty(
|
final Element propMapping = MetadataTools.addProperty(
|
||||||
parent, propertyAuditingData.getName(),
|
parent,
|
||||||
addNestedType ? null : typeName, propertyAuditingData.isForceInsertable() || insertable, key
|
propertyAuditingData.getName(),
|
||||||
|
addNestedType ? null : typeName,
|
||||||
|
propertyAuditingData.isForceInsertable() || insertable,
|
||||||
|
key
|
||||||
);
|
);
|
||||||
MetadataTools.addColumns( prop_mapping, value.getColumnIterator() );
|
MetadataTools.addColumns( propMapping, value.getColumnIterator() );
|
||||||
|
|
||||||
if ( addNestedType ) {
|
if ( addNestedType ) {
|
||||||
Properties typeParameters = ( (SimpleValue) value ).getTypeParameters();
|
final Properties typeParameters = ((SimpleValue) value).getTypeParameters();
|
||||||
Element type_mapping = prop_mapping.addElement( "type" );
|
final Element typeMapping = propMapping.addElement( "type" );
|
||||||
type_mapping.addAttribute( "name", typeName );
|
typeMapping.addAttribute( "name", typeName );
|
||||||
|
|
||||||
if ( "org.hibernate.type.EnumType".equals( typeName ) ) {
|
if ( "org.hibernate.type.EnumType".equals( typeName ) ) {
|
||||||
// Proper handling of enumeration type
|
// Proper handling of enumeration type
|
||||||
mapEnumerationType( type_mapping, type, typeParameters );
|
mapEnumerationType( typeMapping, type, typeParameters );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// By default copying all Hibernate properties
|
// By default copying all Hibernate properties
|
||||||
for ( Object object : typeParameters.keySet() ) {
|
for ( Object object : typeParameters.keySet() ) {
|
||||||
String keyType = (String) object;
|
final String keyType = (String) object;
|
||||||
String property = typeParameters.getProperty( keyType );
|
final String property = typeParameters.getProperty( keyType );
|
||||||
|
|
||||||
if ( property != null ) {
|
if ( property != null ) {
|
||||||
type_mapping.addElement( "param" ).addAttribute( "name", keyType ).setText( property );
|
typeMapping.addElement( "param" ).addAttribute( "name", keyType ).setText( property );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,32 +108,43 @@ public final class BasicMetadataGenerator {
|
||||||
|
|
||||||
private void mapEnumerationType(Element parent, Type type, Properties parameters) {
|
private void mapEnumerationType(Element parent, Type type, Properties parameters) {
|
||||||
if ( parameters.getProperty( EnumType.ENUM ) != null ) {
|
if ( parameters.getProperty( EnumType.ENUM ) != null ) {
|
||||||
parent.addElement( "param" ).addAttribute( "name", EnumType.ENUM ).setText( parameters.getProperty( EnumType.ENUM ) );
|
parent.addElement( "param" )
|
||||||
|
.addAttribute( "name", EnumType.ENUM )
|
||||||
|
.setText( parameters.getProperty( EnumType.ENUM ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parent.addElement( "param" ).addAttribute( "name", EnumType.ENUM ).setText( type.getReturnedClass().getName() );
|
parent.addElement( "param" ).addAttribute( "name", EnumType.ENUM ).setText(
|
||||||
|
type.getReturnedClass()
|
||||||
|
.getName()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if ( parameters.getProperty( EnumType.NAMED ) != null ) {
|
if ( parameters.getProperty( EnumType.NAMED ) != null ) {
|
||||||
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED ).setText( parameters.getProperty( EnumType.NAMED ) );
|
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED ).setText(
|
||||||
|
parameters.getProperty(
|
||||||
|
EnumType.NAMED
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if ( parameters.get( DynamicParameterizedType.XPROPERTY ) != null ) {
|
else if ( parameters.get( DynamicParameterizedType.XPROPERTY ) != null ) {
|
||||||
// Case of annotations.
|
// Case of annotations.
|
||||||
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED )
|
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED )
|
||||||
.setText( "" + !( (EnumType) ( (CustomType) type ).getUserType() ).isOrdinal() );
|
.setText( "" + !((EnumType) ((CustomType) type).getUserType()).isOrdinal() );
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Otherwise we assume that the choice between ordinal and named representation has been omitted.
|
|
||||||
// Call to EnumType#isOrdinal() would always return the default Types.INTEGER. We let Hibernate
|
|
||||||
// to choose the proper strategy during runtime.
|
|
||||||
}
|
}
|
||||||
|
// Otherwise we assume that the choice between ordinal and named representation has been omitted.
|
||||||
|
// Call to EnumType#isOrdinal() would always return the default Types.INTEGER. We let Hibernate
|
||||||
|
// to choose the proper strategy during runtime.
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({"unchecked"})
|
||||||
boolean addManyToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value, SimpleMapperBuilder mapper) {
|
boolean addManyToOne(
|
||||||
Type type = value.getType();
|
Element parent,
|
||||||
|
PropertyAuditingData propertyAuditingData,
|
||||||
|
Value value,
|
||||||
|
SimpleMapperBuilder mapper) {
|
||||||
|
final Type type = value.getType();
|
||||||
|
|
||||||
// A null mapper occurs when adding to composite-id element
|
// A null mapper occurs when adding to composite-id element
|
||||||
Element manyToOneElement = parent.addElement( mapper != null ? "many-to-one" : "key-many-to-one" );
|
final Element manyToOneElement = parent.addElement( mapper != null ? "many-to-one" : "key-many-to-one" );
|
||||||
manyToOneElement.addAttribute( "name", propertyAuditingData.getName() );
|
manyToOneElement.addAttribute( "name", propertyAuditingData.getName() );
|
||||||
manyToOneElement.addAttribute( "class", type.getName() );
|
manyToOneElement.addAttribute( "class", type.getName() );
|
||||||
MetadataTools.addColumns( manyToOneElement, value.getColumnIterator() );
|
MetadataTools.addColumns( manyToOneElement, value.getColumnIterator() );
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -14,6 +37,7 @@ import org.hibernate.mapping.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates metadata for components.
|
* Generates metadata for components.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class ComponentMetadataGenerator {
|
public final class ComponentMetadataGenerator {
|
||||||
|
@ -24,29 +48,38 @@ public final class ComponentMetadataGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public void addComponent(Element parent, PropertyAuditingData propertyAuditingData,
|
public void addComponent(
|
||||||
Value value, CompositeMapperBuilder mapper, String entityName,
|
Element parent, PropertyAuditingData propertyAuditingData,
|
||||||
EntityXmlMappingData xmlMappingData, boolean firstPass) {
|
Value value, CompositeMapperBuilder mapper, String entityName,
|
||||||
Component prop_component = (Component) value;
|
EntityXmlMappingData xmlMappingData, boolean firstPass) {
|
||||||
|
final Component propComponent = (Component) value;
|
||||||
|
|
||||||
Class componentClass = ReflectionTools.loadClass( prop_component.getComponentClassName(), mainGenerator.getClassLoaderService() );
|
final Class componentClass = ReflectionTools.loadClass(
|
||||||
CompositeMapperBuilder componentMapper = mapper.addComponent( propertyAuditingData.getPropertyData(), componentClass );
|
propComponent.getComponentClassName(),
|
||||||
|
mainGenerator.getClassLoaderService()
|
||||||
|
);
|
||||||
|
final CompositeMapperBuilder componentMapper = mapper.addComponent(
|
||||||
|
propertyAuditingData.getPropertyData(),
|
||||||
|
componentClass
|
||||||
|
);
|
||||||
|
|
||||||
// The property auditing data must be for a component.
|
// The property auditing data must be for a component.
|
||||||
ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
|
final ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
|
||||||
|
|
||||||
// Adding all properties of the component
|
// Adding all properties of the component
|
||||||
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator();
|
final Iterator<Property> properties = (Iterator<Property>) propComponent.getPropertyIterator();
|
||||||
while (properties.hasNext()) {
|
while ( properties.hasNext() ) {
|
||||||
Property property = properties.next();
|
final Property property = properties.next();
|
||||||
|
|
||||||
PropertyAuditingData componentPropertyAuditingData =
|
final PropertyAuditingData componentPropertyAuditingData =
|
||||||
componentAuditingData.getPropertyAuditingData(property.getName());
|
componentAuditingData.getPropertyAuditingData( property.getName() );
|
||||||
|
|
||||||
// Checking if that property is audited
|
// Checking if that property is audited
|
||||||
if (componentPropertyAuditingData != null) {
|
if ( componentPropertyAuditingData != null ) {
|
||||||
mainGenerator.addValue(parent, property.getValue(), componentMapper, entityName, xmlMappingData,
|
mainGenerator.addValue(
|
||||||
componentPropertyAuditingData, property.isInsertable(), firstPass, false);
|
parent, property.getValue(), componentMapper, entityName, xmlMappingData,
|
||||||
|
componentPropertyAuditingData, property.isInsertable(), firstPass, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -33,39 +34,39 @@ import org.dom4j.Element;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class EntityXmlMappingData {
|
public class EntityXmlMappingData {
|
||||||
private Document mainXmlMapping;
|
private Document mainXmlMapping;
|
||||||
private List<Document> additionalXmlMappings;
|
private List<Document> additionalXmlMappings;
|
||||||
/**
|
/**
|
||||||
* The xml element that maps the class. The root can be one of the folowing elements:
|
* The xml element that maps the class. The root can be one of the folowing elements:
|
||||||
* class, subclass, union-subclass, joined-subclass
|
* class, subclass, union-subclass, joined-subclass
|
||||||
*/
|
*/
|
||||||
private Element classMapping;
|
private Element classMapping;
|
||||||
|
|
||||||
public EntityXmlMappingData() {
|
public EntityXmlMappingData() {
|
||||||
mainXmlMapping = DocumentHelper.createDocument();
|
mainXmlMapping = DocumentHelper.createDocument();
|
||||||
additionalXmlMappings = new ArrayList<Document>();
|
additionalXmlMappings = new ArrayList<Document>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Document getMainXmlMapping() {
|
public Document getMainXmlMapping() {
|
||||||
return mainXmlMapping;
|
return mainXmlMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Document> getAdditionalXmlMappings() {
|
public List<Document> getAdditionalXmlMappings() {
|
||||||
return additionalXmlMappings;
|
return additionalXmlMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Document newAdditionalMapping() {
|
public Document newAdditionalMapping() {
|
||||||
Document additionalMapping = DocumentHelper.createDocument();
|
Document additionalMapping = DocumentHelper.createDocument();
|
||||||
additionalXmlMappings.add(additionalMapping);
|
additionalXmlMappings.add( additionalMapping );
|
||||||
|
|
||||||
return additionalMapping;
|
return additionalMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element getClassMapping() {
|
public Element getClassMapping() {
|
||||||
return classMapping;
|
return classMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClassMapping(Element classMapping) {
|
public void setClassMapping(Element classMapping) {
|
||||||
this.classMapping = classMapping;
|
this.classMapping = classMapping;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
|
@ -47,127 +48,181 @@ import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates metadata for primary identifiers (ids) of versions entities.
|
* Generates metadata for primary identifiers (ids) of versions entities.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class IdMetadataGenerator {
|
public final class IdMetadataGenerator {
|
||||||
private final AuditMetadataGenerator mainGenerator;
|
private final AuditMetadataGenerator mainGenerator;
|
||||||
|
|
||||||
IdMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
IdMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
||||||
mainGenerator = auditMetadataGenerator;
|
mainGenerator = auditMetadataGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private boolean addIdProperties(Element parent, Iterator<Property> properties, SimpleMapperBuilder mapper, boolean key,
|
private boolean addIdProperties(
|
||||||
boolean audited) {
|
Element parent,
|
||||||
while (properties.hasNext()) {
|
Iterator<Property> properties,
|
||||||
Property property = properties.next();
|
SimpleMapperBuilder mapper,
|
||||||
Type propertyType = property.getType();
|
boolean key,
|
||||||
if (!"_identifierMapper".equals(property.getName())) {
|
boolean audited) {
|
||||||
boolean added = false;
|
while ( properties.hasNext() ) {
|
||||||
if (propertyType instanceof ManyToOneType) {
|
final Property property = properties.next();
|
||||||
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(parent,
|
final Type propertyType = property.getType();
|
||||||
getIdPersistentPropertyAuditingData(property),
|
if ( !"_identifierMapper".equals( property.getName() ) ) {
|
||||||
property.getValue(), mapper);
|
boolean added = false;
|
||||||
} else {
|
if ( propertyType instanceof ManyToOneType ) {
|
||||||
// Last but one parameter: ids are always insertable
|
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(
|
||||||
added = mainGenerator.getBasicMetadataGenerator().addBasic(parent,
|
parent,
|
||||||
getIdPersistentPropertyAuditingData(property),
|
getIdPersistentPropertyAuditingData( property ),
|
||||||
property.getValue(), mapper, true, key);
|
property.getValue(),
|
||||||
}
|
mapper
|
||||||
if (!added) {
|
);
|
||||||
// If the entity is audited, and a non-supported id component is used, throwing an exception.
|
}
|
||||||
// If the entity is not audited, then we simply don't support this entity, even in
|
else {
|
||||||
// target relation mode not audited.
|
// Last but one parameter: ids are always insertable
|
||||||
if (audited) {
|
added = mainGenerator.getBasicMetadataGenerator().addBasic(
|
||||||
throw new MappingException("Type not supported: " + propertyType.getClass().getName());
|
parent,
|
||||||
} else {
|
getIdPersistentPropertyAuditingData( property ),
|
||||||
return false;
|
property.getValue(),
|
||||||
}
|
mapper,
|
||||||
}
|
true,
|
||||||
}
|
key
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
if ( !added ) {
|
||||||
|
// If the entity is audited, and a non-supported id component is used, throwing an exception.
|
||||||
|
// If the entity is not audited, then we simply don't support this entity, even in
|
||||||
|
// target relation mode not audited.
|
||||||
|
if ( audited ) {
|
||||||
|
throw new MappingException( "Type not supported: " + propertyType.getClass().getName() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
IdMappingData addId(PersistentClass pc, boolean audited) {
|
IdMappingData addId(PersistentClass pc, boolean audited) {
|
||||||
// Xml mapping which will be used for relations
|
// Xml mapping which will be used for relations
|
||||||
Element rel_id_mapping = new DefaultElement("properties");
|
final Element relIdMapping = new DefaultElement( "properties" );
|
||||||
// Xml mapping which will be used for the primary key of the versions table
|
// Xml mapping which will be used for the primary key of the versions table
|
||||||
Element orig_id_mapping = new DefaultElement("composite-id");
|
final Element origIdMapping = new DefaultElement( "composite-id" );
|
||||||
|
|
||||||
Property id_prop = pc.getIdentifierProperty();
|
final Property idProp = pc.getIdentifierProperty();
|
||||||
Component id_mapper = pc.getIdentifierMapper();
|
final Component idMapper = pc.getIdentifierMapper();
|
||||||
|
|
||||||
// Checking if the id mapping is supported
|
// Checking if the id mapping is supported
|
||||||
if (id_mapper == null && id_prop == null) {
|
if ( idMapper == null && idProp == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleIdMapperBuilder mapper;
|
SimpleIdMapperBuilder mapper;
|
||||||
if (id_mapper != null) {
|
if ( idMapper != null ) {
|
||||||
// Multiple id
|
// Multiple id
|
||||||
|
final Class componentClass = ReflectionTools.loadClass(
|
||||||
Class componentClass = ReflectionTools.loadClass(
|
( (Component) pc.getIdentifier() ).getComponentClassName(),
|
||||||
( (Component) pc.getIdentifier() ).getComponentClassName(), mainGenerator.getClassLoaderService()
|
mainGenerator.getClassLoaderService()
|
||||||
);
|
);
|
||||||
mapper = new MultipleIdMapper( componentClass );
|
mapper = new MultipleIdMapper( componentClass );
|
||||||
if (!addIdProperties(rel_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), mapper, false, audited)) {
|
if ( !addIdProperties(
|
||||||
return null;
|
relIdMapping,
|
||||||
}
|
(Iterator<Property>) idMapper.getPropertyIterator(),
|
||||||
|
mapper,
|
||||||
|
false,
|
||||||
|
audited
|
||||||
|
) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
||||||
if (!addIdProperties(orig_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), null, true, audited)) {
|
if ( !addIdProperties(
|
||||||
return null;
|
origIdMapping,
|
||||||
}
|
(Iterator<Property>) idMapper.getPropertyIterator(),
|
||||||
} else if (id_prop.isComposite()) {
|
null,
|
||||||
// Embedded id
|
true,
|
||||||
|
audited
|
||||||
Component id_component = (Component) id_prop.getValue();
|
) ) {
|
||||||
Class embeddableClass = ReflectionTools.loadClass(
|
return null;
|
||||||
id_component.getComponentClassName(), mainGenerator.getClassLoaderService()
|
}
|
||||||
|
}
|
||||||
|
else if ( idProp.isComposite() ) {
|
||||||
|
// Embedded id
|
||||||
|
final Component idComponent = (Component) idProp.getValue();
|
||||||
|
final Class embeddableClass = ReflectionTools.loadClass(
|
||||||
|
idComponent.getComponentClassName(),
|
||||||
|
mainGenerator.getClassLoaderService()
|
||||||
);
|
);
|
||||||
mapper = new EmbeddedIdMapper( getIdPropertyData(id_prop), embeddableClass );
|
mapper = new EmbeddedIdMapper( getIdPropertyData( idProp ), embeddableClass );
|
||||||
if (!addIdProperties(rel_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), mapper, false, audited)) {
|
if ( !addIdProperties(
|
||||||
return null;
|
relIdMapping,
|
||||||
}
|
(Iterator<Property>) idComponent.getPropertyIterator(),
|
||||||
|
mapper,
|
||||||
|
false,
|
||||||
|
audited
|
||||||
|
) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
||||||
if (!addIdProperties(orig_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), null, true, audited)) {
|
if ( !addIdProperties(
|
||||||
return null;
|
origIdMapping,
|
||||||
}
|
(Iterator<Property>) idComponent.getPropertyIterator(),
|
||||||
} else {
|
null,
|
||||||
// Single id
|
true,
|
||||||
|
audited
|
||||||
mapper = new SingleIdMapper();
|
) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Single id
|
||||||
|
mapper = new SingleIdMapper();
|
||||||
|
|
||||||
// Last but one parameter: ids are always insertable
|
// Last but one parameter: ids are always insertable
|
||||||
mainGenerator.getBasicMetadataGenerator().addBasic(rel_id_mapping,
|
mainGenerator.getBasicMetadataGenerator().addBasic(
|
||||||
getIdPersistentPropertyAuditingData(id_prop),
|
relIdMapping,
|
||||||
id_prop.getValue(), mapper, true, false);
|
getIdPersistentPropertyAuditingData( idProp ),
|
||||||
|
idProp.getValue(),
|
||||||
|
mapper,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
||||||
mainGenerator.getBasicMetadataGenerator().addBasic(orig_id_mapping,
|
mainGenerator.getBasicMetadataGenerator().addBasic(
|
||||||
getIdPersistentPropertyAuditingData(id_prop),
|
origIdMapping,
|
||||||
id_prop.getValue(), null, true, true);
|
getIdPersistentPropertyAuditingData( idProp ),
|
||||||
}
|
idProp.getValue(),
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
orig_id_mapping.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName());
|
origIdMapping.addAttribute( "name", mainGenerator.getVerEntCfg().getOriginalIdPropName() );
|
||||||
|
|
||||||
// Adding a relation to the revision entity (effectively: the "revision number" property)
|
// Adding a relation to the revision entity (effectively: the "revision number" property)
|
||||||
mainGenerator.addRevisionInfoRelation(orig_id_mapping);
|
mainGenerator.addRevisionInfoRelation( origIdMapping );
|
||||||
|
|
||||||
return new IdMappingData(mapper, orig_id_mapping, rel_id_mapping);
|
return new IdMappingData( mapper, origIdMapping, relIdMapping );
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertyData getIdPropertyData(Property property) {
|
private PropertyData getIdPropertyData(Property property) {
|
||||||
return new PropertyData(property.getName(), property.getName(), property.getPropertyAccessorName(),
|
return new PropertyData(
|
||||||
ModificationStore.FULL);
|
property.getName(), property.getName(), property.getPropertyAccessorName(),
|
||||||
}
|
ModificationStore.FULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
|
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
|
||||||
return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
|
return new PropertyAuditingData(
|
||||||
ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false);
|
property.getName(), property.getPropertyAccessorName(),
|
||||||
}
|
ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.mapping.JoinedSubclass;
|
import org.hibernate.mapping.JoinedSubclass;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
@ -33,33 +34,36 @@ import org.hibernate.mapping.UnionSubclass;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public enum InheritanceType {
|
public enum InheritanceType {
|
||||||
NONE,
|
NONE,
|
||||||
JOINED,
|
JOINED,
|
||||||
SINGLE,
|
SINGLE,
|
||||||
TABLE_PER_CLASS;
|
TABLE_PER_CLASS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param pc The class for which to get the inheritance type.
|
* @param pc The class for which to get the inheritance type.
|
||||||
* @return The inheritance type of this class. NONE, if this class does not inherit from
|
*
|
||||||
* another persisten class.
|
* @return The inheritance type of this class. NONE, if this class does not inherit from
|
||||||
*/
|
* another persistent class.
|
||||||
public static InheritanceType get(PersistentClass pc) {
|
*/
|
||||||
PersistentClass superclass = pc.getSuperclass();
|
public static InheritanceType get(PersistentClass pc) {
|
||||||
if (superclass == null) {
|
final PersistentClass superclass = pc.getSuperclass();
|
||||||
return InheritanceType.NONE;
|
if ( superclass == null ) {
|
||||||
}
|
return InheritanceType.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
// We assume that every subclass is of the same type.
|
// We assume that every subclass is of the same type.
|
||||||
Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
|
final Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
|
||||||
|
|
||||||
if (subclass instanceof SingleTableSubclass) {
|
if ( subclass instanceof SingleTableSubclass ) {
|
||||||
return InheritanceType.SINGLE;
|
return InheritanceType.SINGLE;
|
||||||
} else if (subclass instanceof JoinedSubclass) {
|
}
|
||||||
return InheritanceType.JOINED;
|
else if ( subclass instanceof JoinedSubclass ) {
|
||||||
} else if (subclass instanceof UnionSubclass) {
|
return InheritanceType.JOINED;
|
||||||
return InheritanceType.TABLE_PER_CLASS;
|
}
|
||||||
}
|
else if ( subclass instanceof UnionSubclass ) {
|
||||||
|
return InheritanceType.TABLE_PER_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
throw new MappingException("Unknown subclass class: " + subclass.getClass());
|
throw new MappingException( "Unknown subclass class: " + subclass.getClass() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,8 +22,9 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
import java.util.Iterator;
|
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.dom4j.Attribute;
|
import org.dom4j.Attribute;
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
|
@ -41,52 +42,72 @@ import org.hibernate.mapping.Selectable;
|
||||||
*/
|
*/
|
||||||
public class MetadataTools {
|
public class MetadataTools {
|
||||||
|
|
||||||
public static Element addNativelyGeneratedId(Element parent, String name, String type,
|
public static Element addNativelyGeneratedId(
|
||||||
boolean useRevisionEntityWithNativeId) {
|
Element parent, String name, String type,
|
||||||
Element id_mapping = parent.addElement("id");
|
boolean useRevisionEntityWithNativeId) {
|
||||||
id_mapping.addAttribute("name", name).addAttribute("type", type);
|
final Element idMapping = parent.addElement( "id" );
|
||||||
|
idMapping.addAttribute( "name", name ).addAttribute( "type", type );
|
||||||
|
|
||||||
Element generator_mapping = id_mapping.addElement("generator");
|
final Element generatorMapping = idMapping.addElement( "generator" );
|
||||||
if (useRevisionEntityWithNativeId) {
|
if ( useRevisionEntityWithNativeId ) {
|
||||||
generator_mapping.addAttribute("class", "native");
|
generatorMapping.addAttribute( "class", "native" );
|
||||||
} else {
|
}
|
||||||
generator_mapping.addAttribute("class", "org.hibernate.envers.enhanced.OrderedSequenceGenerator");
|
else {
|
||||||
generator_mapping.addElement("param").addAttribute("name", "sequence_name").setText("REVISION_GENERATOR");
|
generatorMapping.addAttribute( "class", "org.hibernate.envers.enhanced.OrderedSequenceGenerator" );
|
||||||
generator_mapping.addElement("param").addAttribute("name", "table_name").setText("REVISION_GENERATOR");
|
generatorMapping.addElement( "param" ).addAttribute( "name", "sequence_name" ).setText(
|
||||||
generator_mapping.addElement("param").addAttribute("name", "initial_value").setText("1");
|
"REVISION_GENERATOR"
|
||||||
generator_mapping.addElement("param").addAttribute("name", "increment_size").setText("1");
|
);
|
||||||
}
|
generatorMapping.addElement( "param" )
|
||||||
// generator_mapping.addAttribute("class", "sequence");
|
.addAttribute( "name", "table_name" )
|
||||||
// generator_mapping.addElement("param").addAttribute("name", "sequence").setText("custom");
|
.setText( "REVISION_GENERATOR" );
|
||||||
|
generatorMapping.addElement( "param" ).addAttribute( "name", "initial_value" ).setText( "1" );
|
||||||
|
generatorMapping.addElement( "param" ).addAttribute( "name", "increment_size" ).setText( "1" );
|
||||||
|
}
|
||||||
|
// generatorMapping.addAttribute("class", "sequence");
|
||||||
|
// generatorMapping.addElement("param").addAttribute("name", "sequence").setText("custom");
|
||||||
|
|
||||||
return id_mapping;
|
return idMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean updateable, boolean key) {
|
public static Element addProperty(
|
||||||
Element prop_mapping;
|
Element parent,
|
||||||
if (key) {
|
String name,
|
||||||
prop_mapping = parent.addElement("key-property");
|
String type,
|
||||||
} else {
|
boolean insertable,
|
||||||
prop_mapping = parent.addElement("property");
|
boolean updateable,
|
||||||
}
|
boolean key) {
|
||||||
|
final Element propMapping;
|
||||||
|
if ( key ) {
|
||||||
|
propMapping = parent.addElement( "key-property" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
propMapping = parent.addElement( "property" );
|
||||||
|
}
|
||||||
|
|
||||||
prop_mapping.addAttribute("name", name);
|
propMapping.addAttribute( "name", name );
|
||||||
prop_mapping.addAttribute("insert", Boolean.toString(insertable));
|
propMapping.addAttribute( "insert", Boolean.toString( insertable ) );
|
||||||
prop_mapping.addAttribute("update", Boolean.toString(updateable));
|
propMapping.addAttribute( "update", Boolean.toString( updateable ) );
|
||||||
|
|
||||||
if (type != null) {
|
if ( type != null ) {
|
||||||
prop_mapping.addAttribute("type", type);
|
propMapping.addAttribute( "type", type );
|
||||||
}
|
}
|
||||||
|
|
||||||
return prop_mapping;
|
return propMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) {
|
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) {
|
||||||
return addProperty(parent, name, type, insertable, false, key);
|
return addProperty( parent, name, type, insertable, false, key );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Element addModifiedFlagProperty(Element parent, String propertyName, String suffix) {
|
public static Element addModifiedFlagProperty(Element parent, String propertyName, String suffix) {
|
||||||
return addProperty(parent, getModifiedFlagPropertyName(propertyName, suffix), "boolean", true, false, false);
|
return addProperty(
|
||||||
|
parent,
|
||||||
|
getModifiedFlagPropertyName( propertyName, suffix ),
|
||||||
|
"boolean",
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getModifiedFlagPropertyName(String propertyName, String suffix) {
|
public static String getModifiedFlagPropertyName(String propertyName, String suffix) {
|
||||||
|
@ -94,256 +115,319 @@ public class MetadataTools {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addOrModifyAttribute(Element parent, String name, String value) {
|
private static void addOrModifyAttribute(Element parent, String name, String value) {
|
||||||
Attribute attribute = parent.attribute(name);
|
final Attribute attribute = parent.attribute( name );
|
||||||
if (attribute == null) {
|
if ( attribute == null ) {
|
||||||
parent.addAttribute(name, value);
|
parent.addAttribute( name, value );
|
||||||
} else {
|
|
||||||
attribute.setValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Column name shall be wrapped with '`' signs if quotation required.
|
|
||||||
*/
|
|
||||||
public static Element addOrModifyColumn(Element parent, String name) {
|
|
||||||
Element column_mapping = parent.element("column");
|
|
||||||
|
|
||||||
if (column_mapping == null) {
|
|
||||||
return addColumn(parent, name, null, null, null, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StringTools.isEmpty(name)) {
|
|
||||||
addOrModifyAttribute(column_mapping, "name", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return column_mapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds new <code>column</code> element. Method assumes that the value of <code>name</code> attribute is already
|
|
||||||
* wrapped with '`' signs if quotation required. It shall be invoked when column name is taken directly from configuration
|
|
||||||
* file and not from {@link org.hibernate.mapping.PersistentClass} descriptor.
|
|
||||||
*/
|
|
||||||
public static Element addColumn(Element parent, String name, Integer length, Integer scale, Integer precision,
|
|
||||||
String sqlType, String customRead, String customWrite) {
|
|
||||||
return addColumn(parent, name, length, scale, precision, sqlType, customRead, customWrite, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Element addColumn(Element parent, String name, Integer length, Integer scale, Integer precision,
|
|
||||||
String sqlType, String customRead, String customWrite, boolean quoted) {
|
|
||||||
Element column_mapping = parent.addElement("column");
|
|
||||||
|
|
||||||
column_mapping.addAttribute("name", quoted ? "`" + name + "`" : name);
|
|
||||||
if (length != null) {
|
|
||||||
column_mapping.addAttribute("length", length.toString());
|
|
||||||
}
|
|
||||||
if (scale != null) {
|
|
||||||
column_mapping.addAttribute("scale", Integer.toString(scale));
|
|
||||||
}
|
}
|
||||||
if (precision != null) {
|
else {
|
||||||
column_mapping.addAttribute("precision", Integer.toString(precision));
|
attribute.setValue( value );
|
||||||
}
|
}
|
||||||
if (!StringTools.isEmpty(sqlType)) {
|
}
|
||||||
column_mapping.addAttribute("sql-type", sqlType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StringTools.isEmpty(customRead)) {
|
/**
|
||||||
column_mapping.addAttribute("read", customRead);
|
* Column name shall be wrapped with '`' signs if quotation required.
|
||||||
}
|
*/
|
||||||
if (!StringTools.isEmpty(customWrite)) {
|
public static Element addOrModifyColumn(Element parent, String name) {
|
||||||
column_mapping.addAttribute("write", customWrite);
|
final Element columnMapping = parent.element( "column" );
|
||||||
}
|
|
||||||
|
|
||||||
return column_mapping;
|
if ( columnMapping == null ) {
|
||||||
}
|
return addColumn( parent, name, null, null, null, null, null, null );
|
||||||
|
}
|
||||||
|
|
||||||
private static Element createEntityCommon(Document document, String type, AuditTableData auditTableData,
|
if ( !StringTools.isEmpty( name ) ) {
|
||||||
String discriminatorValue, Boolean isAbstract) {
|
addOrModifyAttribute( columnMapping, "name", name );
|
||||||
Element hibernate_mapping = document.addElement("hibernate-mapping");
|
}
|
||||||
hibernate_mapping.addAttribute("auto-import", "false");
|
|
||||||
|
|
||||||
Element class_mapping = hibernate_mapping.addElement(type);
|
return columnMapping;
|
||||||
|
}
|
||||||
|
|
||||||
if (auditTableData.getAuditEntityName() != null) {
|
/**
|
||||||
class_mapping.addAttribute("entity-name", auditTableData.getAuditEntityName());
|
* Adds new <code>column</code> element. Method assumes that the value of <code>name</code> attribute is already
|
||||||
}
|
* wrapped with '`' signs if quotation required. It shall be invoked when column name is taken directly from configuration
|
||||||
|
* file and not from {@link org.hibernate.mapping.PersistentClass} descriptor.
|
||||||
|
*/
|
||||||
|
public static Element addColumn(
|
||||||
|
Element parent,
|
||||||
|
String name,
|
||||||
|
Integer length,
|
||||||
|
Integer scale,
|
||||||
|
Integer precision,
|
||||||
|
String sqlType,
|
||||||
|
String customRead,
|
||||||
|
String customWrite) {
|
||||||
|
return addColumn( parent, name, length, scale, precision, sqlType, customRead, customWrite, false );
|
||||||
|
}
|
||||||
|
|
||||||
if (discriminatorValue != null) {
|
public static Element addColumn(
|
||||||
class_mapping.addAttribute("discriminator-value", discriminatorValue);
|
Element parent,
|
||||||
}
|
String name,
|
||||||
|
Integer length,
|
||||||
|
Integer scale,
|
||||||
|
Integer precision,
|
||||||
|
String sqlType,
|
||||||
|
String customRead,
|
||||||
|
String customWrite,
|
||||||
|
boolean quoted) {
|
||||||
|
final Element columnMapping = parent.addElement( "column" );
|
||||||
|
|
||||||
if (!StringTools.isEmpty(auditTableData.getAuditTableName())) {
|
columnMapping.addAttribute( "name", quoted ? "`" + name + "`" : name );
|
||||||
class_mapping.addAttribute("table", auditTableData.getAuditTableName());
|
if ( length != null ) {
|
||||||
}
|
columnMapping.addAttribute( "length", length.toString() );
|
||||||
|
}
|
||||||
|
if ( scale != null ) {
|
||||||
|
columnMapping.addAttribute( "scale", Integer.toString( scale ) );
|
||||||
|
}
|
||||||
|
if ( precision != null ) {
|
||||||
|
columnMapping.addAttribute( "precision", Integer.toString( precision ) );
|
||||||
|
}
|
||||||
|
if ( !StringTools.isEmpty( sqlType ) ) {
|
||||||
|
columnMapping.addAttribute( "sql-type", sqlType );
|
||||||
|
}
|
||||||
|
|
||||||
if (!StringTools.isEmpty(auditTableData.getSchema())) {
|
if ( !StringTools.isEmpty( customRead ) ) {
|
||||||
class_mapping.addAttribute("schema", auditTableData.getSchema());
|
columnMapping.addAttribute( "read", customRead );
|
||||||
}
|
}
|
||||||
|
if ( !StringTools.isEmpty( customWrite ) ) {
|
||||||
|
columnMapping.addAttribute( "write", customWrite );
|
||||||
|
}
|
||||||
|
|
||||||
if (!StringTools.isEmpty(auditTableData.getCatalog())) {
|
return columnMapping;
|
||||||
class_mapping.addAttribute("catalog", auditTableData.getCatalog());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (isAbstract != null) {
|
private static Element createEntityCommon(
|
||||||
class_mapping.addAttribute("abstract", isAbstract.toString());
|
Document document,
|
||||||
}
|
String type,
|
||||||
|
AuditTableData auditTableData,
|
||||||
|
String discriminatorValue,
|
||||||
|
Boolean isAbstract) {
|
||||||
|
final Element hibernateMapping = document.addElement( "hibernate-mapping" );
|
||||||
|
hibernateMapping.addAttribute( "auto-import", "false" );
|
||||||
|
|
||||||
return class_mapping;
|
final Element classMapping = hibernateMapping.addElement( type );
|
||||||
}
|
|
||||||
|
|
||||||
public static Element createEntity(Document document, AuditTableData auditTableData, String discriminatorValue,
|
if ( auditTableData.getAuditEntityName() != null ) {
|
||||||
Boolean isAbstract) {
|
classMapping.addAttribute( "entity-name", auditTableData.getAuditEntityName() );
|
||||||
return createEntityCommon(document, "class", auditTableData, discriminatorValue, isAbstract);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static Element createSubclassEntity(Document document, String subclassType, AuditTableData auditTableData,
|
if ( discriminatorValue != null ) {
|
||||||
String extendsEntityName, String discriminatorValue, Boolean isAbstract) {
|
classMapping.addAttribute( "discriminator-value", discriminatorValue );
|
||||||
Element class_mapping = createEntityCommon(document, subclassType, auditTableData, discriminatorValue, isAbstract);
|
}
|
||||||
|
|
||||||
class_mapping.addAttribute("extends", extendsEntityName);
|
if ( !StringTools.isEmpty( auditTableData.getAuditTableName() ) ) {
|
||||||
|
classMapping.addAttribute( "table", auditTableData.getAuditTableName() );
|
||||||
|
}
|
||||||
|
|
||||||
return class_mapping;
|
if ( !StringTools.isEmpty( auditTableData.getSchema() ) ) {
|
||||||
}
|
classMapping.addAttribute( "schema", auditTableData.getSchema() );
|
||||||
|
}
|
||||||
|
|
||||||
public static Element createJoin(Element parent, String tableName,
|
if ( !StringTools.isEmpty( auditTableData.getCatalog() ) ) {
|
||||||
String schema, String catalog) {
|
classMapping.addAttribute( "catalog", auditTableData.getCatalog() );
|
||||||
Element join_mapping = parent.addElement("join");
|
}
|
||||||
|
|
||||||
join_mapping.addAttribute("table", tableName);
|
if ( isAbstract != null ) {
|
||||||
|
classMapping.addAttribute( "abstract", isAbstract.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
if (!StringTools.isEmpty(schema)) {
|
return classMapping;
|
||||||
join_mapping.addAttribute("schema", schema);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!StringTools.isEmpty(catalog)) {
|
public static Element createEntity(
|
||||||
join_mapping.addAttribute("catalog", catalog);
|
Document document,
|
||||||
}
|
AuditTableData auditTableData,
|
||||||
|
String discriminatorValue,
|
||||||
|
Boolean isAbstract) {
|
||||||
|
return createEntityCommon( document, "class", auditTableData, discriminatorValue, isAbstract );
|
||||||
|
}
|
||||||
|
|
||||||
return join_mapping;
|
public static Element createSubclassEntity(
|
||||||
}
|
Document document,
|
||||||
|
String subclassType,
|
||||||
|
AuditTableData auditTableData,
|
||||||
|
String extendsEntityName,
|
||||||
|
String discriminatorValue,
|
||||||
|
Boolean isAbstract) {
|
||||||
|
final Element classMapping = createEntityCommon(
|
||||||
|
document,
|
||||||
|
subclassType,
|
||||||
|
auditTableData,
|
||||||
|
discriminatorValue,
|
||||||
|
isAbstract
|
||||||
|
);
|
||||||
|
|
||||||
public static void addColumns(Element any_mapping, Iterator selectables) {
|
classMapping.addAttribute( "extends", extendsEntityName );
|
||||||
while ( selectables.hasNext() ) {
|
|
||||||
|
return classMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Element createJoin(
|
||||||
|
Element parent,
|
||||||
|
String tableName,
|
||||||
|
String schema,
|
||||||
|
String catalog) {
|
||||||
|
final Element joinMapping = parent.addElement( "join" );
|
||||||
|
|
||||||
|
joinMapping.addAttribute( "table", tableName );
|
||||||
|
|
||||||
|
if ( !StringTools.isEmpty( schema ) ) {
|
||||||
|
joinMapping.addAttribute( "schema", schema );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !StringTools.isEmpty( catalog ) ) {
|
||||||
|
joinMapping.addAttribute( "catalog", catalog );
|
||||||
|
}
|
||||||
|
|
||||||
|
return joinMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addColumns(Element anyMapping, Iterator selectables) {
|
||||||
|
while ( selectables.hasNext() ) {
|
||||||
final Selectable selectable = (Selectable) selectables.next();
|
final Selectable selectable = (Selectable) selectables.next();
|
||||||
if ( selectable.isFormula() ) {
|
if ( selectable.isFormula() ) {
|
||||||
throw new FormulaNotSupportedException();
|
throw new FormulaNotSupportedException();
|
||||||
}
|
}
|
||||||
addColumn( any_mapping, (Column) selectable );
|
addColumn( anyMapping, (Column) selectable );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds <code>column</code> element with the following attributes (unless empty): <code>name</code>,
|
|
||||||
* <code>length</code>, <code>scale</code>, <code>precision</code>, <code>sql-type</code>, <code>read</code>
|
|
||||||
* and <code>write</code>.
|
|
||||||
* @param any_mapping Parent element.
|
|
||||||
* @param column Column descriptor.
|
|
||||||
*/
|
|
||||||
public static void addColumn(Element any_mapping, Column column) {
|
|
||||||
addColumn(any_mapping, column.getName(), column.getLength(), column.getScale(), column.getPrecision(),
|
|
||||||
column.getSqlType(), column.getCustomRead(), column.getCustomWrite(), column.isQuoted());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
|
||||||
private static void changeNamesInColumnElement(Element element, ColumnNameIterator columnNameIterator) {
|
|
||||||
Iterator<Element> properties = element.elementIterator();
|
|
||||||
while (properties.hasNext()) {
|
|
||||||
Element property = properties.next();
|
|
||||||
|
|
||||||
if ("column".equals(property.getName())) {
|
|
||||||
Attribute nameAttr = property.attribute("name");
|
|
||||||
if (nameAttr != null) {
|
|
||||||
nameAttr.setText(columnNameIterator.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
|
||||||
public static void prefixNamesInPropertyElement(Element element, String prefix, ColumnNameIterator columnNameIterator,
|
|
||||||
boolean changeToKey, boolean insertable) {
|
|
||||||
Iterator<Element> properties = element.elementIterator();
|
|
||||||
while (properties.hasNext()) {
|
|
||||||
Element property = properties.next();
|
|
||||||
|
|
||||||
if ("property".equals(property.getName()) || "many-to-one".equals(property.getName())) {
|
|
||||||
Attribute nameAttr = property.attribute("name");
|
|
||||||
if (nameAttr != null) {
|
|
||||||
nameAttr.setText(prefix + nameAttr.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
changeNamesInColumnElement(property, columnNameIterator);
|
|
||||||
|
|
||||||
if (changeToKey) {
|
|
||||||
property.setName("key-" + property.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("property".equals(property.getName())) {
|
|
||||||
Attribute insert = property.attribute("insert");
|
|
||||||
insert.setText(Boolean.toString(insertable));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds <code>formula</code> element.
|
|
||||||
* @param element Parent element.
|
|
||||||
* @param formula Formula descriptor.
|
|
||||||
*/
|
|
||||||
public static void addFormula(Element element, Formula formula) {
|
|
||||||
element.addElement("formula").setText(formula.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds all <code>column</code> or <code>formula</code> elements.
|
|
||||||
* @param element Parent element.
|
|
||||||
* @param columnIterator Iterator pointing at {@link org.hibernate.mapping.Column} and/or
|
|
||||||
* {@link org.hibernate.mapping.Formula} objects.
|
|
||||||
*/
|
|
||||||
public static void addColumnsOrFormulas(Element element, Iterator columnIterator) {
|
|
||||||
while (columnIterator.hasNext()) {
|
|
||||||
Object o = columnIterator.next();
|
|
||||||
if (o instanceof Column) {
|
|
||||||
addColumn(element, (Column) o);
|
|
||||||
} else if (o instanceof Formula) {
|
|
||||||
addFormula(element, (Formula) o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An iterator over column names.
|
|
||||||
*/
|
|
||||||
public static abstract class ColumnNameIterator implements Iterator<String> {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ColumnNameIterator getColumnNameIterator(final Iterator<Selectable> selectableIterator) {
|
/**
|
||||||
return new ColumnNameIterator() {
|
* Adds <code>column</code> element with the following attributes (unless empty): <code>name</code>,
|
||||||
public boolean hasNext() {
|
* <code>length</code>, <code>scale</code>, <code>precision</code>, <code>sql-type</code>, <code>read</code>
|
||||||
|
* and <code>write</code>.
|
||||||
|
*
|
||||||
|
* @param anyMapping Parent element.
|
||||||
|
* @param column Column descriptor.
|
||||||
|
*/
|
||||||
|
public static void addColumn(Element anyMapping, Column column) {
|
||||||
|
addColumn(
|
||||||
|
anyMapping,
|
||||||
|
column.getName(),
|
||||||
|
column.getLength(),
|
||||||
|
column.getScale(),
|
||||||
|
column.getPrecision(),
|
||||||
|
column.getSqlType(),
|
||||||
|
column.getCustomRead(),
|
||||||
|
column.getCustomWrite(),
|
||||||
|
column.isQuoted()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
private static void changeNamesInColumnElement(Element element, ColumnNameIterator columnNameIterator) {
|
||||||
|
final Iterator<Element> properties = element.elementIterator();
|
||||||
|
while ( properties.hasNext() ) {
|
||||||
|
final Element property = properties.next();
|
||||||
|
|
||||||
|
if ( "column".equals( property.getName() ) ) {
|
||||||
|
final Attribute nameAttr = property.attribute( "name" );
|
||||||
|
if ( nameAttr != null ) {
|
||||||
|
nameAttr.setText( columnNameIterator.next() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public static void prefixNamesInPropertyElement(
|
||||||
|
Element element,
|
||||||
|
String prefix,
|
||||||
|
ColumnNameIterator columnNameIterator,
|
||||||
|
boolean changeToKey,
|
||||||
|
boolean insertable) {
|
||||||
|
final Iterator<Element> properties = element.elementIterator();
|
||||||
|
while ( properties.hasNext() ) {
|
||||||
|
final Element property = properties.next();
|
||||||
|
|
||||||
|
if ( "property".equals( property.getName() ) || "many-to-one".equals( property.getName() ) ) {
|
||||||
|
final Attribute nameAttr = property.attribute( "name" );
|
||||||
|
if ( nameAttr != null ) {
|
||||||
|
nameAttr.setText( prefix + nameAttr.getText() );
|
||||||
|
}
|
||||||
|
|
||||||
|
changeNamesInColumnElement( property, columnNameIterator );
|
||||||
|
|
||||||
|
if ( changeToKey ) {
|
||||||
|
property.setName( "key-" + property.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( "property".equals( property.getName() ) ) {
|
||||||
|
final Attribute insert = property.attribute( "insert" );
|
||||||
|
insert.setText( Boolean.toString( insertable ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds <code>formula</code> element.
|
||||||
|
*
|
||||||
|
* @param element Parent element.
|
||||||
|
* @param formula Formula descriptor.
|
||||||
|
*/
|
||||||
|
public static void addFormula(Element element, Formula formula) {
|
||||||
|
element.addElement( "formula" ).setText( formula.getText() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all <code>column</code> or <code>formula</code> elements.
|
||||||
|
*
|
||||||
|
* @param element Parent element.
|
||||||
|
* @param columnIterator Iterator pointing at {@link org.hibernate.mapping.Column} and/or
|
||||||
|
* {@link org.hibernate.mapping.Formula} objects.
|
||||||
|
*/
|
||||||
|
public static void addColumnsOrFormulas(Element element, Iterator columnIterator) {
|
||||||
|
while ( columnIterator.hasNext() ) {
|
||||||
|
final Object o = columnIterator.next();
|
||||||
|
if ( o instanceof Column ) {
|
||||||
|
addColumn( element, (Column) o );
|
||||||
|
}
|
||||||
|
else if ( o instanceof Formula ) {
|
||||||
|
addFormula( element, (Formula) o );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An iterator over column names.
|
||||||
|
*/
|
||||||
|
public static abstract class ColumnNameIterator implements Iterator<String> {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ColumnNameIterator getColumnNameIterator(final Iterator<Selectable> selectableIterator) {
|
||||||
|
return new ColumnNameIterator() {
|
||||||
|
public boolean hasNext() {
|
||||||
return selectableIterator.hasNext();
|
return selectableIterator.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String next() {
|
public String next() {
|
||||||
final Selectable next = selectableIterator.next();
|
final Selectable next = selectableIterator.next();
|
||||||
if ( next.isFormula() ) {
|
if ( next.isFormula() ) {
|
||||||
throw new FormulaNotSupportedException();
|
throw new FormulaNotSupportedException();
|
||||||
}
|
}
|
||||||
return ( (Column) next ).getName();
|
return ((Column) next).getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove() {
|
public void remove() {
|
||||||
selectableIterator.remove();
|
selectableIterator.remove();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ColumnNameIterator getColumnNameIterator(final JoinColumn[] joinColumns) {
|
public static ColumnNameIterator getColumnNameIterator(final JoinColumn[] joinColumns) {
|
||||||
return new ColumnNameIterator() {
|
return new ColumnNameIterator() {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
public boolean hasNext() { return counter < joinColumns.length; }
|
|
||||||
public String next() { return joinColumns[counter++].name(); }
|
public boolean hasNext() {
|
||||||
public void remove() { throw new UnsupportedOperationException(); }
|
return counter < joinColumns.length;
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
public String next() {
|
||||||
|
return joinColumns[counter++].name();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -40,64 +41,83 @@ import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
/**
|
/**
|
||||||
* Builds query generators, for reading collection middle tables, along with any related entities.
|
* Builds query generators, for reading collection middle tables, along with any related entities.
|
||||||
* The related entities information can be added gradually, and when complete, the query generator can be built.
|
* The related entities information can be added gradually, and when complete, the query generator can be built.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class QueryGeneratorBuilder {
|
public final class QueryGeneratorBuilder {
|
||||||
private final GlobalConfiguration globalCfg;
|
private final GlobalConfiguration globalCfg;
|
||||||
private final AuditEntitiesConfiguration verEntCfg;
|
private final AuditEntitiesConfiguration verEntCfg;
|
||||||
private final AuditStrategy auditStrategy;
|
private final AuditStrategy auditStrategy;
|
||||||
private final MiddleIdData referencingIdData;
|
private final MiddleIdData referencingIdData;
|
||||||
private final String auditMiddleEntityName;
|
private final String auditMiddleEntityName;
|
||||||
private final List<MiddleIdData> idDatas;
|
private final List<MiddleIdData> idDatas;
|
||||||
private final boolean revisionTypeInId;
|
private final boolean revisionTypeInId;
|
||||||
|
|
||||||
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
QueryGeneratorBuilder(
|
||||||
AuditStrategy auditStrategy, MiddleIdData referencingIdData, String auditMiddleEntityName,
|
GlobalConfiguration globalCfg,
|
||||||
boolean revisionTypeInId) {
|
AuditEntitiesConfiguration verEntCfg,
|
||||||
this.globalCfg = globalCfg;
|
AuditStrategy auditStrategy,
|
||||||
this.verEntCfg = verEntCfg;
|
MiddleIdData referencingIdData,
|
||||||
this.auditStrategy = auditStrategy;
|
String auditMiddleEntityName,
|
||||||
this.referencingIdData = referencingIdData;
|
boolean revisionTypeInId) {
|
||||||
this.auditMiddleEntityName = auditMiddleEntityName;
|
this.globalCfg = globalCfg;
|
||||||
|
this.verEntCfg = verEntCfg;
|
||||||
|
this.auditStrategy = auditStrategy;
|
||||||
|
this.referencingIdData = referencingIdData;
|
||||||
|
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||||
this.revisionTypeInId = revisionTypeInId;
|
this.revisionTypeInId = revisionTypeInId;
|
||||||
|
|
||||||
idDatas = new ArrayList<MiddleIdData>();
|
idDatas = new ArrayList<MiddleIdData>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRelation(MiddleIdData idData) {
|
void addRelation(MiddleIdData idData) {
|
||||||
idDatas.add(idData);
|
idDatas.add( idData );
|
||||||
}
|
}
|
||||||
|
|
||||||
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
||||||
if (idDatas.size() == 0) {
|
if ( idDatas.size() == 0 ) {
|
||||||
return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
return new OneEntityQueryGenerator(
|
||||||
revisionTypeInId, componentDatas);
|
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
} else if (idDatas.size() == 1) {
|
revisionTypeInId, componentDatas
|
||||||
if (idDatas.get(0).isAudited()) {
|
);
|
||||||
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
}
|
||||||
idDatas.get(0), revisionTypeInId, componentDatas);
|
else if ( idDatas.size() == 1 ) {
|
||||||
} else {
|
if ( idDatas.get( 0 ).isAudited() ) {
|
||||||
return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
return new TwoEntityQueryGenerator(
|
||||||
idDatas.get(0), revisionTypeInId, componentDatas);
|
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
}
|
idDatas.get( 0 ), revisionTypeInId, componentDatas
|
||||||
} else if (idDatas.size() == 2) {
|
);
|
||||||
// All entities must be audited.
|
}
|
||||||
if (!idDatas.get(0).isAudited() || !idDatas.get(1).isAudited()) {
|
else {
|
||||||
throw new MappingException("Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported.");
|
return new TwoEntityOneAuditedQueryGenerator(
|
||||||
}
|
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
|
idDatas.get( 0 ), revisionTypeInId, componentDatas
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( idDatas.size() == 2 ) {
|
||||||
|
// All entities must be audited.
|
||||||
|
if ( !idDatas.get( 0 ).isAudited() || !idDatas.get( 1 ).isAudited() ) {
|
||||||
|
throw new MappingException(
|
||||||
|
"Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
return new ThreeEntityQueryGenerator(
|
||||||
idDatas.get(0), idDatas.get(1), revisionTypeInId, componentDatas);
|
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
} else {
|
idDatas.get( 0 ), idDatas.get( 1 ), revisionTypeInId, componentDatas
|
||||||
throw new IllegalStateException("Illegal number of related entities.");
|
);
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
throw new IllegalStateException( "Illegal number of related entities." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Current index of data in the array, which will be the element of a list, returned when executing a query
|
* @return Current index of data in the array, which will be the element of a list, returned when executing a query
|
||||||
* generated by the built query generator.
|
* generated by the built query generator.
|
||||||
*/
|
*/
|
||||||
int getCurrentIndex() {
|
int getCurrentIndex() {
|
||||||
return idDatas.size();
|
return idDatas.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata;
|
package org.hibernate.envers.configuration.internal.metadata;
|
||||||
|
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
|
@ -41,121 +42,166 @@ import org.hibernate.mapping.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates metadata for to-one relations (reference-valued properties).
|
* Generates metadata for to-one relations (reference-valued properties).
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public final class ToOneRelationMetadataGenerator {
|
public final class ToOneRelationMetadataGenerator {
|
||||||
private final AuditMetadataGenerator mainGenerator;
|
private final AuditMetadataGenerator mainGenerator;
|
||||||
|
|
||||||
ToOneRelationMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
ToOneRelationMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
||||||
mainGenerator = auditMetadataGenerator;
|
mainGenerator = auditMetadataGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
void addToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value,
|
void addToOne(
|
||||||
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
|
Element parent,
|
||||||
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
PropertyAuditingData propertyAuditingData,
|
||||||
|
Value value,
|
||||||
|
CompositeMapperBuilder mapper,
|
||||||
|
String entityName,
|
||||||
|
boolean insertable) {
|
||||||
|
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
||||||
|
|
||||||
IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(entityName, referencedEntityName,
|
final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
|
||||||
propertyAuditingData, true);
|
entityName,
|
||||||
|
referencedEntityName,
|
||||||
|
propertyAuditingData,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(propertyAuditingData.getName());
|
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( propertyAuditingData.getName() );
|
||||||
|
|
||||||
// Generating the id mapper for the relation
|
// Generating the id mapper for the relation
|
||||||
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
|
||||||
|
|
||||||
// Storing information about this relation
|
// Storing information about this relation
|
||||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(
|
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
|
||||||
propertyAuditingData.getName(), referencedEntityName, relMapper, insertable);
|
propertyAuditingData.getName(),
|
||||||
|
referencedEntityName,
|
||||||
|
relMapper,
|
||||||
|
insertable
|
||||||
|
);
|
||||||
|
|
||||||
// If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
|
// If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
|
||||||
// that is, when the one side owns the relation (and is a collection), and the many side is non insertable.
|
// that is, when the one side owns the relation (and is a collection), and the many side is non insertable.
|
||||||
// When that's the case and the user specified to store this relation without a middle table (using
|
// When that's the case and the user specified to store this relation without a middle table (using
|
||||||
// @AuditMappedBy), we have to make the property insertable for the purposes of Envers. In case of changes to
|
// @AuditMappedBy), we have to make the property insertable for the purposes of Envers. In case of changes to
|
||||||
// the entity that didn't involve the relation, it's value will then be stored properly. In case of changes
|
// the entity that didn't involve the relation, it's value will then be stored properly. In case of changes
|
||||||
// to the entity that did involve the relation, it's the responsibility of the collection side to store the
|
// to the entity that did involve the relation, it's the responsibility of the collection side to store the
|
||||||
// proper data.
|
// proper data.
|
||||||
boolean nonInsertableFake;
|
boolean nonInsertableFake;
|
||||||
if (!insertable && propertyAuditingData.isForceInsertable()) {
|
if ( !insertable && propertyAuditingData.isForceInsertable() ) {
|
||||||
nonInsertableFake = true;
|
nonInsertableFake = true;
|
||||||
insertable = true;
|
insertable = true;
|
||||||
} else {
|
}
|
||||||
nonInsertableFake = false;
|
else {
|
||||||
}
|
nonInsertableFake = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Adding an element to the mapping corresponding to the references entity id's
|
// Adding an element to the mapping corresponding to the references entity id's
|
||||||
Element properties = (Element) idMapping.getXmlRelationMapping().clone();
|
final Element properties = (Element) idMapping.getXmlRelationMapping().clone();
|
||||||
properties.addAttribute("name", propertyAuditingData.getName());
|
properties.addAttribute( "name", propertyAuditingData.getName() );
|
||||||
|
|
||||||
MetadataTools.prefixNamesInPropertyElement(properties, lastPropertyPrefix,
|
MetadataTools.prefixNamesInPropertyElement(
|
||||||
MetadataTools.getColumnNameIterator(value.getColumnIterator()), false, insertable);
|
properties,
|
||||||
|
lastPropertyPrefix,
|
||||||
|
MetadataTools.getColumnNameIterator( value.getColumnIterator() ),
|
||||||
|
false,
|
||||||
|
insertable
|
||||||
|
);
|
||||||
|
|
||||||
// Extracting related id properties from properties tag
|
// Extracting related id properties from properties tag
|
||||||
for (Object o : properties.content()) {
|
for ( Object o : properties.content() ) {
|
||||||
Element element = (Element) o;
|
final Element element = (Element) o;
|
||||||
element.setParent(null);
|
element.setParent( null );
|
||||||
parent.add(element);
|
parent.add( element );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding mapper for the id
|
// Adding mapper for the id
|
||||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
final PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||||
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName, nonInsertableFake));
|
mapper.addComposite(
|
||||||
}
|
propertyData,
|
||||||
|
new ToOneIdMapper( relMapper, propertyData, referencedEntityName, nonInsertableFake )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
void addOneToOneNotOwning(PropertyAuditingData propertyAuditingData, Value value,
|
void addOneToOneNotOwning(
|
||||||
CompositeMapperBuilder mapper, String entityName) {
|
PropertyAuditingData propertyAuditingData,
|
||||||
OneToOne propertyValue = (OneToOne) value;
|
Value value,
|
||||||
|
CompositeMapperBuilder mapper,
|
||||||
|
String entityName) {
|
||||||
|
final OneToOne propertyValue = (OneToOne) value;
|
||||||
|
final String owningReferencePropertyName = propertyValue.getReferencedPropertyName();
|
||||||
|
|
||||||
String owningReferencePropertyName = propertyValue.getReferencedPropertyName(); // mappedBy
|
final EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get( entityName );
|
||||||
|
if ( configuration == null ) {
|
||||||
|
throw new MappingException( "An audited relation to a non-audited entity " + entityName + "!" );
|
||||||
|
}
|
||||||
|
|
||||||
EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(entityName);
|
final IdMappingData ownedIdMapping = configuration.getIdMappingData();
|
||||||
if (configuration == null) {
|
|
||||||
throw new MappingException("An audited relation to a non-audited entity " + entityName + "!");
|
|
||||||
}
|
|
||||||
|
|
||||||
IdMappingData ownedIdMapping = configuration.getIdMappingData();
|
if ( ownedIdMapping == null ) {
|
||||||
|
throw new MappingException( "An audited relation to a non-audited entity " + entityName + "!" );
|
||||||
|
}
|
||||||
|
|
||||||
if (ownedIdMapping == null) {
|
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( owningReferencePropertyName );
|
||||||
throw new MappingException("An audited relation to a non-audited entity " + entityName + "!");
|
final String referencedEntityName = propertyValue.getReferencedEntityName();
|
||||||
}
|
|
||||||
|
|
||||||
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(owningReferencePropertyName);
|
// Generating the id mapper for the relation
|
||||||
String referencedEntityName = propertyValue.getReferencedEntityName();
|
final IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
|
||||||
|
|
||||||
// Generating the id mapper for the relation
|
// Storing information about this relation
|
||||||
IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneNotOwningRelation(
|
||||||
|
propertyAuditingData.getName(),
|
||||||
|
owningReferencePropertyName,
|
||||||
|
referencedEntityName,
|
||||||
|
ownedIdMapper
|
||||||
|
);
|
||||||
|
|
||||||
// Storing information about this relation
|
// Adding mapper for the id
|
||||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneNotOwningRelation(
|
final PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||||
propertyAuditingData.getName(), owningReferencePropertyName,
|
mapper.addComposite(
|
||||||
referencedEntityName, ownedIdMapper);
|
propertyData,
|
||||||
|
new OneToOneNotOwningMapper( entityName, referencedEntityName, owningReferencePropertyName, propertyData )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Adding mapper for the id
|
@SuppressWarnings({"unchecked"})
|
||||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
void addOneToOnePrimaryKeyJoinColumn(
|
||||||
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(entityName, referencedEntityName,
|
PropertyAuditingData propertyAuditingData,
|
||||||
owningReferencePropertyName, propertyData));
|
Value value,
|
||||||
}
|
CompositeMapperBuilder mapper,
|
||||||
|
String entityName,
|
||||||
|
boolean insertable) {
|
||||||
|
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
|
||||||
void addOneToOnePrimaryKeyJoinColumn(PropertyAuditingData propertyAuditingData, Value value,
|
entityName,
|
||||||
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
|
referencedEntityName,
|
||||||
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
propertyAuditingData,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(entityName, referencedEntityName,
|
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( propertyAuditingData.getName() );
|
||||||
propertyAuditingData, true);
|
|
||||||
|
|
||||||
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(propertyAuditingData.getName());
|
// Generating the id mapper for the relation
|
||||||
|
final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
|
||||||
|
|
||||||
// Generating the id mapper for the relation
|
// Storing information about this relation
|
||||||
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
|
||||||
|
propertyAuditingData.getName(),
|
||||||
|
referencedEntityName,
|
||||||
|
relMapper,
|
||||||
|
insertable
|
||||||
|
);
|
||||||
|
|
||||||
// Storing information about this relation
|
// Adding mapper for the id
|
||||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(propertyAuditingData.getName(),
|
final PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||||
referencedEntityName, relMapper, insertable);
|
mapper.addComposite(
|
||||||
|
propertyData,
|
||||||
// Adding mapper for the id
|
new OneToOnePrimaryKeyJoinColumnMapper( entityName, referencedEntityName, propertyData )
|
||||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
);
|
||||||
mapper.addComposite(propertyData, new OneToOnePrimaryKeyJoinColumnMapper(entityName, referencedEntityName, propertyData));
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ import org.hibernate.mapping.Property;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class to read versioning meta-data from annotations on a persistent class.
|
* A helper class to read versioning meta-data from annotations on a persistent class.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Sebastian Komander
|
* @author Sebastian Komander
|
||||||
*/
|
*/
|
||||||
|
@ -53,8 +55,9 @@ public final class AnnotationsMetadataReader {
|
||||||
*/
|
*/
|
||||||
private final ClassAuditingData auditData;
|
private final ClassAuditingData auditData;
|
||||||
|
|
||||||
public AnnotationsMetadataReader(GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
public AnnotationsMetadataReader(
|
||||||
PersistentClass pc) {
|
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
||||||
|
PersistentClass pc) {
|
||||||
this.globalCfg = globalCfg;
|
this.globalCfg = globalCfg;
|
||||||
this.reflectionManager = reflectionManager;
|
this.reflectionManager = reflectionManager;
|
||||||
this.pc = pc;
|
this.pc = pc;
|
||||||
|
@ -63,71 +66,95 @@ public final class AnnotationsMetadataReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModificationStore getDefaultAudited(XClass clazz) {
|
private ModificationStore getDefaultAudited(XClass clazz) {
|
||||||
Audited defaultAudited = clazz.getAnnotation(Audited.class);
|
final Audited defaultAudited = clazz.getAnnotation( Audited.class );
|
||||||
|
|
||||||
if (defaultAudited != null) {
|
if ( defaultAudited != null ) {
|
||||||
return defaultAudited.modStore();
|
return defaultAudited.modStore();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAuditTable(XClass clazz) {
|
private void addAuditTable(XClass clazz) {
|
||||||
AuditTable auditTable = clazz.getAnnotation(AuditTable.class);
|
final AuditTable auditTable = clazz.getAnnotation( AuditTable.class );
|
||||||
if (auditTable != null) {
|
if ( auditTable != null ) {
|
||||||
auditData.setAuditTable(auditTable);
|
auditData.setAuditTable( auditTable );
|
||||||
} else {
|
}
|
||||||
auditData.setAuditTable(getDefaultAuditTable());
|
else {
|
||||||
|
auditData.setAuditTable( getDefaultAuditTable() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAuditSecondaryTables(XClass clazz) {
|
private void addAuditSecondaryTables(XClass clazz) {
|
||||||
// Getting information on secondary tables
|
// Getting information on secondary tables
|
||||||
SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation(SecondaryAuditTable.class);
|
final SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation( SecondaryAuditTable.class );
|
||||||
if (secondaryVersionsTable1 != null) {
|
if ( secondaryVersionsTable1 != null ) {
|
||||||
auditData.getSecondaryTableDictionary().put(secondaryVersionsTable1.secondaryTableName(),
|
auditData.getSecondaryTableDictionary().put(
|
||||||
secondaryVersionsTable1.secondaryAuditTableName());
|
secondaryVersionsTable1.secondaryTableName(),
|
||||||
|
secondaryVersionsTable1.secondaryAuditTableName()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation(SecondaryAuditTables.class);
|
final SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation( SecondaryAuditTables.class );
|
||||||
if (secondaryAuditTables != null) {
|
if ( secondaryAuditTables != null ) {
|
||||||
for (SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value()) {
|
for ( SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value() ) {
|
||||||
auditData.getSecondaryTableDictionary().put(secondaryAuditTable2.secondaryTableName(),
|
auditData.getSecondaryTableDictionary().put(
|
||||||
secondaryAuditTable2.secondaryAuditTableName());
|
secondaryAuditTable2.secondaryTableName(),
|
||||||
|
secondaryAuditTable2.secondaryAuditTableName()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassAuditingData getAuditData() {
|
public ClassAuditingData getAuditData() {
|
||||||
if (pc.getClassName() == null) {
|
if ( pc.getClassName() == null ) {
|
||||||
return auditData;
|
return auditData;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
XClass xclass = reflectionManager.classForName(pc.getClassName(), this.getClass());
|
final XClass xclass = reflectionManager.classForName( pc.getClassName(), this.getClass() );
|
||||||
|
|
||||||
ModificationStore defaultStore = getDefaultAudited(xclass);
|
final ModificationStore defaultStore = getDefaultAudited( xclass );
|
||||||
if (defaultStore != null) {
|
if ( defaultStore != null ) {
|
||||||
auditData.setDefaultAudited(true);
|
auditData.setDefaultAudited( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
new AuditedPropertiesReader(defaultStore, new PersistentClassPropertiesSource(xclass), auditData,
|
new AuditedPropertiesReader(
|
||||||
globalCfg, reflectionManager, "").read();
|
defaultStore,
|
||||||
|
new PersistentClassPropertiesSource( xclass ),
|
||||||
|
auditData,
|
||||||
|
globalCfg,
|
||||||
|
reflectionManager,
|
||||||
|
""
|
||||||
|
).read();
|
||||||
|
|
||||||
addAuditTable(xclass);
|
addAuditTable( xclass );
|
||||||
addAuditSecondaryTables(xclass);
|
addAuditSecondaryTables( xclass );
|
||||||
} catch (ClassNotFoundException e) {
|
}
|
||||||
throw new MappingException(e);
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new MappingException( e );
|
||||||
}
|
}
|
||||||
|
|
||||||
return auditData;
|
return auditData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuditTable defaultAuditTable = new AuditTable() {
|
private AuditTable defaultAuditTable = new AuditTable() {
|
||||||
public String value() { return ""; }
|
public String value() {
|
||||||
public String schema() { return ""; }
|
return "";
|
||||||
public String catalog() { return ""; }
|
}
|
||||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
|
||||||
|
public String schema() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String catalog() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends Annotation> annotationType() {
|
||||||
|
return this.getClass();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private AuditTable getDefaultAuditTable() {
|
private AuditTable getDefaultAuditTable() {
|
||||||
|
@ -137,11 +164,21 @@ public final class AnnotationsMetadataReader {
|
||||||
private class PersistentClassPropertiesSource implements PersistentPropertiesSource {
|
private class PersistentClassPropertiesSource implements PersistentPropertiesSource {
|
||||||
private final XClass xclass;
|
private final XClass xclass;
|
||||||
|
|
||||||
private PersistentClassPropertiesSource(XClass xclass) { this.xclass = xclass; }
|
private PersistentClassPropertiesSource(XClass xclass) {
|
||||||
|
this.xclass = xclass;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public Iterator<Property> getPropertyIterator() { return pc.getPropertyIterator(); }
|
public Iterator<Property> getPropertyIterator() {
|
||||||
public Property getProperty(String propertyName) { return pc.getProperty(propertyName); }
|
return pc.getPropertyIterator();
|
||||||
public XClass getXClass() { return xclass; }
|
}
|
||||||
|
|
||||||
|
public Property getProperty(String propertyName) {
|
||||||
|
return pc.getProperty( propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public XClass getXClass() {
|
||||||
|
return xclass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementations hold other audited properties.
|
* Implementations hold other audited properties.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Hern&aacut;n Chanfreau
|
* @author Hern&aacut;n Chanfreau
|
||||||
*/
|
*/
|
||||||
public interface AuditedPropertiesHolder {
|
public interface AuditedPropertiesHolder {
|
||||||
/**
|
/**
|
||||||
* Add an audited property.
|
* Add an audited property.
|
||||||
|
*
|
||||||
* @param propertyName Name of the audited property.
|
* @param propertyName Name of the audited property.
|
||||||
* @param auditingData Data for the audited property.
|
* @param auditingData Data for the audited property.
|
||||||
*/
|
*/
|
||||||
|
@ -16,19 +41,20 @@ public interface AuditedPropertiesHolder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param propertyName Name of a property.
|
* @param propertyName Name of a property.
|
||||||
|
*
|
||||||
* @return Auditing data for the property.
|
* @return Auditing data for the property.
|
||||||
*/
|
*/
|
||||||
PropertyAuditingData getPropertyAuditingData(String propertyName);
|
PropertyAuditingData getPropertyAuditingData(String propertyName);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the holder contains any audited property
|
* @return true if the holder contains any audited property
|
||||||
*/
|
*/
|
||||||
boolean isEmpty();
|
boolean isEmpty();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the holder contains the given audited property
|
* @return true if the holder contains the given audited property
|
||||||
*/
|
*/
|
||||||
boolean contains(String propertyName);
|
boolean contains(String propertyName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.MapKey;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Version;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -7,10 +34,6 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.persistence.JoinColumn;
|
|
||||||
import javax.persistence.MapKey;
|
|
||||||
import javax.persistence.OneToMany;
|
|
||||||
import javax.persistence.Version;
|
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||||
|
@ -65,12 +88,13 @@ public class AuditedPropertiesReader {
|
||||||
private final Set<XClass> overriddenAuditedClasses;
|
private final Set<XClass> overriddenAuditedClasses;
|
||||||
private final Set<XClass> overriddenNotAuditedClasses;
|
private final Set<XClass> overriddenNotAuditedClasses;
|
||||||
|
|
||||||
public AuditedPropertiesReader(ModificationStore defaultStore,
|
public AuditedPropertiesReader(
|
||||||
PersistentPropertiesSource persistentPropertiesSource,
|
ModificationStore defaultStore,
|
||||||
AuditedPropertiesHolder auditedPropertiesHolder,
|
PersistentPropertiesSource persistentPropertiesSource,
|
||||||
GlobalConfiguration globalCfg,
|
AuditedPropertiesHolder auditedPropertiesHolder,
|
||||||
ReflectionManager reflectionManager,
|
GlobalConfiguration globalCfg,
|
||||||
String propertyNamePrefix) {
|
ReflectionManager reflectionManager,
|
||||||
|
String propertyNamePrefix) {
|
||||||
this.defaultStore = defaultStore;
|
this.defaultStore = defaultStore;
|
||||||
this.persistentPropertiesSource = persistentPropertiesSource;
|
this.persistentPropertiesSource = persistentPropertiesSource;
|
||||||
this.auditedPropertiesHolder = auditedPropertiesHolder;
|
this.auditedPropertiesHolder = auditedPropertiesHolder;
|
||||||
|
@ -93,245 +117,300 @@ public class AuditedPropertiesReader {
|
||||||
// First reading the access types for the persistent properties.
|
// First reading the access types for the persistent properties.
|
||||||
readPersistentPropertiesAccess();
|
readPersistentPropertiesAccess();
|
||||||
|
|
||||||
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
|
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
|
||||||
// of currently mapped entity or itself.
|
// of currently mapped entity or itself.
|
||||||
XClass clazz = persistentPropertiesSource.getXClass();
|
final XClass clazz = persistentPropertiesSource.getXClass();
|
||||||
readAuditOverrides(clazz);
|
readAuditOverrides( clazz );
|
||||||
|
|
||||||
// Adding all properties from the given class.
|
// Adding all properties from the given class.
|
||||||
addPropertiesFromClass(clazz);
|
addPropertiesFromClass( clazz );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
|
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
|
||||||
* using {@link AuditOverride} annotation.
|
* using {@link AuditOverride} annotation.
|
||||||
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
|
*
|
||||||
*/
|
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
|
||||||
private void readAuditOverrides(XClass clazz) {
|
*/
|
||||||
/* TODO: Code to remove with @Audited.auditParents - start. */
|
private void readAuditOverrides(XClass clazz) {
|
||||||
Audited allClassAudited = clazz.getAnnotation(Audited.class);
|
/* TODO: Code to remove with @Audited.auditParents - start. */
|
||||||
if (allClassAudited != null && allClassAudited.auditParents().length > 0) {
|
final Audited allClassAudited = clazz.getAnnotation( Audited.class );
|
||||||
for (Class c : allClassAudited.auditParents()) {
|
if ( allClassAudited != null && allClassAudited.auditParents().length > 0 ) {
|
||||||
XClass parentClass = reflectionManager.toXClass(c);
|
for ( Class c : allClassAudited.auditParents() ) {
|
||||||
checkSuperclass(clazz, parentClass);
|
final XClass parentClass = reflectionManager.toXClass( c );
|
||||||
if (!overriddenNotAuditedClasses.contains(parentClass)) {
|
checkSuperclass( clazz, parentClass );
|
||||||
// If the class has not been marked as not audited by the subclass.
|
if ( !overriddenNotAuditedClasses.contains( parentClass ) ) {
|
||||||
overriddenAuditedClasses.add(parentClass);
|
// If the class has not been marked as not audited by the subclass.
|
||||||
}
|
overriddenAuditedClasses.add( parentClass );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* TODO: Code to remove with @Audited.auditParents - finish. */
|
/* TODO: Code to remove with @Audited.auditParents - finish. */
|
||||||
List<AuditOverride> auditOverrides = computeAuditOverrides(clazz);
|
final List<AuditOverride> auditOverrides = computeAuditOverrides( clazz );
|
||||||
for (AuditOverride auditOverride : auditOverrides) {
|
for ( AuditOverride auditOverride : auditOverrides ) {
|
||||||
if (auditOverride.forClass() != void.class) {
|
if ( auditOverride.forClass() != void.class ) {
|
||||||
XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass());
|
final XClass overrideClass = reflectionManager.toXClass( auditOverride.forClass() );
|
||||||
checkSuperclass(clazz, overrideClass);
|
checkSuperclass( clazz, overrideClass );
|
||||||
String propertyName = auditOverride.name();
|
final String propertyName = auditOverride.name();
|
||||||
if (!StringTools.isEmpty(propertyName)) {
|
if ( !StringTools.isEmpty( propertyName ) ) {
|
||||||
// Override @Audited annotation on property level.
|
// Override @Audited annotation on property level.
|
||||||
XProperty property = getProperty(overrideClass, propertyName);
|
final XProperty property = getProperty( overrideClass, propertyName );
|
||||||
if (auditOverride.isAudited()) {
|
if ( auditOverride.isAudited() ) {
|
||||||
if (!overriddenNotAuditedProperties.contains(property)) {
|
if ( !overriddenNotAuditedProperties.contains( property ) ) {
|
||||||
// If the property has not been marked as not audited by the subclass.
|
// If the property has not been marked as not audited by the subclass.
|
||||||
overriddenAuditedProperties.add(property);
|
overriddenAuditedProperties.add( property );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (!overriddenAuditedProperties.contains(property)) {
|
else {
|
||||||
// If the property has not been marked as audited by the subclass.
|
if ( !overriddenAuditedProperties.contains( property ) ) {
|
||||||
overriddenNotAuditedProperties.add(property);
|
// If the property has not been marked as audited by the subclass.
|
||||||
}
|
overriddenNotAuditedProperties.add( property );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// Override @Audited annotation on class level.
|
}
|
||||||
if (auditOverride.isAudited()) {
|
else {
|
||||||
if (!overriddenNotAuditedClasses.contains(overrideClass)) {
|
// Override @Audited annotation on class level.
|
||||||
// If the class has not been marked as not audited by the subclass.
|
if ( auditOverride.isAudited() ) {
|
||||||
overriddenAuditedClasses.add(overrideClass);
|
if ( !overriddenNotAuditedClasses.contains( overrideClass ) ) {
|
||||||
}
|
// If the class has not been marked as not audited by the subclass.
|
||||||
} else {
|
overriddenAuditedClasses.add( overrideClass );
|
||||||
if (!overriddenAuditedClasses.contains(overrideClass)) {
|
}
|
||||||
// If the class has not been marked as audited by the subclass.
|
}
|
||||||
overriddenNotAuditedClasses.add(overrideClass);
|
else {
|
||||||
}
|
if ( !overriddenAuditedClasses.contains( overrideClass ) ) {
|
||||||
}
|
// If the class has not been marked as audited by the subclass.
|
||||||
}
|
overriddenNotAuditedClasses.add( overrideClass );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XClass superclass = clazz.getSuperclass();
|
}
|
||||||
if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) {
|
}
|
||||||
readAuditOverrides(superclass);
|
}
|
||||||
}
|
final XClass superclass = clazz.getSuperclass();
|
||||||
}
|
if ( !clazz.isInterface() && !Object.class.getName().equals( superclass.getName() ) ) {
|
||||||
|
readAuditOverrides( superclass );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clazz Source class.
|
* @param clazz Source class.
|
||||||
* @return List of @AuditOverride annotations applied at class level.
|
*
|
||||||
*/
|
* @return List of @AuditOverride annotations applied at class level.
|
||||||
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
|
*/
|
||||||
AuditOverrides auditOverrides = clazz.getAnnotation(AuditOverrides.class);
|
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
|
||||||
AuditOverride auditOverride = clazz.getAnnotation(AuditOverride.class);
|
final AuditOverrides auditOverrides = clazz.getAnnotation( AuditOverrides.class );
|
||||||
if (auditOverrides == null && auditOverride != null) {
|
final AuditOverride auditOverride = clazz.getAnnotation( AuditOverride.class );
|
||||||
return Arrays.asList(auditOverride);
|
if ( auditOverrides == null && auditOverride != null ) {
|
||||||
} else if (auditOverrides != null && auditOverride == null) {
|
return Arrays.asList( auditOverride );
|
||||||
return Arrays.asList(auditOverrides.value());
|
}
|
||||||
} else if (auditOverrides != null && auditOverride != null) {
|
else if ( auditOverrides != null && auditOverride == null ) {
|
||||||
throw new MappingException("@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
|
return Arrays.asList( auditOverrides.value() );
|
||||||
"Please revise Envers annotations applied to class " + clazz.getName() + ".");
|
}
|
||||||
}
|
else if ( auditOverrides != null && auditOverride != null ) {
|
||||||
return Collections.EMPTY_LIST;
|
throw new MappingException(
|
||||||
}
|
"@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
|
||||||
|
"Please revise Envers annotations applied to class " + clazz.getName() + "."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
|
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
|
||||||
* @param child Subclass.
|
*
|
||||||
* @param parent Superclass.
|
* @param child Subclass.
|
||||||
*/
|
* @param parent Superclass.
|
||||||
private void checkSuperclass(XClass child, XClass parent) {
|
*/
|
||||||
if (!parent.isAssignableFrom(child)) {
|
private void checkSuperclass(XClass child, XClass parent) {
|
||||||
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
|
if ( !parent.isAssignableFrom( child ) ) {
|
||||||
"Please revise Envers annotations applied to " + child.getName() + " type.");
|
throw new MappingException(
|
||||||
}
|
"Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
|
||||||
}
|
"Please revise Envers annotations applied to " + child.getName() + " type."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
|
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
|
||||||
* @param clazz Class.
|
*
|
||||||
* @param propertyName Property name.
|
* @param clazz Class.
|
||||||
* @return Property object.
|
* @param propertyName Property name.
|
||||||
*/
|
*
|
||||||
private XProperty getProperty(XClass clazz, String propertyName) {
|
* @return Property object.
|
||||||
XProperty property = ReflectionTools.getProperty(clazz, propertyName);
|
*/
|
||||||
if (property == null) {
|
private XProperty getProperty(XClass clazz, String propertyName) {
|
||||||
throw new MappingException("Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
|
final XProperty property = ReflectionTools.getProperty( clazz, propertyName );
|
||||||
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + ".");
|
if ( property == null ) {
|
||||||
}
|
throw new MappingException(
|
||||||
return property;
|
"Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
|
||||||
}
|
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + "."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
private void readPersistentPropertiesAccess() {
|
private void readPersistentPropertiesAccess() {
|
||||||
Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
|
final Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
|
||||||
while (propertyIter.hasNext()) {
|
while ( propertyIter.hasNext() ) {
|
||||||
Property property = propertyIter.next();
|
final Property property = propertyIter.next();
|
||||||
addPersistentProperty(property);
|
addPersistentProperty( property );
|
||||||
if ("embedded".equals(property.getPropertyAccessorName()) && property.getName().equals(property.getNodeName())) {
|
if ( "embedded".equals( property.getPropertyAccessorName() ) && property.getName()
|
||||||
|
.equals( property.getNodeName() ) ) {
|
||||||
// If property name equals node name and embedded accessor type is used, processing component
|
// If property name equals node name and embedded accessor type is used, processing component
|
||||||
// has been defined with <properties> tag. See HHH-6636 JIRA issue.
|
// has been defined with <properties> tag. See HHH-6636 JIRA issue.
|
||||||
createPropertiesGroupMapping(property);
|
createPropertiesGroupMapping( property );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPersistentProperty(Property property) {
|
private void addPersistentProperty(Property property) {
|
||||||
if ("field".equals(property.getPropertyAccessorName())) {
|
if ( "field".equals( property.getPropertyAccessorName() ) ) {
|
||||||
fieldAccessedPersistentProperties.add(property.getName());
|
fieldAccessedPersistentProperties.add( property.getName() );
|
||||||
} else {
|
}
|
||||||
propertyAccessedPersistentProperties.add(property.getName());
|
else {
|
||||||
}
|
propertyAccessedPersistentProperties.add( property.getName() );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void createPropertiesGroupMapping(Property property) {
|
@SuppressWarnings("unchecked")
|
||||||
Component component = (Component) property.getValue();
|
private void createPropertiesGroupMapping(Property property) {
|
||||||
Iterator<Property> componentProperties = component.getPropertyIterator();
|
final Component component = (Component) property.getValue();
|
||||||
while (componentProperties.hasNext()) {
|
final Iterator<Property> componentProperties = component.getPropertyIterator();
|
||||||
Property componentProperty = componentProperties.next();
|
while ( componentProperties.hasNext() ) {
|
||||||
propertiesGroupMapping.put(componentProperty.getName(), component.getNodeName());
|
final Property componentProperty = componentProperties.next();
|
||||||
}
|
propertiesGroupMapping.put( componentProperty.getName(), component.getNodeName() );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clazz Class which properties are currently being added.
|
* @param clazz Class which properties are currently being added.
|
||||||
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
|
*
|
||||||
* checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection.
|
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
|
||||||
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
|
* checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection.
|
||||||
* {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses}
|
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
|
||||||
* collection, the result is also {@code null}.
|
* {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses}
|
||||||
*/
|
* collection, the result is also {@code null}.
|
||||||
private Audited computeAuditConfiguration(XClass clazz) {
|
*/
|
||||||
Audited allClassAudited = clazz.getAnnotation(Audited.class);
|
private Audited computeAuditConfiguration(XClass clazz) {
|
||||||
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
|
Audited allClassAudited = clazz.getAnnotation( Audited.class );
|
||||||
// forced by any of its child entities configuration (@AuditedOverride.forClass).
|
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
|
||||||
if (allClassAudited == null && overriddenAuditedClasses.contains(clazz)) {
|
// forced by any of its child entities configuration (@AuditedOverride.forClass).
|
||||||
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
|
if ( allClassAudited == null && overriddenAuditedClasses.contains( clazz ) ) {
|
||||||
// currently mapped entity.
|
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
|
||||||
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation(Audited.class);
|
// currently mapped entity.
|
||||||
if (allClassAudited == null) {
|
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation( Audited.class );
|
||||||
// If parent class declares @Audited on the field/property level.
|
if ( allClassAudited == null ) {
|
||||||
allClassAudited = DEFAULT_AUDITED;
|
// If parent class declares @Audited on the field/property level.
|
||||||
}
|
allClassAudited = DEFAULT_AUDITED;
|
||||||
} else if (allClassAudited != null && overriddenNotAuditedClasses.contains(clazz)) {
|
}
|
||||||
return null;
|
}
|
||||||
}
|
else if ( allClassAudited != null && overriddenNotAuditedClasses.contains( clazz ) ) {
|
||||||
return allClassAudited;
|
return null;
|
||||||
}
|
}
|
||||||
|
return allClassAudited;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively adds all audited properties of entity class and its superclasses.
|
* Recursively adds all audited properties of entity class and its superclasses.
|
||||||
* @param clazz Currently processed class.
|
*
|
||||||
*/
|
* @param clazz Currently processed class.
|
||||||
private void addPropertiesFromClass(XClass clazz) {
|
*/
|
||||||
Audited allClassAudited = computeAuditConfiguration(clazz);
|
private void addPropertiesFromClass(XClass clazz) {
|
||||||
|
final Audited allClassAudited = computeAuditConfiguration( clazz );
|
||||||
|
|
||||||
//look in the class
|
//look in the class
|
||||||
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited);
|
addFromProperties(
|
||||||
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited);
|
clazz.getDeclaredProperties( "field" ),
|
||||||
|
"field",
|
||||||
if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) {
|
fieldAccessedPersistentProperties,
|
||||||
XClass superclazz = clazz.getSuperclass();
|
allClassAudited
|
||||||
if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) {
|
);
|
||||||
addPropertiesFromClass(superclazz);
|
addFromProperties(
|
||||||
|
clazz.getDeclaredProperties( "property" ),
|
||||||
|
"property",
|
||||||
|
propertyAccessedPersistentProperties,
|
||||||
|
allClassAudited
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( allClassAudited != null || !auditedPropertiesHolder.isEmpty() ) {
|
||||||
|
final XClass superclazz = clazz.getSuperclass();
|
||||||
|
if ( !clazz.isInterface() && !"java.lang.Object".equals( superclazz.getName() ) ) {
|
||||||
|
addPropertiesFromClass( superclazz );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFromProperties(Iterable<XProperty> properties, String accessType, Set<String> persistentProperties, Audited allClassAudited) {
|
private void addFromProperties(
|
||||||
for (XProperty property : properties) {
|
Iterable<XProperty> properties,
|
||||||
|
String accessType,
|
||||||
|
Set<String> persistentProperties,
|
||||||
|
Audited allClassAudited) {
|
||||||
|
for ( XProperty property : properties ) {
|
||||||
// If this is not a persistent property, with the same access type as currently checked,
|
// If this is not a persistent property, with the same access type as currently checked,
|
||||||
// it's not audited as well.
|
// it's not audited as well.
|
||||||
// If the property was already defined by the subclass, is ignored by superclasses
|
// If the property was already defined by the subclass, is ignored by superclasses
|
||||||
if ((persistentProperties.contains(property.getName()) && (!auditedPropertiesHolder
|
if ( persistentProperties.contains( property.getName() )
|
||||||
.contains(property.getName())))) {
|
&& !auditedPropertiesHolder.contains( property.getName() ) ) {
|
||||||
Value propertyValue = persistentPropertiesSource.getProperty(property.getName()).getValue();
|
final Value propertyValue = persistentPropertiesSource.getProperty( property.getName() ).getValue();
|
||||||
if (propertyValue instanceof Component) {
|
if ( propertyValue instanceof Component ) {
|
||||||
this.addFromComponentProperty(property, accessType, (Component)propertyValue, allClassAudited);
|
this.addFromComponentProperty( property, accessType, (Component) propertyValue, allClassAudited );
|
||||||
} else {
|
|
||||||
this.addFromNotComponentProperty(property, accessType, allClassAudited);
|
|
||||||
}
|
}
|
||||||
} else if (propertiesGroupMapping.containsKey(property.getName())) {
|
else {
|
||||||
|
this.addFromNotComponentProperty( property, accessType, allClassAudited );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( propertiesGroupMapping.containsKey( property.getName() ) ) {
|
||||||
// Retrieve embedded component name based on class field.
|
// Retrieve embedded component name based on class field.
|
||||||
final String embeddedName = propertiesGroupMapping.get(property.getName());
|
final String embeddedName = propertiesGroupMapping.get( property.getName() );
|
||||||
if (!auditedPropertiesHolder.contains(embeddedName)) {
|
if ( !auditedPropertiesHolder.contains( embeddedName ) ) {
|
||||||
// Manage properties mapped within <properties> tag.
|
// Manage properties mapped within <properties> tag.
|
||||||
Value propertyValue = persistentPropertiesSource.getProperty(embeddedName).getValue();
|
final Value propertyValue = persistentPropertiesSource.getProperty( embeddedName ).getValue();
|
||||||
this.addFromPropertiesGroup(embeddedName, property, accessType, (Component)propertyValue, allClassAudited);
|
this.addFromPropertiesGroup(
|
||||||
|
embeddedName,
|
||||||
|
property,
|
||||||
|
accessType,
|
||||||
|
(Component) propertyValue,
|
||||||
|
allClassAudited
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFromPropertiesGroup(String embeddedName, XProperty property, String accessType, Component propertyValue,
|
private void addFromPropertiesGroup(
|
||||||
Audited allClassAudited) {
|
String embeddedName,
|
||||||
ComponentAuditingData componentData = new ComponentAuditingData();
|
XProperty property,
|
||||||
boolean isAudited = fillPropertyData(property, componentData, accessType, allClassAudited);
|
String accessType,
|
||||||
if (isAudited) {
|
Component propertyValue,
|
||||||
|
Audited allClassAudited) {
|
||||||
|
final ComponentAuditingData componentData = new ComponentAuditingData();
|
||||||
|
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
|
||||||
|
if ( isAudited ) {
|
||||||
// EntityPersister.getPropertyNames() returns name of embedded component instead of class field.
|
// EntityPersister.getPropertyNames() returns name of embedded component instead of class field.
|
||||||
componentData.setName(embeddedName);
|
componentData.setName( embeddedName );
|
||||||
// Marking component properties as placed directly in class (not inside another component).
|
// Marking component properties as placed directly in class (not inside another component).
|
||||||
componentData.setBeanName(null);
|
componentData.setBeanName( null );
|
||||||
|
|
||||||
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( reflectionManager, propertyValue );
|
final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
||||||
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
|
reflectionManager,
|
||||||
|
propertyValue
|
||||||
|
);
|
||||||
|
final AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
|
||||||
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
|
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
|
||||||
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName)
|
propertyNamePrefix + MappingTools.createComponentPrefix( embeddedName )
|
||||||
);
|
);
|
||||||
audPropReader.read();
|
audPropReader.read();
|
||||||
|
|
||||||
auditedPropertiesHolder.addPropertyAuditingData(embeddedName, componentData);
|
auditedPropertiesHolder.addPropertyAuditingData( embeddedName, componentData );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFromComponentProperty(XProperty property, String accessType, Component propertyValue, Audited allClassAudited) {
|
private void addFromComponentProperty(
|
||||||
ComponentAuditingData componentData = new ComponentAuditingData();
|
XProperty property,
|
||||||
boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
|
String accessType,
|
||||||
|
Component propertyValue,
|
||||||
|
Audited allClassAudited) {
|
||||||
|
final ComponentAuditingData componentData = new ComponentAuditingData();
|
||||||
|
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
|
||||||
|
|
||||||
if ( propertyValue.isDynamic() ) {
|
if ( propertyValue.isDynamic() ) {
|
||||||
if ( isAudited ) {
|
if ( isAudited ) {
|
||||||
|
@ -343,12 +422,16 @@ public class AuditedPropertiesReader {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
||||||
reflectionManager, propertyValue
|
reflectionManager, propertyValue
|
||||||
);
|
);
|
||||||
|
|
||||||
ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
|
final ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
|
||||||
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
|
ModificationStore.FULL,
|
||||||
|
componentPropertiesSource,
|
||||||
|
componentData,
|
||||||
|
globalCfg,
|
||||||
|
reflectionManager,
|
||||||
propertyNamePrefix + MappingTools.createComponentPrefix( property.getName() )
|
propertyNamePrefix + MappingTools.createComponentPrefix( property.getName() )
|
||||||
);
|
);
|
||||||
audPropReader.read();
|
audPropReader.read();
|
||||||
|
@ -359,85 +442,102 @@ public class AuditedPropertiesReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited){
|
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited) {
|
||||||
PropertyAuditingData propertyData = new PropertyAuditingData();
|
final PropertyAuditingData propertyData = new PropertyAuditingData();
|
||||||
boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited);
|
final boolean isAudited = fillPropertyData( property, propertyData, accessType, allClassAudited );
|
||||||
|
|
||||||
if (isAudited) {
|
if ( isAudited ) {
|
||||||
// Now we know that the property is audited
|
// Now we know that the property is audited
|
||||||
auditedPropertiesHolder.addPropertyAuditingData(property.getName(), propertyData);
|
auditedPropertiesHolder.addPropertyAuditingData( property.getName(), propertyData );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a property is audited and if yes, fills all of its data.
|
* Checks if a property is audited and if yes, fills all of its data.
|
||||||
|
*
|
||||||
* @param property Property to check.
|
* @param property Property to check.
|
||||||
* @param propertyData Property data, on which to set this property's modification store.
|
* @param propertyData Property data, on which to set this property's modification store.
|
||||||
* @param accessType Access type for the property.
|
* @param accessType Access type for the property.
|
||||||
|
*
|
||||||
* @return False if this property is not audited.
|
* @return False if this property is not audited.
|
||||||
*/
|
*/
|
||||||
private boolean fillPropertyData(XProperty property, PropertyAuditingData propertyData,
|
private boolean fillPropertyData(
|
||||||
String accessType, Audited allClassAudited) {
|
XProperty property,
|
||||||
|
PropertyAuditingData propertyData,
|
||||||
|
String accessType,
|
||||||
|
Audited allClassAudited) {
|
||||||
|
|
||||||
// check if a property is declared as not audited to exclude it
|
// check if a property is declared as not audited to exclude it
|
||||||
// useful if a class is audited but some properties should be excluded
|
// useful if a class is audited but some properties should be excluded
|
||||||
NotAudited unVer = property.getAnnotation(NotAudited.class);
|
final NotAudited unVer = property.getAnnotation( NotAudited.class );
|
||||||
if ((unVer != null && !overriddenAuditedProperties.contains(property)) || overriddenNotAuditedProperties.contains(property)) {
|
if ( (unVer != null
|
||||||
|
&& !overriddenAuditedProperties.contains( property ))
|
||||||
|
|| overriddenNotAuditedProperties.contains( property ) ) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// if the optimistic locking field has to be unversioned and the current property
|
// if the optimistic locking field has to be unversioned and the current property
|
||||||
// is the optimistic locking field, don't audit it
|
// is the optimistic locking field, don't audit it
|
||||||
if (globalCfg.isDoNotAuditOptimisticLockingField()) {
|
if ( globalCfg.isDoNotAuditOptimisticLockingField() ) {
|
||||||
Version jpaVer = property.getAnnotation(Version.class);
|
final Version jpaVer = property.getAnnotation( Version.class );
|
||||||
if (jpaVer != null) {
|
if ( jpaVer != null ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!this.checkAudited(property, propertyData, allClassAudited)){
|
if ( !this.checkAudited( property, propertyData, allClassAudited ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String propertyName = propertyNamePrefix + property.getName();
|
final String propertyName = propertyNamePrefix + property.getName();
|
||||||
propertyData.setName(propertyName);
|
propertyData.setName( propertyName );
|
||||||
propertyData.setModifiedFlagName(
|
propertyData.setModifiedFlagName(
|
||||||
MetadataTools.getModifiedFlagPropertyName(
|
MetadataTools.getModifiedFlagPropertyName(
|
||||||
propertyName,
|
propertyName,
|
||||||
globalCfg.getModifiedFlagSuffix()));
|
globalCfg.getModifiedFlagSuffix()
|
||||||
propertyData.setBeanName(property.getName());
|
)
|
||||||
propertyData.setAccessType(accessType);
|
);
|
||||||
|
propertyData.setBeanName( property.getName() );
|
||||||
|
propertyData.setAccessType( accessType );
|
||||||
|
|
||||||
addPropertyJoinTables(property, propertyData);
|
addPropertyJoinTables( property, propertyData );
|
||||||
addPropertyAuditingOverrides(property, propertyData);
|
addPropertyAuditingOverrides( property, propertyData );
|
||||||
if (!processPropertyAuditingOverrides(property, propertyData)) {
|
if ( !processPropertyAuditingOverrides( property, propertyData ) ) {
|
||||||
return false; // not audited due to AuditOverride annotation
|
// not audited due to AuditOverride annotation
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
addPropertyMapKey(property, propertyData);
|
addPropertyMapKey( property, propertyData );
|
||||||
setPropertyAuditMappedBy(property, propertyData);
|
setPropertyAuditMappedBy( property, propertyData );
|
||||||
setPropertyRelationMappedBy(property, propertyData);
|
setPropertyRelationMappedBy( property, propertyData );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected boolean checkAudited(XProperty property,
|
protected boolean checkAudited(
|
||||||
|
XProperty property,
|
||||||
PropertyAuditingData propertyData, Audited allClassAudited) {
|
PropertyAuditingData propertyData, Audited allClassAudited) {
|
||||||
// Checking if this property is explicitly audited or if all properties are.
|
// Checking if this property is explicitly audited or if all properties are.
|
||||||
Audited aud = (property.isAnnotationPresent(Audited.class)) ? (property.getAnnotation(Audited.class)) : allClassAudited;
|
Audited aud = (property.isAnnotationPresent( Audited.class ))
|
||||||
if (aud == null && overriddenAuditedProperties.contains(property) && !overriddenNotAuditedProperties.contains(property)) {
|
? property.getAnnotation( Audited.class )
|
||||||
|
: allClassAudited;
|
||||||
|
if ( aud == null
|
||||||
|
&& overriddenAuditedProperties.contains( property )
|
||||||
|
&& !overriddenNotAuditedProperties.contains( property ) ) {
|
||||||
// Assigning @Audited defaults. If anyone needs to customize those values in the future,
|
// Assigning @Audited defaults. If anyone needs to customize those values in the future,
|
||||||
// appropriate fields shall be added to @AuditOverride annotation.
|
// appropriate fields shall be added to @AuditOverride annotation.
|
||||||
aud = DEFAULT_AUDITED;
|
aud = DEFAULT_AUDITED;
|
||||||
}
|
}
|
||||||
if (aud != null) {
|
if ( aud != null ) {
|
||||||
propertyData.setStore(aud.modStore());
|
propertyData.setStore( aud.modStore() );
|
||||||
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
|
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||||
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
|
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,121 +547,172 @@ public class AuditedPropertiesReader {
|
||||||
globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag();
|
globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||||
OneToMany oneToMany = property.getAnnotation(OneToMany.class);
|
final OneToMany oneToMany = property.getAnnotation( OneToMany.class );
|
||||||
if (oneToMany != null && !"".equals(oneToMany.mappedBy())) {
|
if ( oneToMany != null && !"".equals( oneToMany.mappedBy() ) ) {
|
||||||
propertyData.setRelationMappedBy(oneToMany.mappedBy());
|
propertyData.setRelationMappedBy( oneToMany.mappedBy() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||||
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
|
final AuditMappedBy auditMappedBy = property.getAnnotation( AuditMappedBy.class );
|
||||||
if (auditMappedBy != null) {
|
if ( auditMappedBy != null ) {
|
||||||
propertyData.setAuditMappedBy(auditMappedBy.mappedBy());
|
propertyData.setAuditMappedBy( auditMappedBy.mappedBy() );
|
||||||
if (!"".equals(auditMappedBy.positionMappedBy())) {
|
if ( !"".equals( auditMappedBy.positionMappedBy() ) ) {
|
||||||
propertyData.setPositionMappedBy(auditMappedBy.positionMappedBy());
|
propertyData.setPositionMappedBy( auditMappedBy.positionMappedBy() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
|
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
|
||||||
MapKey mapKey = property.getAnnotation(MapKey.class);
|
final MapKey mapKey = property.getAnnotation( MapKey.class );
|
||||||
if (mapKey != null) {
|
if ( mapKey != null ) {
|
||||||
propertyData.setMapKey(mapKey.name());
|
propertyData.setMapKey( mapKey.name() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
|
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
|
||||||
// first set the join table based on the AuditJoinTable annotation
|
// first set the join table based on the AuditJoinTable annotation
|
||||||
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class);
|
final AuditJoinTable joinTable = property.getAnnotation( AuditJoinTable.class );
|
||||||
if (joinTable != null) {
|
if ( joinTable != null ) {
|
||||||
propertyData.setJoinTable(joinTable);
|
propertyData.setJoinTable( joinTable );
|
||||||
} else {
|
}
|
||||||
propertyData.setJoinTable(DEFAULT_AUDIT_JOIN_TABLE);
|
else {
|
||||||
|
propertyData.setJoinTable( DEFAULT_AUDIT_JOIN_TABLE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/**
|
||||||
* Add the {@link AuditOverride} annotations.
|
* Add the {@link AuditOverride} annotations.
|
||||||
*
|
*
|
||||||
* @param property the property being processed
|
* @param property the property being processed
|
||||||
* @param propertyData the Envers auditing data for this property
|
* @param propertyData the Envers auditing data for this property
|
||||||
*/
|
*/
|
||||||
private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
||||||
AuditOverride annotationOverride = property.getAnnotation(AuditOverride.class);
|
final AuditOverride annotationOverride = property.getAnnotation( AuditOverride.class );
|
||||||
if (annotationOverride != null) {
|
if ( annotationOverride != null ) {
|
||||||
propertyData.addAuditingOverride(annotationOverride);
|
propertyData.addAuditingOverride( annotationOverride );
|
||||||
}
|
}
|
||||||
AuditOverrides annotationOverrides = property.getAnnotation(AuditOverrides.class);
|
final AuditOverrides annotationOverrides = property.getAnnotation( AuditOverrides.class );
|
||||||
if (annotationOverrides != null) {
|
if ( annotationOverrides != null ) {
|
||||||
propertyData.addAuditingOverrides(annotationOverrides);
|
propertyData.addAuditingOverrides( annotationOverrides );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the {@link AuditOverride} annotations for this property.
|
* Process the {@link AuditOverride} annotations for this property.
|
||||||
*
|
*
|
||||||
* @param property
|
* @param property the property for which the {@link AuditOverride}
|
||||||
* the property for which the {@link AuditOverride}
|
* annotations are being processed
|
||||||
* annotations are being processed
|
* @param propertyData the Envers auditing data for this property
|
||||||
* @param propertyData
|
*
|
||||||
* the Envers auditing data for this property
|
|
||||||
* @return {@code false} if isAudited() of the override annotation was set to
|
* @return {@code false} if isAudited() of the override annotation was set to
|
||||||
*/
|
*/
|
||||||
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
||||||
// if this property is part of a component, process all override annotations
|
// if this property is part of a component, process all override annotations
|
||||||
if (this.auditedPropertiesHolder instanceof ComponentAuditingData) {
|
if ( this.auditedPropertiesHolder instanceof ComponentAuditingData ) {
|
||||||
List<AuditOverride> overrides = ((ComponentAuditingData) this.auditedPropertiesHolder).getAuditingOverrides();
|
final List<AuditOverride> overrides = ( (ComponentAuditingData) this.auditedPropertiesHolder ).getAuditingOverrides();
|
||||||
for (AuditOverride override : overrides) {
|
for ( AuditOverride override : overrides ) {
|
||||||
if (property.getName().equals(override.name())) {
|
if ( property.getName().equals( override.name() ) ) {
|
||||||
// the override applies to this property
|
// the override applies to this property
|
||||||
if (!override.isAudited()) {
|
if ( !override.isAudited() ) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
if (override.auditJoinTable() != null) {
|
else {
|
||||||
propertyData.setJoinTable(override.auditJoinTable());
|
if ( override.auditJoinTable() != null ) {
|
||||||
|
propertyData.setJoinTable( override.auditJoinTable() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Audited DEFAULT_AUDITED = new Audited() {
|
private static final Audited DEFAULT_AUDITED = new Audited() {
|
||||||
public ModificationStore modStore() { return ModificationStore.FULL; }
|
@Override
|
||||||
public RelationTargetAuditMode targetAuditMode() { return RelationTargetAuditMode.AUDITED; }
|
public ModificationStore modStore() {
|
||||||
public Class[] auditParents() { return new Class[0]; }
|
return ModificationStore.FULL;
|
||||||
public boolean withModifiedFlag() { return false; }
|
}
|
||||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
private static AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
|
@Override
|
||||||
public String name() { return ""; }
|
public RelationTargetAuditMode targetAuditMode() {
|
||||||
public String schema() { return ""; }
|
return RelationTargetAuditMode.AUDITED;
|
||||||
public String catalog() { return ""; }
|
}
|
||||||
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
|
|
||||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
@Override
|
||||||
|
public Class[] auditParents() {
|
||||||
|
return new Class[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean withModifiedFlag() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Annotation> annotationType() {
|
||||||
|
return this.getClass();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static class ComponentPropertiesSource implements PersistentPropertiesSource {
|
private static final AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String schema() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String catalog() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JoinColumn[] inverseJoinColumns() {
|
||||||
|
return new JoinColumn[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Annotation> annotationType() {
|
||||||
|
return this.getClass();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static class ComponentPropertiesSource implements PersistentPropertiesSource {
|
||||||
private final XClass xclass;
|
private final XClass xclass;
|
||||||
private final Component component;
|
private final Component component;
|
||||||
|
|
||||||
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
|
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
|
||||||
try {
|
try {
|
||||||
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass());
|
this.xclass = reflectionManager.classForName( component.getComponentClassName(), this.getClass() );
|
||||||
} catch (ClassNotFoundException e) {
|
}
|
||||||
throw new MappingException(e);
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new MappingException( e );
|
||||||
}
|
}
|
||||||
|
|
||||||
this.component = component;
|
this.component = component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public Iterator<Property> getPropertyIterator() { return component.getPropertyIterator(); }
|
public Iterator<Property> getPropertyIterator() {
|
||||||
public Property getProperty(String propertyName) { return component.getProperty(propertyName); }
|
return component.getPropertyIterator();
|
||||||
public XClass getXClass() { return xclass; }
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Property getProperty(String propertyName) {
|
||||||
|
return component.getProperty( propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XClass getXClass() {
|
||||||
|
return xclass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.AuditTable;
|
import org.hibernate.envers.AuditTable;
|
||||||
|
@ -32,12 +33,12 @@ import static org.hibernate.envers.internal.tools.Tools.newHashMap;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Sebastian Komander
|
* @author Sebastian Komander
|
||||||
* @author Hern&aacut;n Chanfreau
|
* @author Hern&aacut;n Chanfreau
|
||||||
*/
|
*/
|
||||||
public class ClassAuditingData implements AuditedPropertiesHolder {
|
public class ClassAuditingData implements AuditedPropertiesHolder {
|
||||||
private final Map<String, PropertyAuditingData> properties;
|
private final Map<String, PropertyAuditingData> properties;
|
||||||
private final Map<String, String> secondaryTableDictionary;
|
private final Map<String, String> secondaryTableDictionary;
|
||||||
|
|
||||||
private AuditTable auditTable;
|
private AuditTable auditTable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the class is audited globally (this helps to cover the cases when there are no fields in the class,
|
* True if the class is audited globally (this helps to cover the cases when there are no fields in the class,
|
||||||
|
@ -45,48 +46,52 @@ public class ClassAuditingData implements AuditedPropertiesHolder {
|
||||||
*/
|
*/
|
||||||
private boolean defaultAudited;
|
private boolean defaultAudited;
|
||||||
|
|
||||||
public ClassAuditingData() {
|
public ClassAuditingData() {
|
||||||
properties = newHashMap();
|
properties = newHashMap();
|
||||||
secondaryTableDictionary = newHashMap();
|
secondaryTableDictionary = newHashMap();
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return properties.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
|
||||||
properties.put(propertyName, auditingData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
@Override
|
||||||
return properties.get(propertyName);
|
public boolean isEmpty() {
|
||||||
}
|
return properties.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public Iterable<String> getPropertyNames() {
|
@Override
|
||||||
return properties.keySet();
|
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
||||||
}
|
properties.put( propertyName, auditingData );
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, String> getSecondaryTableDictionary() {
|
@Override
|
||||||
return secondaryTableDictionary;
|
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||||
}
|
return properties.get( propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
public AuditTable getAuditTable() {
|
public Iterable<String> getPropertyNames() {
|
||||||
return auditTable;
|
return properties.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuditTable(AuditTable auditTable) {
|
public Map<String, String> getSecondaryTableDictionary() {
|
||||||
this.auditTable = auditTable;
|
return secondaryTableDictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AuditTable getAuditTable() {
|
||||||
|
return auditTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuditTable(AuditTable auditTable) {
|
||||||
|
this.auditTable = auditTable;
|
||||||
|
}
|
||||||
|
|
||||||
public void setDefaultAudited(boolean defaultAudited) {
|
public void setDefaultAudited(boolean defaultAudited) {
|
||||||
this.defaultAudited = defaultAudited;
|
this.defaultAudited = defaultAudited;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAudited() {
|
public boolean isAudited() {
|
||||||
return defaultAudited || properties.size() > 0;
|
return defaultAudited || properties.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean contains(String propertyName) {
|
public boolean contains(String propertyName) {
|
||||||
return properties.containsKey(propertyName);
|
return properties.containsKey( propertyName );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||||
import org.hibernate.annotations.common.reflection.XProperty;
|
import org.hibernate.annotations.common.reflection.XProperty;
|
||||||
import org.hibernate.envers.Audited;
|
import org.hibernate.envers.Audited;
|
||||||
|
@ -7,34 +31,40 @@ import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the audited properties for components.
|
* Reads the audited properties for components.
|
||||||
*
|
*
|
||||||
* @author Hern&aacut;n Chanfreau
|
* @author Hern&aacut;n Chanfreau
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
||||||
|
|
||||||
public ComponentAuditedPropertiesReader(ModificationStore defaultStore,
|
public ComponentAuditedPropertiesReader(
|
||||||
|
ModificationStore defaultStore,
|
||||||
PersistentPropertiesSource persistentPropertiesSource,
|
PersistentPropertiesSource persistentPropertiesSource,
|
||||||
AuditedPropertiesHolder auditedPropertiesHolder,
|
AuditedPropertiesHolder auditedPropertiesHolder,
|
||||||
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
||||||
String propertyNamePrefix) {
|
String propertyNamePrefix) {
|
||||||
super(defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
|
super(
|
||||||
globalCfg, reflectionManager, propertyNamePrefix);
|
defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
|
||||||
|
globalCfg, reflectionManager, propertyNamePrefix
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean checkAudited(XProperty property,
|
protected boolean checkAudited(
|
||||||
PropertyAuditingData propertyData, Audited allClassAudited) {
|
XProperty property,
|
||||||
|
PropertyAuditingData propertyData,
|
||||||
|
Audited allClassAudited) {
|
||||||
// Checking if this property is explicitly audited or if all properties are.
|
// Checking if this property is explicitly audited or if all properties are.
|
||||||
Audited aud = property.getAnnotation(Audited.class);
|
final Audited aud = property.getAnnotation( Audited.class );
|
||||||
if (aud != null) {
|
if ( aud != null ) {
|
||||||
propertyData.setStore(aud.modStore());
|
propertyData.setStore( aud.modStore() );
|
||||||
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
|
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||||
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
|
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||||
} else {
|
}
|
||||||
propertyData.setStore(ModificationStore.FULL);
|
else {
|
||||||
}
|
propertyData.setStore( ModificationStore.FULL );
|
||||||
return true;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import static org.hibernate.envers.internal.tools.Tools.newHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Audit mapping meta-data for component.
|
* Audit mapping meta-data for component.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Hern&aacut;n Chanfreau
|
* @author Hern&aacut;n Chanfreau
|
||||||
*/
|
*/
|
||||||
|
@ -40,21 +41,25 @@ public class ComponentAuditingData extends PropertyAuditingData implements Audit
|
||||||
this.properties = newHashMap();
|
this.properties = newHashMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return properties.isEmpty();
|
return properties.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
||||||
properties.put(propertyName, auditingData);
|
properties.put( propertyName, auditingData );
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
@Override
|
||||||
return properties.get(propertyName);
|
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||||
}
|
return properties.get( propertyName );
|
||||||
|
}
|
||||||
public boolean contains(String propertyName) {
|
|
||||||
return properties.containsKey(propertyName);
|
@Override
|
||||||
}
|
public boolean contains(String propertyName) {
|
||||||
|
return properties.containsKey( propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getPropertyNames() {
|
public Set<String> getPropertyNames() {
|
||||||
return properties.keySet();
|
return properties.keySet();
|
||||||
|
|
|
@ -1,4 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
|
@ -6,10 +30,13 @@ import org.hibernate.mapping.Property;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A source of data on persistent properties of a class or component.
|
* A source of data on persistent properties of a class or component.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public interface PersistentPropertiesSource {
|
public interface PersistentPropertiesSource {
|
||||||
Iterator<Property> getPropertyIterator();
|
Iterator<Property> getPropertyIterator();
|
||||||
|
|
||||||
Property getProperty(String propertyName);
|
Property getProperty(String propertyName);
|
||||||
|
|
||||||
XClass getXClass();
|
XClass getXClass();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -38,45 +38,46 @@ import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public class PropertyAuditingData {
|
public class PropertyAuditingData {
|
||||||
private String name;
|
private String name;
|
||||||
private String beanName;
|
private String beanName;
|
||||||
private ModificationStore store;
|
private ModificationStore store;
|
||||||
private String mapKey;
|
private String mapKey;
|
||||||
private AuditJoinTable joinTable;
|
private AuditJoinTable joinTable;
|
||||||
private String accessType;
|
private String accessType;
|
||||||
private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>(0);
|
private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>( 0 );
|
||||||
private RelationTargetAuditMode relationTargetAuditMode;
|
private RelationTargetAuditMode relationTargetAuditMode;
|
||||||
private String auditMappedBy;
|
private String auditMappedBy;
|
||||||
private String relationMappedBy;
|
private String relationMappedBy;
|
||||||
private String positionMappedBy;
|
private String positionMappedBy;
|
||||||
private boolean forceInsertable;
|
private boolean forceInsertable;
|
||||||
private boolean usingModifiedFlag;
|
private boolean usingModifiedFlag;
|
||||||
private String modifiedFlagName;
|
private String modifiedFlagName;
|
||||||
|
|
||||||
public PropertyAuditingData() {
|
public PropertyAuditingData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyAuditingData(String name, String accessType, ModificationStore store,
|
public PropertyAuditingData(
|
||||||
RelationTargetAuditMode relationTargetAuditMode,
|
String name, String accessType, ModificationStore store,
|
||||||
String auditMappedBy, String positionMappedBy,
|
RelationTargetAuditMode relationTargetAuditMode,
|
||||||
boolean forceInsertable) {
|
String auditMappedBy, String positionMappedBy,
|
||||||
this.name = name;
|
boolean forceInsertable) {
|
||||||
|
this.name = name;
|
||||||
this.beanName = name;
|
this.beanName = name;
|
||||||
this.accessType = accessType;
|
this.accessType = accessType;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.relationTargetAuditMode = relationTargetAuditMode;
|
this.relationTargetAuditMode = relationTargetAuditMode;
|
||||||
this.auditMappedBy = auditMappedBy;
|
this.auditMappedBy = auditMappedBy;
|
||||||
this.positionMappedBy = positionMappedBy;
|
this.positionMappedBy = positionMappedBy;
|
||||||
this.forceInsertable = forceInsertable;
|
this.forceInsertable = forceInsertable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBeanName() {
|
public String getBeanName() {
|
||||||
return beanName;
|
return beanName;
|
||||||
|
@ -87,77 +88,79 @@ public class PropertyAuditingData {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModificationStore getStore() {
|
public ModificationStore getStore() {
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStore(ModificationStore store) {
|
public void setStore(ModificationStore store) {
|
||||||
this.store = store;
|
this.store = store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMapKey() {
|
public String getMapKey() {
|
||||||
return mapKey;
|
return mapKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMapKey(String mapKey) {
|
public void setMapKey(String mapKey) {
|
||||||
this.mapKey = mapKey;
|
this.mapKey = mapKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuditJoinTable getJoinTable() {
|
public AuditJoinTable getJoinTable() {
|
||||||
return joinTable;
|
return joinTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setJoinTable(AuditJoinTable joinTable) {
|
public void setJoinTable(AuditJoinTable joinTable) {
|
||||||
this.joinTable = joinTable;
|
this.joinTable = joinTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAccessType() {
|
public String getAccessType() {
|
||||||
return accessType;
|
return accessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAccessType(String accessType) {
|
public void setAccessType(String accessType) {
|
||||||
this.accessType = accessType;
|
this.accessType = accessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyData getPropertyData() {
|
public PropertyData getPropertyData() {
|
||||||
return new PropertyData(name, beanName, accessType, store,
|
return new PropertyData(
|
||||||
usingModifiedFlag, modifiedFlagName);
|
name, beanName, accessType, store,
|
||||||
}
|
usingModifiedFlag, modifiedFlagName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public List<AuditOverride> getAuditingOverrides() {
|
public List<AuditOverride> getAuditingOverrides() {
|
||||||
return auditJoinTableOverrides;
|
return auditJoinTableOverrides;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuditMappedBy() {
|
public String getAuditMappedBy() {
|
||||||
return auditMappedBy;
|
return auditMappedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuditMappedBy(String auditMappedBy) {
|
public void setAuditMappedBy(String auditMappedBy) {
|
||||||
this.auditMappedBy = auditMappedBy;
|
this.auditMappedBy = auditMappedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRelationMappedBy() {
|
public String getRelationMappedBy() {
|
||||||
return relationMappedBy;
|
return relationMappedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRelationMappedBy(String relationMappedBy) {
|
public void setRelationMappedBy(String relationMappedBy) {
|
||||||
this.relationMappedBy = relationMappedBy;
|
this.relationMappedBy = relationMappedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPositionMappedBy() {
|
public String getPositionMappedBy() {
|
||||||
return positionMappedBy;
|
return positionMappedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPositionMappedBy(String positionMappedBy) {
|
public void setPositionMappedBy(String positionMappedBy) {
|
||||||
this.positionMappedBy = positionMappedBy;
|
this.positionMappedBy = positionMappedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isForceInsertable() {
|
public boolean isForceInsertable() {
|
||||||
return forceInsertable;
|
return forceInsertable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForceInsertable(boolean forceInsertable) {
|
public void setForceInsertable(boolean forceInsertable) {
|
||||||
this.forceInsertable = forceInsertable;
|
this.forceInsertable = forceInsertable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUsingModifiedFlag() {
|
public boolean isUsingModifiedFlag() {
|
||||||
return usingModifiedFlag;
|
return usingModifiedFlag;
|
||||||
|
@ -172,25 +175,25 @@ public class PropertyAuditingData {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAuditingOverride(AuditOverride annotation) {
|
public void addAuditingOverride(AuditOverride annotation) {
|
||||||
if (annotation != null) {
|
if ( annotation != null ) {
|
||||||
String overrideName = annotation.name();
|
final String overrideName = annotation.name();
|
||||||
boolean present = false;
|
boolean present = false;
|
||||||
for (AuditOverride current : auditJoinTableOverrides) {
|
for ( AuditOverride current : auditJoinTableOverrides ) {
|
||||||
if (current.name().equals(overrideName)) {
|
if ( current.name().equals( overrideName ) ) {
|
||||||
present = true;
|
present = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!present) {
|
if ( !present ) {
|
||||||
auditJoinTableOverrides.add(annotation);
|
auditJoinTableOverrides.add( annotation );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAuditingOverrides(AuditOverrides annotationOverrides) {
|
public void addAuditingOverrides(AuditOverrides annotationOverrides) {
|
||||||
if (annotationOverrides != null) {
|
if ( annotationOverrides != null ) {
|
||||||
for (AuditOverride annotation : annotationOverrides.value()) {
|
for ( AuditOverride annotation : annotationOverrides.value() ) {
|
||||||
addAuditingOverride(annotation);
|
addAuditingOverride( annotation );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -107,30 +107,30 @@ public class AuditConfiguration {
|
||||||
public AuditConfiguration(Configuration cfg, ClassLoaderService classLoaderService) {
|
public AuditConfiguration(Configuration cfg, ClassLoaderService classLoaderService) {
|
||||||
// TODO: Temporarily allow Envers to continuing using
|
// TODO: Temporarily allow Envers to continuing using
|
||||||
// hibernate-commons-annotations' for reflection and class loading.
|
// hibernate-commons-annotations' for reflection and class loading.
|
||||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||||
Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() );
|
Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() );
|
||||||
|
|
||||||
Properties properties = cfg.getProperties();
|
|
||||||
|
|
||||||
ReflectionManager reflectionManager = cfg.getReflectionManager();
|
final Properties properties = cfg.getProperties();
|
||||||
globalCfg = new GlobalConfiguration( properties, classLoaderService );
|
|
||||||
RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg );
|
final ReflectionManager reflectionManager = cfg.getReflectionManager();
|
||||||
RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure( cfg, reflectionManager );
|
this.globalCfg = new GlobalConfiguration( properties, classLoaderService );
|
||||||
auditEntCfg = new AuditEntitiesConfiguration( properties, revInfoCfgResult.getRevisionInfoEntityName() );
|
final RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg );
|
||||||
auditProcessManager = new AuditProcessManager( revInfoCfgResult.getRevisionInfoGenerator() );
|
final RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure( cfg, reflectionManager );
|
||||||
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
|
this.auditEntCfg = new AuditEntitiesConfiguration( properties, revInfoCfgResult.getRevisionInfoEntityName() );
|
||||||
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
|
this.auditProcessManager = new AuditProcessManager( revInfoCfgResult.getRevisionInfoGenerator() );
|
||||||
modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
|
this.revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
|
||||||
|
this.revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
|
||||||
|
this.modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
|
||||||
this.classLoaderService = classLoaderService;
|
this.classLoaderService = classLoaderService;
|
||||||
auditStrategy = initializeAuditStrategy(
|
this.auditStrategy = initializeAuditStrategy(
|
||||||
revInfoCfgResult.getRevisionInfoClass(),
|
revInfoCfgResult.getRevisionInfoClass(),
|
||||||
revInfoCfgResult.getRevisionInfoTimestampData()
|
revInfoCfgResult.getRevisionInfoTimestampData()
|
||||||
);
|
);
|
||||||
entCfg = new EntitiesConfigurator().configure(
|
this.entCfg = new EntitiesConfigurator().configure(
|
||||||
cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy, classLoaderService,
|
cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy, classLoaderService,
|
||||||
revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping()
|
revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping()
|
||||||
);
|
);
|
||||||
|
|
||||||
Thread.currentThread().setContextClassLoader( tccl );
|
Thread.currentThread().setContextClassLoader( tccl );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,11 +143,14 @@ public class AuditConfiguration {
|
||||||
auditStrategyClass = this.getClass().getClassLoader().loadClass( auditEntCfg.getAuditStrategyName() );
|
auditStrategyClass = this.getClass().getClassLoader().loadClass( auditEntCfg.getAuditStrategyName() );
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
auditStrategyClass = ReflectionTools.loadClass( auditEntCfg.getAuditStrategyName(), classLoaderService );
|
auditStrategyClass = ReflectionTools.loadClass(
|
||||||
|
auditEntCfg.getAuditStrategyName(),
|
||||||
|
classLoaderService
|
||||||
|
);
|
||||||
}
|
}
|
||||||
strategy = (AuditStrategy) ReflectHelper.getDefaultConstructor(auditStrategyClass).newInstance();
|
strategy = (AuditStrategy) ReflectHelper.getDefaultConstructor( auditStrategyClass ).newInstance();
|
||||||
}
|
}
|
||||||
catch ( Exception e ) {
|
catch (Exception e) {
|
||||||
throw new MappingException(
|
throw new MappingException(
|
||||||
String.format( "Unable to create AuditStrategy[%s] instance.", auditEntCfg.getAuditStrategyName() ),
|
String.format( "Unable to create AuditStrategy[%s] instance.", auditEntCfg.getAuditStrategyName() ),
|
||||||
e
|
e
|
||||||
|
@ -156,27 +159,25 @@ public class AuditConfiguration {
|
||||||
|
|
||||||
if ( strategy instanceof ValidityAuditStrategy ) {
|
if ( strategy instanceof ValidityAuditStrategy ) {
|
||||||
// further initialization required
|
// further initialization required
|
||||||
Getter revisionTimestampGetter = ReflectionTools.getGetter( revisionInfoClass, revisionInfoTimestampData );
|
final Getter revisionTimestampGetter = ReflectionTools.getGetter( revisionInfoClass, revisionInfoTimestampData );
|
||||||
( (ValidityAuditStrategy) strategy ).setRevisionTimestampGetter( revisionTimestampGetter );
|
( (ValidityAuditStrategy) strategy ).setRevisionTimestampGetter( revisionTimestampGetter );
|
||||||
}
|
}
|
||||||
|
|
||||||
return strategy;
|
return strategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
private static final Map<Configuration, AuditConfiguration> CFGS = new WeakHashMap<Configuration, AuditConfiguration>();
|
||||||
|
|
||||||
private static Map<Configuration, AuditConfiguration> cfgs = new WeakHashMap<Configuration, AuditConfiguration>();
|
|
||||||
|
|
||||||
public synchronized static AuditConfiguration getFor(Configuration cfg) {
|
public synchronized static AuditConfiguration getFor(Configuration cfg) {
|
||||||
return getFor( cfg, null );
|
return getFor( cfg, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized static AuditConfiguration getFor(Configuration cfg, ClassLoaderService classLoaderService) {
|
public synchronized static AuditConfiguration getFor(Configuration cfg, ClassLoaderService classLoaderService) {
|
||||||
AuditConfiguration verCfg = cfgs.get( cfg );
|
AuditConfiguration verCfg = CFGS.get( cfg );
|
||||||
|
|
||||||
if ( verCfg == null ) {
|
if ( verCfg == null ) {
|
||||||
verCfg = new AuditConfiguration( cfg, classLoaderService );
|
verCfg = new AuditConfiguration( cfg, classLoaderService );
|
||||||
cfgs.put( cfg, verCfg );
|
CFGS.put( cfg, verCfg );
|
||||||
|
|
||||||
cfg.buildMappings();
|
cfg.buildMappings();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
package org.hibernate.envers.enhanced;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
@ -8,6 +31,7 @@ import org.hibernate.internal.util.StringHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revision number generator has to produce values in ascending order (gaps may occur).
|
* Revision number generator has to produce values in ascending order (gaps may occur).
|
||||||
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public class OrderedSequenceGenerator extends SequenceStyleGenerator {
|
public class OrderedSequenceGenerator extends SequenceStyleGenerator {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -23,13 +23,13 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.enhanced;
|
package org.hibernate.envers.enhanced;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.MappedSuperclass;
|
import javax.persistence.MappedSuperclass;
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import org.hibernate.annotations.GenericGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
import org.hibernate.annotations.Parameter;
|
import org.hibernate.annotations.Parameter;
|
||||||
|
@ -42,64 +42,72 @@ import org.hibernate.envers.RevisionTimestamp;
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class SequenceIdRevisionEntity implements Serializable {
|
public class SequenceIdRevisionEntity implements Serializable {
|
||||||
private static final long serialVersionUID = 4159156677698841902L;
|
private static final long serialVersionUID = 4159156677698841902L;
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(generator = "RevisionNumberSequenceGenerator")
|
|
||||||
@GenericGenerator(name = "RevisionNumberSequenceGenerator",
|
|
||||||
strategy = "org.hibernate.envers.enhanced.OrderedSequenceGenerator",
|
|
||||||
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
|
@Id
|
||||||
private long timestamp;
|
@GeneratedValue(generator = "RevisionNumberSequenceGenerator")
|
||||||
|
@GenericGenerator(
|
||||||
|
name = "RevisionNumberSequenceGenerator",
|
||||||
|
strategy = "org.hibernate.envers.enhanced.OrderedSequenceGenerator",
|
||||||
|
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;
|
||||||
|
|
||||||
public int getId() {
|
@RevisionTimestamp
|
||||||
return id;
|
private long timestamp;
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(int id) {
|
public int getId() {
|
||||||
this.id = id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient
|
public void setId(int id) {
|
||||||
public Date getRevisionDate() {
|
this.id = id;
|
||||||
return new Date(timestamp);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimestamp() {
|
@Transient
|
||||||
return timestamp;
|
public Date getRevisionDate() {
|
||||||
}
|
return new Date( timestamp );
|
||||||
|
}
|
||||||
|
|
||||||
public void setTimestamp(long timestamp) {
|
public long getTimestamp() {
|
||||||
this.timestamp = timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
if (this == o) return true;
|
public void setTimestamp(long timestamp) {
|
||||||
if (!(o instanceof SequenceIdRevisionEntity )) return false;
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
SequenceIdRevisionEntity that = (SequenceIdRevisionEntity) o;
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( !(o instanceof SequenceIdRevisionEntity) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (id != that.id) return false;
|
final SequenceIdRevisionEntity that = (SequenceIdRevisionEntity) o;
|
||||||
if (timestamp != that.timestamp) return false;
|
return id == that.id && timestamp == that.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
@Override
|
||||||
}
|
public int hashCode() {
|
||||||
|
int result = id;
|
||||||
|
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
@Override
|
||||||
int result = id;
|
public String toString() {
|
||||||
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
|
return "SequenceIdRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(
|
||||||
return result;
|
getRevisionDate()
|
||||||
}
|
) + ")";
|
||||||
|
}
|
||||||
public String toString() {
|
|
||||||
return "SequenceIdRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -23,14 +23,14 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.enhanced;
|
package org.hibernate.envers.enhanced;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.JoinTable;
|
import javax.persistence.JoinTable;
|
||||||
import javax.persistence.MappedSuperclass;
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.annotations.Fetch;
|
import org.hibernate.annotations.Fetch;
|
||||||
import org.hibernate.annotations.FetchMode;
|
import org.hibernate.annotations.FetchMode;
|
||||||
|
@ -40,45 +40,60 @@ import org.hibernate.envers.ModifiedEntityNames;
|
||||||
* Extension of standard {@link SequenceIdRevisionEntity} that allows tracking entity names changed in each revision.
|
* Extension of standard {@link SequenceIdRevisionEntity} 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}
|
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
|
||||||
* parameter is set to {@code true}.
|
* parameter is set to {@code true}.
|
||||||
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class SequenceIdTrackingModifiedEntitiesRevisionEntity extends SequenceIdRevisionEntity {
|
public class SequenceIdTrackingModifiedEntitiesRevisionEntity extends SequenceIdRevisionEntity {
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
||||||
@Column(name = "ENTITYNAME")
|
@Column(name = "ENTITYNAME")
|
||||||
@Fetch(FetchMode.JOIN)
|
@Fetch(FetchMode.JOIN)
|
||||||
@ModifiedEntityNames
|
@ModifiedEntityNames
|
||||||
private Set<String> modifiedEntityNames = new HashSet<String>();
|
private Set<String> modifiedEntityNames = new HashSet<String>();
|
||||||
|
|
||||||
public Set<String> getModifiedEntityNames() {
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
return modifiedEntityNames;
|
public Set<String> getModifiedEntityNames() {
|
||||||
}
|
return modifiedEntityNames;
|
||||||
|
}
|
||||||
|
|
||||||
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
this.modifiedEntityNames = modifiedEntityNames;
|
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
||||||
}
|
this.modifiedEntityNames = modifiedEntityNames;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
@Override
|
||||||
if (this == o) return true;
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof SequenceIdTrackingModifiedEntitiesRevisionEntity )) return false;
|
if ( this == o ) {
|
||||||
if (!super.equals(o)) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if ( !(o instanceof SequenceIdTrackingModifiedEntitiesRevisionEntity) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !super.equals( o ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
SequenceIdTrackingModifiedEntitiesRevisionEntity that = (SequenceIdTrackingModifiedEntitiesRevisionEntity) o;
|
final SequenceIdTrackingModifiedEntitiesRevisionEntity that = (SequenceIdTrackingModifiedEntitiesRevisionEntity) o;
|
||||||
|
|
||||||
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames)
|
if ( modifiedEntityNames == null ) {
|
||||||
: that.modifiedEntityNames != null) return false;
|
return that.modifiedEntityNames == null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return modifiedEntityNames.equals( that.modifiedEntityNames );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
@Override
|
||||||
}
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
@Override
|
||||||
int result = super.hashCode();
|
public String toString() {
|
||||||
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
|
return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString()
|
||||||
return result;
|
+ ", modifiedEntityNames = " + modifiedEntityNames + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,40 +57,40 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
super( enversConfiguration );
|
super( enversConfiguration );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final CollectionEntry getCollectionEntry(AbstractCollectionEvent event) {
|
protected final CollectionEntry getCollectionEntry(AbstractCollectionEvent event) {
|
||||||
return event.getSession().getPersistenceContext().getCollectionEntry(event.getCollection());
|
return event.getSession().getPersistenceContext().getCollectionEntry( event.getCollection() );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void onCollectionAction(
|
protected final void onCollectionAction(
|
||||||
AbstractCollectionEvent event,
|
AbstractCollectionEvent event,
|
||||||
PersistentCollection newColl,
|
PersistentCollection newColl,
|
||||||
Serializable oldColl,
|
Serializable oldColl,
|
||||||
CollectionEntry collectionEntry) {
|
CollectionEntry collectionEntry) {
|
||||||
if ( shouldGenerateRevision( event ) ) {
|
if ( shouldGenerateRevision( event ) ) {
|
||||||
checkIfTransactionInProgress(event.getSession());
|
checkIfTransactionInProgress( event.getSession() );
|
||||||
|
|
||||||
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
|
|
||||||
|
|
||||||
String entityName = event.getAffectedOwnerEntityName();
|
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
|
||||||
String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
|
|
||||||
String referencingPropertyName = collectionEntry.getRole().substring(ownerEntityName.length() + 1);
|
|
||||||
|
|
||||||
// Checking if this is not a "fake" many-to-one bidirectional relation. The relation description may be
|
final String entityName = event.getAffectedOwnerEntityName();
|
||||||
// null in case of collections of non-entities.
|
final String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
|
||||||
RelationDescription rd = searchForRelationDescription( entityName, referencingPropertyName );
|
final String referencingPropertyName = collectionEntry.getRole().substring( ownerEntityName.length() + 1 );
|
||||||
if ( rd != null && rd.getMappedByPropertyName() != null ) {
|
|
||||||
generateFakeBidirecationalRelationWorkUnits(
|
// Checking if this is not a "fake" many-to-one bidirectional relation. The relation description may be
|
||||||
|
// null in case of collections of non-entities.
|
||||||
|
final RelationDescription rd = searchForRelationDescription( entityName, referencingPropertyName );
|
||||||
|
if ( rd != null && rd.getMappedByPropertyName() != null ) {
|
||||||
|
generateFakeBidirecationalRelationWorkUnits(
|
||||||
auditProcess,
|
auditProcess,
|
||||||
newColl,
|
newColl,
|
||||||
oldColl,
|
oldColl,
|
||||||
entityName,
|
entityName,
|
||||||
referencingPropertyName,
|
referencingPropertyName,
|
||||||
event,
|
event,
|
||||||
rd
|
rd
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(
|
final PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
entityName,
|
entityName,
|
||||||
getAuditConfiguration(),
|
getAuditConfiguration(),
|
||||||
|
@ -102,9 +102,9 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
);
|
);
|
||||||
auditProcess.addWorkUnit( workUnit );
|
auditProcess.addWorkUnit( workUnit );
|
||||||
|
|
||||||
if (workUnit.containsWork()) {
|
if ( workUnit.containsWork() ) {
|
||||||
// There are some changes: a revision needs also be generated for the collection owner
|
// There are some changes: a revision needs also be generated for the collection owner
|
||||||
auditProcess.addWorkUnit(
|
auditProcess.addWorkUnit(
|
||||||
new CollectionChangeWorkUnit(
|
new CollectionChangeWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
event.getAffectedOwnerEntityName(),
|
event.getAffectedOwnerEntityName(),
|
||||||
|
@ -115,15 +115,17 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
generateBidirectionalCollectionChangeWorkUnits( auditProcess, event, workUnit, rd );
|
generateBidirectionalCollectionChangeWorkUnits( auditProcess, event, workUnit, rd );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces persistent collection initialization.
|
* Forces persistent collection initialization.
|
||||||
|
*
|
||||||
* @param event Collection event.
|
* @param event Collection event.
|
||||||
|
*
|
||||||
* @return Stored snapshot.
|
* @return Stored snapshot.
|
||||||
*/
|
*/
|
||||||
protected Serializable initializeCollection(AbstractCollectionEvent event) {
|
protected Serializable initializeCollection(AbstractCollectionEvent event) {
|
||||||
|
@ -133,7 +135,9 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether modification of not-owned relation field triggers new revision and owner entity is versioned.
|
* Checks whether modification of not-owned relation field triggers new revision and owner entity is versioned.
|
||||||
|
*
|
||||||
* @param event Collection event.
|
* @param event Collection event.
|
||||||
|
*
|
||||||
* @return {@code true} if revision based on given event should be generated, {@code false} otherwise.
|
* @return {@code true} if revision based on given event should be generated, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
protected boolean shouldGenerateRevision(AbstractCollectionEvent event) {
|
protected boolean shouldGenerateRevision(AbstractCollectionEvent event) {
|
||||||
|
@ -142,27 +146,27 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
&& getAuditConfiguration().getEntCfg().isVersioned( entityName );
|
&& getAuditConfiguration().getEntCfg().isVersioned( entityName );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up a relation description corresponding to the given property in the given entity. If no description is
|
* Looks up a relation description corresponding to the given property in the given entity. If no description is
|
||||||
* found in the given entity, the parent entity is checked (so that inherited relations work).
|
* found in the given entity, the parent entity is checked (so that inherited relations work).
|
||||||
*
|
*
|
||||||
* @param entityName Name of the entity, in which to start looking.
|
* @param entityName Name of the entity, in which to start looking.
|
||||||
* @param referencingPropertyName The name of the property.
|
* @param referencingPropertyName The name of the property.
|
||||||
*
|
*
|
||||||
* @return A found relation description corresponding to the given entity or {@code null}, if no description can
|
* @return A found relation description corresponding to the given entity or {@code null}, if no description can
|
||||||
* be found.
|
* be found.
|
||||||
*/
|
*/
|
||||||
private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) {
|
private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) {
|
||||||
EntityConfiguration configuration = getAuditConfiguration().getEntCfg().get( entityName );
|
final EntityConfiguration configuration = getAuditConfiguration().getEntCfg().get( entityName );
|
||||||
RelationDescription rd = configuration.getRelationDescription(referencingPropertyName);
|
final RelationDescription rd = configuration.getRelationDescription( referencingPropertyName );
|
||||||
if ( rd == null && configuration.getParentEntityName() != null ) {
|
if ( rd == null && configuration.getParentEntityName() != null ) {
|
||||||
return searchForRelationDescription( configuration.getParentEntityName(), referencingPropertyName );
|
return searchForRelationDescription( configuration.getParentEntityName(), referencingPropertyName );
|
||||||
}
|
}
|
||||||
|
|
||||||
return rd;
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateFakeBidirecationalRelationWorkUnits(
|
private void generateFakeBidirecationalRelationWorkUnits(
|
||||||
AuditProcess auditProcess,
|
AuditProcess auditProcess,
|
||||||
PersistentCollection newColl,
|
PersistentCollection newColl,
|
||||||
Serializable oldColl,
|
Serializable oldColl,
|
||||||
|
@ -170,41 +174,47 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
String referencingPropertyName,
|
String referencingPropertyName,
|
||||||
AbstractCollectionEvent event,
|
AbstractCollectionEvent event,
|
||||||
RelationDescription rd) {
|
RelationDescription rd) {
|
||||||
// First computing the relation changes
|
// First computing the relation changes
|
||||||
List<PersistentCollectionChangeData> collectionChanges = getAuditConfiguration()
|
final List<PersistentCollectionChangeData> collectionChanges = getAuditConfiguration()
|
||||||
.getEntCfg()
|
.getEntCfg()
|
||||||
.get( collectionEntityName )
|
.get( collectionEntityName )
|
||||||
.getPropertyMapper()
|
.getPropertyMapper()
|
||||||
.mapCollectionChanges( event.getSession(), referencingPropertyName, newColl, oldColl, event.getAffectedOwnerIdOrNull() );
|
.mapCollectionChanges(
|
||||||
|
event.getSession(),
|
||||||
|
referencingPropertyName,
|
||||||
|
newColl,
|
||||||
|
oldColl,
|
||||||
|
event.getAffectedOwnerIdOrNull()
|
||||||
|
);
|
||||||
|
|
||||||
// Getting the id mapper for the related entity, as the work units generated will corrspond to the related
|
// Getting the id mapper for the related entity, as the work units generated will correspond to the related
|
||||||
// entities.
|
// entities.
|
||||||
String relatedEntityName = rd.getToEntityName();
|
final String relatedEntityName = rd.getToEntityName();
|
||||||
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get(relatedEntityName).getIdMapper();
|
final IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
|
||||||
|
|
||||||
// For each collection change, generating the bidirectional work unit.
|
// For each collection change, generating the bidirectional work unit.
|
||||||
for ( PersistentCollectionChangeData changeData : collectionChanges ) {
|
for ( PersistentCollectionChangeData changeData : collectionChanges ) {
|
||||||
Object relatedObj = changeData.getChangedElement();
|
final Object relatedObj = changeData.getChangedElement();
|
||||||
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity(relatedObj);
|
final Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
|
||||||
RevisionType revType = (RevisionType) changeData.getData().get(
|
final RevisionType revType = (RevisionType) changeData.getData().get(
|
||||||
getAuditConfiguration().getAuditEntCfg().getRevisionTypePropName()
|
getAuditConfiguration().getAuditEntCfg().getRevisionTypePropName()
|
||||||
);
|
);
|
||||||
|
|
||||||
// This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass
|
// This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass
|
||||||
// of relatedEntityName).
|
// of relatedEntityName).
|
||||||
String realRelatedEntityName = event.getSession().bestGuessEntityName(relatedObj);
|
final String realRelatedEntityName = event.getSession().bestGuessEntityName( relatedObj );
|
||||||
|
|
||||||
// By default, the nested work unit is a collection change work unit.
|
// By default, the nested work unit is a collection change work unit.
|
||||||
AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
|
final AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
realRelatedEntityName,
|
realRelatedEntityName,
|
||||||
rd.getMappedByPropertyName(),
|
rd.getMappedByPropertyName(),
|
||||||
getAuditConfiguration(),
|
getAuditConfiguration(),
|
||||||
relatedId,
|
relatedId,
|
||||||
relatedObj
|
relatedObj
|
||||||
);
|
);
|
||||||
|
|
||||||
auditProcess.addWorkUnit(
|
auditProcess.addWorkUnit(
|
||||||
new FakeBidirectionalRelationWorkUnit(
|
new FakeBidirectionalRelationWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
realRelatedEntityName,
|
realRelatedEntityName,
|
||||||
|
@ -218,10 +228,10 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
nestedWorkUnit
|
nestedWorkUnit
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also have to generate a collection change work unit for the owning entity.
|
// We also have to generate a collection change work unit for the owning entity.
|
||||||
auditProcess.addWorkUnit(
|
auditProcess.addWorkUnit(
|
||||||
new CollectionChangeWorkUnit(
|
new CollectionChangeWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
collectionEntityName,
|
collectionEntityName,
|
||||||
|
@ -231,44 +241,47 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
||||||
event.getAffectedOwnerOrNull()
|
event.getAffectedOwnerOrNull()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateBidirectionalCollectionChangeWorkUnits(
|
private void generateBidirectionalCollectionChangeWorkUnits(
|
||||||
AuditProcess auditProcess,
|
AuditProcess auditProcess,
|
||||||
AbstractCollectionEvent event,
|
AbstractCollectionEvent event,
|
||||||
PersistentCollectionChangeWorkUnit workUnit,
|
PersistentCollectionChangeWorkUnit workUnit,
|
||||||
RelationDescription rd) {
|
RelationDescription rd) {
|
||||||
// Checking if this is enabled in configuration ...
|
// Checking if this is enabled in configuration ...
|
||||||
if ( ! getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
if ( !getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checking if this is not a bidirectional relation - then, a revision needs also be generated for
|
// Checking if this is not a bidirectional relation - then, a revision needs also be generated for
|
||||||
// the other side of the relation.
|
// the other side of the relation.
|
||||||
// relDesc can be null if this is a collection of simple values (not a relation).
|
// relDesc can be null if this is a collection of simple values (not a relation).
|
||||||
if ( rd != null && rd.isBidirectional() ) {
|
if ( rd != null && rd.isBidirectional() ) {
|
||||||
String relatedEntityName = rd.getToEntityName();
|
final String relatedEntityName = rd.getToEntityName();
|
||||||
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
|
final IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
|
||||||
|
|
||||||
Set<String> toPropertyNames = getAuditConfiguration().getEntCfg()
|
final Set<String> toPropertyNames = getAuditConfiguration().getEntCfg().getToPropertyNames(
|
||||||
.getToPropertyNames(event.getAffectedOwnerEntityName(), rd.getFromPropertyName(), relatedEntityName);
|
event.getAffectedOwnerEntityName(),
|
||||||
String toPropertyName = toPropertyNames.iterator().next();
|
rd.getFromPropertyName(),
|
||||||
|
relatedEntityName
|
||||||
|
);
|
||||||
|
final String toPropertyName = toPropertyNames.iterator().next();
|
||||||
|
|
||||||
for ( PersistentCollectionChangeData changeData : workUnit.getCollectionChanges() ) {
|
for ( PersistentCollectionChangeData changeData : workUnit.getCollectionChanges() ) {
|
||||||
Object relatedObj = changeData.getChangedElement();
|
final Object relatedObj = changeData.getChangedElement();
|
||||||
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
|
final Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
|
||||||
|
|
||||||
auditProcess.addWorkUnit(
|
auditProcess.addWorkUnit(
|
||||||
new CollectionChangeWorkUnit(
|
new CollectionChangeWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
event.getSession().bestGuessEntityName(relatedObj),
|
event.getSession().bestGuessEntityName( relatedObj ),
|
||||||
toPropertyName,
|
toPropertyName,
|
||||||
getAuditConfiguration(),
|
getAuditConfiguration(),
|
||||||
relatedId,
|
relatedId,
|
||||||
relatedObj
|
relatedObj
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,72 +66,84 @@ public abstract class BaseEnversEventListener implements EnversListener {
|
||||||
Object[] oldState,
|
Object[] oldState,
|
||||||
SessionImplementor session) {
|
SessionImplementor session) {
|
||||||
// Checking if this is enabled in configuration ...
|
// Checking if this is enabled in configuration ...
|
||||||
if ( ! enversConfiguration.getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
if ( !enversConfiguration.getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks every property of the entity, if it is an "owned" to-one relation to another entity.
|
// Checks every property of the entity, if it is an "owned" to-one relation to another entity.
|
||||||
// If the value of that property changed, and the relation is bi-directional, a new revision
|
// If the value of that property changed, and the relation is bi-directional, a new revision
|
||||||
// for the related entity is generated.
|
// for the related entity is generated.
|
||||||
String[] propertyNames = entityPersister.getPropertyNames();
|
final String[] propertyNames = entityPersister.getPropertyNames();
|
||||||
|
|
||||||
for ( int i=0; i<propertyNames.length; i++ ) {
|
for ( int i = 0; i < propertyNames.length; i++ ) {
|
||||||
String propertyName = propertyNames[i];
|
final String propertyName = propertyNames[i];
|
||||||
RelationDescription relDesc = enversConfiguration.getEntCfg().getRelationDescription(entityName, propertyName);
|
final RelationDescription relDesc = enversConfiguration.getEntCfg().getRelationDescription(
|
||||||
if (relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE &&
|
entityName,
|
||||||
relDesc.isInsertable()) {
|
propertyName
|
||||||
|
);
|
||||||
|
if ( relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE &&
|
||||||
|
relDesc.isInsertable() ) {
|
||||||
// Checking for changes
|
// Checking for changes
|
||||||
Object oldValue = oldState == null ? null : oldState[i];
|
final Object oldValue = oldState == null ? null : oldState[i];
|
||||||
Object newValue = newState == null ? null : newState[i];
|
final Object newValue = newState == null ? null : newState[i];
|
||||||
|
|
||||||
if (!EntityTools.entitiesEqual( session, relDesc.getToEntityName(), oldValue, newValue )) {
|
if ( !EntityTools.entitiesEqual( session, relDesc.getToEntityName(), oldValue, newValue ) ) {
|
||||||
// We have to generate changes both in the old collection (size decreses) and new collection
|
// We have to generate changes both in the old collection (size decreses) and new collection
|
||||||
// (size increases).
|
// (size increases).
|
||||||
if (newValue != null) {
|
if ( newValue != null ) {
|
||||||
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, newValue);
|
addCollectionChangeWorkUnit( auditProcess, session, entityName, relDesc, newValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldValue != null) {
|
if ( oldValue != null ) {
|
||||||
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, oldValue);
|
addCollectionChangeWorkUnit( auditProcess, session, entityName, relDesc, oldValue );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCollectionChangeWorkUnit(AuditProcess auditProcess, SessionImplementor session,
|
private void addCollectionChangeWorkUnit(
|
||||||
String fromEntityName, RelationDescription relDesc, Object value) {
|
AuditProcess auditProcess, SessionImplementor session,
|
||||||
|
String fromEntityName, RelationDescription relDesc, Object value) {
|
||||||
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case
|
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case
|
||||||
// of subclasses, this will be root class, no the actual class. So it can't be used here.
|
// of subclasses, this will be root class, no the actual class. So it can't be used here.
|
||||||
String toEntityName;
|
String toEntityName;
|
||||||
Serializable id;
|
Serializable id;
|
||||||
|
|
||||||
if (value instanceof HibernateProxy) {
|
if ( value instanceof HibernateProxy ) {
|
||||||
HibernateProxy hibernateProxy = (HibernateProxy) value;
|
final HibernateProxy hibernateProxy = (HibernateProxy) value;
|
||||||
toEntityName = session.bestGuessEntityName(value);
|
toEntityName = session.bestGuessEntityName( value );
|
||||||
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
||||||
// We've got to initialize the object from the proxy to later read its state.
|
// We've got to initialize the object from the proxy to later read its state.
|
||||||
value = EntityTools.getTargetFromProxy(session.getFactory(), hibernateProxy);
|
value = EntityTools.getTargetFromProxy( session.getFactory(), hibernateProxy );
|
||||||
} else {
|
}
|
||||||
toEntityName = session.guessEntityName(value);
|
else {
|
||||||
|
toEntityName = session.guessEntityName( value );
|
||||||
|
|
||||||
IdMapper idMapper = enversConfiguration.getEntCfg().get(toEntityName).getIdMapper();
|
final IdMapper idMapper = enversConfiguration.getEntCfg().get( toEntityName ).getIdMapper();
|
||||||
id = (Serializable) idMapper.mapToIdFromEntity(value);
|
id = (Serializable) idMapper.mapToIdFromEntity( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> toPropertyNames = enversConfiguration.getEntCfg()
|
final Set<String> toPropertyNames = enversConfiguration.getEntCfg().getToPropertyNames(
|
||||||
.getToPropertyNames(fromEntityName, relDesc.getFromPropertyName(), toEntityName);
|
fromEntityName,
|
||||||
String toPropertyName = toPropertyNames.iterator().next();
|
relDesc.getFromPropertyName(),
|
||||||
|
toEntityName
|
||||||
|
);
|
||||||
|
final String toPropertyName = toPropertyNames.iterator().next();
|
||||||
|
|
||||||
auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName,
|
auditProcess.addWorkUnit(
|
||||||
toPropertyName, enversConfiguration, id, value));
|
new CollectionChangeWorkUnit(
|
||||||
|
session, toEntityName,
|
||||||
|
toPropertyName, enversConfiguration, id, value
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkIfTransactionInProgress(SessionImplementor session) {
|
protected void checkIfTransactionInProgress(SessionImplementor session) {
|
||||||
if (!session.isTransactionInProgress()) {
|
if ( !session.isTransactionInProgress() ) {
|
||||||
// Historical data would not be flushed to audit tables if outside of active transaction
|
// Historical data would not be flushed to audit tables if outside of active transaction
|
||||||
// (AuditProcess#doBeforeTransactionCompletion(SessionImplementor) not executed).
|
// (AuditProcess#doBeforeTransactionCompletion(SessionImplementor) not executed).
|
||||||
throw new AuditException("Unable to create revision because of non-active transaction");
|
throw new AuditException( "Unable to create revision because of non-active transaction" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,15 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EnversIntegrator implements Integrator {
|
public class EnversIntegrator implements Integrator {
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, EnversIntegrator.class.getName() );
|
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||||
|
CoreMessageLogger.class,
|
||||||
|
EnversIntegrator.class.getName()
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of a configuration setting that can be used to control whether auto registration of envers listeners
|
||||||
|
* should happen or not. Default is true
|
||||||
|
*/
|
||||||
public static final String AUTO_REGISTER = "hibernate.listeners.envers.autoRegister";
|
public static final String AUTO_REGISTER = "hibernate.listeners.envers.autoRegister";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,25 +59,55 @@ public class EnversIntegrator implements Integrator {
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
SessionFactoryServiceRegistry serviceRegistry) {
|
SessionFactoryServiceRegistry serviceRegistry) {
|
||||||
final boolean autoRegister = ConfigurationHelper.getBoolean( AUTO_REGISTER, configuration.getProperties(), true );
|
final boolean autoRegister = ConfigurationHelper.getBoolean(
|
||||||
|
AUTO_REGISTER,
|
||||||
|
configuration.getProperties(),
|
||||||
|
true
|
||||||
|
);
|
||||||
if ( !autoRegister ) {
|
if ( !autoRegister ) {
|
||||||
LOG.debug( "Skipping Envers listener auto registration" );
|
LOG.debug( "Skipping Envers listener auto registration" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
|
final EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
|
||||||
listenerRegistry.addDuplicationStrategy( EnversListenerDuplicationStrategy.INSTANCE );
|
listenerRegistry.addDuplicationStrategy( EnversListenerDuplicationStrategy.INSTANCE );
|
||||||
|
|
||||||
final AuditConfiguration enversConfiguration = AuditConfiguration.getFor( configuration, serviceRegistry.getService( ClassLoaderService.class ) );
|
final AuditConfiguration enversConfiguration = AuditConfiguration.getFor(
|
||||||
|
configuration,
|
||||||
|
serviceRegistry.getService(
|
||||||
|
ClassLoaderService.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if (enversConfiguration.getEntCfg().hasAuditedEntities()) {
|
if ( enversConfiguration.getEntCfg().hasAuditedEntities() ) {
|
||||||
listenerRegistry.appendListeners( EventType.POST_DELETE, new EnversPostDeleteEventListenerImpl( enversConfiguration ) );
|
listenerRegistry.appendListeners(
|
||||||
listenerRegistry.appendListeners( EventType.POST_INSERT, new EnversPostInsertEventListenerImpl( enversConfiguration ) );
|
EventType.POST_DELETE, new EnversPostDeleteEventListenerImpl(
|
||||||
listenerRegistry.appendListeners( EventType.POST_UPDATE, new EnversPostUpdateEventListenerImpl( enversConfiguration ) );
|
enversConfiguration
|
||||||
listenerRegistry.appendListeners( EventType.POST_COLLECTION_RECREATE, new EnversPostCollectionRecreateEventListenerImpl( enversConfiguration ) );
|
)
|
||||||
listenerRegistry.appendListeners( EventType.PRE_COLLECTION_REMOVE, new EnversPreCollectionRemoveEventListenerImpl( enversConfiguration ) );
|
);
|
||||||
listenerRegistry.appendListeners( EventType.PRE_COLLECTION_UPDATE, new EnversPreCollectionUpdateEventListenerImpl( enversConfiguration ) );
|
listenerRegistry.appendListeners(
|
||||||
}
|
EventType.POST_INSERT, new EnversPostInsertEventListenerImpl(
|
||||||
|
enversConfiguration
|
||||||
|
)
|
||||||
|
);
|
||||||
|
listenerRegistry.appendListeners(
|
||||||
|
EventType.POST_UPDATE, new EnversPostUpdateEventListenerImpl(
|
||||||
|
enversConfiguration
|
||||||
|
)
|
||||||
|
);
|
||||||
|
listenerRegistry.appendListeners(
|
||||||
|
EventType.POST_COLLECTION_RECREATE,
|
||||||
|
new EnversPostCollectionRecreateEventListenerImpl( enversConfiguration )
|
||||||
|
);
|
||||||
|
listenerRegistry.appendListeners(
|
||||||
|
EventType.PRE_COLLECTION_REMOVE,
|
||||||
|
new EnversPreCollectionRemoveEventListenerImpl( enversConfiguration )
|
||||||
|
);
|
||||||
|
listenerRegistry.appendListeners(
|
||||||
|
EventType.PRE_COLLECTION_UPDATE,
|
||||||
|
new EnversPreCollectionUpdateEventListenerImpl( enversConfiguration )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,9 +121,10 @@ public class EnversIntegrator implements Integrator {
|
||||||
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry)
|
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void integrate( MetadataImplementor metadata,
|
public void integrate(
|
||||||
SessionFactoryImplementor sessionFactory,
|
MetadataImplementor metadata,
|
||||||
SessionFactoryServiceRegistry serviceRegistry ) {
|
SessionFactoryImplementor sessionFactory,
|
||||||
// TODO: implement
|
SessionFactoryServiceRegistry serviceRegistry) {
|
||||||
|
// TODO: implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,5 +31,10 @@ import org.hibernate.envers.configuration.spi.AuditConfiguration;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface EnversListener {
|
public interface EnversListener {
|
||||||
|
/**
|
||||||
|
* Get the Envers AuditConfiguration
|
||||||
|
*
|
||||||
|
* @return The Envers AuditConfiguration
|
||||||
|
*/
|
||||||
public AuditConfiguration getAuditConfiguration();
|
public AuditConfiguration getAuditConfiguration();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,9 @@ import org.hibernate.event.service.spi.DuplicationStrategy;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EnversListenerDuplicationStrategy implements DuplicationStrategy {
|
public class EnversListenerDuplicationStrategy implements DuplicationStrategy {
|
||||||
|
/**
|
||||||
|
* Singleton access
|
||||||
|
*/
|
||||||
public static final EnversListenerDuplicationStrategy INSTANCE = new EnversListenerDuplicationStrategy();
|
public static final EnversListenerDuplicationStrategy INSTANCE = new EnversListenerDuplicationStrategy();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -29,12 +29,14 @@ import org.hibernate.event.spi.PostCollectionRecreateEvent;
|
||||||
import org.hibernate.event.spi.PostCollectionRecreateEventListener;
|
import org.hibernate.event.spi.PostCollectionRecreateEventListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Envers-specific collection recreation event listener
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author HernпїЅn Chanfreau
|
* @author HernпїЅn Chanfreau
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EnversPostCollectionRecreateEventListenerImpl
|
public class EnversPostCollectionRecreateEventListenerImpl
|
||||||
extends BaseEnversCollectionEventListener
|
extends BaseEnversCollectionEventListener
|
||||||
implements PostCollectionRecreateEventListener {
|
implements PostCollectionRecreateEventListener {
|
||||||
|
|
||||||
protected EnversPostCollectionRecreateEventListenerImpl(AuditConfiguration enversConfiguration) {
|
protected EnversPostCollectionRecreateEventListenerImpl(AuditConfiguration enversConfiguration) {
|
||||||
|
@ -43,9 +45,9 @@ public class EnversPostCollectionRecreateEventListenerImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
|
public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
|
||||||
CollectionEntry collectionEntry = getCollectionEntry( event );
|
final CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||||
if ( ! collectionEntry.getLoadedPersister().isInverse() ) {
|
if ( !collectionEntry.getLoadedPersister().isInverse() ) {
|
||||||
onCollectionAction( event, event.getCollection(), null, collectionEntry );
|
onCollectionAction( event, event.getCollection(), null, collectionEntry );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.event.spi.PostDeleteEventListener;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Envers-specific entity (post) deletion event listener
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author HernпїЅn Chanfreau
|
* @author HernпїЅn Chanfreau
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -43,30 +45,30 @@ public class EnversPostDeleteEventListenerImpl extends BaseEnversEventListener i
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostDelete(PostDeleteEvent event) {
|
public void onPostDelete(PostDeleteEvent event) {
|
||||||
String entityName = event.getPersister().getEntityName();
|
final String entityName = event.getPersister().getEntityName();
|
||||||
|
|
||||||
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||||
checkIfTransactionInProgress(event.getSession());
|
checkIfTransactionInProgress( event.getSession() );
|
||||||
|
|
||||||
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
|
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
|
||||||
|
|
||||||
AuditWorkUnit workUnit = new DelWorkUnit(
|
final AuditWorkUnit workUnit = new DelWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
event.getPersister().getEntityName(),
|
event.getPersister().getEntityName(),
|
||||||
getAuditConfiguration(),
|
getAuditConfiguration(),
|
||||||
event.getId(),
|
event.getId(),
|
||||||
event.getPersister(),
|
event.getPersister(),
|
||||||
event.getDeletedState()
|
event.getDeletedState()
|
||||||
);
|
);
|
||||||
auditProcess.addWorkUnit( workUnit );
|
auditProcess.addWorkUnit( workUnit );
|
||||||
|
|
||||||
if ( workUnit.containsWork() ) {
|
if ( workUnit.containsWork() ) {
|
||||||
generateBidirectionalCollectionChangeWorkUnits(
|
generateBidirectionalCollectionChangeWorkUnits(
|
||||||
auditProcess,
|
auditProcess,
|
||||||
event.getPersister(),
|
event.getPersister(),
|
||||||
entityName,
|
entityName,
|
||||||
null,
|
null,
|
||||||
event.getDeletedState(),
|
event.getDeletedState(),
|
||||||
event.getSession()
|
event.getSession()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,44 +32,47 @@ import org.hibernate.event.spi.PostInsertEventListener;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Envers-specific entity (post) insertion event listener
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author HernпїЅn Chanfreau
|
* @author HernпїЅn Chanfreau
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EnversPostInsertEventListenerImpl extends BaseEnversEventListener implements PostInsertEventListener {
|
public class EnversPostInsertEventListenerImpl extends BaseEnversEventListener implements PostInsertEventListener {
|
||||||
public EnversPostInsertEventListenerImpl(AuditConfiguration enversConfiguration) {
|
protected EnversPostInsertEventListenerImpl(AuditConfiguration enversConfiguration) {
|
||||||
super( enversConfiguration );
|
super( enversConfiguration );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPostInsert(PostInsertEvent event) {
|
@Override
|
||||||
String entityName = event.getPersister().getEntityName();
|
public void onPostInsert(PostInsertEvent event) {
|
||||||
|
final String entityName = event.getPersister().getEntityName();
|
||||||
|
|
||||||
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||||
checkIfTransactionInProgress(event.getSession());
|
checkIfTransactionInProgress( event.getSession() );
|
||||||
|
|
||||||
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
|
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
|
||||||
|
|
||||||
AuditWorkUnit workUnit = new AddWorkUnit(
|
final AuditWorkUnit workUnit = new AddWorkUnit(
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
event.getPersister().getEntityName(),
|
event.getPersister().getEntityName(),
|
||||||
getAuditConfiguration(),
|
getAuditConfiguration(),
|
||||||
event.getId(),
|
event.getId(),
|
||||||
event.getPersister(),
|
event.getPersister(),
|
||||||
event.getState()
|
event.getState()
|
||||||
);
|
);
|
||||||
auditProcess.addWorkUnit( workUnit );
|
auditProcess.addWorkUnit( workUnit );
|
||||||
|
|
||||||
if ( workUnit.containsWork() ) {
|
if ( workUnit.containsWork() ) {
|
||||||
generateBidirectionalCollectionChangeWorkUnits(
|
generateBidirectionalCollectionChangeWorkUnits(
|
||||||
auditProcess,
|
auditProcess,
|
||||||
event.getPersister(),
|
event.getPersister(),
|
||||||
entityName,
|
entityName,
|
||||||
event.getState(),
|
event.getState(),
|
||||||
null,
|
null,
|
||||||
event.getSession()
|
event.getSession()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.event.spi.PostUpdateEventListener;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Envers-specific entity (post) update event listener
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author HernпїЅn Chanfreau
|
* @author HernпїЅn Chanfreau
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -43,43 +45,41 @@ public class EnversPostUpdateEventListenerImpl extends BaseEnversEventListener i
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostUpdate(PostUpdateEvent event) {
|
public void onPostUpdate(PostUpdateEvent event) {
|
||||||
String entityName = event.getPersister().getEntityName();
|
final String entityName = event.getPersister().getEntityName();
|
||||||
|
|
||||||
if ( getAuditConfiguration().getEntCfg().isVersioned(entityName) ) {
|
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||||
checkIfTransactionInProgress(event.getSession());
|
checkIfTransactionInProgress( event.getSession() );
|
||||||
|
|
||||||
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
|
|
||||||
|
|
||||||
|
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
|
||||||
final Object[] newDbState = postUpdateDBState( event );
|
final Object[] newDbState = postUpdateDBState( event );
|
||||||
|
final AuditWorkUnit workUnit = new ModWorkUnit(
|
||||||
AuditWorkUnit workUnit = new ModWorkUnit(
|
|
||||||
event.getSession(),
|
event.getSession(),
|
||||||
event.getPersister().getEntityName(),
|
event.getPersister().getEntityName(),
|
||||||
getAuditConfiguration(),
|
getAuditConfiguration(),
|
||||||
event.getId(),
|
event.getId(),
|
||||||
event.getPersister(),
|
event.getPersister(),
|
||||||
newDbState,
|
newDbState,
|
||||||
event.getOldState()
|
event.getOldState()
|
||||||
);
|
);
|
||||||
auditProcess.addWorkUnit( workUnit );
|
auditProcess.addWorkUnit( workUnit );
|
||||||
|
|
||||||
if ( workUnit.containsWork() ) {
|
if ( workUnit.containsWork() ) {
|
||||||
generateBidirectionalCollectionChangeWorkUnits(
|
generateBidirectionalCollectionChangeWorkUnits(
|
||||||
auditProcess,
|
auditProcess,
|
||||||
event.getPersister(),
|
event.getPersister(),
|
||||||
entityName,
|
entityName,
|
||||||
newDbState,
|
newDbState,
|
||||||
event.getOldState(),
|
event.getOldState(),
|
||||||
event.getSession()
|
event.getSession()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object[] postUpdateDBState(PostUpdateEvent event) {
|
private Object[] postUpdateDBState(PostUpdateEvent event) {
|
||||||
Object[] newDbState = event.getState().clone();
|
final Object[] newDbState = event.getState().clone();
|
||||||
if ( event.getOldState() != null ) {
|
if ( event.getOldState() != null ) {
|
||||||
EntityPersister entityPersister = event.getPersister();
|
final EntityPersister entityPersister = event.getPersister();
|
||||||
for ( int i = 0; i < entityPersister.getPropertyNames().length; ++i ) {
|
for ( int i = 0; i < entityPersister.getPropertyNames().length; ++i ) {
|
||||||
if ( !entityPersister.getPropertyUpdateability()[i] ) {
|
if ( !entityPersister.getPropertyUpdateability()[i] ) {
|
||||||
// Assuming that PostUpdateEvent#getOldState() returns database state of the record before modification.
|
// Assuming that PostUpdateEvent#getOldState() returns database state of the record before modification.
|
||||||
|
|
|
@ -31,6 +31,8 @@ import org.hibernate.event.spi.PreCollectionRemoveEvent;
|
||||||
import org.hibernate.event.spi.PreCollectionRemoveEventListener;
|
import org.hibernate.event.spi.PreCollectionRemoveEventListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Envers-specific collection removal event listener
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author HernпїЅn Chanfreau
|
* @author HernпїЅn Chanfreau
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -46,14 +48,14 @@ public class EnversPreCollectionRemoveEventListenerImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPreRemoveCollection(PreCollectionRemoveEvent event) {
|
public void onPreRemoveCollection(PreCollectionRemoveEvent event) {
|
||||||
CollectionEntry collectionEntry = getCollectionEntry( event );
|
final CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||||
if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) {
|
if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) {
|
||||||
Serializable oldColl = collectionEntry.getSnapshot();
|
Serializable oldColl = collectionEntry.getSnapshot();
|
||||||
if ( !event.getCollection().wasInitialized() && shouldGenerateRevision( event ) ) {
|
if ( !event.getCollection().wasInitialized() && shouldGenerateRevision( event ) ) {
|
||||||
// In case of uninitialized collection we need a fresh snapshot to properly calculate audit data.
|
// In case of uninitialized collection we need a fresh snapshot to properly calculate audit data.
|
||||||
oldColl = initializeCollection( event );
|
oldColl = initializeCollection( event );
|
||||||
}
|
}
|
||||||
onCollectionAction( event, null, oldColl, collectionEntry );
|
onCollectionAction( event, null, oldColl, collectionEntry );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ import org.hibernate.event.spi.PreCollectionUpdateEvent;
|
||||||
import org.hibernate.event.spi.PreCollectionUpdateEventListener;
|
import org.hibernate.event.spi.PreCollectionUpdateEventListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Envers-specific collection update event listener
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author HernпїЅn Chanfreau
|
* @author HernпїЅn Chanfreau
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -43,9 +45,9 @@ public class EnversPreCollectionUpdateEventListenerImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
|
public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
|
||||||
CollectionEntry collectionEntry = getCollectionEntry( event );
|
final CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||||
if ( ! collectionEntry.getLoadedPersister().isInverse() ) {
|
if ( !collectionEntry.getLoadedPersister().isInverse() ) {
|
||||||
onCollectionAction( event, event.getCollection(), collectionEntry.getSnapshot(), collectionEntry );
|
onCollectionAction( event, event.getCollection(), collectionEntry.getSnapshot(), collectionEntry );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.exception;
|
package org.hibernate.envers.exception;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,14 +32,14 @@ public class AuditException extends HibernateException {
|
||||||
private static final long serialVersionUID = 4306480965630972168L;
|
private static final long serialVersionUID = 4306480965630972168L;
|
||||||
|
|
||||||
public AuditException(String message) {
|
public AuditException(String message) {
|
||||||
super(message);
|
super( message );
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuditException(String message, Throwable cause) {
|
public AuditException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super( message, cause );
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuditException(Throwable cause) {
|
public AuditException(Throwable cause) {
|
||||||
super(cause);
|
super( cause );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -29,15 +29,15 @@ package org.hibernate.envers.exception;
|
||||||
*/
|
*/
|
||||||
public class NotAuditedException extends AuditException {
|
public class NotAuditedException extends AuditException {
|
||||||
private static final long serialVersionUID = 4809674577449455510L;
|
private static final long serialVersionUID = 4809674577449455510L;
|
||||||
|
|
||||||
private final String entityName;
|
private final String entityName;
|
||||||
|
|
||||||
public NotAuditedException(String entityName, String message) {
|
public NotAuditedException(String entityName, String message) {
|
||||||
super(message);
|
super( message );
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEntityName() {
|
public String getEntityName() {
|
||||||
return entityName;
|
return entityName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.exception;
|
package org.hibernate.envers.exception;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,25 +30,27 @@ import java.util.Date;
|
||||||
*/
|
*/
|
||||||
public class RevisionDoesNotExistException extends AuditException {
|
public class RevisionDoesNotExistException extends AuditException {
|
||||||
private static final long serialVersionUID = -6417768274074962282L;
|
private static final long serialVersionUID = -6417768274074962282L;
|
||||||
|
|
||||||
private Number revision;
|
private final Number revision;
|
||||||
private Date date;
|
private final Date date;
|
||||||
|
|
||||||
public RevisionDoesNotExistException(Number revision) {
|
public RevisionDoesNotExistException(Number revision) {
|
||||||
super("Revision " + revision + " does not exist.");
|
super( "Revision " + revision + " does not exist." );
|
||||||
this.revision = revision;
|
this.revision = revision;
|
||||||
}
|
this.date = null;
|
||||||
|
}
|
||||||
|
|
||||||
public RevisionDoesNotExistException(Date date) {
|
public RevisionDoesNotExistException(Date date) {
|
||||||
super("There is no revision before or at " + date + ".");
|
super( "There is no revision before or at " + date + "." );
|
||||||
this.date = date;
|
this.date = date;
|
||||||
}
|
this.revision = null;
|
||||||
|
}
|
||||||
|
|
||||||
public Number getRevision() {
|
public Number getRevision() {
|
||||||
return revision;
|
return revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getDate() {
|
public Date getDate() {
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -37,10 +37,13 @@ import static org.jboss.logging.Logger.Level.WARN;
|
||||||
* <p/>
|
* <p/>
|
||||||
* New messages must be added after the last message defined to ensure message codes are unique.
|
* New messages must be added after the last message defined to ensure message codes are unique.
|
||||||
*/
|
*/
|
||||||
@MessageLogger( projectCode = "HHH" )
|
@MessageLogger(projectCode = "HHH")
|
||||||
public interface EnversMessageLogger extends CoreMessageLogger {
|
public interface EnversMessageLogger extends CoreMessageLogger {
|
||||||
|
|
||||||
@LogMessage( level = WARN )
|
/**
|
||||||
@Message( value = "ValidTimeAuditStrategy is deprecated, please use ValidityAuditStrategy instead", id = 25001 )
|
* Message indicating that user attempted to use the deprecated ValidTimeAuditStrategy
|
||||||
void validTimeAuditStrategyDeprecated();
|
*/
|
||||||
|
@LogMessage(level = WARN)
|
||||||
|
@Message(value = "ValidTimeAuditStrategy is deprecated, please use ValidityAuditStrategy instead", id = 25001)
|
||||||
|
void validTimeAuditStrategyDeprecated();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities;
|
package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -31,129 +32,136 @@ import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration of the user entities: property mapping of the entities, relations, inheritance.
|
* Configuration of the user entities: property mapping of the entities, relations, inheritance.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Hernán Chanfreau
|
* @author Hernán Chanfreau
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public class EntitiesConfigurations {
|
public class EntitiesConfigurations {
|
||||||
private Map<String, EntityConfiguration> entitiesConfigurations;
|
private Map<String, EntityConfiguration> entitiesConfigurations;
|
||||||
private Map<String, EntityConfiguration> notAuditedEntitiesConfigurations;
|
private Map<String, EntityConfiguration> notAuditedEntitiesConfigurations;
|
||||||
|
|
||||||
// Map versions entity name -> entity name
|
// Map versions entity name -> entity name
|
||||||
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
||||||
|
|
||||||
public EntitiesConfigurations(Map<String, EntityConfiguration> entitiesConfigurations,
|
public EntitiesConfigurations(
|
||||||
Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) {
|
Map<String, EntityConfiguration> entitiesConfigurations,
|
||||||
this.entitiesConfigurations = entitiesConfigurations;
|
Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) {
|
||||||
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
|
this.entitiesConfigurations = entitiesConfigurations;
|
||||||
|
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
|
||||||
|
|
||||||
generateBidirectionRelationInfo();
|
generateBidirectionRelationInfo();
|
||||||
generateVersionsEntityToEntityNames();
|
generateVersionsEntityToEntityNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateVersionsEntityToEntityNames() {
|
private void generateVersionsEntityToEntityNames() {
|
||||||
entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
||||||
|
|
||||||
for (String entityName : entitiesConfigurations.keySet()) {
|
for ( String entityName : entitiesConfigurations.keySet() ) {
|
||||||
entityNamesForVersionsEntityNames.put(entitiesConfigurations.get(entityName).getVersionsEntityName(),
|
entityNamesForVersionsEntityNames.put(
|
||||||
entityName);
|
entitiesConfigurations.get( entityName ).getVersionsEntityName(),
|
||||||
}
|
entityName
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void generateBidirectionRelationInfo() {
|
private void generateBidirectionRelationInfo() {
|
||||||
// Checking each relation if it is bidirectional. If so, storing that information.
|
// Checking each relation if it is bidirectional. If so, storing that information.
|
||||||
for (String entityName : entitiesConfigurations.keySet()) {
|
for ( String entityName : entitiesConfigurations.keySet() ) {
|
||||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||||
// Iterating over all relations from that entity
|
// Iterating over all relations from that entity
|
||||||
for (RelationDescription relDesc : entCfg.getRelationsIterator()) {
|
for ( RelationDescription relDesc : entCfg.getRelationsIterator() ) {
|
||||||
// If this is an "owned" relation, checking the related entity, if it has a relation that has
|
// If this is an "owned" relation, checking the related entity, if it has a relation that has
|
||||||
// a mapped-by attribute to the currently checked. If so, this is a bidirectional relation.
|
// a mapped-by attribute to the currently checked. If so, this is a bidirectional relation.
|
||||||
if (relDesc.getRelationType() == RelationType.TO_ONE ||
|
if ( relDesc.getRelationType() == RelationType.TO_ONE ||
|
||||||
relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) {
|
relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE ) {
|
||||||
EntityConfiguration entityConfiguration = entitiesConfigurations.get(relDesc.getToEntityName());
|
final EntityConfiguration entityConfiguration = entitiesConfigurations.get( relDesc.getToEntityName() );
|
||||||
if (entityConfiguration != null) {
|
if ( entityConfiguration != null ) {
|
||||||
for (RelationDescription other : entityConfiguration.getRelationsIterator()) {
|
for ( RelationDescription other : entityConfiguration.getRelationsIterator() ) {
|
||||||
if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
|
if ( relDesc.getFromPropertyName().equals( other.getMappedByPropertyName() ) &&
|
||||||
(entityName.equals(other.getToEntityName()))) {
|
(entityName.equals( other.getToEntityName() )) ) {
|
||||||
relDesc.setBidirectional(true);
|
relDesc.setBidirectional( true );
|
||||||
other.setBidirectional(true);
|
other.setBidirectional( true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityConfiguration get(String entityName) {
|
public EntityConfiguration get(String entityName) {
|
||||||
return entitiesConfigurations.get(entityName);
|
return entitiesConfigurations.get( entityName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityConfiguration getNotVersionEntityConfiguration(String entityName) {
|
public EntityConfiguration getNotVersionEntityConfiguration(String entityName) {
|
||||||
return notAuditedEntitiesConfigurations.get(entityName);
|
return notAuditedEntitiesConfigurations.get( entityName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEntityNameForVersionsEntityName(String versionsEntityName) {
|
public String getEntityNameForVersionsEntityName(String versionsEntityName) {
|
||||||
return entityNamesForVersionsEntityNames.get(versionsEntityName);
|
return entityNamesForVersionsEntityNames.get( versionsEntityName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVersioned(String entityName) {
|
public boolean isVersioned(String entityName) {
|
||||||
return get(entityName) != null;
|
return get( entityName ) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasAuditedEntities() {
|
public boolean hasAuditedEntities() {
|
||||||
return entitiesConfigurations.size() != 0;
|
return entitiesConfigurations.size() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RelationDescription getRelationDescription(String entityName, String propertyName) {
|
public RelationDescription getRelationDescription(String entityName, String propertyName) {
|
||||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||||
RelationDescription relDesc = entCfg.getRelationDescription(propertyName);
|
final RelationDescription relDesc = entCfg.getRelationDescription( propertyName );
|
||||||
if (relDesc != null) {
|
if ( relDesc != null ) {
|
||||||
return relDesc;
|
return relDesc;
|
||||||
} else if (entCfg.getParentEntityName() != null) {
|
}
|
||||||
// The field may be declared in a superclass ...
|
else if ( entCfg.getParentEntityName() != null ) {
|
||||||
return getRelationDescription(entCfg.getParentEntityName(), propertyName);
|
// The field may be declared in a superclass ...
|
||||||
} else {
|
return getRelationDescription( entCfg.getParentEntityName(), propertyName );
|
||||||
return null;
|
}
|
||||||
}
|
else {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Collection<RelationDescription> getRelationDescriptions(String entityName) {
|
private Collection<RelationDescription> getRelationDescriptions(String entityName) {
|
||||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||||
Collection<RelationDescription> descriptions = new ArrayList<RelationDescription>();
|
Collection<RelationDescription> descriptions = new ArrayList<RelationDescription>();
|
||||||
if (entCfg.getParentEntityName() != null) {
|
if ( entCfg.getParentEntityName() != null ) {
|
||||||
// collect descriptions from super classes
|
// collect descriptions from super classes
|
||||||
descriptions.addAll(getRelationDescriptions(entCfg.getParentEntityName()));
|
descriptions.addAll( getRelationDescriptions( entCfg.getParentEntityName() ) );
|
||||||
}
|
}
|
||||||
for (RelationDescription relationDescription : entCfg.getRelationsIterator()) {
|
for ( RelationDescription relationDescription : entCfg.getRelationsIterator() ) {
|
||||||
descriptions.add(relationDescription);
|
descriptions.add( relationDescription );
|
||||||
}
|
}
|
||||||
return descriptions;
|
return descriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
|
private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
|
||||||
entityNames.add(entityName);
|
entityNames.add( entityName );
|
||||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||||
if (entCfg.getParentEntityName() != null) {
|
if ( entCfg.getParentEntityName() != null ) {
|
||||||
// collect descriptions from super classes
|
// collect descriptions from super classes
|
||||||
addWithParentEntityNames(entCfg.getParentEntityName(), entityNames);
|
addWithParentEntityNames( entCfg.getParentEntityName(), entityNames );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> getEntityAndParentsNames(String entityName) {
|
private Set<String> getEntityAndParentsNames(String entityName) {
|
||||||
Set<String> names = new HashSet<String>();
|
final Set<String> names = new HashSet<String>();
|
||||||
addWithParentEntityNames(entityName, names);
|
addWithParentEntityNames( entityName, names );
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getToPropertyNames(String fromEntityName, String fromPropertyName, String toEntityName) {
|
public Set<String> getToPropertyNames(String fromEntityName, String fromPropertyName, String toEntityName) {
|
||||||
Set<String> entityAndParentsNames = getEntityAndParentsNames(fromEntityName);
|
final Set<String> entityAndParentsNames = getEntityAndParentsNames( fromEntityName );
|
||||||
Set<String> toPropertyNames = new HashSet<String>();
|
final Set<String> toPropertyNames = new HashSet<String>();
|
||||||
for (RelationDescription relationDescription : getRelationDescriptions(toEntityName)) {
|
for ( RelationDescription relationDescription : getRelationDescriptions( toEntityName ) ) {
|
||||||
String relToEntityName = relationDescription.getToEntityName();
|
final String relToEntityName = relationDescription.getToEntityName();
|
||||||
String mappedByPropertyName = relationDescription.getMappedByPropertyName();
|
final String mappedByPropertyName = relationDescription.getMappedByPropertyName();
|
||||||
if (entityAndParentsNames.contains(relToEntityName) && mappedByPropertyName != null && mappedByPropertyName.equals(fromPropertyName)) {
|
if ( entityAndParentsNames.contains( relToEntityName ) && mappedByPropertyName != null && mappedByPropertyName
|
||||||
toPropertyNames.add(relationDescription.getFromPropertyName());
|
.equals( fromPropertyName ) ) {
|
||||||
|
toPropertyNames.add( relationDescription.getFromPropertyName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return toPropertyNames;
|
return toPropertyNames;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities;
|
package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -34,93 +35,160 @@ import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||||
* @author HernпїЅn Chanfreau
|
* @author HernпїЅn Chanfreau
|
||||||
*/
|
*/
|
||||||
public class EntityConfiguration {
|
public class EntityConfiguration {
|
||||||
private String versionsEntityName;
|
private String versionsEntityName;
|
||||||
/** Holds the className for instantiation the configured entity */
|
/**
|
||||||
private String entityClassName;
|
* Holds the className for instantiation the configured entity
|
||||||
|
*/
|
||||||
|
private String entityClassName;
|
||||||
private IdMappingData idMappingData;
|
private IdMappingData idMappingData;
|
||||||
private ExtendedPropertyMapper propertyMapper;
|
private ExtendedPropertyMapper propertyMapper;
|
||||||
// Maps from property name
|
// Maps from property name
|
||||||
private Map<String, RelationDescription> relations;
|
private Map<String, RelationDescription> relations;
|
||||||
private String parentEntityName;
|
private String parentEntityName;
|
||||||
|
|
||||||
public EntityConfiguration(String versionsEntityName, String entityClassName, IdMappingData idMappingData,
|
public EntityConfiguration(
|
||||||
ExtendedPropertyMapper propertyMapper, String parentEntityName) {
|
String versionsEntityName, String entityClassName, IdMappingData idMappingData,
|
||||||
this.versionsEntityName = versionsEntityName;
|
ExtendedPropertyMapper propertyMapper, String parentEntityName) {
|
||||||
this.entityClassName = entityClassName;
|
this.versionsEntityName = versionsEntityName;
|
||||||
this.idMappingData = idMappingData;
|
this.entityClassName = entityClassName;
|
||||||
this.propertyMapper = propertyMapper;
|
this.idMappingData = idMappingData;
|
||||||
this.parentEntityName = parentEntityName;
|
this.propertyMapper = propertyMapper;
|
||||||
|
this.parentEntityName = parentEntityName;
|
||||||
|
|
||||||
this.relations = new HashMap<String, RelationDescription>();
|
this.relations = new HashMap<String, RelationDescription>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable) {
|
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable) {
|
||||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE,
|
relations.put(
|
||||||
toEntityName, null, idMapper, null, null, insertable));
|
fromPropertyName,
|
||||||
}
|
new RelationDescription(
|
||||||
|
fromPropertyName,
|
||||||
|
RelationType.TO_ONE,
|
||||||
|
toEntityName,
|
||||||
|
null,
|
||||||
|
idMapper,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
insertable
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void addToOneNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
|
public void addToOneNotOwningRelation(
|
||||||
IdMapper idMapper) {
|
String fromPropertyName,
|
||||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE_NOT_OWNING,
|
String mappedByPropertyName,
|
||||||
toEntityName, mappedByPropertyName, idMapper, null, null, true));
|
String toEntityName,
|
||||||
}
|
IdMapper idMapper) {
|
||||||
|
relations.put(
|
||||||
|
fromPropertyName,
|
||||||
|
new RelationDescription(
|
||||||
|
fromPropertyName,
|
||||||
|
RelationType.TO_ONE_NOT_OWNING,
|
||||||
|
toEntityName,
|
||||||
|
mappedByPropertyName,
|
||||||
|
idMapper,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void addToManyNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
|
public void addToManyNotOwningRelation(
|
||||||
IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper,
|
String fromPropertyName,
|
||||||
PropertyMapper fakeBidirectionalRelationIndexMapper) {
|
String mappedByPropertyName,
|
||||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_NOT_OWNING,
|
String toEntityName,
|
||||||
toEntityName, mappedByPropertyName, idMapper, fakeBidirectionalRelationMapper,
|
IdMapper idMapper,
|
||||||
fakeBidirectionalRelationIndexMapper, true));
|
PropertyMapper fakeBidirectionalRelationMapper,
|
||||||
}
|
PropertyMapper fakeBidirectionalRelationIndexMapper) {
|
||||||
|
relations.put(
|
||||||
|
fromPropertyName,
|
||||||
|
new RelationDescription(
|
||||||
|
fromPropertyName,
|
||||||
|
RelationType.TO_MANY_NOT_OWNING,
|
||||||
|
toEntityName,
|
||||||
|
mappedByPropertyName,
|
||||||
|
idMapper,
|
||||||
|
fakeBidirectionalRelationMapper,
|
||||||
|
fakeBidirectionalRelationIndexMapper,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) {
|
public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) {
|
||||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE,
|
relations.put(
|
||||||
toEntityName, null, null, null, null, true));
|
fromPropertyName,
|
||||||
}
|
new RelationDescription(
|
||||||
|
fromPropertyName,
|
||||||
|
RelationType.TO_MANY_MIDDLE,
|
||||||
|
toEntityName,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void addToManyMiddleNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName) {
|
public void addToManyMiddleNotOwningRelation(
|
||||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE_NOT_OWNING,
|
String fromPropertyName,
|
||||||
toEntityName, mappedByPropertyName, null, null, null, true));
|
String mappedByPropertyName,
|
||||||
}
|
String toEntityName) {
|
||||||
|
relations.put(
|
||||||
|
fromPropertyName,
|
||||||
|
new RelationDescription(
|
||||||
|
fromPropertyName,
|
||||||
|
RelationType.TO_MANY_MIDDLE_NOT_OWNING,
|
||||||
|
toEntityName,
|
||||||
|
mappedByPropertyName,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRelation(String propertyName) {
|
public boolean isRelation(String propertyName) {
|
||||||
return relations.get(propertyName) != null;
|
return relations.get( propertyName ) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RelationDescription getRelationDescription(String propertyName) {
|
|
||||||
return relations.get(propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IdMappingData getIdMappingData() {
|
public RelationDescription getRelationDescription(String propertyName) {
|
||||||
return idMappingData;
|
return relations.get( propertyName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdMapper getIdMapper() {
|
public IdMappingData getIdMappingData() {
|
||||||
return idMappingData.getIdMapper();
|
return idMappingData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExtendedPropertyMapper getPropertyMapper() {
|
public IdMapper getIdMapper() {
|
||||||
return propertyMapper;
|
return idMappingData.getIdMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParentEntityName() {
|
public ExtendedPropertyMapper getPropertyMapper() {
|
||||||
return parentEntityName;
|
return propertyMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use by EntitiesConfigurations
|
public String getParentEntityName() {
|
||||||
|
return parentEntityName;
|
||||||
|
}
|
||||||
|
|
||||||
String getVersionsEntityName() {
|
// For use by EntitiesConfigurations
|
||||||
return versionsEntityName;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterable<RelationDescription> getRelationsIterator() {
|
String getVersionsEntityName() {
|
||||||
return relations.values();
|
return versionsEntityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
Iterable<RelationDescription> getRelationsIterator() {
|
||||||
* @return the className for the configured entity
|
return relations.values();
|
||||||
*/
|
}
|
||||||
public String getEntityClassName() {
|
|
||||||
|
/**
|
||||||
|
* @return the className for the configured entity
|
||||||
|
*/
|
||||||
|
public String getEntityClassName() {
|
||||||
return entityClassName;
|
return entityClassName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -44,109 +44,136 @@ import org.hibernate.proxy.LazyInitializer;
|
||||||
* @author Hernán Chanfreau
|
* @author Hernán Chanfreau
|
||||||
*/
|
*/
|
||||||
public class EntityInstantiator {
|
public class EntityInstantiator {
|
||||||
private final AuditConfiguration verCfg;
|
private final AuditConfiguration verCfg;
|
||||||
private final AuditReaderImplementor versionsReader;
|
private final AuditReaderImplementor versionsReader;
|
||||||
|
|
||||||
public EntityInstantiator(AuditConfiguration verCfg, AuditReaderImplementor versionsReader) {
|
public EntityInstantiator(AuditConfiguration verCfg, AuditReaderImplementor versionsReader) {
|
||||||
this.verCfg = verCfg;
|
this.verCfg = verCfg;
|
||||||
this.versionsReader = versionsReader;
|
this.versionsReader = versionsReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an entity instance based on an entry from the versions table.
|
* Creates an entity instance based on an entry from the versions table.
|
||||||
* @param entityName Name of the entity, which instances should be read
|
*
|
||||||
* @param versionsEntity An entry in the versions table, from which data should be mapped.
|
* @param entityName Name of the entity, which instances should be read
|
||||||
* @param revision Revision at which this entity was read.
|
* @param versionsEntity An entry in the versions table, from which data should be mapped.
|
||||||
* @return An entity instance, with versioned properties set as in the versionsEntity map, and proxies
|
* @param revision Revision at which this entity was read.
|
||||||
* created for collections.
|
*
|
||||||
*/
|
* @return An entity instance, with versioned properties set as in the versionsEntity map, and proxies
|
||||||
public Object createInstanceFromVersionsEntity(String entityName, Map versionsEntity, Number revision) {
|
* created for collections.
|
||||||
if (versionsEntity == null) {
|
*/
|
||||||
return null;
|
public Object createInstanceFromVersionsEntity(String entityName, Map versionsEntity, Number revision) {
|
||||||
}
|
if ( versionsEntity == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// The $type$ property holds the name of the (versions) entity
|
// The $type$ property holds the name of the (versions) entity
|
||||||
String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName((String) versionsEntity.get("$type$"));
|
final String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName( (String) versionsEntity.get( "$type$" ) );
|
||||||
|
|
||||||
if (type != null) {
|
if ( type != null ) {
|
||||||
entityName = type;
|
entityName = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First mapping the primary key
|
// First mapping the primary key
|
||||||
IdMapper idMapper = verCfg.getEntCfg().get(entityName).getIdMapper();
|
final IdMapper idMapper = verCfg.getEntCfg().get( entityName ).getIdMapper();
|
||||||
Map originalId = (Map) versionsEntity.get(verCfg.getAuditEntCfg().getOriginalIdPropName());
|
final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
|
||||||
|
|
||||||
// Fixes HHH-4751 issue (@IdClass with @ManyToOne relation mapping inside)
|
// Fixes HHH-4751 issue (@IdClass with @ManyToOne relation mapping inside)
|
||||||
// Note that identifiers are always audited
|
// Note that identifiers are always audited
|
||||||
// Replace identifier proxies if do not point to audit tables
|
// Replace identifier proxies if do not point to audit tables
|
||||||
replaceNonAuditIdProxies(versionsEntity, revision);
|
replaceNonAuditIdProxies( versionsEntity, revision );
|
||||||
|
|
||||||
Object primaryKey = idMapper.mapToIdFromMap(originalId);
|
final Object primaryKey = idMapper.mapToIdFromMap( originalId );
|
||||||
|
|
||||||
// Checking if the entity is in cache
|
// Checking if the entity is in cache
|
||||||
if (versionsReader.getFirstLevelCache().contains(entityName, revision, primaryKey)) {
|
if ( versionsReader.getFirstLevelCache().contains( entityName, revision, primaryKey ) ) {
|
||||||
return versionsReader.getFirstLevelCache().get(entityName, revision, primaryKey);
|
return versionsReader.getFirstLevelCache().get( entityName, revision, primaryKey );
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is not in the cache, creating a new entity instance
|
// If it is not in the cache, creating a new entity instance
|
||||||
Object ret;
|
Object ret;
|
||||||
try {
|
try {
|
||||||
EntityConfiguration entCfg = verCfg.getEntCfg().get(entityName);
|
EntityConfiguration entCfg = verCfg.getEntCfg().get( entityName );
|
||||||
if(entCfg == null) {
|
if ( entCfg == null ) {
|
||||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName);
|
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
final Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
||||||
ret = ReflectHelper.getDefaultConstructor(cls).newInstance();
|
ret = ReflectHelper.getDefaultConstructor( cls ).newInstance();
|
||||||
} catch (Exception e) {
|
}
|
||||||
throw new AuditException(e);
|
catch (Exception e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
|
||||||
// Putting the newly created entity instance into the first level cache, in case a one-to-one bidirectional
|
// Putting the newly created entity instance into the first level cache, in case a one-to-one bidirectional
|
||||||
// relation is present (which is eagerly loaded).
|
// relation is present (which is eagerly loaded).
|
||||||
versionsReader.getFirstLevelCache().put(entityName, revision, primaryKey, ret);
|
versionsReader.getFirstLevelCache().put( entityName, revision, primaryKey, ret );
|
||||||
|
|
||||||
verCfg.getEntCfg().get(entityName).getPropertyMapper().mapToEntityFromMap(verCfg, ret, versionsEntity, primaryKey,
|
verCfg.getEntCfg().get( entityName ).getPropertyMapper().mapToEntityFromMap(
|
||||||
versionsReader, revision);
|
verCfg,
|
||||||
idMapper.mapToEntityFromMap(ret, originalId);
|
ret,
|
||||||
|
versionsEntity,
|
||||||
|
primaryKey,
|
||||||
|
versionsReader,
|
||||||
|
revision
|
||||||
|
);
|
||||||
|
idMapper.mapToEntityFromMap( ret, originalId );
|
||||||
|
|
||||||
// Put entity on entityName cache after mapping it from the map representation
|
// Put entity on entityName cache after mapping it from the map representation
|
||||||
versionsReader.getFirstLevelCache().putOnEntityNameCache(primaryKey, revision, ret, entityName);
|
versionsReader.getFirstLevelCache().putOnEntityNameCache( primaryKey, revision, ret, entityName );
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
return ret;
|
||||||
private void replaceNonAuditIdProxies(Map versionsEntity, Number revision) {
|
}
|
||||||
final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
|
|
||||||
for (Object key : originalId.keySet()) {
|
|
||||||
Object value = originalId.get(key);
|
|
||||||
if (value instanceof HibernateProxy) {
|
|
||||||
HibernateProxy hibernateProxy = (HibernateProxy) value;
|
|
||||||
LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
|
|
||||||
final String entityName = initializer.getEntityName();
|
|
||||||
final Serializable entityId = initializer.getIdentifier();
|
|
||||||
if (verCfg.getEntCfg().isVersioned(entityName)) {
|
|
||||||
final String entityClassName = verCfg.getEntCfg().get(entityName).getEntityClassName();
|
|
||||||
final Class entityClass = ReflectionTools.loadClass( entityClassName, verCfg.getClassLoaderService() );
|
|
||||||
final ToOneDelegateSessionImplementor delegate = new ToOneDelegateSessionImplementor(
|
|
||||||
versionsReader, entityClass, entityId, revision,
|
|
||||||
RevisionType.DEL.equals( versionsEntity.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) ),
|
|
||||||
verCfg);
|
|
||||||
originalId.put(key,
|
|
||||||
versionsReader.getSessionImplementor().getFactory().getEntityPersister(entityName).createProxy(entityId, delegate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public void addInstancesFromVersionsEntities(String entityName, Collection addTo, List<Map> versionsEntities, Number revision) {
|
private void replaceNonAuditIdProxies(Map versionsEntity, Number revision) {
|
||||||
for (Map versionsEntity : versionsEntities) {
|
final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
|
||||||
addTo.add(createInstanceFromVersionsEntity(entityName, versionsEntity, revision));
|
for ( Object key : originalId.keySet() ) {
|
||||||
}
|
final Object value = originalId.get( key );
|
||||||
}
|
if ( value instanceof HibernateProxy ) {
|
||||||
|
final HibernateProxy hibernateProxy = (HibernateProxy) value;
|
||||||
|
final LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
|
||||||
|
final String entityName = initializer.getEntityName();
|
||||||
|
final Serializable entityId = initializer.getIdentifier();
|
||||||
|
if ( verCfg.getEntCfg().isVersioned( entityName ) ) {
|
||||||
|
final String entityClassName = verCfg.getEntCfg().get( entityName ).getEntityClassName();
|
||||||
|
final Class entityClass = ReflectionTools.loadClass(
|
||||||
|
entityClassName,
|
||||||
|
verCfg.getClassLoaderService()
|
||||||
|
);
|
||||||
|
final ToOneDelegateSessionImplementor delegate = new ToOneDelegateSessionImplementor(
|
||||||
|
versionsReader, entityClass, entityId, revision,
|
||||||
|
RevisionType.DEL.equals(
|
||||||
|
versionsEntity.get(
|
||||||
|
verCfg.getAuditEntCfg()
|
||||||
|
.getRevisionTypePropName()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
verCfg
|
||||||
|
);
|
||||||
|
originalId.put(
|
||||||
|
key,
|
||||||
|
versionsReader.getSessionImplementor()
|
||||||
|
.getFactory()
|
||||||
|
.getEntityPersister( entityName )
|
||||||
|
.createProxy( entityId, delegate )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public void addInstancesFromVersionsEntities(
|
||||||
|
String entityName,
|
||||||
|
Collection addTo,
|
||||||
|
List<Map> versionsEntities,
|
||||||
|
Number revision) {
|
||||||
|
for ( Map versionsEntity : versionsEntities ) {
|
||||||
|
addTo.add( createInstanceFromVersionsEntity( entityName, versionsEntity, revision ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AuditConfiguration getAuditConfiguration() {
|
public AuditConfiguration getAuditConfiguration() {
|
||||||
return verCfg;
|
return verCfg;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities;
|
package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
|
|
||||||
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||||
|
@ -30,27 +31,27 @@ import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class IdMappingData {
|
public class IdMappingData {
|
||||||
private final IdMapper idMapper;
|
private final IdMapper idMapper;
|
||||||
// Mapping which will be used to generate the entity
|
// Mapping which will be used to generate the entity
|
||||||
private final Element xmlMapping;
|
private final Element xmlMapping;
|
||||||
// Mapping which will be used to generate references to the entity in related entities
|
// Mapping which will be used to generate references to the entity in related entities
|
||||||
private final Element xmlRelationMapping;
|
private final Element xmlRelationMapping;
|
||||||
|
|
||||||
public IdMappingData(IdMapper idMapper, Element xmlMapping, Element xmlRelationMapping) {
|
public IdMappingData(IdMapper idMapper, Element xmlMapping, Element xmlRelationMapping) {
|
||||||
this.idMapper = idMapper;
|
this.idMapper = idMapper;
|
||||||
this.xmlMapping = xmlMapping;
|
this.xmlMapping = xmlMapping;
|
||||||
this.xmlRelationMapping = xmlRelationMapping;
|
this.xmlRelationMapping = xmlRelationMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdMapper getIdMapper() {
|
public IdMapper getIdMapper() {
|
||||||
return idMapper;
|
return idMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element getXmlMapping() {
|
public Element getXmlMapping() {
|
||||||
return xmlMapping;
|
return xmlMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element getXmlRelationMapping() {
|
public Element getXmlRelationMapping() {
|
||||||
return xmlRelationMapping;
|
return xmlRelationMapping;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,76 +22,86 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities;
|
package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
import org.hibernate.envers.ModificationStore;
|
import org.hibernate.envers.ModificationStore;
|
||||||
|
import org.hibernate.internal.util.compare.EqualsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds information on a property that is audited.
|
* Holds information on a property that is audited.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class PropertyData {
|
public class PropertyData {
|
||||||
private final String name;
|
private final String name;
|
||||||
/**
|
/**
|
||||||
* Name of the property in the bean.
|
* Name of the property in the bean.
|
||||||
*/
|
*/
|
||||||
private final String beanName;
|
private final String beanName;
|
||||||
private final String accessType;
|
private final String accessType;
|
||||||
private final ModificationStore store;
|
private final ModificationStore store;
|
||||||
private boolean usingModifiedFlag;
|
private boolean usingModifiedFlag;
|
||||||
private String modifiedFlagName;
|
private String modifiedFlagName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the given property data, except the name.
|
* Copies the given property data, except the name.
|
||||||
* @param newName New name.
|
*
|
||||||
* @param propertyData Property data to copy the rest of properties from.
|
* @param newName New name.
|
||||||
*/
|
* @param propertyData Property data to copy the rest of properties from.
|
||||||
public PropertyData(String newName, PropertyData propertyData) {
|
*/
|
||||||
this.name = newName;
|
public PropertyData(String newName, PropertyData propertyData) {
|
||||||
|
this.name = newName;
|
||||||
this.beanName = propertyData.beanName;
|
this.beanName = propertyData.beanName;
|
||||||
this.accessType = propertyData.accessType;
|
this.accessType = propertyData.accessType;
|
||||||
this.store = propertyData.store;
|
this.store = propertyData.store;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param name Name of the property.
|
|
||||||
* @param beanName Name of the property in the bean.
|
|
||||||
* @param accessType Accessor type for this property.
|
|
||||||
* @param store How this property should be stored.
|
|
||||||
*/
|
|
||||||
public PropertyData(String name, String beanName, String accessType, ModificationStore store) {
|
|
||||||
this.name = name;
|
|
||||||
this.beanName = beanName;
|
|
||||||
this.accessType = accessType;
|
|
||||||
this.store = store;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name Name of the property.
|
* @param name Name of the property.
|
||||||
* @param beanName Name of the property in the bean.
|
* @param beanName Name of the property in the bean.
|
||||||
* @param accessType Accessor type for this property.
|
* @param accessType Accessor type for this property.
|
||||||
* @param store How this property should be stored.
|
* @param store How this property should be stored.
|
||||||
* @param usingModifiedFlag Defines if field changes should be tracked
|
*/
|
||||||
*/
|
public PropertyData(String name, String beanName, String accessType, ModificationStore store) {
|
||||||
public PropertyData(String name, String beanName, String accessType, ModificationStore store, boolean usingModifiedFlag, String modifiedFlagName) {
|
this.name = name;
|
||||||
this(name, beanName, accessType, store);
|
this.beanName = beanName;
|
||||||
|
this.accessType = accessType;
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name Name of the property.
|
||||||
|
* @param beanName Name of the property in the bean.
|
||||||
|
* @param accessType Accessor type for this property.
|
||||||
|
* @param store How this property should be stored.
|
||||||
|
* @param usingModifiedFlag Defines if field changes should be tracked
|
||||||
|
*/
|
||||||
|
public PropertyData(
|
||||||
|
String name,
|
||||||
|
String beanName,
|
||||||
|
String accessType,
|
||||||
|
ModificationStore store,
|
||||||
|
boolean usingModifiedFlag,
|
||||||
|
String modifiedFlagName) {
|
||||||
|
this( name, beanName, accessType, store );
|
||||||
this.usingModifiedFlag = usingModifiedFlag;
|
this.usingModifiedFlag = usingModifiedFlag;
|
||||||
this.modifiedFlagName = modifiedFlagName;
|
this.modifiedFlagName = modifiedFlagName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBeanName() {
|
public String getBeanName() {
|
||||||
return beanName;
|
return beanName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAccessType() {
|
public String getAccessType() {
|
||||||
return accessType;
|
return accessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModificationStore getStore() {
|
public ModificationStore getStore() {
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUsingModifiedFlag() {
|
public boolean isUsingModifiedFlag() {
|
||||||
return usingModifiedFlag;
|
return usingModifiedFlag;
|
||||||
|
@ -103,18 +113,19 @@ public class PropertyData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if ( this == o ) {
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if ( o == null || getClass() != o.getClass() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PropertyData that = (PropertyData) o;
|
final PropertyData that = (PropertyData) o;
|
||||||
|
return usingModifiedFlag == that.usingModifiedFlag
|
||||||
if (accessType != null ? !accessType.equals(that.accessType) : that.accessType != null) return false;
|
&& store == that.store
|
||||||
if (beanName != null ? !beanName.equals(that.beanName) : that.beanName != null) return false;
|
&& EqualsHelper.equals( accessType, that.accessType )
|
||||||
if (name != null ? !name.equals(that.name) : that.name != null) return false;
|
&& EqualsHelper.equals( beanName, that.beanName )
|
||||||
if (store != that.store) return false;
|
&& EqualsHelper.equals( name, that.name );
|
||||||
if (usingModifiedFlag != that.usingModifiedFlag) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,76 +22,78 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities;
|
package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
|
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
|
||||||
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class RelationDescription {
|
public class RelationDescription {
|
||||||
private final String fromPropertyName;
|
private final String fromPropertyName;
|
||||||
private final RelationType relationType;
|
private final RelationType relationType;
|
||||||
private final String toEntityName;
|
private final String toEntityName;
|
||||||
private final String mappedByPropertyName;
|
private final String mappedByPropertyName;
|
||||||
private final IdMapper idMapper;
|
private final IdMapper idMapper;
|
||||||
private final PropertyMapper fakeBidirectionalRelationMapper;
|
private final PropertyMapper fakeBidirectionalRelationMapper;
|
||||||
private final PropertyMapper fakeBidirectionalRelationIndexMapper;
|
private final PropertyMapper fakeBidirectionalRelationIndexMapper;
|
||||||
private final boolean insertable;
|
private final boolean insertable;
|
||||||
private boolean bidirectional;
|
private boolean bidirectional;
|
||||||
|
|
||||||
public RelationDescription(String fromPropertyName, RelationType relationType, String toEntityName,
|
public RelationDescription(
|
||||||
String mappedByPropertyName, IdMapper idMapper,
|
String fromPropertyName, RelationType relationType, String toEntityName,
|
||||||
PropertyMapper fakeBidirectionalRelationMapper,
|
String mappedByPropertyName, IdMapper idMapper,
|
||||||
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) {
|
PropertyMapper fakeBidirectionalRelationMapper,
|
||||||
this.fromPropertyName = fromPropertyName;
|
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) {
|
||||||
this.relationType = relationType;
|
this.fromPropertyName = fromPropertyName;
|
||||||
this.toEntityName = toEntityName;
|
this.relationType = relationType;
|
||||||
this.mappedByPropertyName = mappedByPropertyName;
|
this.toEntityName = toEntityName;
|
||||||
this.idMapper = idMapper;
|
this.mappedByPropertyName = mappedByPropertyName;
|
||||||
this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper;
|
this.idMapper = idMapper;
|
||||||
this.fakeBidirectionalRelationIndexMapper = fakeBidirectionalRelationIndexMapper;
|
this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper;
|
||||||
this.insertable = insertable;
|
this.fakeBidirectionalRelationIndexMapper = fakeBidirectionalRelationIndexMapper;
|
||||||
|
this.insertable = insertable;
|
||||||
|
|
||||||
this.bidirectional = false;
|
this.bidirectional = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFromPropertyName() {
|
public String getFromPropertyName() {
|
||||||
return fromPropertyName;
|
return fromPropertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RelationType getRelationType() {
|
public RelationType getRelationType() {
|
||||||
return relationType;
|
return relationType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getToEntityName() {
|
public String getToEntityName() {
|
||||||
return toEntityName;
|
return toEntityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMappedByPropertyName() {
|
public String getMappedByPropertyName() {
|
||||||
return mappedByPropertyName;
|
return mappedByPropertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdMapper getIdMapper() {
|
public IdMapper getIdMapper() {
|
||||||
return idMapper;
|
return idMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyMapper getFakeBidirectionalRelationMapper() {
|
public PropertyMapper getFakeBidirectionalRelationMapper() {
|
||||||
return fakeBidirectionalRelationMapper;
|
return fakeBidirectionalRelationMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyMapper getFakeBidirectionalRelationIndexMapper() {
|
public PropertyMapper getFakeBidirectionalRelationIndexMapper() {
|
||||||
return fakeBidirectionalRelationIndexMapper;
|
return fakeBidirectionalRelationIndexMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInsertable() {
|
public boolean isInsertable() {
|
||||||
return insertable;
|
return insertable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBidirectional() {
|
public boolean isBidirectional() {
|
||||||
return bidirectional;
|
return bidirectional;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBidirectional(boolean bidirectional) {
|
void setBidirectional(boolean bidirectional) {
|
||||||
this.bidirectional = bidirectional;
|
this.bidirectional = bidirectional;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -26,30 +26,31 @@ package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of a relation between two entities.
|
* Type of a relation between two entities.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public enum RelationType {
|
public enum RelationType {
|
||||||
/**
|
/**
|
||||||
* A single-reference-valued relation. The entity owns the relation.
|
* A single-reference-valued relation. The entity owns the relation.
|
||||||
*/
|
*/
|
||||||
TO_ONE,
|
TO_ONE,
|
||||||
/**
|
/**
|
||||||
* A single-reference-valued relation. The entity doesn't own the relation. It is directly mapped in the related
|
* A single-reference-valued relation. The entity doesn't own the relation. It is directly mapped in the related
|
||||||
* entity.
|
* entity.
|
||||||
*/
|
*/
|
||||||
TO_ONE_NOT_OWNING,
|
TO_ONE_NOT_OWNING,
|
||||||
/**
|
/**
|
||||||
* A collection-of-references-valued relation. The entity doesn't own the relation. It is directly mapped in the
|
* A collection-of-references-valued relation. The entity doesn't own the relation. It is directly mapped in the
|
||||||
* related entity.
|
* related entity.
|
||||||
*/
|
*/
|
||||||
TO_MANY_NOT_OWNING,
|
TO_MANY_NOT_OWNING,
|
||||||
/**
|
/**
|
||||||
* A collection-of-references-valued relation. The entity owns the relation. It is mapped using a middle table.
|
* A collection-of-references-valued relation. The entity owns the relation. It is mapped using a middle table.
|
||||||
*/
|
*/
|
||||||
TO_MANY_MIDDLE,
|
TO_MANY_MIDDLE,
|
||||||
/**
|
/**
|
||||||
* A collection-of-references-valued relation. The entity doesn't own the relation. It is mapped using a middle
|
* A collection-of-references-valued relation. The entity doesn't own the relation. It is mapped using a middle
|
||||||
* table.
|
* table.
|
||||||
*/
|
*/
|
||||||
TO_MANY_MIDDLE_NOT_OWNING
|
TO_MANY_MIDDLE_NOT_OWNING
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -32,78 +32,84 @@ import java.sql.Types;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
|
import org.hibernate.internal.util.compare.EqualsHelper;
|
||||||
import org.hibernate.type.IntegerType;
|
import org.hibernate.type.IntegerType;
|
||||||
import org.hibernate.usertype.UserType;
|
import org.hibernate.usertype.UserType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hibernate type for the {@link RevisionType} enum.
|
* A hibernate type for the {@link RevisionType} enum.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class RevisionTypeType implements UserType, Serializable {
|
public class RevisionTypeType implements UserType, Serializable {
|
||||||
private static final long serialVersionUID = -1053201518229282688L;
|
private static final long serialVersionUID = -1053201518229282688L;
|
||||||
|
|
||||||
private static final int[] SQL_TYPES = { Types.TINYINT };
|
|
||||||
|
|
||||||
public int[] sqlTypes() {
|
private static final int[] SQL_TYPES = {Types.TINYINT};
|
||||||
return SQL_TYPES;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class returnedClass() {
|
@Override
|
||||||
return RevisionType.class;
|
public int[] sqlTypes() {
|
||||||
}
|
return SQL_TYPES;
|
||||||
|
}
|
||||||
|
|
||||||
public RevisionType nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
|
@Override
|
||||||
Integer representationInt = IntegerType.INSTANCE.nullSafeGet( resultSet, names[0], session );
|
public Class returnedClass() {
|
||||||
|
return RevisionType.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RevisionType nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
|
||||||
|
throws HibernateException, SQLException {
|
||||||
|
final Integer representationInt = IntegerType.INSTANCE.nullSafeGet( resultSet, names[0], session );
|
||||||
return representationInt == null ?
|
return representationInt == null ?
|
||||||
null :
|
null :
|
||||||
RevisionType.fromRepresentation( representationInt.byteValue() );
|
RevisionType.fromRepresentation( representationInt.byteValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
|
@Override
|
||||||
|
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
|
||||||
|
throws HibernateException, SQLException {
|
||||||
IntegerType.INSTANCE.nullSafeSet(
|
IntegerType.INSTANCE.nullSafeSet(
|
||||||
preparedStatement,
|
preparedStatement,
|
||||||
( value == null ? null : ((RevisionType) value).getRepresentation().intValue() ),
|
(value == null ? null : ((RevisionType) value).getRepresentation().intValue()),
|
||||||
index,
|
index,
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object deepCopy(Object value) throws HibernateException{
|
@Override
|
||||||
return value;
|
public Object deepCopy(Object value) throws HibernateException {
|
||||||
}
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMutable() {
|
@Override
|
||||||
return false;
|
public boolean isMutable() {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
@Override
|
||||||
return cached;
|
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
||||||
}
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
public Serializable disassemble(Object value) throws HibernateException {
|
@Override
|
||||||
return (Serializable)value;
|
public Serializable disassemble(Object value) throws HibernateException {
|
||||||
}
|
return (Serializable) value;
|
||||||
|
}
|
||||||
|
|
||||||
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
@Override
|
||||||
return original;
|
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
||||||
}
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
public int hashCode(Object x) throws HibernateException {
|
@Override
|
||||||
return x.hashCode();
|
public int hashCode(Object x) throws HibernateException {
|
||||||
}
|
return x.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object x, Object y) throws HibernateException {
|
@Override
|
||||||
//noinspection ObjectEquality
|
public boolean equals(Object x, Object y) throws HibernateException {
|
||||||
if (x == y) {
|
return EqualsHelper.equals( x, y );
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (null == x || null == y) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return x.equals(y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
|
||||||
* JBoss, Home of Professional Open Source
|
|
||||||
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
|
||||||
* as indicated by the @authors tag. All rights reserved.
|
|
||||||
* See the copyright.txt in the distribution for a
|
|
||||||
* full listing of individual contributors.
|
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use,
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* modify, copy, or redistribute it subject to the terms and conditions
|
* indicated by the @author tags or express copyright attribution
|
||||||
* of the GNU Lesser General Public License, v. 2.1.
|
* statements applied by the authors. All third-party contributions are
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT A
|
* distributed under license by Red Hat Inc.
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
*
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* You should have received a copy of the GNU Lesser General Public License,
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
* v.2.1 along with this distribution; if not, write to the Free Software
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
*
|
||||||
* MA 02110-1301, USA.
|
* 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.internal.entities;
|
package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
|
@ -25,14 +28,17 @@ import org.hibernate.metamodel.spi.TypeContributor;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Envers specific TypeContributor
|
||||||
|
*
|
||||||
* @author Brett Meyer
|
* @author Brett Meyer
|
||||||
*/
|
*/
|
||||||
public class TypeContributorImpl implements TypeContributor {
|
public class TypeContributorImpl implements TypeContributor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||||
typeContributions.contributeType( new RevisionTypeType(),
|
typeContributions.contributeType(
|
||||||
new String[] { RevisionTypeType.class.getName() } );
|
new RevisionTypeType(),
|
||||||
|
new String[] { RevisionTypeType.class.getName() }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -43,98 +43,127 @@ import org.hibernate.property.Setter;
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperBuilder {
|
public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperBuilder {
|
||||||
private final PropertyData propertyData;
|
private final PropertyData propertyData;
|
||||||
private final MultiPropertyMapper delegate;
|
private final MultiPropertyMapper delegate;
|
||||||
private final Class componentClass;
|
private final Class componentClass;
|
||||||
|
|
||||||
public ComponentPropertyMapper(PropertyData propertyData, Class componentClass) {
|
public ComponentPropertyMapper(PropertyData propertyData, Class componentClass) {
|
||||||
this.propertyData = propertyData;
|
this.propertyData = propertyData;
|
||||||
this.delegate = new MultiPropertyMapper();
|
this.delegate = new MultiPropertyMapper();
|
||||||
this.componentClass = componentClass;
|
this.componentClass = componentClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(PropertyData propertyData) {
|
|
||||||
delegate.add(propertyData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
|
||||||
return delegate.addComponent(propertyData, componentClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
|
||||||
delegate.addComposite(propertyData, propertyMapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
|
||||||
return delegate.mapToMapFromEntity(session, data, newObj, oldObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
public void add(PropertyData propertyData) {
|
||||||
if (propertyData.isUsingModifiedFlag()) {
|
delegate.add( propertyData );
|
||||||
data.put(propertyData.getModifiedFlagPropertyName(),
|
}
|
||||||
delegate.mapToMapFromEntity(session, new HashMap<String, Object>(), newObj, oldObj));
|
|
||||||
|
@Override
|
||||||
|
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
||||||
|
return delegate.addComponent( propertyData, componentClass );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
||||||
|
delegate.addComposite( propertyData, propertyMapper );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mapToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
return delegate.mapToMapFromEntity( session, data, newObj, oldObj );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mapModifiedFlagsToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
if ( propertyData.isUsingModifiedFlag() ) {
|
||||||
|
data.put(
|
||||||
|
propertyData.getModifiedFlagPropertyName(),
|
||||||
|
delegate.mapToMapFromEntity( session, new HashMap<String, Object>(), newObj, oldObj )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||||
if (propertyData.isUsingModifiedFlag()) {
|
if ( propertyData.isUsingModifiedFlag() ) {
|
||||||
boolean hasModifiedCollection = false;
|
boolean hasModifiedCollection = false;
|
||||||
for (PropertyData propData : delegate.getProperties().keySet()) {
|
for ( PropertyData propData : delegate.getProperties().keySet() ) {
|
||||||
if (collectionPropertyName.equals(propData.getName())) {
|
if ( collectionPropertyName.equals( propData.getName() ) ) {
|
||||||
hasModifiedCollection = true;
|
hasModifiedCollection = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.put(propertyData.getModifiedFlagPropertyName(), hasModifiedCollection);
|
data.put( propertyData.getModifiedFlagPropertyName(), hasModifiedCollection );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
|
@Override
|
||||||
if (data == null || obj == null) {
|
public void mapToEntityFromMap(
|
||||||
return;
|
AuditConfiguration verCfg,
|
||||||
}
|
Object obj,
|
||||||
|
Map data,
|
||||||
|
Object primaryKey,
|
||||||
|
AuditReaderImplementor versionsReader,
|
||||||
|
Number revision) {
|
||||||
|
if ( data == null || obj == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (propertyData.getBeanName() == null) {
|
if ( propertyData.getBeanName() == null ) {
|
||||||
// If properties are not encapsulated in a component but placed directly in a class
|
// If properties are not encapsulated in a component but placed directly in a class
|
||||||
// (e.g. by applying <properties> tag).
|
// (e.g. by applying <properties> tag).
|
||||||
delegate.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
delegate.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
|
final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
|
||||||
|
|
||||||
// If all properties are null and single, then the component has to be null also.
|
// If all properties are null and single, then the component has to be null also.
|
||||||
boolean allNullAndSingle = true;
|
boolean allNullAndSingle = true;
|
||||||
for (Map.Entry<PropertyData, PropertyMapper> property : delegate.getProperties().entrySet()) {
|
for ( Map.Entry<PropertyData, PropertyMapper> property : delegate.getProperties().entrySet() ) {
|
||||||
if (data.get(property.getKey().getName()) != null || !(property.getValue() instanceof SinglePropertyMapper)) {
|
if ( data.get(
|
||||||
|
property.getKey()
|
||||||
|
.getName()
|
||||||
|
) != null || !(property.getValue() instanceof SinglePropertyMapper) ) {
|
||||||
allNullAndSingle = false;
|
allNullAndSingle = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allNullAndSingle) {
|
if ( allNullAndSingle ) {
|
||||||
// single property, but default value need not be null, so we'll set it to null anyway
|
// single property, but default value need not be null, so we'll set it to null anyway
|
||||||
setter.set(obj, null, null);
|
setter.set( obj, null, null );
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// set the component
|
// set the component
|
||||||
try {
|
try {
|
||||||
Object subObj = ReflectHelper.getDefaultConstructor(componentClass).newInstance();
|
final Object subObj = ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
|
||||||
setter.set(obj, subObj, null);
|
setter.set( obj, subObj, null );
|
||||||
delegate.mapToEntityFromMap(verCfg, subObj, data, primaryKey, versionsReader, revision);
|
delegate.mapToEntityFromMap( verCfg, subObj, data, primaryKey, versionsReader, revision );
|
||||||
} catch (Exception e) {
|
}
|
||||||
throw new AuditException(e);
|
catch (Exception e) {
|
||||||
|
throw new AuditException( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
@Override
|
||||||
PersistentCollection newColl,
|
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||||
Serializable oldColl, Serializable id) {
|
SessionImplementor session, String referencingPropertyName,
|
||||||
return delegate.mapCollectionChanges(session, referencingPropertyName, newColl, oldColl, id);
|
PersistentCollection newColl,
|
||||||
}
|
Serializable oldColl, Serializable id) {
|
||||||
|
return delegate.mapCollectionChanges( session, referencingPropertyName, newColl, oldColl, id );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Map<PropertyData, PropertyMapper> getProperties() {
|
public Map<PropertyData, PropertyMapper> getProperties() {
|
||||||
return delegate.getProperties();
|
return delegate.getProperties();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -30,8 +30,10 @@ import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
|
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
|
||||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass);
|
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass);
|
||||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
|
|
||||||
|
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
|
||||||
|
|
||||||
public Map<PropertyData, PropertyMapper> getProperties();
|
public Map<PropertyData, PropertyMapper> getProperties();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
@ -30,5 +31,10 @@ import org.hibernate.engine.spi.SessionImplementor;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
|
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
|
||||||
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState);
|
public boolean map(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
String[] propertyNames,
|
||||||
|
Object[] newState,
|
||||||
|
Object[] oldState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -43,148 +43,183 @@ import org.hibernate.property.Getter;
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public class MultiPropertyMapper implements ExtendedPropertyMapper {
|
public class MultiPropertyMapper implements ExtendedPropertyMapper {
|
||||||
protected final Map<PropertyData, PropertyMapper> properties;
|
protected final Map<PropertyData, PropertyMapper> properties;
|
||||||
private final Map<String, PropertyData> propertyDatas;
|
private final Map<String, PropertyData> propertyDatas;
|
||||||
|
|
||||||
public MultiPropertyMapper() {
|
public MultiPropertyMapper() {
|
||||||
properties = Tools.newHashMap();
|
properties = Tools.newHashMap();
|
||||||
propertyDatas = Tools.newHashMap();
|
propertyDatas = Tools.newHashMap();
|
||||||
}
|
|
||||||
|
|
||||||
public void add(PropertyData propertyData) {
|
|
||||||
SinglePropertyMapper single = new SinglePropertyMapper();
|
|
||||||
single.add(propertyData);
|
|
||||||
properties.put(propertyData, single);
|
|
||||||
propertyDatas.put(propertyData.getName(), propertyData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
|
||||||
if (properties.get(propertyData) != null) {
|
|
||||||
// This is needed for second pass to work properly in the components mapper
|
|
||||||
return (CompositeMapperBuilder) properties.get(propertyData);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentPropertyMapper componentMapperBuilder = new ComponentPropertyMapper(propertyData, componentClass);
|
|
||||||
addComposite(propertyData, componentMapperBuilder);
|
|
||||||
|
|
||||||
return componentMapperBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
|
||||||
properties.put(propertyData, propertyMapper);
|
|
||||||
propertyDatas.put(propertyData.getName(), propertyData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object getAtIndexOrNull(Object[] array, int index) { return array == null ? null : array[index]; }
|
|
||||||
|
|
||||||
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
|
|
||||||
boolean ret = false;
|
|
||||||
for (int i=0; i<propertyNames.length; i++) {
|
|
||||||
String propertyName = propertyNames[i];
|
|
||||||
|
|
||||||
if (propertyDatas.containsKey(propertyName)) {
|
|
||||||
PropertyMapper propertyMapper = properties.get(propertyDatas.get(propertyName));
|
|
||||||
Object newObj = getAtIndexOrNull(newState, i);
|
|
||||||
Object oldObj = getAtIndexOrNull(oldState, i);
|
|
||||||
ret |= propertyMapper.mapToMapFromEntity(session, data, newObj, oldObj);
|
|
||||||
propertyMapper.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
|
||||||
boolean ret = false;
|
|
||||||
for (PropertyData propertyData : properties.keySet()) {
|
|
||||||
Getter getter;
|
|
||||||
if (newObj != null) {
|
|
||||||
getter = ReflectionTools.getGetter(newObj.getClass(), propertyData);
|
|
||||||
} else if (oldObj != null) {
|
|
||||||
getter = ReflectionTools.getGetter(oldObj.getClass(), propertyData);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret |= properties.get(propertyData).mapToMapFromEntity(session, data,
|
|
||||||
newObj == null ? null : getter.get(newObj),
|
|
||||||
oldObj == null ? null : getter.get(oldObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
|
||||||
for (PropertyData propertyData : properties.keySet()) {
|
|
||||||
Getter getter;
|
|
||||||
if (newObj != null) {
|
|
||||||
getter = ReflectionTools.getGetter(newObj.getClass(), propertyData);
|
|
||||||
} else if (oldObj != null) {
|
|
||||||
getter = ReflectionTools.getGetter(oldObj.getClass(), propertyData);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
properties.get(propertyData).mapModifiedFlagsToMapFromEntity(session, data,
|
|
||||||
newObj == null ? null : getter.get(newObj),
|
|
||||||
oldObj == null ? null : getter.get(oldObj));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
@Override
|
||||||
AuditReaderImplementor versionsReader, Number revision) {
|
public void add(PropertyData propertyData) {
|
||||||
for (PropertyMapper mapper : properties.values()) {
|
final SinglePropertyMapper single = new SinglePropertyMapper();
|
||||||
mapper.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
single.add( propertyData );
|
||||||
}
|
properties.put( propertyData, single );
|
||||||
}
|
propertyDatas.put( propertyData.getName(), propertyData );
|
||||||
|
}
|
||||||
|
|
||||||
private Pair<PropertyMapper, String> getMapperAndDelegatePropName(String referencingPropertyName){
|
@Override
|
||||||
|
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
||||||
|
if ( properties.get( propertyData ) != null ) {
|
||||||
|
// This is needed for second pass to work properly in the components mapper
|
||||||
|
return (CompositeMapperBuilder) properties.get( propertyData );
|
||||||
|
}
|
||||||
|
|
||||||
|
final ComponentPropertyMapper componentMapperBuilder = new ComponentPropertyMapper( propertyData, componentClass );
|
||||||
|
addComposite( propertyData, componentMapperBuilder );
|
||||||
|
|
||||||
|
return componentMapperBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
||||||
|
properties.put( propertyData, propertyMapper );
|
||||||
|
propertyDatas.put( propertyData.getName(), propertyData );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getAtIndexOrNull(Object[] array, int index) {
|
||||||
|
return array == null ? null : array[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean map(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
String[] propertyNames,
|
||||||
|
Object[] newState,
|
||||||
|
Object[] oldState) {
|
||||||
|
boolean ret = false;
|
||||||
|
for ( int i = 0; i < propertyNames.length; i++ ) {
|
||||||
|
final String propertyName = propertyNames[i];
|
||||||
|
|
||||||
|
if ( propertyDatas.containsKey( propertyName ) ) {
|
||||||
|
final PropertyMapper propertyMapper = properties.get( propertyDatas.get( propertyName ) );
|
||||||
|
final Object newObj = getAtIndexOrNull( newState, i );
|
||||||
|
final Object oldObj = getAtIndexOrNull( oldState, i );
|
||||||
|
ret |= propertyMapper.mapToMapFromEntity( session, data, newObj, oldObj );
|
||||||
|
propertyMapper.mapModifiedFlagsToMapFromEntity( session, data, newObj, oldObj );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mapToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
boolean ret = false;
|
||||||
|
for ( PropertyData propertyData : properties.keySet() ) {
|
||||||
|
Getter getter;
|
||||||
|
if ( newObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter( newObj.getClass(), propertyData );
|
||||||
|
}
|
||||||
|
else if ( oldObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter( oldObj.getClass(), propertyData );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= properties.get( propertyData ).mapToMapFromEntity(
|
||||||
|
session, data,
|
||||||
|
newObj == null ? null : getter.get( newObj ),
|
||||||
|
oldObj == null ? null : getter.get( oldObj )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mapModifiedFlagsToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
for ( PropertyData propertyData : properties.keySet() ) {
|
||||||
|
Getter getter;
|
||||||
|
if ( newObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter( newObj.getClass(), propertyData );
|
||||||
|
}
|
||||||
|
else if ( oldObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter( oldObj.getClass(), propertyData );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.get( propertyData ).mapModifiedFlagsToMapFromEntity(
|
||||||
|
session, data,
|
||||||
|
newObj == null ? null : getter.get( newObj ),
|
||||||
|
oldObj == null ? null : getter.get( oldObj )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mapToEntityFromMap(
|
||||||
|
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||||
|
AuditReaderImplementor versionsReader, Number revision) {
|
||||||
|
for ( PropertyMapper mapper : properties.values() ) {
|
||||||
|
mapper.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<PropertyMapper, String> getMapperAndDelegatePropName(String referencingPropertyName) {
|
||||||
// Name of the property, to which we will delegate the mapping.
|
// Name of the property, to which we will delegate the mapping.
|
||||||
String delegatePropertyName;
|
String delegatePropertyName;
|
||||||
|
|
||||||
// Checking if the property name doesn't reference a collection in a component - then the name will containa a .
|
// Checking if the property name doesn't reference a collection in a component - then the name will containa a .
|
||||||
int dotIndex = referencingPropertyName.indexOf('.');
|
final int dotIndex = referencingPropertyName.indexOf( '.' );
|
||||||
if (dotIndex != -1) {
|
if ( dotIndex != -1 ) {
|
||||||
// Computing the name of the component
|
// Computing the name of the component
|
||||||
String componentName = referencingPropertyName.substring(0, dotIndex);
|
final String componentName = referencingPropertyName.substring( 0, dotIndex );
|
||||||
// And the name of the property in the component
|
// And the name of the property in the component
|
||||||
String propertyInComponentName = MappingTools.createComponentPrefix(componentName)
|
final String propertyInComponentName = MappingTools.createComponentPrefix( componentName )
|
||||||
+ referencingPropertyName.substring(dotIndex+1);
|
+ referencingPropertyName.substring( dotIndex + 1 );
|
||||||
|
|
||||||
// We need to get the mapper for the component.
|
// We need to get the mapper for the component.
|
||||||
referencingPropertyName = componentName;
|
referencingPropertyName = componentName;
|
||||||
// As this is a component, we delegate to the property in the component.
|
// As this is a component, we delegate to the property in the component.
|
||||||
delegatePropertyName = propertyInComponentName;
|
delegatePropertyName = propertyInComponentName;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// If this is not a component, we delegate to the same property.
|
// If this is not a component, we delegate to the same property.
|
||||||
delegatePropertyName = referencingPropertyName;
|
delegatePropertyName = referencingPropertyName;
|
||||||
}
|
}
|
||||||
return Pair.make(properties.get(propertyDatas.get(referencingPropertyName)), delegatePropertyName);
|
return Pair.make( properties.get( propertyDatas.get( referencingPropertyName ) ), delegatePropertyName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||||
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(collectionPropertyName);
|
final Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName( collectionPropertyName );
|
||||||
PropertyMapper mapper = pair.getFirst();
|
final PropertyMapper mapper = pair.getFirst();
|
||||||
if (mapper != null) {
|
if ( mapper != null ) {
|
||||||
mapper.mapModifiedFlagsToMapForCollectionChange(pair.getSecond(), data);
|
mapper.mapModifiedFlagsToMapForCollectionChange( pair.getSecond(), data );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
|
@Override
|
||||||
String referencingPropertyName,
|
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||||
PersistentCollection newColl,
|
SessionImplementor session,
|
||||||
Serializable oldColl, Serializable id) {
|
String referencingPropertyName,
|
||||||
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName);
|
PersistentCollection newColl,
|
||||||
PropertyMapper mapper = pair.getFirst();
|
Serializable oldColl, Serializable id) {
|
||||||
if (mapper != null) {
|
final Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName( referencingPropertyName );
|
||||||
return mapper.mapCollectionChanges(session, pair.getSecond(), newColl, oldColl, id);
|
final PropertyMapper mapper = pair.getFirst();
|
||||||
} else {
|
if ( mapper != null ) {
|
||||||
|
return mapper.mapCollectionChanges( session, pair.getSecond(), newColl, oldColl, id );
|
||||||
|
}
|
||||||
|
else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Map<PropertyData, PropertyMapper> getProperties() {
|
public Map<PropertyData, PropertyMapper> getProperties() {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.tools.Pair;
|
import org.hibernate.envers.tools.Pair;
|
||||||
|
@ -29,58 +30,58 @@ import org.hibernate.envers.tools.Pair;
|
||||||
/**
|
/**
|
||||||
* Data describing the change of a single object in a persistent collection (when the object was added, removed or
|
* Data describing the change of a single object in a persistent collection (when the object was added, removed or
|
||||||
* modified in the collection).
|
* modified in the collection).
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class PersistentCollectionChangeData {
|
public class PersistentCollectionChangeData {
|
||||||
private final String entityName;
|
private final String entityName;
|
||||||
private final Map<String, Object> data;
|
private final Map<String, Object> data;
|
||||||
private final Object changedElement;
|
private final Object changedElement;
|
||||||
|
|
||||||
public PersistentCollectionChangeData(String entityName, Map<String, Object> data, Object changedElement) {
|
public PersistentCollectionChangeData(String entityName, Map<String, Object> data, Object changedElement) {
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.changedElement = changedElement;
|
this.changedElement = changedElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return Name of the (middle) entity that holds the collection data.
|
||||||
* @return Name of the (middle) entity that holds the collection data.
|
*/
|
||||||
*/
|
public String getEntityName() {
|
||||||
public String getEntityName() {
|
return entityName;
|
||||||
return entityName;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> getData() {
|
public Map<String, Object> getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The affected element, which was changed (added, removed, modified) in the collection.
|
* @return The affected element, which was changed (added, removed, modified) in the collection.
|
||||||
*/
|
*/
|
||||||
public Object getChangedElement() {
|
public Object getChangedElement() {
|
||||||
if (changedElement instanceof Pair) {
|
if ( changedElement instanceof Pair ) {
|
||||||
return ((Pair) changedElement).getSecond();
|
return ((Pair) changedElement).getSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changedElement instanceof Map.Entry) {
|
if ( changedElement instanceof Map.Entry ) {
|
||||||
return ((Map.Entry) changedElement).getValue();
|
return ((Map.Entry) changedElement).getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
return changedElement;
|
return changedElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Index of the affected element, or {@code null} if the collection isn't indexed.
|
* @return Index of the affected element, or {@code null} if the collection isn't indexed.
|
||||||
*/
|
*/
|
||||||
public Object getChangedElementIndex() {
|
public Object getChangedElementIndex() {
|
||||||
if (changedElement instanceof Pair) {
|
if ( changedElement instanceof Pair ) {
|
||||||
return ((Pair) changedElement).getFirst();
|
return ((Pair) changedElement).getFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changedElement instanceof Map.Entry) {
|
if ( changedElement instanceof Map.Entry ) {
|
||||||
return ((Map.Entry) changedElement).getKey();
|
return ((Map.Entry) changedElement).getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -36,41 +37,53 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public interface PropertyMapper {
|
public interface PropertyMapper {
|
||||||
/**
|
/**
|
||||||
* Maps properties to the given map, basing on differences between properties of new and old objects.
|
* Maps properties to the given map, basing on differences between properties of new and old objects.
|
||||||
* @param session The current session.
|
*
|
||||||
|
* @param session The current session.
|
||||||
* @param data Data to map to.
|
* @param data Data to map to.
|
||||||
* @param newObj New state of the entity.
|
* @param newObj New state of the entity.
|
||||||
* @param oldObj Old state of the entity.
|
* @param oldObj Old state of the entity.
|
||||||
|
*
|
||||||
* @return True if there are any differences between the states represented by newObj and oldObj.
|
* @return True if there are any differences between the states represented by newObj and oldObj.
|
||||||
*/
|
*/
|
||||||
boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj);
|
boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps properties from the given map to the given object.
|
* Maps properties from the given map to the given object.
|
||||||
* @param verCfg Versions configuration.
|
*
|
||||||
* @param obj Object to map to.
|
* @param verCfg Versions configuration.
|
||||||
* @param data Data to map from.
|
* @param obj Object to map to.
|
||||||
* @param primaryKey Primary key of the object to which we map (for relations)
|
* @param data Data to map from.
|
||||||
* @param versionsReader VersionsReader for reading relations
|
* @param primaryKey Primary key of the object to which we map (for relations)
|
||||||
* @param revision Revision at which the object is read, for reading relations
|
* @param versionsReader VersionsReader for reading relations
|
||||||
*/
|
* @param revision Revision at which the object is read, for reading relations
|
||||||
void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
*/
|
||||||
AuditReaderImplementor versionsReader, Number revision);
|
void mapToEntityFromMap(
|
||||||
|
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||||
|
AuditReaderImplementor versionsReader, Number revision);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps collection changes.
|
* Maps collection changes.
|
||||||
|
*
|
||||||
* @param session The current session.
|
* @param session The current session.
|
||||||
* @param referencingPropertyName Name of the field, which holds the collection in the entity.
|
* @param referencingPropertyName Name of the field, which holds the collection in the entity.
|
||||||
* @param newColl New collection, after updates.
|
* @param newColl New collection, after updates.
|
||||||
* @param oldColl Old collection, before updates.
|
* @param oldColl Old collection, before updates.
|
||||||
* @param id Id of the object owning the collection.
|
* @param id Id of the object owning the collection.
|
||||||
* @return List of changes that need to be performed on the persistent store.
|
*
|
||||||
*/
|
* @return List of changes that need to be performed on the persistent store.
|
||||||
List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
*/
|
||||||
PersistentCollection newColl,
|
List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||||
Serializable oldColl, Serializable id);
|
SessionImplementor session, String referencingPropertyName,
|
||||||
|
PersistentCollection newColl,
|
||||||
|
Serializable oldColl, Serializable id);
|
||||||
|
|
||||||
|
void mapModifiedFlagsToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj);
|
||||||
|
|
||||||
void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj);
|
|
||||||
void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data);
|
void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,11 +22,12 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import org.hibernate.envers.internal.entities.PropertyData;
|
import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public interface SimpleMapperBuilder {
|
public interface SimpleMapperBuilder {
|
||||||
public void add(PropertyData propertyData);
|
public void add(PropertyData propertyData);
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -43,40 +43,53 @@ import org.hibernate.property.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: diff
|
* TODO: diff
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder {
|
public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder {
|
||||||
private PropertyData propertyData;
|
private PropertyData propertyData;
|
||||||
|
|
||||||
public SinglePropertyMapper(PropertyData propertyData) {
|
public SinglePropertyMapper(PropertyData propertyData) {
|
||||||
this.propertyData = propertyData;
|
this.propertyData = propertyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SinglePropertyMapper() { }
|
public SinglePropertyMapper() {
|
||||||
|
}
|
||||||
public void add(PropertyData propertyData) {
|
|
||||||
if (this.propertyData != null) {
|
|
||||||
throw new AuditException("Only one property can be added!");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.propertyData = propertyData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
|
||||||
data.put(propertyData.getName(), newObj);
|
|
||||||
boolean dbLogicallyDifferent = true;
|
|
||||||
if ((session.getFactory().getDialect() instanceof Oracle8iDialect) && (newObj instanceof String || oldObj instanceof String)) {
|
|
||||||
// Don't generate new revision when database replaces empty string with NULL during INSERT or UPDATE statements.
|
|
||||||
dbLogicallyDifferent = !(StringTools.isEmpty(newObj) && StringTools.isEmpty(oldObj));
|
|
||||||
}
|
|
||||||
return dbLogicallyDifferent && !Tools.objectsEqual(newObj, oldObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
public void add(PropertyData propertyData) {
|
||||||
if (propertyData.isUsingModifiedFlag()) {
|
if ( this.propertyData != null ) {
|
||||||
data.put(propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual(newObj, oldObj));
|
throw new AuditException( "Only one property can be added!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.propertyData = propertyData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mapToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
data.put( propertyData.getName(), newObj );
|
||||||
|
boolean dbLogicallyDifferent = true;
|
||||||
|
if ( (session.getFactory()
|
||||||
|
.getDialect() instanceof Oracle8iDialect) && (newObj instanceof String || oldObj instanceof String) ) {
|
||||||
|
// Don't generate new revision when database replaces empty string with NULL during INSERT or UPDATE statements.
|
||||||
|
dbLogicallyDifferent = !(StringTools.isEmpty( newObj ) && StringTools.isEmpty( oldObj ));
|
||||||
|
}
|
||||||
|
return dbLogicallyDifferent && !Tools.objectsEqual( newObj, oldObj );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mapModifiedFlagsToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
if ( propertyData.isUsingModifiedFlag() ) {
|
||||||
|
data.put( propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual( newObj, oldObj ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,43 +97,50 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
|
||||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
@Override
|
||||||
AuditReaderImplementor versionsReader, Number revision) {
|
public void mapToEntityFromMap(
|
||||||
if (data == null || obj == null) {
|
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||||
return;
|
AuditReaderImplementor versionsReader, Number revision) {
|
||||||
}
|
if ( data == null || obj == null ) {
|
||||||
|
return;
|
||||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
|
|
||||||
Object value = data.get(propertyData.getName());
|
|
||||||
// We only set a null value if the field is not primite. Otherwise, we leave it intact.
|
|
||||||
if (value != null || !isPrimitive(setter, propertyData, obj.getClass())) {
|
|
||||||
setter.set(obj, value, null);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
|
||||||
|
final Object value = data.get( propertyData.getName() );
|
||||||
|
// We only set a null value if the field is not primite. Otherwise, we leave it intact.
|
||||||
|
if ( value != null || !isPrimitive( setter, propertyData, obj.getClass() ) ) {
|
||||||
|
setter.set( obj, value, null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isPrimitive(Setter setter, PropertyData propertyData, Class<?> cls) {
|
private boolean isPrimitive(Setter setter, PropertyData propertyData, Class<?> cls) {
|
||||||
if (cls == null) {
|
if ( cls == null ) {
|
||||||
throw new HibernateException("No field found for property: " + propertyData.getName());
|
throw new HibernateException( "No field found for property: " + propertyData.getName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setter instanceof DirectPropertyAccessor.DirectSetter) {
|
if ( setter instanceof DirectPropertyAccessor.DirectSetter ) {
|
||||||
// In a direct setter, getMethod() returns null
|
// In a direct setter, getMethod() returns null
|
||||||
// Trying to look up the field
|
// Trying to look up the field
|
||||||
try {
|
try {
|
||||||
return cls.getDeclaredField(propertyData.getBeanName()).getType().isPrimitive();
|
return cls.getDeclaredField( propertyData.getBeanName() ).getType().isPrimitive();
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
return isPrimitive(setter, propertyData, cls.getSuperclass());
|
|
||||||
}
|
}
|
||||||
} else {
|
catch (NoSuchFieldException e) {
|
||||||
|
return isPrimitive( setter, propertyData, cls.getSuperclass() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
return setter.getMethod().getParameterTypes()[0].isPrimitive();
|
return setter.getMethod().getParameterTypes()[0].isPrimitive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor sessionImplementor,
|
@Override
|
||||||
String referencingPropertyName,
|
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||||
PersistentCollection newColl,
|
SessionImplementor sessionImplementor,
|
||||||
Serializable oldColl, Serializable id) {
|
String referencingPropertyName,
|
||||||
return null;
|
PersistentCollection newColl,
|
||||||
}
|
Serializable oldColl,
|
||||||
|
Serializable id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -36,84 +37,124 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
/**
|
/**
|
||||||
* A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper
|
* A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper
|
||||||
* should be the mapper of the subclass.
|
* should be the mapper of the subclass.
|
||||||
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public class SubclassPropertyMapper implements ExtendedPropertyMapper {
|
public class SubclassPropertyMapper implements ExtendedPropertyMapper {
|
||||||
private ExtendedPropertyMapper main;
|
private ExtendedPropertyMapper main;
|
||||||
private ExtendedPropertyMapper parentMapper;
|
private ExtendedPropertyMapper parentMapper;
|
||||||
|
|
||||||
public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMapper parentMapper) {
|
public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMapper parentMapper) {
|
||||||
this.main = main;
|
this.main = main;
|
||||||
this.parentMapper = parentMapper;
|
this.parentMapper = parentMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
|
|
||||||
boolean parentDiffs = parentMapper.map(session, data, propertyNames, newState, oldState);
|
|
||||||
boolean mainDiffs = main.map(session, data, propertyNames, newState, oldState);
|
|
||||||
|
|
||||||
return parentDiffs || mainDiffs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
|
||||||
boolean parentDiffs = parentMapper.mapToMapFromEntity(session, data, newObj, oldObj);
|
|
||||||
boolean mainDiffs = main.mapToMapFromEntity(session, data, newObj, oldObj);
|
|
||||||
|
|
||||||
return parentDiffs || mainDiffs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
public boolean map(
|
||||||
parentMapper.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj);
|
SessionImplementor session,
|
||||||
main.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj);
|
Map<String, Object> data,
|
||||||
|
String[] propertyNames,
|
||||||
|
Object[] newState,
|
||||||
|
Object[] oldState) {
|
||||||
|
final boolean parentDiffs = parentMapper.map( session, data, propertyNames, newState, oldState );
|
||||||
|
final boolean mainDiffs = main.map( session, data, propertyNames, newState, oldState );
|
||||||
|
|
||||||
|
return parentDiffs || mainDiffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mapToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
final boolean parentDiffs = parentMapper.mapToMapFromEntity( session, data, newObj, oldObj );
|
||||||
|
final boolean mainDiffs = main.mapToMapFromEntity( session, data, newObj, oldObj );
|
||||||
|
|
||||||
|
return parentDiffs || mainDiffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mapModifiedFlagsToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
parentMapper.mapModifiedFlagsToMapFromEntity( session, data, newObj, oldObj );
|
||||||
|
main.mapModifiedFlagsToMapFromEntity( session, data, newObj, oldObj );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||||
parentMapper.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data);
|
parentMapper.mapModifiedFlagsToMapForCollectionChange( collectionPropertyName, data );
|
||||||
main.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data);
|
main.mapModifiedFlagsToMapForCollectionChange( collectionPropertyName, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
|
@Override
|
||||||
parentMapper.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
public void mapToEntityFromMap(
|
||||||
main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
AuditConfiguration verCfg,
|
||||||
}
|
Object obj,
|
||||||
|
Map data,
|
||||||
|
Object primaryKey,
|
||||||
|
AuditReaderImplementor versionsReader,
|
||||||
|
Number revision) {
|
||||||
|
parentMapper.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
|
||||||
|
main.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
|
||||||
|
}
|
||||||
|
|
||||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
@Override
|
||||||
PersistentCollection newColl,
|
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||||
Serializable oldColl, Serializable id) {
|
SessionImplementor session, String referencingPropertyName,
|
||||||
List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
|
PersistentCollection newColl,
|
||||||
session, referencingPropertyName, newColl, oldColl, id);
|
Serializable oldColl, Serializable id) {
|
||||||
|
final List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
|
||||||
|
session,
|
||||||
|
referencingPropertyName,
|
||||||
|
newColl,
|
||||||
|
oldColl,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
|
||||||
List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
|
final List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
|
||||||
session, referencingPropertyName, newColl, oldColl, id);
|
session,
|
||||||
|
referencingPropertyName,
|
||||||
|
newColl,
|
||||||
|
oldColl,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
|
||||||
if (parentCollectionChanges == null) {
|
if ( parentCollectionChanges == null ) {
|
||||||
return mainCollectionChanges;
|
return mainCollectionChanges;
|
||||||
} else {
|
}
|
||||||
if(mainCollectionChanges != null) {
|
else {
|
||||||
parentCollectionChanges.addAll(mainCollectionChanges);
|
if ( mainCollectionChanges != null ) {
|
||||||
}
|
parentCollectionChanges.addAll( mainCollectionChanges );
|
||||||
|
}
|
||||||
return parentCollectionChanges;
|
return parentCollectionChanges;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
@Override
|
||||||
return main.addComponent(propertyData, componentClass);
|
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
||||||
}
|
return main.addComponent( propertyData, componentClass );
|
||||||
|
}
|
||||||
|
|
||||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
@Override
|
||||||
main.addComposite(propertyData, propertyMapper);
|
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
||||||
}
|
main.addComposite( propertyData, propertyMapper );
|
||||||
|
}
|
||||||
|
|
||||||
public void add(PropertyData propertyData) {
|
@Override
|
||||||
main.add(propertyData);
|
public void add(PropertyData propertyData) {
|
||||||
}
|
main.add( propertyData );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Map<PropertyData, PropertyMapper> getProperties() {
|
public Map<PropertyData, PropertyMapper> getProperties() {
|
||||||
final Map<PropertyData, PropertyMapper> joinedProperties = new HashMap<PropertyData, PropertyMapper>();
|
final Map<PropertyData, PropertyMapper> joinedProperties = new HashMap<PropertyData, PropertyMapper>();
|
||||||
joinedProperties.putAll(parentMapper.getProperties());
|
joinedProperties.putAll( parentMapper.getProperties() );
|
||||||
joinedProperties.putAll(main.getProperties());
|
joinedProperties.putAll( main.getProperties() );
|
||||||
return joinedProperties;
|
return joinedProperties;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -35,36 +35,39 @@ import org.hibernate.internal.util.ReflectHelper;
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractCompositeIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
public abstract class AbstractCompositeIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
||||||
protected Map<PropertyData, SingleIdMapper> ids;
|
protected Map<PropertyData, SingleIdMapper> ids;
|
||||||
protected Class compositeIdClass;
|
protected Class compositeIdClass;
|
||||||
|
|
||||||
protected AbstractCompositeIdMapper(Class compositeIdClass) {
|
protected AbstractCompositeIdMapper(Class compositeIdClass) {
|
||||||
ids = Tools.newLinkedHashMap();
|
ids = Tools.newLinkedHashMap();
|
||||||
this.compositeIdClass = compositeIdClass;
|
this.compositeIdClass = compositeIdClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(PropertyData propertyData) {
|
@Override
|
||||||
ids.put(propertyData, new SingleIdMapper(propertyData));
|
public void add(PropertyData propertyData) {
|
||||||
}
|
ids.put( propertyData, new SingleIdMapper( propertyData ) );
|
||||||
|
}
|
||||||
|
|
||||||
public Object mapToIdFromMap(Map data) {
|
@Override
|
||||||
if (data == null) {
|
public Object mapToIdFromMap(Map data) {
|
||||||
return null;
|
if ( data == null ) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Object ret;
|
final Object ret;
|
||||||
try {
|
try {
|
||||||
ret = ReflectHelper.getDefaultConstructor(compositeIdClass).newInstance();
|
ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
|
||||||
} catch (Exception e) {
|
}
|
||||||
throw new AuditException(e);
|
catch (Exception e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
|
||||||
for (SingleIdMapper mapper : ids.values()) {
|
for ( SingleIdMapper mapper : ids.values() ) {
|
||||||
if (!mapper.mapToEntityFromMap(ret, data)) {
|
if ( !mapper.mapToEntityFromMap( ret, data ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -31,69 +32,96 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractIdMapper implements IdMapper {
|
public abstract class AbstractIdMapper implements IdMapper {
|
||||||
private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) {
|
private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) {
|
||||||
if (paramDatas.size() > 1) {
|
if ( paramDatas.size() > 1 ) {
|
||||||
return parameters.addSubParameters("and");
|
return parameters.addSubParameters( "and" );
|
||||||
} else {
|
}
|
||||||
return parameters;
|
else {
|
||||||
}
|
return parameters;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
|
@Override
|
||||||
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
|
public void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
|
||||||
|
final List<QueryParameterData> paramDatas = mapToQueryParametersFromId( null );
|
||||||
|
|
||||||
Parameters parametersToUse = getParametersToUse(parameters, paramDatas);
|
final Parameters parametersToUse = getParametersToUse( parameters, paramDatas );
|
||||||
|
|
||||||
for (QueryParameterData paramData : paramDatas) {
|
for ( QueryParameterData paramData : paramDatas ) {
|
||||||
parametersToUse.addWhere(paramData.getProperty(prefix1), false, "=", paramData.getProperty(prefix2), false);
|
parametersToUse.addWhere(
|
||||||
}
|
paramData.getProperty( prefix1 ),
|
||||||
}
|
false,
|
||||||
|
"=",
|
||||||
|
paramData.getProperty( prefix2 ),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) {
|
@Override
|
||||||
List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId(null);
|
public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) {
|
||||||
List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId(null);
|
final List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId( null );
|
||||||
|
final List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId( null );
|
||||||
|
|
||||||
Parameters parametersToUse = getParametersToUse(parameters, paramDatas1);
|
final Parameters parametersToUse = getParametersToUse( parameters, paramDatas1 );
|
||||||
|
|
||||||
Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator();
|
final Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator();
|
||||||
Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
|
final Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
|
||||||
while (paramDataIter1.hasNext()) {
|
while ( paramDataIter1.hasNext() ) {
|
||||||
QueryParameterData paramData1 = paramDataIter1.next();
|
final QueryParameterData paramData1 = paramDataIter1.next();
|
||||||
QueryParameterData paramData2 = paramDataIter2.next();
|
final QueryParameterData paramData2 = paramDataIter2.next();
|
||||||
|
|
||||||
parametersToUse.addWhere(paramData1.getProperty(prefix1), false, "=", paramData2.getProperty(prefix2), false);
|
parametersToUse.addWhere(
|
||||||
}
|
paramData1.getProperty( prefix1 ),
|
||||||
}
|
false,
|
||||||
|
"=",
|
||||||
|
paramData2.getProperty( prefix2 ),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals) {
|
@Override
|
||||||
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(id);
|
public void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals) {
|
||||||
|
final List<QueryParameterData> paramDatas = mapToQueryParametersFromId( id );
|
||||||
|
|
||||||
Parameters parametersToUse = getParametersToUse(parameters, paramDatas);
|
final Parameters parametersToUse = getParametersToUse( parameters, paramDatas );
|
||||||
|
|
||||||
for (QueryParameterData paramData : paramDatas) {
|
for ( QueryParameterData paramData : paramDatas ) {
|
||||||
if (paramData.getValue() == null) {
|
if ( paramData.getValue() == null ) {
|
||||||
handleNullValue(parametersToUse, paramData.getProperty(prefix), equals);
|
handleNullValue( parametersToUse, paramData.getProperty( prefix ), equals );
|
||||||
} else {
|
}
|
||||||
parametersToUse.addWhereWithParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getValue());
|
else {
|
||||||
}
|
parametersToUse.addWhereWithParam(
|
||||||
}
|
paramData.getProperty( prefix ),
|
||||||
}
|
equals ? "=" : "<>",
|
||||||
|
paramData.getValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals) {
|
@Override
|
||||||
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
|
public void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals) {
|
||||||
|
final List<QueryParameterData> paramDatas = mapToQueryParametersFromId( null );
|
||||||
|
|
||||||
Parameters parametersToUse = getParametersToUse(parameters, paramDatas);
|
final Parameters parametersToUse = getParametersToUse( parameters, paramDatas );
|
||||||
|
|
||||||
for (QueryParameterData paramData : paramDatas) {
|
for ( QueryParameterData paramData : paramDatas ) {
|
||||||
parametersToUse.addWhereWithNamedParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getQueryParameterName());
|
parametersToUse.addWhereWithNamedParam(
|
||||||
}
|
paramData.getProperty( prefix ),
|
||||||
}
|
equals ? "=" : "<>",
|
||||||
|
paramData.getQueryParameterName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleNullValue(Parameters parameters, String propertyName, boolean equals) {
|
private void handleNullValue(Parameters parameters, String propertyName, boolean equals) {
|
||||||
if (equals) {
|
if ( equals ) {
|
||||||
parameters.addNullRestriction(propertyName, equals);
|
parameters.addNullRestriction( propertyName, equals );
|
||||||
} else {
|
}
|
||||||
parameters.addNotNullRestriction(propertyName, equals);
|
else {
|
||||||
}
|
parameters.addNotNullRestriction( propertyName, equals );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -39,85 +39,92 @@ import org.hibernate.property.Setter;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
||||||
private PropertyData idPropertyData;
|
private PropertyData idPropertyData;
|
||||||
|
|
||||||
public EmbeddedIdMapper(PropertyData idPropertyData, Class compositeIdClass) {
|
public EmbeddedIdMapper(PropertyData idPropertyData, Class compositeIdClass) {
|
||||||
super(compositeIdClass);
|
super( compositeIdClass );
|
||||||
|
|
||||||
this.idPropertyData = idPropertyData;
|
this.idPropertyData = idPropertyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
@Override
|
||||||
for (IdMapper idMapper : ids.values()) {
|
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||||
idMapper.mapToMapFromEntity(data, obj);
|
for ( IdMapper idMapper : ids.values() ) {
|
||||||
}
|
idMapper.mapToMapFromEntity( data, obj );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
@Override
|
||||||
if (obj == null) {
|
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||||
return;
|
if ( obj == null ) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyData);
|
final Getter getter = ReflectionTools.getGetter( obj.getClass(), idPropertyData );
|
||||||
mapToMapFromId(data, getter.get(obj));
|
mapToMapFromId( data, getter.get( obj ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
@Override
|
||||||
if (data == null || obj == null) {
|
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||||
return false;
|
if ( data == null || obj == null ) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyData);
|
final Getter getter = ReflectionTools.getGetter( obj.getClass(), idPropertyData );
|
||||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), idPropertyData);
|
final Setter setter = ReflectionTools.getSetter( obj.getClass(), idPropertyData );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object subObj = ReflectHelper.getDefaultConstructor( getter.getReturnType() ).newInstance();
|
final Object subObj = ReflectHelper.getDefaultConstructor( getter.getReturnType() ).newInstance();
|
||||||
|
|
||||||
boolean ret = true;
|
boolean ret = true;
|
||||||
for (IdMapper idMapper : ids.values()) {
|
for ( IdMapper idMapper : ids.values() ) {
|
||||||
ret &= idMapper.mapToEntityFromMap(subObj, data);
|
ret &= idMapper.mapToEntityFromMap( subObj, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if ( ret ) {
|
||||||
setter.set(obj, subObj, null);
|
setter.set( obj, subObj, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} catch (Exception e) {
|
}
|
||||||
throw new AuditException(e);
|
catch (Exception e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IdMapper prefixMappedProperties(String prefix) {
|
@Override
|
||||||
EmbeddedIdMapper ret = new EmbeddedIdMapper(idPropertyData, compositeIdClass);
|
public IdMapper prefixMappedProperties(String prefix) {
|
||||||
|
final EmbeddedIdMapper ret = new EmbeddedIdMapper( idPropertyData, compositeIdClass );
|
||||||
|
|
||||||
for (PropertyData propertyData : ids.keySet()) {
|
for ( PropertyData propertyData : ids.keySet() ) {
|
||||||
String propertyName = propertyData.getName();
|
final String propertyName = propertyData.getName();
|
||||||
ret.ids.put(propertyData, new SingleIdMapper(new PropertyData(prefix + propertyName, propertyData)));
|
ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object mapToIdFromEntity(Object data) {
|
@Override
|
||||||
if (data == null) {
|
public Object mapToIdFromEntity(Object data) {
|
||||||
return null;
|
if ( data == null ) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Getter getter = ReflectionTools.getGetter(data.getClass(), idPropertyData);
|
final Getter getter = ReflectionTools.getGetter( data.getClass(), idPropertyData );
|
||||||
return getter.get(data);
|
return getter.get( data );
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
@Override
|
||||||
Map<String, Object> data = new LinkedHashMap<String, Object>();
|
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
||||||
mapToMapFromId(data, obj);
|
final Map<String, Object> data = new LinkedHashMap<String, Object>();
|
||||||
|
mapToMapFromId( data, obj );
|
||||||
|
|
||||||
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
|
final List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
|
||||||
|
|
||||||
for (Map.Entry<String, Object> propertyData : data.entrySet()) {
|
for ( Map.Entry<String, Object> propertyData : data.entrySet() ) {
|
||||||
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue()));
|
ret.add( new QueryParameterData( propertyData.getKey(), propertyData.getValue() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -31,73 +32,81 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public interface IdMapper {
|
public interface IdMapper {
|
||||||
void mapToMapFromId(Map<String, Object> data, Object obj);
|
void mapToMapFromId(Map<String, Object> data, Object obj);
|
||||||
|
|
||||||
void mapToMapFromEntity(Map<String, Object> data, Object obj);
|
void mapToMapFromEntity(Map<String, Object> data, Object obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param obj Object to map to.
|
* @param obj Object to map to.
|
||||||
* @param data Data to map.
|
* @param data Data to map.
|
||||||
* @return True if data was mapped; false otherwise (when the id is {@code null}).
|
*
|
||||||
*/
|
* @return True if data was mapped; false otherwise (when the id is {@code null}).
|
||||||
boolean mapToEntityFromMap(Object obj, Map data);
|
*/
|
||||||
|
boolean mapToEntityFromMap(Object obj, Map data);
|
||||||
|
|
||||||
Object mapToIdFromEntity(Object data);
|
Object mapToIdFromEntity(Object data);
|
||||||
|
|
||||||
Object mapToIdFromMap(Map data);
|
Object mapToIdFromMap(Map data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a mapper with all mapped properties prefixed. A mapped property is a property which
|
* Creates a mapper with all mapped properties prefixed. A mapped property is a property which
|
||||||
* is directly mapped to values (not composite).
|
* is directly mapped to values (not composite).
|
||||||
* @param prefix Prefix to add to mapped properties
|
*
|
||||||
* @return A copy of the current property mapper, with mapped properties prefixed.
|
* @param prefix Prefix to add to mapped properties
|
||||||
*/
|
*
|
||||||
IdMapper prefixMappedProperties(String prefix);
|
* @return A copy of the current property mapper, with mapped properties prefixed.
|
||||||
|
*/
|
||||||
|
IdMapper prefixMappedProperties(String prefix);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param obj Id from which to map.
|
* @param obj Id from which to map.
|
||||||
* @return A set parameter data, needed to build a query basing on the given id.
|
*
|
||||||
*/
|
* @return A set parameter data, needed to build a query basing on the given id.
|
||||||
List<QueryParameterData> mapToQueryParametersFromId(Object obj);
|
*/
|
||||||
|
List<QueryParameterData> mapToQueryParametersFromId(Object obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds query statements, which contains restrictions, which express the property that the id of the entity
|
* Adds query statements, which contains restrictions, which express the property that the id of the entity
|
||||||
* with alias prefix1, is equal to the id of the entity with alias prefix2 (the entity is the same).
|
* with alias prefix1, is equal to the id of the entity with alias prefix2 (the entity is the same).
|
||||||
* @param parameters Parameters, to which to add the statements.
|
*
|
||||||
* @param prefix1 First alias of the entity + prefix to add to the properties.
|
* @param parameters Parameters, to which to add the statements.
|
||||||
* @param prefix2 Second alias of the entity + prefix to add to the properties.
|
* @param prefix1 First alias of the entity + prefix to add to the properties.
|
||||||
*/
|
* @param prefix2 Second alias of the entity + prefix to add to the properties.
|
||||||
void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2);
|
*/
|
||||||
|
void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds query statements, which contains restrictions, which express the property that the id of the entity
|
* Adds query statements, which contains restrictions, which express the property that the id of the entity
|
||||||
* with alias prefix1, is equal to the id of the entity with alias prefix2 mapped by the second mapper
|
* with alias prefix1, is equal to the id of the entity with alias prefix2 mapped by the second mapper
|
||||||
* (the second mapper must be for the same entity, but it can have, for example, prefixed properties).
|
* (the second mapper must be for the same entity, but it can have, for example, prefixed properties).
|
||||||
* @param parameters Parameters, to which to add the statements.
|
*
|
||||||
* @param prefix1 First alias of the entity + prefix to add to the properties.
|
* @param parameters Parameters, to which to add the statements.
|
||||||
* @param mapper2 Second mapper for the same entity, which will be used to get properties for the right side
|
* @param prefix1 First alias of the entity + prefix to add to the properties.
|
||||||
* of the equation.
|
* @param mapper2 Second mapper for the same entity, which will be used to get properties for the right side
|
||||||
* @param prefix2 Second alias of the entity + prefix to add to the properties.
|
* of the equation.
|
||||||
*/
|
* @param prefix2 Second alias of the entity + prefix to add to the properties.
|
||||||
void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2);
|
*/
|
||||||
|
void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds query statements, which contains restrictions, which express the property that the id of the entity
|
* Adds query statements, which contains restrictions, which express the property that the id of the entity
|
||||||
* with alias prefix, is equal to the given object.
|
* with alias prefix, is equal to the given object.
|
||||||
* @param parameters Parameters, to which to add the statements.
|
*
|
||||||
* @param id Value of id.
|
* @param parameters Parameters, to which to add the statements.
|
||||||
* @param prefix Prefix to add to the properties (may be null).
|
* @param id Value of id.
|
||||||
* @param equals Should this query express the "=" relation or the "<>" relation.
|
* @param prefix Prefix to add to the properties (may be null).
|
||||||
*/
|
* @param equals Should this query express the "=" relation or the "<>" relation.
|
||||||
void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals);
|
*/
|
||||||
|
void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds query statements, which contains named parameters, which express the property that the id of the entity
|
* Adds query statements, which contains named parameters, which express the property that the id of the entity
|
||||||
* with alias prefix, is equal to the given object. It is the responsibility of the using method to read
|
* with alias prefix, is equal to the given object. It is the responsibility of the using method to read
|
||||||
* parameter values from the id and specify them on the final query object.
|
* parameter values from the id and specify them on the final query object.
|
||||||
* @param parameters Parameters, to which to add the statements.
|
*
|
||||||
* @param prefix Prefix to add to the properties (may be null).
|
* @param parameters Parameters, to which to add the statements.
|
||||||
* @param equals Should this query express the "=" relation or the "<>" relation.
|
* @param prefix Prefix to add to the properties (may be null).
|
||||||
*/
|
* @param equals Should this query express the "=" relation or the "<>" relation.
|
||||||
void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals);
|
*/
|
||||||
|
void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -36,69 +36,76 @@ import org.hibernate.internal.util.ReflectHelper;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
||||||
public MultipleIdMapper(Class compositeIdClass) {
|
public MultipleIdMapper(Class compositeIdClass) {
|
||||||
super(compositeIdClass);
|
super( compositeIdClass );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
@Override
|
||||||
for (IdMapper idMapper : ids.values()) {
|
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||||
idMapper.mapToMapFromEntity(data, obj);
|
for ( IdMapper idMapper : ids.values() ) {
|
||||||
}
|
idMapper.mapToMapFromEntity( data, obj );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
@Override
|
||||||
mapToMapFromId(data, obj);
|
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||||
}
|
mapToMapFromId( data, obj );
|
||||||
|
}
|
||||||
|
|
||||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
@Override
|
||||||
boolean ret = true;
|
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||||
for (IdMapper idMapper : ids.values()) {
|
boolean ret = true;
|
||||||
ret &= idMapper.mapToEntityFromMap(obj, data);
|
for ( IdMapper idMapper : ids.values() ) {
|
||||||
}
|
ret &= idMapper.mapToEntityFromMap( obj, data );
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdMapper prefixMappedProperties(String prefix) {
|
@Override
|
||||||
MultipleIdMapper ret = new MultipleIdMapper(compositeIdClass);
|
public IdMapper prefixMappedProperties(String prefix) {
|
||||||
|
final MultipleIdMapper ret = new MultipleIdMapper( compositeIdClass );
|
||||||
|
|
||||||
for (PropertyData propertyData : ids.keySet()) {
|
for ( PropertyData propertyData : ids.keySet() ) {
|
||||||
String propertyName = propertyData.getName();
|
final String propertyName = propertyData.getName();
|
||||||
ret.ids.put(propertyData, new SingleIdMapper(new PropertyData(prefix + propertyName, propertyData)));
|
ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object mapToIdFromEntity(Object data) {
|
@Override
|
||||||
if (data == null) {
|
public Object mapToIdFromEntity(Object data) {
|
||||||
return null;
|
if ( data == null ) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Object ret;
|
final Object ret;
|
||||||
try {
|
try {
|
||||||
ret = ReflectHelper.getDefaultConstructor(compositeIdClass).newInstance();
|
ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
|
||||||
} catch (Exception e) {
|
}
|
||||||
throw new AuditException(e);
|
catch (Exception e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
|
||||||
for (SingleIdMapper mapper : ids.values()) {
|
for ( SingleIdMapper mapper : ids.values() ) {
|
||||||
mapper.mapToEntityFromEntity(ret, data);
|
mapper.mapToEntityFromEntity( ret, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
@Override
|
||||||
Map<String, Object> data = new LinkedHashMap<String, Object>();
|
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
||||||
mapToMapFromId(data, obj);
|
final Map<String, Object> data = new LinkedHashMap<String, Object>();
|
||||||
|
mapToMapFromId( data, obj );
|
||||||
|
|
||||||
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
|
final List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
|
||||||
|
|
||||||
for (Map.Entry<String, Object> propertyData : data.entrySet()) {
|
for ( Map.Entry<String, Object> propertyData : data.entrySet() ) {
|
||||||
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue()));
|
ret.add( new QueryParameterData( propertyData.getKey(), propertyData.getValue() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,53 +22,58 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.internal.util.compare.EqualsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class QueryParameterData {
|
public class QueryParameterData {
|
||||||
private String flatEntityPropertyName;
|
private String flatEntityPropertyName;
|
||||||
private Object value;
|
private Object value;
|
||||||
|
|
||||||
public QueryParameterData(String flatEntityPropertyName, Object value) {
|
public QueryParameterData(String flatEntityPropertyName, Object value) {
|
||||||
this.flatEntityPropertyName = flatEntityPropertyName;
|
this.flatEntityPropertyName = flatEntityPropertyName;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getProperty(String prefix) {
|
public String getProperty(String prefix) {
|
||||||
if (prefix != null) {
|
if ( prefix != null ) {
|
||||||
return prefix + "." + flatEntityPropertyName;
|
return prefix + "." + flatEntityPropertyName;
|
||||||
} else {
|
}
|
||||||
return flatEntityPropertyName;
|
else {
|
||||||
}
|
return flatEntityPropertyName;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParameterValue(Query query) {
|
public void setParameterValue(Query query) {
|
||||||
query.setParameter(flatEntityPropertyName, value);
|
query.setParameter( flatEntityPropertyName, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getQueryParameterName() {
|
public String getQueryParameterName() {
|
||||||
return flatEntityPropertyName;
|
return flatEntityPropertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
@Override
|
||||||
if (this == o) return true;
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof QueryParameterData)) return false;
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( !(o instanceof QueryParameterData) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QueryParameterData that = (QueryParameterData) o;
|
final QueryParameterData that = (QueryParameterData) o;
|
||||||
|
return EqualsHelper.equals( flatEntityPropertyName, that.flatEntityPropertyName );
|
||||||
|
}
|
||||||
|
|
||||||
if (flatEntityPropertyName != null ? !flatEntityPropertyName.equals(that.flatEntityPropertyName) : that.flatEntityPropertyName != null)
|
@Override
|
||||||
return false;
|
public int hashCode() {
|
||||||
|
return (flatEntityPropertyName != null ? flatEntityPropertyName.hashCode() : 0);
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return (flatEntityPropertyName != null ? flatEntityPropertyName.hashCode() : 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
|
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -38,100 +38,111 @@ import org.hibernate.proxy.HibernateProxy;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
||||||
private PropertyData propertyData;
|
private PropertyData propertyData;
|
||||||
|
|
||||||
public SingleIdMapper() {
|
public SingleIdMapper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SingleIdMapper(PropertyData propertyData) {
|
public SingleIdMapper(PropertyData propertyData) {
|
||||||
this.propertyData = propertyData;
|
this.propertyData = propertyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(PropertyData propertyData) {
|
@Override
|
||||||
if (this.propertyData != null) {
|
public void add(PropertyData propertyData) {
|
||||||
throw new AuditException("Only one property can be added!");
|
if ( this.propertyData != null ) {
|
||||||
}
|
throw new AuditException( "Only one property can be added!" );
|
||||||
|
}
|
||||||
|
|
||||||
this.propertyData = propertyData;
|
this.propertyData = propertyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
@Override
|
||||||
if (data == null || obj == null) {
|
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||||
return false;
|
if ( data == null || obj == null ) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Object value = data.get(propertyData.getName());
|
final Object value = data.get( propertyData.getName() );
|
||||||
if (value == null) {
|
if ( value == null ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
|
final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
|
||||||
setter.set(obj, value, null);
|
setter.set( obj, value, null );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object mapToIdFromMap(Map data) {
|
@Override
|
||||||
if (data == null) {
|
public Object mapToIdFromMap(Map data) {
|
||||||
return null;
|
if ( data == null ) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return data.get(propertyData.getName());
|
return data.get( propertyData.getName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object mapToIdFromEntity(Object data) {
|
@Override
|
||||||
if (data == null) {
|
public Object mapToIdFromEntity(Object data) {
|
||||||
return null;
|
if ( data == null ) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if(data instanceof HibernateProxy) {
|
if ( data instanceof HibernateProxy ) {
|
||||||
HibernateProxy hibernateProxy = (HibernateProxy) data;
|
final HibernateProxy hibernateProxy = (HibernateProxy) data;
|
||||||
return hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
return hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
||||||
} else {
|
}
|
||||||
Getter getter = ReflectionTools.getGetter(data.getClass(), propertyData);
|
else {
|
||||||
return getter.get(data);
|
final Getter getter = ReflectionTools.getGetter( data.getClass(), propertyData );
|
||||||
}
|
return getter.get( data );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
@Override
|
||||||
if (data != null) {
|
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||||
data.put(propertyData.getName(), obj);
|
if ( data != null ) {
|
||||||
}
|
data.put( propertyData.getName(), obj );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
@Override
|
||||||
if (obj == null) {
|
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||||
data.put(propertyData.getName(), null);
|
if ( obj == null ) {
|
||||||
} else {
|
data.put( propertyData.getName(), null );
|
||||||
if(obj instanceof HibernateProxy) {
|
}
|
||||||
HibernateProxy hibernateProxy = (HibernateProxy)obj;
|
else {
|
||||||
data.put(propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier());
|
if ( obj instanceof HibernateProxy ) {
|
||||||
} else {
|
final HibernateProxy hibernateProxy = (HibernateProxy) obj;
|
||||||
Getter getter = ReflectionTools.getGetter(obj.getClass(), propertyData);
|
data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier() );
|
||||||
data.put(propertyData.getName(), getter.get(obj));
|
}
|
||||||
}
|
else {
|
||||||
}
|
final Getter getter = ReflectionTools.getGetter( obj.getClass(), propertyData );
|
||||||
}
|
data.put( propertyData.getName(), getter.get( obj ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void mapToEntityFromEntity(Object objTo, Object objFrom) {
|
public void mapToEntityFromEntity(Object objTo, Object objFrom) {
|
||||||
if (objTo == null || objFrom == null) {
|
if ( objTo == null || objFrom == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Getter getter = ReflectionTools.getGetter(objFrom.getClass(), propertyData);
|
final Getter getter = ReflectionTools.getGetter( objFrom.getClass(), propertyData );
|
||||||
Setter setter = ReflectionTools.getSetter(objTo.getClass(), propertyData);
|
final Setter setter = ReflectionTools.getSetter( objTo.getClass(), propertyData );
|
||||||
setter.set(objTo, getter.get(objFrom), null);
|
setter.set( objTo, getter.get( objFrom ), null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdMapper prefixMappedProperties(String prefix) {
|
@Override
|
||||||
return new SingleIdMapper(new PropertyData(prefix + propertyData.getName(), propertyData));
|
public IdMapper prefixMappedProperties(String prefix) {
|
||||||
}
|
return new SingleIdMapper( new PropertyData( prefix + propertyData.getName(), propertyData ) );
|
||||||
|
}
|
||||||
|
|
||||||
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
@Override
|
||||||
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
|
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
||||||
|
final List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
|
||||||
|
|
||||||
ret.add(new QueryParameterData(propertyData.getName(), obj));
|
ret.add( new QueryParameterData( propertyData.getName(), obj ) );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -53,43 +53,53 @@ import org.hibernate.property.Setter;
|
||||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
||||||
protected final CommonCollectionMapperData commonCollectionMapperData;
|
protected final CommonCollectionMapperData commonCollectionMapperData;
|
||||||
protected final Class<? extends T> collectionClass;
|
protected final Class<? extends T> collectionClass;
|
||||||
protected final boolean ordinalInId;
|
protected final boolean ordinalInId;
|
||||||
protected final boolean revisionTypeInId;
|
protected final boolean revisionTypeInId;
|
||||||
|
|
||||||
private final Constructor<? extends T> proxyConstructor;
|
private final Constructor<? extends T> proxyConstructor;
|
||||||
|
|
||||||
protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
|
protected AbstractCollectionMapper(
|
||||||
|
CommonCollectionMapperData commonCollectionMapperData,
|
||||||
Class<? extends T> collectionClass, Class<? extends T> proxyClass, boolean ordinalInId,
|
Class<? extends T> collectionClass, Class<? extends T> proxyClass, boolean ordinalInId,
|
||||||
boolean revisionTypeInId) {
|
boolean revisionTypeInId) {
|
||||||
this.commonCollectionMapperData = commonCollectionMapperData;
|
this.commonCollectionMapperData = commonCollectionMapperData;
|
||||||
this.collectionClass = collectionClass;
|
this.collectionClass = collectionClass;
|
||||||
this.ordinalInId = ordinalInId;
|
this.ordinalInId = ordinalInId;
|
||||||
this.revisionTypeInId = revisionTypeInId;
|
this.revisionTypeInId = revisionTypeInId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
proxyConstructor = proxyClass.getConstructor(Initializor.class);
|
proxyConstructor = proxyClass.getConstructor( Initializor.class );
|
||||||
} catch (NoSuchMethodException e) {
|
}
|
||||||
throw new AuditException(e);
|
catch (NoSuchMethodException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
|
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
|
||||||
protected abstract Collection getOldCollectionContent(Serializable oldCollection);
|
|
||||||
|
|
||||||
/**
|
protected abstract Collection getOldCollectionContent(Serializable oldCollection);
|
||||||
* Maps the changed collection element to the given map.
|
|
||||||
|
/**
|
||||||
|
* Maps the changed collection element to the given map.
|
||||||
|
*
|
||||||
* @param idData Map to which composite-id data should be added.
|
* @param idData Map to which composite-id data should be added.
|
||||||
* @param data Where to map the data.
|
* @param data Where to map the data.
|
||||||
* @param changed The changed collection element to map.
|
* @param changed The changed collection element to map.
|
||||||
*/
|
*/
|
||||||
protected abstract void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed);
|
protected abstract void mapToMapFromObject(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> idData,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object changed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates map for storing identifier data. Ordinal parameter guarantees uniqueness of primary key.
|
* Creates map for storing identifier data. Ordinal parameter guarantees uniqueness of primary key.
|
||||||
* Composite primary key cannot contain embeddable properties since they might be nullable.
|
* Composite primary key cannot contain embeddable properties since they might be nullable.
|
||||||
|
*
|
||||||
* @param ordinal Iteration ordinal.
|
* @param ordinal Iteration ordinal.
|
||||||
|
*
|
||||||
* @return Map for holding identifier data.
|
* @return Map for holding identifier data.
|
||||||
*/
|
*/
|
||||||
protected Map<String, Object> createIdMap(int ordinal) {
|
protected Map<String, Object> createIdMap(int ordinal) {
|
||||||
|
@ -100,79 +110,113 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
||||||
return idMap;
|
return idMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCollectionChanges(SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
|
private void addCollectionChanges(
|
||||||
Set<Object> changed, RevisionType revisionType, Serializable id) {
|
SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
|
||||||
|
Set<Object> changed, RevisionType revisionType, Serializable id) {
|
||||||
int ordinal = 0;
|
int ordinal = 0;
|
||||||
|
|
||||||
for (Object changedObj : changed) {
|
for ( Object changedObj : changed ) {
|
||||||
Map<String, Object> entityData = new HashMap<String, Object>();
|
final Map<String, Object> entityData = new HashMap<String, Object>();
|
||||||
Map<String, Object> originalId = createIdMap( ordinal++ );
|
final Map<String, Object> originalId = createIdMap( ordinal++ );
|
||||||
entityData.put(commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId);
|
entityData.put( commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId );
|
||||||
|
|
||||||
collectionChanges.add(new PersistentCollectionChangeData(
|
collectionChanges.add(
|
||||||
commonCollectionMapperData.getVersionsMiddleEntityName(), entityData, changedObj));
|
new PersistentCollectionChangeData(
|
||||||
// Mapping the collection owner's id.
|
commonCollectionMapperData.getVersionsMiddleEntityName(), entityData, changedObj
|
||||||
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId(originalId, id);
|
)
|
||||||
|
);
|
||||||
|
// Mapping the collection owner's id.
|
||||||
|
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId( originalId, id );
|
||||||
|
|
||||||
// Mapping collection element and index (if present).
|
// Mapping collection element and index (if present).
|
||||||
mapToMapFromObject(session, originalId, entityData, changedObj);
|
mapToMapFromObject( session, originalId, entityData, changedObj );
|
||||||
|
|
||||||
(revisionTypeInId ? originalId : entityData).put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType);
|
(revisionTypeInId ? originalId : entityData).put(
|
||||||
}
|
commonCollectionMapperData.getVerEntCfg()
|
||||||
}
|
.getRevisionTypePropName(), revisionType
|
||||||
|
);
|
||||||
@SuppressWarnings({"unchecked"})
|
}
|
||||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
|
}
|
||||||
String referencingPropertyName,
|
|
||||||
PersistentCollection newColl,
|
|
||||||
Serializable oldColl, Serializable id) {
|
|
||||||
if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(referencingPropertyName)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PersistentCollectionChangeData> collectionChanges = new ArrayList<PersistentCollectionChangeData>();
|
|
||||||
|
|
||||||
// Comparing new and old collection content.
|
|
||||||
Collection newCollection = getNewCollectionContent(newColl);
|
|
||||||
Collection oldCollection = getOldCollectionContent(oldColl);
|
|
||||||
|
|
||||||
Set<Object> added = new HashSet<Object>();
|
|
||||||
if (newColl != null) { added.addAll(newCollection); }
|
|
||||||
// Re-hashing the old collection as the hash codes of the elements there may have changed, and the
|
|
||||||
// removeAll in AbstractSet has an implementation that is hashcode-change sensitive (as opposed to addAll).
|
|
||||||
if (oldColl != null) { added.removeAll(new HashSet(oldCollection)); }
|
|
||||||
|
|
||||||
addCollectionChanges(session, collectionChanges, added, RevisionType.ADD, id);
|
|
||||||
|
|
||||||
Set<Object> deleted = new HashSet<Object>();
|
|
||||||
if (oldColl != null) { deleted.addAll(oldCollection); }
|
|
||||||
// The same as above - re-hashing new collection.
|
|
||||||
if (newColl != null) { deleted.removeAll(new HashSet(newCollection)); }
|
|
||||||
|
|
||||||
addCollectionChanges(session, collectionChanges, deleted, RevisionType.DEL, id);
|
|
||||||
|
|
||||||
return collectionChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
|
||||||
// Changes are mapped in the "mapCollectionChanges" method.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
@SuppressWarnings({"unchecked"})
|
||||||
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
|
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||||
if (propertyData.isUsingModifiedFlag()) {
|
SessionImplementor session,
|
||||||
if (isNotPersistentCollection(newObj) || isNotPersistentCollection(oldObj)) {
|
String referencingPropertyName,
|
||||||
|
PersistentCollection newColl,
|
||||||
|
Serializable oldColl, Serializable id) {
|
||||||
|
if ( !commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(
|
||||||
|
referencingPropertyName
|
||||||
|
) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<PersistentCollectionChangeData> collectionChanges = new ArrayList<PersistentCollectionChangeData>();
|
||||||
|
|
||||||
|
// Comparing new and old collection content.
|
||||||
|
final Collection newCollection = getNewCollectionContent( newColl );
|
||||||
|
final Collection oldCollection = getOldCollectionContent( oldColl );
|
||||||
|
|
||||||
|
final Set<Object> added = new HashSet<Object>();
|
||||||
|
if ( newColl != null ) {
|
||||||
|
added.addAll( newCollection );
|
||||||
|
}
|
||||||
|
// Re-hashing the old collection as the hash codes of the elements there may have changed, and the
|
||||||
|
// removeAll in AbstractSet has an implementation that is hashcode-change sensitive (as opposed to addAll).
|
||||||
|
if ( oldColl != null ) {
|
||||||
|
added.removeAll( new HashSet( oldCollection ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
addCollectionChanges( session, collectionChanges, added, RevisionType.ADD, id );
|
||||||
|
|
||||||
|
final Set<Object> deleted = new HashSet<Object>();
|
||||||
|
if ( oldColl != null ) {
|
||||||
|
deleted.addAll( oldCollection );
|
||||||
|
}
|
||||||
|
// The same as above - re-hashing new collection.
|
||||||
|
if ( newColl != null ) {
|
||||||
|
deleted.removeAll( new HashSet( newCollection ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
addCollectionChanges( session, collectionChanges, deleted, RevisionType.DEL, id );
|
||||||
|
|
||||||
|
return collectionChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mapToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
// Changes are mapped in the "mapCollectionChanges" method.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mapModifiedFlagsToMapFromEntity(
|
||||||
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
final PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
|
||||||
|
if ( propertyData.isUsingModifiedFlag() ) {
|
||||||
|
if ( isNotPersistentCollection( newObj ) || isNotPersistentCollection( oldObj ) ) {
|
||||||
// Compare POJOs.
|
// Compare POJOs.
|
||||||
data.put(propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual(newObj, oldObj));
|
data.put( propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual( newObj, oldObj ) );
|
||||||
} else if (isFromNullToEmptyOrFromEmptyToNull((PersistentCollection) newObj, (Serializable) oldObj)) {
|
}
|
||||||
data.put(propertyData.getModifiedFlagPropertyName(), true);
|
else if ( isFromNullToEmptyOrFromEmptyToNull( (PersistentCollection) newObj, (Serializable) oldObj ) ) {
|
||||||
} else {
|
data.put( propertyData.getModifiedFlagPropertyName(), true );
|
||||||
List<PersistentCollectionChangeData> changes = mapCollectionChanges(session,
|
}
|
||||||
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
|
else {
|
||||||
(PersistentCollection) newObj, (Serializable) oldObj, null);
|
final List<PersistentCollectionChangeData> changes = mapCollectionChanges(
|
||||||
data.put(propertyData.getModifiedFlagPropertyName(), !changes.isEmpty());
|
session,
|
||||||
|
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
|
||||||
|
(PersistentCollection) newObj,
|
||||||
|
(Serializable) oldObj,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
data.put( propertyData.getModifiedFlagPropertyName(), !changes.isEmpty() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,8 +227,8 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
||||||
|
|
||||||
private boolean isFromNullToEmptyOrFromEmptyToNull(PersistentCollection newColl, Serializable oldColl) {
|
private boolean isFromNullToEmptyOrFromEmptyToNull(PersistentCollection newColl, Serializable oldColl) {
|
||||||
// Comparing new and old collection content.
|
// Comparing new and old collection content.
|
||||||
Collection newCollection = getNewCollectionContent(newColl);
|
final Collection newCollection = getNewCollectionContent( newColl );
|
||||||
Collection oldCollection = getOldCollectionContent(oldColl);
|
final Collection oldCollection = getOldCollectionContent( oldColl );
|
||||||
|
|
||||||
return oldCollection == null && newCollection != null && newCollection.isEmpty()
|
return oldCollection == null && newCollection != null && newCollection.isEmpty()
|
||||||
|| newCollection == null && oldCollection != null && oldCollection.isEmpty();
|
|| newCollection == null && oldCollection != null && oldCollection.isEmpty();
|
||||||
|
@ -192,36 +236,53 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||||
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
|
final PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
|
||||||
if (propertyData.isUsingModifiedFlag()) {
|
if ( propertyData.isUsingModifiedFlag() ) {
|
||||||
data.put(propertyData.getModifiedFlagPropertyName(), propertyData.getName().equals(collectionPropertyName));
|
data.put(
|
||||||
|
propertyData.getModifiedFlagPropertyName(),
|
||||||
|
propertyData.getName().equals( collectionPropertyName )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg,
|
protected abstract Initializor<T> getInitializor(
|
||||||
AuditReaderImplementor versionsReader, Object primaryKey,
|
AuditConfiguration verCfg,
|
||||||
Number revision, boolean removed);
|
AuditReaderImplementor versionsReader, Object primaryKey,
|
||||||
|
Number revision, boolean removed);
|
||||||
|
|
||||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
@Override
|
||||||
AuditReaderImplementor versionsReader, Number revision) {
|
public void mapToEntityFromMap(
|
||||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), commonCollectionMapperData.getCollectionReferencingPropertyData());
|
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||||
try {
|
AuditReaderImplementor versionsReader, Number revision) {
|
||||||
|
final Setter setter = ReflectionTools.getSetter(
|
||||||
|
obj.getClass(),
|
||||||
|
commonCollectionMapperData.getCollectionReferencingPropertyData()
|
||||||
|
);
|
||||||
|
try {
|
||||||
setter.set(
|
setter.set(
|
||||||
obj,
|
obj,
|
||||||
proxyConstructor.newInstance(
|
proxyConstructor.newInstance(
|
||||||
getInitializor(
|
getInitializor(
|
||||||
verCfg, versionsReader, primaryKey, revision,
|
verCfg, versionsReader, primaryKey, revision,
|
||||||
RevisionType.DEL.equals( data.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) )
|
RevisionType.DEL.equals(
|
||||||
|
data.get(
|
||||||
|
verCfg.getAuditEntCfg()
|
||||||
|
.getRevisionTypePropName()
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
} catch (InstantiationException e) {
|
}
|
||||||
throw new AuditException(e);
|
catch (InstantiationException e) {
|
||||||
} catch (IllegalAccessException e) {
|
throw new AuditException( e );
|
||||||
throw new AuditException(e);
|
}
|
||||||
} catch (InvocationTargetException e) {
|
catch (IllegalAccessException e) {
|
||||||
throw new AuditException(e);
|
throw new AuditException( e );
|
||||||
}
|
}
|
||||||
}
|
catch (InvocationTargetException e) {
|
||||||
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.internal.entities.mapper.relation;
|
package org.hibernate.envers.internal.entities.mapper.relation;
|
||||||
|
|
||||||
|
import javax.persistence.NoResultException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.persistence.NoResultException;
|
|
||||||
|
|
||||||
import org.hibernate.NonUniqueResultException;
|
import org.hibernate.NonUniqueResultException;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
@ -13,54 +36,69 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template class for property mappers that manage one-to-one relation.
|
* Template class for property mappers that manage one-to-one relation.
|
||||||
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
|
public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
|
||||||
private final String entityName;
|
private final String entityName;
|
||||||
private final String referencedEntityName;
|
private final String referencedEntityName;
|
||||||
|
|
||||||
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
|
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
|
||||||
super(propertyData);
|
super( propertyData );
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.referencedEntityName = referencedEntityName;
|
this.referencedEntityName = referencedEntityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
public void nullSafeMapToEntityFromMap(
|
||||||
AuditReaderImplementor versionsReader, Number revision) {
|
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||||
EntityInfo referencedEntity = getEntityInfo(verCfg, referencedEntityName);
|
AuditReaderImplementor versionsReader, Number revision) {
|
||||||
|
final EntityInfo referencedEntity = getEntityInfo( verCfg, referencedEntityName );
|
||||||
|
|
||||||
Object value = null;
|
Object value;
|
||||||
try {
|
try {
|
||||||
value = queryForReferencedEntity(versionsReader, referencedEntity, (Serializable) primaryKey, revision);
|
value = queryForReferencedEntity( versionsReader, referencedEntity, (Serializable) primaryKey, revision );
|
||||||
} catch (NoResultException e) {
|
}
|
||||||
value = null;
|
catch (NoResultException e) {
|
||||||
} catch (NonUniqueResultException e) {
|
value = null;
|
||||||
throw new AuditException("Many versions results for one-to-one relationship " + entityName +
|
}
|
||||||
"." + getPropertyData().getBeanName() + ".", e);
|
catch (NonUniqueResultException e) {
|
||||||
}
|
throw new AuditException(
|
||||||
|
"Many versions results for one-to-one relationship " + entityName +
|
||||||
|
"." + getPropertyData().getBeanName() + ".", e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
setPropertyValue(obj, value);
|
setPropertyValue( obj, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param versionsReader Audit reader.
|
* @param versionsReader Audit reader.
|
||||||
* @param referencedEntity Referenced entity descriptor.
|
* @param referencedEntity Referenced entity descriptor.
|
||||||
* @param primaryKey Referenced entity identifier.
|
* @param primaryKey Referenced entity identifier.
|
||||||
* @param revision Revision number.
|
* @param revision Revision number.
|
||||||
* @return Referenced object or proxy of one-to-one relation.
|
*
|
||||||
*/
|
* @return Referenced object or proxy of one-to-one relation.
|
||||||
protected abstract Object queryForReferencedEntity(AuditReaderImplementor versionsReader, EntityInfo referencedEntity,
|
*/
|
||||||
Serializable primaryKey, Number revision);
|
protected abstract Object queryForReferencedEntity(
|
||||||
|
AuditReaderImplementor versionsReader, EntityInfo referencedEntity,
|
||||||
|
Serializable primaryKey, Number revision);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
public void mapModifiedFlagsToMapFromEntity(
|
||||||
}
|
SessionImplementor session,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||||
if (getPropertyData().isUsingModifiedFlag()) {
|
if ( getPropertyData().isUsingModifiedFlag() ) {
|
||||||
data.put(getPropertyData().getModifiedFlagPropertyName(), collectionPropertyName.equals(getPropertyData().getName()));
|
data.put(
|
||||||
}
|
getPropertyData().getModifiedFlagPropertyName(),
|
||||||
}
|
collectionPropertyName.equals( getPropertyData().getName() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.internal.entities.mapper.relation;
|
package org.hibernate.envers.internal.entities.mapper.relation;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -17,87 +40,109 @@ import org.hibernate.property.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for property mappers that manage to-one relation.
|
* Base class for property mappers that manage to-one relation.
|
||||||
|
*
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractToOneMapper implements PropertyMapper {
|
public abstract class AbstractToOneMapper implements PropertyMapper {
|
||||||
private final PropertyData propertyData;
|
private final PropertyData propertyData;
|
||||||
|
|
||||||
protected AbstractToOneMapper(PropertyData propertyData) {
|
protected AbstractToOneMapper(PropertyData propertyData) {
|
||||||
this.propertyData = propertyData;
|
this.propertyData = propertyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
public boolean mapToMapFromEntity(
|
||||||
return false;
|
SessionImplementor session,
|
||||||
}
|
Map<String, Object> data,
|
||||||
|
Object newObj,
|
||||||
|
Object oldObj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
public void mapToEntityFromMap(
|
||||||
AuditReaderImplementor versionsReader, Number revision) {
|
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||||
if (obj != null) {
|
AuditReaderImplementor versionsReader, Number revision) {
|
||||||
nullSafeMapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
if ( obj != null ) {
|
||||||
}
|
nullSafeMapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||||
PersistentCollection newColl, Serializable oldColl,
|
SessionImplementor session, String referencingPropertyName,
|
||||||
Serializable id) {
|
PersistentCollection newColl, Serializable oldColl,
|
||||||
return null;
|
Serializable id) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param verCfg Audit configuration.
|
* @param verCfg Audit configuration.
|
||||||
* @param entityName Entity name.
|
* @param entityName Entity name.
|
||||||
* @return Entity class, name and information whether it is audited or not.
|
*
|
||||||
*/
|
* @return Entity class, name and information whether it is audited or not.
|
||||||
protected EntityInfo getEntityInfo(AuditConfiguration verCfg, String entityName) {
|
*/
|
||||||
EntityConfiguration entCfg = verCfg.getEntCfg().get(entityName);
|
protected EntityInfo getEntityInfo(AuditConfiguration verCfg, String entityName) {
|
||||||
boolean isRelationAudited = true;
|
EntityConfiguration entCfg = verCfg.getEntCfg().get( entityName );
|
||||||
if (entCfg == null) {
|
boolean isRelationAudited = true;
|
||||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
if ( entCfg == null ) {
|
||||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName);
|
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||||
isRelationAudited = false;
|
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
|
||||||
}
|
isRelationAudited = false;
|
||||||
Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
}
|
||||||
return new EntityInfo(entityClass, entityName, isRelationAudited);
|
final Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
||||||
}
|
return new EntityInfo( entityClass, entityName, isRelationAudited );
|
||||||
|
}
|
||||||
|
|
||||||
protected void setPropertyValue(Object targetObject, Object value) {
|
protected void setPropertyValue(Object targetObject, Object value) {
|
||||||
Setter setter = ReflectionTools.getSetter(targetObject.getClass(), propertyData);
|
final Setter setter = ReflectionTools.getSetter( targetObject.getClass(), propertyData );
|
||||||
setter.set(targetObject, value, null);
|
setter.set( targetObject, value, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Bean property that represents the relation.
|
* @return Bean property that represents the relation.
|
||||||
*/
|
*/
|
||||||
protected PropertyData getPropertyData() {
|
protected PropertyData getPropertyData() {
|
||||||
return propertyData;
|
return propertyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter {@code obj} is never {@code null}.
|
* Parameter {@code obj} is never {@code null}.
|
||||||
* @see PropertyMapper#mapToEntityFromMap(AuditConfiguration, Object, Map, Object, AuditReaderImplementor, Number)
|
*
|
||||||
*/
|
* @see PropertyMapper#mapToEntityFromMap(AuditConfiguration, Object, Map, Object, AuditReaderImplementor, Number)
|
||||||
public abstract void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
*/
|
||||||
AuditReaderImplementor versionsReader, Number revision);
|
public abstract void nullSafeMapToEntityFromMap(
|
||||||
|
AuditConfiguration verCfg,
|
||||||
|
Object obj,
|
||||||
|
Map data,
|
||||||
|
Object primaryKey,
|
||||||
|
AuditReaderImplementor versionsReader,
|
||||||
|
Number revision);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple descriptor of an entity.
|
* Simple descriptor of an entity.
|
||||||
*/
|
*/
|
||||||
protected class EntityInfo {
|
protected class EntityInfo {
|
||||||
private final Class entityClass;
|
private final Class entityClass;
|
||||||
private final String entityName;
|
private final String entityName;
|
||||||
private final boolean audited;
|
private final boolean audited;
|
||||||
|
|
||||||
public EntityInfo(Class entityClass, String entityName, boolean audited) {
|
public EntityInfo(Class entityClass, String entityName, boolean audited) {
|
||||||
this.entityClass = entityClass;
|
this.entityClass = entityClass;
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.audited = audited;
|
this.audited = audited;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getEntityClass() { return entityClass; }
|
public Class getEntityClass() {
|
||||||
public String getEntityName() { return entityName; }
|
return entityClass;
|
||||||
public boolean isAudited() { return audited; }
|
}
|
||||||
}
|
|
||||||
|
public String getEntityName() {
|
||||||
|
return entityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAudited() {
|
||||||
|
return audited;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -39,36 +39,50 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class BasicCollectionMapper<T extends Collection> extends AbstractCollectionMapper<T> implements PropertyMapper {
|
public class BasicCollectionMapper<T extends Collection> extends AbstractCollectionMapper<T> implements PropertyMapper {
|
||||||
protected final MiddleComponentData elementComponentData;
|
protected final MiddleComponentData elementComponentData;
|
||||||
|
|
||||||
public BasicCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
|
public BasicCollectionMapper(
|
||||||
|
CommonCollectionMapperData commonCollectionMapperData,
|
||||||
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
|
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
|
||||||
MiddleComponentData elementComponentData, boolean ordinalInId, boolean revisionTypeInId) {
|
MiddleComponentData elementComponentData, boolean ordinalInId, boolean revisionTypeInId) {
|
||||||
super( commonCollectionMapperData, collectionClass, proxyClass, ordinalInId, revisionTypeInId );
|
super( commonCollectionMapperData, collectionClass, proxyClass, ordinalInId, revisionTypeInId );
|
||||||
this.elementComponentData = elementComponentData;
|
this.elementComponentData = elementComponentData;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
@Override
|
||||||
Object primaryKey, Number revision, boolean removed) {
|
protected Initializor<T> getInitializor(
|
||||||
return new BasicCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||||
primaryKey, revision, removed, collectionClass, elementComponentData);
|
Object primaryKey, Number revision, boolean removed) {
|
||||||
}
|
return new BasicCollectionInitializor<T>(
|
||||||
|
verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||||
|
primaryKey, revision, removed, collectionClass, elementComponentData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
@Override
|
||||||
return (Collection) newCollection;
|
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
||||||
}
|
return (Collection) newCollection;
|
||||||
|
}
|
||||||
|
|
||||||
protected Collection getOldCollectionContent(Serializable oldCollection) {
|
@Override
|
||||||
if (oldCollection == null) {
|
protected Collection getOldCollectionContent(Serializable oldCollection) {
|
||||||
return null;
|
if ( oldCollection == null ) {
|
||||||
} else if (oldCollection instanceof Map) {
|
return null;
|
||||||
return ((Map) oldCollection).keySet();
|
}
|
||||||
} else {
|
else if ( oldCollection instanceof Map ) {
|
||||||
return (Collection) oldCollection;
|
return ((Map) oldCollection).keySet();
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
return (Collection) oldCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
|
@Override
|
||||||
elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, changed);
|
protected void mapToMapFromObject(
|
||||||
}
|
SessionImplementor session,
|
||||||
|
Map<String, Object> idData,
|
||||||
|
Map<String, Object> data,
|
||||||
|
Object changed) {
|
||||||
|
elementComponentData.getComponentMapper().mapToMapFromObject( session, idData, data, changed );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue