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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,11 +22,12 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -34,25 +35,25 @@ import javax.persistence.JoinColumn;
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
public @interface AuditJoinTable {
|
||||
/**
|
||||
* @return 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.
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* @return The schema of the join table. Defaults to the schema of the entity owning the association.
|
||||
*/
|
||||
String schema() default "";
|
||||
/**
|
||||
* The schema of the join table. Defaults to the schema of the entity owning the association.
|
||||
*/
|
||||
String schema() default "";
|
||||
|
||||
/**
|
||||
* @return The catalog of the join table. Defaults to the catalog of the entity owning the association.
|
||||
*/
|
||||
String catalog() default "";
|
||||
/**
|
||||
* The catalog of the join table. Defaults to the catalog of the entity owning the association.
|
||||
*/
|
||||
String catalog() default "";
|
||||
|
||||
/**
|
||||
* @return 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).
|
||||
*/
|
||||
JoinColumn[] inverseJoinColumns() default {};
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
JoinColumn[] inverseJoinColumns() default {};
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
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
|
||||
* bi-directional relation.
|
||||
* </p>
|
||||
*
|
||||
* <p/>
|
||||
* <p>
|
||||
* This annotation is <b>experimental</b> and may change in future releases.
|
||||
* </p>
|
||||
|
@ -21,16 +22,17 @@ import java.lang.annotation.Target;
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||
public @interface AuditMappedBy {
|
||||
/**
|
||||
* @return 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)}.
|
||||
*/
|
||||
String mappedBy();
|
||||
/**
|
||||
* 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)}.
|
||||
*/
|
||||
String mappedBy();
|
||||
|
||||
/**
|
||||
* @return 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.
|
||||
* The property should be mapped with {@code @Column(insertable=false, updatable=false)}.
|
||||
*/
|
||||
String positionMappedBy() default "";
|
||||
/**
|
||||
* 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} or
|
||||
* {@link javax.persistence.OrderColumn} is used on the collection. The property should be mapped with
|
||||
* {@code @Column(insertable=false, updatable=false)}.
|
||||
*/
|
||||
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;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* @author Erik-Berndt Scheper
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*
|
||||
* @see javax.persistence.Embedded
|
||||
* @see javax.persistence.Embeddable
|
||||
* @see javax.persistence.MappedSuperclass
|
||||
* @see javax.persistence.MappedSuperclass
|
||||
* @see javax.persistence.AssociationOverride
|
||||
* @see AuditJoinTable
|
||||
*/
|
||||
@Target({ TYPE, METHOD, FIELD })
|
||||
@Target({TYPE, METHOD, FIELD})
|
||||
@Retention(RUNTIME)
|
||||
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 MappedSuperclass} type.
|
||||
* {@link javax.persistence.MappedSuperclass} type.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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}.
|
||||
*/
|
||||
AuditJoinTable auditJoinTable() default @AuditJoinTable;
|
||||
|
||||
/**
|
||||
* @return 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}
|
||||
* type.
|
||||
* 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 javax.persistence.MappedSuperclass} type.
|
||||
*/
|
||||
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;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
@ -21,11 +45,11 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
* @see AuditJoinTable
|
||||
* @see AuditOverride
|
||||
*/
|
||||
@Target({ TYPE, METHOD, FIELD })
|
||||
@Target({TYPE, METHOD, FIELD})
|
||||
@Retention(RUNTIME)
|
||||
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.
|
||||
*/
|
||||
AuditOverride[] value();
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public interface AuditReader {
|
||||
/**
|
||||
* Find an entity by primary key at the given revision.
|
||||
* @param cls Class of the entity.
|
||||
* @param primaryKey Primary key of the entity.
|
||||
* @param revision Revision in which to get the entity.
|
||||
* @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, Object primaryKey, Number revision) throws
|
||||
IllegalArgumentException, NotAuditedException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Find an entity by primary key at the given revision with the specified entityName.
|
||||
* @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.
|
||||
* @param revision Revision in which to get the entity.
|
||||
* @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,
|
||||
/**
|
||||
* Find an entity by primary key at the given revision.
|
||||
*
|
||||
* @param cls Class of the entity.
|
||||
* @param primaryKey Primary key of the entity.
|
||||
* @param revision Revision in which to get the entity.
|
||||
* @param <T> The type of the entity to find
|
||||
*
|
||||
* @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, Object primaryKey, Number revision) throws
|
||||
IllegalArgumentException, NotAuditedException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Find an entity by primary key at the given revision with the specified entityName.
|
||||
*
|
||||
* @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.
|
||||
* @param revision Revision in which to get the entity.
|
||||
* @param <T> The type of the entity to find
|
||||
*
|
||||
* @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,
|
||||
NotAuditedException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Find an entity by primary key at the given revision with the specified entityName,
|
||||
* 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 primaryKey Primary key of the entity.
|
||||
* @param revision Revision in which to get the entity.
|
||||
* @param includeDeletions Whether to include deleted entities in the search.
|
||||
* @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,
|
||||
/**
|
||||
* Find an entity by primary key at the given revision with the specified entityName,
|
||||
* 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 primaryKey Primary key of the entity.
|
||||
* @param revision Revision in which to get the entity.
|
||||
* @param includeDeletions Whether to include deleted entities in the search.
|
||||
* @param <T> The type of the entity to find
|
||||
*
|
||||
* @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, boolean includeDeletions) throws IllegalArgumentException,
|
||||
NotAuditedException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
||||
* 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, Object primaryKey)
|
||||
throws IllegalArgumentException, NotAuditedException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Get a list of revision numbers, at which an entity was modified, looking by entityName.
|
||||
* @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.
|
||||
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
||||
* 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)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
||||
* 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, Object primaryKey)
|
||||
throws IllegalArgumentException, NotAuditedException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Get a list of revision numbers, at which an entity was modified, looking by entityName.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
|
||||
* 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,
|
||||
IllegalStateException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws IllegalArgumentException If revision is less or equal to 0.
|
||||
* @throws RevisionDoesNotExistException If the revision does not exist.
|
||||
* @throws IllegalStateException If the associated entity manager is closed.
|
||||
*/
|
||||
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.
|
||||
* @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.
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @throws IllegalArgumentException If revision is less or equal to 0.
|
||||
* @throws RevisionDoesNotExistException If the revision does not exist.
|
||||
* @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,
|
||||
IllegalStateException;
|
||||
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
* 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
|
||||
* {@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.
|
||||
*/
|
||||
<T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist);
|
||||
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
* is closed.
|
||||
*/
|
||||
AuditQueryCreator createQuery();
|
||||
/**
|
||||
* 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
|
||||
* is closed.
|
||||
*/
|
||||
AuditQueryCreator createQuery();
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks if the entityClass was configured to be audited. Calling
|
||||
* isEntityNameAudited() with the string of the class name will return the
|
||||
* same value.
|
||||
*
|
||||
* @param entityClass
|
||||
* Class of the entity asking for audit support
|
||||
* @return true if the entityClass is audited.
|
||||
*/
|
||||
boolean isEntityClassAudited(Class<?> entityClass);
|
||||
|
||||
*
|
||||
* @param entityClass Class of the entity asking for audit support
|
||||
*
|
||||
* @return true if the entityClass is audited.
|
||||
*/
|
||||
boolean isEntityClassAudited(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Checks if the entityName was configured to be audited.
|
||||
*
|
||||
*
|
||||
* @param entityName EntityName of the entity asking for audit support.
|
||||
*
|
||||
* @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
|
||||
* not associated with this AuditReader instance.
|
||||
*/
|
||||
String getEntityName(Object primaryKey, Number revision, Object entity)
|
||||
throws HibernateException;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @throws AuditException If none of the following conditions is satisfied:
|
||||
* <ul>
|
||||
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
|
||||
* parameter is set to <code>true</code>.</li>
|
||||
* <li>Custom revision entity (annotated with {@link RevisionEntity})
|
||||
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
|
||||
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
|
||||
* marked with {@link ModifiedEntityNames} interface.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public CrossTypeRevisionChangesReader getCrossTypeRevisionChangesReader() throws AuditException;
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* @throws AuditException If none of the following conditions is satisfied:
|
||||
* <ul>
|
||||
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
|
||||
* parameter is set to <code>true</code>.</li>
|
||||
* <li>Custom revision entity (annotated with {@link RevisionEntity})
|
||||
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
|
||||
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
|
||||
* marked with {@link ModifiedEntityNames} interface.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public CrossTypeRevisionChangesReader getCrossTypeRevisionChangesReader() throws AuditException;
|
||||
}
|
||||
|
|
|
@ -38,20 +38,25 @@ import org.hibernate.event.spi.PostInsertEventListener;
|
|||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class AuditReaderFactory {
|
||||
private AuditReaderFactory() { }
|
||||
private AuditReaderFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* after the session is closed.
|
||||
* @throws AuditException When the given required listeners aren't installed.
|
||||
*/
|
||||
public static AuditReader get(Session session) throws AuditException {
|
||||
SessionImplementor sessionImpl;
|
||||
if (!(session instanceof SessionImplementor)) {
|
||||
/**
|
||||
* 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
|
||||
* after the session is closed.
|
||||
*
|
||||
* @throws AuditException When the given required listeners aren't installed.
|
||||
*/
|
||||
public static AuditReader get(Session session) throws AuditException {
|
||||
SessionImplementor sessionImpl;
|
||||
if ( !(session instanceof SessionImplementor) ) {
|
||||
sessionImpl = (SessionImplementor) session.getSessionFactory().getCurrentSession();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sessionImpl = (SessionImplementor) session;
|
||||
}
|
||||
|
||||
|
@ -61,37 +66,41 @@ public class AuditReaderFactory {
|
|||
.getServiceRegistry()
|
||||
.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 ) {
|
||||
// todo : slightly different from original code in that I am not checking the other listener groups...
|
||||
return new AuditReaderImpl(
|
||||
( (EnversListener) listener ).getAuditConfiguration(),
|
||||
((EnversListener) listener).getAuditConfiguration(),
|
||||
session,
|
||||
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.
|
||||
* @param entityManager An open entity manager.
|
||||
* @return An audit reader associated with the given entity manager. It shouldn't be used
|
||||
* after the entity manager is closed.
|
||||
* @throws AuditException When the given entity manager is not based on Hibernate, or if the required
|
||||
* listeners aren't installed.
|
||||
*/
|
||||
public static AuditReader get(EntityManager entityManager) throws AuditException {
|
||||
if (entityManager.getDelegate() instanceof Session) {
|
||||
return get((Session) entityManager.getDelegate());
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
* after the entity manager is closed.
|
||||
*
|
||||
* @throws AuditException When the given entity manager is not based on Hibernate, or if the required
|
||||
* listeners aren't installed.
|
||||
*/
|
||||
public static AuditReader get(EntityManager entityManager) throws AuditException {
|
||||
if ( entityManager.getDelegate() instanceof Session ) {
|
||||
return get( (Session) entityManager.getDelegate() );
|
||||
}
|
||||
|
||||
if (entityManager.getDelegate() instanceof EntityManager) {
|
||||
return get((EntityManager) entityManager.getDelegate());
|
||||
}
|
||||
if ( entityManager.getDelegate() instanceof EntityManager ) {
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -33,15 +34,18 @@ import java.lang.annotation.Target;
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
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.
|
||||
*/
|
||||
String schema() default "";
|
||||
/**
|
||||
* The schema of the table. Defaults to the schema of the annotated entity.
|
||||
*/
|
||||
String schema() default "";
|
||||
|
||||
/**
|
||||
* @return The catalog of the table. Defaults to the catalog of the annotated entity.
|
||||
*/
|
||||
String catalog() default "";
|
||||
/**
|
||||
* The catalog of the table. Defaults to the catalog of the annotated entity.
|
||||
*/
|
||||
String catalog() default "";
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
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 field, indicates that this field should be audited.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Tomasz Bech
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
|
@ -38,33 +40,37 @@ import java.lang.annotation.Target;
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
|
||||
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.
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* The scope of this functionality is limited to the class hierarchy of the annotated entity.
|
||||
*
|
||||
* If a parent type lists any of its parent types using this attribute, all properties in the specified classes
|
||||
* will also be audited.
|
||||
*
|
||||
* @deprecated Use {@code @AuditOverride(forClass=SomeEntity.class)} instead.
|
||||
*/
|
||||
Class[] auditParents() default {};
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
* <p/>
|
||||
* If a parent type lists any of its parent types using this attribute, all properties in the specified classes
|
||||
* will also be audited.
|
||||
*
|
||||
* @deprecated Use {@code @AuditOverride(forClass=SomeEntity.class)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Class[] auditParents() default {};
|
||||
|
||||
/**
|
||||
* @return 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.
|
||||
* This can be used for example in queries.
|
||||
*/
|
||||
/**
|
||||
* 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.
|
||||
* This can be used for example in queries.
|
||||
*/
|
||||
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;
|
||||
|
||||
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
|
||||
* revision. Note that this API can be legally used only when default mechanism of tracking modified entity names
|
||||
* is enabled.
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public interface CrossTypeRevisionChangesReader {
|
||||
/**
|
||||
* 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.
|
||||
* @param revision Revision number.
|
||||
* @return Snapshots of all audited entities changed in a given revision.
|
||||
* @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 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.
|
||||
*
|
||||
* @param revision Revision number.
|
||||
*
|
||||
* @return Snapshots of all audited entities changed in a given revision.
|
||||
*
|
||||
* @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,
|
||||
* where <i>n</i> is a number of different entity classes modified within specified revision.
|
||||
* @param revision Revision number.
|
||||
* @param revisionType Type of modification.
|
||||
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
|
||||
* @throws IllegalStateException If the associated entity manager is closed.
|
||||
* @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 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.
|
||||
*
|
||||
* @param revision Revision number.
|
||||
* @param revisionType Type of modification.
|
||||
*
|
||||
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
|
||||
*
|
||||
* @throws IllegalStateException If the associated entity manager is closed.
|
||||
* @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.
|
||||
* Executes <i>mn+1</i> SQL queries, where:
|
||||
* <ul>
|
||||
* <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.
|
||||
* </ul>
|
||||
* @param revision Revision number.
|
||||
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
|
||||
* @throws IllegalStateException If the associated entity manager is closed.
|
||||
* @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;
|
||||
/**
|
||||
* Find all entities changed (added, updated and removed) in a given revision grouped by modification type.
|
||||
* Executes <i>mn+1</i> SQL queries, where:
|
||||
* <ul>
|
||||
* <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.
|
||||
* </ul>
|
||||
*
|
||||
* @param revision Revision number.
|
||||
*
|
||||
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
|
||||
*
|
||||
* @throws IllegalStateException If the associated entity manager is closed.
|
||||
* @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.
|
||||
* @param revision Revision number.
|
||||
* @return Set of entity names and corresponding Java classes modified in a given revision.
|
||||
* @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;
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,13 +22,14 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -36,56 +37,61 @@ import javax.persistence.Transient;
|
|||
@MappedSuperclass
|
||||
public class DefaultRevisionEntity implements Serializable {
|
||||
private static final long serialVersionUID = 8530213963961662300L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@RevisionNumber
|
||||
private int id;
|
||||
|
||||
@RevisionTimestamp
|
||||
private long timestamp;
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@RevisionNumber
|
||||
private int id;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
@RevisionTimestamp
|
||||
private long timestamp;
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Date getRevisionDate() {
|
||||
return new Date(timestamp);
|
||||
}
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
@Transient
|
||||
public Date getRevisionDate() {
|
||||
return new Date( timestamp );
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof DefaultRevisionEntity)) return false;
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
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;
|
||||
if (timestamp != that.timestamp) return false;
|
||||
final DefaultRevisionEntity that = (DefaultRevisionEntity) o;
|
||||
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() {
|
||||
int result;
|
||||
result = id;
|
||||
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
|
||||
}
|
||||
@Override
|
||||
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;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
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.
|
||||
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
|
||||
* parameter is set to {@code true}.
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
||||
@Column(name = "ENTITYNAME")
|
||||
@Fetch(FetchMode.JOIN)
|
||||
@ModifiedEntityNames
|
||||
private Set<String> modifiedEntityNames = new HashSet<String>();
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
||||
@Column(name = "ENTITYNAME")
|
||||
@Fetch(FetchMode.JOIN)
|
||||
@ModifiedEntityNames
|
||||
private Set<String> modifiedEntityNames = new HashSet<String>();
|
||||
|
||||
public Set<String> getModifiedEntityNames() {
|
||||
return modifiedEntityNames;
|
||||
}
|
||||
public Set<String> getModifiedEntityNames() {
|
||||
return modifiedEntityNames;
|
||||
}
|
||||
|
||||
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
||||
this.modifiedEntityNames = modifiedEntityNames;
|
||||
}
|
||||
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
||||
this.modifiedEntityNames = modifiedEntityNames;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity)) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( !(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !super.equals( o ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
|
||||
final DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
|
||||
|
||||
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames)
|
||||
: that.modifiedEntityNames != null) return false;
|
||||
if ( modifiedEntityNames != null ? !modifiedEntityNames.equals( that.modifiedEntityNames )
|
||||
: that.modifiedEntityNames != null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
|
||||
}
|
||||
@Override
|
||||
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;
|
||||
|
||||
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
|
||||
* added, modified or removed within current revision boundaries.
|
||||
* @see RevisionListener
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @see RevisionListener
|
||||
*/
|
||||
public interface EntityTrackingRevisionListener extends RevisionListener {
|
||||
/**
|
||||
* 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,
|
||||
* potentially to different tables.
|
||||
* @param entityId Identifier of modified entity.
|
||||
* @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);
|
||||
/**
|
||||
* 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,
|
||||
* potentially to different tables.
|
||||
* @param entityId Identifier of modified entity.
|
||||
* @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);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
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;
|
||||
|
||||
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.
|
||||
* This annotation expects field of <code>{@literal Set<String>}</code> type.
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
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.
|
||||
*
|
||||
* @author Sebastian Komander
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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}
|
||||
* already has those two fields, so you may extend it, but you may also write your own revision entity
|
||||
* from scratch.
|
||||
*
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface RevisionEntity {
|
||||
/**
|
||||
* @return 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.
|
||||
*/
|
||||
Class<? extends RevisionListener> value() default RevisionListener.class;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Class<? extends RevisionListener> value() default RevisionListener.class;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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
|
||||
* {@link RevisionEntity} annotation.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public interface RevisionListener {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void newRevision(Object revisionEntity);
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @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
|
||||
* {@link RevisionListener}. The value of this property will be automatically set by Envers.
|
||||
*
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public enum RevisionType {
|
||||
/**
|
||||
* Indicates that the entity was added (persisted) at that revision.
|
||||
*/
|
||||
ADD((byte) 0),
|
||||
/**
|
||||
* Indicates that the entity was modified (one or more of its fields) at that revision.
|
||||
*/
|
||||
MOD((byte) 1),
|
||||
/**
|
||||
* Indicates that the entity was deleted (removed) at that revision.
|
||||
*/
|
||||
DEL((byte) 2);
|
||||
/**
|
||||
* Indicates that the entity was added (persisted) at that revision.
|
||||
*/
|
||||
ADD( (byte) 0 ),
|
||||
/**
|
||||
* Indicates that the entity was modified (one or more of its fields) at that revision.
|
||||
*/
|
||||
MOD( (byte) 1 ),
|
||||
/**
|
||||
* Indicates that the entity was deleted (removed) at that revision.
|
||||
*/
|
||||
DEL( (byte) 2 );
|
||||
|
||||
private Byte representation;
|
||||
private Byte representation;
|
||||
|
||||
RevisionType(byte representation) {
|
||||
this.representation = representation;
|
||||
}
|
||||
RevisionType(byte representation) {
|
||||
this.representation = representation;
|
||||
}
|
||||
|
||||
public Byte getRepresentation() {
|
||||
return representation;
|
||||
}
|
||||
public Byte getRepresentation() {
|
||||
return representation;
|
||||
}
|
||||
|
||||
public static RevisionType fromRepresentation(Object representation) {
|
||||
if (representation == null || !(representation instanceof Byte)) {
|
||||
return null;
|
||||
}
|
||||
public static RevisionType fromRepresentation(Object representation) {
|
||||
if ( representation == null || !(representation instanceof Byte) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch ((Byte) representation) {
|
||||
case 0: return ADD;
|
||||
case 1: return MOD;
|
||||
case 2: return DEL;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown representation: " + representation);
|
||||
}
|
||||
switch ( (Byte) representation ) {
|
||||
case 0: {
|
||||
return ADD;
|
||||
}
|
||||
case 1: {
|
||||
return MOD;
|
||||
}
|
||||
case 2: {
|
||||
return DEL;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException( "Unknown representation: " + representation );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -33,7 +34,7 @@ import java.lang.annotation.Target;
|
|||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SecondaryAuditTable {
|
||||
String secondaryTableName();
|
||||
String secondaryTableName();
|
||||
|
||||
String secondaryAuditTableName();
|
||||
String secondaryAuditTableName();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -33,5 +34,5 @@ import java.lang.annotation.Target;
|
|||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
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;
|
||||
|
||||
import org.hibernate.envers.strategy.DefaultAuditStrategy;
|
||||
|
||||
/**
|
||||
* Configuration property names.
|
||||
*
|
||||
|
@ -69,7 +90,7 @@ public interface EnversSettings {
|
|||
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";
|
||||
|
||||
|
@ -99,7 +120,7 @@ public interface EnversSettings {
|
|||
* 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";
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* 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 String revisionEndTimestampFieldName;
|
||||
|
||||
|
||||
private final String embeddableSetOrdinalPropertyName;
|
||||
|
||||
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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -15,84 +39,100 @@ import org.hibernate.mapping.PersistentClass;
|
|||
|
||||
/**
|
||||
* A helper class holding auditing meta-data for all persistent classes.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
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.
|
||||
* @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);
|
||||
}
|
||||
/**
|
||||
* @return A collection of all auditing meta-data for persistent classes.
|
||||
*/
|
||||
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
|
||||
return persistentClassToAuditingData.entrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A collection of all auditing meta-data for persistent classes.
|
||||
*/
|
||||
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
|
||||
return persistentClassToAuditingData.entrySet();
|
||||
}
|
||||
/**
|
||||
* @param entityName Name of the entity.
|
||||
*
|
||||
* @return Auditing meta-data for the given entity.
|
||||
*/
|
||||
public ClassAuditingData getClassAuditingData(String entityName) {
|
||||
return entityNameToAuditingData.get( entityName );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entityName Name of the entity.
|
||||
* @return Auditing meta-data for the given entity.
|
||||
*/
|
||||
public ClassAuditingData getClassAuditingData(String entityName) {
|
||||
return entityNameToAuditingData.get(entityName);
|
||||
}
|
||||
/**
|
||||
* 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() ) {
|
||||
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()
|
||||
);
|
||||
|
||||
/**
|
||||
* 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());
|
||||
final ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get( referencedEntityName );
|
||||
|
||||
ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get(referencedEntityName);
|
||||
forcePropertyInsertable(
|
||||
referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
|
||||
pc.getEntityName(), referencedEntityName
|
||||
);
|
||||
|
||||
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
|
||||
pc.getEntityName(), referencedEntityName);
|
||||
forcePropertyInsertable(
|
||||
referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
|
||||
pc.getEntityName(), referencedEntityName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
|
||||
pc.getEntityName(), referencedEntityName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void forcePropertyInsertable(
|
||||
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,
|
||||
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);
|
||||
}
|
||||
LOG.debugf(
|
||||
"Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
|
||||
referencedEntityName,
|
||||
propertyName,
|
||||
entityName
|
||||
);
|
||||
|
||||
LOG.debugf("Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
|
||||
referencedEntityName,
|
||||
propertyName,
|
||||
entityName);
|
||||
|
||||
classAuditingData
|
||||
.getPropertyAuditingData(propertyName)
|
||||
.setForceInsertable(true);
|
||||
}
|
||||
}
|
||||
classAuditingData
|
||||
.getPropertyAuditingData( propertyName )
|
||||
.setForceInsertable( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public class EntitiesConfigurator {
|
||||
public EntitiesConfigurations configure(Configuration cfg, ReflectionManager reflectionManager,
|
||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
|
||||
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
|
||||
// Creating a name register to capture all audit entity names created.
|
||||
AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister();
|
||||
DOMWriter writer = new DOMWriter();
|
||||
public EntitiesConfigurations configure(
|
||||
Configuration cfg, ReflectionManager reflectionManager,
|
||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
|
||||
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
|
||||
// Creating a name register to capture all audit entity names created.
|
||||
final AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister();
|
||||
final DOMWriter writer = new DOMWriter();
|
||||
|
||||
// Sorting the persistent class topologically - superclass always before subclass
|
||||
Iterator<PersistentClass> classes = GraphTopologicalSort.sort(new PersistentClassGraphDefiner(cfg)).iterator();
|
||||
// Sorting the persistent class topologically - superclass always before subclass
|
||||
final Iterator<PersistentClass> classes = GraphTopologicalSort.sort( new PersistentClassGraphDefiner( cfg ) )
|
||||
.iterator();
|
||||
|
||||
ClassesAuditingData classesAuditingData = new ClassesAuditingData();
|
||||
Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
|
||||
final ClassesAuditingData classesAuditingData = new ClassesAuditingData();
|
||||
final Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
|
||||
|
||||
// Reading metadata from annotations
|
||||
while (classes.hasNext()) {
|
||||
PersistentClass pc = classes.next();
|
||||
// Reading metadata from annotations
|
||||
while ( classes.hasNext() ) {
|
||||
final PersistentClass pc = classes.next();
|
||||
|
||||
// Collecting information from annotations on the persistent class pc
|
||||
AnnotationsMetadataReader annotationsMetadataReader =
|
||||
new AnnotationsMetadataReader(globalCfg, reflectionManager, pc);
|
||||
ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
|
||||
// Collecting information from annotations on the persistent class pc
|
||||
final AnnotationsMetadataReader annotationsMetadataReader =
|
||||
new AnnotationsMetadataReader( globalCfg, reflectionManager, pc );
|
||||
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.
|
||||
classesAuditingData.updateCalculatedFields();
|
||||
// Now that all information is read we can update the calculated fields.
|
||||
classesAuditingData.updateCalculatedFields();
|
||||
|
||||
AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(cfg, globalCfg, verEntCfg, auditStrategy,
|
||||
classLoaderService, revisionInfoRelationMapping, auditEntityNameRegister);
|
||||
final AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(
|
||||
cfg, globalCfg, verEntCfg, auditStrategy,
|
||||
classLoaderService, revisionInfoRelationMapping, auditEntityNameRegister
|
||||
);
|
||||
|
||||
// First pass
|
||||
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData()) {
|
||||
PersistentClass pc = pcDatasEntry.getKey();
|
||||
ClassAuditingData auditData = pcDatasEntry.getValue();
|
||||
// First pass
|
||||
for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
|
||||
final PersistentClass pc = pcDatasEntry.getKey();
|
||||
final ClassAuditingData auditData = pcDatasEntry.getValue();
|
||||
|
||||
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
|
||||
if (auditData.isAudited()) {
|
||||
if (!StringTools.isEmpty(auditData.getAuditTable().value())) {
|
||||
verEntCfg.addCustomAuditTableName(pc.getEntityName(), auditData.getAuditTable().value());
|
||||
}
|
||||
final EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
|
||||
if ( auditData.isAudited() ) {
|
||||
if ( !StringTools.isEmpty( auditData.getAuditTable().value() ) ) {
|
||||
verEntCfg.addCustomAuditTableName( pc.getEntityName(), auditData.getAuditTable().value() );
|
||||
}
|
||||
|
||||
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, true);
|
||||
} else {
|
||||
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, false);
|
||||
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, true );
|
||||
}
|
||||
else {
|
||||
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, false );
|
||||
}
|
||||
|
||||
xmlMappings.put(pc, xmlMappingData);
|
||||
}
|
||||
xmlMappings.put( pc, xmlMappingData );
|
||||
}
|
||||
|
||||
// Second pass
|
||||
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData()) {
|
||||
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey());
|
||||
// Second pass
|
||||
for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
|
||||
final EntityXmlMappingData xmlMappingData = xmlMappings.get( pcDatasEntry.getKey() );
|
||||
|
||||
if (pcDatasEntry.getValue().isAudited()) {
|
||||
auditMetaGen.generateSecondPass(pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData);
|
||||
try {
|
||||
cfg.addDocument(writer.write(xmlMappingData.getMainXmlMapping()));
|
||||
//writeDocument(xmlMappingData.getMainXmlMapping());
|
||||
if ( pcDatasEntry.getValue().isAudited() ) {
|
||||
auditMetaGen.generateSecondPass( pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData );
|
||||
try {
|
||||
cfg.addDocument( writer.write( xmlMappingData.getMainXmlMapping() ) );
|
||||
//writeDocument(xmlMappingData.getMainXmlMapping());
|
||||
|
||||
for (Document additionalMapping : xmlMappingData.getAdditionalXmlMappings()) {
|
||||
cfg.addDocument(writer.write(additionalMapping));
|
||||
//writeDocument(additionalMapping);
|
||||
}
|
||||
} catch (DocumentException e) {
|
||||
throw new MappingException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( Document additionalMapping : xmlMappingData.getAdditionalXmlMappings() ) {
|
||||
cfg.addDocument( writer.write( additionalMapping ) );
|
||||
//writeDocument(additionalMapping);
|
||||
}
|
||||
}
|
||||
catch (DocumentException e) {
|
||||
throw new MappingException( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only if there are any versioned classes
|
||||
if (auditMetaGen.getEntitiesConfigurations().size() > 0) {
|
||||
try {
|
||||
if (revisionInfoXmlMapping != null) {
|
||||
//writeDocument(revisionInfoXmlMapping);
|
||||
cfg.addDocument(writer.write(revisionInfoXmlMapping));
|
||||
}
|
||||
} catch (DocumentException e) {
|
||||
throw new MappingException(e);
|
||||
}
|
||||
}
|
||||
// Only if there are any versioned classes
|
||||
if ( auditMetaGen.getEntitiesConfigurations().size() > 0 ) {
|
||||
try {
|
||||
if ( revisionInfoXmlMapping != null ) {
|
||||
//writeDocument(revisionInfoXmlMapping);
|
||||
cfg.addDocument( writer.write( revisionInfoXmlMapping ) );
|
||||
}
|
||||
}
|
||||
catch (DocumentException e) {
|
||||
throw new MappingException( e );
|
||||
}
|
||||
}
|
||||
|
||||
return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations(),
|
||||
auditMetaGen.getNotAuditedEntitiesConfigurations());
|
||||
}
|
||||
return new EntitiesConfigurations(
|
||||
auditMetaGen.getEntitiesConfigurations(),
|
||||
auditMetaGen.getNotAuditedEntitiesConfigurations()
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
private void writeDocument(Document e) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Writer w = new PrintWriter(baos);
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
private void writeDocument(Document e) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final Writer w = new PrintWriter( baos );
|
||||
|
||||
try {
|
||||
XMLWriter xw = new XMLWriter(w, new OutputFormat(" ", true));
|
||||
xw.write(e);
|
||||
w.flush();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
try {
|
||||
final XMLWriter xw = new XMLWriter( w, new OutputFormat( " ", true ) );
|
||||
xw.write( e );
|
||||
w.flush();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("-----------");
|
||||
System.out.println(baos.toString());
|
||||
System.out.println("-----------");
|
||||
}
|
||||
System.out.println( "-----------" );
|
||||
System.out.println( baos.toString() );
|
||||
System.out.println( "-----------" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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"
|
||||
);
|
||||
|
||||
String revisionListenerClassName = properties.getProperty( EnversSettings.REVISION_LISTENER, null );
|
||||
final String revisionListenerClassName = properties.getProperty( EnversSettings.REVISION_LISTENER, null );
|
||||
if ( revisionListenerClassName != null ) {
|
||||
try {
|
||||
revisionListenerClass = ReflectionTools.loadClass( revisionListenerClassName, classLoaderService );
|
||||
}
|
||||
catch ( ClassLoadingException e ) {
|
||||
throw new MappingException( "Revision listener class not found: " + revisionListenerClassName + ".", e );
|
||||
catch (ClassLoadingException e) {
|
||||
throw new MappingException(
|
||||
"Revision listener class not found: " + revisionListenerClassName + ".",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
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
|
||||
* p.c. A to p.c. B iff A is a superclass of B.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass, String> {
|
||||
private Configuration cfg;
|
||||
private Configuration cfg;
|
||||
|
||||
public PersistentClassGraphDefiner(Configuration cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
public PersistentClassGraphDefiner(Configuration cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
public String getRepresentation(PersistentClass pc) {
|
||||
return pc.getEntityName();
|
||||
}
|
||||
@Override
|
||||
public String getRepresentation(PersistentClass pc) {
|
||||
return pc.getEntityName();
|
||||
}
|
||||
|
||||
public PersistentClass getValue(String entityName) {
|
||||
return cfg.getClassMapping(entityName);
|
||||
}
|
||||
@Override
|
||||
public PersistentClass getValue(String entityName) {
|
||||
return cfg.getClassMapping( entityName );
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
|
||||
while (subclassIterator.hasNext()) {
|
||||
PersistentClass subclass = subclassIterator.next();
|
||||
neighbours.add(subclass);
|
||||
addNeighbours(neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator());
|
||||
}
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
|
||||
while ( subclassIterator.hasNext() ) {
|
||||
final PersistentClass subclass = subclassIterator.next();
|
||||
neighbours.add( subclass );
|
||||
addNeighbours( neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator() );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public List<PersistentClass> getNeighbours(PersistentClass pc) {
|
||||
List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
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"})
|
||||
public List<PersistentClass> getValues() {
|
||||
return Tools.iteratorToList( cfg.getClassMappings() );
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public List<PersistentClass> getValues() {
|
||||
return Tools.iteratorToList( cfg.getClassMappings() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,10 +22,11 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
|
@ -65,301 +66,394 @@ import org.hibernate.type.Type;
|
|||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class RevisionInfoConfiguration {
|
||||
private String revisionInfoEntityName;
|
||||
private PropertyData revisionInfoIdData;
|
||||
private PropertyData revisionInfoTimestampData;
|
||||
private PropertyData modifiedEntityNamesData;
|
||||
private Type revisionInfoTimestampType;
|
||||
private GlobalConfiguration globalCfg;
|
||||
private String revisionInfoEntityName;
|
||||
private PropertyData revisionInfoIdData;
|
||||
private PropertyData revisionInfoTimestampData;
|
||||
private PropertyData modifiedEntityNamesData;
|
||||
private Type revisionInfoTimestampType;
|
||||
private GlobalConfiguration globalCfg;
|
||||
|
||||
private String revisionPropType;
|
||||
private String revisionPropSqlType;
|
||||
private String revisionPropType;
|
||||
private String revisionPropSqlType;
|
||||
|
||||
public RevisionInfoConfiguration(GlobalConfiguration globalCfg) {
|
||||
this.globalCfg = globalCfg;
|
||||
if (globalCfg.isUseRevisionEntityWithNativeId()) {
|
||||
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
|
||||
} else {
|
||||
revisionInfoEntityName = "org.hibernate.envers.enhanced.SequenceIdRevisionEntity";
|
||||
}
|
||||
revisionInfoIdData = new PropertyData("id", "id", "field", null);
|
||||
revisionInfoTimestampData = new PropertyData("timestamp", "timestamp", "field", null);
|
||||
modifiedEntityNamesData = new PropertyData("modifiedEntityNames", "modifiedEntityNames", "field", null);
|
||||
revisionInfoTimestampType = new LongType();
|
||||
public RevisionInfoConfiguration(GlobalConfiguration globalCfg) {
|
||||
this.globalCfg = globalCfg;
|
||||
if ( globalCfg.isUseRevisionEntityWithNativeId() ) {
|
||||
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
|
||||
}
|
||||
else {
|
||||
revisionInfoEntityName = "org.hibernate.envers.enhanced.SequenceIdRevisionEntity";
|
||||
}
|
||||
revisionInfoIdData = new PropertyData( "id", "id", "field", null );
|
||||
revisionInfoTimestampData = new PropertyData( "timestamp", "timestamp", "field", null );
|
||||
modifiedEntityNamesData = new PropertyData( "modifiedEntityNames", "modifiedEntityNames", "field", null );
|
||||
revisionInfoTimestampType = new LongType();
|
||||
|
||||
revisionPropType = "integer";
|
||||
}
|
||||
revisionPropType = "integer";
|
||||
}
|
||||
|
||||
private Document generateDefaultRevisionInfoXmlMapping() {
|
||||
Document document = XMLHelper.getDocumentFactory().createDocument();
|
||||
private Document generateDefaultRevisionInfoXmlMapping() {
|
||||
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);
|
||||
class_mapping.addAttribute("table", "REVINFO");
|
||||
classMapping.addAttribute( "name", revisionInfoEntityName );
|
||||
classMapping.addAttribute( "table", "REVINFO" );
|
||||
|
||||
Element idProperty = MetadataTools.addNativelyGeneratedId(class_mapping, revisionInfoIdData.getName(),
|
||||
revisionPropType, globalCfg.isUseRevisionEntityWithNativeId());
|
||||
MetadataTools.addColumn(idProperty, "REV", null, null, null, null, null, null, false);
|
||||
final Element idProperty = MetadataTools.addNativelyGeneratedId(
|
||||
classMapping,
|
||||
revisionInfoIdData.getName(),
|
||||
revisionPropType,
|
||||
globalCfg.isUseRevisionEntityWithNativeId()
|
||||
);
|
||||
MetadataTools.addColumn( idProperty, "REV", null, null, null, null, null, null, false );
|
||||
|
||||
Element timestampProperty = MetadataTools.addProperty(class_mapping, revisionInfoTimestampData.getName(),
|
||||
revisionInfoTimestampType.getName(), true, false);
|
||||
MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, null, null, null, null, null, false);
|
||||
final Element timestampProperty = MetadataTools.addProperty(
|
||||
classMapping,
|
||||
revisionInfoTimestampData.getName(),
|
||||
revisionInfoTimestampType.getName(),
|
||||
true,
|
||||
false
|
||||
);
|
||||
MetadataTools.addColumn( timestampProperty, "REVTSTMP", null, null, null, null, null, null, false );
|
||||
|
||||
if (globalCfg.isTrackEntitiesChangedInRevision()) {
|
||||
generateEntityNamesTrackingTableMapping(class_mapping, "modifiedEntityNames",
|
||||
globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName(),
|
||||
"REVCHANGES", "REV", "ENTITYNAME", "string");
|
||||
}
|
||||
if ( globalCfg.isTrackEntitiesChangedInRevision() ) {
|
||||
generateEntityNamesTrackingTableMapping(
|
||||
classMapping,
|
||||
"modifiedEntityNames",
|
||||
globalCfg.getDefaultSchemaName(),
|
||||
globalCfg.getDefaultCatalogName(),
|
||||
"REVCHANGES",
|
||||
"REV",
|
||||
"ENTITYNAME",
|
||||
"string"
|
||||
);
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates mapping that represents a set of primitive types.<br />
|
||||
* <code>
|
||||
* <set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog"
|
||||
* cascade="persist, delete" lazy="false" fetch="join"><br />
|
||||
* <key column="joinTablePrimaryKeyColumnName" /><br />
|
||||
* <element type="joinTableValueColumnType"><br />
|
||||
* <column name="joinTableValueColumnName" /><br />
|
||||
* </element><br />
|
||||
* </set>
|
||||
* </code>
|
||||
*/
|
||||
private void generateEntityNamesTrackingTableMapping(Element class_mapping, String propertyName,
|
||||
String joinTableSchema, String joinTableCatalog, String joinTableName,
|
||||
String joinTablePrimaryKeyColumnName, String joinTableValueColumnName,
|
||||
String joinTableValueColumnType) {
|
||||
Element set = class_mapping.addElement("set");
|
||||
set.addAttribute("name", propertyName);
|
||||
set.addAttribute("table", joinTableName);
|
||||
set.addAttribute("schema", joinTableSchema);
|
||||
set.addAttribute("catalog", joinTableCatalog);
|
||||
set.addAttribute("cascade", "persist, delete");
|
||||
set.addAttribute("fetch", "join");
|
||||
set.addAttribute("lazy", "false");
|
||||
Element key = set.addElement("key");
|
||||
key.addAttribute("column", joinTablePrimaryKeyColumnName);
|
||||
Element element = set.addElement("element");
|
||||
element.addAttribute("type", joinTableValueColumnType);
|
||||
Element column = element.addElement("column");
|
||||
column.addAttribute("name", joinTableValueColumnName);
|
||||
}
|
||||
/**
|
||||
* Generates mapping that represents a set of primitive types.<br />
|
||||
* <code>
|
||||
* <set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog"
|
||||
* cascade="persist, delete" lazy="false" fetch="join"><br />
|
||||
* <key column="joinTablePrimaryKeyColumnName" /><br />
|
||||
* <element type="joinTableValueColumnType"><br />
|
||||
* <column name="joinTableValueColumnName" /><br />
|
||||
* </element><br />
|
||||
* </set>
|
||||
* </code>
|
||||
*/
|
||||
private void generateEntityNamesTrackingTableMapping(
|
||||
Element classMapping,
|
||||
String propertyName,
|
||||
String joinTableSchema,
|
||||
String joinTableCatalog,
|
||||
String joinTableName,
|
||||
String joinTablePrimaryKeyColumnName,
|
||||
String joinTableValueColumnName,
|
||||
String joinTableValueColumnType) {
|
||||
final Element set = classMapping.addElement( "set" );
|
||||
set.addAttribute( "name", propertyName );
|
||||
set.addAttribute( "table", joinTableName );
|
||||
set.addAttribute( "schema", joinTableSchema );
|
||||
set.addAttribute( "catalog", joinTableCatalog );
|
||||
set.addAttribute( "cascade", "persist, delete" );
|
||||
set.addAttribute( "fetch", "join" );
|
||||
set.addAttribute( "lazy", "false" );
|
||||
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() {
|
||||
Document document = XMLHelper.getDocumentFactory().createDocument();
|
||||
Element rev_rel_mapping = document.addElement("key-many-to-one");
|
||||
rev_rel_mapping.addAttribute("type", revisionPropType);
|
||||
rev_rel_mapping.addAttribute("class", revisionInfoEntityName);
|
||||
private Element generateRevisionInfoRelationMapping() {
|
||||
final Document document = XMLHelper.getDocumentFactory().createDocument();
|
||||
final Element revRelMapping = document.addElement( "key-many-to-one" );
|
||||
revRelMapping.addAttribute( "type", revisionPropType );
|
||||
revRelMapping.addAttribute( "class", revisionInfoEntityName );
|
||||
|
||||
if (revisionPropSqlType != null) {
|
||||
// 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);
|
||||
}
|
||||
if ( revisionPropSqlType != null ) {
|
||||
// Putting a fake name to make Hibernate happy. It will be replaced later anyway.
|
||||
MetadataTools.addColumn( revRelMapping, "*", null, null, null, revisionPropSqlType, null, null, false );
|
||||
}
|
||||
|
||||
return rev_rel_mapping;
|
||||
}
|
||||
return revRelMapping;
|
||||
}
|
||||
|
||||
private void searchForRevisionInfoCfgInProperties(XClass clazz, ReflectionManager reflectionManager,
|
||||
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
|
||||
MutableBoolean modifiedEntityNamesFound, String accessType) {
|
||||
for (XProperty property : clazz.getDeclaredProperties(accessType)) {
|
||||
RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
|
||||
RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class);
|
||||
ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class);
|
||||
private void searchForRevisionInfoCfgInProperties(
|
||||
XClass clazz,
|
||||
ReflectionManager reflectionManager,
|
||||
MutableBoolean revisionNumberFound,
|
||||
MutableBoolean revisionTimestampFound,
|
||||
MutableBoolean modifiedEntityNamesFound,
|
||||
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 (revisionNumberFound.isSet()) {
|
||||
throw new MappingException("Only one property may be annotated with @RevisionNumber!");
|
||||
}
|
||||
if ( revisionNumber != null ) {
|
||||
if ( revisionNumberFound.isSet() ) {
|
||||
throw new MappingException( "Only one property may be annotated with @RevisionNumber!" );
|
||||
}
|
||||
|
||||
XClass revisionNumberClass = property.getType();
|
||||
if (reflectionManager.equals(revisionNumberClass, Integer.class) ||
|
||||
reflectionManager.equals(revisionNumberClass, Integer.TYPE)) {
|
||||
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null);
|
||||
revisionNumberFound.set();
|
||||
} else if (reflectionManager.equals(revisionNumberClass, Long.class) ||
|
||||
reflectionManager.equals(revisionNumberClass, Long.TYPE)) {
|
||||
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null);
|
||||
revisionNumberFound.set();
|
||||
final XClass revisionNumberClass = property.getType();
|
||||
if ( reflectionManager.equals( revisionNumberClass, Integer.class ) ||
|
||||
reflectionManager.equals( revisionNumberClass, Integer.TYPE ) ) {
|
||||
revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
|
||||
revisionNumberFound.set();
|
||||
}
|
||||
else if ( reflectionManager.equals( revisionNumberClass, Long.class ) ||
|
||||
reflectionManager.equals( revisionNumberClass, Long.TYPE ) ) {
|
||||
revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
|
||||
revisionNumberFound.set();
|
||||
|
||||
// The default is integer
|
||||
revisionPropType = "long";
|
||||
} else {
|
||||
throw new MappingException("The field annotated with @RevisionNumber must be of type " +
|
||||
"int, Integer, long or Long");
|
||||
}
|
||||
// The default is integer
|
||||
revisionPropType = "long";
|
||||
}
|
||||
else {
|
||||
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
|
||||
// generate the same mapping for the relation from an audit table's revision number to the
|
||||
// revision entity revision number.
|
||||
Column revisionPropColumn = property.getAnnotation(Column.class);
|
||||
if (revisionPropColumn != null) {
|
||||
revisionPropSqlType = revisionPropColumn.columnDefinition();
|
||||
}
|
||||
}
|
||||
// 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
|
||||
// revision entity revision number.
|
||||
final Column revisionPropColumn = property.getAnnotation( Column.class );
|
||||
if ( revisionPropColumn != null ) {
|
||||
revisionPropSqlType = revisionPropColumn.columnDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
if (revisionTimestamp != null) {
|
||||
if (revisionTimestampFound.isSet()) {
|
||||
throw new MappingException("Only one property may be annotated with @RevisionTimestamp!");
|
||||
}
|
||||
if ( revisionTimestamp != null ) {
|
||||
if ( revisionTimestampFound.isSet() ) {
|
||||
throw new MappingException( "Only one property may be annotated with @RevisionTimestamp!" );
|
||||
}
|
||||
|
||||
XClass revisionTimestampClass = property.getType();
|
||||
if (reflectionManager.equals(revisionTimestampClass, Long.class) ||
|
||||
reflectionManager.equals(revisionTimestampClass, Long.TYPE) ||
|
||||
reflectionManager.equals(revisionTimestampClass, Date.class) ||
|
||||
reflectionManager.equals(revisionTimestampClass, java.sql.Date.class)) {
|
||||
revisionInfoTimestampData = new PropertyData(property.getName(), property.getName(), accessType, 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");
|
||||
}
|
||||
}
|
||||
final XClass revisionTimestampClass = property.getType();
|
||||
if ( reflectionManager.equals( revisionTimestampClass, Long.class ) ||
|
||||
reflectionManager.equals( revisionTimestampClass, Long.TYPE ) ||
|
||||
reflectionManager.equals( revisionTimestampClass, Date.class ) ||
|
||||
reflectionManager.equals( revisionTimestampClass, java.sql.Date.class ) ) {
|
||||
revisionInfoTimestampData = new PropertyData(
|
||||
property.getName(),
|
||||
property.getName(),
|
||||
accessType,
|
||||
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 (modifiedEntityNamesFound.isSet()) {
|
||||
throw new MappingException("Only one property may be annotated with @ModifiedEntityNames!");
|
||||
}
|
||||
XClass modifiedEntityNamesClass = property.getType();
|
||||
if (reflectionManager.equals(modifiedEntityNamesClass, Set.class) &&
|
||||
reflectionManager.equals(property.getElementClass(), String.class)) {
|
||||
modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null);
|
||||
modifiedEntityNamesFound.set();
|
||||
} else {
|
||||
throw new MappingException("The field annotated with @ModifiedEntityNames must be of Set<String> type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( modifiedEntityNames != null ) {
|
||||
if ( modifiedEntityNamesFound.isSet() ) {
|
||||
throw new MappingException( "Only one property may be annotated with @ModifiedEntityNames!" );
|
||||
}
|
||||
final XClass modifiedEntityNamesClass = property.getType();
|
||||
if ( reflectionManager.equals( modifiedEntityNamesClass, Set.class ) &&
|
||||
reflectionManager.equals( property.getElementClass(), String.class ) ) {
|
||||
modifiedEntityNamesData = new PropertyData(
|
||||
property.getName(),
|
||||
property.getName(),
|
||||
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,
|
||||
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
|
||||
MutableBoolean modifiedEntityNamesFound) {
|
||||
XClass superclazz = clazz.getSuperclass();
|
||||
if (!"java.lang.Object".equals(superclazz.getName())) {
|
||||
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
|
||||
}
|
||||
private void searchForRevisionInfoCfg(
|
||||
XClass clazz, ReflectionManager reflectionManager,
|
||||
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
|
||||
MutableBoolean modifiedEntityNamesFound) {
|
||||
final XClass superclazz = clazz.getSuperclass();
|
||||
if ( !"java.lang.Object".equals( superclazz.getName() ) ) {
|
||||
searchForRevisionInfoCfg(
|
||||
superclazz,
|
||||
reflectionManager,
|
||||
revisionNumberFound,
|
||||
revisionTimestampFound,
|
||||
modifiedEntityNamesFound
|
||||
);
|
||||
}
|
||||
|
||||
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
||||
modifiedEntityNamesFound, "field");
|
||||
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
||||
modifiedEntityNamesFound, "property");
|
||||
}
|
||||
searchForRevisionInfoCfgInProperties(
|
||||
clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
||||
modifiedEntityNamesFound, "field"
|
||||
);
|
||||
searchForRevisionInfoCfgInProperties(
|
||||
clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
|
||||
modifiedEntityNamesFound, "property"
|
||||
);
|
||||
}
|
||||
|
||||
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
|
||||
Iterator<PersistentClass> classes = cfg.getClassMappings();
|
||||
boolean revisionEntityFound = false;
|
||||
RevisionInfoGenerator revisionInfoGenerator = null;
|
||||
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
|
||||
boolean revisionEntityFound = false;
|
||||
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()) {
|
||||
PersistentClass pc = classes.next();
|
||||
XClass clazz;
|
||||
try {
|
||||
clazz = reflectionManager.classForName(pc.getClassName(), this.getClass());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new MappingException(e);
|
||||
}
|
||||
final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
|
||||
if ( revisionEntity != null ) {
|
||||
if ( revisionEntityFound ) {
|
||||
throw new MappingException( "Only one entity may be annotated with @RevisionEntity!" );
|
||||
}
|
||||
|
||||
RevisionEntity revisionEntity = clazz.getAnnotation(RevisionEntity.class);
|
||||
if (revisionEntity != null) {
|
||||
if (revisionEntityFound) {
|
||||
throw new MappingException("Only one entity may be annotated with @RevisionEntity!");
|
||||
}
|
||||
// Checking if custom revision entity isn't audited
|
||||
if ( clazz.getAnnotation( Audited.class ) != null ) {
|
||||
throw new MappingException( "An entity annotated with @RevisionEntity cannot be audited!" );
|
||||
}
|
||||
|
||||
// Checking if custom revision entity isn't audited
|
||||
if (clazz.getAnnotation(Audited.class) != null) {
|
||||
throw new MappingException("An entity annotated with @RevisionEntity cannot be audited!");
|
||||
}
|
||||
revisionEntityFound = true;
|
||||
|
||||
revisionEntityFound = true;
|
||||
final MutableBoolean revisionNumberFound = new MutableBoolean();
|
||||
final MutableBoolean revisionTimestampFound = new MutableBoolean();
|
||||
final MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
|
||||
|
||||
MutableBoolean revisionNumberFound = new MutableBoolean();
|
||||
MutableBoolean revisionTimestampFound = new MutableBoolean();
|
||||
MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
|
||||
searchForRevisionInfoCfg(
|
||||
clazz,
|
||||
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()) {
|
||||
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
|
||||
"with @RevisionNumber!");
|
||||
}
|
||||
if ( !revisionTimestampFound.isSet() ) {
|
||||
throw new MappingException(
|
||||
"An entity annotated with @RevisionEntity must have a field annotated " +
|
||||
"with @RevisionTimestamp!"
|
||||
);
|
||||
}
|
||||
|
||||
if (!revisionTimestampFound.isSet()) {
|
||||
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
|
||||
"with @RevisionTimestamp!");
|
||||
}
|
||||
revisionInfoEntityName = pc.getEntityName();
|
||||
revisionInfoClass = pc.getMappedClass();
|
||||
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();
|
||||
revisionInfoClass = pc.getMappedClass();
|
||||
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.
|
||||
Document revisionInfoXmlMapping = null;
|
||||
|
||||
// In case of a custom revision info generator, the mapping will be null.
|
||||
Document revisionInfoXmlMapping = null;
|
||||
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( RevisionListener.class );
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
return new RevisionInfoConfigurationResult(
|
||||
revisionInfoGenerator, revisionInfoXmlMapping,
|
||||
new RevisionInfoQueryCreator(
|
||||
revisionInfoEntityName, revisionInfoIdData.getName(),
|
||||
revisionInfoTimestampData.getName(), isTimestampAsDate()
|
||||
),
|
||||
generateRevisionInfoRelationMapping(),
|
||||
new RevisionInfoNumberReader( revisionInfoClass, revisionInfoIdData ),
|
||||
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(
|
||||
revisionInfoClass,
|
||||
modifiedEntityNamesData
|
||||
)
|
||||
: null,
|
||||
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData
|
||||
);
|
||||
}
|
||||
|
||||
return new RevisionInfoConfigurationResult(
|
||||
revisionInfoGenerator, revisionInfoXmlMapping,
|
||||
new RevisionInfoQueryCreator(revisionInfoEntityName, revisionInfoIdData.getName(),
|
||||
revisionInfoTimestampData.getName(), isTimestampAsDate()),
|
||||
generateRevisionInfoRelationMapping(),
|
||||
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData),
|
||||
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData)
|
||||
: null,
|
||||
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData);
|
||||
}
|
||||
private boolean isTimestampAsDate() {
|
||||
final String typename = revisionInfoTimestampType.getName();
|
||||
return "date".equals( typename ) || "time".equals( typename ) || "timestamp".equals( typename );
|
||||
}
|
||||
|
||||
private boolean isTimestampAsDate() {
|
||||
String typename = revisionInfoTimestampType.getName();
|
||||
return "date".equals(typename) || "time".equals(typename) || "timestamp".equals(typename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
|
||||
* parameter has not been set.
|
||||
* @return Revision listener.
|
||||
*/
|
||||
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) {
|
||||
if (globalCfg.getRevisionListenerClass() != null) {
|
||||
return globalCfg.getRevisionListenerClass();
|
||||
}
|
||||
return defaultListener;
|
||||
}
|
||||
/**
|
||||
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
|
||||
* parameter has not been set.
|
||||
*
|
||||
* @return Revision listener.
|
||||
*/
|
||||
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> 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;
|
||||
|
||||
import org.dom4j.Document;
|
||||
|
@ -23,11 +46,12 @@ public class RevisionInfoConfigurationResult {
|
|||
private final Class<?> revisionInfoClass;
|
||||
private final PropertyData revisionInfoTimestampData;
|
||||
|
||||
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
|
||||
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
|
||||
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
|
||||
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
|
||||
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
|
||||
RevisionInfoConfigurationResult(
|
||||
RevisionInfoGenerator revisionInfoGenerator,
|
||||
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
|
||||
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
|
||||
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
|
||||
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
|
||||
this.revisionInfoGenerator = revisionInfoGenerator;
|
||||
this.revisionInfoXmlMapping = revisionInfoXmlMapping;
|
||||
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;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -6,46 +30,49 @@ import org.hibernate.MappingException;
|
|||
|
||||
/**
|
||||
* A register of all audit entity names used so far.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
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.
|
||||
* @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 auditEntityName Name of the audit entity.
|
||||
*
|
||||
* @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 True if the given audit entity name is already used.
|
||||
*/
|
||||
private boolean check(String auditEntityName) {
|
||||
return auditEntityNames.contains( auditEntityName );
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -21,41 +21,41 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
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
|
||||
* entity name.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class AuditTableData {
|
||||
private final String auditEntityName;
|
||||
private final String auditTableName;
|
||||
private final String schema;
|
||||
private final String catalog;
|
||||
private final String auditEntityName;
|
||||
private final String auditTableName;
|
||||
private final String schema;
|
||||
private final String catalog;
|
||||
|
||||
public AuditTableData(String auditEntityName, String auditTableName, String schema, String catalog) {
|
||||
this.auditEntityName = auditEntityName;
|
||||
this.auditTableName = auditTableName;
|
||||
this.schema = schema;
|
||||
this.catalog = catalog;
|
||||
}
|
||||
public AuditTableData(String auditEntityName, String auditTableName, String schema, String catalog) {
|
||||
this.auditEntityName = auditEntityName;
|
||||
this.auditTableName = auditTableName;
|
||||
this.schema = schema;
|
||||
this.catalog = catalog;
|
||||
}
|
||||
|
||||
public String getAuditEntityName() {
|
||||
return auditEntityName;
|
||||
}
|
||||
public String getAuditEntityName() {
|
||||
return auditEntityName;
|
||||
}
|
||||
|
||||
public String getAuditTableName() {
|
||||
return auditTableName;
|
||||
}
|
||||
public String getAuditTableName() {
|
||||
return auditTableName;
|
||||
}
|
||||
|
||||
public String getSchema() {
|
||||
return schema;
|
||||
}
|
||||
public String getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
public String getCatalog() {
|
||||
return catalog;
|
||||
}
|
||||
public String getCatalog() {
|
||||
return catalog;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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).
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public final class BasicMetadataGenerator {
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
boolean addBasic(Element parent, PropertyAuditingData propertyAuditingData,
|
||||
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
||||
Type type = value.getType();
|
||||
@SuppressWarnings({"unchecked"})
|
||||
boolean addBasic(
|
||||
Element parent, PropertyAuditingData propertyAuditingData,
|
||||
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
||||
final Type type = value.getType();
|
||||
|
||||
if ( type instanceof BasicType || type instanceof SerializableToBlobType ||
|
||||
"org.hibernate.type.PrimitiveByteArrayBlobType".equals( type.getClass().getName() ) ) {
|
||||
if ( type instanceof BasicType
|
||||
|| type instanceof SerializableToBlobType
|
||||
|| "org.hibernate.type.PrimitiveByteArrayBlobType".equals( type.getClass().getName() ) ) {
|
||||
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();
|
||||
if ( typeName == null ) {
|
||||
typeName = type.getClass().getName();
|
||||
}
|
||||
|
||||
Element prop_mapping = MetadataTools.addProperty(
|
||||
parent, propertyAuditingData.getName(),
|
||||
addNestedType ? null : typeName, propertyAuditingData.isForceInsertable() || insertable, key
|
||||
final Element propMapping = MetadataTools.addProperty(
|
||||
parent,
|
||||
propertyAuditingData.getName(),
|
||||
addNestedType ? null : typeName,
|
||||
propertyAuditingData.isForceInsertable() || insertable,
|
||||
key
|
||||
);
|
||||
MetadataTools.addColumns( prop_mapping, value.getColumnIterator() );
|
||||
MetadataTools.addColumns( propMapping, value.getColumnIterator() );
|
||||
|
||||
if ( addNestedType ) {
|
||||
Properties typeParameters = ( (SimpleValue) value ).getTypeParameters();
|
||||
Element type_mapping = prop_mapping.addElement( "type" );
|
||||
type_mapping.addAttribute( "name", typeName );
|
||||
final Properties typeParameters = ((SimpleValue) value).getTypeParameters();
|
||||
final Element typeMapping = propMapping.addElement( "type" );
|
||||
typeMapping.addAttribute( "name", typeName );
|
||||
|
||||
if ( "org.hibernate.type.EnumType".equals( typeName ) ) {
|
||||
// Proper handling of enumeration type
|
||||
mapEnumerationType( type_mapping, type, typeParameters );
|
||||
mapEnumerationType( typeMapping, type, typeParameters );
|
||||
}
|
||||
else {
|
||||
// By default copying all Hibernate properties
|
||||
for ( Object object : typeParameters.keySet() ) {
|
||||
String keyType = (String) object;
|
||||
String property = typeParameters.getProperty( keyType );
|
||||
final String keyType = (String) object;
|
||||
final String property = typeParameters.getProperty( keyType );
|
||||
|
||||
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) {
|
||||
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 {
|
||||
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 ) {
|
||||
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 ) {
|
||||
// Case of annotations.
|
||||
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED )
|
||||
.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.
|
||||
.setText( "" + !((EnumType) ((CustomType) type).getUserType()).isOrdinal() );
|
||||
}
|
||||
// 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" })
|
||||
boolean addManyToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value, SimpleMapperBuilder mapper) {
|
||||
Type type = value.getType();
|
||||
@SuppressWarnings({"unchecked"})
|
||||
boolean addManyToOne(
|
||||
Element parent,
|
||||
PropertyAuditingData propertyAuditingData,
|
||||
Value value,
|
||||
SimpleMapperBuilder mapper) {
|
||||
final Type type = value.getType();
|
||||
|
||||
// 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( "class", type.getName() );
|
||||
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;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
@ -14,6 +37,7 @@ import org.hibernate.mapping.Value;
|
|||
|
||||
/**
|
||||
* Generates metadata for components.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public final class ComponentMetadataGenerator {
|
||||
|
@ -24,29 +48,38 @@ public final class ComponentMetadataGenerator {
|
|||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public void addComponent(Element parent, PropertyAuditingData propertyAuditingData,
|
||||
Value value, CompositeMapperBuilder mapper, String entityName,
|
||||
EntityXmlMappingData xmlMappingData, boolean firstPass) {
|
||||
Component prop_component = (Component) value;
|
||||
public void addComponent(
|
||||
Element parent, PropertyAuditingData propertyAuditingData,
|
||||
Value value, CompositeMapperBuilder mapper, String entityName,
|
||||
EntityXmlMappingData xmlMappingData, boolean firstPass) {
|
||||
final Component propComponent = (Component) value;
|
||||
|
||||
Class componentClass = ReflectionTools.loadClass( prop_component.getComponentClassName(), mainGenerator.getClassLoaderService() );
|
||||
CompositeMapperBuilder componentMapper = mapper.addComponent( propertyAuditingData.getPropertyData(), componentClass );
|
||||
final Class componentClass = ReflectionTools.loadClass(
|
||||
propComponent.getComponentClassName(),
|
||||
mainGenerator.getClassLoaderService()
|
||||
);
|
||||
final CompositeMapperBuilder componentMapper = mapper.addComponent(
|
||||
propertyAuditingData.getPropertyData(),
|
||||
componentClass
|
||||
);
|
||||
|
||||
// The property auditing data must be for a component.
|
||||
ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
|
||||
final ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
|
||||
|
||||
// Adding all properties of the component
|
||||
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator();
|
||||
while (properties.hasNext()) {
|
||||
Property property = properties.next();
|
||||
final Iterator<Property> properties = (Iterator<Property>) propComponent.getPropertyIterator();
|
||||
while ( properties.hasNext() ) {
|
||||
final Property property = properties.next();
|
||||
|
||||
PropertyAuditingData componentPropertyAuditingData =
|
||||
componentAuditingData.getPropertyAuditingData(property.getName());
|
||||
final PropertyAuditingData componentPropertyAuditingData =
|
||||
componentAuditingData.getPropertyAuditingData( property.getName() );
|
||||
|
||||
// Checking if that property is audited
|
||||
if (componentPropertyAuditingData != null) {
|
||||
mainGenerator.addValue(parent, property.getValue(), componentMapper, entityName, xmlMappingData,
|
||||
componentPropertyAuditingData, property.isInsertable(), firstPass, false);
|
||||
if ( componentPropertyAuditingData != null ) {
|
||||
mainGenerator.addValue(
|
||||
parent, property.getValue(), componentMapper, entityName, xmlMappingData,
|
||||
componentPropertyAuditingData, property.isInsertable(), firstPass, false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -33,39 +34,39 @@ import org.dom4j.Element;
|
|||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class EntityXmlMappingData {
|
||||
private Document mainXmlMapping;
|
||||
private List<Document> additionalXmlMappings;
|
||||
/**
|
||||
* The xml element that maps the class. The root can be one of the folowing elements:
|
||||
* class, subclass, union-subclass, joined-subclass
|
||||
*/
|
||||
private Element classMapping;
|
||||
private Document mainXmlMapping;
|
||||
private List<Document> additionalXmlMappings;
|
||||
/**
|
||||
* The xml element that maps the class. The root can be one of the folowing elements:
|
||||
* class, subclass, union-subclass, joined-subclass
|
||||
*/
|
||||
private Element classMapping;
|
||||
|
||||
public EntityXmlMappingData() {
|
||||
mainXmlMapping = DocumentHelper.createDocument();
|
||||
additionalXmlMappings = new ArrayList<Document>();
|
||||
}
|
||||
public EntityXmlMappingData() {
|
||||
mainXmlMapping = DocumentHelper.createDocument();
|
||||
additionalXmlMappings = new ArrayList<Document>();
|
||||
}
|
||||
|
||||
public Document getMainXmlMapping() {
|
||||
return mainXmlMapping;
|
||||
}
|
||||
public Document getMainXmlMapping() {
|
||||
return mainXmlMapping;
|
||||
}
|
||||
|
||||
public List<Document> getAdditionalXmlMappings() {
|
||||
return additionalXmlMappings;
|
||||
}
|
||||
public List<Document> getAdditionalXmlMappings() {
|
||||
return additionalXmlMappings;
|
||||
}
|
||||
|
||||
public Document newAdditionalMapping() {
|
||||
Document additionalMapping = DocumentHelper.createDocument();
|
||||
additionalXmlMappings.add(additionalMapping);
|
||||
public Document newAdditionalMapping() {
|
||||
Document additionalMapping = DocumentHelper.createDocument();
|
||||
additionalXmlMappings.add( additionalMapping );
|
||||
|
||||
return additionalMapping;
|
||||
}
|
||||
return additionalMapping;
|
||||
}
|
||||
|
||||
public Element getClassMapping() {
|
||||
return classMapping;
|
||||
}
|
||||
public Element getClassMapping() {
|
||||
return classMapping;
|
||||
}
|
||||
|
||||
public void setClassMapping(Element classMapping) {
|
||||
this.classMapping = classMapping;
|
||||
}
|
||||
public void setClassMapping(Element classMapping) {
|
||||
this.classMapping = classMapping;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.dom4j.Element;
|
||||
|
@ -47,127 +48,181 @@ import org.hibernate.type.Type;
|
|||
|
||||
/**
|
||||
* Generates metadata for primary identifiers (ids) of versions entities.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public final class IdMetadataGenerator {
|
||||
private final AuditMetadataGenerator mainGenerator;
|
||||
private final AuditMetadataGenerator mainGenerator;
|
||||
|
||||
IdMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
||||
mainGenerator = auditMetadataGenerator;
|
||||
}
|
||||
IdMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
||||
mainGenerator = auditMetadataGenerator;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private boolean addIdProperties(Element parent, Iterator<Property> properties, SimpleMapperBuilder mapper, boolean key,
|
||||
boolean audited) {
|
||||
while (properties.hasNext()) {
|
||||
Property property = properties.next();
|
||||
Type propertyType = property.getType();
|
||||
if (!"_identifierMapper".equals(property.getName())) {
|
||||
boolean added = false;
|
||||
if (propertyType instanceof ManyToOneType) {
|
||||
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(parent,
|
||||
getIdPersistentPropertyAuditingData(property),
|
||||
property.getValue(), mapper);
|
||||
} else {
|
||||
// Last but one parameter: ids are always insertable
|
||||
added = mainGenerator.getBasicMetadataGenerator().addBasic(parent,
|
||||
getIdPersistentPropertyAuditingData(property),
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private boolean addIdProperties(
|
||||
Element parent,
|
||||
Iterator<Property> properties,
|
||||
SimpleMapperBuilder mapper,
|
||||
boolean key,
|
||||
boolean audited) {
|
||||
while ( properties.hasNext() ) {
|
||||
final Property property = properties.next();
|
||||
final Type propertyType = property.getType();
|
||||
if ( !"_identifierMapper".equals( property.getName() ) ) {
|
||||
boolean added = false;
|
||||
if ( propertyType instanceof ManyToOneType ) {
|
||||
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(
|
||||
parent,
|
||||
getIdPersistentPropertyAuditingData( property ),
|
||||
property.getValue(),
|
||||
mapper
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Last but one parameter: ids are always insertable
|
||||
added = mainGenerator.getBasicMetadataGenerator().addBasic(
|
||||
parent,
|
||||
getIdPersistentPropertyAuditingData( property ),
|
||||
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"})
|
||||
IdMappingData addId(PersistentClass pc, boolean audited) {
|
||||
// Xml mapping which will be used for relations
|
||||
Element rel_id_mapping = new DefaultElement("properties");
|
||||
// Xml mapping which will be used for the primary key of the versions table
|
||||
Element orig_id_mapping = new DefaultElement("composite-id");
|
||||
@SuppressWarnings({"unchecked"})
|
||||
IdMappingData addId(PersistentClass pc, boolean audited) {
|
||||
// Xml mapping which will be used for relations
|
||||
final Element relIdMapping = new DefaultElement( "properties" );
|
||||
// Xml mapping which will be used for the primary key of the versions table
|
||||
final Element origIdMapping = new DefaultElement( "composite-id" );
|
||||
|
||||
Property id_prop = pc.getIdentifierProperty();
|
||||
Component id_mapper = pc.getIdentifierMapper();
|
||||
final Property idProp = pc.getIdentifierProperty();
|
||||
final Component idMapper = pc.getIdentifierMapper();
|
||||
|
||||
// Checking if the id mapping is supported
|
||||
if (id_mapper == null && id_prop == null) {
|
||||
return null;
|
||||
}
|
||||
// Checking if the id mapping is supported
|
||||
if ( idMapper == null && idProp == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SimpleIdMapperBuilder mapper;
|
||||
if (id_mapper != null) {
|
||||
// Multiple id
|
||||
|
||||
Class componentClass = ReflectionTools.loadClass(
|
||||
( (Component) pc.getIdentifier() ).getComponentClassName(), mainGenerator.getClassLoaderService()
|
||||
SimpleIdMapperBuilder mapper;
|
||||
if ( idMapper != null ) {
|
||||
// Multiple id
|
||||
final Class componentClass = ReflectionTools.loadClass(
|
||||
( (Component) pc.getIdentifier() ).getComponentClassName(),
|
||||
mainGenerator.getClassLoaderService()
|
||||
);
|
||||
mapper = new MultipleIdMapper( componentClass );
|
||||
if (!addIdProperties(rel_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), mapper, false, audited)) {
|
||||
return null;
|
||||
}
|
||||
if ( !addIdProperties(
|
||||
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
|
||||
if (!addIdProperties(orig_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), null, true, audited)) {
|
||||
return null;
|
||||
}
|
||||
} else if (id_prop.isComposite()) {
|
||||
// Embedded id
|
||||
|
||||
Component id_component = (Component) id_prop.getValue();
|
||||
Class embeddableClass = ReflectionTools.loadClass(
|
||||
id_component.getComponentClassName(), mainGenerator.getClassLoaderService()
|
||||
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
||||
if ( !addIdProperties(
|
||||
origIdMapping,
|
||||
(Iterator<Property>) idMapper.getPropertyIterator(),
|
||||
null,
|
||||
true,
|
||||
audited
|
||||
) ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
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 );
|
||||
if (!addIdProperties(rel_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), mapper, false, audited)) {
|
||||
return null;
|
||||
}
|
||||
mapper = new EmbeddedIdMapper( getIdPropertyData( idProp ), embeddableClass );
|
||||
if ( !addIdProperties(
|
||||
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
|
||||
if (!addIdProperties(orig_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), null, true, audited)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// Single id
|
||||
|
||||
mapper = new SingleIdMapper();
|
||||
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
||||
if ( !addIdProperties(
|
||||
origIdMapping,
|
||||
(Iterator<Property>) idComponent.getPropertyIterator(),
|
||||
null,
|
||||
true,
|
||||
audited
|
||||
) ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Single id
|
||||
mapper = new SingleIdMapper();
|
||||
|
||||
// Last but one parameter: ids are always insertable
|
||||
mainGenerator.getBasicMetadataGenerator().addBasic(rel_id_mapping,
|
||||
getIdPersistentPropertyAuditingData(id_prop),
|
||||
id_prop.getValue(), mapper, true, false);
|
||||
// Last but one parameter: ids are always insertable
|
||||
mainGenerator.getBasicMetadataGenerator().addBasic(
|
||||
relIdMapping,
|
||||
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
|
||||
mainGenerator.getBasicMetadataGenerator().addBasic(orig_id_mapping,
|
||||
getIdPersistentPropertyAuditingData(id_prop),
|
||||
id_prop.getValue(), null, true, true);
|
||||
}
|
||||
// null mapper - the mapping where already added the first time, now we only want to generate the xml
|
||||
mainGenerator.getBasicMetadataGenerator().addBasic(
|
||||
origIdMapping,
|
||||
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)
|
||||
mainGenerator.addRevisionInfoRelation(orig_id_mapping);
|
||||
// Adding a relation to the revision entity (effectively: the "revision number" property)
|
||||
mainGenerator.addRevisionInfoRelation( origIdMapping );
|
||||
|
||||
return new IdMappingData(mapper, orig_id_mapping, rel_id_mapping);
|
||||
}
|
||||
return new IdMappingData( mapper, origIdMapping, relIdMapping );
|
||||
}
|
||||
|
||||
private PropertyData getIdPropertyData(Property property) {
|
||||
return new PropertyData(property.getName(), property.getName(), property.getPropertyAccessorName(),
|
||||
ModificationStore.FULL);
|
||||
}
|
||||
private PropertyData getIdPropertyData(Property property) {
|
||||
return new PropertyData(
|
||||
property.getName(), property.getName(), property.getPropertyAccessorName(),
|
||||
ModificationStore.FULL
|
||||
);
|
||||
}
|
||||
|
||||
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
|
||||
return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
|
||||
ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false);
|
||||
}
|
||||
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
|
||||
return new PropertyAuditingData(
|
||||
property.getName(), property.getPropertyAccessorName(),
|
||||
ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.mapping.JoinedSubclass;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
|
@ -33,33 +34,36 @@ import org.hibernate.mapping.UnionSubclass;
|
|||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public enum InheritanceType {
|
||||
NONE,
|
||||
JOINED,
|
||||
SINGLE,
|
||||
TABLE_PER_CLASS;
|
||||
NONE,
|
||||
JOINED,
|
||||
SINGLE,
|
||||
TABLE_PER_CLASS;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
public static InheritanceType get(PersistentClass pc) {
|
||||
PersistentClass superclass = pc.getSuperclass();
|
||||
if (superclass == null) {
|
||||
return InheritanceType.NONE;
|
||||
}
|
||||
/**
|
||||
* @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 persistent class.
|
||||
*/
|
||||
public static InheritanceType get(PersistentClass pc) {
|
||||
final PersistentClass superclass = pc.getSuperclass();
|
||||
if ( superclass == null ) {
|
||||
return InheritanceType.NONE;
|
||||
}
|
||||
|
||||
// We assume that every subclass is of the same type.
|
||||
Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
|
||||
// We assume that every subclass is of the same type.
|
||||
final Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
|
||||
|
||||
if (subclass instanceof SingleTableSubclass) {
|
||||
return InheritanceType.SINGLE;
|
||||
} else if (subclass instanceof JoinedSubclass) {
|
||||
return InheritanceType.JOINED;
|
||||
} else if (subclass instanceof UnionSubclass) {
|
||||
return InheritanceType.TABLE_PER_CLASS;
|
||||
}
|
||||
if ( subclass instanceof SingleTableSubclass ) {
|
||||
return InheritanceType.SINGLE;
|
||||
}
|
||||
else if ( subclass instanceof JoinedSubclass ) {
|
||||
return InheritanceType.JOINED;
|
||||
}
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,8 +22,9 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.dom4j.Attribute;
|
||||
import org.dom4j.Document;
|
||||
|
@ -41,52 +42,72 @@ import org.hibernate.mapping.Selectable;
|
|||
*/
|
||||
public class MetadataTools {
|
||||
|
||||
public static Element addNativelyGeneratedId(Element parent, String name, String type,
|
||||
boolean useRevisionEntityWithNativeId) {
|
||||
Element id_mapping = parent.addElement("id");
|
||||
id_mapping.addAttribute("name", name).addAttribute("type", type);
|
||||
public static Element addNativelyGeneratedId(
|
||||
Element parent, String name, String type,
|
||||
boolean useRevisionEntityWithNativeId) {
|
||||
final Element idMapping = parent.addElement( "id" );
|
||||
idMapping.addAttribute( "name", name ).addAttribute( "type", type );
|
||||
|
||||
Element generator_mapping = id_mapping.addElement("generator");
|
||||
if (useRevisionEntityWithNativeId) {
|
||||
generator_mapping.addAttribute("class", "native");
|
||||
} else {
|
||||
generator_mapping.addAttribute("class", "org.hibernate.envers.enhanced.OrderedSequenceGenerator");
|
||||
generator_mapping.addElement("param").addAttribute("name", "sequence_name").setText("REVISION_GENERATOR");
|
||||
generator_mapping.addElement("param").addAttribute("name", "table_name").setText("REVISION_GENERATOR");
|
||||
generator_mapping.addElement("param").addAttribute("name", "initial_value").setText("1");
|
||||
generator_mapping.addElement("param").addAttribute("name", "increment_size").setText("1");
|
||||
}
|
||||
// generator_mapping.addAttribute("class", "sequence");
|
||||
// generator_mapping.addElement("param").addAttribute("name", "sequence").setText("custom");
|
||||
final Element generatorMapping = idMapping.addElement( "generator" );
|
||||
if ( useRevisionEntityWithNativeId ) {
|
||||
generatorMapping.addAttribute( "class", "native" );
|
||||
}
|
||||
else {
|
||||
generatorMapping.addAttribute( "class", "org.hibernate.envers.enhanced.OrderedSequenceGenerator" );
|
||||
generatorMapping.addElement( "param" ).addAttribute( "name", "sequence_name" ).setText(
|
||||
"REVISION_GENERATOR"
|
||||
);
|
||||
generatorMapping.addElement( "param" )
|
||||
.addAttribute( "name", "table_name" )
|
||||
.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) {
|
||||
Element prop_mapping;
|
||||
if (key) {
|
||||
prop_mapping = parent.addElement("key-property");
|
||||
} else {
|
||||
prop_mapping = parent.addElement("property");
|
||||
}
|
||||
public static Element addProperty(
|
||||
Element parent,
|
||||
String name,
|
||||
String type,
|
||||
boolean insertable,
|
||||
boolean updateable,
|
||||
boolean key) {
|
||||
final Element propMapping;
|
||||
if ( key ) {
|
||||
propMapping = parent.addElement( "key-property" );
|
||||
}
|
||||
else {
|
||||
propMapping = parent.addElement( "property" );
|
||||
}
|
||||
|
||||
prop_mapping.addAttribute("name", name);
|
||||
prop_mapping.addAttribute("insert", Boolean.toString(insertable));
|
||||
prop_mapping.addAttribute("update", Boolean.toString(updateable));
|
||||
propMapping.addAttribute( "name", name );
|
||||
propMapping.addAttribute( "insert", Boolean.toString( insertable ) );
|
||||
propMapping.addAttribute( "update", Boolean.toString( updateable ) );
|
||||
|
||||
if (type != null) {
|
||||
prop_mapping.addAttribute("type", type);
|
||||
}
|
||||
if ( type != null ) {
|
||||
propMapping.addAttribute( "type", type );
|
||||
}
|
||||
|
||||
return prop_mapping;
|
||||
}
|
||||
return propMapping;
|
||||
}
|
||||
|
||||
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) {
|
||||
return addProperty(parent, name, type, insertable, false, key);
|
||||
}
|
||||
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) {
|
||||
return addProperty( parent, name, type, insertable, false, key );
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -94,256 +115,319 @@ public class MetadataTools {
|
|||
}
|
||||
|
||||
private static void addOrModifyAttribute(Element parent, String name, String value) {
|
||||
Attribute attribute = parent.attribute(name);
|
||||
if (attribute == null) {
|
||||
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));
|
||||
final Attribute attribute = parent.attribute( name );
|
||||
if ( attribute == null ) {
|
||||
parent.addAttribute( name, value );
|
||||
}
|
||||
if (precision != null) {
|
||||
column_mapping.addAttribute("precision", Integer.toString(precision));
|
||||
else {
|
||||
attribute.setValue( value );
|
||||
}
|
||||
if (!StringTools.isEmpty(sqlType)) {
|
||||
column_mapping.addAttribute("sql-type", sqlType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringTools.isEmpty(customRead)) {
|
||||
column_mapping.addAttribute("read", customRead);
|
||||
}
|
||||
if (!StringTools.isEmpty(customWrite)) {
|
||||
column_mapping.addAttribute("write", customWrite);
|
||||
}
|
||||
/**
|
||||
* Column name shall be wrapped with '`' signs if quotation required.
|
||||
*/
|
||||
public static Element addOrModifyColumn(Element parent, String name) {
|
||||
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,
|
||||
String discriminatorValue, Boolean isAbstract) {
|
||||
Element hibernate_mapping = document.addElement("hibernate-mapping");
|
||||
hibernate_mapping.addAttribute("auto-import", "false");
|
||||
if ( !StringTools.isEmpty( name ) ) {
|
||||
addOrModifyAttribute( columnMapping, "name", name );
|
||||
}
|
||||
|
||||
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) {
|
||||
class_mapping.addAttribute("discriminator-value", discriminatorValue);
|
||||
}
|
||||
public static Element addColumn(
|
||||
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())) {
|
||||
class_mapping.addAttribute("table", auditTableData.getAuditTableName());
|
||||
}
|
||||
columnMapping.addAttribute( "name", quoted ? "`" + name + "`" : name );
|
||||
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())) {
|
||||
class_mapping.addAttribute("schema", auditTableData.getSchema());
|
||||
}
|
||||
if ( !StringTools.isEmpty( customRead ) ) {
|
||||
columnMapping.addAttribute( "read", customRead );
|
||||
}
|
||||
if ( !StringTools.isEmpty( customWrite ) ) {
|
||||
columnMapping.addAttribute( "write", customWrite );
|
||||
}
|
||||
|
||||
if (!StringTools.isEmpty(auditTableData.getCatalog())) {
|
||||
class_mapping.addAttribute("catalog", auditTableData.getCatalog());
|
||||
}
|
||||
return columnMapping;
|
||||
}
|
||||
|
||||
if (isAbstract != null) {
|
||||
class_mapping.addAttribute("abstract", isAbstract.toString());
|
||||
}
|
||||
private static Element createEntityCommon(
|
||||
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,
|
||||
Boolean isAbstract) {
|
||||
return createEntityCommon(document, "class", auditTableData, discriminatorValue, isAbstract);
|
||||
}
|
||||
if ( auditTableData.getAuditEntityName() != null ) {
|
||||
classMapping.addAttribute( "entity-name", auditTableData.getAuditEntityName() );
|
||||
}
|
||||
|
||||
public static Element createSubclassEntity(Document document, String subclassType, AuditTableData auditTableData,
|
||||
String extendsEntityName, String discriminatorValue, Boolean isAbstract) {
|
||||
Element class_mapping = createEntityCommon(document, subclassType, auditTableData, discriminatorValue, isAbstract);
|
||||
if ( discriminatorValue != null ) {
|
||||
classMapping.addAttribute( "discriminator-value", discriminatorValue );
|
||||
}
|
||||
|
||||
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,
|
||||
String schema, String catalog) {
|
||||
Element join_mapping = parent.addElement("join");
|
||||
if ( !StringTools.isEmpty( auditTableData.getCatalog() ) ) {
|
||||
classMapping.addAttribute( "catalog", auditTableData.getCatalog() );
|
||||
}
|
||||
|
||||
join_mapping.addAttribute("table", tableName);
|
||||
if ( isAbstract != null ) {
|
||||
classMapping.addAttribute( "abstract", isAbstract.toString() );
|
||||
}
|
||||
|
||||
if (!StringTools.isEmpty(schema)) {
|
||||
join_mapping.addAttribute("schema", schema);
|
||||
}
|
||||
return classMapping;
|
||||
}
|
||||
|
||||
if (!StringTools.isEmpty(catalog)) {
|
||||
join_mapping.addAttribute("catalog", catalog);
|
||||
}
|
||||
public static Element createEntity(
|
||||
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) {
|
||||
while ( selectables.hasNext() ) {
|
||||
classMapping.addAttribute( "extends", extendsEntityName );
|
||||
|
||||
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();
|
||||
if ( selectable.isFormula() ) {
|
||||
throw new FormulaNotSupportedException();
|
||||
}
|
||||
addColumn( any_mapping, (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> {
|
||||
addColumn( anyMapping, (Column) selectable );
|
||||
}
|
||||
}
|
||||
|
||||
public static ColumnNameIterator getColumnNameIterator(final Iterator<Selectable> selectableIterator) {
|
||||
return new ColumnNameIterator() {
|
||||
public boolean hasNext() {
|
||||
/**
|
||||
* 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 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();
|
||||
}
|
||||
|
||||
public String next() {
|
||||
public String next() {
|
||||
final Selectable next = selectableIterator.next();
|
||||
if ( next.isFormula() ) {
|
||||
throw new FormulaNotSupportedException();
|
||||
}
|
||||
return ( (Column) next ).getName();
|
||||
return ((Column) next).getName();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
public void remove() {
|
||||
selectableIterator.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static ColumnNameIterator getColumnNameIterator(final JoinColumn[] joinColumns) {
|
||||
return new ColumnNameIterator() {
|
||||
int counter = 0;
|
||||
public boolean hasNext() { return counter < joinColumns.length; }
|
||||
public String next() { return joinColumns[counter++].name(); }
|
||||
public void remove() { throw new UnsupportedOperationException(); }
|
||||
};
|
||||
}
|
||||
public static ColumnNameIterator getColumnNameIterator(final JoinColumn[] joinColumns) {
|
||||
return new ColumnNameIterator() {
|
||||
int counter = 0;
|
||||
|
||||
public boolean hasNext() {
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.
|
||||
* 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)
|
||||
*/
|
||||
public final class QueryGeneratorBuilder {
|
||||
private final GlobalConfiguration globalCfg;
|
||||
private final AuditEntitiesConfiguration verEntCfg;
|
||||
private final AuditStrategy auditStrategy;
|
||||
private final MiddleIdData referencingIdData;
|
||||
private final String auditMiddleEntityName;
|
||||
private final List<MiddleIdData> idDatas;
|
||||
private final GlobalConfiguration globalCfg;
|
||||
private final AuditEntitiesConfiguration verEntCfg;
|
||||
private final AuditStrategy auditStrategy;
|
||||
private final MiddleIdData referencingIdData;
|
||||
private final String auditMiddleEntityName;
|
||||
private final List<MiddleIdData> idDatas;
|
||||
private final boolean revisionTypeInId;
|
||||
|
||||
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy, MiddleIdData referencingIdData, String auditMiddleEntityName,
|
||||
boolean revisionTypeInId) {
|
||||
this.globalCfg = globalCfg;
|
||||
this.verEntCfg = verEntCfg;
|
||||
this.auditStrategy = auditStrategy;
|
||||
this.referencingIdData = referencingIdData;
|
||||
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||
QueryGeneratorBuilder(
|
||||
GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
MiddleIdData referencingIdData,
|
||||
String auditMiddleEntityName,
|
||||
boolean revisionTypeInId) {
|
||||
this.globalCfg = globalCfg;
|
||||
this.verEntCfg = verEntCfg;
|
||||
this.auditStrategy = auditStrategy;
|
||||
this.referencingIdData = referencingIdData;
|
||||
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||
this.revisionTypeInId = revisionTypeInId;
|
||||
|
||||
idDatas = new ArrayList<MiddleIdData>();
|
||||
}
|
||||
idDatas = new ArrayList<MiddleIdData>();
|
||||
}
|
||||
|
||||
void addRelation(MiddleIdData idData) {
|
||||
idDatas.add(idData);
|
||||
}
|
||||
void addRelation(MiddleIdData idData) {
|
||||
idDatas.add( idData );
|
||||
}
|
||||
|
||||
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
||||
if (idDatas.size() == 0) {
|
||||
return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
revisionTypeInId, componentDatas);
|
||||
} else if (idDatas.size() == 1) {
|
||||
if (idDatas.get(0).isAudited()) {
|
||||
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get(0), revisionTypeInId, componentDatas);
|
||||
} else {
|
||||
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.");
|
||||
}
|
||||
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
||||
if ( idDatas.size() == 0 ) {
|
||||
return new OneEntityQueryGenerator(
|
||||
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
revisionTypeInId, componentDatas
|
||||
);
|
||||
}
|
||||
else if ( idDatas.size() == 1 ) {
|
||||
if ( idDatas.get( 0 ).isAudited() ) {
|
||||
return new TwoEntityQueryGenerator(
|
||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get( 0 ), revisionTypeInId, componentDatas
|
||||
);
|
||||
}
|
||||
else {
|
||||
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,
|
||||
idDatas.get(0), idDatas.get(1), revisionTypeInId, componentDatas);
|
||||
} else {
|
||||
throw new IllegalStateException("Illegal number of related entities.");
|
||||
}
|
||||
}
|
||||
return new ThreeEntityQueryGenerator(
|
||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get( 0 ), idDatas.get( 1 ), revisionTypeInId, componentDatas
|
||||
);
|
||||
}
|
||||
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
|
||||
* generated by the built query generator.
|
||||
*/
|
||||
int getCurrentIndex() {
|
||||
return idDatas.size();
|
||||
}
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
int getCurrentIndex() {
|
||||
return idDatas.size();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata;
|
||||
|
||||
import org.dom4j.Element;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -41,121 +42,166 @@ import org.hibernate.mapping.Value;
|
|||
|
||||
/**
|
||||
* Generates metadata for to-one relations (reference-valued properties).
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public final class ToOneRelationMetadataGenerator {
|
||||
private final AuditMetadataGenerator mainGenerator;
|
||||
private final AuditMetadataGenerator mainGenerator;
|
||||
|
||||
ToOneRelationMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
||||
mainGenerator = auditMetadataGenerator;
|
||||
}
|
||||
ToOneRelationMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
|
||||
mainGenerator = auditMetadataGenerator;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
void addToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value,
|
||||
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
|
||||
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
||||
@SuppressWarnings({"unchecked"})
|
||||
void addToOne(
|
||||
Element parent,
|
||||
PropertyAuditingData propertyAuditingData,
|
||||
Value value,
|
||||
CompositeMapperBuilder mapper,
|
||||
String entityName,
|
||||
boolean insertable) {
|
||||
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
||||
|
||||
IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(entityName, referencedEntityName,
|
||||
propertyAuditingData, true);
|
||||
final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
|
||||
entityName,
|
||||
referencedEntityName,
|
||||
propertyAuditingData,
|
||||
true
|
||||
);
|
||||
|
||||
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(propertyAuditingData.getName());
|
||||
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( propertyAuditingData.getName() );
|
||||
|
||||
// Generating the id mapper for the relation
|
||||
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
||||
// Generating the id mapper for the relation
|
||||
final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
|
||||
|
||||
// Storing information about this relation
|
||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(
|
||||
propertyAuditingData.getName(), referencedEntityName, relMapper, insertable);
|
||||
// Storing information about this relation
|
||||
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
|
||||
propertyAuditingData.getName(),
|
||||
referencedEntityName,
|
||||
relMapper,
|
||||
insertable
|
||||
);
|
||||
|
||||
// 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.
|
||||
// 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
|
||||
// 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
|
||||
// proper data.
|
||||
boolean nonInsertableFake;
|
||||
if (!insertable && propertyAuditingData.isForceInsertable()) {
|
||||
nonInsertableFake = true;
|
||||
insertable = true;
|
||||
} else {
|
||||
nonInsertableFake = false;
|
||||
}
|
||||
// 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.
|
||||
// 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
|
||||
// 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
|
||||
// proper data.
|
||||
boolean nonInsertableFake;
|
||||
if ( !insertable && propertyAuditingData.isForceInsertable() ) {
|
||||
nonInsertableFake = true;
|
||||
insertable = true;
|
||||
}
|
||||
else {
|
||||
nonInsertableFake = false;
|
||||
}
|
||||
|
||||
// Adding an element to the mapping corresponding to the references entity id's
|
||||
Element properties = (Element) idMapping.getXmlRelationMapping().clone();
|
||||
properties.addAttribute("name", propertyAuditingData.getName());
|
||||
// Adding an element to the mapping corresponding to the references entity id's
|
||||
final Element properties = (Element) idMapping.getXmlRelationMapping().clone();
|
||||
properties.addAttribute( "name", propertyAuditingData.getName() );
|
||||
|
||||
MetadataTools.prefixNamesInPropertyElement(properties, lastPropertyPrefix,
|
||||
MetadataTools.getColumnNameIterator(value.getColumnIterator()), false, insertable);
|
||||
MetadataTools.prefixNamesInPropertyElement(
|
||||
properties,
|
||||
lastPropertyPrefix,
|
||||
MetadataTools.getColumnNameIterator( value.getColumnIterator() ),
|
||||
false,
|
||||
insertable
|
||||
);
|
||||
|
||||
// Extracting related id properties from properties tag
|
||||
for (Object o : properties.content()) {
|
||||
Element element = (Element) o;
|
||||
element.setParent(null);
|
||||
parent.add(element);
|
||||
for ( Object o : properties.content() ) {
|
||||
final Element element = (Element) o;
|
||||
element.setParent( null );
|
||||
parent.add( element );
|
||||
}
|
||||
|
||||
// Adding mapper for the id
|
||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName, nonInsertableFake));
|
||||
}
|
||||
final PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(
|
||||
propertyData,
|
||||
new ToOneIdMapper( relMapper, propertyData, referencedEntityName, nonInsertableFake )
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
void addOneToOneNotOwning(PropertyAuditingData propertyAuditingData, Value value,
|
||||
CompositeMapperBuilder mapper, String entityName) {
|
||||
OneToOne propertyValue = (OneToOne) value;
|
||||
@SuppressWarnings({"unchecked"})
|
||||
void addOneToOneNotOwning(
|
||||
PropertyAuditingData propertyAuditingData,
|
||||
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);
|
||||
if (configuration == null) {
|
||||
throw new MappingException("An audited relation to a non-audited entity " + entityName + "!");
|
||||
}
|
||||
final IdMappingData ownedIdMapping = configuration.getIdMappingData();
|
||||
|
||||
IdMappingData ownedIdMapping = configuration.getIdMappingData();
|
||||
if ( ownedIdMapping == null ) {
|
||||
throw new MappingException( "An audited relation to a non-audited entity " + entityName + "!" );
|
||||
}
|
||||
|
||||
if (ownedIdMapping == null) {
|
||||
throw new MappingException("An audited relation to a non-audited entity " + entityName + "!");
|
||||
}
|
||||
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( owningReferencePropertyName );
|
||||
final String referencedEntityName = propertyValue.getReferencedEntityName();
|
||||
|
||||
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(owningReferencePropertyName);
|
||||
String referencedEntityName = propertyValue.getReferencedEntityName();
|
||||
// Generating the id mapper for the relation
|
||||
final IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
|
||||
|
||||
// Generating the id mapper for the relation
|
||||
IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
||||
// Storing information about this relation
|
||||
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneNotOwningRelation(
|
||||
propertyAuditingData.getName(),
|
||||
owningReferencePropertyName,
|
||||
referencedEntityName,
|
||||
ownedIdMapper
|
||||
);
|
||||
|
||||
// Storing information about this relation
|
||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneNotOwningRelation(
|
||||
propertyAuditingData.getName(), owningReferencePropertyName,
|
||||
referencedEntityName, ownedIdMapper);
|
||||
// Adding mapper for the id
|
||||
final PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(
|
||||
propertyData,
|
||||
new OneToOneNotOwningMapper( entityName, referencedEntityName, owningReferencePropertyName, propertyData )
|
||||
);
|
||||
}
|
||||
|
||||
// Adding mapper for the id
|
||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(entityName, referencedEntityName,
|
||||
owningReferencePropertyName, propertyData));
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
void addOneToOnePrimaryKeyJoinColumn(
|
||||
PropertyAuditingData propertyAuditingData,
|
||||
Value value,
|
||||
CompositeMapperBuilder mapper,
|
||||
String entityName,
|
||||
boolean insertable) {
|
||||
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
void addOneToOnePrimaryKeyJoinColumn(PropertyAuditingData propertyAuditingData, Value value,
|
||||
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
|
||||
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
||||
final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
|
||||
entityName,
|
||||
referencedEntityName,
|
||||
propertyAuditingData,
|
||||
true
|
||||
);
|
||||
|
||||
IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(entityName, referencedEntityName,
|
||||
propertyAuditingData, true);
|
||||
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( propertyAuditingData.getName() );
|
||||
|
||||
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
|
||||
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
||||
// Storing information about this relation
|
||||
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
|
||||
propertyAuditingData.getName(),
|
||||
referencedEntityName,
|
||||
relMapper,
|
||||
insertable
|
||||
);
|
||||
|
||||
// Storing information about this relation
|
||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(propertyAuditingData.getName(),
|
||||
referencedEntityName, relMapper, insertable);
|
||||
|
||||
// Adding mapper for the id
|
||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(propertyData, new OneToOnePrimaryKeyJoinColumnMapper(entityName, referencedEntityName, propertyData));
|
||||
}
|
||||
// Adding mapper for the id
|
||||
final PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(
|
||||
propertyData,
|
||||
new OneToOnePrimaryKeyJoinColumnMapper( entityName, referencedEntityName, propertyData )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
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.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Sebastian Komander
|
||||
*/
|
||||
|
@ -53,8 +55,9 @@ public final class AnnotationsMetadataReader {
|
|||
*/
|
||||
private final ClassAuditingData auditData;
|
||||
|
||||
public AnnotationsMetadataReader(GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
||||
PersistentClass pc) {
|
||||
public AnnotationsMetadataReader(
|
||||
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
||||
PersistentClass pc) {
|
||||
this.globalCfg = globalCfg;
|
||||
this.reflectionManager = reflectionManager;
|
||||
this.pc = pc;
|
||||
|
@ -63,71 +66,95 @@ public final class AnnotationsMetadataReader {
|
|||
}
|
||||
|
||||
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();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addAuditTable(XClass clazz) {
|
||||
AuditTable auditTable = clazz.getAnnotation(AuditTable.class);
|
||||
if (auditTable != null) {
|
||||
auditData.setAuditTable(auditTable);
|
||||
} else {
|
||||
auditData.setAuditTable(getDefaultAuditTable());
|
||||
final AuditTable auditTable = clazz.getAnnotation( AuditTable.class );
|
||||
if ( auditTable != null ) {
|
||||
auditData.setAuditTable( auditTable );
|
||||
}
|
||||
else {
|
||||
auditData.setAuditTable( getDefaultAuditTable() );
|
||||
}
|
||||
}
|
||||
|
||||
private void addAuditSecondaryTables(XClass clazz) {
|
||||
// Getting information on secondary tables
|
||||
SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation(SecondaryAuditTable.class);
|
||||
if (secondaryVersionsTable1 != null) {
|
||||
auditData.getSecondaryTableDictionary().put(secondaryVersionsTable1.secondaryTableName(),
|
||||
secondaryVersionsTable1.secondaryAuditTableName());
|
||||
final SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation( SecondaryAuditTable.class );
|
||||
if ( secondaryVersionsTable1 != null ) {
|
||||
auditData.getSecondaryTableDictionary().put(
|
||||
secondaryVersionsTable1.secondaryTableName(),
|
||||
secondaryVersionsTable1.secondaryAuditTableName()
|
||||
);
|
||||
}
|
||||
|
||||
SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation(SecondaryAuditTables.class);
|
||||
if (secondaryAuditTables != null) {
|
||||
for (SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value()) {
|
||||
auditData.getSecondaryTableDictionary().put(secondaryAuditTable2.secondaryTableName(),
|
||||
secondaryAuditTable2.secondaryAuditTableName());
|
||||
final SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation( SecondaryAuditTables.class );
|
||||
if ( secondaryAuditTables != null ) {
|
||||
for ( SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value() ) {
|
||||
auditData.getSecondaryTableDictionary().put(
|
||||
secondaryAuditTable2.secondaryTableName(),
|
||||
secondaryAuditTable2.secondaryAuditTableName()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ClassAuditingData getAuditData() {
|
||||
if (pc.getClassName() == null) {
|
||||
if ( pc.getClassName() == null ) {
|
||||
return auditData;
|
||||
}
|
||||
|
||||
try {
|
||||
XClass xclass = reflectionManager.classForName(pc.getClassName(), this.getClass());
|
||||
final XClass xclass = reflectionManager.classForName( pc.getClassName(), this.getClass() );
|
||||
|
||||
ModificationStore defaultStore = getDefaultAudited(xclass);
|
||||
if (defaultStore != null) {
|
||||
auditData.setDefaultAudited(true);
|
||||
final ModificationStore defaultStore = getDefaultAudited( xclass );
|
||||
if ( defaultStore != null ) {
|
||||
auditData.setDefaultAudited( true );
|
||||
}
|
||||
|
||||
new AuditedPropertiesReader(defaultStore, new PersistentClassPropertiesSource(xclass), auditData,
|
||||
globalCfg, reflectionManager, "").read();
|
||||
new AuditedPropertiesReader(
|
||||
defaultStore,
|
||||
new PersistentClassPropertiesSource( xclass ),
|
||||
auditData,
|
||||
globalCfg,
|
||||
reflectionManager,
|
||||
""
|
||||
).read();
|
||||
|
||||
addAuditTable(xclass);
|
||||
addAuditSecondaryTables(xclass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new MappingException(e);
|
||||
addAuditTable( xclass );
|
||||
addAuditSecondaryTables( xclass );
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new MappingException( e );
|
||||
}
|
||||
|
||||
return auditData;
|
||||
}
|
||||
|
||||
private AuditTable defaultAuditTable = new AuditTable() {
|
||||
public String value() { return ""; }
|
||||
public String schema() { return ""; }
|
||||
public String catalog() { return ""; }
|
||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
||||
public String value() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String catalog() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return this.getClass();
|
||||
}
|
||||
};
|
||||
|
||||
private AuditTable getDefaultAuditTable() {
|
||||
|
@ -137,11 +164,21 @@ public final class AnnotationsMetadataReader {
|
|||
private class PersistentClassPropertiesSource implements PersistentPropertiesSource {
|
||||
private final XClass xclass;
|
||||
|
||||
private PersistentClassPropertiesSource(XClass xclass) { this.xclass = xclass; }
|
||||
private PersistentClassPropertiesSource(XClass xclass) {
|
||||
this.xclass = xclass;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public Iterator<Property> getPropertyIterator() { return pc.getPropertyIterator(); }
|
||||
public Property getProperty(String propertyName) { return pc.getProperty(propertyName); }
|
||||
public XClass getXClass() { return xclass; }
|
||||
public Iterator<Property> getPropertyIterator() {
|
||||
return pc.getPropertyIterator();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Implementations hold other audited properties.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Hern&aacut;n Chanfreau
|
||||
*/
|
||||
public interface AuditedPropertiesHolder {
|
||||
/**
|
||||
* Add an audited property.
|
||||
*
|
||||
* @param propertyName Name of the audited property.
|
||||
* @param auditingData Data for the audited property.
|
||||
*/
|
||||
|
@ -16,19 +41,20 @@ public interface AuditedPropertiesHolder {
|
|||
|
||||
/**
|
||||
* @param propertyName Name of a property.
|
||||
*
|
||||
* @return Auditing data for the property.
|
||||
*/
|
||||
PropertyAuditingData getPropertyAuditingData(String propertyName);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the holder contains any audited property
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the holder contains the given audited property
|
||||
*/
|
||||
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;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKey;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -7,10 +34,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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.annotations.common.reflection.ReflectionManager;
|
||||
|
@ -65,12 +88,13 @@ public class AuditedPropertiesReader {
|
|||
private final Set<XClass> overriddenAuditedClasses;
|
||||
private final Set<XClass> overriddenNotAuditedClasses;
|
||||
|
||||
public AuditedPropertiesReader(ModificationStore defaultStore,
|
||||
PersistentPropertiesSource persistentPropertiesSource,
|
||||
AuditedPropertiesHolder auditedPropertiesHolder,
|
||||
GlobalConfiguration globalCfg,
|
||||
ReflectionManager reflectionManager,
|
||||
String propertyNamePrefix) {
|
||||
public AuditedPropertiesReader(
|
||||
ModificationStore defaultStore,
|
||||
PersistentPropertiesSource persistentPropertiesSource,
|
||||
AuditedPropertiesHolder auditedPropertiesHolder,
|
||||
GlobalConfiguration globalCfg,
|
||||
ReflectionManager reflectionManager,
|
||||
String propertyNamePrefix) {
|
||||
this.defaultStore = defaultStore;
|
||||
this.persistentPropertiesSource = persistentPropertiesSource;
|
||||
this.auditedPropertiesHolder = auditedPropertiesHolder;
|
||||
|
@ -93,245 +117,300 @@ public class AuditedPropertiesReader {
|
|||
// First reading the access types for the persistent properties.
|
||||
readPersistentPropertiesAccess();
|
||||
|
||||
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
|
||||
// of currently mapped entity or itself.
|
||||
XClass clazz = persistentPropertiesSource.getXClass();
|
||||
readAuditOverrides(clazz);
|
||||
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
|
||||
// of currently mapped entity or itself.
|
||||
final XClass clazz = persistentPropertiesSource.getXClass();
|
||||
readAuditOverrides( clazz );
|
||||
|
||||
// Adding all properties from the given class.
|
||||
addPropertiesFromClass(clazz);
|
||||
// Adding all properties from the given class.
|
||||
addPropertiesFromClass( clazz );
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
|
||||
* using {@link AuditOverride} annotation.
|
||||
* @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. */
|
||||
Audited allClassAudited = clazz.getAnnotation(Audited.class);
|
||||
if (allClassAudited != null && allClassAudited.auditParents().length > 0) {
|
||||
for (Class c : allClassAudited.auditParents()) {
|
||||
XClass parentClass = reflectionManager.toXClass(c);
|
||||
checkSuperclass(clazz, parentClass);
|
||||
if (!overriddenNotAuditedClasses.contains(parentClass)) {
|
||||
// If the class has not been marked as not audited by the subclass.
|
||||
overriddenAuditedClasses.add(parentClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
|
||||
* using {@link AuditOverride} annotation.
|
||||
*
|
||||
* @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. */
|
||||
final Audited allClassAudited = clazz.getAnnotation( Audited.class );
|
||||
if ( allClassAudited != null && allClassAudited.auditParents().length > 0 ) {
|
||||
for ( Class c : allClassAudited.auditParents() ) {
|
||||
final XClass parentClass = reflectionManager.toXClass( c );
|
||||
checkSuperclass( clazz, parentClass );
|
||||
if ( !overriddenNotAuditedClasses.contains( 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. */
|
||||
List<AuditOverride> auditOverrides = computeAuditOverrides(clazz);
|
||||
for (AuditOverride auditOverride : auditOverrides) {
|
||||
if (auditOverride.forClass() != void.class) {
|
||||
XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass());
|
||||
checkSuperclass(clazz, overrideClass);
|
||||
String propertyName = auditOverride.name();
|
||||
if (!StringTools.isEmpty(propertyName)) {
|
||||
// Override @Audited annotation on property level.
|
||||
XProperty property = getProperty(overrideClass, propertyName);
|
||||
if (auditOverride.isAudited()) {
|
||||
if (!overriddenNotAuditedProperties.contains(property)) {
|
||||
// If the property has not been marked as not audited by the subclass.
|
||||
overriddenAuditedProperties.add(property);
|
||||
}
|
||||
} else {
|
||||
if (!overriddenAuditedProperties.contains(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()) {
|
||||
if (!overriddenNotAuditedClasses.contains(overrideClass)) {
|
||||
// If the class has not been marked as not audited by the subclass.
|
||||
overriddenAuditedClasses.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 List<AuditOverride> auditOverrides = computeAuditOverrides( clazz );
|
||||
for ( AuditOverride auditOverride : auditOverrides ) {
|
||||
if ( auditOverride.forClass() != void.class ) {
|
||||
final XClass overrideClass = reflectionManager.toXClass( auditOverride.forClass() );
|
||||
checkSuperclass( clazz, overrideClass );
|
||||
final String propertyName = auditOverride.name();
|
||||
if ( !StringTools.isEmpty( propertyName ) ) {
|
||||
// Override @Audited annotation on property level.
|
||||
final XProperty property = getProperty( overrideClass, propertyName );
|
||||
if ( auditOverride.isAudited() ) {
|
||||
if ( !overriddenNotAuditedProperties.contains( property ) ) {
|
||||
// If the property has not been marked as not audited by the subclass.
|
||||
overriddenAuditedProperties.add( property );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( !overriddenAuditedProperties.contains( 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() ) {
|
||||
if ( !overriddenNotAuditedClasses.contains( overrideClass ) ) {
|
||||
// If the class has not been marked as not audited by the subclass.
|
||||
overriddenAuditedClasses.add( overrideClass );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( !overriddenAuditedClasses.contains( overrideClass ) ) {
|
||||
// If the class has not been marked as audited by the subclass.
|
||||
overriddenNotAuditedClasses.add( overrideClass );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final XClass superclass = clazz.getSuperclass();
|
||||
if ( !clazz.isInterface() && !Object.class.getName().equals( superclass.getName() ) ) {
|
||||
readAuditOverrides( superclass );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz Source class.
|
||||
* @return List of @AuditOverride annotations applied at class level.
|
||||
*/
|
||||
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
|
||||
AuditOverrides auditOverrides = clazz.getAnnotation(AuditOverrides.class);
|
||||
AuditOverride auditOverride = clazz.getAnnotation(AuditOverride.class);
|
||||
if (auditOverrides == null && auditOverride != null) {
|
||||
return Arrays.asList(auditOverride);
|
||||
} else if (auditOverrides != null && auditOverride == null) {
|
||||
return Arrays.asList(auditOverrides.value());
|
||||
} else if (auditOverrides != null && auditOverride != null) {
|
||||
throw new MappingException("@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
|
||||
"Please revise Envers annotations applied to class " + clazz.getName() + ".");
|
||||
}
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
/**
|
||||
* @param clazz Source class.
|
||||
*
|
||||
* @return List of @AuditOverride annotations applied at class level.
|
||||
*/
|
||||
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
|
||||
final AuditOverrides auditOverrides = clazz.getAnnotation( AuditOverrides.class );
|
||||
final AuditOverride auditOverride = clazz.getAnnotation( AuditOverride.class );
|
||||
if ( auditOverrides == null && auditOverride != null ) {
|
||||
return Arrays.asList( auditOverride );
|
||||
}
|
||||
else if ( auditOverrides != null && auditOverride == null ) {
|
||||
return Arrays.asList( auditOverrides.value() );
|
||||
}
|
||||
else if ( auditOverrides != null && auditOverride != null ) {
|
||||
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.
|
||||
* @param child Subclass.
|
||||
* @param parent Superclass.
|
||||
*/
|
||||
private void checkSuperclass(XClass child, XClass parent) {
|
||||
if (!parent.isAssignableFrom(child)) {
|
||||
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
|
||||
"Please revise Envers annotations applied to " + child.getName() + " type.");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
|
||||
*
|
||||
* @param child Subclass.
|
||||
* @param parent Superclass.
|
||||
*/
|
||||
private void checkSuperclass(XClass child, XClass parent) {
|
||||
if ( !parent.isAssignableFrom( child ) ) {
|
||||
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.
|
||||
* @param clazz Class.
|
||||
* @param propertyName Property name.
|
||||
* @return Property object.
|
||||
*/
|
||||
private XProperty getProperty(XClass clazz, String propertyName) {
|
||||
XProperty property = ReflectionTools.getProperty(clazz, propertyName);
|
||||
if (property == null) {
|
||||
throw new MappingException("Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
|
||||
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + ".");
|
||||
}
|
||||
return property;
|
||||
}
|
||||
/**
|
||||
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
|
||||
*
|
||||
* @param clazz Class.
|
||||
* @param propertyName Property name.
|
||||
*
|
||||
* @return Property object.
|
||||
*/
|
||||
private XProperty getProperty(XClass clazz, String propertyName) {
|
||||
final XProperty property = ReflectionTools.getProperty( clazz, propertyName );
|
||||
if ( property == null ) {
|
||||
throw new MappingException(
|
||||
"Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
|
||||
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + "."
|
||||
);
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
private void readPersistentPropertiesAccess() {
|
||||
Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
|
||||
while (propertyIter.hasNext()) {
|
||||
Property property = propertyIter.next();
|
||||
addPersistentProperty(property);
|
||||
if ("embedded".equals(property.getPropertyAccessorName()) && property.getName().equals(property.getNodeName())) {
|
||||
final Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
|
||||
while ( propertyIter.hasNext() ) {
|
||||
final Property property = propertyIter.next();
|
||||
addPersistentProperty( property );
|
||||
if ( "embedded".equals( property.getPropertyAccessorName() ) && property.getName()
|
||||
.equals( property.getNodeName() ) ) {
|
||||
// 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.
|
||||
createPropertiesGroupMapping(property);
|
||||
createPropertiesGroupMapping( property );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPersistentProperty(Property property) {
|
||||
if ("field".equals(property.getPropertyAccessorName())) {
|
||||
fieldAccessedPersistentProperties.add(property.getName());
|
||||
} else {
|
||||
propertyAccessedPersistentProperties.add(property.getName());
|
||||
}
|
||||
}
|
||||
private void addPersistentProperty(Property property) {
|
||||
if ( "field".equals( property.getPropertyAccessorName() ) ) {
|
||||
fieldAccessedPersistentProperties.add( property.getName() );
|
||||
}
|
||||
else {
|
||||
propertyAccessedPersistentProperties.add( property.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
private void createPropertiesGroupMapping(Property property) {
|
||||
Component component = (Component) property.getValue();
|
||||
Iterator<Property> componentProperties = component.getPropertyIterator();
|
||||
while (componentProperties.hasNext()) {
|
||||
Property componentProperty = componentProperties.next();
|
||||
propertiesGroupMapping.put(componentProperty.getName(), component.getNodeName());
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private void createPropertiesGroupMapping(Property property) {
|
||||
final Component component = (Component) property.getValue();
|
||||
final Iterator<Property> componentProperties = component.getPropertyIterator();
|
||||
while ( componentProperties.hasNext() ) {
|
||||
final Property componentProperty = componentProperties.next();
|
||||
propertiesGroupMapping.put( componentProperty.getName(), component.getNodeName() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
|
||||
* {@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);
|
||||
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
|
||||
// forced by any of its child entities configuration (@AuditedOverride.forClass).
|
||||
if (allClassAudited == null && overriddenAuditedClasses.contains(clazz)) {
|
||||
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
|
||||
// currently mapped entity.
|
||||
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation(Audited.class);
|
||||
if (allClassAudited == null) {
|
||||
// If parent class declares @Audited on the field/property level.
|
||||
allClassAudited = DEFAULT_AUDITED;
|
||||
}
|
||||
} else if (allClassAudited != null && overriddenNotAuditedClasses.contains(clazz)) {
|
||||
return null;
|
||||
}
|
||||
return allClassAudited;
|
||||
}
|
||||
/**
|
||||
* @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.
|
||||
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
|
||||
* {@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 );
|
||||
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
|
||||
// forced by any of its child entities configuration (@AuditedOverride.forClass).
|
||||
if ( allClassAudited == null && overriddenAuditedClasses.contains( clazz ) ) {
|
||||
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
|
||||
// currently mapped entity.
|
||||
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation( Audited.class );
|
||||
if ( allClassAudited == null ) {
|
||||
// If parent class declares @Audited on the field/property level.
|
||||
allClassAudited = DEFAULT_AUDITED;
|
||||
}
|
||||
}
|
||||
else if ( allClassAudited != null && overriddenNotAuditedClasses.contains( clazz ) ) {
|
||||
return null;
|
||||
}
|
||||
return allClassAudited;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively adds all audited properties of entity class and its superclasses.
|
||||
* @param clazz Currently processed class.
|
||||
*/
|
||||
private void addPropertiesFromClass(XClass clazz) {
|
||||
Audited allClassAudited = computeAuditConfiguration(clazz);
|
||||
/**
|
||||
* Recursively adds all audited properties of entity class and its superclasses.
|
||||
*
|
||||
* @param clazz Currently processed class.
|
||||
*/
|
||||
private void addPropertiesFromClass(XClass clazz) {
|
||||
final Audited allClassAudited = computeAuditConfiguration( clazz );
|
||||
|
||||
//look in the class
|
||||
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited);
|
||||
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited);
|
||||
|
||||
if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) {
|
||||
XClass superclazz = clazz.getSuperclass();
|
||||
if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) {
|
||||
addPropertiesFromClass(superclazz);
|
||||
addFromProperties(
|
||||
clazz.getDeclaredProperties( "field" ),
|
||||
"field",
|
||||
fieldAccessedPersistentProperties,
|
||||
allClassAudited
|
||||
);
|
||||
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) {
|
||||
for (XProperty property : properties) {
|
||||
private void addFromProperties(
|
||||
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,
|
||||
// it's not audited as well.
|
||||
// If the property was already defined by the subclass, is ignored by superclasses
|
||||
if ((persistentProperties.contains(property.getName()) && (!auditedPropertiesHolder
|
||||
.contains(property.getName())))) {
|
||||
Value propertyValue = persistentPropertiesSource.getProperty(property.getName()).getValue();
|
||||
if (propertyValue instanceof Component) {
|
||||
this.addFromComponentProperty(property, accessType, (Component)propertyValue, allClassAudited);
|
||||
} else {
|
||||
this.addFromNotComponentProperty(property, accessType, allClassAudited);
|
||||
if ( persistentProperties.contains( property.getName() )
|
||||
&& !auditedPropertiesHolder.contains( property.getName() ) ) {
|
||||
final Value propertyValue = persistentPropertiesSource.getProperty( property.getName() ).getValue();
|
||||
if ( propertyValue instanceof Component ) {
|
||||
this.addFromComponentProperty( property, accessType, (Component) propertyValue, 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.
|
||||
final String embeddedName = propertiesGroupMapping.get(property.getName());
|
||||
if (!auditedPropertiesHolder.contains(embeddedName)) {
|
||||
final String embeddedName = propertiesGroupMapping.get( property.getName() );
|
||||
if ( !auditedPropertiesHolder.contains( embeddedName ) ) {
|
||||
// Manage properties mapped within <properties> tag.
|
||||
Value propertyValue = persistentPropertiesSource.getProperty(embeddedName).getValue();
|
||||
this.addFromPropertiesGroup(embeddedName, property, accessType, (Component)propertyValue, allClassAudited);
|
||||
final Value propertyValue = persistentPropertiesSource.getProperty( embeddedName ).getValue();
|
||||
this.addFromPropertiesGroup(
|
||||
embeddedName,
|
||||
property,
|
||||
accessType,
|
||||
(Component) propertyValue,
|
||||
allClassAudited
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addFromPropertiesGroup(String embeddedName, XProperty property, String accessType, Component propertyValue,
|
||||
Audited allClassAudited) {
|
||||
ComponentAuditingData componentData = new ComponentAuditingData();
|
||||
boolean isAudited = fillPropertyData(property, componentData, accessType, allClassAudited);
|
||||
if (isAudited) {
|
||||
private void addFromPropertiesGroup(
|
||||
String embeddedName,
|
||||
XProperty property,
|
||||
String accessType,
|
||||
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.
|
||||
componentData.setName(embeddedName);
|
||||
componentData.setName( embeddedName );
|
||||
// Marking component properties as placed directly in class (not inside another component).
|
||||
componentData.setBeanName(null);
|
||||
componentData.setBeanName( null );
|
||||
|
||||
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( reflectionManager, propertyValue );
|
||||
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
|
||||
final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
||||
reflectionManager,
|
||||
propertyValue
|
||||
);
|
||||
final AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
|
||||
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
|
||||
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName)
|
||||
propertyNamePrefix + MappingTools.createComponentPrefix( embeddedName )
|
||||
);
|
||||
audPropReader.read();
|
||||
|
||||
auditedPropertiesHolder.addPropertyAuditingData(embeddedName, componentData);
|
||||
auditedPropertiesHolder.addPropertyAuditingData( embeddedName, componentData );
|
||||
}
|
||||
}
|
||||
|
||||
private void addFromComponentProperty(XProperty property, String accessType, Component propertyValue, Audited allClassAudited) {
|
||||
ComponentAuditingData componentData = new ComponentAuditingData();
|
||||
boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
|
||||
private void addFromComponentProperty(
|
||||
XProperty property,
|
||||
String accessType,
|
||||
Component propertyValue,
|
||||
Audited allClassAudited) {
|
||||
final ComponentAuditingData componentData = new ComponentAuditingData();
|
||||
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
|
||||
|
||||
if ( propertyValue.isDynamic() ) {
|
||||
if ( isAudited ) {
|
||||
|
@ -343,12 +422,16 @@ public class AuditedPropertiesReader {
|
|||
return;
|
||||
}
|
||||
|
||||
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
||||
final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
||||
reflectionManager, propertyValue
|
||||
);
|
||||
|
||||
ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
|
||||
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
|
||||
final ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
|
||||
ModificationStore.FULL,
|
||||
componentPropertiesSource,
|
||||
componentData,
|
||||
globalCfg,
|
||||
reflectionManager,
|
||||
propertyNamePrefix + MappingTools.createComponentPrefix( property.getName() )
|
||||
);
|
||||
audPropReader.read();
|
||||
|
@ -359,85 +442,102 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
}
|
||||
|
||||
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited){
|
||||
PropertyAuditingData propertyData = new PropertyAuditingData();
|
||||
boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited);
|
||||
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited) {
|
||||
final PropertyAuditingData propertyData = new PropertyAuditingData();
|
||||
final boolean isAudited = fillPropertyData( property, propertyData, accessType, allClassAudited );
|
||||
|
||||
if (isAudited) {
|
||||
if ( isAudited ) {
|
||||
// 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.
|
||||
*
|
||||
* @param property Property to check.
|
||||
* @param propertyData Property data, on which to set this property's modification store.
|
||||
* @param accessType Access type for the property.
|
||||
*
|
||||
* @return False if this property is not audited.
|
||||
*/
|
||||
private boolean fillPropertyData(XProperty property, PropertyAuditingData propertyData,
|
||||
String accessType, Audited allClassAudited) {
|
||||
private boolean fillPropertyData(
|
||||
XProperty property,
|
||||
PropertyAuditingData propertyData,
|
||||
String accessType,
|
||||
Audited allClassAudited) {
|
||||
|
||||
// check if a property is declared as not audited to exclude it
|
||||
// useful if a class is audited but some properties should be excluded
|
||||
NotAudited unVer = property.getAnnotation(NotAudited.class);
|
||||
if ((unVer != null && !overriddenAuditedProperties.contains(property)) || overriddenNotAuditedProperties.contains(property)) {
|
||||
final NotAudited unVer = property.getAnnotation( NotAudited.class );
|
||||
if ( (unVer != null
|
||||
&& !overriddenAuditedProperties.contains( property ))
|
||||
|| overriddenNotAuditedProperties.contains( property ) ) {
|
||||
return false;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// if the optimistic locking field has to be unversioned and the current property
|
||||
// is the optimistic locking field, don't audit it
|
||||
if (globalCfg.isDoNotAuditOptimisticLockingField()) {
|
||||
Version jpaVer = property.getAnnotation(Version.class);
|
||||
if (jpaVer != null) {
|
||||
if ( globalCfg.isDoNotAuditOptimisticLockingField() ) {
|
||||
final Version jpaVer = property.getAnnotation( Version.class );
|
||||
if ( jpaVer != null ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!this.checkAudited(property, propertyData, allClassAudited)){
|
||||
|
||||
if ( !this.checkAudited( property, propertyData, allClassAudited ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String propertyName = propertyNamePrefix + property.getName();
|
||||
propertyData.setName(propertyName);
|
||||
final String propertyName = propertyNamePrefix + property.getName();
|
||||
propertyData.setName( propertyName );
|
||||
propertyData.setModifiedFlagName(
|
||||
MetadataTools.getModifiedFlagPropertyName(
|
||||
propertyName,
|
||||
globalCfg.getModifiedFlagSuffix()));
|
||||
propertyData.setBeanName(property.getName());
|
||||
propertyData.setAccessType(accessType);
|
||||
MetadataTools.getModifiedFlagPropertyName(
|
||||
propertyName,
|
||||
globalCfg.getModifiedFlagSuffix()
|
||||
)
|
||||
);
|
||||
propertyData.setBeanName( property.getName() );
|
||||
propertyData.setAccessType( accessType );
|
||||
|
||||
addPropertyJoinTables(property, propertyData);
|
||||
addPropertyAuditingOverrides(property, propertyData);
|
||||
if (!processPropertyAuditingOverrides(property, propertyData)) {
|
||||
return false; // not audited due to AuditOverride annotation
|
||||
addPropertyJoinTables( property, propertyData );
|
||||
addPropertyAuditingOverrides( property, propertyData );
|
||||
if ( !processPropertyAuditingOverrides( property, propertyData ) ) {
|
||||
// not audited due to AuditOverride annotation
|
||||
return false;
|
||||
}
|
||||
addPropertyMapKey(property, propertyData);
|
||||
setPropertyAuditMappedBy(property, propertyData);
|
||||
setPropertyRelationMappedBy(property, propertyData);
|
||||
addPropertyMapKey( property, propertyData );
|
||||
setPropertyAuditMappedBy( property, propertyData );
|
||||
setPropertyRelationMappedBy( property, propertyData );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected boolean checkAudited(XProperty property,
|
||||
protected boolean checkAudited(
|
||||
XProperty property,
|
||||
PropertyAuditingData propertyData, Audited allClassAudited) {
|
||||
// Checking if this property is explicitly audited or if all properties are.
|
||||
Audited aud = (property.isAnnotationPresent(Audited.class)) ? (property.getAnnotation(Audited.class)) : allClassAudited;
|
||||
if (aud == null && overriddenAuditedProperties.contains(property) && !overriddenNotAuditedProperties.contains(property)) {
|
||||
Audited aud = (property.isAnnotationPresent( Audited.class ))
|
||||
? 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,
|
||||
// appropriate fields shall be added to @AuditOverride annotation.
|
||||
aud = DEFAULT_AUDITED;
|
||||
}
|
||||
if (aud != null) {
|
||||
propertyData.setStore(aud.modStore());
|
||||
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
|
||||
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
|
||||
if ( aud != null ) {
|
||||
propertyData.setStore( aud.modStore() );
|
||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -447,121 +547,172 @@ public class AuditedPropertiesReader {
|
|||
globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag();
|
||||
}
|
||||
|
||||
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||
OneToMany oneToMany = property.getAnnotation(OneToMany.class);
|
||||
if (oneToMany != null && !"".equals(oneToMany.mappedBy())) {
|
||||
propertyData.setRelationMappedBy(oneToMany.mappedBy());
|
||||
}
|
||||
}
|
||||
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||
final OneToMany oneToMany = property.getAnnotation( OneToMany.class );
|
||||
if ( oneToMany != null && !"".equals( oneToMany.mappedBy() ) ) {
|
||||
propertyData.setRelationMappedBy( oneToMany.mappedBy() );
|
||||
}
|
||||
}
|
||||
|
||||
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
|
||||
if (auditMappedBy != null) {
|
||||
propertyData.setAuditMappedBy(auditMappedBy.mappedBy());
|
||||
if (!"".equals(auditMappedBy.positionMappedBy())) {
|
||||
propertyData.setPositionMappedBy(auditMappedBy.positionMappedBy());
|
||||
}
|
||||
}
|
||||
}
|
||||
final AuditMappedBy auditMappedBy = property.getAnnotation( AuditMappedBy.class );
|
||||
if ( auditMappedBy != null ) {
|
||||
propertyData.setAuditMappedBy( auditMappedBy.mappedBy() );
|
||||
if ( !"".equals( auditMappedBy.positionMappedBy() ) ) {
|
||||
propertyData.setPositionMappedBy( auditMappedBy.positionMappedBy() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
|
||||
MapKey mapKey = property.getAnnotation(MapKey.class);
|
||||
if (mapKey != null) {
|
||||
propertyData.setMapKey(mapKey.name());
|
||||
final MapKey mapKey = property.getAnnotation( MapKey.class );
|
||||
if ( mapKey != null ) {
|
||||
propertyData.setMapKey( mapKey.name() );
|
||||
}
|
||||
}
|
||||
|
||||
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
|
||||
// first set the join table based on the AuditJoinTable annotation
|
||||
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class);
|
||||
if (joinTable != null) {
|
||||
propertyData.setJoinTable(joinTable);
|
||||
} else {
|
||||
propertyData.setJoinTable(DEFAULT_AUDIT_JOIN_TABLE);
|
||||
final AuditJoinTable joinTable = property.getAnnotation( AuditJoinTable.class );
|
||||
if ( joinTable != null ) {
|
||||
propertyData.setJoinTable( joinTable );
|
||||
}
|
||||
else {
|
||||
propertyData.setJoinTable( DEFAULT_AUDIT_JOIN_TABLE );
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
/**
|
||||
* Add the {@link AuditOverride} annotations.
|
||||
*
|
||||
* @param property the property being processed
|
||||
* @param propertyData the Envers auditing data for this property
|
||||
*/
|
||||
private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
||||
AuditOverride annotationOverride = property.getAnnotation(AuditOverride.class);
|
||||
if (annotationOverride != null) {
|
||||
propertyData.addAuditingOverride(annotationOverride);
|
||||
final AuditOverride annotationOverride = property.getAnnotation( AuditOverride.class );
|
||||
if ( annotationOverride != null ) {
|
||||
propertyData.addAuditingOverride( annotationOverride );
|
||||
}
|
||||
AuditOverrides annotationOverrides = property.getAnnotation(AuditOverrides.class);
|
||||
if (annotationOverrides != null) {
|
||||
propertyData.addAuditingOverrides(annotationOverrides);
|
||||
final AuditOverrides annotationOverrides = property.getAnnotation( AuditOverrides.class );
|
||||
if ( annotationOverrides != null ) {
|
||||
propertyData.addAuditingOverrides( annotationOverrides );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the {@link AuditOverride} annotations for this property.
|
||||
*
|
||||
* @param property
|
||||
* the property for which the {@link AuditOverride}
|
||||
* annotations are being processed
|
||||
* @param propertyData
|
||||
* the Envers auditing data for this property
|
||||
* @param property the property for which the {@link AuditOverride}
|
||||
* annotations are being processed
|
||||
* @param propertyData the Envers auditing data for this property
|
||||
*
|
||||
* @return {@code false} if isAudited() of the override annotation was set to
|
||||
*/
|
||||
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
||||
// if this property is part of a component, process all override annotations
|
||||
if (this.auditedPropertiesHolder instanceof ComponentAuditingData) {
|
||||
List<AuditOverride> overrides = ((ComponentAuditingData) this.auditedPropertiesHolder).getAuditingOverrides();
|
||||
for (AuditOverride override : overrides) {
|
||||
if (property.getName().equals(override.name())) {
|
||||
if ( this.auditedPropertiesHolder instanceof ComponentAuditingData ) {
|
||||
final List<AuditOverride> overrides = ( (ComponentAuditingData) this.auditedPropertiesHolder ).getAuditingOverrides();
|
||||
for ( AuditOverride override : overrides ) {
|
||||
if ( property.getName().equals( override.name() ) ) {
|
||||
// the override applies to this property
|
||||
if (!override.isAudited()) {
|
||||
if ( !override.isAudited() ) {
|
||||
return false;
|
||||
} else {
|
||||
if (override.auditJoinTable() != null) {
|
||||
propertyData.setJoinTable(override.auditJoinTable());
|
||||
}
|
||||
else {
|
||||
if ( override.auditJoinTable() != null ) {
|
||||
propertyData.setJoinTable( override.auditJoinTable() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Audited DEFAULT_AUDITED = new Audited() {
|
||||
public ModificationStore modStore() { return ModificationStore.FULL; }
|
||||
public RelationTargetAuditMode targetAuditMode() { return RelationTargetAuditMode.AUDITED; }
|
||||
public Class[] auditParents() { return new Class[0]; }
|
||||
public boolean withModifiedFlag() { return false; }
|
||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
||||
};
|
||||
private static final Audited DEFAULT_AUDITED = new Audited() {
|
||||
@Override
|
||||
public ModificationStore modStore() {
|
||||
return ModificationStore.FULL;
|
||||
}
|
||||
|
||||
private static AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
|
||||
public String name() { return ""; }
|
||||
public String schema() { return ""; }
|
||||
public String catalog() { return ""; }
|
||||
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
|
||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
||||
@Override
|
||||
public RelationTargetAuditMode targetAuditMode() {
|
||||
return RelationTargetAuditMode.AUDITED;
|
||||
}
|
||||
|
||||
@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 Component component;
|
||||
|
||||
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
|
||||
try {
|
||||
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new MappingException(e);
|
||||
this.xclass = reflectionManager.classForName( component.getComponentClassName(), this.getClass() );
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new MappingException( e );
|
||||
}
|
||||
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public Iterator<Property> getPropertyIterator() { return component.getPropertyIterator(); }
|
||||
public Property getProperty(String propertyName) { return component.getProperty(propertyName); }
|
||||
public XClass getXClass() { return xclass; }
|
||||
public Iterator<Property> getPropertyIterator() {
|
||||
return component.getPropertyIterator();
|
||||
}
|
||||
|
||||
@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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
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 Sebastian Komander
|
||||
* @author Hern&aacut;n Chanfreau
|
||||
*/
|
||||
*/
|
||||
public class ClassAuditingData implements AuditedPropertiesHolder {
|
||||
private final Map<String, PropertyAuditingData> properties;
|
||||
private final Map<String, String> secondaryTableDictionary;
|
||||
private final Map<String, PropertyAuditingData> properties;
|
||||
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,
|
||||
|
@ -45,48 +46,52 @@ public class ClassAuditingData implements AuditedPropertiesHolder {
|
|||
*/
|
||||
private boolean defaultAudited;
|
||||
|
||||
public ClassAuditingData() {
|
||||
properties = newHashMap();
|
||||
secondaryTableDictionary = newHashMap();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return properties.isEmpty();
|
||||
}
|
||||
|
||||
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
||||
properties.put(propertyName, auditingData);
|
||||
public ClassAuditingData() {
|
||||
properties = newHashMap();
|
||||
secondaryTableDictionary = newHashMap();
|
||||
}
|
||||
|
||||
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||
return properties.get(propertyName);
|
||||
}
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return properties.isEmpty();
|
||||
}
|
||||
|
||||
public Iterable<String> getPropertyNames() {
|
||||
return properties.keySet();
|
||||
}
|
||||
@Override
|
||||
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
||||
properties.put( propertyName, auditingData );
|
||||
}
|
||||
|
||||
public Map<String, String> getSecondaryTableDictionary() {
|
||||
return secondaryTableDictionary;
|
||||
}
|
||||
@Override
|
||||
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||
return properties.get( propertyName );
|
||||
}
|
||||
|
||||
public AuditTable getAuditTable() {
|
||||
return auditTable;
|
||||
}
|
||||
public Iterable<String> getPropertyNames() {
|
||||
return properties.keySet();
|
||||
}
|
||||
|
||||
public void setAuditTable(AuditTable auditTable) {
|
||||
this.auditTable = auditTable;
|
||||
}
|
||||
public Map<String, String> getSecondaryTableDictionary() {
|
||||
return secondaryTableDictionary;
|
||||
}
|
||||
|
||||
public AuditTable getAuditTable() {
|
||||
return auditTable;
|
||||
}
|
||||
|
||||
public void setAuditTable(AuditTable auditTable) {
|
||||
this.auditTable = auditTable;
|
||||
}
|
||||
|
||||
public void setDefaultAudited(boolean defaultAudited) {
|
||||
this.defaultAudited = defaultAudited;
|
||||
}
|
||||
|
||||
public boolean isAudited() {
|
||||
return defaultAudited || properties.size() > 0;
|
||||
}
|
||||
|
||||
return defaultAudited || properties.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.envers.Audited;
|
||||
|
@ -7,34 +31,40 @@ import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
|||
|
||||
/**
|
||||
* Reads the audited properties for components.
|
||||
*
|
||||
*
|
||||
* @author Hern&aacut;n Chanfreau
|
||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||
*/
|
||||
public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
||||
|
||||
public ComponentAuditedPropertiesReader(ModificationStore defaultStore,
|
||||
public ComponentAuditedPropertiesReader(
|
||||
ModificationStore defaultStore,
|
||||
PersistentPropertiesSource persistentPropertiesSource,
|
||||
AuditedPropertiesHolder auditedPropertiesHolder,
|
||||
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
||||
String propertyNamePrefix) {
|
||||
super(defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
|
||||
globalCfg, reflectionManager, propertyNamePrefix);
|
||||
super(
|
||||
defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
|
||||
globalCfg, reflectionManager, propertyNamePrefix
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean checkAudited(XProperty property,
|
||||
PropertyAuditingData propertyData, Audited allClassAudited) {
|
||||
protected boolean checkAudited(
|
||||
XProperty property,
|
||||
PropertyAuditingData propertyData,
|
||||
Audited allClassAudited) {
|
||||
// Checking if this property is explicitly audited or if all properties are.
|
||||
Audited aud = property.getAnnotation(Audited.class);
|
||||
if (aud != null) {
|
||||
propertyData.setStore(aud.modStore());
|
||||
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
|
||||
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
|
||||
} else {
|
||||
propertyData.setStore(ModificationStore.FULL);
|
||||
}
|
||||
return true;
|
||||
final Audited aud = property.getAnnotation( Audited.class );
|
||||
if ( aud != null ) {
|
||||
propertyData.setStore( aud.modStore() );
|
||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||
}
|
||||
else {
|
||||
propertyData.setStore( ModificationStore.FULL );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,9 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -30,6 +30,7 @@ import static org.hibernate.envers.internal.tools.Tools.newHashMap;
|
|||
|
||||
/**
|
||||
* Audit mapping meta-data for component.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Hern&aacut;n Chanfreau
|
||||
*/
|
||||
|
@ -40,21 +41,25 @@ public class ComponentAuditingData extends PropertyAuditingData implements Audit
|
|||
this.properties = newHashMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return properties.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
||||
properties.put(propertyName, auditingData);
|
||||
properties.put( propertyName, auditingData );
|
||||
}
|
||||
|
||||
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||
return properties.get(propertyName);
|
||||
}
|
||||
|
||||
public boolean contains(String propertyName) {
|
||||
return properties.containsKey(propertyName);
|
||||
}
|
||||
@Override
|
||||
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||
return properties.get( propertyName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String propertyName) {
|
||||
return properties.containsKey( propertyName );
|
||||
}
|
||||
|
||||
public Set<String> getPropertyNames() {
|
||||
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;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
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.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public interface PersistentPropertiesSource {
|
||||
Iterator<Property> getPropertyIterator();
|
||||
|
||||
Property getProperty(String propertyName);
|
||||
|
||||
XClass getXClass();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,9 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -38,45 +38,46 @@ import org.hibernate.envers.internal.entities.PropertyData;
|
|||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||
*/
|
||||
public class PropertyAuditingData {
|
||||
private String name;
|
||||
private String name;
|
||||
private String beanName;
|
||||
private ModificationStore store;
|
||||
private String mapKey;
|
||||
private AuditJoinTable joinTable;
|
||||
private String accessType;
|
||||
private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>(0);
|
||||
private ModificationStore store;
|
||||
private String mapKey;
|
||||
private AuditJoinTable joinTable;
|
||||
private String accessType;
|
||||
private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>( 0 );
|
||||
private RelationTargetAuditMode relationTargetAuditMode;
|
||||
private String auditMappedBy;
|
||||
private String relationMappedBy;
|
||||
private String positionMappedBy;
|
||||
private boolean forceInsertable;
|
||||
private String auditMappedBy;
|
||||
private String relationMappedBy;
|
||||
private String positionMappedBy;
|
||||
private boolean forceInsertable;
|
||||
private boolean usingModifiedFlag;
|
||||
private String modifiedFlagName;
|
||||
|
||||
public PropertyAuditingData() {
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyAuditingData(String name, String accessType, ModificationStore store,
|
||||
RelationTargetAuditMode relationTargetAuditMode,
|
||||
String auditMappedBy, String positionMappedBy,
|
||||
boolean forceInsertable) {
|
||||
this.name = name;
|
||||
public PropertyAuditingData(
|
||||
String name, String accessType, ModificationStore store,
|
||||
RelationTargetAuditMode relationTargetAuditMode,
|
||||
String auditMappedBy, String positionMappedBy,
|
||||
boolean forceInsertable) {
|
||||
this.name = name;
|
||||
this.beanName = name;
|
||||
this.accessType = accessType;
|
||||
this.store = store;
|
||||
this.accessType = accessType;
|
||||
this.store = store;
|
||||
this.relationTargetAuditMode = relationTargetAuditMode;
|
||||
this.auditMappedBy = auditMappedBy;
|
||||
this.positionMappedBy = positionMappedBy;
|
||||
this.forceInsertable = forceInsertable;
|
||||
}
|
||||
this.auditMappedBy = auditMappedBy;
|
||||
this.positionMappedBy = positionMappedBy;
|
||||
this.forceInsertable = forceInsertable;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getBeanName() {
|
||||
return beanName;
|
||||
|
@ -87,77 +88,79 @@ public class PropertyAuditingData {
|
|||
}
|
||||
|
||||
public ModificationStore getStore() {
|
||||
return store;
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
public void setStore(ModificationStore store) {
|
||||
this.store = store;
|
||||
}
|
||||
public void setStore(ModificationStore store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
public String getMapKey() {
|
||||
return mapKey;
|
||||
}
|
||||
public String getMapKey() {
|
||||
return mapKey;
|
||||
}
|
||||
|
||||
public void setMapKey(String mapKey) {
|
||||
this.mapKey = mapKey;
|
||||
}
|
||||
public void setMapKey(String mapKey) {
|
||||
this.mapKey = mapKey;
|
||||
}
|
||||
|
||||
public AuditJoinTable getJoinTable() {
|
||||
return joinTable;
|
||||
}
|
||||
public AuditJoinTable getJoinTable() {
|
||||
return joinTable;
|
||||
}
|
||||
|
||||
public void setJoinTable(AuditJoinTable joinTable) {
|
||||
this.joinTable = joinTable;
|
||||
}
|
||||
public void setJoinTable(AuditJoinTable joinTable) {
|
||||
this.joinTable = joinTable;
|
||||
}
|
||||
|
||||
public String getAccessType() {
|
||||
return accessType;
|
||||
}
|
||||
public String getAccessType() {
|
||||
return accessType;
|
||||
}
|
||||
|
||||
public void setAccessType(String accessType) {
|
||||
this.accessType = accessType;
|
||||
}
|
||||
public void setAccessType(String accessType) {
|
||||
this.accessType = accessType;
|
||||
}
|
||||
|
||||
public PropertyData getPropertyData() {
|
||||
return new PropertyData(name, beanName, accessType, store,
|
||||
usingModifiedFlag, modifiedFlagName);
|
||||
}
|
||||
public PropertyData getPropertyData() {
|
||||
return new PropertyData(
|
||||
name, beanName, accessType, store,
|
||||
usingModifiedFlag, modifiedFlagName
|
||||
);
|
||||
}
|
||||
|
||||
public List<AuditOverride> getAuditingOverrides() {
|
||||
return auditJoinTableOverrides;
|
||||
}
|
||||
|
||||
public String getAuditMappedBy() {
|
||||
return auditMappedBy;
|
||||
}
|
||||
public String getAuditMappedBy() {
|
||||
return auditMappedBy;
|
||||
}
|
||||
|
||||
public void setAuditMappedBy(String auditMappedBy) {
|
||||
this.auditMappedBy = auditMappedBy;
|
||||
}
|
||||
public void setAuditMappedBy(String auditMappedBy) {
|
||||
this.auditMappedBy = auditMappedBy;
|
||||
}
|
||||
|
||||
public String getRelationMappedBy() {
|
||||
return relationMappedBy;
|
||||
}
|
||||
public String getRelationMappedBy() {
|
||||
return relationMappedBy;
|
||||
}
|
||||
|
||||
public void setRelationMappedBy(String relationMappedBy) {
|
||||
this.relationMappedBy = relationMappedBy;
|
||||
}
|
||||
public void setRelationMappedBy(String relationMappedBy) {
|
||||
this.relationMappedBy = relationMappedBy;
|
||||
}
|
||||
|
||||
public String getPositionMappedBy() {
|
||||
return positionMappedBy;
|
||||
}
|
||||
public String getPositionMappedBy() {
|
||||
return positionMappedBy;
|
||||
}
|
||||
|
||||
public void setPositionMappedBy(String positionMappedBy) {
|
||||
this.positionMappedBy = positionMappedBy;
|
||||
}
|
||||
public void setPositionMappedBy(String positionMappedBy) {
|
||||
this.positionMappedBy = positionMappedBy;
|
||||
}
|
||||
|
||||
public boolean isForceInsertable() {
|
||||
return forceInsertable;
|
||||
}
|
||||
public boolean isForceInsertable() {
|
||||
return forceInsertable;
|
||||
}
|
||||
|
||||
public void setForceInsertable(boolean forceInsertable) {
|
||||
this.forceInsertable = forceInsertable;
|
||||
}
|
||||
public void setForceInsertable(boolean forceInsertable) {
|
||||
this.forceInsertable = forceInsertable;
|
||||
}
|
||||
|
||||
public boolean isUsingModifiedFlag() {
|
||||
return usingModifiedFlag;
|
||||
|
@ -172,25 +175,25 @@ public class PropertyAuditingData {
|
|||
}
|
||||
|
||||
public void addAuditingOverride(AuditOverride annotation) {
|
||||
if (annotation != null) {
|
||||
String overrideName = annotation.name();
|
||||
if ( annotation != null ) {
|
||||
final String overrideName = annotation.name();
|
||||
boolean present = false;
|
||||
for (AuditOverride current : auditJoinTableOverrides) {
|
||||
if (current.name().equals(overrideName)) {
|
||||
for ( AuditOverride current : auditJoinTableOverrides ) {
|
||||
if ( current.name().equals( overrideName ) ) {
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!present) {
|
||||
auditJoinTableOverrides.add(annotation);
|
||||
if ( !present ) {
|
||||
auditJoinTableOverrides.add( annotation );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addAuditingOverrides(AuditOverrides annotationOverrides) {
|
||||
if (annotationOverrides != null) {
|
||||
for (AuditOverride annotation : annotationOverrides.value()) {
|
||||
addAuditingOverride(annotation);
|
||||
if ( annotationOverrides != null ) {
|
||||
for ( AuditOverride annotation : annotationOverrides.value() ) {
|
||||
addAuditingOverride( annotation );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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) {
|
||||
// TODO: Temporarily allow Envers to continuing using
|
||||
// hibernate-commons-annotations' for reflection and class loading.
|
||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() );
|
||||
|
||||
Properties properties = cfg.getProperties();
|
||||
|
||||
ReflectionManager reflectionManager = cfg.getReflectionManager();
|
||||
globalCfg = new GlobalConfiguration( properties, classLoaderService );
|
||||
RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg );
|
||||
RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure( cfg, reflectionManager );
|
||||
auditEntCfg = new AuditEntitiesConfiguration( properties, revInfoCfgResult.getRevisionInfoEntityName() );
|
||||
auditProcessManager = new AuditProcessManager( revInfoCfgResult.getRevisionInfoGenerator() );
|
||||
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
|
||||
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
|
||||
modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
|
||||
final Properties properties = cfg.getProperties();
|
||||
|
||||
final ReflectionManager reflectionManager = cfg.getReflectionManager();
|
||||
this.globalCfg = new GlobalConfiguration( properties, classLoaderService );
|
||||
final RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg );
|
||||
final RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure( cfg, reflectionManager );
|
||||
this.auditEntCfg = new AuditEntitiesConfiguration( properties, revInfoCfgResult.getRevisionInfoEntityName() );
|
||||
this.auditProcessManager = new AuditProcessManager( revInfoCfgResult.getRevisionInfoGenerator() );
|
||||
this.revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
|
||||
this.revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
|
||||
this.modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
|
||||
this.classLoaderService = classLoaderService;
|
||||
auditStrategy = initializeAuditStrategy(
|
||||
this.auditStrategy = initializeAuditStrategy(
|
||||
revInfoCfgResult.getRevisionInfoClass(),
|
||||
revInfoCfgResult.getRevisionInfoTimestampData()
|
||||
);
|
||||
entCfg = new EntitiesConfigurator().configure(
|
||||
this.entCfg = new EntitiesConfigurator().configure(
|
||||
cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy, classLoaderService,
|
||||
revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping()
|
||||
);
|
||||
|
||||
|
||||
Thread.currentThread().setContextClassLoader( tccl );
|
||||
}
|
||||
|
||||
|
@ -143,11 +143,14 @@ public class AuditConfiguration {
|
|||
auditStrategyClass = this.getClass().getClassLoader().loadClass( auditEntCfg.getAuditStrategyName() );
|
||||
}
|
||||
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(
|
||||
String.format( "Unable to create AuditStrategy[%s] instance.", auditEntCfg.getAuditStrategyName() ),
|
||||
e
|
||||
|
@ -156,27 +159,25 @@ public class AuditConfiguration {
|
|||
|
||||
if ( strategy instanceof ValidityAuditStrategy ) {
|
||||
// further initialization required
|
||||
Getter revisionTimestampGetter = ReflectionTools.getGetter( revisionInfoClass, revisionInfoTimestampData );
|
||||
final Getter revisionTimestampGetter = ReflectionTools.getGetter( revisionInfoClass, revisionInfoTimestampData );
|
||||
( (ValidityAuditStrategy) strategy ).setRevisionTimestampGetter( revisionTimestampGetter );
|
||||
}
|
||||
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private static Map<Configuration, AuditConfiguration> cfgs = new WeakHashMap<Configuration, AuditConfiguration>();
|
||||
private static final Map<Configuration, AuditConfiguration> CFGS = new WeakHashMap<Configuration, AuditConfiguration>();
|
||||
|
||||
public synchronized static AuditConfiguration getFor(Configuration cfg) {
|
||||
return getFor( cfg, null );
|
||||
}
|
||||
|
||||
public synchronized static AuditConfiguration getFor(Configuration cfg, ClassLoaderService classLoaderService) {
|
||||
AuditConfiguration verCfg = cfgs.get( cfg );
|
||||
AuditConfiguration verCfg = CFGS.get( cfg );
|
||||
|
||||
if ( verCfg == null ) {
|
||||
verCfg = new AuditConfiguration( cfg, classLoaderService );
|
||||
cfgs.put( cfg, verCfg );
|
||||
CFGS.put( cfg, verCfg );
|
||||
|
||||
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;
|
||||
|
||||
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).
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class OrderedSequenceGenerator extends SequenceStyleGenerator {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -23,13 +23,13 @@
|
|||
*/
|
||||
package org.hibernate.envers.enhanced;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
@ -42,64 +42,72 @@ import org.hibernate.envers.RevisionTimestamp;
|
|||
*/
|
||||
@MappedSuperclass
|
||||
public class SequenceIdRevisionEntity implements Serializable {
|
||||
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;
|
||||
private static final long serialVersionUID = 4159156677698841902L;
|
||||
|
||||
@RevisionTimestamp
|
||||
private long timestamp;
|
||||
@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;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
@RevisionTimestamp
|
||||
private long timestamp;
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Date getRevisionDate() {
|
||||
return new Date(timestamp);
|
||||
}
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
@Transient
|
||||
public Date getRevisionDate() {
|
||||
return new Date( timestamp );
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SequenceIdRevisionEntity )) return false;
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public void setTimestamp(long timestamp) {
|
||||
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;
|
||||
if (timestamp != that.timestamp) return false;
|
||||
final SequenceIdRevisionEntity that = (SequenceIdRevisionEntity) o;
|
||||
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() {
|
||||
int result = id;
|
||||
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SequenceIdRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SequenceIdRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(
|
||||
getRevisionDate()
|
||||
) + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -23,14 +23,14 @@
|
|||
*/
|
||||
package org.hibernate.envers.enhanced;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
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.
|
||||
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
|
||||
* parameter is set to {@code true}.
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public class SequenceIdTrackingModifiedEntitiesRevisionEntity extends SequenceIdRevisionEntity {
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
||||
@Column(name = "ENTITYNAME")
|
||||
@Fetch(FetchMode.JOIN)
|
||||
@ModifiedEntityNames
|
||||
private Set<String> modifiedEntityNames = new HashSet<String>();
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
|
||||
@Column(name = "ENTITYNAME")
|
||||
@Fetch(FetchMode.JOIN)
|
||||
@ModifiedEntityNames
|
||||
private Set<String> modifiedEntityNames = new HashSet<String>();
|
||||
|
||||
public Set<String> getModifiedEntityNames() {
|
||||
return modifiedEntityNames;
|
||||
}
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public Set<String> getModifiedEntityNames() {
|
||||
return modifiedEntityNames;
|
||||
}
|
||||
|
||||
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
||||
this.modifiedEntityNames = modifiedEntityNames;
|
||||
}
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
|
||||
this.modifiedEntityNames = modifiedEntityNames;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SequenceIdTrackingModifiedEntitiesRevisionEntity )) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
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)
|
||||
: that.modifiedEntityNames != null) return false;
|
||||
if ( modifiedEntityNames == null ) {
|
||||
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() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString()
|
||||
+ ", modifiedEntityNames = " + modifiedEntityNames + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,40 +57,40 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
super( enversConfiguration );
|
||||
}
|
||||
|
||||
protected final CollectionEntry getCollectionEntry(AbstractCollectionEvent event) {
|
||||
return event.getSession().getPersistenceContext().getCollectionEntry(event.getCollection());
|
||||
}
|
||||
protected final CollectionEntry getCollectionEntry(AbstractCollectionEvent event) {
|
||||
return event.getSession().getPersistenceContext().getCollectionEntry( event.getCollection() );
|
||||
}
|
||||
|
||||
protected final void onCollectionAction(
|
||||
protected final void onCollectionAction(
|
||||
AbstractCollectionEvent event,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
CollectionEntry collectionEntry) {
|
||||
if ( shouldGenerateRevision( event ) ) {
|
||||
checkIfTransactionInProgress(event.getSession());
|
||||
|
||||
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
|
||||
if ( shouldGenerateRevision( event ) ) {
|
||||
checkIfTransactionInProgress( event.getSession() );
|
||||
|
||||
String entityName = event.getAffectedOwnerEntityName();
|
||||
String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
|
||||
String referencingPropertyName = collectionEntry.getRole().substring(ownerEntityName.length() + 1);
|
||||
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
|
||||
|
||||
// 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.
|
||||
RelationDescription rd = searchForRelationDescription( entityName, referencingPropertyName );
|
||||
if ( rd != null && rd.getMappedByPropertyName() != null ) {
|
||||
generateFakeBidirecationalRelationWorkUnits(
|
||||
final String entityName = event.getAffectedOwnerEntityName();
|
||||
final String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
|
||||
final 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
|
||||
// null in case of collections of non-entities.
|
||||
final RelationDescription rd = searchForRelationDescription( entityName, referencingPropertyName );
|
||||
if ( rd != null && rd.getMappedByPropertyName() != null ) {
|
||||
generateFakeBidirecationalRelationWorkUnits(
|
||||
auditProcess,
|
||||
newColl,
|
||||
oldColl,
|
||||
entityName,
|
||||
referencingPropertyName,
|
||||
referencingPropertyName,
|
||||
event,
|
||||
rd
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(
|
||||
final PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(
|
||||
event.getSession(),
|
||||
entityName,
|
||||
getAuditConfiguration(),
|
||||
|
@ -102,9 +102,9 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
);
|
||||
auditProcess.addWorkUnit( workUnit );
|
||||
|
||||
if (workUnit.containsWork()) {
|
||||
// There are some changes: a revision needs also be generated for the collection owner
|
||||
auditProcess.addWorkUnit(
|
||||
if ( workUnit.containsWork() ) {
|
||||
// There are some changes: a revision needs also be generated for the collection owner
|
||||
auditProcess.addWorkUnit(
|
||||
new CollectionChangeWorkUnit(
|
||||
event.getSession(),
|
||||
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.
|
||||
*
|
||||
* @param event Collection event.
|
||||
*
|
||||
* @return Stored snapshot.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param event Collection event.
|
||||
*
|
||||
* @return {@code true} if revision based on given event should be generated, {@code false} otherwise.
|
||||
*/
|
||||
protected boolean shouldGenerateRevision(AbstractCollectionEvent event) {
|
||||
|
@ -142,27 +146,27 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
&& getAuditConfiguration().getEntCfg().isVersioned( entityName );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @param entityName Name of the entity, in which to start looking.
|
||||
* @param referencingPropertyName The name of the property.
|
||||
*
|
||||
* @return A found relation description corresponding to the given entity or {@code null}, if no description can
|
||||
* be found.
|
||||
*/
|
||||
private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) {
|
||||
EntityConfiguration configuration = getAuditConfiguration().getEntCfg().get( entityName );
|
||||
RelationDescription rd = configuration.getRelationDescription(referencingPropertyName);
|
||||
if ( rd == null && configuration.getParentEntityName() != null ) {
|
||||
return searchForRelationDescription( configuration.getParentEntityName(), referencingPropertyName );
|
||||
}
|
||||
* @param entityName Name of the entity, in which to start looking.
|
||||
* @param referencingPropertyName The name of the property.
|
||||
*
|
||||
* @return A found relation description corresponding to the given entity or {@code null}, if no description can
|
||||
* be found.
|
||||
*/
|
||||
private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) {
|
||||
final EntityConfiguration configuration = getAuditConfiguration().getEntCfg().get( entityName );
|
||||
final RelationDescription rd = configuration.getRelationDescription( referencingPropertyName );
|
||||
if ( rd == null && configuration.getParentEntityName() != null ) {
|
||||
return searchForRelationDescription( configuration.getParentEntityName(), referencingPropertyName );
|
||||
}
|
||||
|
||||
return rd;
|
||||
}
|
||||
return rd;
|
||||
}
|
||||
|
||||
private void generateFakeBidirecationalRelationWorkUnits(
|
||||
private void generateFakeBidirecationalRelationWorkUnits(
|
||||
AuditProcess auditProcess,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
|
@ -170,41 +174,47 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
String referencingPropertyName,
|
||||
AbstractCollectionEvent event,
|
||||
RelationDescription rd) {
|
||||
// First computing the relation changes
|
||||
List<PersistentCollectionChangeData> collectionChanges = getAuditConfiguration()
|
||||
// First computing the relation changes
|
||||
final List<PersistentCollectionChangeData> collectionChanges = getAuditConfiguration()
|
||||
.getEntCfg()
|
||||
.get( collectionEntityName )
|
||||
.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
|
||||
// entities.
|
||||
String relatedEntityName = rd.getToEntityName();
|
||||
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get(relatedEntityName).getIdMapper();
|
||||
// Getting the id mapper for the related entity, as the work units generated will correspond to the related
|
||||
// entities.
|
||||
final String relatedEntityName = rd.getToEntityName();
|
||||
final IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
|
||||
|
||||
// For each collection change, generating the bidirectional work unit.
|
||||
for ( PersistentCollectionChangeData changeData : collectionChanges ) {
|
||||
Object relatedObj = changeData.getChangedElement();
|
||||
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity(relatedObj);
|
||||
RevisionType revType = (RevisionType) changeData.getData().get(
|
||||
// For each collection change, generating the bidirectional work unit.
|
||||
for ( PersistentCollectionChangeData changeData : collectionChanges ) {
|
||||
final Object relatedObj = changeData.getChangedElement();
|
||||
final Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
|
||||
final RevisionType revType = (RevisionType) changeData.getData().get(
|
||||
getAuditConfiguration().getAuditEntCfg().getRevisionTypePropName()
|
||||
);
|
||||
|
||||
// This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass
|
||||
// of relatedEntityName).
|
||||
String realRelatedEntityName = event.getSession().bestGuessEntityName(relatedObj);
|
||||
// This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass
|
||||
// of relatedEntityName).
|
||||
final String realRelatedEntityName = event.getSession().bestGuessEntityName( relatedObj );
|
||||
|
||||
// By default, the nested work unit is a collection change work unit.
|
||||
AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
|
||||
// By default, the nested work unit is a collection change work unit.
|
||||
final AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
|
||||
event.getSession(),
|
||||
realRelatedEntityName,
|
||||
rd.getMappedByPropertyName(),
|
||||
getAuditConfiguration(),
|
||||
relatedId,
|
||||
relatedId,
|
||||
relatedObj
|
||||
);
|
||||
|
||||
auditProcess.addWorkUnit(
|
||||
auditProcess.addWorkUnit(
|
||||
new FakeBidirectionalRelationWorkUnit(
|
||||
event.getSession(),
|
||||
realRelatedEntityName,
|
||||
|
@ -218,10 +228,10 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
nestedWorkUnit
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// We also have to generate a collection change work unit for the owning entity.
|
||||
auditProcess.addWorkUnit(
|
||||
// We also have to generate a collection change work unit for the owning entity.
|
||||
auditProcess.addWorkUnit(
|
||||
new CollectionChangeWorkUnit(
|
||||
event.getSession(),
|
||||
collectionEntityName,
|
||||
|
@ -231,44 +241,47 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
event.getAffectedOwnerOrNull()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateBidirectionalCollectionChangeWorkUnits(
|
||||
private void generateBidirectionalCollectionChangeWorkUnits(
|
||||
AuditProcess auditProcess,
|
||||
AbstractCollectionEvent event,
|
||||
PersistentCollectionChangeWorkUnit workUnit,
|
||||
RelationDescription rd) {
|
||||
// Checking if this is enabled in configuration ...
|
||||
if ( ! getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
||||
return;
|
||||
}
|
||||
// Checking if this is enabled in configuration ...
|
||||
if ( !getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Checking if this is not a bidirectional relation - then, a revision needs also be generated for
|
||||
// the other side of the relation.
|
||||
// relDesc can be null if this is a collection of simple values (not a relation).
|
||||
if ( rd != null && rd.isBidirectional() ) {
|
||||
String relatedEntityName = rd.getToEntityName();
|
||||
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
|
||||
// Checking if this is not a bidirectional relation - then, a revision needs also be generated for
|
||||
// the other side of the relation.
|
||||
// relDesc can be null if this is a collection of simple values (not a relation).
|
||||
if ( rd != null && rd.isBidirectional() ) {
|
||||
final String relatedEntityName = rd.getToEntityName();
|
||||
final IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
|
||||
|
||||
Set<String> toPropertyNames = getAuditConfiguration().getEntCfg()
|
||||
.getToPropertyNames(event.getAffectedOwnerEntityName(), rd.getFromPropertyName(), relatedEntityName);
|
||||
String toPropertyName = toPropertyNames.iterator().next();
|
||||
final Set<String> toPropertyNames = getAuditConfiguration().getEntCfg().getToPropertyNames(
|
||||
event.getAffectedOwnerEntityName(),
|
||||
rd.getFromPropertyName(),
|
||||
relatedEntityName
|
||||
);
|
||||
final String toPropertyName = toPropertyNames.iterator().next();
|
||||
|
||||
for ( PersistentCollectionChangeData changeData : workUnit.getCollectionChanges() ) {
|
||||
Object relatedObj = changeData.getChangedElement();
|
||||
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
|
||||
for ( PersistentCollectionChangeData changeData : workUnit.getCollectionChanges() ) {
|
||||
final Object relatedObj = changeData.getChangedElement();
|
||||
final Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
|
||||
|
||||
auditProcess.addWorkUnit(
|
||||
auditProcess.addWorkUnit(
|
||||
new CollectionChangeWorkUnit(
|
||||
event.getSession(),
|
||||
event.getSession().bestGuessEntityName(relatedObj),
|
||||
event.getSession().bestGuessEntityName( relatedObj ),
|
||||
toPropertyName,
|
||||
getAuditConfiguration(),
|
||||
relatedId,
|
||||
relatedObj
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,72 +66,84 @@ public abstract class BaseEnversEventListener implements EnversListener {
|
|||
Object[] oldState,
|
||||
SessionImplementor session) {
|
||||
// Checking if this is enabled in configuration ...
|
||||
if ( ! enversConfiguration.getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
||||
if ( !enversConfiguration.getGlobalCfg().isGenerateRevisionsForCollections() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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
|
||||
// for the related entity is generated.
|
||||
String[] propertyNames = entityPersister.getPropertyNames();
|
||||
final String[] propertyNames = entityPersister.getPropertyNames();
|
||||
|
||||
for ( int i=0; i<propertyNames.length; i++ ) {
|
||||
String propertyName = propertyNames[i];
|
||||
RelationDescription relDesc = enversConfiguration.getEntCfg().getRelationDescription(entityName, propertyName);
|
||||
if (relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE &&
|
||||
relDesc.isInsertable()) {
|
||||
for ( int i = 0; i < propertyNames.length; i++ ) {
|
||||
final String propertyName = propertyNames[i];
|
||||
final RelationDescription relDesc = enversConfiguration.getEntCfg().getRelationDescription(
|
||||
entityName,
|
||||
propertyName
|
||||
);
|
||||
if ( relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE &&
|
||||
relDesc.isInsertable() ) {
|
||||
// Checking for changes
|
||||
Object oldValue = oldState == null ? null : oldState[i];
|
||||
Object newValue = newState == null ? null : newState[i];
|
||||
final Object oldValue = oldState == null ? null : oldState[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
|
||||
// (size increases).
|
||||
if (newValue != null) {
|
||||
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, newValue);
|
||||
if ( newValue != null ) {
|
||||
addCollectionChangeWorkUnit( auditProcess, session, entityName, relDesc, newValue );
|
||||
}
|
||||
|
||||
if (oldValue != null) {
|
||||
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, oldValue);
|
||||
if ( oldValue != null ) {
|
||||
addCollectionChangeWorkUnit( auditProcess, session, entityName, relDesc, oldValue );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addCollectionChangeWorkUnit(AuditProcess auditProcess, SessionImplementor session,
|
||||
String fromEntityName, RelationDescription relDesc, Object value) {
|
||||
private void addCollectionChangeWorkUnit(
|
||||
AuditProcess auditProcess, SessionImplementor session,
|
||||
String fromEntityName, RelationDescription relDesc, Object value) {
|
||||
// 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.
|
||||
String toEntityName;
|
||||
Serializable id;
|
||||
|
||||
if (value instanceof HibernateProxy) {
|
||||
HibernateProxy hibernateProxy = (HibernateProxy) value;
|
||||
toEntityName = session.bestGuessEntityName(value);
|
||||
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
||||
// We've got to initialize the object from the proxy to later read its state.
|
||||
value = EntityTools.getTargetFromProxy(session.getFactory(), hibernateProxy);
|
||||
} else {
|
||||
toEntityName = session.guessEntityName(value);
|
||||
if ( value instanceof HibernateProxy ) {
|
||||
final HibernateProxy hibernateProxy = (HibernateProxy) value;
|
||||
toEntityName = session.bestGuessEntityName( value );
|
||||
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
||||
// We've got to initialize the object from the proxy to later read its state.
|
||||
value = EntityTools.getTargetFromProxy( session.getFactory(), hibernateProxy );
|
||||
}
|
||||
else {
|
||||
toEntityName = session.guessEntityName( value );
|
||||
|
||||
IdMapper idMapper = enversConfiguration.getEntCfg().get(toEntityName).getIdMapper();
|
||||
id = (Serializable) idMapper.mapToIdFromEntity(value);
|
||||
final IdMapper idMapper = enversConfiguration.getEntCfg().get( toEntityName ).getIdMapper();
|
||||
id = (Serializable) idMapper.mapToIdFromEntity( value );
|
||||
}
|
||||
|
||||
Set<String> toPropertyNames = enversConfiguration.getEntCfg()
|
||||
.getToPropertyNames(fromEntityName, relDesc.getFromPropertyName(), toEntityName);
|
||||
String toPropertyName = toPropertyNames.iterator().next();
|
||||
final Set<String> toPropertyNames = enversConfiguration.getEntCfg().getToPropertyNames(
|
||||
fromEntityName,
|
||||
relDesc.getFromPropertyName(),
|
||||
toEntityName
|
||||
);
|
||||
final String toPropertyName = toPropertyNames.iterator().next();
|
||||
|
||||
auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName,
|
||||
toPropertyName, enversConfiguration, id, value));
|
||||
auditProcess.addWorkUnit(
|
||||
new CollectionChangeWorkUnit(
|
||||
session, toEntityName,
|
||||
toPropertyName, enversConfiguration, id, value
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected void checkIfTransactionInProgress(SessionImplementor session) {
|
||||
if (!session.isTransactionInProgress()) {
|
||||
// Historical data would not be flushed to audit tables if outside of active transaction
|
||||
// (AuditProcess#doBeforeTransactionCompletion(SessionImplementor) not executed).
|
||||
throw new AuditException("Unable to create revision because of non-active transaction");
|
||||
}
|
||||
}
|
||||
protected void checkIfTransactionInProgress(SessionImplementor session) {
|
||||
if ( !session.isTransactionInProgress() ) {
|
||||
// Historical data would not be flushed to audit tables if outside of active transaction
|
||||
// (AuditProcess#doBeforeTransactionCompletion(SessionImplementor) not executed).
|
||||
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
|
||||
*/
|
||||
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";
|
||||
|
||||
@Override
|
||||
|
@ -52,25 +59,55 @@ public class EnversIntegrator implements Integrator {
|
|||
Configuration configuration,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SessionFactoryServiceRegistry serviceRegistry) {
|
||||
final boolean autoRegister = ConfigurationHelper.getBoolean( AUTO_REGISTER, configuration.getProperties(), true );
|
||||
final boolean autoRegister = ConfigurationHelper.getBoolean(
|
||||
AUTO_REGISTER,
|
||||
configuration.getProperties(),
|
||||
true
|
||||
);
|
||||
if ( !autoRegister ) {
|
||||
LOG.debug( "Skipping Envers listener auto registration" );
|
||||
return;
|
||||
}
|
||||
|
||||
EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
|
||||
final EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
|
||||
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()) {
|
||||
listenerRegistry.appendListeners( EventType.POST_DELETE, new EnversPostDeleteEventListenerImpl( 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 ) );
|
||||
}
|
||||
if ( enversConfiguration.getEntCfg().hasAuditedEntities() ) {
|
||||
listenerRegistry.appendListeners(
|
||||
EventType.POST_DELETE, new EnversPostDeleteEventListenerImpl(
|
||||
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
|
||||
|
@ -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)
|
||||
*/
|
||||
@Override
|
||||
public void integrate( MetadataImplementor metadata,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SessionFactoryServiceRegistry serviceRegistry ) {
|
||||
// TODO: implement
|
||||
public void integrate(
|
||||
MetadataImplementor metadata,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SessionFactoryServiceRegistry serviceRegistry) {
|
||||
// TODO: implement
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,5 +31,10 @@ import org.hibernate.envers.configuration.spi.AuditConfiguration;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EnversListener {
|
||||
/**
|
||||
* Get the Envers AuditConfiguration
|
||||
*
|
||||
* @return The Envers AuditConfiguration
|
||||
*/
|
||||
public AuditConfiguration getAuditConfiguration();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ import org.hibernate.event.service.spi.DuplicationStrategy;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnversListenerDuplicationStrategy implements DuplicationStrategy {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final EnversListenerDuplicationStrategy INSTANCE = new EnversListenerDuplicationStrategy();
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,12 +29,14 @@ import org.hibernate.event.spi.PostCollectionRecreateEvent;
|
|||
import org.hibernate.event.spi.PostCollectionRecreateEventListener;
|
||||
|
||||
/**
|
||||
* Envers-specific collection recreation event listener
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author HernпїЅn Chanfreau
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnversPostCollectionRecreateEventListenerImpl
|
||||
extends BaseEnversCollectionEventListener
|
||||
extends BaseEnversCollectionEventListener
|
||||
implements PostCollectionRecreateEventListener {
|
||||
|
||||
protected EnversPostCollectionRecreateEventListenerImpl(AuditConfiguration enversConfiguration) {
|
||||
|
@ -43,9 +45,9 @@ public class EnversPostCollectionRecreateEventListenerImpl
|
|||
|
||||
@Override
|
||||
public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
|
||||
CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||
if ( ! collectionEntry.getLoadedPersister().isInverse() ) {
|
||||
onCollectionAction( event, event.getCollection(), null, collectionEntry );
|
||||
}
|
||||
final CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||
if ( !collectionEntry.getLoadedPersister().isInverse() ) {
|
||||
onCollectionAction( event, event.getCollection(), null, collectionEntry );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.event.spi.PostDeleteEventListener;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
* Envers-specific entity (post) deletion event listener
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author HernпїЅn Chanfreau
|
||||
* @author Steve Ebersole
|
||||
|
@ -43,30 +45,30 @@ public class EnversPostDeleteEventListenerImpl extends BaseEnversEventListener i
|
|||
|
||||
@Override
|
||||
public void onPostDelete(PostDeleteEvent event) {
|
||||
String entityName = event.getPersister().getEntityName();
|
||||
final String entityName = event.getPersister().getEntityName();
|
||||
|
||||
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||
checkIfTransactionInProgress(event.getSession());
|
||||
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||
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.getPersister().getEntityName(),
|
||||
getAuditConfiguration(),
|
||||
event.getId(),
|
||||
event.getId(),
|
||||
event.getPersister(),
|
||||
event.getDeletedState()
|
||||
);
|
||||
auditProcess.addWorkUnit( workUnit );
|
||||
auditProcess.addWorkUnit( workUnit );
|
||||
|
||||
if ( workUnit.containsWork() ) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(
|
||||
if ( workUnit.containsWork() ) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(
|
||||
auditProcess,
|
||||
event.getPersister(),
|
||||
entityName,
|
||||
null,
|
||||
event.getDeletedState(),
|
||||
event.getDeletedState(),
|
||||
event.getSession()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -32,44 +32,47 @@ import org.hibernate.event.spi.PostInsertEventListener;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
* Envers-specific entity (post) insertion event listener
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author HernпїЅn Chanfreau
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnversPostInsertEventListenerImpl extends BaseEnversEventListener implements PostInsertEventListener {
|
||||
public EnversPostInsertEventListenerImpl(AuditConfiguration enversConfiguration) {
|
||||
protected EnversPostInsertEventListenerImpl(AuditConfiguration enversConfiguration) {
|
||||
super( enversConfiguration );
|
||||
}
|
||||
|
||||
public void onPostInsert(PostInsertEvent event) {
|
||||
String entityName = event.getPersister().getEntityName();
|
||||
@Override
|
||||
public void onPostInsert(PostInsertEvent event) {
|
||||
final String entityName = event.getPersister().getEntityName();
|
||||
|
||||
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||
checkIfTransactionInProgress(event.getSession());
|
||||
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||
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.getPersister().getEntityName(),
|
||||
getAuditConfiguration(),
|
||||
event.getId(),
|
||||
event.getId(),
|
||||
event.getPersister(),
|
||||
event.getState()
|
||||
);
|
||||
auditProcess.addWorkUnit( workUnit );
|
||||
auditProcess.addWorkUnit( workUnit );
|
||||
|
||||
if ( workUnit.containsWork() ) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(
|
||||
if ( workUnit.containsWork() ) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(
|
||||
auditProcess,
|
||||
event.getPersister(),
|
||||
entityName,
|
||||
event.getState(),
|
||||
null,
|
||||
null,
|
||||
event.getSession()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.event.spi.PostUpdateEventListener;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
* Envers-specific entity (post) update event listener
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author HernпїЅn Chanfreau
|
||||
* @author Steve Ebersole
|
||||
|
@ -43,43 +45,41 @@ public class EnversPostUpdateEventListenerImpl extends BaseEnversEventListener i
|
|||
|
||||
@Override
|
||||
public void onPostUpdate(PostUpdateEvent event) {
|
||||
String entityName = event.getPersister().getEntityName();
|
||||
final String entityName = event.getPersister().getEntityName();
|
||||
|
||||
if ( getAuditConfiguration().getEntCfg().isVersioned(entityName) ) {
|
||||
checkIfTransactionInProgress(event.getSession());
|
||||
|
||||
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
|
||||
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
|
||||
checkIfTransactionInProgress( event.getSession() );
|
||||
|
||||
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
|
||||
final Object[] newDbState = postUpdateDBState( event );
|
||||
|
||||
AuditWorkUnit workUnit = new ModWorkUnit(
|
||||
final AuditWorkUnit workUnit = new ModWorkUnit(
|
||||
event.getSession(),
|
||||
event.getPersister().getEntityName(),
|
||||
getAuditConfiguration(),
|
||||
event.getId(),
|
||||
event.getId(),
|
||||
event.getPersister(),
|
||||
newDbState,
|
||||
event.getOldState()
|
||||
);
|
||||
auditProcess.addWorkUnit( workUnit );
|
||||
auditProcess.addWorkUnit( workUnit );
|
||||
|
||||
if ( workUnit.containsWork() ) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(
|
||||
if ( workUnit.containsWork() ) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(
|
||||
auditProcess,
|
||||
event.getPersister(),
|
||||
entityName,
|
||||
newDbState,
|
||||
event.getOldState(),
|
||||
event.getOldState(),
|
||||
event.getSession()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] postUpdateDBState(PostUpdateEvent event) {
|
||||
Object[] newDbState = event.getState().clone();
|
||||
final Object[] newDbState = event.getState().clone();
|
||||
if ( event.getOldState() != null ) {
|
||||
EntityPersister entityPersister = event.getPersister();
|
||||
final EntityPersister entityPersister = event.getPersister();
|
||||
for ( int i = 0; i < entityPersister.getPropertyNames().length; ++i ) {
|
||||
if ( !entityPersister.getPropertyUpdateability()[i] ) {
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Envers-specific collection removal event listener
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author HernпїЅn Chanfreau
|
||||
* @author Steve Ebersole
|
||||
|
@ -46,14 +48,14 @@ public class EnversPreCollectionRemoveEventListenerImpl
|
|||
|
||||
@Override
|
||||
public void onPreRemoveCollection(PreCollectionRemoveEvent event) {
|
||||
CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||
if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) {
|
||||
final CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||
if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) {
|
||||
Serializable oldColl = collectionEntry.getSnapshot();
|
||||
if ( !event.getCollection().wasInitialized() && shouldGenerateRevision( event ) ) {
|
||||
// In case of uninitialized collection we need a fresh snapshot to properly calculate audit data.
|
||||
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;
|
||||
|
||||
/**
|
||||
* Envers-specific collection update event listener
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author HernпїЅn Chanfreau
|
||||
* @author Steve Ebersole
|
||||
|
@ -43,9 +45,9 @@ public class EnversPreCollectionUpdateEventListenerImpl
|
|||
|
||||
@Override
|
||||
public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
|
||||
CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||
if ( ! collectionEntry.getLoadedPersister().isInverse() ) {
|
||||
onCollectionAction( event, event.getCollection(), collectionEntry.getSnapshot(), collectionEntry );
|
||||
}
|
||||
final CollectionEntry collectionEntry = getCollectionEntry( event );
|
||||
if ( !collectionEntry.getLoadedPersister().isInverse() ) {
|
||||
onCollectionAction( event, event.getCollection(), collectionEntry.getSnapshot(), collectionEntry );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.exception;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
/**
|
||||
|
@ -31,14 +32,14 @@ public class AuditException extends HibernateException {
|
|||
private static final long serialVersionUID = 4306480965630972168L;
|
||||
|
||||
public AuditException(String message) {
|
||||
super(message);
|
||||
}
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AuditException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
public AuditException(String message, Throwable cause) {
|
||||
super( message, cause );
|
||||
}
|
||||
|
||||
public AuditException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
public AuditException(Throwable cause) {
|
||||
super( cause );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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 {
|
||||
private static final long serialVersionUID = 4809674577449455510L;
|
||||
|
||||
private final String entityName;
|
||||
|
||||
private final String entityName;
|
||||
|
||||
public NotAuditedException(String entityName, String message) {
|
||||
super(message);
|
||||
this.entityName = entityName;
|
||||
}
|
||||
super( message );
|
||||
this.entityName = entityName;
|
||||
}
|
||||
|
||||
public String getEntityName() {
|
||||
return entityName;
|
||||
}
|
||||
public String getEntityName() {
|
||||
return entityName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.exception;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
|
@ -29,25 +30,27 @@ import java.util.Date;
|
|||
*/
|
||||
public class RevisionDoesNotExistException extends AuditException {
|
||||
private static final long serialVersionUID = -6417768274074962282L;
|
||||
|
||||
private Number revision;
|
||||
private Date date;
|
||||
|
||||
private final Number revision;
|
||||
private final Date date;
|
||||
|
||||
public RevisionDoesNotExistException(Number revision) {
|
||||
super("Revision " + revision + " does not exist.");
|
||||
this.revision = revision;
|
||||
}
|
||||
super( "Revision " + revision + " does not exist." );
|
||||
this.revision = revision;
|
||||
this.date = null;
|
||||
}
|
||||
|
||||
public RevisionDoesNotExistException(Date date) {
|
||||
super("There is no revision before or at " + date + ".");
|
||||
this.date = date;
|
||||
}
|
||||
public RevisionDoesNotExistException(Date date) {
|
||||
super( "There is no revision before or at " + date + "." );
|
||||
this.date = date;
|
||||
this.revision = null;
|
||||
}
|
||||
|
||||
public Number getRevision() {
|
||||
return revision;
|
||||
}
|
||||
public Number getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
|
@ -37,10 +37,13 @@ import static org.jboss.logging.Logger.Level.WARN;
|
|||
* <p/>
|
||||
* 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 {
|
||||
|
||||
@LogMessage( level = WARN )
|
||||
@Message( value = "ValidTimeAuditStrategy is deprecated, please use ValidityAuditStrategy instead", id = 25001 )
|
||||
void validTimeAuditStrategyDeprecated();
|
||||
/**
|
||||
* Message indicating that user attempted to use the deprecated ValidTimeAuditStrategy
|
||||
*/
|
||||
@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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -31,129 +32,136 @@ import java.util.Set;
|
|||
|
||||
/**
|
||||
* Configuration of the user entities: property mapping of the entities, relations, inheritance.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Hernán Chanfreau
|
||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||
*/
|
||||
public class EntitiesConfigurations {
|
||||
private Map<String, EntityConfiguration> entitiesConfigurations;
|
||||
private Map<String, EntityConfiguration> notAuditedEntitiesConfigurations;
|
||||
private Map<String, EntityConfiguration> entitiesConfigurations;
|
||||
private Map<String, EntityConfiguration> notAuditedEntitiesConfigurations;
|
||||
|
||||
// Map versions entity name -> entity name
|
||||
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
||||
// Map versions entity name -> entity name
|
||||
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
||||
|
||||
public EntitiesConfigurations(Map<String, EntityConfiguration> entitiesConfigurations,
|
||||
Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) {
|
||||
this.entitiesConfigurations = entitiesConfigurations;
|
||||
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
|
||||
public EntitiesConfigurations(
|
||||
Map<String, EntityConfiguration> entitiesConfigurations,
|
||||
Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) {
|
||||
this.entitiesConfigurations = entitiesConfigurations;
|
||||
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
|
||||
|
||||
generateBidirectionRelationInfo();
|
||||
generateVersionsEntityToEntityNames();
|
||||
}
|
||||
generateBidirectionRelationInfo();
|
||||
generateVersionsEntityToEntityNames();
|
||||
}
|
||||
|
||||
private void generateVersionsEntityToEntityNames() {
|
||||
entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
||||
private void generateVersionsEntityToEntityNames() {
|
||||
entityNamesForVersionsEntityNames = new HashMap<String, String>();
|
||||
|
||||
for (String entityName : entitiesConfigurations.keySet()) {
|
||||
entityNamesForVersionsEntityNames.put(entitiesConfigurations.get(entityName).getVersionsEntityName(),
|
||||
entityName);
|
||||
}
|
||||
}
|
||||
for ( String entityName : entitiesConfigurations.keySet() ) {
|
||||
entityNamesForVersionsEntityNames.put(
|
||||
entitiesConfigurations.get( entityName ).getVersionsEntityName(),
|
||||
entityName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateBidirectionRelationInfo() {
|
||||
// Checking each relation if it is bidirectional. If so, storing that information.
|
||||
for (String entityName : entitiesConfigurations.keySet()) {
|
||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
||||
// Iterating over all relations from that entity
|
||||
for (RelationDescription relDesc : entCfg.getRelationsIterator()) {
|
||||
// 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.
|
||||
if (relDesc.getRelationType() == RelationType.TO_ONE ||
|
||||
relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) {
|
||||
EntityConfiguration entityConfiguration = entitiesConfigurations.get(relDesc.getToEntityName());
|
||||
if (entityConfiguration != null) {
|
||||
for (RelationDescription other : entityConfiguration.getRelationsIterator()) {
|
||||
if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
|
||||
(entityName.equals(other.getToEntityName()))) {
|
||||
relDesc.setBidirectional(true);
|
||||
other.setBidirectional(true);
|
||||
private void generateBidirectionRelationInfo() {
|
||||
// Checking each relation if it is bidirectional. If so, storing that information.
|
||||
for ( String entityName : entitiesConfigurations.keySet() ) {
|
||||
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||
// Iterating over all relations from that entity
|
||||
for ( RelationDescription relDesc : entCfg.getRelationsIterator() ) {
|
||||
// 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.
|
||||
if ( relDesc.getRelationType() == RelationType.TO_ONE ||
|
||||
relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE ) {
|
||||
final EntityConfiguration entityConfiguration = entitiesConfigurations.get( relDesc.getToEntityName() );
|
||||
if ( entityConfiguration != null ) {
|
||||
for ( RelationDescription other : entityConfiguration.getRelationsIterator() ) {
|
||||
if ( relDesc.getFromPropertyName().equals( other.getMappedByPropertyName() ) &&
|
||||
(entityName.equals( other.getToEntityName() )) ) {
|
||||
relDesc.setBidirectional( true );
|
||||
other.setBidirectional( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EntityConfiguration get(String entityName) {
|
||||
return entitiesConfigurations.get(entityName);
|
||||
}
|
||||
public EntityConfiguration get(String entityName) {
|
||||
return entitiesConfigurations.get( entityName );
|
||||
}
|
||||
|
||||
public EntityConfiguration getNotVersionEntityConfiguration(String entityName) {
|
||||
return notAuditedEntitiesConfigurations.get(entityName);
|
||||
}
|
||||
public EntityConfiguration getNotVersionEntityConfiguration(String entityName) {
|
||||
return notAuditedEntitiesConfigurations.get( entityName );
|
||||
}
|
||||
|
||||
public String getEntityNameForVersionsEntityName(String versionsEntityName) {
|
||||
return entityNamesForVersionsEntityNames.get(versionsEntityName);
|
||||
}
|
||||
public String getEntityNameForVersionsEntityName(String versionsEntityName) {
|
||||
return entityNamesForVersionsEntityNames.get( versionsEntityName );
|
||||
}
|
||||
|
||||
public boolean isVersioned(String entityName) {
|
||||
return get(entityName) != null;
|
||||
}
|
||||
public boolean isVersioned(String entityName) {
|
||||
return get( entityName ) != null;
|
||||
}
|
||||
|
||||
public boolean hasAuditedEntities() {
|
||||
return entitiesConfigurations.size() != 0;
|
||||
}
|
||||
public boolean hasAuditedEntities() {
|
||||
return entitiesConfigurations.size() != 0;
|
||||
}
|
||||
|
||||
public RelationDescription getRelationDescription(String entityName, String propertyName) {
|
||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
||||
RelationDescription relDesc = entCfg.getRelationDescription(propertyName);
|
||||
if (relDesc != null) {
|
||||
return relDesc;
|
||||
} else if (entCfg.getParentEntityName() != null) {
|
||||
// The field may be declared in a superclass ...
|
||||
return getRelationDescription(entCfg.getParentEntityName(), propertyName);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public RelationDescription getRelationDescription(String entityName, String propertyName) {
|
||||
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||
final RelationDescription relDesc = entCfg.getRelationDescription( propertyName );
|
||||
if ( relDesc != null ) {
|
||||
return relDesc;
|
||||
}
|
||||
else if ( entCfg.getParentEntityName() != null ) {
|
||||
// The field may be declared in a superclass ...
|
||||
return getRelationDescription( entCfg.getParentEntityName(), propertyName );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<RelationDescription> getRelationDescriptions(String entityName) {
|
||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
||||
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||
Collection<RelationDescription> descriptions = new ArrayList<RelationDescription>();
|
||||
if (entCfg.getParentEntityName() != null) {
|
||||
if ( entCfg.getParentEntityName() != null ) {
|
||||
// collect descriptions from super classes
|
||||
descriptions.addAll(getRelationDescriptions(entCfg.getParentEntityName()));
|
||||
descriptions.addAll( getRelationDescriptions( entCfg.getParentEntityName() ) );
|
||||
}
|
||||
for (RelationDescription relationDescription : entCfg.getRelationsIterator()) {
|
||||
descriptions.add(relationDescription);
|
||||
for ( RelationDescription relationDescription : entCfg.getRelationsIterator() ) {
|
||||
descriptions.add( relationDescription );
|
||||
}
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
|
||||
entityNames.add(entityName);
|
||||
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
|
||||
if (entCfg.getParentEntityName() != null) {
|
||||
entityNames.add( entityName );
|
||||
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||
if ( entCfg.getParentEntityName() != null ) {
|
||||
// collect descriptions from super classes
|
||||
addWithParentEntityNames(entCfg.getParentEntityName(), entityNames);
|
||||
addWithParentEntityNames( entCfg.getParentEntityName(), entityNames );
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getEntityAndParentsNames(String entityName) {
|
||||
Set<String> names = new HashSet<String>();
|
||||
addWithParentEntityNames(entityName, names);
|
||||
final Set<String> names = new HashSet<String>();
|
||||
addWithParentEntityNames( entityName, names );
|
||||
return names;
|
||||
}
|
||||
|
||||
public Set<String> getToPropertyNames(String fromEntityName, String fromPropertyName, String toEntityName) {
|
||||
Set<String> entityAndParentsNames = getEntityAndParentsNames(fromEntityName);
|
||||
Set<String> toPropertyNames = new HashSet<String>();
|
||||
for (RelationDescription relationDescription : getRelationDescriptions(toEntityName)) {
|
||||
String relToEntityName = relationDescription.getToEntityName();
|
||||
String mappedByPropertyName = relationDescription.getMappedByPropertyName();
|
||||
if (entityAndParentsNames.contains(relToEntityName) && mappedByPropertyName != null && mappedByPropertyName.equals(fromPropertyName)) {
|
||||
toPropertyNames.add(relationDescription.getFromPropertyName());
|
||||
final Set<String> entityAndParentsNames = getEntityAndParentsNames( fromEntityName );
|
||||
final Set<String> toPropertyNames = new HashSet<String>();
|
||||
for ( RelationDescription relationDescription : getRelationDescriptions( toEntityName ) ) {
|
||||
final String relToEntityName = relationDescription.getToEntityName();
|
||||
final String mappedByPropertyName = relationDescription.getMappedByPropertyName();
|
||||
if ( entityAndParentsNames.contains( relToEntityName ) && mappedByPropertyName != null && mappedByPropertyName
|
||||
.equals( fromPropertyName ) ) {
|
||||
toPropertyNames.add( relationDescription.getFromPropertyName() );
|
||||
}
|
||||
}
|
||||
return toPropertyNames;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -34,93 +35,160 @@ import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
|||
* @author HernпїЅn Chanfreau
|
||||
*/
|
||||
public class EntityConfiguration {
|
||||
private String versionsEntityName;
|
||||
/** Holds the className for instantiation the configured entity */
|
||||
private String entityClassName;
|
||||
private String versionsEntityName;
|
||||
/**
|
||||
* Holds the className for instantiation the configured entity
|
||||
*/
|
||||
private String entityClassName;
|
||||
private IdMappingData idMappingData;
|
||||
private ExtendedPropertyMapper propertyMapper;
|
||||
// Maps from property name
|
||||
private Map<String, RelationDescription> relations;
|
||||
private String parentEntityName;
|
||||
private ExtendedPropertyMapper propertyMapper;
|
||||
// Maps from property name
|
||||
private Map<String, RelationDescription> relations;
|
||||
private String parentEntityName;
|
||||
|
||||
public EntityConfiguration(String versionsEntityName, String entityClassName, IdMappingData idMappingData,
|
||||
ExtendedPropertyMapper propertyMapper, String parentEntityName) {
|
||||
this.versionsEntityName = versionsEntityName;
|
||||
this.entityClassName = entityClassName;
|
||||
this.idMappingData = idMappingData;
|
||||
this.propertyMapper = propertyMapper;
|
||||
this.parentEntityName = parentEntityName;
|
||||
public EntityConfiguration(
|
||||
String versionsEntityName, String entityClassName, IdMappingData idMappingData,
|
||||
ExtendedPropertyMapper propertyMapper, String parentEntityName) {
|
||||
this.versionsEntityName = versionsEntityName;
|
||||
this.entityClassName = entityClassName;
|
||||
this.idMappingData = idMappingData;
|
||||
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) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE,
|
||||
toEntityName, null, idMapper, null, null, insertable));
|
||||
}
|
||||
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable) {
|
||||
relations.put(
|
||||
fromPropertyName,
|
||||
new RelationDescription(
|
||||
fromPropertyName,
|
||||
RelationType.TO_ONE,
|
||||
toEntityName,
|
||||
null,
|
||||
idMapper,
|
||||
null,
|
||||
null,
|
||||
insertable
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public void addToOneNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
|
||||
IdMapper idMapper) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE_NOT_OWNING,
|
||||
toEntityName, mappedByPropertyName, idMapper, null, null, true));
|
||||
}
|
||||
public void addToOneNotOwningRelation(
|
||||
String fromPropertyName,
|
||||
String mappedByPropertyName,
|
||||
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,
|
||||
IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper,
|
||||
PropertyMapper fakeBidirectionalRelationIndexMapper) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_NOT_OWNING,
|
||||
toEntityName, mappedByPropertyName, idMapper, fakeBidirectionalRelationMapper,
|
||||
fakeBidirectionalRelationIndexMapper, true));
|
||||
}
|
||||
public void addToManyNotOwningRelation(
|
||||
String fromPropertyName,
|
||||
String mappedByPropertyName,
|
||||
String toEntityName,
|
||||
IdMapper idMapper,
|
||||
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) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE,
|
||||
toEntityName, null, null, null, null, true));
|
||||
}
|
||||
public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) {
|
||||
relations.put(
|
||||
fromPropertyName,
|
||||
new RelationDescription(
|
||||
fromPropertyName,
|
||||
RelationType.TO_MANY_MIDDLE,
|
||||
toEntityName,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public void addToManyMiddleNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE_NOT_OWNING,
|
||||
toEntityName, mappedByPropertyName, null, null, null, true));
|
||||
}
|
||||
public void addToManyMiddleNotOwningRelation(
|
||||
String fromPropertyName,
|
||||
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) {
|
||||
return relations.get(propertyName) != null;
|
||||
}
|
||||
|
||||
public RelationDescription getRelationDescription(String propertyName) {
|
||||
return relations.get(propertyName);
|
||||
}
|
||||
public boolean isRelation(String propertyName) {
|
||||
return relations.get( propertyName ) != null;
|
||||
}
|
||||
|
||||
public IdMappingData getIdMappingData() {
|
||||
return idMappingData;
|
||||
}
|
||||
public RelationDescription getRelationDescription(String propertyName) {
|
||||
return relations.get( propertyName );
|
||||
}
|
||||
|
||||
public IdMapper getIdMapper() {
|
||||
return idMappingData.getIdMapper();
|
||||
}
|
||||
public IdMappingData getIdMappingData() {
|
||||
return idMappingData;
|
||||
}
|
||||
|
||||
public ExtendedPropertyMapper getPropertyMapper() {
|
||||
return propertyMapper;
|
||||
}
|
||||
public IdMapper getIdMapper() {
|
||||
return idMappingData.getIdMapper();
|
||||
}
|
||||
|
||||
public String getParentEntityName() {
|
||||
return parentEntityName;
|
||||
}
|
||||
public ExtendedPropertyMapper getPropertyMapper() {
|
||||
return propertyMapper;
|
||||
}
|
||||
|
||||
// For use by EntitiesConfigurations
|
||||
public String getParentEntityName() {
|
||||
return parentEntityName;
|
||||
}
|
||||
|
||||
String getVersionsEntityName() {
|
||||
return versionsEntityName;
|
||||
}
|
||||
// For use by EntitiesConfigurations
|
||||
|
||||
Iterable<RelationDescription> getRelationsIterator() {
|
||||
return relations.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the className for the configured entity
|
||||
*/
|
||||
public String getEntityClassName() {
|
||||
String getVersionsEntityName() {
|
||||
return versionsEntityName;
|
||||
}
|
||||
|
||||
Iterable<RelationDescription> getRelationsIterator() {
|
||||
return relations.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the className for the configured entity
|
||||
*/
|
||||
public String getEntityClassName() {
|
||||
return entityClassName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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
|
||||
*/
|
||||
public class EntityInstantiator {
|
||||
private final AuditConfiguration verCfg;
|
||||
private final AuditReaderImplementor versionsReader;
|
||||
private final AuditConfiguration verCfg;
|
||||
private final AuditReaderImplementor versionsReader;
|
||||
|
||||
public EntityInstantiator(AuditConfiguration verCfg, AuditReaderImplementor versionsReader) {
|
||||
this.verCfg = verCfg;
|
||||
this.versionsReader = versionsReader;
|
||||
}
|
||||
public EntityInstantiator(AuditConfiguration verCfg, AuditReaderImplementor versionsReader) {
|
||||
this.verCfg = verCfg;
|
||||
this.versionsReader = versionsReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 revision Revision at which this entity was read.
|
||||
* @return An entity instance, with versioned properties set as in the versionsEntity map, and proxies
|
||||
* created for collections.
|
||||
*/
|
||||
public Object createInstanceFromVersionsEntity(String entityName, Map versionsEntity, Number revision) {
|
||||
if (versionsEntity == null) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 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 revision Revision at which this entity was read.
|
||||
*
|
||||
* @return An entity instance, with versioned properties set as in the versionsEntity map, and proxies
|
||||
* created for collections.
|
||||
*/
|
||||
public Object createInstanceFromVersionsEntity(String entityName, Map versionsEntity, Number revision) {
|
||||
if ( versionsEntity == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The $type$ property holds the name of the (versions) entity
|
||||
String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName((String) versionsEntity.get("$type$"));
|
||||
// The $type$ property holds the name of the (versions) entity
|
||||
final String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName( (String) versionsEntity.get( "$type$" ) );
|
||||
|
||||
if (type != null) {
|
||||
entityName = type;
|
||||
}
|
||||
if ( type != null ) {
|
||||
entityName = type;
|
||||
}
|
||||
|
||||
// First mapping the primary key
|
||||
IdMapper idMapper = verCfg.getEntCfg().get(entityName).getIdMapper();
|
||||
Map originalId = (Map) versionsEntity.get(verCfg.getAuditEntCfg().getOriginalIdPropName());
|
||||
// First mapping the primary key
|
||||
final IdMapper idMapper = verCfg.getEntCfg().get( entityName ).getIdMapper();
|
||||
final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
|
||||
|
||||
// Fixes HHH-4751 issue (@IdClass with @ManyToOne relation mapping inside)
|
||||
// Note that identifiers are always audited
|
||||
// Replace identifier proxies if do not point to audit tables
|
||||
replaceNonAuditIdProxies(versionsEntity, revision);
|
||||
// Fixes HHH-4751 issue (@IdClass with @ManyToOne relation mapping inside)
|
||||
// Note that identifiers are always audited
|
||||
// Replace identifier proxies if do not point to audit tables
|
||||
replaceNonAuditIdProxies( versionsEntity, revision );
|
||||
|
||||
Object primaryKey = idMapper.mapToIdFromMap(originalId);
|
||||
final Object primaryKey = idMapper.mapToIdFromMap( originalId );
|
||||
|
||||
// Checking if the entity is in cache
|
||||
if (versionsReader.getFirstLevelCache().contains(entityName, revision, primaryKey)) {
|
||||
return versionsReader.getFirstLevelCache().get(entityName, revision, primaryKey);
|
||||
}
|
||||
// Checking if the entity is in cache
|
||||
if ( versionsReader.getFirstLevelCache().contains( entityName, revision, primaryKey ) ) {
|
||||
return versionsReader.getFirstLevelCache().get( entityName, revision, primaryKey );
|
||||
}
|
||||
|
||||
// If it is not in the cache, creating a new entity instance
|
||||
Object ret;
|
||||
try {
|
||||
EntityConfiguration entCfg = verCfg.getEntCfg().get(entityName);
|
||||
if(entCfg == null) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName);
|
||||
}
|
||||
// If it is not in the cache, creating a new entity instance
|
||||
Object ret;
|
||||
try {
|
||||
EntityConfiguration entCfg = verCfg.getEntCfg().get( entityName );
|
||||
if ( entCfg == null ) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
|
||||
}
|
||||
|
||||
Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
||||
ret = ReflectHelper.getDefaultConstructor(cls).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new AuditException(e);
|
||||
}
|
||||
final Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
||||
ret = ReflectHelper.getDefaultConstructor( cls ).newInstance();
|
||||
}
|
||||
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
|
||||
// relation is present (which is eagerly loaded).
|
||||
versionsReader.getFirstLevelCache().put(entityName, revision, primaryKey, ret);
|
||||
// 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).
|
||||
versionsReader.getFirstLevelCache().put( entityName, revision, primaryKey, ret );
|
||||
|
||||
verCfg.getEntCfg().get(entityName).getPropertyMapper().mapToEntityFromMap(verCfg, ret, versionsEntity, primaryKey,
|
||||
versionsReader, revision);
|
||||
idMapper.mapToEntityFromMap(ret, originalId);
|
||||
verCfg.getEntCfg().get( entityName ).getPropertyMapper().mapToEntityFromMap(
|
||||
verCfg,
|
||||
ret,
|
||||
versionsEntity,
|
||||
primaryKey,
|
||||
versionsReader,
|
||||
revision
|
||||
);
|
||||
idMapper.mapToEntityFromMap( ret, originalId );
|
||||
|
||||
// Put entity on entityName cache after mapping it from the map representation
|
||||
versionsReader.getFirstLevelCache().putOnEntityNameCache(primaryKey, revision, ret, entityName);
|
||||
|
||||
return ret;
|
||||
}
|
||||
// Put entity on entityName cache after mapping it from the map representation
|
||||
versionsReader.getFirstLevelCache().putOnEntityNameCache( primaryKey, revision, ret, entityName );
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public void addInstancesFromVersionsEntities(String entityName, Collection addTo, List<Map> versionsEntities, Number revision) {
|
||||
for (Map versionsEntity : versionsEntities) {
|
||||
addTo.add(createInstanceFromVersionsEntity(entityName, versionsEntity, revision));
|
||||
}
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private void replaceNonAuditIdProxies(Map versionsEntity, Number revision) {
|
||||
final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
|
||||
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() {
|
||||
return verCfg;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities;
|
||||
|
||||
import org.dom4j.Element;
|
||||
|
||||
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)
|
||||
*/
|
||||
public class IdMappingData {
|
||||
private final IdMapper idMapper;
|
||||
// Mapping which will be used to generate the entity
|
||||
private final Element xmlMapping;
|
||||
// Mapping which will be used to generate references to the entity in related entities
|
||||
private final Element xmlRelationMapping;
|
||||
private final IdMapper idMapper;
|
||||
// Mapping which will be used to generate the entity
|
||||
private final Element xmlMapping;
|
||||
// Mapping which will be used to generate references to the entity in related entities
|
||||
private final Element xmlRelationMapping;
|
||||
|
||||
public IdMappingData(IdMapper idMapper, Element xmlMapping, Element xmlRelationMapping) {
|
||||
this.idMapper = idMapper;
|
||||
this.xmlMapping = xmlMapping;
|
||||
this.xmlRelationMapping = xmlRelationMapping;
|
||||
}
|
||||
public IdMappingData(IdMapper idMapper, Element xmlMapping, Element xmlRelationMapping) {
|
||||
this.idMapper = idMapper;
|
||||
this.xmlMapping = xmlMapping;
|
||||
this.xmlRelationMapping = xmlRelationMapping;
|
||||
}
|
||||
|
||||
public IdMapper getIdMapper() {
|
||||
return idMapper;
|
||||
}
|
||||
public IdMapper getIdMapper() {
|
||||
return idMapper;
|
||||
}
|
||||
|
||||
public Element getXmlMapping() {
|
||||
return xmlMapping;
|
||||
}
|
||||
public Element getXmlMapping() {
|
||||
return xmlMapping;
|
||||
}
|
||||
|
||||
public Element getXmlRelationMapping() {
|
||||
return xmlRelationMapping;
|
||||
}
|
||||
public Element getXmlRelationMapping() {
|
||||
return xmlRelationMapping;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,76 +22,86 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities;
|
||||
|
||||
import org.hibernate.envers.ModificationStore;
|
||||
import org.hibernate.internal.util.compare.EqualsHelper;
|
||||
|
||||
/**
|
||||
* Holds information on a property that is audited.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class PropertyData {
|
||||
private final String name;
|
||||
private final String name;
|
||||
/**
|
||||
* Name of the property in the bean.
|
||||
*/
|
||||
private final String beanName;
|
||||
private final String accessType;
|
||||
private final ModificationStore store;
|
||||
private final String accessType;
|
||||
private final ModificationStore store;
|
||||
private boolean usingModifiedFlag;
|
||||
private String modifiedFlagName;
|
||||
|
||||
/**
|
||||
* Copies the given property data, except the name.
|
||||
* @param newName New name.
|
||||
* @param propertyData Property data to copy the rest of properties from.
|
||||
*/
|
||||
public PropertyData(String newName, PropertyData propertyData) {
|
||||
this.name = newName;
|
||||
/**
|
||||
* Copies the given property data, except the name.
|
||||
*
|
||||
* @param newName New name.
|
||||
* @param propertyData Property data to copy the rest of properties from.
|
||||
*/
|
||||
public PropertyData(String newName, PropertyData propertyData) {
|
||||
this.name = newName;
|
||||
this.beanName = propertyData.beanName;
|
||||
this.accessType = propertyData.accessType;
|
||||
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;
|
||||
}
|
||||
this.accessType = propertyData.accessType;
|
||||
this.store = propertyData.store;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Name of the property.
|
||||
* @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);
|
||||
* @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 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.modifiedFlagName = modifiedFlagName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getBeanName() {
|
||||
return beanName;
|
||||
}
|
||||
|
||||
public String getAccessType() {
|
||||
return accessType;
|
||||
}
|
||||
return accessType;
|
||||
}
|
||||
|
||||
public ModificationStore getStore() {
|
||||
return store;
|
||||
}
|
||||
public ModificationStore getStore() {
|
||||
return store;
|
||||
}
|
||||
|
||||
public boolean isUsingModifiedFlag() {
|
||||
return usingModifiedFlag;
|
||||
|
@ -103,18 +113,19 @@ public class PropertyData {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyData that = (PropertyData) o;
|
||||
|
||||
if (accessType != null ? !accessType.equals(that.accessType) : that.accessType != null) return false;
|
||||
if (beanName != null ? !beanName.equals(that.beanName) : that.beanName != null) return false;
|
||||
if (name != null ? !name.equals(that.name) : that.name != null) return false;
|
||||
if (store != that.store) return false;
|
||||
if (usingModifiedFlag != that.usingModifiedFlag) return false;
|
||||
|
||||
return true;
|
||||
final PropertyData that = (PropertyData) o;
|
||||
return usingModifiedFlag == that.usingModifiedFlag
|
||||
&& store == that.store
|
||||
&& EqualsHelper.equals( accessType, that.accessType )
|
||||
&& EqualsHelper.equals( beanName, that.beanName )
|
||||
&& EqualsHelper.equals( name, that.name );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,76 +22,78 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities;
|
||||
|
||||
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
*/
|
||||
public class RelationDescription {
|
||||
private final String fromPropertyName;
|
||||
private final RelationType relationType;
|
||||
private final String toEntityName;
|
||||
private final String mappedByPropertyName;
|
||||
private final IdMapper idMapper;
|
||||
private final PropertyMapper fakeBidirectionalRelationMapper;
|
||||
private final PropertyMapper fakeBidirectionalRelationIndexMapper;
|
||||
private final boolean insertable;
|
||||
private boolean bidirectional;
|
||||
private final String fromPropertyName;
|
||||
private final RelationType relationType;
|
||||
private final String toEntityName;
|
||||
private final String mappedByPropertyName;
|
||||
private final IdMapper idMapper;
|
||||
private final PropertyMapper fakeBidirectionalRelationMapper;
|
||||
private final PropertyMapper fakeBidirectionalRelationIndexMapper;
|
||||
private final boolean insertable;
|
||||
private boolean bidirectional;
|
||||
|
||||
public RelationDescription(String fromPropertyName, RelationType relationType, String toEntityName,
|
||||
String mappedByPropertyName, IdMapper idMapper,
|
||||
PropertyMapper fakeBidirectionalRelationMapper,
|
||||
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) {
|
||||
this.fromPropertyName = fromPropertyName;
|
||||
this.relationType = relationType;
|
||||
this.toEntityName = toEntityName;
|
||||
this.mappedByPropertyName = mappedByPropertyName;
|
||||
this.idMapper = idMapper;
|
||||
this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper;
|
||||
this.fakeBidirectionalRelationIndexMapper = fakeBidirectionalRelationIndexMapper;
|
||||
this.insertable = insertable;
|
||||
public RelationDescription(
|
||||
String fromPropertyName, RelationType relationType, String toEntityName,
|
||||
String mappedByPropertyName, IdMapper idMapper,
|
||||
PropertyMapper fakeBidirectionalRelationMapper,
|
||||
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) {
|
||||
this.fromPropertyName = fromPropertyName;
|
||||
this.relationType = relationType;
|
||||
this.toEntityName = toEntityName;
|
||||
this.mappedByPropertyName = mappedByPropertyName;
|
||||
this.idMapper = idMapper;
|
||||
this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper;
|
||||
this.fakeBidirectionalRelationIndexMapper = fakeBidirectionalRelationIndexMapper;
|
||||
this.insertable = insertable;
|
||||
|
||||
this.bidirectional = false;
|
||||
}
|
||||
this.bidirectional = false;
|
||||
}
|
||||
|
||||
public String getFromPropertyName() {
|
||||
return fromPropertyName;
|
||||
}
|
||||
public String getFromPropertyName() {
|
||||
return fromPropertyName;
|
||||
}
|
||||
|
||||
public RelationType getRelationType() {
|
||||
return relationType;
|
||||
}
|
||||
public RelationType getRelationType() {
|
||||
return relationType;
|
||||
}
|
||||
|
||||
public String getToEntityName() {
|
||||
return toEntityName;
|
||||
}
|
||||
public String getToEntityName() {
|
||||
return toEntityName;
|
||||
}
|
||||
|
||||
public String getMappedByPropertyName() {
|
||||
return mappedByPropertyName;
|
||||
}
|
||||
public String getMappedByPropertyName() {
|
||||
return mappedByPropertyName;
|
||||
}
|
||||
|
||||
public IdMapper getIdMapper() {
|
||||
return idMapper;
|
||||
}
|
||||
public IdMapper getIdMapper() {
|
||||
return idMapper;
|
||||
}
|
||||
|
||||
public PropertyMapper getFakeBidirectionalRelationMapper() {
|
||||
return fakeBidirectionalRelationMapper;
|
||||
}
|
||||
public PropertyMapper getFakeBidirectionalRelationMapper() {
|
||||
return fakeBidirectionalRelationMapper;
|
||||
}
|
||||
|
||||
public PropertyMapper getFakeBidirectionalRelationIndexMapper() {
|
||||
return fakeBidirectionalRelationIndexMapper;
|
||||
}
|
||||
public PropertyMapper getFakeBidirectionalRelationIndexMapper() {
|
||||
return fakeBidirectionalRelationIndexMapper;
|
||||
}
|
||||
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
public boolean isBidirectional() {
|
||||
return bidirectional;
|
||||
}
|
||||
public boolean isBidirectional() {
|
||||
return bidirectional;
|
||||
}
|
||||
|
||||
void setBidirectional(boolean bidirectional) {
|
||||
this.bidirectional = bidirectional;
|
||||
}
|
||||
void setBidirectional(boolean bidirectional) {
|
||||
this.bidirectional = bidirectional;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
*/
|
||||
public enum RelationType {
|
||||
/**
|
||||
* A single-reference-valued relation. The entity owns the relation.
|
||||
*/
|
||||
TO_ONE,
|
||||
/**
|
||||
* A single-reference-valued relation. The entity doesn't own the relation. It is directly mapped in the related
|
||||
* entity.
|
||||
*/
|
||||
TO_ONE_NOT_OWNING,
|
||||
/**
|
||||
* A collection-of-references-valued relation. The entity doesn't own the relation. It is directly mapped in the
|
||||
* related entity.
|
||||
*/
|
||||
TO_MANY_NOT_OWNING,
|
||||
/**
|
||||
* A collection-of-references-valued relation. The entity owns the relation. It is mapped using a middle table.
|
||||
*/
|
||||
TO_MANY_MIDDLE,
|
||||
/**
|
||||
* A collection-of-references-valued relation. The entity doesn't own the relation. It is mapped using a middle
|
||||
* table.
|
||||
*/
|
||||
TO_MANY_MIDDLE_NOT_OWNING
|
||||
/**
|
||||
* A single-reference-valued relation. The entity owns the relation.
|
||||
*/
|
||||
TO_ONE,
|
||||
/**
|
||||
* A single-reference-valued relation. The entity doesn't own the relation. It is directly mapped in the related
|
||||
* entity.
|
||||
*/
|
||||
TO_ONE_NOT_OWNING,
|
||||
/**
|
||||
* A collection-of-references-valued relation. The entity doesn't own the relation. It is directly mapped in the
|
||||
* related entity.
|
||||
*/
|
||||
TO_MANY_NOT_OWNING,
|
||||
/**
|
||||
* A collection-of-references-valued relation. The entity owns the relation. It is mapped using a middle table.
|
||||
*/
|
||||
TO_MANY_MIDDLE,
|
||||
/**
|
||||
* A collection-of-references-valued relation. The entity doesn't own the relation. It is mapped using a middle
|
||||
* table.
|
||||
*/
|
||||
TO_MANY_MIDDLE_NOT_OWNING
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.internal.util.compare.EqualsHelper;
|
||||
import org.hibernate.type.IntegerType;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
/**
|
||||
* A hibernate type for the {@link RevisionType} enum.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class RevisionTypeType implements UserType, Serializable {
|
||||
private static final long serialVersionUID = -1053201518229282688L;
|
||||
|
||||
private static final int[] SQL_TYPES = { Types.TINYINT };
|
||||
private static final long serialVersionUID = -1053201518229282688L;
|
||||
|
||||
public int[] sqlTypes() {
|
||||
return SQL_TYPES;
|
||||
}
|
||||
private static final int[] SQL_TYPES = {Types.TINYINT};
|
||||
|
||||
public Class returnedClass() {
|
||||
return RevisionType.class;
|
||||
}
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return SQL_TYPES;
|
||||
}
|
||||
|
||||
public RevisionType nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
|
||||
Integer representationInt = IntegerType.INSTANCE.nullSafeGet( resultSet, names[0], session );
|
||||
@Override
|
||||
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 ?
|
||||
null :
|
||||
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(
|
||||
preparedStatement,
|
||||
( value == null ? null : ((RevisionType) value).getRepresentation().intValue() ),
|
||||
(value == null ? null : ((RevisionType) value).getRepresentation().intValue()),
|
||||
index,
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public Object deepCopy(Object value) throws HibernateException{
|
||||
return value;
|
||||
}
|
||||
@Override
|
||||
public Object deepCopy(Object value) throws HibernateException {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
||||
return cached;
|
||||
}
|
||||
@Override
|
||||
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
||||
return cached;
|
||||
}
|
||||
|
||||
public Serializable disassemble(Object value) throws HibernateException {
|
||||
return (Serializable)value;
|
||||
}
|
||||
@Override
|
||||
public Serializable disassemble(Object value) throws HibernateException {
|
||||
return (Serializable) value;
|
||||
}
|
||||
|
||||
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
||||
return original;
|
||||
}
|
||||
@Override
|
||||
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
||||
return original;
|
||||
}
|
||||
|
||||
public int hashCode(Object x) throws HibernateException {
|
||||
return x.hashCode();
|
||||
}
|
||||
@Override
|
||||
public int hashCode(Object x) throws HibernateException {
|
||||
return x.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object x, Object y) throws HibernateException {
|
||||
//noinspection ObjectEquality
|
||||
if (x == y) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (null == x || null == y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return x.equals(y);
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object x, Object y) throws HibernateException {
|
||||
return EqualsHelper.equals( x, y );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
/*
|
||||
/*
|
||||
* 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,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License, v. 2.1.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT A
|
||||
* 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,
|
||||
* v.2.1 along with this distribution; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
* 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;
|
||||
|
||||
|
@ -25,14 +28,17 @@ import org.hibernate.metamodel.spi.TypeContributor;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* Envers specific TypeContributor
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class TypeContributorImpl implements TypeContributor {
|
||||
|
||||
@Override
|
||||
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
typeContributions.contributeType( new RevisionTypeType(),
|
||||
new String[] { RevisionTypeType.class.getName() } );
|
||||
typeContributions.contributeType(
|
||||
new RevisionTypeType(),
|
||||
new String[] { RevisionTypeType.class.getName() }
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperBuilder {
|
||||
private final PropertyData propertyData;
|
||||
private final MultiPropertyMapper delegate;
|
||||
private final PropertyData propertyData;
|
||||
private final MultiPropertyMapper delegate;
|
||||
private final Class componentClass;
|
||||
|
||||
public ComponentPropertyMapper(PropertyData propertyData, Class componentClass) {
|
||||
this.propertyData = propertyData;
|
||||
this.delegate = new MultiPropertyMapper();
|
||||
public ComponentPropertyMapper(PropertyData propertyData, Class componentClass) {
|
||||
this.propertyData = propertyData;
|
||||
this.delegate = new MultiPropertyMapper();
|
||||
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
|
||||
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));
|
||||
public void add(PropertyData propertyData) {
|
||||
delegate.add( propertyData );
|
||||
}
|
||||
|
||||
@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
|
||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||
if (propertyData.isUsingModifiedFlag()) {
|
||||
if ( propertyData.isUsingModifiedFlag() ) {
|
||||
boolean hasModifiedCollection = false;
|
||||
for (PropertyData propData : delegate.getProperties().keySet()) {
|
||||
if (collectionPropertyName.equals(propData.getName())) {
|
||||
for ( PropertyData propData : delegate.getProperties().keySet() ) {
|
||||
if ( collectionPropertyName.equals( propData.getName() ) ) {
|
||||
hasModifiedCollection = true;
|
||||
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) {
|
||||
if (data == null || obj == null) {
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public void mapToEntityFromMap(
|
||||
AuditConfiguration verCfg,
|
||||
Object obj,
|
||||
Map data,
|
||||
Object primaryKey,
|
||||
AuditReaderImplementor versionsReader,
|
||||
Number revision) {
|
||||
if ( data == null || obj == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (propertyData.getBeanName() == null) {
|
||||
// If properties are not encapsulated in a component but placed directly in a class
|
||||
// (e.g. by applying <properties> tag).
|
||||
delegate.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
||||
return;
|
||||
}
|
||||
if ( propertyData.getBeanName() == null ) {
|
||||
// If properties are not encapsulated in a component but placed directly in a class
|
||||
// (e.g. by applying <properties> tag).
|
||||
delegate.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
|
||||
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.
|
||||
boolean allNullAndSingle = true;
|
||||
for (Map.Entry<PropertyData, PropertyMapper> property : delegate.getProperties().entrySet()) {
|
||||
if (data.get(property.getKey().getName()) != null || !(property.getValue() instanceof SinglePropertyMapper)) {
|
||||
for ( Map.Entry<PropertyData, PropertyMapper> property : delegate.getProperties().entrySet() ) {
|
||||
if ( data.get(
|
||||
property.getKey()
|
||||
.getName()
|
||||
) != null || !(property.getValue() instanceof SinglePropertyMapper) ) {
|
||||
allNullAndSingle = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allNullAndSingle) {
|
||||
if ( allNullAndSingle ) {
|
||||
// single property, but default value need not be null, so we'll set it to null anyway
|
||||
setter.set(obj, null, null);
|
||||
} else {
|
||||
setter.set( obj, null, null );
|
||||
}
|
||||
else {
|
||||
// set the component
|
||||
try {
|
||||
Object subObj = ReflectHelper.getDefaultConstructor(componentClass).newInstance();
|
||||
setter.set(obj, subObj, null);
|
||||
delegate.mapToEntityFromMap(verCfg, subObj, data, primaryKey, versionsReader, revision);
|
||||
} catch (Exception e) {
|
||||
throw new AuditException(e);
|
||||
final Object subObj = ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
|
||||
setter.set( obj, subObj, null );
|
||||
delegate.mapToEntityFromMap( verCfg, subObj, data, primaryKey, versionsReader, revision );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AuditException( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
return delegate.mapCollectionChanges(session, referencingPropertyName, newColl, oldColl, id);
|
||||
}
|
||||
@Override
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||
SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
return delegate.mapCollectionChanges( session, referencingPropertyName, newColl, oldColl, id );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PropertyData, PropertyMapper> getProperties() {
|
||||
return delegate.getProperties();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
|
||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass);
|
||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
|
||||
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
|
||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass);
|
||||
|
||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
|
||||
|
||||
public Map<PropertyData, PropertyMapper> getProperties();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
@ -30,5 +31,10 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public class MultiPropertyMapper implements ExtendedPropertyMapper {
|
||||
protected final Map<PropertyData, PropertyMapper> properties;
|
||||
private final Map<String, PropertyData> propertyDatas;
|
||||
protected final Map<PropertyData, PropertyMapper> properties;
|
||||
private final Map<String, PropertyData> propertyDatas;
|
||||
|
||||
public MultiPropertyMapper() {
|
||||
properties = 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 MultiPropertyMapper() {
|
||||
properties = Tools.newHashMap();
|
||||
propertyDatas = Tools.newHashMap();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void add(PropertyData propertyData) {
|
||||
final SinglePropertyMapper single = new SinglePropertyMapper();
|
||||
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.
|
||||
String delegatePropertyName;
|
||||
|
||||
// Checking if the property name doesn't reference a collection in a component - then the name will containa a .
|
||||
int dotIndex = referencingPropertyName.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
final int dotIndex = referencingPropertyName.indexOf( '.' );
|
||||
if ( dotIndex != -1 ) {
|
||||
// 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
|
||||
String propertyInComponentName = MappingTools.createComponentPrefix(componentName)
|
||||
+ referencingPropertyName.substring(dotIndex+1);
|
||||
final String propertyInComponentName = MappingTools.createComponentPrefix( componentName )
|
||||
+ referencingPropertyName.substring( dotIndex + 1 );
|
||||
|
||||
// We need to get the mapper for the component.
|
||||
referencingPropertyName = componentName;
|
||||
// As this is a component, we delegate to the property in the component.
|
||||
delegatePropertyName = propertyInComponentName;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// If this is not a component, we delegate to the same property.
|
||||
delegatePropertyName = referencingPropertyName;
|
||||
}
|
||||
return Pair.make(properties.get(propertyDatas.get(referencingPropertyName)), delegatePropertyName);
|
||||
return Pair.make( properties.get( propertyDatas.get( referencingPropertyName ) ), delegatePropertyName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(collectionPropertyName);
|
||||
PropertyMapper mapper = pair.getFirst();
|
||||
if (mapper != null) {
|
||||
mapper.mapModifiedFlagsToMapForCollectionChange(pair.getSecond(), data);
|
||||
final Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName( collectionPropertyName );
|
||||
final PropertyMapper mapper = pair.getFirst();
|
||||
if ( mapper != null ) {
|
||||
mapper.mapModifiedFlagsToMapForCollectionChange( pair.getSecond(), data );
|
||||
}
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
|
||||
String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName);
|
||||
PropertyMapper mapper = pair.getFirst();
|
||||
if (mapper != null) {
|
||||
return mapper.mapCollectionChanges(session, pair.getSecond(), newColl, oldColl, id);
|
||||
} else {
|
||||
@Override
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||
SessionImplementor session,
|
||||
String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
final Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName( referencingPropertyName );
|
||||
final PropertyMapper mapper = pair.getFirst();
|
||||
if ( mapper != null ) {
|
||||
return mapper.mapCollectionChanges( session, pair.getSecond(), newColl, oldColl, id );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PropertyData, PropertyMapper> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
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
|
||||
* modified in the collection).
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class PersistentCollectionChangeData {
|
||||
private final String entityName;
|
||||
private final Map<String, Object> data;
|
||||
private final Object changedElement;
|
||||
private final String entityName;
|
||||
private final Map<String, Object> data;
|
||||
private final Object changedElement;
|
||||
|
||||
public PersistentCollectionChangeData(String entityName, Map<String, Object> data, Object changedElement) {
|
||||
this.entityName = entityName;
|
||||
this.data = data;
|
||||
this.changedElement = changedElement;
|
||||
}
|
||||
public PersistentCollectionChangeData(String entityName, Map<String, Object> data, Object changedElement) {
|
||||
this.entityName = entityName;
|
||||
this.data = data;
|
||||
this.changedElement = changedElement;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Name of the (middle) entity that holds the collection data.
|
||||
*/
|
||||
public String getEntityName() {
|
||||
return entityName;
|
||||
}
|
||||
/**
|
||||
* @return Name of the (middle) entity that holds the collection data.
|
||||
*/
|
||||
public String getEntityName() {
|
||||
return entityName;
|
||||
}
|
||||
|
||||
public Map<String, Object> getData() {
|
||||
return data;
|
||||
}
|
||||
public Map<String, Object> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The affected element, which was changed (added, removed, modified) in the collection.
|
||||
*/
|
||||
public Object getChangedElement() {
|
||||
if (changedElement instanceof Pair) {
|
||||
return ((Pair) changedElement).getSecond();
|
||||
}
|
||||
/**
|
||||
* @return The affected element, which was changed (added, removed, modified) in the collection.
|
||||
*/
|
||||
public Object getChangedElement() {
|
||||
if ( changedElement instanceof Pair ) {
|
||||
return ((Pair) changedElement).getSecond();
|
||||
}
|
||||
|
||||
if (changedElement instanceof Map.Entry) {
|
||||
return ((Map.Entry) changedElement).getValue();
|
||||
}
|
||||
if ( changedElement instanceof Map.Entry ) {
|
||||
return ((Map.Entry) changedElement).getValue();
|
||||
}
|
||||
|
||||
return changedElement;
|
||||
}
|
||||
return changedElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Index of the affected element, or {@code null} if the collection isn't indexed.
|
||||
*/
|
||||
public Object getChangedElementIndex() {
|
||||
if (changedElement instanceof Pair) {
|
||||
return ((Pair) changedElement).getFirst();
|
||||
}
|
||||
/**
|
||||
* @return Index of the affected element, or {@code null} if the collection isn't indexed.
|
||||
*/
|
||||
public Object getChangedElementIndex() {
|
||||
if ( changedElement instanceof Pair ) {
|
||||
return ((Pair) changedElement).getFirst();
|
||||
}
|
||||
|
||||
if (changedElement instanceof Map.Entry) {
|
||||
return ((Map.Entry) changedElement).getKey();
|
||||
}
|
||||
if ( changedElement instanceof Map.Entry ) {
|
||||
return ((Map.Entry) changedElement).getKey();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -36,41 +37,53 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
|||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||
*/
|
||||
public interface PropertyMapper {
|
||||
/**
|
||||
* Maps properties to the given map, basing on differences between properties of new and old objects.
|
||||
* @param session The current session.
|
||||
/**
|
||||
* Maps properties to the given map, basing on differences between properties of new and old objects.
|
||||
*
|
||||
* @param session The current session.
|
||||
* @param data Data to map to.
|
||||
* @param newObj New 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.
|
||||
*/
|
||||
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.
|
||||
* @param verCfg Versions configuration.
|
||||
* @param obj Object to map to.
|
||||
* @param data Data to map from.
|
||||
* @param primaryKey Primary key of the object to which we map (for 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);
|
||||
/**
|
||||
* Maps properties from the given map to the given object.
|
||||
*
|
||||
* @param verCfg Versions configuration.
|
||||
* @param obj Object to map to.
|
||||
* @param data Data to map from.
|
||||
* @param primaryKey Primary key of the object to which we map (for 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);
|
||||
|
||||
/**
|
||||
* Maps collection changes.
|
||||
/**
|
||||
* Maps collection changes.
|
||||
*
|
||||
* @param session The current session.
|
||||
* @param referencingPropertyName Name of the field, which holds the collection in the entity.
|
||||
* @param newColl New collection, after updates.
|
||||
* @param oldColl Old collection, before updates.
|
||||
* @param id Id of the object owning the collection.
|
||||
* @return List of changes that need to be performed on the persistent store.
|
||||
*/
|
||||
List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id);
|
||||
* @param referencingPropertyName Name of the field, which holds the collection in the entity.
|
||||
* @param newColl New collection, after updates.
|
||||
* @param oldColl Old collection, before updates.
|
||||
* @param id Id of the object owning the collection.
|
||||
*
|
||||
* @return List of changes that need to be performed on the persistent store.
|
||||
*/
|
||||
List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,11 +22,12 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper;
|
||||
|
||||
import org.hibernate.envers.internal.entities.PropertyData;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public interface SimpleMapperBuilder {
|
||||
public void add(PropertyData propertyData);
|
||||
public interface SimpleMapperBuilder {
|
||||
public void add(PropertyData propertyData);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -43,40 +43,53 @@ import org.hibernate.property.Setter;
|
|||
|
||||
/**
|
||||
* TODO: diff
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||
*/
|
||||
public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder {
|
||||
private PropertyData propertyData;
|
||||
private PropertyData propertyData;
|
||||
|
||||
public SinglePropertyMapper(PropertyData propertyData) {
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
public SinglePropertyMapper(PropertyData propertyData) {
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
public SinglePropertyMapper() {
|
||||
}
|
||||
|
||||
@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));
|
||||
public void add(PropertyData propertyData) {
|
||||
if ( this.propertyData != null ) {
|
||||
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 mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
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);
|
||||
@Override
|
||||
public void mapToEntityFromMap(
|
||||
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
if ( data == null || obj == null ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (cls == null) {
|
||||
throw new HibernateException("No field found for property: " + propertyData.getName());
|
||||
if ( cls == null ) {
|
||||
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
|
||||
// Trying to look up the field
|
||||
try {
|
||||
return cls.getDeclaredField(propertyData.getBeanName()).getType().isPrimitive();
|
||||
} catch (NoSuchFieldException e) {
|
||||
return isPrimitive(setter, propertyData, cls.getSuperclass());
|
||||
return cls.getDeclaredField( propertyData.getBeanName() ).getType().isPrimitive();
|
||||
}
|
||||
} else {
|
||||
catch (NoSuchFieldException e) {
|
||||
return isPrimitive( setter, propertyData, cls.getSuperclass() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return setter.getMethod().getParameterTypes()[0].isPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor sessionImplementor,
|
||||
String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||
SessionImplementor sessionImplementor,
|
||||
String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
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
|
||||
* should be the mapper of the subclass.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||
*/
|
||||
public class SubclassPropertyMapper implements ExtendedPropertyMapper {
|
||||
private ExtendedPropertyMapper main;
|
||||
private ExtendedPropertyMapper parentMapper;
|
||||
private ExtendedPropertyMapper main;
|
||||
private ExtendedPropertyMapper parentMapper;
|
||||
|
||||
public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMapper parentMapper) {
|
||||
this.main = main;
|
||||
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;
|
||||
}
|
||||
public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMapper parentMapper) {
|
||||
this.main = main;
|
||||
this.parentMapper = parentMapper;
|
||||
}
|
||||
|
||||
@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);
|
||||
public boolean map(
|
||||
SessionImplementor session,
|
||||
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
|
||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||
parentMapper.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data);
|
||||
main.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data);
|
||||
parentMapper.mapModifiedFlagsToMapForCollectionChange( collectionPropertyName, data );
|
||||
main.mapModifiedFlagsToMapForCollectionChange( collectionPropertyName, data );
|
||||
}
|
||||
|
||||
public void mapToEntityFromMap(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);
|
||||
}
|
||||
@Override
|
||||
public void mapToEntityFromMap(
|
||||
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,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
|
||||
session, referencingPropertyName, newColl, oldColl, id);
|
||||
@Override
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||
SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
final List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
|
||||
session,
|
||||
referencingPropertyName,
|
||||
newColl,
|
||||
oldColl,
|
||||
id
|
||||
);
|
||||
|
||||
List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
|
||||
session, referencingPropertyName, newColl, oldColl, id);
|
||||
final List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
|
||||
session,
|
||||
referencingPropertyName,
|
||||
newColl,
|
||||
oldColl,
|
||||
id
|
||||
);
|
||||
|
||||
if (parentCollectionChanges == null) {
|
||||
return mainCollectionChanges;
|
||||
} else {
|
||||
if(mainCollectionChanges != null) {
|
||||
parentCollectionChanges.addAll(mainCollectionChanges);
|
||||
}
|
||||
if ( parentCollectionChanges == null ) {
|
||||
return mainCollectionChanges;
|
||||
}
|
||||
else {
|
||||
if ( mainCollectionChanges != null ) {
|
||||
parentCollectionChanges.addAll( mainCollectionChanges );
|
||||
}
|
||||
return parentCollectionChanges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
||||
return main.addComponent(propertyData, componentClass);
|
||||
}
|
||||
@Override
|
||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
|
||||
return main.addComponent( propertyData, componentClass );
|
||||
}
|
||||
|
||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
||||
main.addComposite(propertyData, propertyMapper);
|
||||
}
|
||||
@Override
|
||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
|
||||
main.addComposite( propertyData, propertyMapper );
|
||||
}
|
||||
|
||||
public void add(PropertyData propertyData) {
|
||||
main.add(propertyData);
|
||||
}
|
||||
@Override
|
||||
public void add(PropertyData propertyData) {
|
||||
main.add( propertyData );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PropertyData, PropertyMapper> getProperties() {
|
||||
final Map<PropertyData, PropertyMapper> joinedProperties = new HashMap<PropertyData, PropertyMapper>();
|
||||
joinedProperties.putAll(parentMapper.getProperties());
|
||||
joinedProperties.putAll(main.getProperties());
|
||||
joinedProperties.putAll( parentMapper.getProperties() );
|
||||
joinedProperties.putAll( main.getProperties() );
|
||||
return joinedProperties;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public abstract class AbstractCompositeIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
||||
protected Map<PropertyData, SingleIdMapper> ids;
|
||||
protected Class compositeIdClass;
|
||||
protected Map<PropertyData, SingleIdMapper> ids;
|
||||
protected Class compositeIdClass;
|
||||
|
||||
protected AbstractCompositeIdMapper(Class compositeIdClass) {
|
||||
ids = Tools.newLinkedHashMap();
|
||||
this.compositeIdClass = compositeIdClass;
|
||||
}
|
||||
protected AbstractCompositeIdMapper(Class compositeIdClass) {
|
||||
ids = Tools.newLinkedHashMap();
|
||||
this.compositeIdClass = compositeIdClass;
|
||||
}
|
||||
|
||||
public void add(PropertyData propertyData) {
|
||||
ids.put(propertyData, new SingleIdMapper(propertyData));
|
||||
}
|
||||
@Override
|
||||
public void add(PropertyData propertyData) {
|
||||
ids.put( propertyData, new SingleIdMapper( propertyData ) );
|
||||
}
|
||||
|
||||
public Object mapToIdFromMap(Map data) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object mapToIdFromMap(Map data) {
|
||||
if ( data == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object ret;
|
||||
try {
|
||||
ret = ReflectHelper.getDefaultConstructor(compositeIdClass).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new AuditException(e);
|
||||
}
|
||||
final Object ret;
|
||||
try {
|
||||
ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AuditException( e );
|
||||
}
|
||||
|
||||
for (SingleIdMapper mapper : ids.values()) {
|
||||
if (!mapper.mapToEntityFromMap(ret, data)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
for ( SingleIdMapper mapper : ids.values() ) {
|
||||
if ( !mapper.mapToEntityFromMap( ret, data ) ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.id;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -31,69 +32,96 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
|||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public abstract class AbstractIdMapper implements IdMapper {
|
||||
private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) {
|
||||
if (paramDatas.size() > 1) {
|
||||
return parameters.addSubParameters("and");
|
||||
} else {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) {
|
||||
if ( paramDatas.size() > 1 ) {
|
||||
return parameters.addSubParameters( "and" );
|
||||
}
|
||||
else {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
public void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
|
||||
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
|
||||
@Override
|
||||
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) {
|
||||
parametersToUse.addWhere(paramData.getProperty(prefix1), false, "=", paramData.getProperty(prefix2), false);
|
||||
}
|
||||
}
|
||||
for ( QueryParameterData paramData : paramDatas ) {
|
||||
parametersToUse.addWhere(
|
||||
paramData.getProperty( prefix1 ),
|
||||
false,
|
||||
"=",
|
||||
paramData.getProperty( prefix2 ),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) {
|
||||
List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId(null);
|
||||
List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId(null);
|
||||
@Override
|
||||
public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) {
|
||||
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();
|
||||
Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
|
||||
while (paramDataIter1.hasNext()) {
|
||||
QueryParameterData paramData1 = paramDataIter1.next();
|
||||
QueryParameterData paramData2 = paramDataIter2.next();
|
||||
final Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator();
|
||||
final Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
|
||||
while ( paramDataIter1.hasNext() ) {
|
||||
final QueryParameterData paramData1 = paramDataIter1.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) {
|
||||
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(id);
|
||||
@Override
|
||||
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) {
|
||||
if (paramData.getValue() == null) {
|
||||
handleNullValue(parametersToUse, paramData.getProperty(prefix), equals);
|
||||
} else {
|
||||
parametersToUse.addWhereWithParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( QueryParameterData paramData : paramDatas ) {
|
||||
if ( paramData.getValue() == null ) {
|
||||
handleNullValue( parametersToUse, paramData.getProperty( prefix ), equals );
|
||||
}
|
||||
else {
|
||||
parametersToUse.addWhereWithParam(
|
||||
paramData.getProperty( prefix ),
|
||||
equals ? "=" : "<>",
|
||||
paramData.getValue()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals) {
|
||||
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
|
||||
@Override
|
||||
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) {
|
||||
parametersToUse.addWhereWithNamedParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getQueryParameterName());
|
||||
}
|
||||
}
|
||||
for ( QueryParameterData paramData : paramDatas ) {
|
||||
parametersToUse.addWhereWithNamedParam(
|
||||
paramData.getProperty( prefix ),
|
||||
equals ? "=" : "<>",
|
||||
paramData.getQueryParameterName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNullValue(Parameters parameters, String propertyName, boolean equals) {
|
||||
if (equals) {
|
||||
parameters.addNullRestriction(propertyName, equals);
|
||||
} else {
|
||||
parameters.addNotNullRestriction(propertyName, equals);
|
||||
}
|
||||
}
|
||||
private void handleNullValue(Parameters parameters, String propertyName, boolean equals) {
|
||||
if ( equals ) {
|
||||
parameters.addNullRestriction( propertyName, equals );
|
||||
}
|
||||
else {
|
||||
parameters.addNotNullRestriction( propertyName, equals );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
||||
private PropertyData idPropertyData;
|
||||
private PropertyData idPropertyData;
|
||||
|
||||
public EmbeddedIdMapper(PropertyData idPropertyData, Class compositeIdClass) {
|
||||
super(compositeIdClass);
|
||||
public EmbeddedIdMapper(PropertyData idPropertyData, Class compositeIdClass) {
|
||||
super( compositeIdClass );
|
||||
|
||||
this.idPropertyData = idPropertyData;
|
||||
}
|
||||
this.idPropertyData = idPropertyData;
|
||||
}
|
||||
|
||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||
for (IdMapper idMapper : ids.values()) {
|
||||
idMapper.mapToMapFromEntity(data, obj);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||
for ( IdMapper idMapper : ids.values() ) {
|
||||
idMapper.mapToMapFromEntity( data, obj );
|
||||
}
|
||||
}
|
||||
|
||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||
if ( obj == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyData);
|
||||
mapToMapFromId(data, getter.get(obj));
|
||||
}
|
||||
final Getter getter = ReflectionTools.getGetter( obj.getClass(), idPropertyData );
|
||||
mapToMapFromId( data, getter.get( obj ) );
|
||||
}
|
||||
|
||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||
if (data == null || obj == null) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||
if ( data == null || obj == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyData);
|
||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), idPropertyData);
|
||||
final Getter getter = ReflectionTools.getGetter( obj.getClass(), idPropertyData );
|
||||
final Setter setter = ReflectionTools.getSetter( obj.getClass(), idPropertyData );
|
||||
|
||||
try {
|
||||
Object subObj = ReflectHelper.getDefaultConstructor( getter.getReturnType() ).newInstance();
|
||||
try {
|
||||
final Object subObj = ReflectHelper.getDefaultConstructor( getter.getReturnType() ).newInstance();
|
||||
|
||||
boolean ret = true;
|
||||
for (IdMapper idMapper : ids.values()) {
|
||||
ret &= idMapper.mapToEntityFromMap(subObj, data);
|
||||
}
|
||||
boolean ret = true;
|
||||
for ( IdMapper idMapper : ids.values() ) {
|
||||
ret &= idMapper.mapToEntityFromMap( subObj, data );
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
setter.set(obj, subObj, null);
|
||||
}
|
||||
if ( ret ) {
|
||||
setter.set( obj, subObj, null );
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (Exception e) {
|
||||
throw new AuditException(e);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AuditException( e );
|
||||
}
|
||||
}
|
||||
|
||||
public IdMapper prefixMappedProperties(String prefix) {
|
||||
EmbeddedIdMapper ret = new EmbeddedIdMapper(idPropertyData, compositeIdClass);
|
||||
@Override
|
||||
public IdMapper prefixMappedProperties(String prefix) {
|
||||
final EmbeddedIdMapper ret = new EmbeddedIdMapper( idPropertyData, compositeIdClass );
|
||||
|
||||
for (PropertyData propertyData : ids.keySet()) {
|
||||
String propertyName = propertyData.getName();
|
||||
ret.ids.put(propertyData, new SingleIdMapper(new PropertyData(prefix + propertyName, propertyData)));
|
||||
}
|
||||
for ( PropertyData propertyData : ids.keySet() ) {
|
||||
final String propertyName = propertyData.getName();
|
||||
ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Object mapToIdFromEntity(Object data) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object mapToIdFromEntity(Object data) {
|
||||
if ( data == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Getter getter = ReflectionTools.getGetter(data.getClass(), idPropertyData);
|
||||
return getter.get(data);
|
||||
}
|
||||
final Getter getter = ReflectionTools.getGetter( data.getClass(), idPropertyData );
|
||||
return getter.get( data );
|
||||
}
|
||||
|
||||
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
||||
Map<String, Object> data = new LinkedHashMap<String, Object>();
|
||||
mapToMapFromId(data, obj);
|
||||
@Override
|
||||
public List<QueryParameterData> mapToQueryParametersFromId(Object 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()) {
|
||||
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue()));
|
||||
}
|
||||
for ( Map.Entry<String, Object> propertyData : data.entrySet() ) {
|
||||
ret.add( new QueryParameterData( propertyData.getKey(), propertyData.getValue() ) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.id;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -31,73 +32,81 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
|||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
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 data Data to map.
|
||||
* @return True if data was mapped; false otherwise (when the id is {@code null}).
|
||||
*/
|
||||
boolean mapToEntityFromMap(Object obj, Map data);
|
||||
/**
|
||||
* @param obj Object to map to.
|
||||
* @param data Data to map.
|
||||
*
|
||||
* @return True if data was mapped; false otherwise (when the id is {@code null}).
|
||||
*/
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
IdMapper prefixMappedProperties(String prefix);
|
||||
/**
|
||||
* Creates a mapper with all mapped properties prefixed. A mapped property is a property which
|
||||
* 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.
|
||||
*/
|
||||
IdMapper prefixMappedProperties(String prefix);
|
||||
|
||||
/**
|
||||
* @param obj Id from which to map.
|
||||
* @return A set parameter data, needed to build a query basing on the given id.
|
||||
*/
|
||||
List<QueryParameterData> mapToQueryParametersFromId(Object obj);
|
||||
/**
|
||||
* @param obj Id from which to map.
|
||||
*
|
||||
* @return A set parameter data, needed to build a query basing on the given id.
|
||||
*/
|
||||
List<QueryParameterData> mapToQueryParametersFromId(Object obj);
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* @param parameters Parameters, to which to add the statements.
|
||||
* @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);
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @param parameters Parameters, to which to add the statements.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* (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 mapper2 Second mapper for the same entity, which will be used to get properties for the right side
|
||||
* 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);
|
||||
/**
|
||||
* 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
|
||||
* (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 mapper2 Second mapper for the same entity, which will be used to get properties for the right side
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param parameters Parameters, to which to add the statements.
|
||||
* @param id Value of id.
|
||||
* @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);
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param parameters Parameters, to which to add the statements.
|
||||
* @param id Value of id.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 equals Should this query express the "=" relation or the "<>" relation.
|
||||
*/
|
||||
void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals);
|
||||
/**
|
||||
* 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
|
||||
* 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 equals Should this query express the "=" relation or the "<>" relation.
|
||||
*/
|
||||
void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
||||
public MultipleIdMapper(Class compositeIdClass) {
|
||||
super(compositeIdClass);
|
||||
}
|
||||
public MultipleIdMapper(Class compositeIdClass) {
|
||||
super( compositeIdClass );
|
||||
}
|
||||
|
||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||
for (IdMapper idMapper : ids.values()) {
|
||||
idMapper.mapToMapFromEntity(data, obj);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||
for ( IdMapper idMapper : ids.values() ) {
|
||||
idMapper.mapToMapFromEntity( data, obj );
|
||||
}
|
||||
}
|
||||
|
||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||
mapToMapFromId(data, obj);
|
||||
}
|
||||
@Override
|
||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||
mapToMapFromId( data, obj );
|
||||
}
|
||||
|
||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||
boolean ret = true;
|
||||
for (IdMapper idMapper : ids.values()) {
|
||||
ret &= idMapper.mapToEntityFromMap(obj, data);
|
||||
}
|
||||
@Override
|
||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||
boolean ret = true;
|
||||
for ( IdMapper idMapper : ids.values() ) {
|
||||
ret &= idMapper.mapToEntityFromMap( obj, data );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public IdMapper prefixMappedProperties(String prefix) {
|
||||
MultipleIdMapper ret = new MultipleIdMapper(compositeIdClass);
|
||||
@Override
|
||||
public IdMapper prefixMappedProperties(String prefix) {
|
||||
final MultipleIdMapper ret = new MultipleIdMapper( compositeIdClass );
|
||||
|
||||
for (PropertyData propertyData : ids.keySet()) {
|
||||
String propertyName = propertyData.getName();
|
||||
ret.ids.put(propertyData, new SingleIdMapper(new PropertyData(prefix + propertyName, propertyData)));
|
||||
}
|
||||
for ( PropertyData propertyData : ids.keySet() ) {
|
||||
final String propertyName = propertyData.getName();
|
||||
ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Object mapToIdFromEntity(Object data) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object mapToIdFromEntity(Object data) {
|
||||
if ( data == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object ret;
|
||||
try {
|
||||
ret = ReflectHelper.getDefaultConstructor(compositeIdClass).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new AuditException(e);
|
||||
}
|
||||
final Object ret;
|
||||
try {
|
||||
ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AuditException( e );
|
||||
}
|
||||
|
||||
for (SingleIdMapper mapper : ids.values()) {
|
||||
mapper.mapToEntityFromEntity(ret, data);
|
||||
}
|
||||
for ( SingleIdMapper mapper : ids.values() ) {
|
||||
mapper.mapToEntityFromEntity( ret, data );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
||||
Map<String, Object> data = new LinkedHashMap<String, Object>();
|
||||
mapToMapFromId(data, obj);
|
||||
@Override
|
||||
public List<QueryParameterData> mapToQueryParametersFromId(Object 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()) {
|
||||
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue()));
|
||||
}
|
||||
for ( Map.Entry<String, Object> propertyData : data.entrySet() ) {
|
||||
ret.add( new QueryParameterData( propertyData.getKey(), propertyData.getValue() ) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,53 +22,58 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.id;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.internal.util.compare.EqualsHelper;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class QueryParameterData {
|
||||
private String flatEntityPropertyName;
|
||||
private Object value;
|
||||
private String flatEntityPropertyName;
|
||||
private Object value;
|
||||
|
||||
public QueryParameterData(String flatEntityPropertyName, Object value) {
|
||||
this.flatEntityPropertyName = flatEntityPropertyName;
|
||||
this.value = value;
|
||||
}
|
||||
public QueryParameterData(String flatEntityPropertyName, Object value) {
|
||||
this.flatEntityPropertyName = flatEntityPropertyName;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getProperty(String prefix) {
|
||||
if (prefix != null) {
|
||||
return prefix + "." + flatEntityPropertyName;
|
||||
} else {
|
||||
return flatEntityPropertyName;
|
||||
}
|
||||
}
|
||||
public String getProperty(String prefix) {
|
||||
if ( prefix != null ) {
|
||||
return prefix + "." + flatEntityPropertyName;
|
||||
}
|
||||
else {
|
||||
return flatEntityPropertyName;
|
||||
}
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setParameterValue(Query query) {
|
||||
query.setParameter(flatEntityPropertyName, value);
|
||||
}
|
||||
public void setParameterValue(Query query) {
|
||||
query.setParameter( flatEntityPropertyName, value );
|
||||
}
|
||||
|
||||
public String getQueryParameterName() {
|
||||
return flatEntityPropertyName;
|
||||
}
|
||||
public String getQueryParameterName() {
|
||||
return flatEntityPropertyName;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof QueryParameterData)) return false;
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
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)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (flatEntityPropertyName != null ? flatEntityPropertyName.hashCode() : 0);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (flatEntityPropertyName != null ? flatEntityPropertyName.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.id;
|
||||
|
||||
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
||||
private PropertyData propertyData;
|
||||
private PropertyData propertyData;
|
||||
|
||||
public SingleIdMapper() {
|
||||
}
|
||||
public SingleIdMapper() {
|
||||
}
|
||||
|
||||
public SingleIdMapper(PropertyData propertyData) {
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
public SingleIdMapper(PropertyData propertyData) {
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
|
||||
public void add(PropertyData propertyData) {
|
||||
if (this.propertyData != null) {
|
||||
throw new AuditException("Only one property can be added!");
|
||||
}
|
||||
@Override
|
||||
public void add(PropertyData propertyData) {
|
||||
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) {
|
||||
if (data == null || obj == null) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean mapToEntityFromMap(Object obj, Map data) {
|
||||
if ( data == null || obj == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object value = data.get(propertyData.getName());
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
final Object value = data.get( propertyData.getName() );
|
||||
if ( value == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
|
||||
setter.set(obj, value, null);
|
||||
final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
|
||||
setter.set( obj, value, null );
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object mapToIdFromMap(Map data) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object mapToIdFromMap(Map data) {
|
||||
if ( data == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return data.get(propertyData.getName());
|
||||
}
|
||||
return data.get( propertyData.getName() );
|
||||
}
|
||||
|
||||
public Object mapToIdFromEntity(Object data) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object mapToIdFromEntity(Object data) {
|
||||
if ( data == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(data instanceof HibernateProxy) {
|
||||
HibernateProxy hibernateProxy = (HibernateProxy) data;
|
||||
return hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
||||
} else {
|
||||
Getter getter = ReflectionTools.getGetter(data.getClass(), propertyData);
|
||||
return getter.get(data);
|
||||
}
|
||||
}
|
||||
if ( data instanceof HibernateProxy ) {
|
||||
final HibernateProxy hibernateProxy = (HibernateProxy) data;
|
||||
return hibernateProxy.getHibernateLazyInitializer().getIdentifier();
|
||||
}
|
||||
else {
|
||||
final Getter getter = ReflectionTools.getGetter( data.getClass(), propertyData );
|
||||
return getter.get( data );
|
||||
}
|
||||
}
|
||||
|
||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||
if (data != null) {
|
||||
data.put(propertyData.getName(), obj);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mapToMapFromId(Map<String, Object> data, Object obj) {
|
||||
if ( data != null ) {
|
||||
data.put( propertyData.getName(), obj );
|
||||
}
|
||||
}
|
||||
|
||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||
if (obj == null) {
|
||||
data.put(propertyData.getName(), null);
|
||||
} else {
|
||||
if(obj instanceof HibernateProxy) {
|
||||
HibernateProxy hibernateProxy = (HibernateProxy)obj;
|
||||
data.put(propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier());
|
||||
} else {
|
||||
Getter getter = ReflectionTools.getGetter(obj.getClass(), propertyData);
|
||||
data.put(propertyData.getName(), getter.get(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
|
||||
if ( obj == null ) {
|
||||
data.put( propertyData.getName(), null );
|
||||
}
|
||||
else {
|
||||
if ( obj instanceof HibernateProxy ) {
|
||||
final HibernateProxy hibernateProxy = (HibernateProxy) obj;
|
||||
data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier() );
|
||||
}
|
||||
else {
|
||||
final Getter getter = ReflectionTools.getGetter( obj.getClass(), propertyData );
|
||||
data.put( propertyData.getName(), getter.get( obj ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mapToEntityFromEntity(Object objTo, Object objFrom) {
|
||||
if (objTo == null || objFrom == null) {
|
||||
return;
|
||||
}
|
||||
public void mapToEntityFromEntity(Object objTo, Object objFrom) {
|
||||
if ( objTo == null || objFrom == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Getter getter = ReflectionTools.getGetter(objFrom.getClass(), propertyData);
|
||||
Setter setter = ReflectionTools.getSetter(objTo.getClass(), propertyData);
|
||||
setter.set(objTo, getter.get(objFrom), null);
|
||||
}
|
||||
final Getter getter = ReflectionTools.getGetter( objFrom.getClass(), propertyData );
|
||||
final Setter setter = ReflectionTools.getSetter( objTo.getClass(), propertyData );
|
||||
setter.set( objTo, getter.get( objFrom ), null );
|
||||
}
|
||||
|
||||
public IdMapper prefixMappedProperties(String prefix) {
|
||||
return new SingleIdMapper(new PropertyData(prefix + propertyData.getName(), propertyData));
|
||||
}
|
||||
@Override
|
||||
public IdMapper prefixMappedProperties(String prefix) {
|
||||
return new SingleIdMapper( new PropertyData( prefix + propertyData.getName(), propertyData ) );
|
||||
}
|
||||
|
||||
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
|
||||
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
|
||||
@Override
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
||||
protected final CommonCollectionMapperData commonCollectionMapperData;
|
||||
protected final Class<? extends T> collectionClass;
|
||||
protected final boolean ordinalInId;
|
||||
protected final CommonCollectionMapperData commonCollectionMapperData;
|
||||
protected final Class<? extends T> collectionClass;
|
||||
protected final boolean ordinalInId;
|
||||
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,
|
||||
boolean revisionTypeInId) {
|
||||
this.commonCollectionMapperData = commonCollectionMapperData;
|
||||
this.collectionClass = collectionClass;
|
||||
this.commonCollectionMapperData = commonCollectionMapperData;
|
||||
this.collectionClass = collectionClass;
|
||||
this.ordinalInId = ordinalInId;
|
||||
this.revisionTypeInId = revisionTypeInId;
|
||||
|
||||
try {
|
||||
proxyConstructor = proxyClass.getConstructor(Initializor.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AuditException(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
proxyConstructor = proxyClass.getConstructor( Initializor.class );
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new AuditException( e );
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
|
||||
protected abstract Collection getOldCollectionContent(Serializable oldCollection);
|
||||
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
|
||||
|
||||
/**
|
||||
* Maps the changed collection element to the given map.
|
||||
protected abstract Collection getOldCollectionContent(Serializable oldCollection);
|
||||
|
||||
/**
|
||||
* Maps the changed collection element to the given map.
|
||||
*
|
||||
* @param idData Map to which composite-id data should be added.
|
||||
* @param data Where to map the data.
|
||||
* @param changed The changed collection element to map.
|
||||
*/
|
||||
protected abstract void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed);
|
||||
* @param data Where to map the data.
|
||||
* @param changed The changed collection element to map.
|
||||
*/
|
||||
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.
|
||||
* Composite primary key cannot contain embeddable properties since they might be nullable.
|
||||
*
|
||||
* @param ordinal Iteration ordinal.
|
||||
*
|
||||
* @return Map for holding identifier data.
|
||||
*/
|
||||
protected Map<String, Object> createIdMap(int ordinal) {
|
||||
|
@ -100,79 +110,113 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
|||
return idMap;
|
||||
}
|
||||
|
||||
private void addCollectionChanges(SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
|
||||
Set<Object> changed, RevisionType revisionType, Serializable id) {
|
||||
private void addCollectionChanges(
|
||||
SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
|
||||
Set<Object> changed, RevisionType revisionType, Serializable id) {
|
||||
int ordinal = 0;
|
||||
|
||||
for (Object changedObj : changed) {
|
||||
Map<String, Object> entityData = new HashMap<String, Object>();
|
||||
Map<String, Object> originalId = createIdMap( ordinal++ );
|
||||
entityData.put(commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId);
|
||||
for ( Object changedObj : changed ) {
|
||||
final Map<String, Object> entityData = new HashMap<String, Object>();
|
||||
final Map<String, Object> originalId = createIdMap( ordinal++ );
|
||||
entityData.put( commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId );
|
||||
|
||||
collectionChanges.add(new PersistentCollectionChangeData(
|
||||
commonCollectionMapperData.getVersionsMiddleEntityName(), entityData, changedObj));
|
||||
// Mapping the collection owner's id.
|
||||
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId(originalId, id);
|
||||
collectionChanges.add(
|
||||
new PersistentCollectionChangeData(
|
||||
commonCollectionMapperData.getVersionsMiddleEntityName(), entityData, changedObj
|
||||
)
|
||||
);
|
||||
// Mapping the collection owner's id.
|
||||
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId( originalId, id );
|
||||
|
||||
// Mapping collection element and index (if present).
|
||||
mapToMapFromObject(session, originalId, entityData, changedObj);
|
||||
// Mapping collection element and index (if present).
|
||||
mapToMapFromObject( session, originalId, entityData, changedObj );
|
||||
|
||||
(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;
|
||||
}
|
||||
(revisionTypeInId ? originalId : entityData).put(
|
||||
commonCollectionMapperData.getVerEntCfg()
|
||||
.getRevisionTypePropName(), revisionType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
||||
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
|
||||
if (propertyData.isUsingModifiedFlag()) {
|
||||
if (isNotPersistentCollection(newObj) || isNotPersistentCollection(oldObj)) {
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||
SessionImplementor session,
|
||||
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.
|
||||
data.put(propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual(newObj, oldObj));
|
||||
} else if (isFromNullToEmptyOrFromEmptyToNull((PersistentCollection) newObj, (Serializable) oldObj)) {
|
||||
data.put(propertyData.getModifiedFlagPropertyName(), true);
|
||||
} else {
|
||||
List<PersistentCollectionChangeData> changes = mapCollectionChanges(session,
|
||||
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
|
||||
(PersistentCollection) newObj, (Serializable) oldObj, null);
|
||||
data.put(propertyData.getModifiedFlagPropertyName(), !changes.isEmpty());
|
||||
data.put( propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual( newObj, oldObj ) );
|
||||
}
|
||||
else if ( isFromNullToEmptyOrFromEmptyToNull( (PersistentCollection) newObj, (Serializable) oldObj ) ) {
|
||||
data.put( propertyData.getModifiedFlagPropertyName(), true );
|
||||
}
|
||||
else {
|
||||
final List<PersistentCollectionChangeData> changes = mapCollectionChanges(
|
||||
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) {
|
||||
// Comparing new and old collection content.
|
||||
Collection newCollection = getNewCollectionContent(newColl);
|
||||
Collection oldCollection = getOldCollectionContent(oldColl);
|
||||
final Collection newCollection = getNewCollectionContent( newColl );
|
||||
final Collection oldCollection = getOldCollectionContent( oldColl );
|
||||
|
||||
return oldCollection == null && newCollection != null && newCollection.isEmpty()
|
||||
|| newCollection == null && oldCollection != null && oldCollection.isEmpty();
|
||||
|
@ -192,36 +236,53 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
|||
|
||||
@Override
|
||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
|
||||
if (propertyData.isUsingModifiedFlag()) {
|
||||
data.put(propertyData.getModifiedFlagPropertyName(), propertyData.getName().equals(collectionPropertyName));
|
||||
final PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
|
||||
if ( propertyData.isUsingModifiedFlag() ) {
|
||||
data.put(
|
||||
propertyData.getModifiedFlagPropertyName(),
|
||||
propertyData.getName().equals( collectionPropertyName )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg,
|
||||
AuditReaderImplementor versionsReader, Object primaryKey,
|
||||
Number revision, boolean removed);
|
||||
protected abstract Initializor<T> getInitializor(
|
||||
AuditConfiguration verCfg,
|
||||
AuditReaderImplementor versionsReader, Object primaryKey,
|
||||
Number revision, boolean removed);
|
||||
|
||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), commonCollectionMapperData.getCollectionReferencingPropertyData());
|
||||
try {
|
||||
@Override
|
||||
public void mapToEntityFromMap(
|
||||
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
final Setter setter = ReflectionTools.getSetter(
|
||||
obj.getClass(),
|
||||
commonCollectionMapperData.getCollectionReferencingPropertyData()
|
||||
);
|
||||
try {
|
||||
setter.set(
|
||||
obj,
|
||||
proxyConstructor.newInstance(
|
||||
getInitializor(
|
||||
verCfg, versionsReader, primaryKey, revision,
|
||||
RevisionType.DEL.equals( data.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) )
|
||||
RevisionType.DEL.equals(
|
||||
data.get(
|
||||
verCfg.getAuditEntCfg()
|
||||
.getRevisionTypePropName()
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
null
|
||||
);
|
||||
} catch (InstantiationException e) {
|
||||
throw new AuditException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AuditException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new AuditException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InstantiationException e) {
|
||||
throw new AuditException( e );
|
||||
}
|
||||
catch (IllegalAccessException 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;
|
||||
|
||||
import javax.persistence.NoResultException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import javax.persistence.NoResultException;
|
||||
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
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.
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
|
||||
private final String entityName;
|
||||
private final String referencedEntityName;
|
||||
private final String entityName;
|
||||
private final String referencedEntityName;
|
||||
|
||||
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
|
||||
super(propertyData);
|
||||
this.entityName = entityName;
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
}
|
||||
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
|
||||
super( propertyData );
|
||||
this.entityName = entityName;
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
EntityInfo referencedEntity = getEntityInfo(verCfg, referencedEntityName);
|
||||
@Override
|
||||
public void nullSafeMapToEntityFromMap(
|
||||
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
final EntityInfo referencedEntity = getEntityInfo( verCfg, referencedEntityName );
|
||||
|
||||
Object value = null;
|
||||
try {
|
||||
value = queryForReferencedEntity(versionsReader, referencedEntity, (Serializable) primaryKey, revision);
|
||||
} catch (NoResultException e) {
|
||||
value = null;
|
||||
} catch (NonUniqueResultException e) {
|
||||
throw new AuditException("Many versions results for one-to-one relationship " + entityName +
|
||||
"." + getPropertyData().getBeanName() + ".", e);
|
||||
}
|
||||
Object value;
|
||||
try {
|
||||
value = queryForReferencedEntity( versionsReader, referencedEntity, (Serializable) primaryKey, revision );
|
||||
}
|
||||
catch (NoResultException e) {
|
||||
value = null;
|
||||
}
|
||||
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 referencedEntity Referenced entity descriptor.
|
||||
* @param primaryKey Referenced entity identifier.
|
||||
* @param revision Revision number.
|
||||
* @return Referenced object or proxy of one-to-one relation.
|
||||
*/
|
||||
protected abstract Object queryForReferencedEntity(AuditReaderImplementor versionsReader, EntityInfo referencedEntity,
|
||||
Serializable primaryKey, Number revision);
|
||||
/**
|
||||
* @param versionsReader Audit reader.
|
||||
* @param referencedEntity Referenced entity descriptor.
|
||||
* @param primaryKey Referenced entity identifier.
|
||||
* @param revision Revision number.
|
||||
*
|
||||
* @return Referenced object or proxy of one-to-one relation.
|
||||
*/
|
||||
protected abstract Object queryForReferencedEntity(
|
||||
AuditReaderImplementor versionsReader, EntityInfo referencedEntity,
|
||||
Serializable primaryKey, Number revision);
|
||||
|
||||
@Override
|
||||
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
||||
}
|
||||
@Override
|
||||
public void mapModifiedFlagsToMapFromEntity(
|
||||
SessionImplementor session,
|
||||
Map<String, Object> data,
|
||||
Object newObj,
|
||||
Object oldObj) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||
if (getPropertyData().isUsingModifiedFlag()) {
|
||||
data.put(getPropertyData().getModifiedFlagPropertyName(), collectionPropertyName.equals(getPropertyData().getName()));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
|
||||
if ( getPropertyData().isUsingModifiedFlag() ) {
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -17,87 +40,109 @@ import org.hibernate.property.Setter;
|
|||
|
||||
/**
|
||||
* Base class for property mappers that manage to-one relation.
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public abstract class AbstractToOneMapper implements PropertyMapper {
|
||||
private final PropertyData propertyData;
|
||||
private final PropertyData propertyData;
|
||||
|
||||
protected AbstractToOneMapper(PropertyData propertyData) {
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
protected AbstractToOneMapper(PropertyData propertyData) {
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean mapToMapFromEntity(
|
||||
SessionImplementor session,
|
||||
Map<String, Object> data,
|
||||
Object newObj,
|
||||
Object oldObj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
if (obj != null) {
|
||||
nullSafeMapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mapToEntityFromMap(
|
||||
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
if ( obj != null ) {
|
||||
nullSafeMapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl, Serializable oldColl,
|
||||
Serializable id) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(
|
||||
SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl, Serializable oldColl,
|
||||
Serializable id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param verCfg Audit configuration.
|
||||
* @param entityName Entity name.
|
||||
* @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);
|
||||
boolean isRelationAudited = true;
|
||||
if (entCfg == null) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName);
|
||||
isRelationAudited = false;
|
||||
}
|
||||
Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
||||
return new EntityInfo(entityClass, entityName, isRelationAudited);
|
||||
}
|
||||
/**
|
||||
* @param verCfg Audit configuration.
|
||||
* @param entityName Entity name.
|
||||
*
|
||||
* @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 );
|
||||
boolean isRelationAudited = true;
|
||||
if ( entCfg == null ) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
|
||||
isRelationAudited = false;
|
||||
}
|
||||
final Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
|
||||
return new EntityInfo( entityClass, entityName, isRelationAudited );
|
||||
}
|
||||
|
||||
protected void setPropertyValue(Object targetObject, Object value) {
|
||||
Setter setter = ReflectionTools.getSetter(targetObject.getClass(), propertyData);
|
||||
setter.set(targetObject, value, null);
|
||||
}
|
||||
protected void setPropertyValue(Object targetObject, Object value) {
|
||||
final Setter setter = ReflectionTools.getSetter( targetObject.getClass(), propertyData );
|
||||
setter.set( targetObject, value, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Bean property that represents the relation.
|
||||
*/
|
||||
protected PropertyData getPropertyData() {
|
||||
return propertyData;
|
||||
}
|
||||
/**
|
||||
* @return Bean property that represents the relation.
|
||||
*/
|
||||
protected PropertyData getPropertyData() {
|
||||
return propertyData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter {@code obj} is never {@code null}.
|
||||
* @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);
|
||||
/**
|
||||
* Parameter {@code obj} is never {@code null}.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Simple descriptor of an entity.
|
||||
*/
|
||||
protected class EntityInfo {
|
||||
private final Class entityClass;
|
||||
private final String entityName;
|
||||
private final boolean audited;
|
||||
/**
|
||||
* Simple descriptor of an entity.
|
||||
*/
|
||||
protected class EntityInfo {
|
||||
private final Class entityClass;
|
||||
private final String entityName;
|
||||
private final boolean audited;
|
||||
|
||||
public EntityInfo(Class entityClass, String entityName, boolean audited) {
|
||||
this.entityClass = entityClass;
|
||||
this.entityName = entityName;
|
||||
this.audited = audited;
|
||||
}
|
||||
public EntityInfo(Class entityClass, String entityName, boolean audited) {
|
||||
this.entityClass = entityClass;
|
||||
this.entityName = entityName;
|
||||
this.audited = audited;
|
||||
}
|
||||
|
||||
public Class getEntityClass() { return entityClass; }
|
||||
public String getEntityName() { return entityName; }
|
||||
public boolean isAudited() { return audited; }
|
||||
}
|
||||
public Class getEntityClass() {
|
||||
return entityClass;
|
||||
}
|
||||
|
||||
public String getEntityName() {
|
||||
return entityName;
|
||||
}
|
||||
|
||||
public boolean isAudited() {
|
||||
return audited;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* 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)
|
||||
*/
|
||||
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,
|
||||
MiddleComponentData elementComponentData, boolean ordinalInId, boolean revisionTypeInId) {
|
||||
super( commonCollectionMapperData, collectionClass, proxyClass, ordinalInId, revisionTypeInId );
|
||||
this.elementComponentData = elementComponentData;
|
||||
}
|
||||
this.elementComponentData = elementComponentData;
|
||||
}
|
||||
|
||||
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||
Object primaryKey, Number revision, boolean removed) {
|
||||
return new BasicCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||
primaryKey, revision, removed, collectionClass, elementComponentData);
|
||||
}
|
||||
@Override
|
||||
protected Initializor<T> getInitializor(
|
||||
AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||
Object primaryKey, Number revision, boolean removed) {
|
||||
return new BasicCollectionInitializor<T>(
|
||||
verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||
primaryKey, revision, removed, collectionClass, elementComponentData
|
||||
);
|
||||
}
|
||||
|
||||
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
||||
return (Collection) newCollection;
|
||||
}
|
||||
@Override
|
||||
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
||||
return (Collection) newCollection;
|
||||
}
|
||||
|
||||
protected Collection getOldCollectionContent(Serializable oldCollection) {
|
||||
if (oldCollection == null) {
|
||||
return null;
|
||||
} else if (oldCollection instanceof Map) {
|
||||
return ((Map) oldCollection).keySet();
|
||||
} else {
|
||||
return (Collection) oldCollection;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected Collection getOldCollectionContent(Serializable oldCollection) {
|
||||
if ( oldCollection == null ) {
|
||||
return null;
|
||||
}
|
||||
else if ( oldCollection instanceof Map ) {
|
||||
return ((Map) oldCollection).keySet();
|
||||
}
|
||||
else {
|
||||
return (Collection) oldCollection;
|
||||
}
|
||||
}
|
||||
|
||||
protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
|
||||
elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, changed);
|
||||
}
|
||||
@Override
|
||||
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