HHH-8159 - Apply fixups indicated by analysis tools

This commit is contained in:
Steve Ebersole 2013-05-02 10:01:16 -05:00
parent ad1d1ab8b4
commit 364a47f2c7
867 changed files with 45715 additions and 37131 deletions

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,11 +22,12 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers; package org.hibernate.envers;
import javax.persistence.JoinColumn;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import javax.persistence.JoinColumn;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
@ -34,25 +35,25 @@ import javax.persistence.JoinColumn;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD}) @Target({ElementType.FIELD, ElementType.METHOD})
public @interface AuditJoinTable { public @interface AuditJoinTable {
/** /**
* @return Name of the join table. Defaults to a concatenation of the names of the primary table of the entity * Name of the join table. Defaults to a concatenation of the names of the primary table of the entity
* owning the association and of the primary table of the entity referenced by the association. * owning the association and of the primary table of the entity referenced by the association.
*/ */
String name() default ""; String name() default "";
/** /**
* @return The schema of the join table. Defaults to the schema of the entity owning the association. * The schema of the join table. Defaults to the schema of the entity owning the association.
*/ */
String schema() default ""; String schema() default "";
/** /**
* @return The catalog of the join table. Defaults to the catalog of the entity owning the association. * The catalog of the join table. Defaults to the catalog of the entity owning the association.
*/ */
String catalog() default ""; String catalog() default "";
/** /**
* @return The foreign key columns of the join table which reference the primary table of the entity that does not * The foreign key columns of the join table which reference the primary table of the entity that does not
* own the association (i.e. the inverse side of the association). * own the association (i.e. the inverse side of the association).
*/ */
JoinColumn[] inverseJoinColumns() default {}; JoinColumn[] inverseJoinColumns() default {};
} }

View File

@ -1,4 +1,5 @@
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -11,7 +12,7 @@ import java.lang.annotation.Target;
* the many side. Then, Envers won't use a join table to audit this relation, but will store changes as in a normal * the many side. Then, Envers won't use a join table to audit this relation, but will store changes as in a normal
* bi-directional relation. * bi-directional relation.
* </p> * </p>
* * <p/>
* <p> * <p>
* This annotation is <b>experimental</b> and may change in future releases. * This annotation is <b>experimental</b> and may change in future releases.
* </p> * </p>
@ -21,16 +22,17 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD}) @Target({ElementType.METHOD, ElementType.FIELD})
public @interface AuditMappedBy { public @interface AuditMappedBy {
/** /**
* @return Name of the property in the related entity which maps back to this entity. The property should be * Name of the property in the related entity which maps back to this entity. The property should be
* mapped with {@code @ManyToOne} and {@code @Column(insertable=false, updatable=false)}. * mapped with {@code @ManyToOne} and {@code @Column(insertable=false, updatable=false)}.
*/ */
String mappedBy(); String mappedBy();
/** /**
* @return Name of the property in the related entity which maps to the position column. Should be specified only * Name of the property in the related entity which maps to the position column. Should be specified only
* for indexed collection, when @{@link org.hibernate.annotations.IndexColumn} is used on the collection. * for indexed collection, when @{@link org.hibernate.annotations.IndexColumn} or
* The property should be mapped with {@code @Column(insertable=false, updatable=false)}. * {@link javax.persistence.OrderColumn} is used on the collection. The property should be mapped with
*/ * {@code @Column(insertable=false, updatable=false)}.
String positionMappedBy() default ""; */
String positionMappedBy() default "";
} }

View File

@ -1,7 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import javax.persistence.MappedSuperclass;
import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.METHOD;
@ -10,43 +33,44 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* The {@code AuditingOverride} annotation is used to override the auditing * The {@code AuditingOverride} annotation is used to override the auditing
* behavior of a superclass or single property inherited from {@link MappedSuperclass} * behavior of a superclass or single property inherited from {@link javax.persistence.MappedSuperclass}
* type, or attribute inside an embedded component. * type, or attribute inside an embedded component.
* *
* @author Erik-Berndt Scheper * @author Erik-Berndt Scheper
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*
* @see javax.persistence.Embedded * @see javax.persistence.Embedded
* @see javax.persistence.Embeddable * @see javax.persistence.Embeddable
* @see javax.persistence.MappedSuperclass * @see javax.persistence.MappedSuperclass
* @see javax.persistence.AssociationOverride * @see javax.persistence.AssociationOverride
* @see AuditJoinTable * @see AuditJoinTable
*/ */
@Target({ TYPE, METHOD, FIELD }) @Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface AuditOverride { public @interface AuditOverride {
/** /**
* @return Name of the field (or property) whose mapping is being overridden. Allows empty value if * Name of the field (or property) whose mapping is being overridden. Allows empty value if
* {@link AuditOverride} is used to change auditing behavior of all attributes inherited from * {@link AuditOverride} is used to change auditing behavior of all attributes inherited from
* {@link MappedSuperclass} type. * {@link javax.persistence.MappedSuperclass} type.
*/ */
String name() default ""; String name() default "";
/** /**
* @return Indicates if the field (or property) is audited; defaults to {@code true}. * Indicates if the field (or property) is audited; defaults to {@code true}.
*/ */
boolean isAudited() default true; boolean isAudited() default true;
/** /**
* @return New {@link AuditJoinTable} used for this field (or property). Its value * New {@link AuditJoinTable} used for this field (or property). Its value
* is ignored if {@link #isAudited()} equals to {@code false}. * is ignored if {@link #isAudited()} equals to {@code false}.
*/ */
AuditJoinTable auditJoinTable() default @AuditJoinTable; AuditJoinTable auditJoinTable() default @AuditJoinTable;
/** /**
* @return Specifies class which field (or property) mapping is being overridden. <strong>Required</strong> if * Specifies class which field (or property) mapping is being overridden. <strong>Required</strong> if
* {@link AuditOverride} is used to change auditing behavior of attributes inherited from {@link MappedSuperclass} * {@link AuditOverride} is used to change auditing behavior of attributes inherited from
* type. * {@link javax.persistence.MappedSuperclass} type.
*/ */
Class forClass() default void.class; Class forClass() default void.class;
} }

View File

@ -1,4 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@ -21,11 +45,11 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* @see AuditJoinTable * @see AuditJoinTable
* @see AuditOverride * @see AuditOverride
*/ */
@Target({ TYPE, METHOD, FIELD }) @Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface AuditOverrides { public @interface AuditOverrides {
/** /**
* @return An array of {@link AuditOverride} values, to define the new auditing * An array of {@link AuditOverride} values, to define the new auditing
* behavior. * behavior.
*/ */
AuditOverride[] value(); AuditOverride[] value();

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -40,207 +40,241 @@ import org.hibernate.envers.query.AuditQueryCreator;
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public interface AuditReader { public interface AuditReader {
/** /**
* Find an entity by primary key at the given revision. * Find an entity by primary key at the given revision.
* @param cls Class of the entity. *
* @param primaryKey Primary key of the entity. * @param cls Class of the entity.
* @param revision Revision in which to get the entity. * @param primaryKey Primary key of the entity.
* @return The found entity instance at the given revision (its properties may be partially filled * @param revision Revision in which to get the entity.
* if not all properties are audited) or null, if an entity with that id didn't exist at that * @param <T> The type of the entity to find
* revision. *
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0. * @return The found entity instance at the given revision (its properties may be partially filled
* @throws NotAuditedException When entities of the given class are not audited. * if not all properties are audited) or null, if an entity with that id didn't exist at that
* @throws IllegalStateException If the associated entity manager is closed. * revision.
*/ *
<T> T find(Class<T> cls, Object primaryKey, Number revision) throws * @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
IllegalArgumentException, NotAuditedException, IllegalStateException; * @throws NotAuditedException When entities of the given class are not audited.
* @throws IllegalStateException If the associated entity manager is closed.
/** */
* Find an entity by primary key at the given revision with the specified entityName. <T> T find(Class<T> cls, Object primaryKey, Number revision) throws
* @param cls Class of the entity. IllegalArgumentException, NotAuditedException, IllegalStateException;
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
* @param primaryKey Primary key of the entity. /**
* @param revision Revision in which to get the entity. * Find an entity by primary key at the given revision with the specified entityName.
* @return The found entity instance at the given revision (its properties may be partially filled *
* if not all properties are audited) or null, if an entity with that id didn't exist at that * @param cls Class of the entity.
* revision. * @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0. * @param primaryKey Primary key of the entity.
* @throws NotAuditedException When entities of the given class are not audited. * @param revision Revision in which to get the entity.
* @throws IllegalStateException If the associated entity manager is closed. * @param <T> The type of the entity to find
*/ *
<T> T find(Class<T> cls, String entityName, Object primaryKey, * @return The found entity instance at the given revision (its properties may be partially filled
* if not all properties are audited) or null, if an entity with that id didn't exist at that
* revision.
*
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
* @throws NotAuditedException When entities of the given class are not audited.
* @throws IllegalStateException If the associated entity manager is closed.
*/
<T> T find(
Class<T> cls, String entityName, Object primaryKey,
Number revision) throws IllegalArgumentException, Number revision) throws IllegalArgumentException,
NotAuditedException, IllegalStateException; NotAuditedException, IllegalStateException;
/** /**
* Find an entity by primary key at the given revision with the specified entityName, * Find an entity by primary key at the given revision with the specified entityName,
* possibly including deleted entities in the search. * possibly including deleted entities in the search.
* @param cls Class of the entity. *
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}). * @param cls Class of the entity.
* @param primaryKey Primary key of the entity. * @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
* @param revision Revision in which to get the entity. * @param primaryKey Primary key of the entity.
* @param includeDeletions Whether to include deleted entities in the search. * @param revision Revision in which to get the entity.
* @return The found entity instance at the given revision (its properties may be partially filled * @param includeDeletions Whether to include deleted entities in the search.
* if not all properties are audited) or null, if an entity with that id didn't exist at that * @param <T> The type of the entity to find
* revision. *
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0. * @return The found entity instance at the given revision (its properties may be partially filled
* @throws NotAuditedException When entities of the given class are not audited. * if not all properties are audited) or null, if an entity with that id didn't exist at that
* @throws IllegalStateException If the associated entity manager is closed. * revision.
*/ *
<T> T find(Class<T> cls, String entityName, Object primaryKey, * @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
* @throws NotAuditedException When entities of the given class are not audited.
* @throws IllegalStateException If the associated entity manager is closed.
*/
<T> T find(
Class<T> cls, String entityName, Object primaryKey,
Number revision, boolean includeDeletions) throws IllegalArgumentException, Number revision, boolean includeDeletions) throws IllegalArgumentException,
NotAuditedException, IllegalStateException; NotAuditedException, IllegalStateException;
/** /**
* Get a list of revision numbers, at which an entity was modified. * Get a list of revision numbers, at which an entity was modified.
* @param cls Class of the entity. *
* @param primaryKey Primary key of the entity. * @param cls Class of the entity.
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older * @param primaryKey Primary key of the entity.
* revisions come first). *
* @throws NotAuditedException When entities of the given class are not audited. * @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
* @throws IllegalArgumentException If cls or primaryKey is null. * revisions come first).
* @throws IllegalStateException If the associated entity manager is closed. *
*/ * @throws NotAuditedException When entities of the given class are not audited.
List<Number> getRevisions(Class<?> cls, Object primaryKey) * @throws IllegalArgumentException If cls or primaryKey is null.
throws IllegalArgumentException, NotAuditedException, IllegalStateException; * @throws IllegalStateException If the associated entity manager is closed.
*/
/** List<Number> getRevisions(Class<?> cls, Object primaryKey)
* Get a list of revision numbers, at which an entity was modified, looking by entityName. throws IllegalArgumentException, NotAuditedException, IllegalStateException;
* @param cls Class of the entity.
* @param entityName Name of the entity (if can't be guessed basing on the {@code cls}). /**
* @param primaryKey Primary key of the entity. * Get a list of revision numbers, at which an entity was modified, looking by entityName.
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older *
* revisions come first). * @param cls Class of the entity.
* @throws NotAuditedException When entities of the given class are not audited. * @param entityName Name of the entity (if can't be guessed basing on the {@code cls}).
* @throws IllegalArgumentException If cls or primaryKey is null. * @param primaryKey Primary key of the entity.
* @throws IllegalStateException If the associated entity manager is closed. *
*/ * @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
List<Number> getRevisions(Class<?> cls, String entityName, Object primaryKey) * revisions come first).
*
* @throws NotAuditedException When entities of the given class are not audited.
* @throws IllegalArgumentException If cls or primaryKey is null.
* @throws IllegalStateException If the associated entity manager is closed.
*/
List<Number> getRevisions(Class<?> cls, String entityName, Object primaryKey)
throws IllegalArgumentException, NotAuditedException, throws IllegalArgumentException, NotAuditedException,
IllegalStateException; IllegalStateException;
/** /**
* Get the date, at which a revision was created. * Get the date, at which a revision was created.
* @param revision Number of the revision for which to get the date. *
* @return Date of commiting the given revision. * @param revision Number of the revision for which to get the date.
* @throws IllegalArgumentException If revision is less or equal to 0. *
* @throws RevisionDoesNotExistException If the revision does not exist. * @return Date of commiting the given revision.
* @throws IllegalStateException If the associated entity manager is closed. *
*/ * @throws IllegalArgumentException If revision is less or equal to 0.
Date getRevisionDate(Number revision) throws IllegalArgumentException, RevisionDoesNotExistException, * @throws RevisionDoesNotExistException If the revision does not exist.
IllegalStateException; * @throws IllegalStateException If the associated entity manager is closed.
/**
* Gets the revision number, that corresponds to the given date. More precisely, returns
* the number of the highest revision, which was created on or before the given date. So:
* <code>getRevisionDate(getRevisionNumberForDate(date)) <= date</code> and
* <code>getRevisionDate(getRevisionNumberForDate(date)+1) > date</code>.
* @param date Date for which to get the revision.
* @return Revision number corresponding to the given date.
* @throws IllegalStateException If the associated entity manager is closed.
* @throws RevisionDoesNotExistException If the given date is before the first revision.
* @throws IllegalArgumentException If <code>date</code> is <code>null</code>.
*/
Number getRevisionNumberForDate(Date date) throws IllegalStateException, RevisionDoesNotExistException,
IllegalArgumentException;
/**
* A helper method; should be used only if a custom revision entity is used. See also {@link RevisionEntity}.
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
* @param revision Number of the revision for which to get the data.
* @return Entity containing data for the given revision.
* @throws IllegalArgumentException If revision is less or equal to 0 or if the class of the revision entity
* is invalid.
* @throws RevisionDoesNotExistException If the revision does not exist.
* @throws IllegalStateException If the associated entity manager is closed.
*/
<T> T findRevision(Class<T> revisionEntityClass, Number revision) throws IllegalArgumentException,
RevisionDoesNotExistException, IllegalStateException;
/**
* Find a map of revisions using the revision numbers specified.
*
* @param revisionEntityClass
* Class of the revision entity. Should be annotated with
* {@link RevisionEntity}.
* @param revisions
* Revision numbers of the revision for which to get the data.
* @return A map of revision number and the given revision entity.
* @throws IllegalArgumentException
* If a revision number is less or equal to 0 or if the class of
* the revision entity is invalid.
* @throws IllegalStateException
* If the associated entity manager is closed.
*/ */
<T> Map<Number, T> findRevisions(Class<T> revisionEntityClass, Date getRevisionDate(Number revision) throws IllegalArgumentException, RevisionDoesNotExistException,
IllegalStateException;
/**
* Gets the revision number, that corresponds to the given date. More precisely, returns
* the number of the highest revision, which was created on or before the given date. So:
* <code>getRevisionDate(getRevisionNumberForDate(date)) <= date</code> and
* <code>getRevisionDate(getRevisionNumberForDate(date)+1) > date</code>.
*
* @param date Date for which to get the revision.
*
* @return Revision number corresponding to the given date.
*
* @throws IllegalStateException If the associated entity manager is closed.
* @throws RevisionDoesNotExistException If the given date is before the first revision.
* @throws IllegalArgumentException If <code>date</code> is <code>null</code>.
*/
Number getRevisionNumberForDate(Date date) throws IllegalStateException, RevisionDoesNotExistException,
IllegalArgumentException;
/**
* A helper method; should be used only if a custom revision entity is used. See also {@link RevisionEntity}.
*
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
* @param revision Number of the revision for which to get the data.
* @param <T> The type of the revision entity to find
*
* @return Entity containing data for the given revision.
*
* @throws IllegalArgumentException If revision is less or equal to 0 or if the class of the revision entity
* is invalid.
* @throws RevisionDoesNotExistException If the revision does not exist.
* @throws IllegalStateException If the associated entity manager is closed.
*/
<T> T findRevision(Class<T> revisionEntityClass, Number revision) throws IllegalArgumentException,
RevisionDoesNotExistException, IllegalStateException;
/**
* Find a map of revisions using the revision numbers specified.
*
* @param revisionEntityClass Class of the revision entity. Should be annotated with
* {@link RevisionEntity}.
* @param revisions Revision numbers of the revision for which to get the data.
* @param <T> The type of the revision entity to find
*
* @return A map of revision number and the given revision entity.
*
* @throws IllegalArgumentException If a revision number is less or equal to 0 or if the class of
* the revision entity is invalid.
* @throws IllegalStateException If the associated entity manager is closed.
*/
<T> Map<Number, T> findRevisions(
Class<T> revisionEntityClass,
Set<Number> revisions) throws IllegalArgumentException, Set<Number> revisions) throws IllegalArgumentException,
IllegalStateException; IllegalStateException;
/** /**
* Gets an instance of the current revision entity, to which any entries in the audit tables will be bound. * Gets an instance of the current revision entity, to which any entries in the audit tables will be bound.
* Please note the if {@code persist} is {@code false}, and no audited entities are modified in this session, * Please note the if {@code persist} is {@code false}, and no audited entities are modified in this session,
* then the obtained revision entity instance won't be persisted. If {@code persist} is {@code true}, the revision * then the obtained revision entity instance won't be persisted. If {@code persist} is {@code true}, the revision
* entity instance will always be persisted, regardless of whether audited entities are changed or not. * entity instance will always be persisted, regardless of whether audited entities are changed or not.
*
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}. * @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
* @param persist If the revision entity is not yet persisted, should it become persisted. This way, the primary * @param persist If the revision entity is not yet persisted, should it become persisted. This way, the primary
* identifier (id) will be filled (if it's assigned by the DB) and available, but the revision entity will be * identifier (id) will be filled (if it's assigned by the DB) and available, but the revision entity will be
* persisted even if there are no changes to audited entities. Otherwise, the revision number (id) can be * persisted even if there are no changes to audited entities. Otherwise, the revision number (id) can be
* {@code null}. * {@code null}.
* @param <T> The type of the revision entity to find
*
* @return The current revision entity, to which any entries in the audit tables will be bound. * @return The current revision entity, to which any entries in the audit tables will be bound.
*/ */
<T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist); <T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist);
/** /**
* * Creates an audit query
* @return A query creator, associated with this AuditReader instance, with which queries can be *
* created and later executed. Shouldn't be used after the associated Session or EntityManager * @return A query creator, associated with this AuditReader instance, with which queries can be
* is closed. * created and later executed. Shouldn't be used after the associated Session or EntityManager
*/ * is closed.
AuditQueryCreator createQuery(); */
AuditQueryCreator createQuery();
/** /**
* Checks if the entityClass was configured to be audited. Calling * Checks if the entityClass was configured to be audited. Calling
* isEntityNameAudited() with the string of the class name will return the * isEntityNameAudited() with the string of the class name will return the
* same value. * same value.
* *
* @param entityClass * @param entityClass Class of the entity asking for audit support
* Class of the entity asking for audit support *
* @return true if the entityClass is audited. * @return true if the entityClass is audited.
*/ */
boolean isEntityClassAudited(Class<?> entityClass); boolean isEntityClassAudited(Class<?> entityClass);
/** /**
* Checks if the entityName was configured to be audited. * Checks if the entityName was configured to be audited.
* *
* @param entityName EntityName of the entity asking for audit support. * @param entityName EntityName of the entity asking for audit support.
*
* @return true if the entityName is audited. * @return true if the entityName is audited.
*/ */
boolean isEntityNameAudited(String entityName); boolean isEntityNameAudited(String entityName);
/** /**
* * @param entity that was obtained previously from the same AuditReader.
* @param entity *
* that was obtained previously from the same AuditReader.
*
* @return the entityName for the given entity, null in case the entity is * @return the entityName for the given entity, null in case the entity is
* not associated with this AuditReader instance. * not associated with this AuditReader instance.
*/ */
String getEntityName(Object primaryKey, Number revision, Object entity) String getEntityName(Object primaryKey, Number revision, Object entity)
throws HibernateException; throws HibernateException;
/** /**
* @return Basic implementation of {@link CrossTypeRevisionChangesReader} interface. Raises an exception if the default * @return Basic implementation of {@link CrossTypeRevisionChangesReader} interface. Raises an exception if the default
* mechanism of tracking entity names modified during revisions has not been enabled. * mechanism of tracking entity names modified during revisions has not been enabled.
* @throws AuditException If none of the following conditions is satisfied: *
* <ul> * @throws AuditException If none of the following conditions is satisfied:
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code> * <ul>
* parameter is set to <code>true</code>.</li> * <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) * parameter is set to <code>true</code>.</li>
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li> * <li>Custom revision entity (annotated with {@link RevisionEntity})
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field * extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
* marked with {@link ModifiedEntityNames} interface.</li> * <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* </ul> * marked with {@link ModifiedEntityNames} interface.</li>
*/ * </ul>
public CrossTypeRevisionChangesReader getCrossTypeRevisionChangesReader() throws AuditException; */
public CrossTypeRevisionChangesReader getCrossTypeRevisionChangesReader() throws AuditException;
} }

View File

@ -38,20 +38,25 @@ import org.hibernate.event.spi.PostInsertEventListener;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class AuditReaderFactory { public class AuditReaderFactory {
private AuditReaderFactory() { } private AuditReaderFactory() {
}
/** /**
* Create an audit reader associated with an open session. * Create an audit reader associated with an open session.
* @param session An open session. *
* @return An audit reader associated with the given sesison. It shouldn't be used * @param session An open session.
* after the session is closed. *
* @throws AuditException When the given required listeners aren't installed. * @return An audit reader associated with the given sesison. It shouldn't be used
*/ * after the session is closed.
public static AuditReader get(Session session) throws AuditException { *
SessionImplementor sessionImpl; * @throws AuditException When the given required listeners aren't installed.
if (!(session instanceof SessionImplementor)) { */
public static AuditReader get(Session session) throws AuditException {
SessionImplementor sessionImpl;
if ( !(session instanceof SessionImplementor) ) {
sessionImpl = (SessionImplementor) session.getSessionFactory().getCurrentSession(); sessionImpl = (SessionImplementor) session.getSessionFactory().getCurrentSession();
} else { }
else {
sessionImpl = (SessionImplementor) session; sessionImpl = (SessionImplementor) session;
} }
@ -61,37 +66,41 @@ public class AuditReaderFactory {
.getServiceRegistry() .getServiceRegistry()
.getService( EventListenerRegistry.class ); .getService( EventListenerRegistry.class );
for ( PostInsertEventListener listener : listenerRegistry.getEventListenerGroup( EventType.POST_INSERT ).listeners() ) { for ( PostInsertEventListener listener : listenerRegistry.getEventListenerGroup( EventType.POST_INSERT )
.listeners() ) {
if ( listener instanceof EnversListener ) { if ( listener instanceof EnversListener ) {
// todo : slightly different from original code in that I am not checking the other listener groups... // todo : slightly different from original code in that I am not checking the other listener groups...
return new AuditReaderImpl( return new AuditReaderImpl(
( (EnversListener) listener ).getAuditConfiguration(), ((EnversListener) listener).getAuditConfiguration(),
session, session,
sessionImpl sessionImpl
); );
} }
} }
throw new AuditException( "Envers listeners were not properly registered" ); throw new AuditException( "Envers listeners were not properly registered" );
} }
/** /**
* Create an audit reader associated with an open entity manager. * Create an audit reader associated with an open entity manager.
* @param entityManager An open entity manager. *
* @return An audit reader associated with the given entity manager. It shouldn't be used * @param entityManager An open entity manager.
* after the entity manager is closed. *
* @throws AuditException When the given entity manager is not based on Hibernate, or if the required * @return An audit reader associated with the given entity manager. It shouldn't be used
* listeners aren't installed. * after the entity manager is closed.
*/ *
public static AuditReader get(EntityManager entityManager) throws AuditException { * @throws AuditException When the given entity manager is not based on Hibernate, or if the required
if (entityManager.getDelegate() instanceof Session) { * listeners aren't installed.
return get((Session) entityManager.getDelegate()); */
} public static AuditReader get(EntityManager entityManager) throws AuditException {
if ( entityManager.getDelegate() instanceof Session ) {
return get( (Session) entityManager.getDelegate() );
}
if (entityManager.getDelegate() instanceof EntityManager) { if ( entityManager.getDelegate() instanceof EntityManager ) {
return get((EntityManager) entityManager.getDelegate()); return get( (EntityManager) entityManager.getDelegate() );
} }
throw new AuditException("Hibernate EntityManager not present!"); throw new AuditException( "Hibernate EntityManager not present!" );
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -33,15 +34,18 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface AuditTable { public @interface AuditTable {
String value(); /**
* The name of the table
*/
String value();
/** /**
* @return The schema of the table. Defaults to the schema of the annotated entity. * The schema of the table. Defaults to the schema of the annotated entity.
*/ */
String schema() default ""; String schema() default "";
/** /**
* @return The catalog of the table. Defaults to the catalog of the annotated entity. * The catalog of the table. Defaults to the catalog of the annotated entity.
*/ */
String catalog() default ""; String catalog() default "";
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -30,6 +31,7 @@ import java.lang.annotation.Target;
/** /**
* When applied to a class, indicates that all of its properties should be audited. * When applied to a class, indicates that all of its properties should be audited.
* When applied to a field, indicates that this field should be audited. * When applied to a field, indicates that this field should be audited.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Tomasz Bech * @author Tomasz Bech
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
@ -38,33 +40,37 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface Audited { public @interface Audited {
ModificationStore modStore() default ModificationStore.FULL; /**
* Specifies modification store to use
*/
ModificationStore modStore() default ModificationStore.FULL;
/** /**
* @return Specifies if the entity that is the target of the relation should be audited or not. If not, then when * Specifies if the entity that is the target of the relation should be audited or not. If not, then when
* reading a historic version an audited entity, the relation will always point to the "current" entity. * reading a historic version an audited entity, the relation will always point to the "current" entity.
* This is useful for dictionary-like entities, which don't change and don't need to be audited. * This is useful for dictionary-like entities, which don't change and don't need to be audited.
*/ */
RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED; RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED;
/** /**
* @return Specifies the superclasses for which properties should be audited, even if the superclasses are not * Specifies the superclasses for which properties should be audited, even if the superclasses are not
* annotated with {@link Audited}. Causes all properties of the listed classes to be audited, just as if the * annotated with {@link Audited}. Causes all properties of the listed classes to be audited, just as if the
* classes had {@link Audited} annotation applied on the class level. * classes had {@link Audited} annotation applied on the class level.
* * <p/>
* The scope of this functionality is limited to the class hierarchy of the annotated entity. * The scope of this functionality is limited to the class hierarchy of the annotated entity.
* * <p/>
* If a parent type lists any of its parent types using this attribute, all properties in the specified classes * If a parent type lists any of its parent types using this attribute, all properties in the specified classes
* will also be audited. * will also be audited.
* *
* @deprecated Use {@code @AuditOverride(forClass=SomeEntity.class)} instead. * @deprecated Use {@code @AuditOverride(forClass=SomeEntity.class)} instead.
*/ */
Class[] auditParents() default {}; @Deprecated
Class[] auditParents() default {};
/** /**
* @return Should a modification flag be stored for each property in the annotated class or for the annotated * Should a modification flag be stored for each property in the annotated class or for the annotated
* property. The flag stores information if a property has been changed at a given revision. * property. The flag stores information if a property has been changed at a given revision.
* This can be used for example in queries. * This can be used for example in queries.
*/ */
boolean withModifiedFlag() default false; boolean withModifiedFlag() default false;
} }

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers; package org.hibernate.envers;
import java.util.List; import java.util.List;
@ -10,52 +33,67 @@ import org.hibernate.envers.tools.Pair;
* Queries that allow retrieving snapshots of all entities (regardless of their particular type) changed in the given * Queries that allow retrieving snapshots of all entities (regardless of their particular type) changed in the given
* revision. Note that this API can be legally used only when default mechanism of tracking modified entity names * revision. Note that this API can be legally used only when default mechanism of tracking modified entity names
* is enabled. * is enabled.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public interface CrossTypeRevisionChangesReader { public interface CrossTypeRevisionChangesReader {
/** /**
* Find all entities changed (added, updated and removed) in a given revision. Executes <i>n+1</i> SQL queries, * Find all entities changed (added, updated and removed) in a given revision. Executes <i>n+1</i> SQL queries,
* where <i>n</i> is a number of different entity classes modified within specified revision. * where <i>n</i> is a number of different entity classes modified within specified revision.
* @param revision Revision number. *
* @return Snapshots of all audited entities changed in a given revision. * @param revision Revision number.
* @throws IllegalStateException If the associated entity manager is closed. *
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0. * @return Snapshots of all audited entities changed in a given revision.
*/ *
public List<Object> findEntities(Number revision) throws IllegalStateException, IllegalArgumentException; * @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
*/
public List<Object> findEntities(Number revision) throws IllegalStateException, IllegalArgumentException;
/** /**
* Find all entities changed (added, updated or removed) in a given revision. Executes <i>n+1</i> SQL queries, * Find all entities changed (added, updated or removed) in a given revision. Executes <i>n+1</i> SQL queries,
* where <i>n</i> is a number of different entity classes modified within specified revision. * where <i>n</i> is a number of different entity classes modified within specified revision.
* @param revision Revision number. *
* @param revisionType Type of modification. * @param revision Revision number.
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type. * @param revisionType Type of modification.
* @throws IllegalStateException If the associated entity manager is closed. *
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0. * @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
*/ *
public List<Object> findEntities(Number revision, RevisionType revisionType) throws IllegalStateException, * @throws IllegalStateException If the associated entity manager is closed.
IllegalArgumentException; * @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public List<Object> findEntities(Number revision, RevisionType revisionType) throws IllegalStateException,
IllegalArgumentException;
/** /**
* Find all entities changed (added, updated and removed) in a given revision grouped by modification type. * Find all entities changed (added, updated and removed) in a given revision grouped by modification type.
* Executes <i>mn+1</i> SQL queries, where: * Executes <i>mn+1</i> SQL queries, where:
* <ul> * <ul>
* <li><i>n</i> - number of different entity classes modified within specified revision. * <li><i>n</i> - number of different entity classes modified within specified revision.
* <li><i>m</i> - number of different revision types. See {@link RevisionType} enum. * <li><i>m</i> - number of different revision types. See {@link RevisionType} enum.
* </ul> * </ul>
* @param revision Revision number. *
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal). * @param revision Revision number.
* @throws IllegalStateException If the associated entity manager is closed. *
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0. * @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
*/ *
public Map<RevisionType, List<Object>> findEntitiesGroupByRevisionType(Number revision) throws IllegalStateException, * @throws IllegalStateException If the associated entity manager is closed.
IllegalArgumentException; * @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public Map<RevisionType, List<Object>> findEntitiesGroupByRevisionType(Number revision)
throws IllegalStateException,
IllegalArgumentException;
/** /**
* Returns set of entity names and corresponding Java classes modified in a given revision. * Returns set of entity names and corresponding Java classes modified in a given revision.
* @param revision Revision number. *
* @return Set of entity names and corresponding Java classes modified in a given revision. * @param revision Revision number.
* @throws IllegalStateException If the associated entity manager is closed. *
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0. * @return Set of entity names and corresponding Java classes modified in a given revision.
*/ *
public Set<Pair<String, Class>> findEntityTypes(Number revision) throws IllegalStateException, IllegalArgumentException; * @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public Set<Pair<String, Class>> findEntityTypes(Number revision)
throws IllegalStateException, IllegalArgumentException;
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,13 +22,14 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers; package org.hibernate.envers;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.Date;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.Transient; import javax.persistence.Transient;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.Date;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
@ -36,56 +37,61 @@ import javax.persistence.Transient;
@MappedSuperclass @MappedSuperclass
public class DefaultRevisionEntity implements Serializable { public class DefaultRevisionEntity implements Serializable {
private static final long serialVersionUID = 8530213963961662300L; private static final long serialVersionUID = 8530213963961662300L;
@Id
@GeneratedValue
@RevisionNumber
private int id;
@RevisionTimestamp @Id
private long timestamp; @GeneratedValue
@RevisionNumber
private int id;
public int getId() { @RevisionTimestamp
return id; private long timestamp;
}
public void setId(int id) { public int getId() {
this.id = id; return id;
} }
@Transient public void setId(int id) {
public Date getRevisionDate() { this.id = id;
return new Date(timestamp); }
}
public long getTimestamp() { @Transient
return timestamp; public Date getRevisionDate() {
} return new Date( timestamp );
}
public void setTimestamp(long timestamp) { public long getTimestamp() {
this.timestamp = timestamp; return timestamp;
} }
public boolean equals(Object o) { public void setTimestamp(long timestamp) {
if (this == o) return true; this.timestamp = timestamp;
if (!(o instanceof DefaultRevisionEntity)) return false; }
DefaultRevisionEntity that = (DefaultRevisionEntity) o; @Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( !(o instanceof DefaultRevisionEntity) ) {
return false;
}
if (id != that.id) return false; final DefaultRevisionEntity that = (DefaultRevisionEntity) o;
if (timestamp != that.timestamp) return false; return id == that.id
&& timestamp == that.timestamp;
}
return true; @Override
} public int hashCode() {
int result;
result = id;
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
return result;
}
public int hashCode() { @Override
int result; public String toString() {
result = id; return "DefaultRevisionEntity(id = " + id
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); + ", revisionDate = " + DateFormat.getDateTimeInstance().format( getRevisionDate() ) + ")";
return result; }
}
public String toString() {
return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
}
} }

View File

@ -1,13 +1,36 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers; package org.hibernate.envers;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.annotations.Fetch; import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.FetchMode;
@ -16,45 +39,57 @@ import org.hibernate.annotations.FetchMode;
* Extension of standard {@link DefaultRevisionEntity} that allows tracking entity names changed in each revision. * Extension of standard {@link DefaultRevisionEntity} that allows tracking entity names changed in each revision.
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision} * This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}. * parameter is set to {@code true}.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
@MappedSuperclass @MappedSuperclass
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity { public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER) @ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV")) @JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME") @Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN) @Fetch(FetchMode.JOIN)
@ModifiedEntityNames @ModifiedEntityNames
private Set<String> modifiedEntityNames = new HashSet<String>(); private Set<String> modifiedEntityNames = new HashSet<String>();
public Set<String> getModifiedEntityNames() { public Set<String> getModifiedEntityNames() {
return modifiedEntityNames; return modifiedEntityNames;
} }
public void setModifiedEntityNames(Set<String> modifiedEntityNames) { public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
this.modifiedEntityNames = modifiedEntityNames; this.modifiedEntityNames = modifiedEntityNames;
} }
public boolean equals(Object o) { @Override
if (this == o) return true; public boolean equals(Object o) {
if (!(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity)) return false; if ( this == o ) {
if (!super.equals(o)) return false; return true;
}
if ( !(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity) ) {
return false;
}
if ( !super.equals( o ) ) {
return false;
}
DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o; final DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames) if ( modifiedEntityNames != null ? !modifiedEntityNames.equals( that.modifiedEntityNames )
: that.modifiedEntityNames != null) return false; : that.modifiedEntityNames != null ) {
return false;
}
return true; return true;
} }
public int hashCode() { @Override
int result = super.hashCode(); public int hashCode() {
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0); int result = super.hashCode();
return result; result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
} return result;
}
public String toString() { @Override
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")"; public String toString() {
} return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
}
} }

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers; package org.hibernate.envers;
import java.io.Serializable; import java.io.Serializable;
@ -5,19 +28,22 @@ import java.io.Serializable;
/** /**
* Extension of standard {@link RevisionListener} that notifies whenever an entity instance has been * Extension of standard {@link RevisionListener} that notifies whenever an entity instance has been
* added, modified or removed within current revision boundaries. * added, modified or removed within current revision boundaries.
* @see RevisionListener *
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @see RevisionListener
*/ */
public interface EntityTrackingRevisionListener extends RevisionListener { public interface EntityTrackingRevisionListener extends RevisionListener {
/** /**
* Called after audited entity data has been persisted. * Called after audited entity data has been persisted.
* @param entityClass Audited entity class. *
* @param entityName Name of the audited entity. May be useful when Java class is mapped multiple times, * @param entityClass Audited entity class.
* potentially to different tables. * @param entityName Name of the audited entity. May be useful when Java class is mapped multiple times,
* @param entityId Identifier of modified entity. * potentially to different tables.
* @param revisionType Modification type (addition, update or removal). * @param entityId Identifier of modified entity.
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}. * @param revisionType Modification type (addition, update or removal).
*/ * @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}.
void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType, */
Object revisionEntity); void entityChanged(
Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity);
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -28,5 +28,5 @@ package org.hibernate.envers;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public enum ModificationStore { public enum ModificationStore {
FULL FULL
} }

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
@ -8,6 +31,7 @@ import java.lang.annotation.Target;
/** /**
* Marks a property which holds entity names that have been modified during each revision. * Marks a property which holds entity names that have been modified during each revision.
* This annotation expects field of <code>{@literal Set<String>}</code> type. * This annotation expects field of <code>{@literal Set<String>}</code> type.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -29,6 +30,7 @@ import java.lang.annotation.Target;
/** /**
* When applied to a field, indicates that this field should not be audited. * When applied to a field, indicates that this field should not be audited.
*
* @author Sebastian Komander * @author Sebastian Komander
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU

View File

@ -34,15 +34,15 @@ import java.lang.annotation.Target;
* and a long-valued property annotated with {@link RevisionTimestamp}. The {@link DefaultRevisionEntity} * and a long-valued property annotated with {@link RevisionTimestamp}. The {@link DefaultRevisionEntity}
* already has those two fields, so you may extend it, but you may also write your own revision entity * already has those two fields, so you may extend it, but you may also write your own revision entity
* from scratch. * from scratch.
* *
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface RevisionEntity { public @interface RevisionEntity {
/** /**
* @return The optional listener that will be used to fill in the custom revision entity. * The optional listener that will be used to fill in the custom revision entity.
* May also be specified using the {@code org.hibernate.envers.revision_listener} configuration property. * May also be specified using the {@code org.hibernate.envers.revision_listener} configuration property.
*/ */
Class<? extends RevisionListener> value() default RevisionListener.class; Class<? extends RevisionListener> value() default RevisionListener.class;
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -27,13 +27,15 @@ package org.hibernate.envers;
/** /**
* An implementation of this class, having a no-arg constructor, should be passed as an argument to the * An implementation of this class, having a no-arg constructor, should be passed as an argument to the
* {@link RevisionEntity} annotation. * {@link RevisionEntity} annotation.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public interface RevisionListener { public interface RevisionListener {
/** /**
* Called when a new revision is created. * Called when a new revision is created.
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}, which will be persisted *
* after this method returns. All properties on this entity that are to be persisted should be set by this method. * @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}, which will be persisted
*/ * after this method returns. All properties on this entity that are to be persisted should be set by this method.
void newRevision(Object revisionEntity); */
void newRevision(Object revisionEntity);
} }

View File

@ -33,7 +33,7 @@ import java.lang.annotation.Target;
* {@link RevisionListener}. Values of this property should form a strictly-increasing sequence * {@link RevisionListener}. Values of this property should form a strictly-increasing sequence
* of numbers. The value of this property won't be set by Envers. In most cases, this should be * of numbers. The value of this property won't be set by Envers. In most cases, this should be
* an auto-generated database-assigned primary id. * an auto-generated database-assigned primary id.
* *
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Sanne Grinovero * @author Sanne Grinovero
*/ */

View File

@ -31,7 +31,7 @@ import java.lang.annotation.Target;
/** /**
* Marks a property which will hold the timestamp of the revision in a revision entity, see * Marks a property which will hold the timestamp of the revision in a revision entity, see
* {@link RevisionListener}. The value of this property will be automatically set by Envers. * {@link RevisionListener}. The value of this property will be automatically set by Envers.
* *
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Sanne Grinovero * @author Sanne Grinovero
*/ */

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -26,43 +26,51 @@ package org.hibernate.envers;
/** /**
* Type of the revision. * Type of the revision.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public enum RevisionType { public enum RevisionType {
/** /**
* Indicates that the entity was added (persisted) at that revision. * Indicates that the entity was added (persisted) at that revision.
*/ */
ADD((byte) 0), ADD( (byte) 0 ),
/** /**
* Indicates that the entity was modified (one or more of its fields) at that revision. * Indicates that the entity was modified (one or more of its fields) at that revision.
*/ */
MOD((byte) 1), MOD( (byte) 1 ),
/** /**
* Indicates that the entity was deleted (removed) at that revision. * Indicates that the entity was deleted (removed) at that revision.
*/ */
DEL((byte) 2); DEL( (byte) 2 );
private Byte representation; private Byte representation;
RevisionType(byte representation) { RevisionType(byte representation) {
this.representation = representation; this.representation = representation;
} }
public Byte getRepresentation() { public Byte getRepresentation() {
return representation; return representation;
} }
public static RevisionType fromRepresentation(Object representation) { public static RevisionType fromRepresentation(Object representation) {
if (representation == null || !(representation instanceof Byte)) { if ( representation == null || !(representation instanceof Byte) ) {
return null; return null;
} }
switch ((Byte) representation) { switch ( (Byte) representation ) {
case 0: return ADD; case 0: {
case 1: return MOD; return ADD;
case 2: return DEL; }
} case 1: {
return MOD;
throw new IllegalArgumentException("Unknown representation: " + representation); }
} case 2: {
return DEL;
}
default: {
throw new IllegalArgumentException( "Unknown representation: " + representation );
}
}
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -33,7 +34,7 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface SecondaryAuditTable { public @interface SecondaryAuditTable {
String secondaryTableName(); String secondaryTableName();
String secondaryAuditTableName(); String secondaryAuditTableName();
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers; package org.hibernate.envers;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -33,5 +34,5 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface SecondaryAuditTables { public @interface SecondaryAuditTables {
SecondaryAuditTable[] value(); SecondaryAuditTable[] value();
} }

View File

@ -1,7 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration; package org.hibernate.envers.configuration;
import org.hibernate.envers.strategy.DefaultAuditStrategy;
/** /**
* Configuration property names. * Configuration property names.
* *
@ -69,7 +90,7 @@ public interface EnversSettings {
public static final String AUDIT_TABLE_SUFFIX = "org.hibernate.envers.audit_table_suffix"; public static final String AUDIT_TABLE_SUFFIX = "org.hibernate.envers.audit_table_suffix";
/** /**
* Audit strategy. Defaults to {@link DefaultAuditStrategy}. * Audit strategy. Defaults to {@link org.hibernate.envers.strategy.DefaultAuditStrategy}.
*/ */
public static final String AUDIT_STRATEGY = "org.hibernate.envers.audit_strategy"; public static final String AUDIT_STRATEGY = "org.hibernate.envers.audit_strategy";
@ -99,7 +120,7 @@ public interface EnversSettings {
* Defaults to {@literal REVEND_TSTMP}. * Defaults to {@literal REVEND_TSTMP}.
*/ */
public static final String AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME = "org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name"; public static final String AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME = "org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name";
/** /**
* Name of column used for storing ordinal of the change in sets of embeddable elements. Defaults to {@literal SETORDINAL}. * Name of column used for storing ordinal of the change in sets of embeddable elements. Defaults to {@literal SETORDINAL}.
*/ */

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -59,7 +59,7 @@ public class AuditEntitiesConfiguration {
private final boolean revisionEndTimestampEnabled; private final boolean revisionEndTimestampEnabled;
private final String revisionEndTimestampFieldName; private final String revisionEndTimestampFieldName;
private final String embeddableSetOrdinalPropertyName; private final String embeddableSetOrdinalPropertyName;
public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) { public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {

View File

@ -1,4 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal; package org.hibernate.envers.configuration.internal;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -15,84 +39,100 @@ import org.hibernate.mapping.PersistentClass;
/** /**
* A helper class holding auditing meta-data for all persistent classes. * A helper class holding auditing meta-data for all persistent classes.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class ClassesAuditingData { public class ClassesAuditingData {
private static final EnversMessageLogger LOG = Logger.getMessageLogger(
EnversMessageLogger.class,
ClassesAuditingData.class.getName()
);
public static final EnversMessageLogger LOG = Logger.getMessageLogger(EnversMessageLogger.class, ClassesAuditingData.class.getName()); private final Map<String, ClassAuditingData> entityNameToAuditingData = new HashMap<String, ClassAuditingData>();
private final Map<PersistentClass, ClassAuditingData> persistentClassToAuditingData = new LinkedHashMap<PersistentClass, ClassAuditingData>();
private final Map<String, ClassAuditingData> entityNameToAuditingData = new HashMap<String, ClassAuditingData>(); /**
private final Map<PersistentClass, ClassAuditingData> persistentClassToAuditingData = new LinkedHashMap<PersistentClass, ClassAuditingData>(); * Stores information about auditing meta-data for the given class.
*
* @param pc Persistent class.
* @param cad Auditing meta-data for the given class.
*/
public void addClassAuditingData(PersistentClass pc, ClassAuditingData cad) {
entityNameToAuditingData.put( pc.getEntityName(), cad );
persistentClassToAuditingData.put( pc, cad );
}
/** /**
* Stores information about auditing meta-data for the given class. * @return A collection of all auditing meta-data for persistent classes.
* @param pc Persistent class. */
* @param cad Auditing meta-data for the given class. public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
*/ return persistentClassToAuditingData.entrySet();
public void addClassAuditingData(PersistentClass pc, ClassAuditingData cad) { }
entityNameToAuditingData.put(pc.getEntityName(), cad);
persistentClassToAuditingData.put(pc, cad);
}
/** /**
* @return A collection of all auditing meta-data for persistent classes. * @param entityName Name of the entity.
*/ *
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() { * @return Auditing meta-data for the given entity.
return persistentClassToAuditingData.entrySet(); */
} public ClassAuditingData getClassAuditingData(String entityName) {
return entityNameToAuditingData.get( entityName );
}
/** /**
* @param entityName Name of the entity. * After all meta-data is read, updates calculated fields. This includes:
* @return Auditing meta-data for the given entity. * <ul>
*/ * <li>setting {@code forceInsertable} to {@code true} for properties specified by {@code @AuditMappedBy}</li>
public ClassAuditingData getClassAuditingData(String entityName) { * </ul>
return entityNameToAuditingData.get(entityName); */
} public void updateCalculatedFields() {
for ( Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet() ) {
final PersistentClass pc = classAuditingDataEntry.getKey();
final ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
for ( String propertyName : classAuditingData.getPropertyNames() ) {
final PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData( propertyName );
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
if ( propertyAuditingData.getAuditMappedBy() != null ) {
final String referencedEntityName = MappingTools.getReferencedEntityName(
pc.getProperty( propertyName ).getValue()
);
/** final ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get( referencedEntityName );
* After all meta-data is read, updates calculated fields. This includes:
* <ul>
* <li>setting {@code forceInsertable} to {@code true} for properties specified by {@code @AuditMappedBy}</li>
* </ul>
*/
public void updateCalculatedFields() {
for (Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet()) {
PersistentClass pc = classAuditingDataEntry.getKey();
ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
for (String propertyName : classAuditingData.getPropertyNames()) {
PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData(propertyName);
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
if (propertyAuditingData.getAuditMappedBy() != null) {
String referencedEntityName = MappingTools.getReferencedEntityName(pc.getProperty(propertyName).getValue());
ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get(referencedEntityName); forcePropertyInsertable(
referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
pc.getEntityName(), referencedEntityName
);
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(), forcePropertyInsertable(
pc.getEntityName(), referencedEntityName); referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
pc.getEntityName(), referencedEntityName
);
}
}
}
}
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(), private void forcePropertyInsertable(
pc.getEntityName(), referencedEntityName); ClassAuditingData classAuditingData, String propertyName,
} String entityName, String referencedEntityName) {
} if ( propertyName != null ) {
} if ( classAuditingData.getPropertyAuditingData( propertyName ) == null ) {
} throw new MappingException(
"@AuditMappedBy points to a property that doesn't exist: " +
referencedEntityName + "." + propertyName
);
}
private void forcePropertyInsertable(ClassAuditingData classAuditingData, String propertyName, LOG.debugf(
String entityName, String referencedEntityName) { "Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
if (propertyName != null) { referencedEntityName,
if (classAuditingData.getPropertyAuditingData(propertyName) == null) { propertyName,
throw new MappingException("@AuditMappedBy points to a property that doesn't exist: " + entityName
referencedEntityName + "." + propertyName); );
}
LOG.debugf("Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity", classAuditingData
referencedEntityName, .getPropertyAuditingData( propertyName )
propertyName, .setForceInsertable( true );
entityName); }
}
classAuditingData
.getPropertyAuditingData(propertyName)
.setForceInsertable(true);
}
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -57,108 +57,118 @@ import org.hibernate.mapping.PersistentClass;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class EntitiesConfigurator { public class EntitiesConfigurator {
public EntitiesConfigurations configure(Configuration cfg, ReflectionManager reflectionManager, public EntitiesConfigurations configure(
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg, Configuration cfg, ReflectionManager reflectionManager,
AuditStrategy auditStrategy, ClassLoaderService classLoaderService, GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) { AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
// Creating a name register to capture all audit entity names created. Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister(); // Creating a name register to capture all audit entity names created.
DOMWriter writer = new DOMWriter(); final AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister();
final DOMWriter writer = new DOMWriter();
// Sorting the persistent class topologically - superclass always before subclass // Sorting the persistent class topologically - superclass always before subclass
Iterator<PersistentClass> classes = GraphTopologicalSort.sort(new PersistentClassGraphDefiner(cfg)).iterator(); final Iterator<PersistentClass> classes = GraphTopologicalSort.sort( new PersistentClassGraphDefiner( cfg ) )
.iterator();
ClassesAuditingData classesAuditingData = new ClassesAuditingData(); final ClassesAuditingData classesAuditingData = new ClassesAuditingData();
Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>(); final Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
// Reading metadata from annotations // Reading metadata from annotations
while (classes.hasNext()) { while ( classes.hasNext() ) {
PersistentClass pc = classes.next(); final PersistentClass pc = classes.next();
// Collecting information from annotations on the persistent class pc // Collecting information from annotations on the persistent class pc
AnnotationsMetadataReader annotationsMetadataReader = final AnnotationsMetadataReader annotationsMetadataReader =
new AnnotationsMetadataReader(globalCfg, reflectionManager, pc); new AnnotationsMetadataReader( globalCfg, reflectionManager, pc );
ClassAuditingData auditData = annotationsMetadataReader.getAuditData(); final ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
classesAuditingData.addClassAuditingData(pc, auditData); classesAuditingData.addClassAuditingData( pc, auditData );
} }
// Now that all information is read we can update the calculated fields. // Now that all information is read we can update the calculated fields.
classesAuditingData.updateCalculatedFields(); classesAuditingData.updateCalculatedFields();
AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(cfg, globalCfg, verEntCfg, auditStrategy, final AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(
classLoaderService, revisionInfoRelationMapping, auditEntityNameRegister); cfg, globalCfg, verEntCfg, auditStrategy,
classLoaderService, revisionInfoRelationMapping, auditEntityNameRegister
);
// First pass // First pass
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData()) { for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
PersistentClass pc = pcDatasEntry.getKey(); final PersistentClass pc = pcDatasEntry.getKey();
ClassAuditingData auditData = pcDatasEntry.getValue(); final ClassAuditingData auditData = pcDatasEntry.getValue();
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData(); final EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
if (auditData.isAudited()) { if ( auditData.isAudited() ) {
if (!StringTools.isEmpty(auditData.getAuditTable().value())) { if ( !StringTools.isEmpty( auditData.getAuditTable().value() ) ) {
verEntCfg.addCustomAuditTableName(pc.getEntityName(), auditData.getAuditTable().value()); verEntCfg.addCustomAuditTableName( pc.getEntityName(), auditData.getAuditTable().value() );
} }
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, true); auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, true );
} else { }
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, false); else {
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, false );
} }
xmlMappings.put(pc, xmlMappingData); xmlMappings.put( pc, xmlMappingData );
} }
// Second pass // Second pass
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData()) { for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey()); final EntityXmlMappingData xmlMappingData = xmlMappings.get( pcDatasEntry.getKey() );
if (pcDatasEntry.getValue().isAudited()) { if ( pcDatasEntry.getValue().isAudited() ) {
auditMetaGen.generateSecondPass(pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData); auditMetaGen.generateSecondPass( pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData );
try { try {
cfg.addDocument(writer.write(xmlMappingData.getMainXmlMapping())); cfg.addDocument( writer.write( xmlMappingData.getMainXmlMapping() ) );
//writeDocument(xmlMappingData.getMainXmlMapping()); //writeDocument(xmlMappingData.getMainXmlMapping());
for (Document additionalMapping : xmlMappingData.getAdditionalXmlMappings()) { for ( Document additionalMapping : xmlMappingData.getAdditionalXmlMappings() ) {
cfg.addDocument(writer.write(additionalMapping)); cfg.addDocument( writer.write( additionalMapping ) );
//writeDocument(additionalMapping); //writeDocument(additionalMapping);
} }
} catch (DocumentException e) { }
throw new MappingException(e); catch (DocumentException e) {
} throw new MappingException( e );
} }
} }
}
// Only if there are any versioned classes // Only if there are any versioned classes
if (auditMetaGen.getEntitiesConfigurations().size() > 0) { if ( auditMetaGen.getEntitiesConfigurations().size() > 0 ) {
try { try {
if (revisionInfoXmlMapping != null) { if ( revisionInfoXmlMapping != null ) {
//writeDocument(revisionInfoXmlMapping); //writeDocument(revisionInfoXmlMapping);
cfg.addDocument(writer.write(revisionInfoXmlMapping)); cfg.addDocument( writer.write( revisionInfoXmlMapping ) );
} }
} catch (DocumentException e) { }
throw new MappingException(e); catch (DocumentException e) {
} throw new MappingException( e );
} }
}
return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations(), return new EntitiesConfigurations(
auditMetaGen.getNotAuditedEntitiesConfigurations()); auditMetaGen.getEntitiesConfigurations(),
} auditMetaGen.getNotAuditedEntitiesConfigurations()
);
}
@SuppressWarnings({"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration"})
private void writeDocument(Document e) { private void writeDocument(Document e) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); final ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer w = new PrintWriter(baos); final Writer w = new PrintWriter( baos );
try { try {
XMLWriter xw = new XMLWriter(w, new OutputFormat(" ", true)); final XMLWriter xw = new XMLWriter( w, new OutputFormat( " ", true ) );
xw.write(e); xw.write( e );
w.flush(); w.flush();
} catch (IOException e1) { }
e1.printStackTrace(); catch (IOException e1) {
} e1.printStackTrace();
}
System.out.println("-----------"); System.out.println( "-----------" );
System.out.println(baos.toString()); System.out.println( baos.toString() );
System.out.println("-----------"); System.out.println( "-----------" );
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -116,13 +116,16 @@ public class GlobalConfiguration {
EnversSettings.MODIFIED_FLAG_SUFFIX, properties, "_MOD" EnversSettings.MODIFIED_FLAG_SUFFIX, properties, "_MOD"
); );
String revisionListenerClassName = properties.getProperty( EnversSettings.REVISION_LISTENER, null ); final String revisionListenerClassName = properties.getProperty( EnversSettings.REVISION_LISTENER, null );
if ( revisionListenerClassName != null ) { if ( revisionListenerClassName != null ) {
try { try {
revisionListenerClass = ReflectionTools.loadClass( revisionListenerClassName, classLoaderService ); revisionListenerClass = ReflectionTools.loadClass( revisionListenerClassName, classLoaderService );
} }
catch ( ClassLoadingException e ) { catch (ClassLoadingException e) {
throw new MappingException( "Revision listener class not found: " + revisionListenerClassName + ".", e ); throw new MappingException(
"Revision listener class not found: " + revisionListenerClassName + ".",
e
);
} }
} }
else { else {

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal; package org.hibernate.envers.configuration.internal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -34,43 +35,48 @@ import org.hibernate.mapping.PersistentClass;
/** /**
* Defines a graph, where the vertexes are all persistent classes, and there is an edge from * Defines a graph, where the vertexes are all persistent classes, and there is an edge from
* p.c. A to p.c. B iff A is a superclass of B. * p.c. A to p.c. B iff A is a superclass of B.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass, String> { public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass, String> {
private Configuration cfg; private Configuration cfg;
public PersistentClassGraphDefiner(Configuration cfg) { public PersistentClassGraphDefiner(Configuration cfg) {
this.cfg = cfg; this.cfg = cfg;
} }
public String getRepresentation(PersistentClass pc) { @Override
return pc.getEntityName(); public String getRepresentation(PersistentClass pc) {
} return pc.getEntityName();
}
public PersistentClass getValue(String entityName) { @Override
return cfg.getClassMapping(entityName); public PersistentClass getValue(String entityName) {
} return cfg.getClassMapping( entityName );
}
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) { private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
while (subclassIterator.hasNext()) { while ( subclassIterator.hasNext() ) {
PersistentClass subclass = subclassIterator.next(); final PersistentClass subclass = subclassIterator.next();
neighbours.add(subclass); neighbours.add( subclass );
addNeighbours(neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator()); addNeighbours( neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator() );
} }
} }
@SuppressWarnings({"unchecked"}) @Override
public List<PersistentClass> getNeighbours(PersistentClass pc) { @SuppressWarnings({"unchecked"})
List<PersistentClass> neighbours = new ArrayList<PersistentClass>(); public List<PersistentClass> getNeighbours(PersistentClass pc) {
final List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
addNeighbours(neighbours, (Iterator<PersistentClass>) pc.getSubclassIterator()); addNeighbours( neighbours, (Iterator<PersistentClass>) pc.getSubclassIterator() );
return neighbours; return neighbours;
} }
@SuppressWarnings({"unchecked"}) @Override
public List<PersistentClass> getValues() { @SuppressWarnings({"unchecked"})
return Tools.iteratorToList( cfg.getClassMappings() ); public List<PersistentClass> getValues() {
} return Tools.iteratorToList( cfg.getClassMappings() );
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,10 +22,11 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal; package org.hibernate.envers.configuration.internal;
import javax.persistence.Column;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import javax.persistence.Column;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.Element; import org.dom4j.Element;
@ -65,301 +66,394 @@ import org.hibernate.type.Type;
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public class RevisionInfoConfiguration { public class RevisionInfoConfiguration {
private String revisionInfoEntityName; private String revisionInfoEntityName;
private PropertyData revisionInfoIdData; private PropertyData revisionInfoIdData;
private PropertyData revisionInfoTimestampData; private PropertyData revisionInfoTimestampData;
private PropertyData modifiedEntityNamesData; private PropertyData modifiedEntityNamesData;
private Type revisionInfoTimestampType; private Type revisionInfoTimestampType;
private GlobalConfiguration globalCfg; private GlobalConfiguration globalCfg;
private String revisionPropType; private String revisionPropType;
private String revisionPropSqlType; private String revisionPropSqlType;
public RevisionInfoConfiguration(GlobalConfiguration globalCfg) { public RevisionInfoConfiguration(GlobalConfiguration globalCfg) {
this.globalCfg = globalCfg; this.globalCfg = globalCfg;
if (globalCfg.isUseRevisionEntityWithNativeId()) { if ( globalCfg.isUseRevisionEntityWithNativeId() ) {
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity"; revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
} else { }
revisionInfoEntityName = "org.hibernate.envers.enhanced.SequenceIdRevisionEntity"; else {
} revisionInfoEntityName = "org.hibernate.envers.enhanced.SequenceIdRevisionEntity";
revisionInfoIdData = new PropertyData("id", "id", "field", null); }
revisionInfoTimestampData = new PropertyData("timestamp", "timestamp", "field", null); revisionInfoIdData = new PropertyData( "id", "id", "field", null );
modifiedEntityNamesData = new PropertyData("modifiedEntityNames", "modifiedEntityNames", "field", null); revisionInfoTimestampData = new PropertyData( "timestamp", "timestamp", "field", null );
revisionInfoTimestampType = new LongType(); modifiedEntityNamesData = new PropertyData( "modifiedEntityNames", "modifiedEntityNames", "field", null );
revisionInfoTimestampType = new LongType();
revisionPropType = "integer"; revisionPropType = "integer";
} }
private Document generateDefaultRevisionInfoXmlMapping() { private Document generateDefaultRevisionInfoXmlMapping() {
Document document = XMLHelper.getDocumentFactory().createDocument(); final Document document = XMLHelper.getDocumentFactory().createDocument();
Element class_mapping = MetadataTools.createEntity(document, new AuditTableData(null, null, globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName()), null, null); final Element classMapping = MetadataTools.createEntity(
document,
new AuditTableData( null, null, globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName() ),
null,
null
);
class_mapping.addAttribute("name", revisionInfoEntityName); classMapping.addAttribute( "name", revisionInfoEntityName );
class_mapping.addAttribute("table", "REVINFO"); classMapping.addAttribute( "table", "REVINFO" );
Element idProperty = MetadataTools.addNativelyGeneratedId(class_mapping, revisionInfoIdData.getName(), final Element idProperty = MetadataTools.addNativelyGeneratedId(
revisionPropType, globalCfg.isUseRevisionEntityWithNativeId()); classMapping,
MetadataTools.addColumn(idProperty, "REV", null, null, null, null, null, null, false); revisionInfoIdData.getName(),
revisionPropType,
globalCfg.isUseRevisionEntityWithNativeId()
);
MetadataTools.addColumn( idProperty, "REV", null, null, null, null, null, null, false );
Element timestampProperty = MetadataTools.addProperty(class_mapping, revisionInfoTimestampData.getName(), final Element timestampProperty = MetadataTools.addProperty(
revisionInfoTimestampType.getName(), true, false); classMapping,
MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, null, null, null, null, null, false); revisionInfoTimestampData.getName(),
revisionInfoTimestampType.getName(),
true,
false
);
MetadataTools.addColumn( timestampProperty, "REVTSTMP", null, null, null, null, null, null, false );
if (globalCfg.isTrackEntitiesChangedInRevision()) { if ( globalCfg.isTrackEntitiesChangedInRevision() ) {
generateEntityNamesTrackingTableMapping(class_mapping, "modifiedEntityNames", generateEntityNamesTrackingTableMapping(
globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName(), classMapping,
"REVCHANGES", "REV", "ENTITYNAME", "string"); "modifiedEntityNames",
} globalCfg.getDefaultSchemaName(),
globalCfg.getDefaultCatalogName(),
"REVCHANGES",
"REV",
"ENTITYNAME",
"string"
);
}
return document; return document;
} }
/** /**
* Generates mapping that represents a set of primitive types.<br /> * Generates mapping that represents a set of primitive types.<br />
* <code> * <code>
* &lt;set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog" * &lt;set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog"
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cascade="persist, delete" lazy="false" fetch="join"&gt;<br /> * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cascade="persist, delete" lazy="false" fetch="join"&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;key column="joinTablePrimaryKeyColumnName" /&gt;<br /> * &nbsp;&nbsp;&nbsp;&lt;key column="joinTablePrimaryKeyColumnName" /&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;element type="joinTableValueColumnType"&gt;<br /> * &nbsp;&nbsp;&nbsp;&lt;element type="joinTableValueColumnType"&gt;<br />
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;column name="joinTableValueColumnName" /&gt;<br /> * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;column name="joinTableValueColumnName" /&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;/element&gt;<br /> * &nbsp;&nbsp;&nbsp;&lt;/element&gt;<br />
* &lt;/set&gt; * &lt;/set&gt;
* </code> * </code>
*/ */
private void generateEntityNamesTrackingTableMapping(Element class_mapping, String propertyName, private void generateEntityNamesTrackingTableMapping(
String joinTableSchema, String joinTableCatalog, String joinTableName, Element classMapping,
String joinTablePrimaryKeyColumnName, String joinTableValueColumnName, String propertyName,
String joinTableValueColumnType) { String joinTableSchema,
Element set = class_mapping.addElement("set"); String joinTableCatalog,
set.addAttribute("name", propertyName); String joinTableName,
set.addAttribute("table", joinTableName); String joinTablePrimaryKeyColumnName,
set.addAttribute("schema", joinTableSchema); String joinTableValueColumnName,
set.addAttribute("catalog", joinTableCatalog); String joinTableValueColumnType) {
set.addAttribute("cascade", "persist, delete"); final Element set = classMapping.addElement( "set" );
set.addAttribute("fetch", "join"); set.addAttribute( "name", propertyName );
set.addAttribute("lazy", "false"); set.addAttribute( "table", joinTableName );
Element key = set.addElement("key"); set.addAttribute( "schema", joinTableSchema );
key.addAttribute("column", joinTablePrimaryKeyColumnName); set.addAttribute( "catalog", joinTableCatalog );
Element element = set.addElement("element"); set.addAttribute( "cascade", "persist, delete" );
element.addAttribute("type", joinTableValueColumnType); set.addAttribute( "fetch", "join" );
Element column = element.addElement("column"); set.addAttribute( "lazy", "false" );
column.addAttribute("name", joinTableValueColumnName); final Element key = set.addElement( "key" );
} key.addAttribute( "column", joinTablePrimaryKeyColumnName );
final Element element = set.addElement( "element" );
element.addAttribute( "type", joinTableValueColumnType );
final Element column = element.addElement( "column" );
column.addAttribute( "name", joinTableValueColumnName );
}
private Element generateRevisionInfoRelationMapping() { private Element generateRevisionInfoRelationMapping() {
Document document = XMLHelper.getDocumentFactory().createDocument(); final Document document = XMLHelper.getDocumentFactory().createDocument();
Element rev_rel_mapping = document.addElement("key-many-to-one"); final Element revRelMapping = document.addElement( "key-many-to-one" );
rev_rel_mapping.addAttribute("type", revisionPropType); revRelMapping.addAttribute( "type", revisionPropType );
rev_rel_mapping.addAttribute("class", revisionInfoEntityName); revRelMapping.addAttribute( "class", revisionInfoEntityName );
if (revisionPropSqlType != null) { if ( revisionPropSqlType != null ) {
// Putting a fake name to make Hibernate happy. It will be replaced later anyway. // Putting a fake name to make Hibernate happy. It will be replaced later anyway.
MetadataTools.addColumn(rev_rel_mapping, "*" , null, null, null, revisionPropSqlType, null, null, false); MetadataTools.addColumn( revRelMapping, "*", null, null, null, revisionPropSqlType, null, null, false );
} }
return rev_rel_mapping; return revRelMapping;
} }
private void searchForRevisionInfoCfgInProperties(XClass clazz, ReflectionManager reflectionManager, private void searchForRevisionInfoCfgInProperties(
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound, XClass clazz,
MutableBoolean modifiedEntityNamesFound, String accessType) { ReflectionManager reflectionManager,
for (XProperty property : clazz.getDeclaredProperties(accessType)) { MutableBoolean revisionNumberFound,
RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class); MutableBoolean revisionTimestampFound,
RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class); MutableBoolean modifiedEntityNamesFound,
ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class); String accessType) {
for ( XProperty property : clazz.getDeclaredProperties( accessType ) ) {
final RevisionNumber revisionNumber = property.getAnnotation( RevisionNumber.class );
final RevisionTimestamp revisionTimestamp = property.getAnnotation( RevisionTimestamp.class );
final ModifiedEntityNames modifiedEntityNames = property.getAnnotation( ModifiedEntityNames.class );
if (revisionNumber != null) { if ( revisionNumber != null ) {
if (revisionNumberFound.isSet()) { if ( revisionNumberFound.isSet() ) {
throw new MappingException("Only one property may be annotated with @RevisionNumber!"); throw new MappingException( "Only one property may be annotated with @RevisionNumber!" );
} }
XClass revisionNumberClass = property.getType(); final XClass revisionNumberClass = property.getType();
if (reflectionManager.equals(revisionNumberClass, Integer.class) || if ( reflectionManager.equals( revisionNumberClass, Integer.class ) ||
reflectionManager.equals(revisionNumberClass, Integer.TYPE)) { reflectionManager.equals( revisionNumberClass, Integer.TYPE ) ) {
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null); revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
revisionNumberFound.set(); revisionNumberFound.set();
} else if (reflectionManager.equals(revisionNumberClass, Long.class) || }
reflectionManager.equals(revisionNumberClass, Long.TYPE)) { else if ( reflectionManager.equals( revisionNumberClass, Long.class ) ||
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null); reflectionManager.equals( revisionNumberClass, Long.TYPE ) ) {
revisionNumberFound.set(); revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
revisionNumberFound.set();
// The default is integer // The default is integer
revisionPropType = "long"; revisionPropType = "long";
} else { }
throw new MappingException("The field annotated with @RevisionNumber must be of type " + else {
"int, Integer, long or Long"); throw new MappingException(
} "The field annotated with @RevisionNumber must be of type " +
"int, Integer, long or Long"
);
}
// Getting the @Column definition of the revision number property, to later use that info to // Getting the @Column definition of the revision number property, to later use that info to
// generate the same mapping for the relation from an audit table's revision number to the // generate the same mapping for the relation from an audit table's revision number to the
// revision entity revision number. // revision entity revision number.
Column revisionPropColumn = property.getAnnotation(Column.class); final Column revisionPropColumn = property.getAnnotation( Column.class );
if (revisionPropColumn != null) { if ( revisionPropColumn != null ) {
revisionPropSqlType = revisionPropColumn.columnDefinition(); revisionPropSqlType = revisionPropColumn.columnDefinition();
} }
} }
if (revisionTimestamp != null) { if ( revisionTimestamp != null ) {
if (revisionTimestampFound.isSet()) { if ( revisionTimestampFound.isSet() ) {
throw new MappingException("Only one property may be annotated with @RevisionTimestamp!"); throw new MappingException( "Only one property may be annotated with @RevisionTimestamp!" );
} }
XClass revisionTimestampClass = property.getType(); final XClass revisionTimestampClass = property.getType();
if (reflectionManager.equals(revisionTimestampClass, Long.class) || if ( reflectionManager.equals( revisionTimestampClass, Long.class ) ||
reflectionManager.equals(revisionTimestampClass, Long.TYPE) || reflectionManager.equals( revisionTimestampClass, Long.TYPE ) ||
reflectionManager.equals(revisionTimestampClass, Date.class) || reflectionManager.equals( revisionTimestampClass, Date.class ) ||
reflectionManager.equals(revisionTimestampClass, java.sql.Date.class)) { reflectionManager.equals( revisionTimestampClass, java.sql.Date.class ) ) {
revisionInfoTimestampData = new PropertyData(property.getName(), property.getName(), accessType, null); revisionInfoTimestampData = new PropertyData(
revisionTimestampFound.set(); property.getName(),
} else { property.getName(),
throw new MappingException("The field annotated with @RevisionTimestamp must be of type " + accessType,
"long, Long, java.util.Date or java.sql.Date"); null
} );
} revisionTimestampFound.set();
}
else {
throw new MappingException(
"The field annotated with @RevisionTimestamp must be of type " +
"long, Long, java.util.Date or java.sql.Date"
);
}
}
if (modifiedEntityNames != null) { if ( modifiedEntityNames != null ) {
if (modifiedEntityNamesFound.isSet()) { if ( modifiedEntityNamesFound.isSet() ) {
throw new MappingException("Only one property may be annotated with @ModifiedEntityNames!"); throw new MappingException( "Only one property may be annotated with @ModifiedEntityNames!" );
} }
XClass modifiedEntityNamesClass = property.getType(); final XClass modifiedEntityNamesClass = property.getType();
if (reflectionManager.equals(modifiedEntityNamesClass, Set.class) && if ( reflectionManager.equals( modifiedEntityNamesClass, Set.class ) &&
reflectionManager.equals(property.getElementClass(), String.class)) { reflectionManager.equals( property.getElementClass(), String.class ) ) {
modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null); modifiedEntityNamesData = new PropertyData(
modifiedEntityNamesFound.set(); property.getName(),
} else { property.getName(),
throw new MappingException("The field annotated with @ModifiedEntityNames must be of Set<String> type."); accessType,
} null
} );
} modifiedEntityNamesFound.set();
} }
else {
throw new MappingException(
"The field annotated with @ModifiedEntityNames must be of Set<String> type."
);
}
}
}
}
private void searchForRevisionInfoCfg(XClass clazz, ReflectionManager reflectionManager, private void searchForRevisionInfoCfg(
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound, XClass clazz, ReflectionManager reflectionManager,
MutableBoolean modifiedEntityNamesFound) { MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
XClass superclazz = clazz.getSuperclass(); MutableBoolean modifiedEntityNamesFound) {
if (!"java.lang.Object".equals(superclazz.getName())) { final XClass superclazz = clazz.getSuperclass();
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound); if ( !"java.lang.Object".equals( superclazz.getName() ) ) {
} searchForRevisionInfoCfg(
superclazz,
reflectionManager,
revisionNumberFound,
revisionTimestampFound,
modifiedEntityNamesFound
);
}
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, searchForRevisionInfoCfgInProperties(
modifiedEntityNamesFound, "field"); clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound, "field"
modifiedEntityNamesFound, "property"); );
} searchForRevisionInfoCfgInProperties(
clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityNamesFound, "property"
);
}
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) { public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
Iterator<PersistentClass> classes = cfg.getClassMappings(); boolean revisionEntityFound = false;
boolean revisionEntityFound = false; RevisionInfoGenerator revisionInfoGenerator = null;
RevisionInfoGenerator revisionInfoGenerator = null; Class<?> revisionInfoClass = null;
Class<?> revisionInfoClass = null; final Iterator<PersistentClass> classes = cfg.getClassMappings();
while ( classes.hasNext() ) {
PersistentClass pc = classes.next();
XClass clazz;
try {
clazz = reflectionManager.classForName( pc.getClassName(), this.getClass() );
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
while (classes.hasNext()) { final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
PersistentClass pc = classes.next(); if ( revisionEntity != null ) {
XClass clazz; if ( revisionEntityFound ) {
try { throw new MappingException( "Only one entity may be annotated with @RevisionEntity!" );
clazz = reflectionManager.classForName(pc.getClassName(), this.getClass()); }
} catch (ClassNotFoundException e) {
throw new MappingException(e);
}
RevisionEntity revisionEntity = clazz.getAnnotation(RevisionEntity.class); // Checking if custom revision entity isn't audited
if (revisionEntity != null) { if ( clazz.getAnnotation( Audited.class ) != null ) {
if (revisionEntityFound) { throw new MappingException( "An entity annotated with @RevisionEntity cannot be audited!" );
throw new MappingException("Only one entity may be annotated with @RevisionEntity!"); }
}
// Checking if custom revision entity isn't audited revisionEntityFound = true;
if (clazz.getAnnotation(Audited.class) != null) {
throw new MappingException("An entity annotated with @RevisionEntity cannot be audited!");
}
revisionEntityFound = true; final MutableBoolean revisionNumberFound = new MutableBoolean();
final MutableBoolean revisionTimestampFound = new MutableBoolean();
final MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
MutableBoolean revisionNumberFound = new MutableBoolean(); searchForRevisionInfoCfg(
MutableBoolean revisionTimestampFound = new MutableBoolean(); clazz,
MutableBoolean modifiedEntityNamesFound = new MutableBoolean(); reflectionManager,
revisionNumberFound,
revisionTimestampFound,
modifiedEntityNamesFound
);
searchForRevisionInfoCfg(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound); if ( !revisionNumberFound.isSet() ) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionNumber!"
);
}
if (!revisionNumberFound.isSet()) { if ( !revisionTimestampFound.isSet() ) {
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " + throw new MappingException(
"with @RevisionNumber!"); "An entity annotated with @RevisionEntity must have a field annotated " +
} "with @RevisionTimestamp!"
);
}
if (!revisionTimestampFound.isSet()) { revisionInfoEntityName = pc.getEntityName();
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " + revisionInfoClass = pc.getMappedClass();
"with @RevisionTimestamp!"); final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( revisionEntity.value() );
} revisionInfoTimestampType = pc.getProperty( revisionInfoTimestampData.getName() ).getType();
if ( globalCfg.isTrackEntitiesChangedInRevision()
|| (globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom( revisionInfoClass ))
|| (!globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom( revisionInfoClass ))
|| modifiedEntityNamesFound.isSet() ) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityName,
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityNamesData
);
globalCfg.setTrackEntitiesChangedInRevision( true );
}
else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
}
}
revisionInfoEntityName = pc.getEntityName(); // In case of a custom revision info generator, the mapping will be null.
revisionInfoClass = pc.getMappedClass(); Document revisionInfoXmlMapping = null;
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(revisionEntity.value());
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
if (globalCfg.isTrackEntitiesChangedInRevision()
|| (globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass))
|| (!globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass))
|| modifiedEntityNamesFound.isSet()) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName,
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityNamesData);
globalCfg.setTrackEntitiesChangedInRevision(true);
} else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
}
}
}
// In case of a custom revision info generator, the mapping will be null. final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( RevisionListener.class );
Document revisionInfoXmlMapping = null;
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(RevisionListener.class); if ( revisionInfoGenerator == null ) {
if ( globalCfg.isTrackEntitiesChangedInRevision() ) {
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ?
DefaultTrackingModifiedEntitiesRevisionEntity.class
:
SequenceIdTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = revisionInfoClass.getName();
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData
);
}
else {
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultRevisionEntity.class
: SequenceIdRevisionEntity.class;
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
}
if (revisionInfoGenerator == null) { return new RevisionInfoConfigurationResult(
if (globalCfg.isTrackEntitiesChangedInRevision()) { revisionInfoGenerator, revisionInfoXmlMapping,
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultTrackingModifiedEntitiesRevisionEntity.class new RevisionInfoQueryCreator(
: SequenceIdTrackingModifiedEntitiesRevisionEntity.class; revisionInfoEntityName, revisionInfoIdData.getName(),
revisionInfoEntityName = revisionInfoClass.getName(); revisionInfoTimestampData.getName(), isTimestampAsDate()
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass, ),
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData); generateRevisionInfoRelationMapping(),
} else { new RevisionInfoNumberReader( revisionInfoClass, revisionInfoIdData ),
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultRevisionEntity.class globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(
: SequenceIdRevisionEntity.class; revisionInfoClass,
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass, modifiedEntityNamesData
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()); )
} : null,
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping(); revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData
} );
}
return new RevisionInfoConfigurationResult( private boolean isTimestampAsDate() {
revisionInfoGenerator, revisionInfoXmlMapping, final String typename = revisionInfoTimestampType.getName();
new RevisionInfoQueryCreator(revisionInfoEntityName, revisionInfoIdData.getName(), return "date".equals( typename ) || "time".equals( typename ) || "timestamp".equals( typename );
revisionInfoTimestampData.getName(), isTimestampAsDate()), }
generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData),
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData)
: null,
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData);
}
private boolean isTimestampAsDate() { /**
String typename = revisionInfoTimestampType.getName(); * @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
return "date".equals(typename) || "time".equals(typename) || "timestamp".equals(typename); * parameter has not been set.
} *
* @return Revision listener.
/** */
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener} private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) {
* parameter has not been set. if ( globalCfg.getRevisionListenerClass() != null ) {
* @return Revision listener. return globalCfg.getRevisionListenerClass();
*/ }
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) { return defaultListener;
if (globalCfg.getRevisionListenerClass() != null) { }
return globalCfg.getRevisionListenerClass();
}
return defaultListener;
}
} }

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal; package org.hibernate.envers.configuration.internal;
import org.dom4j.Document; import org.dom4j.Document;
@ -23,11 +46,12 @@ public class RevisionInfoConfigurationResult {
private final Class<?> revisionInfoClass; private final Class<?> revisionInfoClass;
private final PropertyData revisionInfoTimestampData; private final PropertyData revisionInfoTimestampData;
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator, RevisionInfoConfigurationResult(
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator, RevisionInfoGenerator revisionInfoGenerator,
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader, Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName, Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) { ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
this.revisionInfoGenerator = revisionInfoGenerator; this.revisionInfoGenerator = revisionInfoGenerator;
this.revisionInfoXmlMapping = revisionInfoXmlMapping; this.revisionInfoXmlMapping = revisionInfoXmlMapping;
this.revisionInfoQueryCreator = revisionInfoQueryCreator; this.revisionInfoQueryCreator = revisionInfoQueryCreator;

View File

@ -1,4 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -6,46 +30,49 @@ import org.hibernate.MappingException;
/** /**
* A register of all audit entity names used so far. * A register of all audit entity names used so far.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class AuditEntityNameRegister { public class AuditEntityNameRegister {
private final Set<String> auditEntityNames = new HashSet<String>(); private final Set<String> auditEntityNames = new HashSet<String>();
/** /**
* @param auditEntityName Name of the audit entity. * @param auditEntityName Name of the audit entity.
* @return True if the given audit entity name is already used.
*/
private boolean check(String auditEntityName) {
return auditEntityNames.contains(auditEntityName);
}
/**
* Register an audit entity name. If the name is already registered, an exception is thrown.
* @param auditEntityName Name of the audit entity.
*/
public void register(String auditEntityName) {
if (auditEntityNames.contains(auditEntityName)) {
throw new MappingException("The audit entity name '" + auditEntityName + "' is already registered.");
}
auditEntityNames.add(auditEntityName);
}
/**
* Creates a unique (not yet registered) audit entity name by appending consecutive numbers to the base
* name. If the base name is not yet used, it is returned unmodified.
* *
* @param baseAuditEntityName The base entity name. * @return True if the given audit entity name is already used.
* */
* @return A unique audit entity name private boolean check(String auditEntityName) {
*/ return auditEntityNames.contains( auditEntityName );
public String createUnique(final String baseAuditEntityName) { }
String auditEntityName = baseAuditEntityName;
int count = 1;
while (check(auditEntityName)) {
auditEntityName = baseAuditEntityName + count++;
}
return auditEntityName; /**
} * Register an audit entity name. If the name is already registered, an exception is thrown.
*
* @param auditEntityName Name of the audit entity.
*/
public void register(String auditEntityName) {
if ( auditEntityNames.contains( auditEntityName ) ) {
throw new MappingException( "The audit entity name '" + auditEntityName + "' is already registered." );
}
auditEntityNames.add( auditEntityName );
}
/**
* Creates a unique (not yet registered) audit entity name by appending consecutive numbers to the base
* name. If the base name is not yet used, it is returned unmodified.
*
* @param baseAuditEntityName The base entity name.
*
* @return A unique audit entity name
*/
public String createUnique(final String baseAuditEntityName) {
String auditEntityName = baseAuditEntityName;
int count = 1;
while ( check( auditEntityName ) ) {
auditEntityName = baseAuditEntityName + count++;
}
return auditEntityName;
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -21,41 +21,41 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
/** /**
* Holds information necessary to create an audit table: its name, schema and catalog, as well as the audit * Holds information necessary to create an audit table: its name, schema and catalog, as well as the audit
* entity name. * entity name.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class AuditTableData { public class AuditTableData {
private final String auditEntityName; private final String auditEntityName;
private final String auditTableName; private final String auditTableName;
private final String schema; private final String schema;
private final String catalog; private final String catalog;
public AuditTableData(String auditEntityName, String auditTableName, String schema, String catalog) { public AuditTableData(String auditEntityName, String auditTableName, String schema, String catalog) {
this.auditEntityName = auditEntityName; this.auditEntityName = auditEntityName;
this.auditTableName = auditTableName; this.auditTableName = auditTableName;
this.schema = schema; this.schema = schema;
this.catalog = catalog; this.catalog = catalog;
} }
public String getAuditEntityName() { public String getAuditEntityName() {
return auditEntityName; return auditEntityName;
} }
public String getAuditTableName() { public String getAuditTableName() {
return auditTableName; return auditTableName;
} }
public String getSchema() { public String getSchema() {
return schema; return schema;
} }
public String getCatalog() { public String getCatalog() {
return catalog; return catalog;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -40,47 +40,54 @@ import org.hibernate.usertype.DynamicParameterizedType;
/** /**
* Generates metadata for basic properties: immutable types (including enums). * Generates metadata for basic properties: immutable types (including enums).
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class BasicMetadataGenerator { public final class BasicMetadataGenerator {
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({"unchecked"})
boolean addBasic(Element parent, PropertyAuditingData propertyAuditingData, boolean addBasic(
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) { Element parent, PropertyAuditingData propertyAuditingData,
Type type = value.getType(); Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
final Type type = value.getType();
if ( type instanceof BasicType || type instanceof SerializableToBlobType || if ( type instanceof BasicType
"org.hibernate.type.PrimitiveByteArrayBlobType".equals( type.getClass().getName() ) ) { || type instanceof SerializableToBlobType
|| "org.hibernate.type.PrimitiveByteArrayBlobType".equals( type.getClass().getName() ) ) {
if ( parent != null ) { if ( parent != null ) {
boolean addNestedType = ( value instanceof SimpleValue ) && ( (SimpleValue) value ).getTypeParameters() != null; final boolean addNestedType = (value instanceof SimpleValue)
&& ((SimpleValue) value).getTypeParameters() != null;
String typeName = type.getName(); String typeName = type.getName();
if ( typeName == null ) { if ( typeName == null ) {
typeName = type.getClass().getName(); typeName = type.getClass().getName();
} }
Element prop_mapping = MetadataTools.addProperty( final Element propMapping = MetadataTools.addProperty(
parent, propertyAuditingData.getName(), parent,
addNestedType ? null : typeName, propertyAuditingData.isForceInsertable() || insertable, key propertyAuditingData.getName(),
addNestedType ? null : typeName,
propertyAuditingData.isForceInsertable() || insertable,
key
); );
MetadataTools.addColumns( prop_mapping, value.getColumnIterator() ); MetadataTools.addColumns( propMapping, value.getColumnIterator() );
if ( addNestedType ) { if ( addNestedType ) {
Properties typeParameters = ( (SimpleValue) value ).getTypeParameters(); final Properties typeParameters = ((SimpleValue) value).getTypeParameters();
Element type_mapping = prop_mapping.addElement( "type" ); final Element typeMapping = propMapping.addElement( "type" );
type_mapping.addAttribute( "name", typeName ); typeMapping.addAttribute( "name", typeName );
if ( "org.hibernate.type.EnumType".equals( typeName ) ) { if ( "org.hibernate.type.EnumType".equals( typeName ) ) {
// Proper handling of enumeration type // Proper handling of enumeration type
mapEnumerationType( type_mapping, type, typeParameters ); mapEnumerationType( typeMapping, type, typeParameters );
} }
else { else {
// By default copying all Hibernate properties // By default copying all Hibernate properties
for ( Object object : typeParameters.keySet() ) { for ( Object object : typeParameters.keySet() ) {
String keyType = (String) object; final String keyType = (String) object;
String property = typeParameters.getProperty( keyType ); final String property = typeParameters.getProperty( keyType );
if ( property != null ) { if ( property != null ) {
type_mapping.addElement( "param" ).addAttribute( "name", keyType ).setText( property ); typeMapping.addElement( "param" ).addAttribute( "name", keyType ).setText( property );
} }
} }
} }
@ -101,32 +108,43 @@ public final class BasicMetadataGenerator {
private void mapEnumerationType(Element parent, Type type, Properties parameters) { private void mapEnumerationType(Element parent, Type type, Properties parameters) {
if ( parameters.getProperty( EnumType.ENUM ) != null ) { if ( parameters.getProperty( EnumType.ENUM ) != null ) {
parent.addElement( "param" ).addAttribute( "name", EnumType.ENUM ).setText( parameters.getProperty( EnumType.ENUM ) ); parent.addElement( "param" )
.addAttribute( "name", EnumType.ENUM )
.setText( parameters.getProperty( EnumType.ENUM ) );
} }
else { else {
parent.addElement( "param" ).addAttribute( "name", EnumType.ENUM ).setText( type.getReturnedClass().getName() ); parent.addElement( "param" ).addAttribute( "name", EnumType.ENUM ).setText(
type.getReturnedClass()
.getName()
);
} }
if ( parameters.getProperty( EnumType.NAMED ) != null ) { if ( parameters.getProperty( EnumType.NAMED ) != null ) {
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED ).setText( parameters.getProperty( EnumType.NAMED ) ); parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED ).setText(
parameters.getProperty(
EnumType.NAMED
)
);
} }
else if ( parameters.get( DynamicParameterizedType.XPROPERTY ) != null ) { else if ( parameters.get( DynamicParameterizedType.XPROPERTY ) != null ) {
// Case of annotations. // Case of annotations.
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED ) parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED )
.setText( "" + !( (EnumType) ( (CustomType) type ).getUserType() ).isOrdinal() ); .setText( "" + !((EnumType) ((CustomType) type).getUserType()).isOrdinal() );
}
else {
// Otherwise we assume that the choice between ordinal and named representation has been omitted.
// Call to EnumType#isOrdinal() would always return the default Types.INTEGER. We let Hibernate
// to choose the proper strategy during runtime.
} }
// Otherwise we assume that the choice between ordinal and named representation has been omitted.
// Call to EnumType#isOrdinal() would always return the default Types.INTEGER. We let Hibernate
// to choose the proper strategy during runtime.
} }
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({"unchecked"})
boolean addManyToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value, SimpleMapperBuilder mapper) { boolean addManyToOne(
Type type = value.getType(); Element parent,
PropertyAuditingData propertyAuditingData,
Value value,
SimpleMapperBuilder mapper) {
final Type type = value.getType();
// A null mapper occurs when adding to composite-id element // A null mapper occurs when adding to composite-id element
Element manyToOneElement = parent.addElement( mapper != null ? "many-to-one" : "key-many-to-one" ); final Element manyToOneElement = parent.addElement( mapper != null ? "many-to-one" : "key-many-to-one" );
manyToOneElement.addAttribute( "name", propertyAuditingData.getName() ); manyToOneElement.addAttribute( "name", propertyAuditingData.getName() );
manyToOneElement.addAttribute( "class", type.getName() ); manyToOneElement.addAttribute( "class", type.getName() );
MetadataTools.addColumns( manyToOneElement, value.getColumnIterator() ); MetadataTools.addColumns( manyToOneElement, value.getColumnIterator() );

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import java.util.Iterator; import java.util.Iterator;
@ -14,6 +37,7 @@ import org.hibernate.mapping.Value;
/** /**
* Generates metadata for components. * Generates metadata for components.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class ComponentMetadataGenerator { public final class ComponentMetadataGenerator {
@ -24,29 +48,38 @@ public final class ComponentMetadataGenerator {
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public void addComponent(Element parent, PropertyAuditingData propertyAuditingData, public void addComponent(
Value value, CompositeMapperBuilder mapper, String entityName, Element parent, PropertyAuditingData propertyAuditingData,
EntityXmlMappingData xmlMappingData, boolean firstPass) { Value value, CompositeMapperBuilder mapper, String entityName,
Component prop_component = (Component) value; EntityXmlMappingData xmlMappingData, boolean firstPass) {
final Component propComponent = (Component) value;
Class componentClass = ReflectionTools.loadClass( prop_component.getComponentClassName(), mainGenerator.getClassLoaderService() ); final Class componentClass = ReflectionTools.loadClass(
CompositeMapperBuilder componentMapper = mapper.addComponent( propertyAuditingData.getPropertyData(), componentClass ); propComponent.getComponentClassName(),
mainGenerator.getClassLoaderService()
);
final CompositeMapperBuilder componentMapper = mapper.addComponent(
propertyAuditingData.getPropertyData(),
componentClass
);
// The property auditing data must be for a component. // The property auditing data must be for a component.
ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData; final ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
// Adding all properties of the component // Adding all properties of the component
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator(); final Iterator<Property> properties = (Iterator<Property>) propComponent.getPropertyIterator();
while (properties.hasNext()) { while ( properties.hasNext() ) {
Property property = properties.next(); final Property property = properties.next();
PropertyAuditingData componentPropertyAuditingData = final PropertyAuditingData componentPropertyAuditingData =
componentAuditingData.getPropertyAuditingData(property.getName()); componentAuditingData.getPropertyAuditingData( property.getName() );
// Checking if that property is audited // Checking if that property is audited
if (componentPropertyAuditingData != null) { if ( componentPropertyAuditingData != null ) {
mainGenerator.addValue(parent, property.getValue(), componentMapper, entityName, xmlMappingData, mainGenerator.addValue(
componentPropertyAuditingData, property.isInsertable(), firstPass, false); parent, property.getValue(), componentMapper, entityName, xmlMappingData,
componentPropertyAuditingData, property.isInsertable(), firstPass, false
);
} }
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -33,39 +34,39 @@ import org.dom4j.Element;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class EntityXmlMappingData { public class EntityXmlMappingData {
private Document mainXmlMapping; private Document mainXmlMapping;
private List<Document> additionalXmlMappings; private List<Document> additionalXmlMappings;
/** /**
* The xml element that maps the class. The root can be one of the folowing elements: * The xml element that maps the class. The root can be one of the folowing elements:
* class, subclass, union-subclass, joined-subclass * class, subclass, union-subclass, joined-subclass
*/ */
private Element classMapping; private Element classMapping;
public EntityXmlMappingData() { public EntityXmlMappingData() {
mainXmlMapping = DocumentHelper.createDocument(); mainXmlMapping = DocumentHelper.createDocument();
additionalXmlMappings = new ArrayList<Document>(); additionalXmlMappings = new ArrayList<Document>();
} }
public Document getMainXmlMapping() { public Document getMainXmlMapping() {
return mainXmlMapping; return mainXmlMapping;
} }
public List<Document> getAdditionalXmlMappings() { public List<Document> getAdditionalXmlMappings() {
return additionalXmlMappings; return additionalXmlMappings;
} }
public Document newAdditionalMapping() { public Document newAdditionalMapping() {
Document additionalMapping = DocumentHelper.createDocument(); Document additionalMapping = DocumentHelper.createDocument();
additionalXmlMappings.add(additionalMapping); additionalXmlMappings.add( additionalMapping );
return additionalMapping; return additionalMapping;
} }
public Element getClassMapping() { public Element getClassMapping() {
return classMapping; return classMapping;
} }
public void setClassMapping(Element classMapping) { public void setClassMapping(Element classMapping) {
this.classMapping = classMapping; this.classMapping = classMapping;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import java.util.Iterator; import java.util.Iterator;
import org.dom4j.Element; import org.dom4j.Element;
@ -47,127 +48,181 @@ import org.hibernate.type.Type;
/** /**
* Generates metadata for primary identifiers (ids) of versions entities. * Generates metadata for primary identifiers (ids) of versions entities.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class IdMetadataGenerator { public final class IdMetadataGenerator {
private final AuditMetadataGenerator mainGenerator; private final AuditMetadataGenerator mainGenerator;
IdMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) { IdMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
mainGenerator = auditMetadataGenerator; mainGenerator = auditMetadataGenerator;
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
private boolean addIdProperties(Element parent, Iterator<Property> properties, SimpleMapperBuilder mapper, boolean key, private boolean addIdProperties(
boolean audited) { Element parent,
while (properties.hasNext()) { Iterator<Property> properties,
Property property = properties.next(); SimpleMapperBuilder mapper,
Type propertyType = property.getType(); boolean key,
if (!"_identifierMapper".equals(property.getName())) { boolean audited) {
boolean added = false; while ( properties.hasNext() ) {
if (propertyType instanceof ManyToOneType) { final Property property = properties.next();
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(parent, final Type propertyType = property.getType();
getIdPersistentPropertyAuditingData(property), if ( !"_identifierMapper".equals( property.getName() ) ) {
property.getValue(), mapper); boolean added = false;
} else { if ( propertyType instanceof ManyToOneType ) {
// Last but one parameter: ids are always insertable added = mainGenerator.getBasicMetadataGenerator().addManyToOne(
added = mainGenerator.getBasicMetadataGenerator().addBasic(parent, parent,
getIdPersistentPropertyAuditingData(property), getIdPersistentPropertyAuditingData( property ),
property.getValue(), mapper, true, key); property.getValue(),
} mapper
if (!added) { );
// If the entity is audited, and a non-supported id component is used, throwing an exception. }
// If the entity is not audited, then we simply don't support this entity, even in else {
// target relation mode not audited. // Last but one parameter: ids are always insertable
if (audited) { added = mainGenerator.getBasicMetadataGenerator().addBasic(
throw new MappingException("Type not supported: " + propertyType.getClass().getName()); parent,
} else { getIdPersistentPropertyAuditingData( property ),
return false; property.getValue(),
} mapper,
} true,
} key
} );
}
if ( !added ) {
// If the entity is audited, and a non-supported id component is used, throwing an exception.
// If the entity is not audited, then we simply don't support this entity, even in
// target relation mode not audited.
if ( audited ) {
throw new MappingException( "Type not supported: " + propertyType.getClass().getName() );
}
else {
return false;
}
}
}
}
return true; return true;
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
IdMappingData addId(PersistentClass pc, boolean audited) { IdMappingData addId(PersistentClass pc, boolean audited) {
// Xml mapping which will be used for relations // Xml mapping which will be used for relations
Element rel_id_mapping = new DefaultElement("properties"); final Element relIdMapping = new DefaultElement( "properties" );
// Xml mapping which will be used for the primary key of the versions table // Xml mapping which will be used for the primary key of the versions table
Element orig_id_mapping = new DefaultElement("composite-id"); final Element origIdMapping = new DefaultElement( "composite-id" );
Property id_prop = pc.getIdentifierProperty(); final Property idProp = pc.getIdentifierProperty();
Component id_mapper = pc.getIdentifierMapper(); final Component idMapper = pc.getIdentifierMapper();
// Checking if the id mapping is supported // Checking if the id mapping is supported
if (id_mapper == null && id_prop == null) { if ( idMapper == null && idProp == null ) {
return null; return null;
} }
SimpleIdMapperBuilder mapper; SimpleIdMapperBuilder mapper;
if (id_mapper != null) { if ( idMapper != null ) {
// Multiple id // Multiple id
final Class componentClass = ReflectionTools.loadClass(
Class componentClass = ReflectionTools.loadClass( ( (Component) pc.getIdentifier() ).getComponentClassName(),
( (Component) pc.getIdentifier() ).getComponentClassName(), mainGenerator.getClassLoaderService() mainGenerator.getClassLoaderService()
); );
mapper = new MultipleIdMapper( componentClass ); mapper = new MultipleIdMapper( componentClass );
if (!addIdProperties(rel_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), mapper, false, audited)) { if ( !addIdProperties(
return null; relIdMapping,
} (Iterator<Property>) idMapper.getPropertyIterator(),
mapper,
false,
audited
) ) {
return null;
}
// null mapper - the mapping where already added the first time, now we only want to generate the xml // null mapper - the mapping where already added the first time, now we only want to generate the xml
if (!addIdProperties(orig_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), null, true, audited)) { if ( !addIdProperties(
return null; origIdMapping,
} (Iterator<Property>) idMapper.getPropertyIterator(),
} else if (id_prop.isComposite()) { null,
// Embedded id true,
audited
Component id_component = (Component) id_prop.getValue(); ) ) {
Class embeddableClass = ReflectionTools.loadClass( return null;
id_component.getComponentClassName(), mainGenerator.getClassLoaderService() }
}
else if ( idProp.isComposite() ) {
// Embedded id
final Component idComponent = (Component) idProp.getValue();
final Class embeddableClass = ReflectionTools.loadClass(
idComponent.getComponentClassName(),
mainGenerator.getClassLoaderService()
); );
mapper = new EmbeddedIdMapper( getIdPropertyData(id_prop), embeddableClass ); mapper = new EmbeddedIdMapper( getIdPropertyData( idProp ), embeddableClass );
if (!addIdProperties(rel_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), mapper, false, audited)) { if ( !addIdProperties(
return null; relIdMapping,
} (Iterator<Property>) idComponent.getPropertyIterator(),
mapper,
false,
audited
) ) {
return null;
}
// null mapper - the mapping where already added the first time, now we only want to generate the xml // null mapper - the mapping where already added the first time, now we only want to generate the xml
if (!addIdProperties(orig_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), null, true, audited)) { if ( !addIdProperties(
return null; origIdMapping,
} (Iterator<Property>) idComponent.getPropertyIterator(),
} else { null,
// Single id true,
audited
mapper = new SingleIdMapper(); ) ) {
return null;
}
}
else {
// Single id
mapper = new SingleIdMapper();
// Last but one parameter: ids are always insertable // Last but one parameter: ids are always insertable
mainGenerator.getBasicMetadataGenerator().addBasic(rel_id_mapping, mainGenerator.getBasicMetadataGenerator().addBasic(
getIdPersistentPropertyAuditingData(id_prop), relIdMapping,
id_prop.getValue(), mapper, true, false); getIdPersistentPropertyAuditingData( idProp ),
idProp.getValue(),
mapper,
true,
false
);
// null mapper - the mapping where already added the first time, now we only want to generate the xml // null mapper - the mapping where already added the first time, now we only want to generate the xml
mainGenerator.getBasicMetadataGenerator().addBasic(orig_id_mapping, mainGenerator.getBasicMetadataGenerator().addBasic(
getIdPersistentPropertyAuditingData(id_prop), origIdMapping,
id_prop.getValue(), null, true, true); getIdPersistentPropertyAuditingData( idProp ),
} idProp.getValue(),
null,
true,
true
);
}
orig_id_mapping.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName()); origIdMapping.addAttribute( "name", mainGenerator.getVerEntCfg().getOriginalIdPropName() );
// Adding a relation to the revision entity (effectively: the "revision number" property) // Adding a relation to the revision entity (effectively: the "revision number" property)
mainGenerator.addRevisionInfoRelation(orig_id_mapping); mainGenerator.addRevisionInfoRelation( origIdMapping );
return new IdMappingData(mapper, orig_id_mapping, rel_id_mapping); return new IdMappingData( mapper, origIdMapping, relIdMapping );
} }
private PropertyData getIdPropertyData(Property property) { private PropertyData getIdPropertyData(Property property) {
return new PropertyData(property.getName(), property.getName(), property.getPropertyAccessorName(), return new PropertyData(
ModificationStore.FULL); property.getName(), property.getName(), property.getPropertyAccessorName(),
} ModificationStore.FULL
);
}
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) { private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(), return new PropertyAuditingData(
ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false); property.getName(), property.getPropertyAccessorName(),
} ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false
);
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.mapping.JoinedSubclass; import org.hibernate.mapping.JoinedSubclass;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
@ -33,33 +34,36 @@ import org.hibernate.mapping.UnionSubclass;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public enum InheritanceType { public enum InheritanceType {
NONE, NONE,
JOINED, JOINED,
SINGLE, SINGLE,
TABLE_PER_CLASS; TABLE_PER_CLASS;
/** /**
* @param pc The class for which to get the inheritance type. * @param pc The class for which to get the inheritance type.
* @return The inheritance type of this class. NONE, if this class does not inherit from *
* another persisten class. * @return The inheritance type of this class. NONE, if this class does not inherit from
*/ * another persistent class.
public static InheritanceType get(PersistentClass pc) { */
PersistentClass superclass = pc.getSuperclass(); public static InheritanceType get(PersistentClass pc) {
if (superclass == null) { final PersistentClass superclass = pc.getSuperclass();
return InheritanceType.NONE; if ( superclass == null ) {
} return InheritanceType.NONE;
}
// We assume that every subclass is of the same type. // We assume that every subclass is of the same type.
Subclass subclass = (Subclass) superclass.getSubclassIterator().next(); final Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
if (subclass instanceof SingleTableSubclass) { if ( subclass instanceof SingleTableSubclass ) {
return InheritanceType.SINGLE; return InheritanceType.SINGLE;
} else if (subclass instanceof JoinedSubclass) { }
return InheritanceType.JOINED; else if ( subclass instanceof JoinedSubclass ) {
} else if (subclass instanceof UnionSubclass) { return InheritanceType.JOINED;
return InheritanceType.TABLE_PER_CLASS; }
} else if ( subclass instanceof UnionSubclass ) {
return InheritanceType.TABLE_PER_CLASS;
}
throw new MappingException("Unknown subclass class: " + subclass.getClass()); throw new MappingException( "Unknown subclass class: " + subclass.getClass() );
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,8 +22,9 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import java.util.Iterator;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import java.util.Iterator;
import org.dom4j.Attribute; import org.dom4j.Attribute;
import org.dom4j.Document; import org.dom4j.Document;
@ -41,52 +42,72 @@ import org.hibernate.mapping.Selectable;
*/ */
public class MetadataTools { public class MetadataTools {
public static Element addNativelyGeneratedId(Element parent, String name, String type, public static Element addNativelyGeneratedId(
boolean useRevisionEntityWithNativeId) { Element parent, String name, String type,
Element id_mapping = parent.addElement("id"); boolean useRevisionEntityWithNativeId) {
id_mapping.addAttribute("name", name).addAttribute("type", type); final Element idMapping = parent.addElement( "id" );
idMapping.addAttribute( "name", name ).addAttribute( "type", type );
Element generator_mapping = id_mapping.addElement("generator"); final Element generatorMapping = idMapping.addElement( "generator" );
if (useRevisionEntityWithNativeId) { if ( useRevisionEntityWithNativeId ) {
generator_mapping.addAttribute("class", "native"); generatorMapping.addAttribute( "class", "native" );
} else { }
generator_mapping.addAttribute("class", "org.hibernate.envers.enhanced.OrderedSequenceGenerator"); else {
generator_mapping.addElement("param").addAttribute("name", "sequence_name").setText("REVISION_GENERATOR"); generatorMapping.addAttribute( "class", "org.hibernate.envers.enhanced.OrderedSequenceGenerator" );
generator_mapping.addElement("param").addAttribute("name", "table_name").setText("REVISION_GENERATOR"); generatorMapping.addElement( "param" ).addAttribute( "name", "sequence_name" ).setText(
generator_mapping.addElement("param").addAttribute("name", "initial_value").setText("1"); "REVISION_GENERATOR"
generator_mapping.addElement("param").addAttribute("name", "increment_size").setText("1"); );
} generatorMapping.addElement( "param" )
// generator_mapping.addAttribute("class", "sequence"); .addAttribute( "name", "table_name" )
// generator_mapping.addElement("param").addAttribute("name", "sequence").setText("custom"); .setText( "REVISION_GENERATOR" );
generatorMapping.addElement( "param" ).addAttribute( "name", "initial_value" ).setText( "1" );
generatorMapping.addElement( "param" ).addAttribute( "name", "increment_size" ).setText( "1" );
}
// generatorMapping.addAttribute("class", "sequence");
// generatorMapping.addElement("param").addAttribute("name", "sequence").setText("custom");
return id_mapping; return idMapping;
} }
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean updateable, boolean key) { public static Element addProperty(
Element prop_mapping; Element parent,
if (key) { String name,
prop_mapping = parent.addElement("key-property"); String type,
} else { boolean insertable,
prop_mapping = parent.addElement("property"); boolean updateable,
} boolean key) {
final Element propMapping;
if ( key ) {
propMapping = parent.addElement( "key-property" );
}
else {
propMapping = parent.addElement( "property" );
}
prop_mapping.addAttribute("name", name); propMapping.addAttribute( "name", name );
prop_mapping.addAttribute("insert", Boolean.toString(insertable)); propMapping.addAttribute( "insert", Boolean.toString( insertable ) );
prop_mapping.addAttribute("update", Boolean.toString(updateable)); propMapping.addAttribute( "update", Boolean.toString( updateable ) );
if (type != null) { if ( type != null ) {
prop_mapping.addAttribute("type", type); propMapping.addAttribute( "type", type );
} }
return prop_mapping; return propMapping;
} }
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) { public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) {
return addProperty(parent, name, type, insertable, false, key); return addProperty( parent, name, type, insertable, false, key );
} }
public static Element addModifiedFlagProperty(Element parent, String propertyName, String suffix) { public static Element addModifiedFlagProperty(Element parent, String propertyName, String suffix) {
return addProperty(parent, getModifiedFlagPropertyName(propertyName, suffix), "boolean", true, false, false); return addProperty(
parent,
getModifiedFlagPropertyName( propertyName, suffix ),
"boolean",
true,
false,
false
);
} }
public static String getModifiedFlagPropertyName(String propertyName, String suffix) { public static String getModifiedFlagPropertyName(String propertyName, String suffix) {
@ -94,256 +115,319 @@ public class MetadataTools {
} }
private static void addOrModifyAttribute(Element parent, String name, String value) { private static void addOrModifyAttribute(Element parent, String name, String value) {
Attribute attribute = parent.attribute(name); final Attribute attribute = parent.attribute( name );
if (attribute == null) { if ( attribute == null ) {
parent.addAttribute(name, value); parent.addAttribute( name, value );
} else {
attribute.setValue(value);
}
}
/**
* Column name shall be wrapped with '`' signs if quotation required.
*/
public static Element addOrModifyColumn(Element parent, String name) {
Element column_mapping = parent.element("column");
if (column_mapping == null) {
return addColumn(parent, name, null, null, null, null, null, null);
}
if (!StringTools.isEmpty(name)) {
addOrModifyAttribute(column_mapping, "name", name);
}
return column_mapping;
}
/**
* Adds new <code>column</code> element. Method assumes that the value of <code>name</code> attribute is already
* wrapped with '`' signs if quotation required. It shall be invoked when column name is taken directly from configuration
* file and not from {@link org.hibernate.mapping.PersistentClass} descriptor.
*/
public static Element addColumn(Element parent, String name, Integer length, Integer scale, Integer precision,
String sqlType, String customRead, String customWrite) {
return addColumn(parent, name, length, scale, precision, sqlType, customRead, customWrite, false);
}
public static Element addColumn(Element parent, String name, Integer length, Integer scale, Integer precision,
String sqlType, String customRead, String customWrite, boolean quoted) {
Element column_mapping = parent.addElement("column");
column_mapping.addAttribute("name", quoted ? "`" + name + "`" : name);
if (length != null) {
column_mapping.addAttribute("length", length.toString());
}
if (scale != null) {
column_mapping.addAttribute("scale", Integer.toString(scale));
} }
if (precision != null) { else {
column_mapping.addAttribute("precision", Integer.toString(precision)); attribute.setValue( value );
} }
if (!StringTools.isEmpty(sqlType)) { }
column_mapping.addAttribute("sql-type", sqlType);
}
if (!StringTools.isEmpty(customRead)) { /**
column_mapping.addAttribute("read", customRead); * Column name shall be wrapped with '`' signs if quotation required.
} */
if (!StringTools.isEmpty(customWrite)) { public static Element addOrModifyColumn(Element parent, String name) {
column_mapping.addAttribute("write", customWrite); final Element columnMapping = parent.element( "column" );
}
return column_mapping; if ( columnMapping == null ) {
} return addColumn( parent, name, null, null, null, null, null, null );
}
private static Element createEntityCommon(Document document, String type, AuditTableData auditTableData, if ( !StringTools.isEmpty( name ) ) {
String discriminatorValue, Boolean isAbstract) { addOrModifyAttribute( columnMapping, "name", name );
Element hibernate_mapping = document.addElement("hibernate-mapping"); }
hibernate_mapping.addAttribute("auto-import", "false");
Element class_mapping = hibernate_mapping.addElement(type); return columnMapping;
}
if (auditTableData.getAuditEntityName() != null) { /**
class_mapping.addAttribute("entity-name", auditTableData.getAuditEntityName()); * Adds new <code>column</code> element. Method assumes that the value of <code>name</code> attribute is already
} * wrapped with '`' signs if quotation required. It shall be invoked when column name is taken directly from configuration
* file and not from {@link org.hibernate.mapping.PersistentClass} descriptor.
*/
public static Element addColumn(
Element parent,
String name,
Integer length,
Integer scale,
Integer precision,
String sqlType,
String customRead,
String customWrite) {
return addColumn( parent, name, length, scale, precision, sqlType, customRead, customWrite, false );
}
if (discriminatorValue != null) { public static Element addColumn(
class_mapping.addAttribute("discriminator-value", discriminatorValue); Element parent,
} String name,
Integer length,
Integer scale,
Integer precision,
String sqlType,
String customRead,
String customWrite,
boolean quoted) {
final Element columnMapping = parent.addElement( "column" );
if (!StringTools.isEmpty(auditTableData.getAuditTableName())) { columnMapping.addAttribute( "name", quoted ? "`" + name + "`" : name );
class_mapping.addAttribute("table", auditTableData.getAuditTableName()); if ( length != null ) {
} columnMapping.addAttribute( "length", length.toString() );
}
if ( scale != null ) {
columnMapping.addAttribute( "scale", Integer.toString( scale ) );
}
if ( precision != null ) {
columnMapping.addAttribute( "precision", Integer.toString( precision ) );
}
if ( !StringTools.isEmpty( sqlType ) ) {
columnMapping.addAttribute( "sql-type", sqlType );
}
if (!StringTools.isEmpty(auditTableData.getSchema())) { if ( !StringTools.isEmpty( customRead ) ) {
class_mapping.addAttribute("schema", auditTableData.getSchema()); columnMapping.addAttribute( "read", customRead );
} }
if ( !StringTools.isEmpty( customWrite ) ) {
columnMapping.addAttribute( "write", customWrite );
}
if (!StringTools.isEmpty(auditTableData.getCatalog())) { return columnMapping;
class_mapping.addAttribute("catalog", auditTableData.getCatalog()); }
}
if (isAbstract != null) { private static Element createEntityCommon(
class_mapping.addAttribute("abstract", isAbstract.toString()); Document document,
} String type,
AuditTableData auditTableData,
String discriminatorValue,
Boolean isAbstract) {
final Element hibernateMapping = document.addElement( "hibernate-mapping" );
hibernateMapping.addAttribute( "auto-import", "false" );
return class_mapping; final Element classMapping = hibernateMapping.addElement( type );
}
public static Element createEntity(Document document, AuditTableData auditTableData, String discriminatorValue, if ( auditTableData.getAuditEntityName() != null ) {
Boolean isAbstract) { classMapping.addAttribute( "entity-name", auditTableData.getAuditEntityName() );
return createEntityCommon(document, "class", auditTableData, discriminatorValue, isAbstract); }
}
public static Element createSubclassEntity(Document document, String subclassType, AuditTableData auditTableData, if ( discriminatorValue != null ) {
String extendsEntityName, String discriminatorValue, Boolean isAbstract) { classMapping.addAttribute( "discriminator-value", discriminatorValue );
Element class_mapping = createEntityCommon(document, subclassType, auditTableData, discriminatorValue, isAbstract); }
class_mapping.addAttribute("extends", extendsEntityName); if ( !StringTools.isEmpty( auditTableData.getAuditTableName() ) ) {
classMapping.addAttribute( "table", auditTableData.getAuditTableName() );
}
return class_mapping; if ( !StringTools.isEmpty( auditTableData.getSchema() ) ) {
} classMapping.addAttribute( "schema", auditTableData.getSchema() );
}
public static Element createJoin(Element parent, String tableName, if ( !StringTools.isEmpty( auditTableData.getCatalog() ) ) {
String schema, String catalog) { classMapping.addAttribute( "catalog", auditTableData.getCatalog() );
Element join_mapping = parent.addElement("join"); }
join_mapping.addAttribute("table", tableName); if ( isAbstract != null ) {
classMapping.addAttribute( "abstract", isAbstract.toString() );
}
if (!StringTools.isEmpty(schema)) { return classMapping;
join_mapping.addAttribute("schema", schema); }
}
if (!StringTools.isEmpty(catalog)) { public static Element createEntity(
join_mapping.addAttribute("catalog", catalog); Document document,
} AuditTableData auditTableData,
String discriminatorValue,
Boolean isAbstract) {
return createEntityCommon( document, "class", auditTableData, discriminatorValue, isAbstract );
}
return join_mapping; public static Element createSubclassEntity(
} Document document,
String subclassType,
AuditTableData auditTableData,
String extendsEntityName,
String discriminatorValue,
Boolean isAbstract) {
final Element classMapping = createEntityCommon(
document,
subclassType,
auditTableData,
discriminatorValue,
isAbstract
);
public static void addColumns(Element any_mapping, Iterator selectables) { classMapping.addAttribute( "extends", extendsEntityName );
while ( selectables.hasNext() ) {
return classMapping;
}
public static Element createJoin(
Element parent,
String tableName,
String schema,
String catalog) {
final Element joinMapping = parent.addElement( "join" );
joinMapping.addAttribute( "table", tableName );
if ( !StringTools.isEmpty( schema ) ) {
joinMapping.addAttribute( "schema", schema );
}
if ( !StringTools.isEmpty( catalog ) ) {
joinMapping.addAttribute( "catalog", catalog );
}
return joinMapping;
}
public static void addColumns(Element anyMapping, Iterator selectables) {
while ( selectables.hasNext() ) {
final Selectable selectable = (Selectable) selectables.next(); final Selectable selectable = (Selectable) selectables.next();
if ( selectable.isFormula() ) { if ( selectable.isFormula() ) {
throw new FormulaNotSupportedException(); throw new FormulaNotSupportedException();
} }
addColumn( any_mapping, (Column) selectable ); addColumn( anyMapping, (Column) selectable );
} }
}
/**
* Adds <code>column</code> element with the following attributes (unless empty): <code>name</code>,
* <code>length</code>, <code>scale</code>, <code>precision</code>, <code>sql-type</code>, <code>read</code>
* and <code>write</code>.
* @param any_mapping Parent element.
* @param column Column descriptor.
*/
public static void addColumn(Element any_mapping, Column column) {
addColumn(any_mapping, column.getName(), column.getLength(), column.getScale(), column.getPrecision(),
column.getSqlType(), column.getCustomRead(), column.getCustomWrite(), column.isQuoted());
}
@SuppressWarnings({"unchecked"})
private static void changeNamesInColumnElement(Element element, ColumnNameIterator columnNameIterator) {
Iterator<Element> properties = element.elementIterator();
while (properties.hasNext()) {
Element property = properties.next();
if ("column".equals(property.getName())) {
Attribute nameAttr = property.attribute("name");
if (nameAttr != null) {
nameAttr.setText(columnNameIterator.next());
}
}
}
}
@SuppressWarnings({"unchecked"})
public static void prefixNamesInPropertyElement(Element element, String prefix, ColumnNameIterator columnNameIterator,
boolean changeToKey, boolean insertable) {
Iterator<Element> properties = element.elementIterator();
while (properties.hasNext()) {
Element property = properties.next();
if ("property".equals(property.getName()) || "many-to-one".equals(property.getName())) {
Attribute nameAttr = property.attribute("name");
if (nameAttr != null) {
nameAttr.setText(prefix + nameAttr.getText());
}
changeNamesInColumnElement(property, columnNameIterator);
if (changeToKey) {
property.setName("key-" + property.getName());
}
if ("property".equals(property.getName())) {
Attribute insert = property.attribute("insert");
insert.setText(Boolean.toString(insertable));
}
}
}
}
/**
* Adds <code>formula</code> element.
* @param element Parent element.
* @param formula Formula descriptor.
*/
public static void addFormula(Element element, Formula formula) {
element.addElement("formula").setText(formula.getText());
}
/**
* Adds all <code>column</code> or <code>formula</code> elements.
* @param element Parent element.
* @param columnIterator Iterator pointing at {@link org.hibernate.mapping.Column} and/or
* {@link org.hibernate.mapping.Formula} objects.
*/
public static void addColumnsOrFormulas(Element element, Iterator columnIterator) {
while (columnIterator.hasNext()) {
Object o = columnIterator.next();
if (o instanceof Column) {
addColumn(element, (Column) o);
} else if (o instanceof Formula) {
addFormula(element, (Formula) o);
}
}
}
/**
* An iterator over column names.
*/
public static abstract class ColumnNameIterator implements Iterator<String> {
} }
public static ColumnNameIterator getColumnNameIterator(final Iterator<Selectable> selectableIterator) { /**
return new ColumnNameIterator() { * Adds <code>column</code> element with the following attributes (unless empty): <code>name</code>,
public boolean hasNext() { * <code>length</code>, <code>scale</code>, <code>precision</code>, <code>sql-type</code>, <code>read</code>
* and <code>write</code>.
*
* @param anyMapping Parent element.
* @param column Column descriptor.
*/
public static void addColumn(Element anyMapping, Column column) {
addColumn(
anyMapping,
column.getName(),
column.getLength(),
column.getScale(),
column.getPrecision(),
column.getSqlType(),
column.getCustomRead(),
column.getCustomWrite(),
column.isQuoted()
);
}
@SuppressWarnings({"unchecked"})
private static void changeNamesInColumnElement(Element element, ColumnNameIterator columnNameIterator) {
final Iterator<Element> properties = element.elementIterator();
while ( properties.hasNext() ) {
final Element property = properties.next();
if ( "column".equals( property.getName() ) ) {
final Attribute nameAttr = property.attribute( "name" );
if ( nameAttr != null ) {
nameAttr.setText( columnNameIterator.next() );
}
}
}
}
@SuppressWarnings({"unchecked"})
public static void prefixNamesInPropertyElement(
Element element,
String prefix,
ColumnNameIterator columnNameIterator,
boolean changeToKey,
boolean insertable) {
final Iterator<Element> properties = element.elementIterator();
while ( properties.hasNext() ) {
final Element property = properties.next();
if ( "property".equals( property.getName() ) || "many-to-one".equals( property.getName() ) ) {
final Attribute nameAttr = property.attribute( "name" );
if ( nameAttr != null ) {
nameAttr.setText( prefix + nameAttr.getText() );
}
changeNamesInColumnElement( property, columnNameIterator );
if ( changeToKey ) {
property.setName( "key-" + property.getName() );
}
if ( "property".equals( property.getName() ) ) {
final Attribute insert = property.attribute( "insert" );
insert.setText( Boolean.toString( insertable ) );
}
}
}
}
/**
* Adds <code>formula</code> element.
*
* @param element Parent element.
* @param formula Formula descriptor.
*/
public static void addFormula(Element element, Formula formula) {
element.addElement( "formula" ).setText( formula.getText() );
}
/**
* Adds all <code>column</code> or <code>formula</code> elements.
*
* @param element Parent element.
* @param columnIterator Iterator pointing at {@link org.hibernate.mapping.Column} and/or
* {@link org.hibernate.mapping.Formula} objects.
*/
public static void addColumnsOrFormulas(Element element, Iterator columnIterator) {
while ( columnIterator.hasNext() ) {
final Object o = columnIterator.next();
if ( o instanceof Column ) {
addColumn( element, (Column) o );
}
else if ( o instanceof Formula ) {
addFormula( element, (Formula) o );
}
}
}
/**
* An iterator over column names.
*/
public static abstract class ColumnNameIterator implements Iterator<String> {
}
public static ColumnNameIterator getColumnNameIterator(final Iterator<Selectable> selectableIterator) {
return new ColumnNameIterator() {
public boolean hasNext() {
return selectableIterator.hasNext(); return selectableIterator.hasNext();
} }
public String next() { public String next() {
final Selectable next = selectableIterator.next(); final Selectable next = selectableIterator.next();
if ( next.isFormula() ) { if ( next.isFormula() ) {
throw new FormulaNotSupportedException(); throw new FormulaNotSupportedException();
} }
return ( (Column) next ).getName(); return ((Column) next).getName();
} }
public void remove() { public void remove() {
selectableIterator.remove(); selectableIterator.remove();
} }
}; };
} }
public static ColumnNameIterator getColumnNameIterator(final JoinColumn[] joinColumns) { public static ColumnNameIterator getColumnNameIterator(final JoinColumn[] joinColumns) {
return new ColumnNameIterator() { return new ColumnNameIterator() {
int counter = 0; int counter = 0;
public boolean hasNext() { return counter < joinColumns.length; }
public String next() { return joinColumns[counter++].name(); } public boolean hasNext() {
public void remove() { throw new UnsupportedOperationException(); } return counter < joinColumns.length;
}; }
}
public String next() {
return joinColumns[counter++].name();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -40,64 +41,83 @@ import org.hibernate.envers.strategy.AuditStrategy;
/** /**
* Builds query generators, for reading collection middle tables, along with any related entities. * Builds query generators, for reading collection middle tables, along with any related entities.
* The related entities information can be added gradually, and when complete, the query generator can be built. * The related entities information can be added gradually, and when complete, the query generator can be built.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class QueryGeneratorBuilder { public final class QueryGeneratorBuilder {
private final GlobalConfiguration globalCfg; private final GlobalConfiguration globalCfg;
private final AuditEntitiesConfiguration verEntCfg; private final AuditEntitiesConfiguration verEntCfg;
private final AuditStrategy auditStrategy; private final AuditStrategy auditStrategy;
private final MiddleIdData referencingIdData; private final MiddleIdData referencingIdData;
private final String auditMiddleEntityName; private final String auditMiddleEntityName;
private final List<MiddleIdData> idDatas; private final List<MiddleIdData> idDatas;
private final boolean revisionTypeInId; private final boolean revisionTypeInId;
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg, QueryGeneratorBuilder(
AuditStrategy auditStrategy, MiddleIdData referencingIdData, String auditMiddleEntityName, GlobalConfiguration globalCfg,
boolean revisionTypeInId) { AuditEntitiesConfiguration verEntCfg,
this.globalCfg = globalCfg; AuditStrategy auditStrategy,
this.verEntCfg = verEntCfg; MiddleIdData referencingIdData,
this.auditStrategy = auditStrategy; String auditMiddleEntityName,
this.referencingIdData = referencingIdData; boolean revisionTypeInId) {
this.auditMiddleEntityName = auditMiddleEntityName; this.globalCfg = globalCfg;
this.verEntCfg = verEntCfg;
this.auditStrategy = auditStrategy;
this.referencingIdData = referencingIdData;
this.auditMiddleEntityName = auditMiddleEntityName;
this.revisionTypeInId = revisionTypeInId; this.revisionTypeInId = revisionTypeInId;
idDatas = new ArrayList<MiddleIdData>(); idDatas = new ArrayList<MiddleIdData>();
} }
void addRelation(MiddleIdData idData) { void addRelation(MiddleIdData idData) {
idDatas.add(idData); idDatas.add( idData );
} }
RelationQueryGenerator build(MiddleComponentData... componentDatas) { RelationQueryGenerator build(MiddleComponentData... componentDatas) {
if (idDatas.size() == 0) { if ( idDatas.size() == 0 ) {
return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, return new OneEntityQueryGenerator(
revisionTypeInId, componentDatas); verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
} else if (idDatas.size() == 1) { revisionTypeInId, componentDatas
if (idDatas.get(0).isAudited()) { );
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, }
idDatas.get(0), revisionTypeInId, componentDatas); else if ( idDatas.size() == 1 ) {
} else { if ( idDatas.get( 0 ).isAudited() ) {
return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, return new TwoEntityQueryGenerator(
idDatas.get(0), revisionTypeInId, componentDatas); globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
} idDatas.get( 0 ), revisionTypeInId, componentDatas
} else if (idDatas.size() == 2) { );
// All entities must be audited. }
if (!idDatas.get(0).isAudited() || !idDatas.get(1).isAudited()) { else {
throw new MappingException("Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported."); return new TwoEntityOneAuditedQueryGenerator(
} verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
idDatas.get( 0 ), revisionTypeInId, componentDatas
);
}
}
else if ( idDatas.size() == 2 ) {
// All entities must be audited.
if ( !idDatas.get( 0 ).isAudited() || !idDatas.get( 1 ).isAudited() ) {
throw new MappingException(
"Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported."
);
}
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, return new ThreeEntityQueryGenerator(
idDatas.get(0), idDatas.get(1), revisionTypeInId, componentDatas); globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
} else { idDatas.get( 0 ), idDatas.get( 1 ), revisionTypeInId, componentDatas
throw new IllegalStateException("Illegal number of related entities."); );
} }
} else {
throw new IllegalStateException( "Illegal number of related entities." );
}
}
/** /**
* @return Current index of data in the array, which will be the element of a list, returned when executing a query * @return Current index of data in the array, which will be the element of a list, returned when executing a query
* generated by the built query generator. * generated by the built query generator.
*/ */
int getCurrentIndex() { int getCurrentIndex() {
return idDatas.size(); return idDatas.size();
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata; package org.hibernate.envers.configuration.internal.metadata;
import org.dom4j.Element; import org.dom4j.Element;
import org.hibernate.MappingException; import org.hibernate.MappingException;
@ -41,121 +42,166 @@ import org.hibernate.mapping.Value;
/** /**
* Generates metadata for to-one relations (reference-valued properties). * Generates metadata for to-one relations (reference-valued properties).
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public final class ToOneRelationMetadataGenerator { public final class ToOneRelationMetadataGenerator {
private final AuditMetadataGenerator mainGenerator; private final AuditMetadataGenerator mainGenerator;
ToOneRelationMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) { ToOneRelationMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
mainGenerator = auditMetadataGenerator; mainGenerator = auditMetadataGenerator;
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
void addToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value, void addToOne(
CompositeMapperBuilder mapper, String entityName, boolean insertable) { Element parent,
String referencedEntityName = ((ToOne) value).getReferencedEntityName(); PropertyAuditingData propertyAuditingData,
Value value,
CompositeMapperBuilder mapper,
String entityName,
boolean insertable) {
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(entityName, referencedEntityName, final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
propertyAuditingData, true); entityName,
referencedEntityName,
propertyAuditingData,
true
);
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(propertyAuditingData.getName()); final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( propertyAuditingData.getName() );
// Generating the id mapper for the relation // Generating the id mapper for the relation
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix); final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
// Storing information about this relation // Storing information about this relation
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation( mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
propertyAuditingData.getName(), referencedEntityName, relMapper, insertable); propertyAuditingData.getName(),
referencedEntityName,
relMapper,
insertable
);
// If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship, // If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
// that is, when the one side owns the relation (and is a collection), and the many side is non insertable. // that is, when the one side owns the relation (and is a collection), and the many side is non insertable.
// When that's the case and the user specified to store this relation without a middle table (using // When that's the case and the user specified to store this relation without a middle table (using
// @AuditMappedBy), we have to make the property insertable for the purposes of Envers. In case of changes to // @AuditMappedBy), we have to make the property insertable for the purposes of Envers. In case of changes to
// the entity that didn't involve the relation, it's value will then be stored properly. In case of changes // the entity that didn't involve the relation, it's value will then be stored properly. In case of changes
// to the entity that did involve the relation, it's the responsibility of the collection side to store the // to the entity that did involve the relation, it's the responsibility of the collection side to store the
// proper data. // proper data.
boolean nonInsertableFake; boolean nonInsertableFake;
if (!insertable && propertyAuditingData.isForceInsertable()) { if ( !insertable && propertyAuditingData.isForceInsertable() ) {
nonInsertableFake = true; nonInsertableFake = true;
insertable = true; insertable = true;
} else { }
nonInsertableFake = false; else {
} nonInsertableFake = false;
}
// Adding an element to the mapping corresponding to the references entity id's // Adding an element to the mapping corresponding to the references entity id's
Element properties = (Element) idMapping.getXmlRelationMapping().clone(); final Element properties = (Element) idMapping.getXmlRelationMapping().clone();
properties.addAttribute("name", propertyAuditingData.getName()); properties.addAttribute( "name", propertyAuditingData.getName() );
MetadataTools.prefixNamesInPropertyElement(properties, lastPropertyPrefix, MetadataTools.prefixNamesInPropertyElement(
MetadataTools.getColumnNameIterator(value.getColumnIterator()), false, insertable); properties,
lastPropertyPrefix,
MetadataTools.getColumnNameIterator( value.getColumnIterator() ),
false,
insertable
);
// Extracting related id properties from properties tag // Extracting related id properties from properties tag
for (Object o : properties.content()) { for ( Object o : properties.content() ) {
Element element = (Element) o; final Element element = (Element) o;
element.setParent(null); element.setParent( null );
parent.add(element); parent.add( element );
} }
// Adding mapper for the id // Adding mapper for the id
PropertyData propertyData = propertyAuditingData.getPropertyData(); final PropertyData propertyData = propertyAuditingData.getPropertyData();
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName, nonInsertableFake)); mapper.addComposite(
} propertyData,
new ToOneIdMapper( relMapper, propertyData, referencedEntityName, nonInsertableFake )
);
}
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
void addOneToOneNotOwning(PropertyAuditingData propertyAuditingData, Value value, void addOneToOneNotOwning(
CompositeMapperBuilder mapper, String entityName) { PropertyAuditingData propertyAuditingData,
OneToOne propertyValue = (OneToOne) value; Value value,
CompositeMapperBuilder mapper,
String entityName) {
final OneToOne propertyValue = (OneToOne) value;
final String owningReferencePropertyName = propertyValue.getReferencedPropertyName();
String owningReferencePropertyName = propertyValue.getReferencedPropertyName(); // mappedBy final EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get( entityName );
if ( configuration == null ) {
throw new MappingException( "An audited relation to a non-audited entity " + entityName + "!" );
}
EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(entityName); final IdMappingData ownedIdMapping = configuration.getIdMappingData();
if (configuration == null) {
throw new MappingException("An audited relation to a non-audited entity " + entityName + "!");
}
IdMappingData ownedIdMapping = configuration.getIdMappingData(); if ( ownedIdMapping == null ) {
throw new MappingException( "An audited relation to a non-audited entity " + entityName + "!" );
}
if (ownedIdMapping == null) { final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( owningReferencePropertyName );
throw new MappingException("An audited relation to a non-audited entity " + entityName + "!"); final String referencedEntityName = propertyValue.getReferencedEntityName();
}
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(owningReferencePropertyName); // Generating the id mapper for the relation
String referencedEntityName = propertyValue.getReferencedEntityName(); final IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
// Generating the id mapper for the relation // Storing information about this relation
IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix); mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneNotOwningRelation(
propertyAuditingData.getName(),
owningReferencePropertyName,
referencedEntityName,
ownedIdMapper
);
// Storing information about this relation // Adding mapper for the id
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneNotOwningRelation( final PropertyData propertyData = propertyAuditingData.getPropertyData();
propertyAuditingData.getName(), owningReferencePropertyName, mapper.addComposite(
referencedEntityName, ownedIdMapper); propertyData,
new OneToOneNotOwningMapper( entityName, referencedEntityName, owningReferencePropertyName, propertyData )
);
}
// Adding mapper for the id @SuppressWarnings({"unchecked"})
PropertyData propertyData = propertyAuditingData.getPropertyData(); void addOneToOnePrimaryKeyJoinColumn(
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(entityName, referencedEntityName, PropertyAuditingData propertyAuditingData,
owningReferencePropertyName, propertyData)); Value value,
} CompositeMapperBuilder mapper,
String entityName,
boolean insertable) {
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
@SuppressWarnings({"unchecked"}) final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
void addOneToOnePrimaryKeyJoinColumn(PropertyAuditingData propertyAuditingData, Value value, entityName,
CompositeMapperBuilder mapper, String entityName, boolean insertable) { referencedEntityName,
String referencedEntityName = ((ToOne) value).getReferencedEntityName(); propertyAuditingData,
true
);
IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(entityName, referencedEntityName, final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( propertyAuditingData.getName() );
propertyAuditingData, true);
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(propertyAuditingData.getName()); // Generating the id mapper for the relation
final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
// Generating the id mapper for the relation // Storing information about this relation
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix); mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
propertyAuditingData.getName(),
referencedEntityName,
relMapper,
insertable
);
// Storing information about this relation // Adding mapper for the id
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(propertyAuditingData.getName(), final PropertyData propertyData = propertyAuditingData.getPropertyData();
referencedEntityName, relMapper, insertable); mapper.addComposite(
propertyData,
// Adding mapper for the id new OneToOnePrimaryKeyJoinColumnMapper( entityName, referencedEntityName, propertyData )
PropertyData propertyData = propertyAuditingData.getPropertyData(); );
mapper.addComposite(propertyData, new OneToOnePrimaryKeyJoinColumnMapper(entityName, referencedEntityName, propertyData)); }
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Iterator; import java.util.Iterator;
@ -39,6 +40,7 @@ import org.hibernate.mapping.Property;
/** /**
* A helper class to read versioning meta-data from annotations on a persistent class. * A helper class to read versioning meta-data from annotations on a persistent class.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander * @author Sebastian Komander
*/ */
@ -53,8 +55,9 @@ public final class AnnotationsMetadataReader {
*/ */
private final ClassAuditingData auditData; private final ClassAuditingData auditData;
public AnnotationsMetadataReader(GlobalConfiguration globalCfg, ReflectionManager reflectionManager, public AnnotationsMetadataReader(
PersistentClass pc) { GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
PersistentClass pc) {
this.globalCfg = globalCfg; this.globalCfg = globalCfg;
this.reflectionManager = reflectionManager; this.reflectionManager = reflectionManager;
this.pc = pc; this.pc = pc;
@ -63,71 +66,95 @@ public final class AnnotationsMetadataReader {
} }
private ModificationStore getDefaultAudited(XClass clazz) { private ModificationStore getDefaultAudited(XClass clazz) {
Audited defaultAudited = clazz.getAnnotation(Audited.class); final Audited defaultAudited = clazz.getAnnotation( Audited.class );
if (defaultAudited != null) { if ( defaultAudited != null ) {
return defaultAudited.modStore(); return defaultAudited.modStore();
} else { }
else {
return null; return null;
} }
} }
private void addAuditTable(XClass clazz) { private void addAuditTable(XClass clazz) {
AuditTable auditTable = clazz.getAnnotation(AuditTable.class); final AuditTable auditTable = clazz.getAnnotation( AuditTable.class );
if (auditTable != null) { if ( auditTable != null ) {
auditData.setAuditTable(auditTable); auditData.setAuditTable( auditTable );
} else { }
auditData.setAuditTable(getDefaultAuditTable()); else {
auditData.setAuditTable( getDefaultAuditTable() );
} }
} }
private void addAuditSecondaryTables(XClass clazz) { private void addAuditSecondaryTables(XClass clazz) {
// Getting information on secondary tables // Getting information on secondary tables
SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation(SecondaryAuditTable.class); final SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation( SecondaryAuditTable.class );
if (secondaryVersionsTable1 != null) { if ( secondaryVersionsTable1 != null ) {
auditData.getSecondaryTableDictionary().put(secondaryVersionsTable1.secondaryTableName(), auditData.getSecondaryTableDictionary().put(
secondaryVersionsTable1.secondaryAuditTableName()); secondaryVersionsTable1.secondaryTableName(),
secondaryVersionsTable1.secondaryAuditTableName()
);
} }
SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation(SecondaryAuditTables.class); final SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation( SecondaryAuditTables.class );
if (secondaryAuditTables != null) { if ( secondaryAuditTables != null ) {
for (SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value()) { for ( SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value() ) {
auditData.getSecondaryTableDictionary().put(secondaryAuditTable2.secondaryTableName(), auditData.getSecondaryTableDictionary().put(
secondaryAuditTable2.secondaryAuditTableName()); secondaryAuditTable2.secondaryTableName(),
secondaryAuditTable2.secondaryAuditTableName()
);
} }
} }
} }
public ClassAuditingData getAuditData() { public ClassAuditingData getAuditData() {
if (pc.getClassName() == null) { if ( pc.getClassName() == null ) {
return auditData; return auditData;
} }
try { try {
XClass xclass = reflectionManager.classForName(pc.getClassName(), this.getClass()); final XClass xclass = reflectionManager.classForName( pc.getClassName(), this.getClass() );
ModificationStore defaultStore = getDefaultAudited(xclass); final ModificationStore defaultStore = getDefaultAudited( xclass );
if (defaultStore != null) { if ( defaultStore != null ) {
auditData.setDefaultAudited(true); auditData.setDefaultAudited( true );
} }
new AuditedPropertiesReader(defaultStore, new PersistentClassPropertiesSource(xclass), auditData, new AuditedPropertiesReader(
globalCfg, reflectionManager, "").read(); defaultStore,
new PersistentClassPropertiesSource( xclass ),
auditData,
globalCfg,
reflectionManager,
""
).read();
addAuditTable(xclass); addAuditTable( xclass );
addAuditSecondaryTables(xclass); addAuditSecondaryTables( xclass );
} catch (ClassNotFoundException e) { }
throw new MappingException(e); catch (ClassNotFoundException e) {
throw new MappingException( e );
} }
return auditData; return auditData;
} }
private AuditTable defaultAuditTable = new AuditTable() { private AuditTable defaultAuditTable = new AuditTable() {
public String value() { return ""; } public String value() {
public String schema() { return ""; } return "";
public String catalog() { return ""; } }
public Class<? extends Annotation> annotationType() { return this.getClass(); }
public String schema() {
return "";
}
public String catalog() {
return "";
}
public Class<? extends Annotation> annotationType() {
return this.getClass();
}
}; };
private AuditTable getDefaultAuditTable() { private AuditTable getDefaultAuditTable() {
@ -137,11 +164,21 @@ public final class AnnotationsMetadataReader {
private class PersistentClassPropertiesSource implements PersistentPropertiesSource { private class PersistentClassPropertiesSource implements PersistentPropertiesSource {
private final XClass xclass; private final XClass xclass;
private PersistentClassPropertiesSource(XClass xclass) { this.xclass = xclass; } private PersistentClassPropertiesSource(XClass xclass) {
this.xclass = xclass;
}
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public Iterator<Property> getPropertyIterator() { return pc.getPropertyIterator(); } public Iterator<Property> getPropertyIterator() {
public Property getProperty(String propertyName) { return pc.getProperty(propertyName); } return pc.getPropertyIterator();
public XClass getXClass() { return xclass; } }
public Property getProperty(String propertyName) {
return pc.getProperty( propertyName );
}
public XClass getXClass() {
return xclass;
}
} }
} }

View File

@ -1,14 +1,39 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
/** /**
* Implementations hold other audited properties. * Implementations hold other audited properties.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Hern&aacut;n Chanfreau * @author Hern&aacut;n Chanfreau
*/ */
public interface AuditedPropertiesHolder { public interface AuditedPropertiesHolder {
/** /**
* Add an audited property. * Add an audited property.
*
* @param propertyName Name of the audited property. * @param propertyName Name of the audited property.
* @param auditingData Data for the audited property. * @param auditingData Data for the audited property.
*/ */
@ -16,19 +41,20 @@ public interface AuditedPropertiesHolder {
/** /**
* @param propertyName Name of a property. * @param propertyName Name of a property.
*
* @return Auditing data for the property. * @return Auditing data for the property.
*/ */
PropertyAuditingData getPropertyAuditingData(String propertyName); PropertyAuditingData getPropertyAuditingData(String propertyName);
/** /**
* @return true if the holder contains any audited property * @return true if the holder contains any audited property
*/ */
boolean isEmpty(); boolean isEmpty();
/** /**
* @return true if the holder contains the given audited property * @return true if the holder contains the given audited property
*/ */
boolean contains(String propertyName); boolean contains(String propertyName);
} }

View File

@ -1,5 +1,32 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -7,10 +34,6 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;
@ -65,12 +88,13 @@ public class AuditedPropertiesReader {
private final Set<XClass> overriddenAuditedClasses; private final Set<XClass> overriddenAuditedClasses;
private final Set<XClass> overriddenNotAuditedClasses; private final Set<XClass> overriddenNotAuditedClasses;
public AuditedPropertiesReader(ModificationStore defaultStore, public AuditedPropertiesReader(
PersistentPropertiesSource persistentPropertiesSource, ModificationStore defaultStore,
AuditedPropertiesHolder auditedPropertiesHolder, PersistentPropertiesSource persistentPropertiesSource,
GlobalConfiguration globalCfg, AuditedPropertiesHolder auditedPropertiesHolder,
ReflectionManager reflectionManager, GlobalConfiguration globalCfg,
String propertyNamePrefix) { ReflectionManager reflectionManager,
String propertyNamePrefix) {
this.defaultStore = defaultStore; this.defaultStore = defaultStore;
this.persistentPropertiesSource = persistentPropertiesSource; this.persistentPropertiesSource = persistentPropertiesSource;
this.auditedPropertiesHolder = auditedPropertiesHolder; this.auditedPropertiesHolder = auditedPropertiesHolder;
@ -93,245 +117,300 @@ public class AuditedPropertiesReader {
// First reading the access types for the persistent properties. // First reading the access types for the persistent properties.
readPersistentPropertiesAccess(); readPersistentPropertiesAccess();
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass // Retrieve classes and properties that are explicitly marked for auditing process by any superclass
// of currently mapped entity or itself. // of currently mapped entity or itself.
XClass clazz = persistentPropertiesSource.getXClass(); final XClass clazz = persistentPropertiesSource.getXClass();
readAuditOverrides(clazz); readAuditOverrides( clazz );
// Adding all properties from the given class. // Adding all properties from the given class.
addPropertiesFromClass(clazz); addPropertiesFromClass( clazz );
} }
/** /**
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden * Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
* using {@link AuditOverride} annotation. * using {@link AuditOverride} annotation.
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation. *
*/ * @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
private void readAuditOverrides(XClass clazz) { */
/* TODO: Code to remove with @Audited.auditParents - start. */ private void readAuditOverrides(XClass clazz) {
Audited allClassAudited = clazz.getAnnotation(Audited.class); /* TODO: Code to remove with @Audited.auditParents - start. */
if (allClassAudited != null && allClassAudited.auditParents().length > 0) { final Audited allClassAudited = clazz.getAnnotation( Audited.class );
for (Class c : allClassAudited.auditParents()) { if ( allClassAudited != null && allClassAudited.auditParents().length > 0 ) {
XClass parentClass = reflectionManager.toXClass(c); for ( Class c : allClassAudited.auditParents() ) {
checkSuperclass(clazz, parentClass); final XClass parentClass = reflectionManager.toXClass( c );
if (!overriddenNotAuditedClasses.contains(parentClass)) { checkSuperclass( clazz, parentClass );
// If the class has not been marked as not audited by the subclass. if ( !overriddenNotAuditedClasses.contains( parentClass ) ) {
overriddenAuditedClasses.add(parentClass); // If the class has not been marked as not audited by the subclass.
} overriddenAuditedClasses.add( parentClass );
} }
} }
}
/* TODO: Code to remove with @Audited.auditParents - finish. */ /* TODO: Code to remove with @Audited.auditParents - finish. */
List<AuditOverride> auditOverrides = computeAuditOverrides(clazz); final List<AuditOverride> auditOverrides = computeAuditOverrides( clazz );
for (AuditOverride auditOverride : auditOverrides) { for ( AuditOverride auditOverride : auditOverrides ) {
if (auditOverride.forClass() != void.class) { if ( auditOverride.forClass() != void.class ) {
XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass()); final XClass overrideClass = reflectionManager.toXClass( auditOverride.forClass() );
checkSuperclass(clazz, overrideClass); checkSuperclass( clazz, overrideClass );
String propertyName = auditOverride.name(); final String propertyName = auditOverride.name();
if (!StringTools.isEmpty(propertyName)) { if ( !StringTools.isEmpty( propertyName ) ) {
// Override @Audited annotation on property level. // Override @Audited annotation on property level.
XProperty property = getProperty(overrideClass, propertyName); final XProperty property = getProperty( overrideClass, propertyName );
if (auditOverride.isAudited()) { if ( auditOverride.isAudited() ) {
if (!overriddenNotAuditedProperties.contains(property)) { if ( !overriddenNotAuditedProperties.contains( property ) ) {
// If the property has not been marked as not audited by the subclass. // If the property has not been marked as not audited by the subclass.
overriddenAuditedProperties.add(property); overriddenAuditedProperties.add( property );
} }
} else { }
if (!overriddenAuditedProperties.contains(property)) { else {
// If the property has not been marked as audited by the subclass. if ( !overriddenAuditedProperties.contains( property ) ) {
overriddenNotAuditedProperties.add(property); // If the property has not been marked as audited by the subclass.
} overriddenNotAuditedProperties.add( property );
} }
} else { }
// Override @Audited annotation on class level. }
if (auditOverride.isAudited()) { else {
if (!overriddenNotAuditedClasses.contains(overrideClass)) { // Override @Audited annotation on class level.
// If the class has not been marked as not audited by the subclass. if ( auditOverride.isAudited() ) {
overriddenAuditedClasses.add(overrideClass); if ( !overriddenNotAuditedClasses.contains( overrideClass ) ) {
} // If the class has not been marked as not audited by the subclass.
} else { overriddenAuditedClasses.add( overrideClass );
if (!overriddenAuditedClasses.contains(overrideClass)) { }
// If the class has not been marked as audited by the subclass. }
overriddenNotAuditedClasses.add(overrideClass); else {
} if ( !overriddenAuditedClasses.contains( overrideClass ) ) {
} // If the class has not been marked as audited by the subclass.
} overriddenNotAuditedClasses.add( overrideClass );
} }
} }
XClass superclass = clazz.getSuperclass(); }
if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) { }
readAuditOverrides(superclass); }
} final XClass superclass = clazz.getSuperclass();
} if ( !clazz.isInterface() && !Object.class.getName().equals( superclass.getName() ) ) {
readAuditOverrides( superclass );
}
}
/** /**
* @param clazz Source class. * @param clazz Source class.
* @return List of @AuditOverride annotations applied at class level. *
*/ * @return List of @AuditOverride annotations applied at class level.
private List<AuditOverride> computeAuditOverrides(XClass clazz) { */
AuditOverrides auditOverrides = clazz.getAnnotation(AuditOverrides.class); private List<AuditOverride> computeAuditOverrides(XClass clazz) {
AuditOverride auditOverride = clazz.getAnnotation(AuditOverride.class); final AuditOverrides auditOverrides = clazz.getAnnotation( AuditOverrides.class );
if (auditOverrides == null && auditOverride != null) { final AuditOverride auditOverride = clazz.getAnnotation( AuditOverride.class );
return Arrays.asList(auditOverride); if ( auditOverrides == null && auditOverride != null ) {
} else if (auditOverrides != null && auditOverride == null) { return Arrays.asList( auditOverride );
return Arrays.asList(auditOverrides.value()); }
} else if (auditOverrides != null && auditOverride != null) { else if ( auditOverrides != null && auditOverride == null ) {
throw new MappingException("@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " + return Arrays.asList( auditOverrides.value() );
"Please revise Envers annotations applied to class " + clazz.getName() + "."); }
} else if ( auditOverrides != null && auditOverride != null ) {
return Collections.EMPTY_LIST; throw new MappingException(
} "@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
"Please revise Envers annotations applied to class " + clazz.getName() + "."
);
}
return Collections.emptyList();
}
/** /**
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown. * Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
* @param child Subclass. *
* @param parent Superclass. * @param child Subclass.
*/ * @param parent Superclass.
private void checkSuperclass(XClass child, XClass parent) { */
if (!parent.isAssignableFrom(child)) { private void checkSuperclass(XClass child, XClass parent) {
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " + if ( !parent.isAssignableFrom( child ) ) {
"Please revise Envers annotations applied to " + child.getName() + " type."); throw new MappingException(
} "Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
} "Please revise Envers annotations applied to " + child.getName() + " type."
);
}
}
/** /**
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown. * Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
* @param clazz Class. *
* @param propertyName Property name. * @param clazz Class.
* @return Property object. * @param propertyName Property name.
*/ *
private XProperty getProperty(XClass clazz, String propertyName) { * @return Property object.
XProperty property = ReflectionTools.getProperty(clazz, propertyName); */
if (property == null) { private XProperty getProperty(XClass clazz, String propertyName) {
throw new MappingException("Property '" + propertyName + "' not found in class " + clazz.getName() + ". " + final XProperty property = ReflectionTools.getProperty( clazz, propertyName );
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + "."); if ( property == null ) {
} throw new MappingException(
return property; "Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
} "Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + "."
);
}
return property;
}
private void readPersistentPropertiesAccess() { private void readPersistentPropertiesAccess() {
Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator(); final Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
while (propertyIter.hasNext()) { while ( propertyIter.hasNext() ) {
Property property = propertyIter.next(); final Property property = propertyIter.next();
addPersistentProperty(property); addPersistentProperty( property );
if ("embedded".equals(property.getPropertyAccessorName()) && property.getName().equals(property.getNodeName())) { if ( "embedded".equals( property.getPropertyAccessorName() ) && property.getName()
.equals( property.getNodeName() ) ) {
// If property name equals node name and embedded accessor type is used, processing component // If property name equals node name and embedded accessor type is used, processing component
// has been defined with <properties> tag. See HHH-6636 JIRA issue. // has been defined with <properties> tag. See HHH-6636 JIRA issue.
createPropertiesGroupMapping(property); createPropertiesGroupMapping( property );
} }
} }
} }
private void addPersistentProperty(Property property) { private void addPersistentProperty(Property property) {
if ("field".equals(property.getPropertyAccessorName())) { if ( "field".equals( property.getPropertyAccessorName() ) ) {
fieldAccessedPersistentProperties.add(property.getName()); fieldAccessedPersistentProperties.add( property.getName() );
} else { }
propertyAccessedPersistentProperties.add(property.getName()); else {
} propertyAccessedPersistentProperties.add( property.getName() );
} }
}
private void createPropertiesGroupMapping(Property property) { @SuppressWarnings("unchecked")
Component component = (Component) property.getValue(); private void createPropertiesGroupMapping(Property property) {
Iterator<Property> componentProperties = component.getPropertyIterator(); final Component component = (Component) property.getValue();
while (componentProperties.hasNext()) { final Iterator<Property> componentProperties = component.getPropertyIterator();
Property componentProperty = componentProperties.next(); while ( componentProperties.hasNext() ) {
propertiesGroupMapping.put(componentProperty.getName(), component.getNodeName()); final Property componentProperty = componentProperties.next();
} propertiesGroupMapping.put( componentProperty.getName(), component.getNodeName() );
} }
}
/** /**
* @param clazz Class which properties are currently being added. * @param clazz Class which properties are currently being added.
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method *
* checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection. * @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise * checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection.
* {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses} * In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
* collection, the result is also {@code null}. * {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses}
*/ * collection, the result is also {@code null}.
private Audited computeAuditConfiguration(XClass clazz) { */
Audited allClassAudited = clazz.getAnnotation(Audited.class); private Audited computeAuditConfiguration(XClass clazz) {
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is Audited allClassAudited = clazz.getAnnotation( Audited.class );
// forced by any of its child entities configuration (@AuditedOverride.forClass). // If processed class is not explicitly marked with @Audited annotation, check whether auditing is
if (allClassAudited == null && overriddenAuditedClasses.contains(clazz)) { // forced by any of its child entities configuration (@AuditedOverride.forClass).
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from if ( allClassAudited == null && overriddenAuditedClasses.contains( clazz ) ) {
// currently mapped entity. // Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation(Audited.class); // currently mapped entity.
if (allClassAudited == null) { allClassAudited = persistentPropertiesSource.getXClass().getAnnotation( Audited.class );
// If parent class declares @Audited on the field/property level. if ( allClassAudited == null ) {
allClassAudited = DEFAULT_AUDITED; // If parent class declares @Audited on the field/property level.
} allClassAudited = DEFAULT_AUDITED;
} else if (allClassAudited != null && overriddenNotAuditedClasses.contains(clazz)) { }
return null; }
} else if ( allClassAudited != null && overriddenNotAuditedClasses.contains( clazz ) ) {
return allClassAudited; return null;
} }
return allClassAudited;
}
/** /**
* Recursively adds all audited properties of entity class and its superclasses. * Recursively adds all audited properties of entity class and its superclasses.
* @param clazz Currently processed class. *
*/ * @param clazz Currently processed class.
private void addPropertiesFromClass(XClass clazz) { */
Audited allClassAudited = computeAuditConfiguration(clazz); private void addPropertiesFromClass(XClass clazz) {
final Audited allClassAudited = computeAuditConfiguration( clazz );
//look in the class //look in the class
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited); addFromProperties(
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited); clazz.getDeclaredProperties( "field" ),
"field",
if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) { fieldAccessedPersistentProperties,
XClass superclazz = clazz.getSuperclass(); allClassAudited
if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) { );
addPropertiesFromClass(superclazz); addFromProperties(
clazz.getDeclaredProperties( "property" ),
"property",
propertyAccessedPersistentProperties,
allClassAudited
);
if ( allClassAudited != null || !auditedPropertiesHolder.isEmpty() ) {
final XClass superclazz = clazz.getSuperclass();
if ( !clazz.isInterface() && !"java.lang.Object".equals( superclazz.getName() ) ) {
addPropertiesFromClass( superclazz );
} }
} }
} }
private void addFromProperties(Iterable<XProperty> properties, String accessType, Set<String> persistentProperties, Audited allClassAudited) { private void addFromProperties(
for (XProperty property : properties) { Iterable<XProperty> properties,
String accessType,
Set<String> persistentProperties,
Audited allClassAudited) {
for ( XProperty property : properties ) {
// If this is not a persistent property, with the same access type as currently checked, // If this is not a persistent property, with the same access type as currently checked,
// it's not audited as well. // it's not audited as well.
// If the property was already defined by the subclass, is ignored by superclasses // If the property was already defined by the subclass, is ignored by superclasses
if ((persistentProperties.contains(property.getName()) && (!auditedPropertiesHolder if ( persistentProperties.contains( property.getName() )
.contains(property.getName())))) { && !auditedPropertiesHolder.contains( property.getName() ) ) {
Value propertyValue = persistentPropertiesSource.getProperty(property.getName()).getValue(); final Value propertyValue = persistentPropertiesSource.getProperty( property.getName() ).getValue();
if (propertyValue instanceof Component) { if ( propertyValue instanceof Component ) {
this.addFromComponentProperty(property, accessType, (Component)propertyValue, allClassAudited); this.addFromComponentProperty( property, accessType, (Component) propertyValue, allClassAudited );
} else {
this.addFromNotComponentProperty(property, accessType, allClassAudited);
} }
} else if (propertiesGroupMapping.containsKey(property.getName())) { else {
this.addFromNotComponentProperty( property, accessType, allClassAudited );
}
}
else if ( propertiesGroupMapping.containsKey( property.getName() ) ) {
// Retrieve embedded component name based on class field. // Retrieve embedded component name based on class field.
final String embeddedName = propertiesGroupMapping.get(property.getName()); final String embeddedName = propertiesGroupMapping.get( property.getName() );
if (!auditedPropertiesHolder.contains(embeddedName)) { if ( !auditedPropertiesHolder.contains( embeddedName ) ) {
// Manage properties mapped within <properties> tag. // Manage properties mapped within <properties> tag.
Value propertyValue = persistentPropertiesSource.getProperty(embeddedName).getValue(); final Value propertyValue = persistentPropertiesSource.getProperty( embeddedName ).getValue();
this.addFromPropertiesGroup(embeddedName, property, accessType, (Component)propertyValue, allClassAudited); this.addFromPropertiesGroup(
embeddedName,
property,
accessType,
(Component) propertyValue,
allClassAudited
);
} }
} }
} }
} }
private void addFromPropertiesGroup(String embeddedName, XProperty property, String accessType, Component propertyValue, private void addFromPropertiesGroup(
Audited allClassAudited) { String embeddedName,
ComponentAuditingData componentData = new ComponentAuditingData(); XProperty property,
boolean isAudited = fillPropertyData(property, componentData, accessType, allClassAudited); String accessType,
if (isAudited) { Component propertyValue,
Audited allClassAudited) {
final ComponentAuditingData componentData = new ComponentAuditingData();
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
if ( isAudited ) {
// EntityPersister.getPropertyNames() returns name of embedded component instead of class field. // EntityPersister.getPropertyNames() returns name of embedded component instead of class field.
componentData.setName(embeddedName); componentData.setName( embeddedName );
// Marking component properties as placed directly in class (not inside another component). // Marking component properties as placed directly in class (not inside another component).
componentData.setBeanName(null); componentData.setBeanName( null );
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( reflectionManager, propertyValue ); final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader( reflectionManager,
propertyValue
);
final AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager, ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName) propertyNamePrefix + MappingTools.createComponentPrefix( embeddedName )
); );
audPropReader.read(); audPropReader.read();
auditedPropertiesHolder.addPropertyAuditingData(embeddedName, componentData); auditedPropertiesHolder.addPropertyAuditingData( embeddedName, componentData );
} }
} }
private void addFromComponentProperty(XProperty property, String accessType, Component propertyValue, Audited allClassAudited) { private void addFromComponentProperty(
ComponentAuditingData componentData = new ComponentAuditingData(); XProperty property,
boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited ); String accessType,
Component propertyValue,
Audited allClassAudited) {
final ComponentAuditingData componentData = new ComponentAuditingData();
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
if ( propertyValue.isDynamic() ) { if ( propertyValue.isDynamic() ) {
if ( isAudited ) { if ( isAudited ) {
@ -343,12 +422,16 @@ public class AuditedPropertiesReader {
return; return;
} }
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
reflectionManager, propertyValue reflectionManager, propertyValue
); );
ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader( final ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager, ModificationStore.FULL,
componentPropertiesSource,
componentData,
globalCfg,
reflectionManager,
propertyNamePrefix + MappingTools.createComponentPrefix( property.getName() ) propertyNamePrefix + MappingTools.createComponentPrefix( property.getName() )
); );
audPropReader.read(); audPropReader.read();
@ -359,85 +442,102 @@ public class AuditedPropertiesReader {
} }
} }
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited){ private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited) {
PropertyAuditingData propertyData = new PropertyAuditingData(); final PropertyAuditingData propertyData = new PropertyAuditingData();
boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited); final boolean isAudited = fillPropertyData( property, propertyData, accessType, allClassAudited );
if (isAudited) { if ( isAudited ) {
// Now we know that the property is audited // Now we know that the property is audited
auditedPropertiesHolder.addPropertyAuditingData(property.getName(), propertyData); auditedPropertiesHolder.addPropertyAuditingData( property.getName(), propertyData );
} }
} }
/** /**
* Checks if a property is audited and if yes, fills all of its data. * Checks if a property is audited and if yes, fills all of its data.
*
* @param property Property to check. * @param property Property to check.
* @param propertyData Property data, on which to set this property's modification store. * @param propertyData Property data, on which to set this property's modification store.
* @param accessType Access type for the property. * @param accessType Access type for the property.
*
* @return False if this property is not audited. * @return False if this property is not audited.
*/ */
private boolean fillPropertyData(XProperty property, PropertyAuditingData propertyData, private boolean fillPropertyData(
String accessType, Audited allClassAudited) { XProperty property,
PropertyAuditingData propertyData,
String accessType,
Audited allClassAudited) {
// check if a property is declared as not audited to exclude it // check if a property is declared as not audited to exclude it
// useful if a class is audited but some properties should be excluded // useful if a class is audited but some properties should be excluded
NotAudited unVer = property.getAnnotation(NotAudited.class); final NotAudited unVer = property.getAnnotation( NotAudited.class );
if ((unVer != null && !overriddenAuditedProperties.contains(property)) || overriddenNotAuditedProperties.contains(property)) { if ( (unVer != null
&& !overriddenAuditedProperties.contains( property ))
|| overriddenNotAuditedProperties.contains( property ) ) {
return false; return false;
} else { }
else {
// if the optimistic locking field has to be unversioned and the current property // if the optimistic locking field has to be unversioned and the current property
// is the optimistic locking field, don't audit it // is the optimistic locking field, don't audit it
if (globalCfg.isDoNotAuditOptimisticLockingField()) { if ( globalCfg.isDoNotAuditOptimisticLockingField() ) {
Version jpaVer = property.getAnnotation(Version.class); final Version jpaVer = property.getAnnotation( Version.class );
if (jpaVer != null) { if ( jpaVer != null ) {
return false; return false;
} }
} }
} }
if(!this.checkAudited(property, propertyData, allClassAudited)){ if ( !this.checkAudited( property, propertyData, allClassAudited ) ) {
return false; return false;
} }
String propertyName = propertyNamePrefix + property.getName(); final String propertyName = propertyNamePrefix + property.getName();
propertyData.setName(propertyName); propertyData.setName( propertyName );
propertyData.setModifiedFlagName( propertyData.setModifiedFlagName(
MetadataTools.getModifiedFlagPropertyName( MetadataTools.getModifiedFlagPropertyName(
propertyName, propertyName,
globalCfg.getModifiedFlagSuffix())); globalCfg.getModifiedFlagSuffix()
propertyData.setBeanName(property.getName()); )
propertyData.setAccessType(accessType); );
propertyData.setBeanName( property.getName() );
propertyData.setAccessType( accessType );
addPropertyJoinTables(property, propertyData); addPropertyJoinTables( property, propertyData );
addPropertyAuditingOverrides(property, propertyData); addPropertyAuditingOverrides( property, propertyData );
if (!processPropertyAuditingOverrides(property, propertyData)) { if ( !processPropertyAuditingOverrides( property, propertyData ) ) {
return false; // not audited due to AuditOverride annotation // not audited due to AuditOverride annotation
return false;
} }
addPropertyMapKey(property, propertyData); addPropertyMapKey( property, propertyData );
setPropertyAuditMappedBy(property, propertyData); setPropertyAuditMappedBy( property, propertyData );
setPropertyRelationMappedBy(property, propertyData); setPropertyRelationMappedBy( property, propertyData );
return true; return true;
} }
protected boolean checkAudited(XProperty property, protected boolean checkAudited(
XProperty property,
PropertyAuditingData propertyData, Audited allClassAudited) { PropertyAuditingData propertyData, Audited allClassAudited) {
// Checking if this property is explicitly audited or if all properties are. // Checking if this property is explicitly audited or if all properties are.
Audited aud = (property.isAnnotationPresent(Audited.class)) ? (property.getAnnotation(Audited.class)) : allClassAudited; Audited aud = (property.isAnnotationPresent( Audited.class ))
if (aud == null && overriddenAuditedProperties.contains(property) && !overriddenNotAuditedProperties.contains(property)) { ? property.getAnnotation( Audited.class )
: allClassAudited;
if ( aud == null
&& overriddenAuditedProperties.contains( property )
&& !overriddenNotAuditedProperties.contains( property ) ) {
// Assigning @Audited defaults. If anyone needs to customize those values in the future, // Assigning @Audited defaults. If anyone needs to customize those values in the future,
// appropriate fields shall be added to @AuditOverride annotation. // appropriate fields shall be added to @AuditOverride annotation.
aud = DEFAULT_AUDITED; aud = DEFAULT_AUDITED;
} }
if (aud != null) { if ( aud != null ) {
propertyData.setStore(aud.modStore()); propertyData.setStore( aud.modStore() );
propertyData.setRelationTargetAuditMode(aud.targetAuditMode()); propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud)); propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@ -447,121 +547,172 @@ public class AuditedPropertiesReader {
globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag(); globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag();
} }
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) { private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
OneToMany oneToMany = property.getAnnotation(OneToMany.class); final OneToMany oneToMany = property.getAnnotation( OneToMany.class );
if (oneToMany != null && !"".equals(oneToMany.mappedBy())) { if ( oneToMany != null && !"".equals( oneToMany.mappedBy() ) ) {
propertyData.setRelationMappedBy(oneToMany.mappedBy()); propertyData.setRelationMappedBy( oneToMany.mappedBy() );
} }
} }
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) { private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class); final AuditMappedBy auditMappedBy = property.getAnnotation( AuditMappedBy.class );
if (auditMappedBy != null) { if ( auditMappedBy != null ) {
propertyData.setAuditMappedBy(auditMappedBy.mappedBy()); propertyData.setAuditMappedBy( auditMappedBy.mappedBy() );
if (!"".equals(auditMappedBy.positionMappedBy())) { if ( !"".equals( auditMappedBy.positionMappedBy() ) ) {
propertyData.setPositionMappedBy(auditMappedBy.positionMappedBy()); propertyData.setPositionMappedBy( auditMappedBy.positionMappedBy() );
} }
} }
} }
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) { private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
MapKey mapKey = property.getAnnotation(MapKey.class); final MapKey mapKey = property.getAnnotation( MapKey.class );
if (mapKey != null) { if ( mapKey != null ) {
propertyData.setMapKey(mapKey.name()); propertyData.setMapKey( mapKey.name() );
} }
} }
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) { private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
// first set the join table based on the AuditJoinTable annotation // first set the join table based on the AuditJoinTable annotation
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class); final AuditJoinTable joinTable = property.getAnnotation( AuditJoinTable.class );
if (joinTable != null) { if ( joinTable != null ) {
propertyData.setJoinTable(joinTable); propertyData.setJoinTable( joinTable );
} else { }
propertyData.setJoinTable(DEFAULT_AUDIT_JOIN_TABLE); else {
propertyData.setJoinTable( DEFAULT_AUDIT_JOIN_TABLE );
} }
} }
/*** /**
* Add the {@link AuditOverride} annotations. * Add the {@link AuditOverride} annotations.
* *
* @param property the property being processed * @param property the property being processed
* @param propertyData the Envers auditing data for this property * @param propertyData the Envers auditing data for this property
*/ */
private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) { private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
AuditOverride annotationOverride = property.getAnnotation(AuditOverride.class); final AuditOverride annotationOverride = property.getAnnotation( AuditOverride.class );
if (annotationOverride != null) { if ( annotationOverride != null ) {
propertyData.addAuditingOverride(annotationOverride); propertyData.addAuditingOverride( annotationOverride );
} }
AuditOverrides annotationOverrides = property.getAnnotation(AuditOverrides.class); final AuditOverrides annotationOverrides = property.getAnnotation( AuditOverrides.class );
if (annotationOverrides != null) { if ( annotationOverrides != null ) {
propertyData.addAuditingOverrides(annotationOverrides); propertyData.addAuditingOverrides( annotationOverrides );
} }
} }
/** /**
* Process the {@link AuditOverride} annotations for this property. * Process the {@link AuditOverride} annotations for this property.
* *
* @param property * @param property the property for which the {@link AuditOverride}
* the property for which the {@link AuditOverride} * annotations are being processed
* annotations are being processed * @param propertyData the Envers auditing data for this property
* @param propertyData *
* the Envers auditing data for this property
* @return {@code false} if isAudited() of the override annotation was set to * @return {@code false} if isAudited() of the override annotation was set to
*/ */
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) { private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
// if this property is part of a component, process all override annotations // if this property is part of a component, process all override annotations
if (this.auditedPropertiesHolder instanceof ComponentAuditingData) { if ( this.auditedPropertiesHolder instanceof ComponentAuditingData ) {
List<AuditOverride> overrides = ((ComponentAuditingData) this.auditedPropertiesHolder).getAuditingOverrides(); final List<AuditOverride> overrides = ( (ComponentAuditingData) this.auditedPropertiesHolder ).getAuditingOverrides();
for (AuditOverride override : overrides) { for ( AuditOverride override : overrides ) {
if (property.getName().equals(override.name())) { if ( property.getName().equals( override.name() ) ) {
// the override applies to this property // the override applies to this property
if (!override.isAudited()) { if ( !override.isAudited() ) {
return false; return false;
} else { }
if (override.auditJoinTable() != null) { else {
propertyData.setJoinTable(override.auditJoinTable()); if ( override.auditJoinTable() != null ) {
propertyData.setJoinTable( override.auditJoinTable() );
} }
} }
} }
} }
} }
return true; return true;
} }
private static Audited DEFAULT_AUDITED = new Audited() { private static final Audited DEFAULT_AUDITED = new Audited() {
public ModificationStore modStore() { return ModificationStore.FULL; } @Override
public RelationTargetAuditMode targetAuditMode() { return RelationTargetAuditMode.AUDITED; } public ModificationStore modStore() {
public Class[] auditParents() { return new Class[0]; } return ModificationStore.FULL;
public boolean withModifiedFlag() { return false; } }
public Class<? extends Annotation> annotationType() { return this.getClass(); }
};
private static AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() { @Override
public String name() { return ""; } public RelationTargetAuditMode targetAuditMode() {
public String schema() { return ""; } return RelationTargetAuditMode.AUDITED;
public String catalog() { return ""; } }
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
public Class<? extends Annotation> annotationType() { return this.getClass(); } @Override
public Class[] auditParents() {
return new Class[0];
}
@Override
public boolean withModifiedFlag() {
return false;
}
@Override
public Class<? extends Annotation> annotationType() {
return this.getClass();
}
}; };
public static class ComponentPropertiesSource implements PersistentPropertiesSource { private static final AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
@Override
public String name() {
return "";
}
@Override
public String schema() {
return "";
}
@Override
public String catalog() {
return "";
}
@Override
public JoinColumn[] inverseJoinColumns() {
return new JoinColumn[0];
}
@Override
public Class<? extends Annotation> annotationType() {
return this.getClass();
}
};
public static class ComponentPropertiesSource implements PersistentPropertiesSource {
private final XClass xclass; private final XClass xclass;
private final Component component; private final Component component;
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) { public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
try { try {
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass()); this.xclass = reflectionManager.classForName( component.getComponentClassName(), this.getClass() );
} catch (ClassNotFoundException e) { }
throw new MappingException(e); catch (ClassNotFoundException e) {
throw new MappingException( e );
} }
this.component = component; this.component = component;
} }
@Override
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public Iterator<Property> getPropertyIterator() { return component.getPropertyIterator(); } public Iterator<Property> getPropertyIterator() {
public Property getProperty(String propertyName) { return component.getProperty(propertyName); } return component.getPropertyIterator();
public XClass getXClass() { return xclass; } }
@Override
public Property getProperty(String propertyName) {
return component.getProperty( propertyName );
}
@Override
public XClass getXClass() {
return xclass;
}
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
import java.util.Map; import java.util.Map;
import org.hibernate.envers.AuditTable; import org.hibernate.envers.AuditTable;
@ -32,12 +33,12 @@ import static org.hibernate.envers.internal.tools.Tools.newHashMap;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander * @author Sebastian Komander
* @author Hern&aacut;n Chanfreau * @author Hern&aacut;n Chanfreau
*/ */
public class ClassAuditingData implements AuditedPropertiesHolder { public class ClassAuditingData implements AuditedPropertiesHolder {
private final Map<String, PropertyAuditingData> properties; private final Map<String, PropertyAuditingData> properties;
private final Map<String, String> secondaryTableDictionary; private final Map<String, String> secondaryTableDictionary;
private AuditTable auditTable; private AuditTable auditTable;
/** /**
* True if the class is audited globally (this helps to cover the cases when there are no fields in the class, * True if the class is audited globally (this helps to cover the cases when there are no fields in the class,
@ -45,48 +46,52 @@ public class ClassAuditingData implements AuditedPropertiesHolder {
*/ */
private boolean defaultAudited; private boolean defaultAudited;
public ClassAuditingData() { public ClassAuditingData() {
properties = newHashMap(); properties = newHashMap();
secondaryTableDictionary = newHashMap(); secondaryTableDictionary = newHashMap();
}
public boolean isEmpty() {
return properties.isEmpty();
}
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
properties.put(propertyName, auditingData);
} }
public PropertyAuditingData getPropertyAuditingData(String propertyName) { @Override
return properties.get(propertyName); public boolean isEmpty() {
} return properties.isEmpty();
}
public Iterable<String> getPropertyNames() { @Override
return properties.keySet(); public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
} properties.put( propertyName, auditingData );
}
public Map<String, String> getSecondaryTableDictionary() { @Override
return secondaryTableDictionary; public PropertyAuditingData getPropertyAuditingData(String propertyName) {
} return properties.get( propertyName );
}
public AuditTable getAuditTable() { public Iterable<String> getPropertyNames() {
return auditTable; return properties.keySet();
} }
public void setAuditTable(AuditTable auditTable) { public Map<String, String> getSecondaryTableDictionary() {
this.auditTable = auditTable; return secondaryTableDictionary;
} }
public AuditTable getAuditTable() {
return auditTable;
}
public void setAuditTable(AuditTable auditTable) {
this.auditTable = auditTable;
}
public void setDefaultAudited(boolean defaultAudited) { public void setDefaultAudited(boolean defaultAudited) {
this.defaultAudited = defaultAudited; this.defaultAudited = defaultAudited;
} }
public boolean isAudited() { public boolean isAudited() {
return defaultAudited || properties.size() > 0; return defaultAudited || properties.size() > 0;
} }
@Override
public boolean contains(String propertyName) { public boolean contains(String propertyName) {
return properties.containsKey(propertyName); return properties.containsKey( propertyName );
} }
} }

View File

@ -1,4 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.envers.Audited; import org.hibernate.envers.Audited;
@ -7,34 +31,40 @@ import org.hibernate.envers.configuration.internal.GlobalConfiguration;
/** /**
* Reads the audited properties for components. * Reads the audited properties for components.
* *
* @author Hern&aacut;n Chanfreau * @author Hern&aacut;n Chanfreau
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader { public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
public ComponentAuditedPropertiesReader(ModificationStore defaultStore, public ComponentAuditedPropertiesReader(
ModificationStore defaultStore,
PersistentPropertiesSource persistentPropertiesSource, PersistentPropertiesSource persistentPropertiesSource,
AuditedPropertiesHolder auditedPropertiesHolder, AuditedPropertiesHolder auditedPropertiesHolder,
GlobalConfiguration globalCfg, ReflectionManager reflectionManager, GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
String propertyNamePrefix) { String propertyNamePrefix) {
super(defaultStore, persistentPropertiesSource, auditedPropertiesHolder, super(
globalCfg, reflectionManager, propertyNamePrefix); defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
globalCfg, reflectionManager, propertyNamePrefix
);
} }
@Override @Override
protected boolean checkAudited(XProperty property, protected boolean checkAudited(
PropertyAuditingData propertyData, Audited allClassAudited) { XProperty property,
PropertyAuditingData propertyData,
Audited allClassAudited) {
// Checking if this property is explicitly audited or if all properties are. // Checking if this property is explicitly audited or if all properties are.
Audited aud = property.getAnnotation(Audited.class); final Audited aud = property.getAnnotation( Audited.class );
if (aud != null) { if ( aud != null ) {
propertyData.setStore(aud.modStore()); propertyData.setStore( aud.modStore() );
propertyData.setRelationTargetAuditMode(aud.targetAuditMode()); propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud)); propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
} else { }
propertyData.setStore(ModificationStore.FULL); else {
} propertyData.setStore( ModificationStore.FULL );
return true; }
return true;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -30,6 +30,7 @@ import static org.hibernate.envers.internal.tools.Tools.newHashMap;
/** /**
* Audit mapping meta-data for component. * Audit mapping meta-data for component.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Hern&aacut;n Chanfreau * @author Hern&aacut;n Chanfreau
*/ */
@ -40,21 +41,25 @@ public class ComponentAuditingData extends PropertyAuditingData implements Audit
this.properties = newHashMap(); this.properties = newHashMap();
} }
@Override
public boolean isEmpty() { public boolean isEmpty() {
return properties.isEmpty(); return properties.isEmpty();
} }
@Override
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) { public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
properties.put(propertyName, auditingData); properties.put( propertyName, auditingData );
} }
public PropertyAuditingData getPropertyAuditingData(String propertyName) { @Override
return properties.get(propertyName); public PropertyAuditingData getPropertyAuditingData(String propertyName) {
} return properties.get( propertyName );
}
public boolean contains(String propertyName) {
return properties.containsKey(propertyName); @Override
} public boolean contains(String propertyName) {
return properties.containsKey( propertyName );
}
public Set<String> getPropertyNames() { public Set<String> getPropertyNames() {
return properties.keySet(); return properties.keySet();

View File

@ -1,4 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
import java.util.Iterator; import java.util.Iterator;
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
@ -6,10 +30,13 @@ import org.hibernate.mapping.Property;
/** /**
* A source of data on persistent properties of a class or component. * A source of data on persistent properties of a class or component.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public interface PersistentPropertiesSource { public interface PersistentPropertiesSource {
Iterator<Property> getPropertyIterator(); Iterator<Property> getPropertyIterator();
Property getProperty(String propertyName); Property getProperty(String propertyName);
XClass getXClass(); XClass getXClass();
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.envers.configuration.internal.metadata.reader; package org.hibernate.envers.configuration.internal.metadata.reader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -38,45 +38,46 @@ import org.hibernate.envers.internal.entities.PropertyData;
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public class PropertyAuditingData { public class PropertyAuditingData {
private String name; private String name;
private String beanName; private String beanName;
private ModificationStore store; private ModificationStore store;
private String mapKey; private String mapKey;
private AuditJoinTable joinTable; private AuditJoinTable joinTable;
private String accessType; private String accessType;
private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>(0); private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>( 0 );
private RelationTargetAuditMode relationTargetAuditMode; private RelationTargetAuditMode relationTargetAuditMode;
private String auditMappedBy; private String auditMappedBy;
private String relationMappedBy; private String relationMappedBy;
private String positionMappedBy; private String positionMappedBy;
private boolean forceInsertable; private boolean forceInsertable;
private boolean usingModifiedFlag; private boolean usingModifiedFlag;
private String modifiedFlagName; private String modifiedFlagName;
public PropertyAuditingData() { public PropertyAuditingData() {
} }
public PropertyAuditingData(String name, String accessType, ModificationStore store, public PropertyAuditingData(
RelationTargetAuditMode relationTargetAuditMode, String name, String accessType, ModificationStore store,
String auditMappedBy, String positionMappedBy, RelationTargetAuditMode relationTargetAuditMode,
boolean forceInsertable) { String auditMappedBy, String positionMappedBy,
this.name = name; boolean forceInsertable) {
this.name = name;
this.beanName = name; this.beanName = name;
this.accessType = accessType; this.accessType = accessType;
this.store = store; this.store = store;
this.relationTargetAuditMode = relationTargetAuditMode; this.relationTargetAuditMode = relationTargetAuditMode;
this.auditMappedBy = auditMappedBy; this.auditMappedBy = auditMappedBy;
this.positionMappedBy = positionMappedBy; this.positionMappedBy = positionMappedBy;
this.forceInsertable = forceInsertable; this.forceInsertable = forceInsertable;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public String getBeanName() { public String getBeanName() {
return beanName; return beanName;
@ -87,77 +88,79 @@ public class PropertyAuditingData {
} }
public ModificationStore getStore() { public ModificationStore getStore() {
return store; return store;
} }
public void setStore(ModificationStore store) { public void setStore(ModificationStore store) {
this.store = store; this.store = store;
} }
public String getMapKey() { public String getMapKey() {
return mapKey; return mapKey;
} }
public void setMapKey(String mapKey) { public void setMapKey(String mapKey) {
this.mapKey = mapKey; this.mapKey = mapKey;
} }
public AuditJoinTable getJoinTable() { public AuditJoinTable getJoinTable() {
return joinTable; return joinTable;
} }
public void setJoinTable(AuditJoinTable joinTable) { public void setJoinTable(AuditJoinTable joinTable) {
this.joinTable = joinTable; this.joinTable = joinTable;
} }
public String getAccessType() { public String getAccessType() {
return accessType; return accessType;
} }
public void setAccessType(String accessType) { public void setAccessType(String accessType) {
this.accessType = accessType; this.accessType = accessType;
} }
public PropertyData getPropertyData() { public PropertyData getPropertyData() {
return new PropertyData(name, beanName, accessType, store, return new PropertyData(
usingModifiedFlag, modifiedFlagName); name, beanName, accessType, store,
} usingModifiedFlag, modifiedFlagName
);
}
public List<AuditOverride> getAuditingOverrides() { public List<AuditOverride> getAuditingOverrides() {
return auditJoinTableOverrides; return auditJoinTableOverrides;
} }
public String getAuditMappedBy() { public String getAuditMappedBy() {
return auditMappedBy; return auditMappedBy;
} }
public void setAuditMappedBy(String auditMappedBy) { public void setAuditMappedBy(String auditMappedBy) {
this.auditMappedBy = auditMappedBy; this.auditMappedBy = auditMappedBy;
} }
public String getRelationMappedBy() { public String getRelationMappedBy() {
return relationMappedBy; return relationMappedBy;
} }
public void setRelationMappedBy(String relationMappedBy) { public void setRelationMappedBy(String relationMappedBy) {
this.relationMappedBy = relationMappedBy; this.relationMappedBy = relationMappedBy;
} }
public String getPositionMappedBy() { public String getPositionMappedBy() {
return positionMappedBy; return positionMappedBy;
} }
public void setPositionMappedBy(String positionMappedBy) { public void setPositionMappedBy(String positionMappedBy) {
this.positionMappedBy = positionMappedBy; this.positionMappedBy = positionMappedBy;
} }
public boolean isForceInsertable() { public boolean isForceInsertable() {
return forceInsertable; return forceInsertable;
} }
public void setForceInsertable(boolean forceInsertable) { public void setForceInsertable(boolean forceInsertable) {
this.forceInsertable = forceInsertable; this.forceInsertable = forceInsertable;
} }
public boolean isUsingModifiedFlag() { public boolean isUsingModifiedFlag() {
return usingModifiedFlag; return usingModifiedFlag;
@ -172,25 +175,25 @@ public class PropertyAuditingData {
} }
public void addAuditingOverride(AuditOverride annotation) { public void addAuditingOverride(AuditOverride annotation) {
if (annotation != null) { if ( annotation != null ) {
String overrideName = annotation.name(); final String overrideName = annotation.name();
boolean present = false; boolean present = false;
for (AuditOverride current : auditJoinTableOverrides) { for ( AuditOverride current : auditJoinTableOverrides ) {
if (current.name().equals(overrideName)) { if ( current.name().equals( overrideName ) ) {
present = true; present = true;
break; break;
} }
} }
if (!present) { if ( !present ) {
auditJoinTableOverrides.add(annotation); auditJoinTableOverrides.add( annotation );
} }
} }
} }
public void addAuditingOverrides(AuditOverrides annotationOverrides) { public void addAuditingOverrides(AuditOverrides annotationOverrides) {
if (annotationOverrides != null) { if ( annotationOverrides != null ) {
for (AuditOverride annotation : annotationOverrides.value()) { for ( AuditOverride annotation : annotationOverrides.value() ) {
addAuditingOverride(annotation); addAuditingOverride( annotation );
} }
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -107,30 +107,30 @@ public class AuditConfiguration {
public AuditConfiguration(Configuration cfg, ClassLoaderService classLoaderService) { public AuditConfiguration(Configuration cfg, ClassLoaderService classLoaderService) {
// TODO: Temporarily allow Envers to continuing using // TODO: Temporarily allow Envers to continuing using
// hibernate-commons-annotations' for reflection and class loading. // hibernate-commons-annotations' for reflection and class loading.
ClassLoader tccl = Thread.currentThread().getContextClassLoader(); final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() ); Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() );
Properties properties = cfg.getProperties();
ReflectionManager reflectionManager = cfg.getReflectionManager(); final Properties properties = cfg.getProperties();
globalCfg = new GlobalConfiguration( properties, classLoaderService );
RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg ); final ReflectionManager reflectionManager = cfg.getReflectionManager();
RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure( cfg, reflectionManager ); this.globalCfg = new GlobalConfiguration( properties, classLoaderService );
auditEntCfg = new AuditEntitiesConfiguration( properties, revInfoCfgResult.getRevisionInfoEntityName() ); final RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg );
auditProcessManager = new AuditProcessManager( revInfoCfgResult.getRevisionInfoGenerator() ); final RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure( cfg, reflectionManager );
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator(); this.auditEntCfg = new AuditEntitiesConfiguration( properties, revInfoCfgResult.getRevisionInfoEntityName() );
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader(); this.auditProcessManager = new AuditProcessManager( revInfoCfgResult.getRevisionInfoGenerator() );
modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader(); this.revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
this.revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
this.modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
this.classLoaderService = classLoaderService; this.classLoaderService = classLoaderService;
auditStrategy = initializeAuditStrategy( this.auditStrategy = initializeAuditStrategy(
revInfoCfgResult.getRevisionInfoClass(), revInfoCfgResult.getRevisionInfoClass(),
revInfoCfgResult.getRevisionInfoTimestampData() revInfoCfgResult.getRevisionInfoTimestampData()
); );
entCfg = new EntitiesConfigurator().configure( this.entCfg = new EntitiesConfigurator().configure(
cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy, classLoaderService, cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy, classLoaderService,
revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping() revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping()
); );
Thread.currentThread().setContextClassLoader( tccl ); Thread.currentThread().setContextClassLoader( tccl );
} }
@ -143,11 +143,14 @@ public class AuditConfiguration {
auditStrategyClass = this.getClass().getClassLoader().loadClass( auditEntCfg.getAuditStrategyName() ); auditStrategyClass = this.getClass().getClassLoader().loadClass( auditEntCfg.getAuditStrategyName() );
} }
catch (Exception e) { catch (Exception e) {
auditStrategyClass = ReflectionTools.loadClass( auditEntCfg.getAuditStrategyName(), classLoaderService ); auditStrategyClass = ReflectionTools.loadClass(
auditEntCfg.getAuditStrategyName(),
classLoaderService
);
} }
strategy = (AuditStrategy) ReflectHelper.getDefaultConstructor(auditStrategyClass).newInstance(); strategy = (AuditStrategy) ReflectHelper.getDefaultConstructor( auditStrategyClass ).newInstance();
} }
catch ( Exception e ) { catch (Exception e) {
throw new MappingException( throw new MappingException(
String.format( "Unable to create AuditStrategy[%s] instance.", auditEntCfg.getAuditStrategyName() ), String.format( "Unable to create AuditStrategy[%s] instance.", auditEntCfg.getAuditStrategyName() ),
e e
@ -156,27 +159,25 @@ public class AuditConfiguration {
if ( strategy instanceof ValidityAuditStrategy ) { if ( strategy instanceof ValidityAuditStrategy ) {
// further initialization required // further initialization required
Getter revisionTimestampGetter = ReflectionTools.getGetter( revisionInfoClass, revisionInfoTimestampData ); final Getter revisionTimestampGetter = ReflectionTools.getGetter( revisionInfoClass, revisionInfoTimestampData );
( (ValidityAuditStrategy) strategy ).setRevisionTimestampGetter( revisionTimestampGetter ); ( (ValidityAuditStrategy) strategy ).setRevisionTimestampGetter( revisionTimestampGetter );
} }
return strategy; return strategy;
} }
// private static final Map<Configuration, AuditConfiguration> CFGS = new WeakHashMap<Configuration, AuditConfiguration>();
private static Map<Configuration, AuditConfiguration> cfgs = new WeakHashMap<Configuration, AuditConfiguration>();
public synchronized static AuditConfiguration getFor(Configuration cfg) { public synchronized static AuditConfiguration getFor(Configuration cfg) {
return getFor( cfg, null ); return getFor( cfg, null );
} }
public synchronized static AuditConfiguration getFor(Configuration cfg, ClassLoaderService classLoaderService) { public synchronized static AuditConfiguration getFor(Configuration cfg, ClassLoaderService classLoaderService) {
AuditConfiguration verCfg = cfgs.get( cfg ); AuditConfiguration verCfg = CFGS.get( cfg );
if ( verCfg == null ) { if ( verCfg == null ) {
verCfg = new AuditConfiguration( cfg, classLoaderService ); verCfg = new AuditConfiguration( cfg, classLoaderService );
cfgs.put( cfg, verCfg ); CFGS.put( cfg, verCfg );
cfg.buildMappings(); cfg.buildMappings();
} }

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.enhanced; package org.hibernate.envers.enhanced;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -8,6 +31,7 @@ import org.hibernate.internal.util.StringHelper;
/** /**
* Revision number generator has to produce values in ascending order (gaps may occur). * Revision number generator has to produce values in ascending order (gaps may occur).
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public class OrderedSequenceGenerator extends SequenceStyleGenerator { public class OrderedSequenceGenerator extends SequenceStyleGenerator {

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -23,13 +23,13 @@
*/ */
package org.hibernate.envers.enhanced; package org.hibernate.envers.enhanced;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.Date;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.Transient; import javax.persistence.Transient;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.Date;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Parameter;
@ -42,64 +42,72 @@ import org.hibernate.envers.RevisionTimestamp;
*/ */
@MappedSuperclass @MappedSuperclass
public class SequenceIdRevisionEntity implements Serializable { public class SequenceIdRevisionEntity implements Serializable {
private static final long serialVersionUID = 4159156677698841902L; private static final long serialVersionUID = 4159156677698841902L;
@Id
@GeneratedValue(generator = "RevisionNumberSequenceGenerator")
@GenericGenerator(name = "RevisionNumberSequenceGenerator",
strategy = "org.hibernate.envers.enhanced.OrderedSequenceGenerator",
parameters = {@Parameter(name = "table_name", value = "REVISION_GENERATOR"),
@Parameter(name = "sequence_name", value = "REVISION_GENERATOR"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1")
}
)
@RevisionNumber
private int id;
@RevisionTimestamp @Id
private long timestamp; @GeneratedValue(generator = "RevisionNumberSequenceGenerator")
@GenericGenerator(
name = "RevisionNumberSequenceGenerator",
strategy = "org.hibernate.envers.enhanced.OrderedSequenceGenerator",
parameters = {
@Parameter(name = "table_name", value = "REVISION_GENERATOR"),
@Parameter(name = "sequence_name", value = "REVISION_GENERATOR"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1")
}
)
@RevisionNumber
private int id;
public int getId() { @RevisionTimestamp
return id; private long timestamp;
}
public void setId(int id) { public int getId() {
this.id = id; return id;
} }
@Transient public void setId(int id) {
public Date getRevisionDate() { this.id = id;
return new Date(timestamp); }
}
public long getTimestamp() { @Transient
return timestamp; public Date getRevisionDate() {
} return new Date( timestamp );
}
public void setTimestamp(long timestamp) { public long getTimestamp() {
this.timestamp = timestamp; return timestamp;
} }
public boolean equals(Object o) { @SuppressWarnings("UnusedDeclaration")
if (this == o) return true; public void setTimestamp(long timestamp) {
if (!(o instanceof SequenceIdRevisionEntity )) return false; this.timestamp = timestamp;
}
SequenceIdRevisionEntity that = (SequenceIdRevisionEntity) o; @Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( !(o instanceof SequenceIdRevisionEntity) ) {
return false;
}
if (id != that.id) return false; final SequenceIdRevisionEntity that = (SequenceIdRevisionEntity) o;
if (timestamp != that.timestamp) return false; return id == that.id && timestamp == that.timestamp;
}
return true; @Override
} public int hashCode() {
int result = id;
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
return result;
}
public int hashCode() { @Override
int result = id; public String toString() {
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); return "SequenceIdRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(
return result; getRevisionDate()
} ) + ")";
}
public String toString() {
return "SequenceIdRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -23,14 +23,14 @@
*/ */
package org.hibernate.envers.enhanced; package org.hibernate.envers.enhanced;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.annotations.Fetch; import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.FetchMode;
@ -40,45 +40,60 @@ import org.hibernate.envers.ModifiedEntityNames;
* Extension of standard {@link SequenceIdRevisionEntity} that allows tracking entity names changed in each revision. * Extension of standard {@link SequenceIdRevisionEntity} that allows tracking entity names changed in each revision.
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision} * This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}. * parameter is set to {@code true}.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
@MappedSuperclass @MappedSuperclass
public class SequenceIdTrackingModifiedEntitiesRevisionEntity extends SequenceIdRevisionEntity { public class SequenceIdTrackingModifiedEntitiesRevisionEntity extends SequenceIdRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER) @ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV")) @JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME") @Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN) @Fetch(FetchMode.JOIN)
@ModifiedEntityNames @ModifiedEntityNames
private Set<String> modifiedEntityNames = new HashSet<String>(); private Set<String> modifiedEntityNames = new HashSet<String>();
public Set<String> getModifiedEntityNames() { @SuppressWarnings("UnusedDeclaration")
return modifiedEntityNames; public Set<String> getModifiedEntityNames() {
} return modifiedEntityNames;
}
public void setModifiedEntityNames(Set<String> modifiedEntityNames) { @SuppressWarnings("UnusedDeclaration")
this.modifiedEntityNames = modifiedEntityNames; public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
} this.modifiedEntityNames = modifiedEntityNames;
}
public boolean equals(Object o) { @Override
if (this == o) return true; public boolean equals(Object o) {
if (!(o instanceof SequenceIdTrackingModifiedEntitiesRevisionEntity )) return false; if ( this == o ) {
if (!super.equals(o)) return false; return true;
}
if ( !(o instanceof SequenceIdTrackingModifiedEntitiesRevisionEntity) ) {
return false;
}
if ( !super.equals( o ) ) {
return false;
}
SequenceIdTrackingModifiedEntitiesRevisionEntity that = (SequenceIdTrackingModifiedEntitiesRevisionEntity) o; final SequenceIdTrackingModifiedEntitiesRevisionEntity that = (SequenceIdTrackingModifiedEntitiesRevisionEntity) o;
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames) if ( modifiedEntityNames == null ) {
: that.modifiedEntityNames != null) return false; return that.modifiedEntityNames == null;
}
else {
return modifiedEntityNames.equals( that.modifiedEntityNames );
}
}
return true; @Override
} public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
return result;
}
public int hashCode() { @Override
int result = super.hashCode(); public String toString() {
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0); return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString()
return result; + ", modifiedEntityNames = " + modifiedEntityNames + ")";
} }
public String toString() {
return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
}
} }

View File

@ -57,40 +57,40 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
super( enversConfiguration ); super( enversConfiguration );
} }
protected final CollectionEntry getCollectionEntry(AbstractCollectionEvent event) { protected final CollectionEntry getCollectionEntry(AbstractCollectionEvent event) {
return event.getSession().getPersistenceContext().getCollectionEntry(event.getCollection()); return event.getSession().getPersistenceContext().getCollectionEntry( event.getCollection() );
} }
protected final void onCollectionAction( protected final void onCollectionAction(
AbstractCollectionEvent event, AbstractCollectionEvent event,
PersistentCollection newColl, PersistentCollection newColl,
Serializable oldColl, Serializable oldColl,
CollectionEntry collectionEntry) { CollectionEntry collectionEntry) {
if ( shouldGenerateRevision( event ) ) { if ( shouldGenerateRevision( event ) ) {
checkIfTransactionInProgress(event.getSession()); checkIfTransactionInProgress( event.getSession() );
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
String entityName = event.getAffectedOwnerEntityName(); final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
String referencingPropertyName = collectionEntry.getRole().substring(ownerEntityName.length() + 1);
// Checking if this is not a "fake" many-to-one bidirectional relation. The relation description may be final String entityName = event.getAffectedOwnerEntityName();
// null in case of collections of non-entities. final String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
RelationDescription rd = searchForRelationDescription( entityName, referencingPropertyName ); final String referencingPropertyName = collectionEntry.getRole().substring( ownerEntityName.length() + 1 );
if ( rd != null && rd.getMappedByPropertyName() != null ) {
generateFakeBidirecationalRelationWorkUnits( // Checking if this is not a "fake" many-to-one bidirectional relation. The relation description may be
// null in case of collections of non-entities.
final RelationDescription rd = searchForRelationDescription( entityName, referencingPropertyName );
if ( rd != null && rd.getMappedByPropertyName() != null ) {
generateFakeBidirecationalRelationWorkUnits(
auditProcess, auditProcess,
newColl, newColl,
oldColl, oldColl,
entityName, entityName,
referencingPropertyName, referencingPropertyName,
event, event,
rd rd
); );
} }
else { else {
PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit( final PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(
event.getSession(), event.getSession(),
entityName, entityName,
getAuditConfiguration(), getAuditConfiguration(),
@ -102,9 +102,9 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
); );
auditProcess.addWorkUnit( workUnit ); auditProcess.addWorkUnit( workUnit );
if (workUnit.containsWork()) { if ( workUnit.containsWork() ) {
// There are some changes: a revision needs also be generated for the collection owner // There are some changes: a revision needs also be generated for the collection owner
auditProcess.addWorkUnit( auditProcess.addWorkUnit(
new CollectionChangeWorkUnit( new CollectionChangeWorkUnit(
event.getSession(), event.getSession(),
event.getAffectedOwnerEntityName(), event.getAffectedOwnerEntityName(),
@ -115,15 +115,17 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
) )
); );
generateBidirectionalCollectionChangeWorkUnits( auditProcess, event, workUnit, rd ); generateBidirectionalCollectionChangeWorkUnits( auditProcess, event, workUnit, rd );
} }
} }
} }
} }
/** /**
* Forces persistent collection initialization. * Forces persistent collection initialization.
*
* @param event Collection event. * @param event Collection event.
*
* @return Stored snapshot. * @return Stored snapshot.
*/ */
protected Serializable initializeCollection(AbstractCollectionEvent event) { protected Serializable initializeCollection(AbstractCollectionEvent event) {
@ -133,7 +135,9 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
/** /**
* Checks whether modification of not-owned relation field triggers new revision and owner entity is versioned. * Checks whether modification of not-owned relation field triggers new revision and owner entity is versioned.
*
* @param event Collection event. * @param event Collection event.
*
* @return {@code true} if revision based on given event should be generated, {@code false} otherwise. * @return {@code true} if revision based on given event should be generated, {@code false} otherwise.
*/ */
protected boolean shouldGenerateRevision(AbstractCollectionEvent event) { protected boolean shouldGenerateRevision(AbstractCollectionEvent event) {
@ -142,27 +146,27 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
&& getAuditConfiguration().getEntCfg().isVersioned( entityName ); && getAuditConfiguration().getEntCfg().isVersioned( entityName );
} }
/** /**
* Looks up a relation description corresponding to the given property in the given entity. If no description is * Looks up a relation description corresponding to the given property in the given entity. If no description is
* found in the given entity, the parent entity is checked (so that inherited relations work). * found in the given entity, the parent entity is checked (so that inherited relations work).
* *
* @param entityName Name of the entity, in which to start looking. * @param entityName Name of the entity, in which to start looking.
* @param referencingPropertyName The name of the property. * @param referencingPropertyName The name of the property.
* *
* @return A found relation description corresponding to the given entity or {@code null}, if no description can * @return A found relation description corresponding to the given entity or {@code null}, if no description can
* be found. * be found.
*/ */
private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) { private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) {
EntityConfiguration configuration = getAuditConfiguration().getEntCfg().get( entityName ); final EntityConfiguration configuration = getAuditConfiguration().getEntCfg().get( entityName );
RelationDescription rd = configuration.getRelationDescription(referencingPropertyName); final RelationDescription rd = configuration.getRelationDescription( referencingPropertyName );
if ( rd == null && configuration.getParentEntityName() != null ) { if ( rd == null && configuration.getParentEntityName() != null ) {
return searchForRelationDescription( configuration.getParentEntityName(), referencingPropertyName ); return searchForRelationDescription( configuration.getParentEntityName(), referencingPropertyName );
} }
return rd; return rd;
} }
private void generateFakeBidirecationalRelationWorkUnits( private void generateFakeBidirecationalRelationWorkUnits(
AuditProcess auditProcess, AuditProcess auditProcess,
PersistentCollection newColl, PersistentCollection newColl,
Serializable oldColl, Serializable oldColl,
@ -170,41 +174,47 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
String referencingPropertyName, String referencingPropertyName,
AbstractCollectionEvent event, AbstractCollectionEvent event,
RelationDescription rd) { RelationDescription rd) {
// First computing the relation changes // First computing the relation changes
List<PersistentCollectionChangeData> collectionChanges = getAuditConfiguration() final List<PersistentCollectionChangeData> collectionChanges = getAuditConfiguration()
.getEntCfg() .getEntCfg()
.get( collectionEntityName ) .get( collectionEntityName )
.getPropertyMapper() .getPropertyMapper()
.mapCollectionChanges( event.getSession(), referencingPropertyName, newColl, oldColl, event.getAffectedOwnerIdOrNull() ); .mapCollectionChanges(
event.getSession(),
referencingPropertyName,
newColl,
oldColl,
event.getAffectedOwnerIdOrNull()
);
// Getting the id mapper for the related entity, as the work units generated will corrspond to the related // Getting the id mapper for the related entity, as the work units generated will correspond to the related
// entities. // entities.
String relatedEntityName = rd.getToEntityName(); final String relatedEntityName = rd.getToEntityName();
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get(relatedEntityName).getIdMapper(); final IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
// For each collection change, generating the bidirectional work unit. // For each collection change, generating the bidirectional work unit.
for ( PersistentCollectionChangeData changeData : collectionChanges ) { for ( PersistentCollectionChangeData changeData : collectionChanges ) {
Object relatedObj = changeData.getChangedElement(); final Object relatedObj = changeData.getChangedElement();
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity(relatedObj); final Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
RevisionType revType = (RevisionType) changeData.getData().get( final RevisionType revType = (RevisionType) changeData.getData().get(
getAuditConfiguration().getAuditEntCfg().getRevisionTypePropName() getAuditConfiguration().getAuditEntCfg().getRevisionTypePropName()
); );
// This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass // This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass
// of relatedEntityName). // of relatedEntityName).
String realRelatedEntityName = event.getSession().bestGuessEntityName(relatedObj); final String realRelatedEntityName = event.getSession().bestGuessEntityName( relatedObj );
// By default, the nested work unit is a collection change work unit. // By default, the nested work unit is a collection change work unit.
AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit( final AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
event.getSession(), event.getSession(),
realRelatedEntityName, realRelatedEntityName,
rd.getMappedByPropertyName(), rd.getMappedByPropertyName(),
getAuditConfiguration(), getAuditConfiguration(),
relatedId, relatedId,
relatedObj relatedObj
); );
auditProcess.addWorkUnit( auditProcess.addWorkUnit(
new FakeBidirectionalRelationWorkUnit( new FakeBidirectionalRelationWorkUnit(
event.getSession(), event.getSession(),
realRelatedEntityName, realRelatedEntityName,
@ -218,10 +228,10 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
nestedWorkUnit nestedWorkUnit
) )
); );
} }
// We also have to generate a collection change work unit for the owning entity. // We also have to generate a collection change work unit for the owning entity.
auditProcess.addWorkUnit( auditProcess.addWorkUnit(
new CollectionChangeWorkUnit( new CollectionChangeWorkUnit(
event.getSession(), event.getSession(),
collectionEntityName, collectionEntityName,
@ -231,44 +241,47 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
event.getAffectedOwnerOrNull() event.getAffectedOwnerOrNull()
) )
); );
} }
private void generateBidirectionalCollectionChangeWorkUnits( private void generateBidirectionalCollectionChangeWorkUnits(
AuditProcess auditProcess, AuditProcess auditProcess,
AbstractCollectionEvent event, AbstractCollectionEvent event,
PersistentCollectionChangeWorkUnit workUnit, PersistentCollectionChangeWorkUnit workUnit,
RelationDescription rd) { RelationDescription rd) {
// Checking if this is enabled in configuration ... // Checking if this is enabled in configuration ...
if ( ! getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections() ) { if ( !getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections() ) {
return; return;
} }
// Checking if this is not a bidirectional relation - then, a revision needs also be generated for // Checking if this is not a bidirectional relation - then, a revision needs also be generated for
// the other side of the relation. // the other side of the relation.
// relDesc can be null if this is a collection of simple values (not a relation). // relDesc can be null if this is a collection of simple values (not a relation).
if ( rd != null && rd.isBidirectional() ) { if ( rd != null && rd.isBidirectional() ) {
String relatedEntityName = rd.getToEntityName(); final String relatedEntityName = rd.getToEntityName();
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper(); final IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
Set<String> toPropertyNames = getAuditConfiguration().getEntCfg() final Set<String> toPropertyNames = getAuditConfiguration().getEntCfg().getToPropertyNames(
.getToPropertyNames(event.getAffectedOwnerEntityName(), rd.getFromPropertyName(), relatedEntityName); event.getAffectedOwnerEntityName(),
String toPropertyName = toPropertyNames.iterator().next(); rd.getFromPropertyName(),
relatedEntityName
);
final String toPropertyName = toPropertyNames.iterator().next();
for ( PersistentCollectionChangeData changeData : workUnit.getCollectionChanges() ) { for ( PersistentCollectionChangeData changeData : workUnit.getCollectionChanges() ) {
Object relatedObj = changeData.getChangedElement(); final Object relatedObj = changeData.getChangedElement();
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj ); final Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
auditProcess.addWorkUnit( auditProcess.addWorkUnit(
new CollectionChangeWorkUnit( new CollectionChangeWorkUnit(
event.getSession(), event.getSession(),
event.getSession().bestGuessEntityName(relatedObj), event.getSession().bestGuessEntityName( relatedObj ),
toPropertyName, toPropertyName,
getAuditConfiguration(), getAuditConfiguration(),
relatedId, relatedId,
relatedObj relatedObj
) )
); );
} }
} }
} }
} }

View File

@ -66,72 +66,84 @@ public abstract class BaseEnversEventListener implements EnversListener {
Object[] oldState, Object[] oldState,
SessionImplementor session) { SessionImplementor session) {
// Checking if this is enabled in configuration ... // Checking if this is enabled in configuration ...
if ( ! enversConfiguration.getGlobalCfg().isGenerateRevisionsForCollections() ) { if ( !enversConfiguration.getGlobalCfg().isGenerateRevisionsForCollections() ) {
return; return;
} }
// Checks every property of the entity, if it is an "owned" to-one relation to another entity. // Checks every property of the entity, if it is an "owned" to-one relation to another entity.
// If the value of that property changed, and the relation is bi-directional, a new revision // If the value of that property changed, and the relation is bi-directional, a new revision
// for the related entity is generated. // for the related entity is generated.
String[] propertyNames = entityPersister.getPropertyNames(); final String[] propertyNames = entityPersister.getPropertyNames();
for ( int i=0; i<propertyNames.length; i++ ) { for ( int i = 0; i < propertyNames.length; i++ ) {
String propertyName = propertyNames[i]; final String propertyName = propertyNames[i];
RelationDescription relDesc = enversConfiguration.getEntCfg().getRelationDescription(entityName, propertyName); final RelationDescription relDesc = enversConfiguration.getEntCfg().getRelationDescription(
if (relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE && entityName,
relDesc.isInsertable()) { propertyName
);
if ( relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE &&
relDesc.isInsertable() ) {
// Checking for changes // Checking for changes
Object oldValue = oldState == null ? null : oldState[i]; final Object oldValue = oldState == null ? null : oldState[i];
Object newValue = newState == null ? null : newState[i]; final Object newValue = newState == null ? null : newState[i];
if (!EntityTools.entitiesEqual( session, relDesc.getToEntityName(), oldValue, newValue )) { if ( !EntityTools.entitiesEqual( session, relDesc.getToEntityName(), oldValue, newValue ) ) {
// We have to generate changes both in the old collection (size decreses) and new collection // We have to generate changes both in the old collection (size decreses) and new collection
// (size increases). // (size increases).
if (newValue != null) { if ( newValue != null ) {
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, newValue); addCollectionChangeWorkUnit( auditProcess, session, entityName, relDesc, newValue );
} }
if (oldValue != null) { if ( oldValue != null ) {
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, oldValue); addCollectionChangeWorkUnit( auditProcess, session, entityName, relDesc, oldValue );
} }
} }
} }
} }
} }
private void addCollectionChangeWorkUnit(AuditProcess auditProcess, SessionImplementor session, private void addCollectionChangeWorkUnit(
String fromEntityName, RelationDescription relDesc, Object value) { AuditProcess auditProcess, SessionImplementor session,
String fromEntityName, RelationDescription relDesc, Object value) {
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case // relDesc.getToEntityName() doesn't always return the entity name of the value - in case
// of subclasses, this will be root class, no the actual class. So it can't be used here. // of subclasses, this will be root class, no the actual class. So it can't be used here.
String toEntityName; String toEntityName;
Serializable id; Serializable id;
if (value instanceof HibernateProxy) { if ( value instanceof HibernateProxy ) {
HibernateProxy hibernateProxy = (HibernateProxy) value; final HibernateProxy hibernateProxy = (HibernateProxy) value;
toEntityName = session.bestGuessEntityName(value); toEntityName = session.bestGuessEntityName( value );
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier(); id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
// We've got to initialize the object from the proxy to later read its state. // We've got to initialize the object from the proxy to later read its state.
value = EntityTools.getTargetFromProxy(session.getFactory(), hibernateProxy); value = EntityTools.getTargetFromProxy( session.getFactory(), hibernateProxy );
} else { }
toEntityName = session.guessEntityName(value); else {
toEntityName = session.guessEntityName( value );
IdMapper idMapper = enversConfiguration.getEntCfg().get(toEntityName).getIdMapper(); final IdMapper idMapper = enversConfiguration.getEntCfg().get( toEntityName ).getIdMapper();
id = (Serializable) idMapper.mapToIdFromEntity(value); id = (Serializable) idMapper.mapToIdFromEntity( value );
} }
Set<String> toPropertyNames = enversConfiguration.getEntCfg() final Set<String> toPropertyNames = enversConfiguration.getEntCfg().getToPropertyNames(
.getToPropertyNames(fromEntityName, relDesc.getFromPropertyName(), toEntityName); fromEntityName,
String toPropertyName = toPropertyNames.iterator().next(); relDesc.getFromPropertyName(),
toEntityName
);
final String toPropertyName = toPropertyNames.iterator().next();
auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, auditProcess.addWorkUnit(
toPropertyName, enversConfiguration, id, value)); new CollectionChangeWorkUnit(
session, toEntityName,
toPropertyName, enversConfiguration, id, value
)
);
} }
protected void checkIfTransactionInProgress(SessionImplementor session) { protected void checkIfTransactionInProgress(SessionImplementor session) {
if (!session.isTransactionInProgress()) { if ( !session.isTransactionInProgress() ) {
// Historical data would not be flushed to audit tables if outside of active transaction // Historical data would not be flushed to audit tables if outside of active transaction
// (AuditProcess#doBeforeTransactionCompletion(SessionImplementor) not executed). // (AuditProcess#doBeforeTransactionCompletion(SessionImplementor) not executed).
throw new AuditException("Unable to create revision because of non-active transaction"); throw new AuditException( "Unable to create revision because of non-active transaction" );
} }
} }
} }

View File

@ -43,8 +43,15 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistry;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EnversIntegrator implements Integrator { public class EnversIntegrator implements Integrator {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, EnversIntegrator.class.getName() ); private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
EnversIntegrator.class.getName()
);
/**
* The name of a configuration setting that can be used to control whether auto registration of envers listeners
* should happen or not. Default is true
*/
public static final String AUTO_REGISTER = "hibernate.listeners.envers.autoRegister"; public static final String AUTO_REGISTER = "hibernate.listeners.envers.autoRegister";
@Override @Override
@ -52,25 +59,55 @@ public class EnversIntegrator implements Integrator {
Configuration configuration, Configuration configuration,
SessionFactoryImplementor sessionFactory, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) { SessionFactoryServiceRegistry serviceRegistry) {
final boolean autoRegister = ConfigurationHelper.getBoolean( AUTO_REGISTER, configuration.getProperties(), true ); final boolean autoRegister = ConfigurationHelper.getBoolean(
AUTO_REGISTER,
configuration.getProperties(),
true
);
if ( !autoRegister ) { if ( !autoRegister ) {
LOG.debug( "Skipping Envers listener auto registration" ); LOG.debug( "Skipping Envers listener auto registration" );
return; return;
} }
EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class ); final EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
listenerRegistry.addDuplicationStrategy( EnversListenerDuplicationStrategy.INSTANCE ); listenerRegistry.addDuplicationStrategy( EnversListenerDuplicationStrategy.INSTANCE );
final AuditConfiguration enversConfiguration = AuditConfiguration.getFor( configuration, serviceRegistry.getService( ClassLoaderService.class ) ); final AuditConfiguration enversConfiguration = AuditConfiguration.getFor(
configuration,
serviceRegistry.getService(
ClassLoaderService.class
)
);
if (enversConfiguration.getEntCfg().hasAuditedEntities()) { if ( enversConfiguration.getEntCfg().hasAuditedEntities() ) {
listenerRegistry.appendListeners( EventType.POST_DELETE, new EnversPostDeleteEventListenerImpl( enversConfiguration ) ); listenerRegistry.appendListeners(
listenerRegistry.appendListeners( EventType.POST_INSERT, new EnversPostInsertEventListenerImpl( enversConfiguration ) ); EventType.POST_DELETE, new EnversPostDeleteEventListenerImpl(
listenerRegistry.appendListeners( EventType.POST_UPDATE, new EnversPostUpdateEventListenerImpl( enversConfiguration ) ); enversConfiguration
listenerRegistry.appendListeners( EventType.POST_COLLECTION_RECREATE, new EnversPostCollectionRecreateEventListenerImpl( enversConfiguration ) ); )
listenerRegistry.appendListeners( EventType.PRE_COLLECTION_REMOVE, new EnversPreCollectionRemoveEventListenerImpl( enversConfiguration ) ); );
listenerRegistry.appendListeners( EventType.PRE_COLLECTION_UPDATE, new EnversPreCollectionUpdateEventListenerImpl( enversConfiguration ) ); listenerRegistry.appendListeners(
} EventType.POST_INSERT, new EnversPostInsertEventListenerImpl(
enversConfiguration
)
);
listenerRegistry.appendListeners(
EventType.POST_UPDATE, new EnversPostUpdateEventListenerImpl(
enversConfiguration
)
);
listenerRegistry.appendListeners(
EventType.POST_COLLECTION_RECREATE,
new EnversPostCollectionRecreateEventListenerImpl( enversConfiguration )
);
listenerRegistry.appendListeners(
EventType.PRE_COLLECTION_REMOVE,
new EnversPreCollectionRemoveEventListenerImpl( enversConfiguration )
);
listenerRegistry.appendListeners(
EventType.PRE_COLLECTION_UPDATE,
new EnversPreCollectionUpdateEventListenerImpl( enversConfiguration )
);
}
} }
@Override @Override
@ -84,9 +121,10 @@ public class EnversIntegrator implements Integrator {
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry) * @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry)
*/ */
@Override @Override
public void integrate( MetadataImplementor metadata, public void integrate(
SessionFactoryImplementor sessionFactory, MetadataImplementor metadata,
SessionFactoryServiceRegistry serviceRegistry ) { SessionFactoryImplementor sessionFactory,
// TODO: implement SessionFactoryServiceRegistry serviceRegistry) {
// TODO: implement
} }
} }

View File

@ -31,5 +31,10 @@ import org.hibernate.envers.configuration.spi.AuditConfiguration;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface EnversListener { public interface EnversListener {
/**
* Get the Envers AuditConfiguration
*
* @return The Envers AuditConfiguration
*/
public AuditConfiguration getAuditConfiguration(); public AuditConfiguration getAuditConfiguration();
} }

View File

@ -31,6 +31,9 @@ import org.hibernate.event.service.spi.DuplicationStrategy;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EnversListenerDuplicationStrategy implements DuplicationStrategy { public class EnversListenerDuplicationStrategy implements DuplicationStrategy {
/**
* Singleton access
*/
public static final EnversListenerDuplicationStrategy INSTANCE = new EnversListenerDuplicationStrategy(); public static final EnversListenerDuplicationStrategy INSTANCE = new EnversListenerDuplicationStrategy();
@Override @Override

View File

@ -29,12 +29,14 @@ import org.hibernate.event.spi.PostCollectionRecreateEvent;
import org.hibernate.event.spi.PostCollectionRecreateEventListener; import org.hibernate.event.spi.PostCollectionRecreateEventListener;
/** /**
* Envers-specific collection recreation event listener
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EnversPostCollectionRecreateEventListenerImpl public class EnversPostCollectionRecreateEventListenerImpl
extends BaseEnversCollectionEventListener extends BaseEnversCollectionEventListener
implements PostCollectionRecreateEventListener { implements PostCollectionRecreateEventListener {
protected EnversPostCollectionRecreateEventListenerImpl(AuditConfiguration enversConfiguration) { protected EnversPostCollectionRecreateEventListenerImpl(AuditConfiguration enversConfiguration) {
@ -43,9 +45,9 @@ public class EnversPostCollectionRecreateEventListenerImpl
@Override @Override
public void onPostRecreateCollection(PostCollectionRecreateEvent event) { public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
CollectionEntry collectionEntry = getCollectionEntry( event ); final CollectionEntry collectionEntry = getCollectionEntry( event );
if ( ! collectionEntry.getLoadedPersister().isInverse() ) { if ( !collectionEntry.getLoadedPersister().isInverse() ) {
onCollectionAction( event, event.getCollection(), null, collectionEntry ); onCollectionAction( event, event.getCollection(), null, collectionEntry );
} }
} }
} }

View File

@ -32,6 +32,8 @@ import org.hibernate.event.spi.PostDeleteEventListener;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
* Envers-specific entity (post) deletion event listener
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
* @author Steve Ebersole * @author Steve Ebersole
@ -43,30 +45,30 @@ public class EnversPostDeleteEventListenerImpl extends BaseEnversEventListener i
@Override @Override
public void onPostDelete(PostDeleteEvent event) { public void onPostDelete(PostDeleteEvent event) {
String entityName = event.getPersister().getEntityName(); final String entityName = event.getPersister().getEntityName();
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) { if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
checkIfTransactionInProgress(event.getSession()); checkIfTransactionInProgress( event.getSession() );
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() ); final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
AuditWorkUnit workUnit = new DelWorkUnit( final AuditWorkUnit workUnit = new DelWorkUnit(
event.getSession(), event.getSession(),
event.getPersister().getEntityName(), event.getPersister().getEntityName(),
getAuditConfiguration(), getAuditConfiguration(),
event.getId(), event.getId(),
event.getPersister(), event.getPersister(),
event.getDeletedState() event.getDeletedState()
); );
auditProcess.addWorkUnit( workUnit ); auditProcess.addWorkUnit( workUnit );
if ( workUnit.containsWork() ) { if ( workUnit.containsWork() ) {
generateBidirectionalCollectionChangeWorkUnits( generateBidirectionalCollectionChangeWorkUnits(
auditProcess, auditProcess,
event.getPersister(), event.getPersister(),
entityName, entityName,
null, null,
event.getDeletedState(), event.getDeletedState(),
event.getSession() event.getSession()
); );
} }

View File

@ -32,44 +32,47 @@ import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
* Envers-specific entity (post) insertion event listener
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EnversPostInsertEventListenerImpl extends BaseEnversEventListener implements PostInsertEventListener { public class EnversPostInsertEventListenerImpl extends BaseEnversEventListener implements PostInsertEventListener {
public EnversPostInsertEventListenerImpl(AuditConfiguration enversConfiguration) { protected EnversPostInsertEventListenerImpl(AuditConfiguration enversConfiguration) {
super( enversConfiguration ); super( enversConfiguration );
} }
public void onPostInsert(PostInsertEvent event) { @Override
String entityName = event.getPersister().getEntityName(); public void onPostInsert(PostInsertEvent event) {
final String entityName = event.getPersister().getEntityName();
if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) { if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
checkIfTransactionInProgress(event.getSession()); checkIfTransactionInProgress( event.getSession() );
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession()); final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
AuditWorkUnit workUnit = new AddWorkUnit( final AuditWorkUnit workUnit = new AddWorkUnit(
event.getSession(), event.getSession(),
event.getPersister().getEntityName(), event.getPersister().getEntityName(),
getAuditConfiguration(), getAuditConfiguration(),
event.getId(), event.getId(),
event.getPersister(), event.getPersister(),
event.getState() event.getState()
); );
auditProcess.addWorkUnit( workUnit ); auditProcess.addWorkUnit( workUnit );
if ( workUnit.containsWork() ) { if ( workUnit.containsWork() ) {
generateBidirectionalCollectionChangeWorkUnits( generateBidirectionalCollectionChangeWorkUnits(
auditProcess, auditProcess,
event.getPersister(), event.getPersister(),
entityName, entityName,
event.getState(), event.getState(),
null, null,
event.getSession() event.getSession()
); );
} }
} }
} }
@Override @Override

View File

@ -32,6 +32,8 @@ import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
* Envers-specific entity (post) update event listener
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
* @author Steve Ebersole * @author Steve Ebersole
@ -43,43 +45,41 @@ public class EnversPostUpdateEventListenerImpl extends BaseEnversEventListener i
@Override @Override
public void onPostUpdate(PostUpdateEvent event) { public void onPostUpdate(PostUpdateEvent event) {
String entityName = event.getPersister().getEntityName(); final String entityName = event.getPersister().getEntityName();
if ( getAuditConfiguration().getEntCfg().isVersioned(entityName) ) { if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
checkIfTransactionInProgress(event.getSession()); checkIfTransactionInProgress( event.getSession() );
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
final Object[] newDbState = postUpdateDBState( event ); final Object[] newDbState = postUpdateDBState( event );
final AuditWorkUnit workUnit = new ModWorkUnit(
AuditWorkUnit workUnit = new ModWorkUnit(
event.getSession(), event.getSession(),
event.getPersister().getEntityName(), event.getPersister().getEntityName(),
getAuditConfiguration(), getAuditConfiguration(),
event.getId(), event.getId(),
event.getPersister(), event.getPersister(),
newDbState, newDbState,
event.getOldState() event.getOldState()
); );
auditProcess.addWorkUnit( workUnit ); auditProcess.addWorkUnit( workUnit );
if ( workUnit.containsWork() ) { if ( workUnit.containsWork() ) {
generateBidirectionalCollectionChangeWorkUnits( generateBidirectionalCollectionChangeWorkUnits(
auditProcess, auditProcess,
event.getPersister(), event.getPersister(),
entityName, entityName,
newDbState, newDbState,
event.getOldState(), event.getOldState(),
event.getSession() event.getSession()
); );
} }
} }
} }
private Object[] postUpdateDBState(PostUpdateEvent event) { private Object[] postUpdateDBState(PostUpdateEvent event) {
Object[] newDbState = event.getState().clone(); final Object[] newDbState = event.getState().clone();
if ( event.getOldState() != null ) { if ( event.getOldState() != null ) {
EntityPersister entityPersister = event.getPersister(); final EntityPersister entityPersister = event.getPersister();
for ( int i = 0; i < entityPersister.getPropertyNames().length; ++i ) { for ( int i = 0; i < entityPersister.getPropertyNames().length; ++i ) {
if ( !entityPersister.getPropertyUpdateability()[i] ) { if ( !entityPersister.getPropertyUpdateability()[i] ) {
// Assuming that PostUpdateEvent#getOldState() returns database state of the record before modification. // Assuming that PostUpdateEvent#getOldState() returns database state of the record before modification.

View File

@ -31,6 +31,8 @@ import org.hibernate.event.spi.PreCollectionRemoveEvent;
import org.hibernate.event.spi.PreCollectionRemoveEventListener; import org.hibernate.event.spi.PreCollectionRemoveEventListener;
/** /**
* Envers-specific collection removal event listener
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
* @author Steve Ebersole * @author Steve Ebersole
@ -46,14 +48,14 @@ public class EnversPreCollectionRemoveEventListenerImpl
@Override @Override
public void onPreRemoveCollection(PreCollectionRemoveEvent event) { public void onPreRemoveCollection(PreCollectionRemoveEvent event) {
CollectionEntry collectionEntry = getCollectionEntry( event ); final CollectionEntry collectionEntry = getCollectionEntry( event );
if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) { if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) {
Serializable oldColl = collectionEntry.getSnapshot(); Serializable oldColl = collectionEntry.getSnapshot();
if ( !event.getCollection().wasInitialized() && shouldGenerateRevision( event ) ) { if ( !event.getCollection().wasInitialized() && shouldGenerateRevision( event ) ) {
// In case of uninitialized collection we need a fresh snapshot to properly calculate audit data. // In case of uninitialized collection we need a fresh snapshot to properly calculate audit data.
oldColl = initializeCollection( event ); oldColl = initializeCollection( event );
} }
onCollectionAction( event, null, oldColl, collectionEntry ); onCollectionAction( event, null, oldColl, collectionEntry );
} }
} }
} }

View File

@ -29,6 +29,8 @@ import org.hibernate.event.spi.PreCollectionUpdateEvent;
import org.hibernate.event.spi.PreCollectionUpdateEventListener; import org.hibernate.event.spi.PreCollectionUpdateEventListener;
/** /**
* Envers-specific collection update event listener
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
* @author Steve Ebersole * @author Steve Ebersole
@ -43,9 +45,9 @@ public class EnversPreCollectionUpdateEventListenerImpl
@Override @Override
public void onPreUpdateCollection(PreCollectionUpdateEvent event) { public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
CollectionEntry collectionEntry = getCollectionEntry( event ); final CollectionEntry collectionEntry = getCollectionEntry( event );
if ( ! collectionEntry.getLoadedPersister().isInverse() ) { if ( !collectionEntry.getLoadedPersister().isInverse() ) {
onCollectionAction( event, event.getCollection(), collectionEntry.getSnapshot(), collectionEntry ); onCollectionAction( event, event.getCollection(), collectionEntry.getSnapshot(), collectionEntry );
} }
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.exception; package org.hibernate.envers.exception;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
/** /**
@ -31,14 +32,14 @@ public class AuditException extends HibernateException {
private static final long serialVersionUID = 4306480965630972168L; private static final long serialVersionUID = 4306480965630972168L;
public AuditException(String message) { public AuditException(String message) {
super(message); super( message );
} }
public AuditException(String message, Throwable cause) { public AuditException(String message, Throwable cause) {
super(message, cause); super( message, cause );
} }
public AuditException(Throwable cause) { public AuditException(Throwable cause) {
super(cause); super( cause );
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -29,15 +29,15 @@ package org.hibernate.envers.exception;
*/ */
public class NotAuditedException extends AuditException { public class NotAuditedException extends AuditException {
private static final long serialVersionUID = 4809674577449455510L; private static final long serialVersionUID = 4809674577449455510L;
private final String entityName; private final String entityName;
public NotAuditedException(String entityName, String message) { public NotAuditedException(String entityName, String message) {
super(message); super( message );
this.entityName = entityName; this.entityName = entityName;
} }
public String getEntityName() { public String getEntityName() {
return entityName; return entityName;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.exception; package org.hibernate.envers.exception;
import java.util.Date; import java.util.Date;
/** /**
@ -29,25 +30,27 @@ import java.util.Date;
*/ */
public class RevisionDoesNotExistException extends AuditException { public class RevisionDoesNotExistException extends AuditException {
private static final long serialVersionUID = -6417768274074962282L; private static final long serialVersionUID = -6417768274074962282L;
private Number revision; private final Number revision;
private Date date; private final Date date;
public RevisionDoesNotExistException(Number revision) { public RevisionDoesNotExistException(Number revision) {
super("Revision " + revision + " does not exist."); super( "Revision " + revision + " does not exist." );
this.revision = revision; this.revision = revision;
} this.date = null;
}
public RevisionDoesNotExistException(Date date) { public RevisionDoesNotExistException(Date date) {
super("There is no revision before or at " + date + "."); super( "There is no revision before or at " + date + "." );
this.date = date; this.date = date;
} this.revision = null;
}
public Number getRevision() { public Number getRevision() {
return revision; return revision;
} }
public Date getDate() { public Date getDate() {
return date; return date;
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -37,10 +37,13 @@ import static org.jboss.logging.Logger.Level.WARN;
* <p/> * <p/>
* New messages must be added after the last message defined to ensure message codes are unique. * New messages must be added after the last message defined to ensure message codes are unique.
*/ */
@MessageLogger( projectCode = "HHH" ) @MessageLogger(projectCode = "HHH")
public interface EnversMessageLogger extends CoreMessageLogger { public interface EnversMessageLogger extends CoreMessageLogger {
@LogMessage( level = WARN ) /**
@Message( value = "ValidTimeAuditStrategy is deprecated, please use ValidityAuditStrategy instead", id = 25001 ) * Message indicating that user attempted to use the deprecated ValidTimeAuditStrategy
void validTimeAuditStrategyDeprecated(); */
@LogMessage(level = WARN)
@Message(value = "ValidTimeAuditStrategy is deprecated, please use ValidityAuditStrategy instead", id = 25001)
void validTimeAuditStrategyDeprecated();
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities; package org.hibernate.envers.internal.entities;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -31,129 +32,136 @@ import java.util.Set;
/** /**
* Configuration of the user entities: property mapping of the entities, relations, inheritance. * Configuration of the user entities: property mapping of the entities, relations, inheritance.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Hern&aacute;n Chanfreau * @author Hern&aacute;n Chanfreau
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public class EntitiesConfigurations { public class EntitiesConfigurations {
private Map<String, EntityConfiguration> entitiesConfigurations; private Map<String, EntityConfiguration> entitiesConfigurations;
private Map<String, EntityConfiguration> notAuditedEntitiesConfigurations; private Map<String, EntityConfiguration> notAuditedEntitiesConfigurations;
// Map versions entity name -> entity name // Map versions entity name -> entity name
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>(); private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
public EntitiesConfigurations(Map<String, EntityConfiguration> entitiesConfigurations, public EntitiesConfigurations(
Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) { Map<String, EntityConfiguration> entitiesConfigurations,
this.entitiesConfigurations = entitiesConfigurations; Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) {
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations; this.entitiesConfigurations = entitiesConfigurations;
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
generateBidirectionRelationInfo(); generateBidirectionRelationInfo();
generateVersionsEntityToEntityNames(); generateVersionsEntityToEntityNames();
} }
private void generateVersionsEntityToEntityNames() { private void generateVersionsEntityToEntityNames() {
entityNamesForVersionsEntityNames = new HashMap<String, String>(); entityNamesForVersionsEntityNames = new HashMap<String, String>();
for (String entityName : entitiesConfigurations.keySet()) { for ( String entityName : entitiesConfigurations.keySet() ) {
entityNamesForVersionsEntityNames.put(entitiesConfigurations.get(entityName).getVersionsEntityName(), entityNamesForVersionsEntityNames.put(
entityName); entitiesConfigurations.get( entityName ).getVersionsEntityName(),
} entityName
} );
}
}
private void generateBidirectionRelationInfo() { private void generateBidirectionRelationInfo() {
// Checking each relation if it is bidirectional. If so, storing that information. // Checking each relation if it is bidirectional. If so, storing that information.
for (String entityName : entitiesConfigurations.keySet()) { for ( String entityName : entitiesConfigurations.keySet() ) {
EntityConfiguration entCfg = entitiesConfigurations.get(entityName); final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
// Iterating over all relations from that entity // Iterating over all relations from that entity
for (RelationDescription relDesc : entCfg.getRelationsIterator()) { for ( RelationDescription relDesc : entCfg.getRelationsIterator() ) {
// If this is an "owned" relation, checking the related entity, if it has a relation that has // If this is an "owned" relation, checking the related entity, if it has a relation that has
// a mapped-by attribute to the currently checked. If so, this is a bidirectional relation. // a mapped-by attribute to the currently checked. If so, this is a bidirectional relation.
if (relDesc.getRelationType() == RelationType.TO_ONE || if ( relDesc.getRelationType() == RelationType.TO_ONE ||
relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) { relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE ) {
EntityConfiguration entityConfiguration = entitiesConfigurations.get(relDesc.getToEntityName()); final EntityConfiguration entityConfiguration = entitiesConfigurations.get( relDesc.getToEntityName() );
if (entityConfiguration != null) { if ( entityConfiguration != null ) {
for (RelationDescription other : entityConfiguration.getRelationsIterator()) { for ( RelationDescription other : entityConfiguration.getRelationsIterator() ) {
if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) && if ( relDesc.getFromPropertyName().equals( other.getMappedByPropertyName() ) &&
(entityName.equals(other.getToEntityName()))) { (entityName.equals( other.getToEntityName() )) ) {
relDesc.setBidirectional(true); relDesc.setBidirectional( true );
other.setBidirectional(true); other.setBidirectional( true );
} }
} }
} }
} }
} }
} }
} }
public EntityConfiguration get(String entityName) { public EntityConfiguration get(String entityName) {
return entitiesConfigurations.get(entityName); return entitiesConfigurations.get( entityName );
} }
public EntityConfiguration getNotVersionEntityConfiguration(String entityName) { public EntityConfiguration getNotVersionEntityConfiguration(String entityName) {
return notAuditedEntitiesConfigurations.get(entityName); return notAuditedEntitiesConfigurations.get( entityName );
} }
public String getEntityNameForVersionsEntityName(String versionsEntityName) { public String getEntityNameForVersionsEntityName(String versionsEntityName) {
return entityNamesForVersionsEntityNames.get(versionsEntityName); return entityNamesForVersionsEntityNames.get( versionsEntityName );
} }
public boolean isVersioned(String entityName) { public boolean isVersioned(String entityName) {
return get(entityName) != null; return get( entityName ) != null;
} }
public boolean hasAuditedEntities() { public boolean hasAuditedEntities() {
return entitiesConfigurations.size() != 0; return entitiesConfigurations.size() != 0;
} }
public RelationDescription getRelationDescription(String entityName, String propertyName) { public RelationDescription getRelationDescription(String entityName, String propertyName) {
EntityConfiguration entCfg = entitiesConfigurations.get(entityName); final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
RelationDescription relDesc = entCfg.getRelationDescription(propertyName); final RelationDescription relDesc = entCfg.getRelationDescription( propertyName );
if (relDesc != null) { if ( relDesc != null ) {
return relDesc; return relDesc;
} else if (entCfg.getParentEntityName() != null) { }
// The field may be declared in a superclass ... else if ( entCfg.getParentEntityName() != null ) {
return getRelationDescription(entCfg.getParentEntityName(), propertyName); // The field may be declared in a superclass ...
} else { return getRelationDescription( entCfg.getParentEntityName(), propertyName );
return null; }
} else {
} return null;
}
}
private Collection<RelationDescription> getRelationDescriptions(String entityName) { private Collection<RelationDescription> getRelationDescriptions(String entityName) {
EntityConfiguration entCfg = entitiesConfigurations.get(entityName); final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
Collection<RelationDescription> descriptions = new ArrayList<RelationDescription>(); Collection<RelationDescription> descriptions = new ArrayList<RelationDescription>();
if (entCfg.getParentEntityName() != null) { if ( entCfg.getParentEntityName() != null ) {
// collect descriptions from super classes // collect descriptions from super classes
descriptions.addAll(getRelationDescriptions(entCfg.getParentEntityName())); descriptions.addAll( getRelationDescriptions( entCfg.getParentEntityName() ) );
} }
for (RelationDescription relationDescription : entCfg.getRelationsIterator()) { for ( RelationDescription relationDescription : entCfg.getRelationsIterator() ) {
descriptions.add(relationDescription); descriptions.add( relationDescription );
} }
return descriptions; return descriptions;
} }
private void addWithParentEntityNames(String entityName, Set<String> entityNames) { private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
entityNames.add(entityName); entityNames.add( entityName );
EntityConfiguration entCfg = entitiesConfigurations.get(entityName); final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
if (entCfg.getParentEntityName() != null) { if ( entCfg.getParentEntityName() != null ) {
// collect descriptions from super classes // collect descriptions from super classes
addWithParentEntityNames(entCfg.getParentEntityName(), entityNames); addWithParentEntityNames( entCfg.getParentEntityName(), entityNames );
} }
} }
private Set<String> getEntityAndParentsNames(String entityName) { private Set<String> getEntityAndParentsNames(String entityName) {
Set<String> names = new HashSet<String>(); final Set<String> names = new HashSet<String>();
addWithParentEntityNames(entityName, names); addWithParentEntityNames( entityName, names );
return names; return names;
} }
public Set<String> getToPropertyNames(String fromEntityName, String fromPropertyName, String toEntityName) { public Set<String> getToPropertyNames(String fromEntityName, String fromPropertyName, String toEntityName) {
Set<String> entityAndParentsNames = getEntityAndParentsNames(fromEntityName); final Set<String> entityAndParentsNames = getEntityAndParentsNames( fromEntityName );
Set<String> toPropertyNames = new HashSet<String>(); final Set<String> toPropertyNames = new HashSet<String>();
for (RelationDescription relationDescription : getRelationDescriptions(toEntityName)) { for ( RelationDescription relationDescription : getRelationDescriptions( toEntityName ) ) {
String relToEntityName = relationDescription.getToEntityName(); final String relToEntityName = relationDescription.getToEntityName();
String mappedByPropertyName = relationDescription.getMappedByPropertyName(); final String mappedByPropertyName = relationDescription.getMappedByPropertyName();
if (entityAndParentsNames.contains(relToEntityName) && mappedByPropertyName != null && mappedByPropertyName.equals(fromPropertyName)) { if ( entityAndParentsNames.contains( relToEntityName ) && mappedByPropertyName != null && mappedByPropertyName
toPropertyNames.add(relationDescription.getFromPropertyName()); .equals( fromPropertyName ) ) {
toPropertyNames.add( relationDescription.getFromPropertyName() );
} }
} }
return toPropertyNames; return toPropertyNames;

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities; package org.hibernate.envers.internal.entities;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -34,93 +35,160 @@ import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
*/ */
public class EntityConfiguration { public class EntityConfiguration {
private String versionsEntityName; private String versionsEntityName;
/** Holds the className for instantiation the configured entity */ /**
private String entityClassName; * Holds the className for instantiation the configured entity
*/
private String entityClassName;
private IdMappingData idMappingData; private IdMappingData idMappingData;
private ExtendedPropertyMapper propertyMapper; private ExtendedPropertyMapper propertyMapper;
// Maps from property name // Maps from property name
private Map<String, RelationDescription> relations; private Map<String, RelationDescription> relations;
private String parentEntityName; private String parentEntityName;
public EntityConfiguration(String versionsEntityName, String entityClassName, IdMappingData idMappingData, public EntityConfiguration(
ExtendedPropertyMapper propertyMapper, String parentEntityName) { String versionsEntityName, String entityClassName, IdMappingData idMappingData,
this.versionsEntityName = versionsEntityName; ExtendedPropertyMapper propertyMapper, String parentEntityName) {
this.entityClassName = entityClassName; this.versionsEntityName = versionsEntityName;
this.idMappingData = idMappingData; this.entityClassName = entityClassName;
this.propertyMapper = propertyMapper; this.idMappingData = idMappingData;
this.parentEntityName = parentEntityName; this.propertyMapper = propertyMapper;
this.parentEntityName = parentEntityName;
this.relations = new HashMap<String, RelationDescription>(); this.relations = new HashMap<String, RelationDescription>();
} }
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable) { public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable) {
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE, relations.put(
toEntityName, null, idMapper, null, null, insertable)); fromPropertyName,
} new RelationDescription(
fromPropertyName,
RelationType.TO_ONE,
toEntityName,
null,
idMapper,
null,
null,
insertable
)
);
}
public void addToOneNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName, public void addToOneNotOwningRelation(
IdMapper idMapper) { String fromPropertyName,
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE_NOT_OWNING, String mappedByPropertyName,
toEntityName, mappedByPropertyName, idMapper, null, null, true)); String toEntityName,
} IdMapper idMapper) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_ONE_NOT_OWNING,
toEntityName,
mappedByPropertyName,
idMapper,
null,
null,
true
)
);
}
public void addToManyNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName, public void addToManyNotOwningRelation(
IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper, String fromPropertyName,
PropertyMapper fakeBidirectionalRelationIndexMapper) { String mappedByPropertyName,
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_NOT_OWNING, String toEntityName,
toEntityName, mappedByPropertyName, idMapper, fakeBidirectionalRelationMapper, IdMapper idMapper,
fakeBidirectionalRelationIndexMapper, true)); PropertyMapper fakeBidirectionalRelationMapper,
} PropertyMapper fakeBidirectionalRelationIndexMapper) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_MANY_NOT_OWNING,
toEntityName,
mappedByPropertyName,
idMapper,
fakeBidirectionalRelationMapper,
fakeBidirectionalRelationIndexMapper,
true
)
);
}
public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) { public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) {
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE, relations.put(
toEntityName, null, null, null, null, true)); fromPropertyName,
} new RelationDescription(
fromPropertyName,
RelationType.TO_MANY_MIDDLE,
toEntityName,
null,
null,
null,
null,
true
)
);
}
public void addToManyMiddleNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName) { public void addToManyMiddleNotOwningRelation(
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE_NOT_OWNING, String fromPropertyName,
toEntityName, mappedByPropertyName, null, null, null, true)); String mappedByPropertyName,
} String toEntityName) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_MANY_MIDDLE_NOT_OWNING,
toEntityName,
mappedByPropertyName,
null,
null,
null,
true
)
);
}
public boolean isRelation(String propertyName) { public boolean isRelation(String propertyName) {
return relations.get(propertyName) != null; return relations.get( propertyName ) != null;
} }
public RelationDescription getRelationDescription(String propertyName) {
return relations.get(propertyName);
}
public IdMappingData getIdMappingData() { public RelationDescription getRelationDescription(String propertyName) {
return idMappingData; return relations.get( propertyName );
} }
public IdMapper getIdMapper() { public IdMappingData getIdMappingData() {
return idMappingData.getIdMapper(); return idMappingData;
} }
public ExtendedPropertyMapper getPropertyMapper() { public IdMapper getIdMapper() {
return propertyMapper; return idMappingData.getIdMapper();
} }
public String getParentEntityName() { public ExtendedPropertyMapper getPropertyMapper() {
return parentEntityName; return propertyMapper;
} }
// For use by EntitiesConfigurations public String getParentEntityName() {
return parentEntityName;
}
String getVersionsEntityName() { // For use by EntitiesConfigurations
return versionsEntityName;
}
Iterable<RelationDescription> getRelationsIterator() { String getVersionsEntityName() {
return relations.values(); return versionsEntityName;
} }
/** Iterable<RelationDescription> getRelationsIterator() {
* @return the className for the configured entity return relations.values();
*/ }
public String getEntityClassName() {
/**
* @return the className for the configured entity
*/
public String getEntityClassName() {
return entityClassName; return entityClassName;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -44,109 +44,136 @@ import org.hibernate.proxy.LazyInitializer;
* @author Hern&aacute;n Chanfreau * @author Hern&aacute;n Chanfreau
*/ */
public class EntityInstantiator { public class EntityInstantiator {
private final AuditConfiguration verCfg; private final AuditConfiguration verCfg;
private final AuditReaderImplementor versionsReader; private final AuditReaderImplementor versionsReader;
public EntityInstantiator(AuditConfiguration verCfg, AuditReaderImplementor versionsReader) { public EntityInstantiator(AuditConfiguration verCfg, AuditReaderImplementor versionsReader) {
this.verCfg = verCfg; this.verCfg = verCfg;
this.versionsReader = versionsReader; this.versionsReader = versionsReader;
} }
/** /**
* Creates an entity instance based on an entry from the versions table. * Creates an entity instance based on an entry from the versions table.
* @param entityName Name of the entity, which instances should be read *
* @param versionsEntity An entry in the versions table, from which data should be mapped. * @param entityName Name of the entity, which instances should be read
* @param revision Revision at which this entity was read. * @param versionsEntity An entry in the versions table, from which data should be mapped.
* @return An entity instance, with versioned properties set as in the versionsEntity map, and proxies * @param revision Revision at which this entity was read.
* created for collections. *
*/ * @return An entity instance, with versioned properties set as in the versionsEntity map, and proxies
public Object createInstanceFromVersionsEntity(String entityName, Map versionsEntity, Number revision) { * created for collections.
if (versionsEntity == null) { */
return null; public Object createInstanceFromVersionsEntity(String entityName, Map versionsEntity, Number revision) {
} if ( versionsEntity == null ) {
return null;
}
// The $type$ property holds the name of the (versions) entity // The $type$ property holds the name of the (versions) entity
String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName((String) versionsEntity.get("$type$")); final String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName( (String) versionsEntity.get( "$type$" ) );
if (type != null) { if ( type != null ) {
entityName = type; entityName = type;
} }
// First mapping the primary key // First mapping the primary key
IdMapper idMapper = verCfg.getEntCfg().get(entityName).getIdMapper(); final IdMapper idMapper = verCfg.getEntCfg().get( entityName ).getIdMapper();
Map originalId = (Map) versionsEntity.get(verCfg.getAuditEntCfg().getOriginalIdPropName()); final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
// Fixes HHH-4751 issue (@IdClass with @ManyToOne relation mapping inside) // Fixes HHH-4751 issue (@IdClass with @ManyToOne relation mapping inside)
// Note that identifiers are always audited // Note that identifiers are always audited
// Replace identifier proxies if do not point to audit tables // Replace identifier proxies if do not point to audit tables
replaceNonAuditIdProxies(versionsEntity, revision); replaceNonAuditIdProxies( versionsEntity, revision );
Object primaryKey = idMapper.mapToIdFromMap(originalId); final Object primaryKey = idMapper.mapToIdFromMap( originalId );
// Checking if the entity is in cache // Checking if the entity is in cache
if (versionsReader.getFirstLevelCache().contains(entityName, revision, primaryKey)) { if ( versionsReader.getFirstLevelCache().contains( entityName, revision, primaryKey ) ) {
return versionsReader.getFirstLevelCache().get(entityName, revision, primaryKey); return versionsReader.getFirstLevelCache().get( entityName, revision, primaryKey );
} }
// If it is not in the cache, creating a new entity instance // If it is not in the cache, creating a new entity instance
Object ret; Object ret;
try { try {
EntityConfiguration entCfg = verCfg.getEntCfg().get(entityName); EntityConfiguration entCfg = verCfg.getEntCfg().get( entityName );
if(entCfg == null) { if ( entCfg == null ) {
// a relation marked as RelationTargetAuditMode.NOT_AUDITED // a relation marked as RelationTargetAuditMode.NOT_AUDITED
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName); entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
} }
Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() ); final Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
ret = ReflectHelper.getDefaultConstructor(cls).newInstance(); ret = ReflectHelper.getDefaultConstructor( cls ).newInstance();
} catch (Exception e) { }
throw new AuditException(e); catch (Exception e) {
} throw new AuditException( e );
}
// Putting the newly created entity instance into the first level cache, in case a one-to-one bidirectional // Putting the newly created entity instance into the first level cache, in case a one-to-one bidirectional
// relation is present (which is eagerly loaded). // relation is present (which is eagerly loaded).
versionsReader.getFirstLevelCache().put(entityName, revision, primaryKey, ret); versionsReader.getFirstLevelCache().put( entityName, revision, primaryKey, ret );
verCfg.getEntCfg().get(entityName).getPropertyMapper().mapToEntityFromMap(verCfg, ret, versionsEntity, primaryKey, verCfg.getEntCfg().get( entityName ).getPropertyMapper().mapToEntityFromMap(
versionsReader, revision); verCfg,
idMapper.mapToEntityFromMap(ret, originalId); ret,
versionsEntity,
primaryKey,
versionsReader,
revision
);
idMapper.mapToEntityFromMap( ret, originalId );
// Put entity on entityName cache after mapping it from the map representation // Put entity on entityName cache after mapping it from the map representation
versionsReader.getFirstLevelCache().putOnEntityNameCache(primaryKey, revision, ret, entityName); versionsReader.getFirstLevelCache().putOnEntityNameCache( primaryKey, revision, ret, entityName );
return ret;
}
@SuppressWarnings({"unchecked"}) return ret;
private void replaceNonAuditIdProxies(Map versionsEntity, Number revision) { }
final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
for (Object key : originalId.keySet()) {
Object value = originalId.get(key);
if (value instanceof HibernateProxy) {
HibernateProxy hibernateProxy = (HibernateProxy) value;
LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
final String entityName = initializer.getEntityName();
final Serializable entityId = initializer.getIdentifier();
if (verCfg.getEntCfg().isVersioned(entityName)) {
final String entityClassName = verCfg.getEntCfg().get(entityName).getEntityClassName();
final Class entityClass = ReflectionTools.loadClass( entityClassName, verCfg.getClassLoaderService() );
final ToOneDelegateSessionImplementor delegate = new ToOneDelegateSessionImplementor(
versionsReader, entityClass, entityId, revision,
RevisionType.DEL.equals( versionsEntity.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) ),
verCfg);
originalId.put(key,
versionsReader.getSessionImplementor().getFactory().getEntityPersister(entityName).createProxy(entityId, delegate));
}
}
}
}
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public void addInstancesFromVersionsEntities(String entityName, Collection addTo, List<Map> versionsEntities, Number revision) { private void replaceNonAuditIdProxies(Map versionsEntity, Number revision) {
for (Map versionsEntity : versionsEntities) { final Map originalId = (Map) versionsEntity.get( verCfg.getAuditEntCfg().getOriginalIdPropName() );
addTo.add(createInstanceFromVersionsEntity(entityName, versionsEntity, revision)); for ( Object key : originalId.keySet() ) {
} final Object value = originalId.get( key );
} if ( value instanceof HibernateProxy ) {
final HibernateProxy hibernateProxy = (HibernateProxy) value;
final LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
final String entityName = initializer.getEntityName();
final Serializable entityId = initializer.getIdentifier();
if ( verCfg.getEntCfg().isVersioned( entityName ) ) {
final String entityClassName = verCfg.getEntCfg().get( entityName ).getEntityClassName();
final Class entityClass = ReflectionTools.loadClass(
entityClassName,
verCfg.getClassLoaderService()
);
final ToOneDelegateSessionImplementor delegate = new ToOneDelegateSessionImplementor(
versionsReader, entityClass, entityId, revision,
RevisionType.DEL.equals(
versionsEntity.get(
verCfg.getAuditEntCfg()
.getRevisionTypePropName()
)
),
verCfg
);
originalId.put(
key,
versionsReader.getSessionImplementor()
.getFactory()
.getEntityPersister( entityName )
.createProxy( entityId, delegate )
);
}
}
}
}
@SuppressWarnings({"unchecked"})
public void addInstancesFromVersionsEntities(
String entityName,
Collection addTo,
List<Map> versionsEntities,
Number revision) {
for ( Map versionsEntity : versionsEntities ) {
addTo.add( createInstanceFromVersionsEntity( entityName, versionsEntity, revision ) );
}
}
public AuditConfiguration getAuditConfiguration() { public AuditConfiguration getAuditConfiguration() {
return verCfg; return verCfg;

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities; package org.hibernate.envers.internal.entities;
import org.dom4j.Element; import org.dom4j.Element;
import org.hibernate.envers.internal.entities.mapper.id.IdMapper; import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
@ -30,27 +31,27 @@ import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class IdMappingData { public class IdMappingData {
private final IdMapper idMapper; private final IdMapper idMapper;
// Mapping which will be used to generate the entity // Mapping which will be used to generate the entity
private final Element xmlMapping; private final Element xmlMapping;
// Mapping which will be used to generate references to the entity in related entities // Mapping which will be used to generate references to the entity in related entities
private final Element xmlRelationMapping; private final Element xmlRelationMapping;
public IdMappingData(IdMapper idMapper, Element xmlMapping, Element xmlRelationMapping) { public IdMappingData(IdMapper idMapper, Element xmlMapping, Element xmlRelationMapping) {
this.idMapper = idMapper; this.idMapper = idMapper;
this.xmlMapping = xmlMapping; this.xmlMapping = xmlMapping;
this.xmlRelationMapping = xmlRelationMapping; this.xmlRelationMapping = xmlRelationMapping;
} }
public IdMapper getIdMapper() { public IdMapper getIdMapper() {
return idMapper; return idMapper;
} }
public Element getXmlMapping() { public Element getXmlMapping() {
return xmlMapping; return xmlMapping;
} }
public Element getXmlRelationMapping() { public Element getXmlRelationMapping() {
return xmlRelationMapping; return xmlRelationMapping;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,76 +22,86 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities; package org.hibernate.envers.internal.entities;
import org.hibernate.envers.ModificationStore; import org.hibernate.envers.ModificationStore;
import org.hibernate.internal.util.compare.EqualsHelper;
/** /**
* Holds information on a property that is audited. * Holds information on a property that is audited.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class PropertyData { public class PropertyData {
private final String name; private final String name;
/** /**
* Name of the property in the bean. * Name of the property in the bean.
*/ */
private final String beanName; private final String beanName;
private final String accessType; private final String accessType;
private final ModificationStore store; private final ModificationStore store;
private boolean usingModifiedFlag; private boolean usingModifiedFlag;
private String modifiedFlagName; private String modifiedFlagName;
/** /**
* Copies the given property data, except the name. * Copies the given property data, except the name.
* @param newName New name. *
* @param propertyData Property data to copy the rest of properties from. * @param newName New name.
*/ * @param propertyData Property data to copy the rest of properties from.
public PropertyData(String newName, PropertyData propertyData) { */
this.name = newName; public PropertyData(String newName, PropertyData propertyData) {
this.name = newName;
this.beanName = propertyData.beanName; this.beanName = propertyData.beanName;
this.accessType = propertyData.accessType; this.accessType = propertyData.accessType;
this.store = propertyData.store; this.store = propertyData.store;
} }
/**
* @param name Name of the property.
* @param beanName Name of the property in the bean.
* @param accessType Accessor type for this property.
* @param store How this property should be stored.
*/
public PropertyData(String name, String beanName, String accessType, ModificationStore store) {
this.name = name;
this.beanName = beanName;
this.accessType = accessType;
this.store = store;
}
/** /**
* @param name Name of the property. * @param name Name of the property.
* @param beanName Name of the property in the bean. * @param beanName Name of the property in the bean.
* @param accessType Accessor type for this property. * @param accessType Accessor type for this property.
* @param store How this property should be stored. * @param store How this property should be stored.
* @param usingModifiedFlag Defines if field changes should be tracked */
*/ public PropertyData(String name, String beanName, String accessType, ModificationStore store) {
public PropertyData(String name, String beanName, String accessType, ModificationStore store, boolean usingModifiedFlag, String modifiedFlagName) { this.name = name;
this(name, beanName, accessType, store); this.beanName = beanName;
this.accessType = accessType;
this.store = store;
}
/**
* @param name Name of the property.
* @param beanName Name of the property in the bean.
* @param accessType Accessor type for this property.
* @param store How this property should be stored.
* @param usingModifiedFlag Defines if field changes should be tracked
*/
public PropertyData(
String name,
String beanName,
String accessType,
ModificationStore store,
boolean usingModifiedFlag,
String modifiedFlagName) {
this( name, beanName, accessType, store );
this.usingModifiedFlag = usingModifiedFlag; this.usingModifiedFlag = usingModifiedFlag;
this.modifiedFlagName = modifiedFlagName; this.modifiedFlagName = modifiedFlagName;
} }
public String getName() { public String getName() {
return name; return name;
} }
public String getBeanName() { public String getBeanName() {
return beanName; return beanName;
} }
public String getAccessType() { public String getAccessType() {
return accessType; return accessType;
} }
public ModificationStore getStore() { public ModificationStore getStore() {
return store; return store;
} }
public boolean isUsingModifiedFlag() { public boolean isUsingModifiedFlag() {
return usingModifiedFlag; return usingModifiedFlag;
@ -103,18 +113,19 @@ public class PropertyData {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if ( this == o ) {
if (o == null || getClass() != o.getClass()) return false; return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PropertyData that = (PropertyData) o; final PropertyData that = (PropertyData) o;
return usingModifiedFlag == that.usingModifiedFlag
if (accessType != null ? !accessType.equals(that.accessType) : that.accessType != null) return false; && store == that.store
if (beanName != null ? !beanName.equals(that.beanName) : that.beanName != null) return false; && EqualsHelper.equals( accessType, that.accessType )
if (name != null ? !name.equals(that.name) : that.name != null) return false; && EqualsHelper.equals( beanName, that.beanName )
if (store != that.store) return false; && EqualsHelper.equals( name, that.name );
if (usingModifiedFlag != that.usingModifiedFlag) return false;
return true;
} }
@Override @Override

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,76 +22,78 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities; package org.hibernate.envers.internal.entities;
import org.hibernate.envers.internal.entities.mapper.PropertyMapper; import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
import org.hibernate.envers.internal.entities.mapper.id.IdMapper; import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class RelationDescription { public class RelationDescription {
private final String fromPropertyName; private final String fromPropertyName;
private final RelationType relationType; private final RelationType relationType;
private final String toEntityName; private final String toEntityName;
private final String mappedByPropertyName; private final String mappedByPropertyName;
private final IdMapper idMapper; private final IdMapper idMapper;
private final PropertyMapper fakeBidirectionalRelationMapper; private final PropertyMapper fakeBidirectionalRelationMapper;
private final PropertyMapper fakeBidirectionalRelationIndexMapper; private final PropertyMapper fakeBidirectionalRelationIndexMapper;
private final boolean insertable; private final boolean insertable;
private boolean bidirectional; private boolean bidirectional;
public RelationDescription(String fromPropertyName, RelationType relationType, String toEntityName, public RelationDescription(
String mappedByPropertyName, IdMapper idMapper, String fromPropertyName, RelationType relationType, String toEntityName,
PropertyMapper fakeBidirectionalRelationMapper, String mappedByPropertyName, IdMapper idMapper,
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) { PropertyMapper fakeBidirectionalRelationMapper,
this.fromPropertyName = fromPropertyName; PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) {
this.relationType = relationType; this.fromPropertyName = fromPropertyName;
this.toEntityName = toEntityName; this.relationType = relationType;
this.mappedByPropertyName = mappedByPropertyName; this.toEntityName = toEntityName;
this.idMapper = idMapper; this.mappedByPropertyName = mappedByPropertyName;
this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper; this.idMapper = idMapper;
this.fakeBidirectionalRelationIndexMapper = fakeBidirectionalRelationIndexMapper; this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper;
this.insertable = insertable; this.fakeBidirectionalRelationIndexMapper = fakeBidirectionalRelationIndexMapper;
this.insertable = insertable;
this.bidirectional = false; this.bidirectional = false;
} }
public String getFromPropertyName() { public String getFromPropertyName() {
return fromPropertyName; return fromPropertyName;
} }
public RelationType getRelationType() { public RelationType getRelationType() {
return relationType; return relationType;
} }
public String getToEntityName() { public String getToEntityName() {
return toEntityName; return toEntityName;
} }
public String getMappedByPropertyName() { public String getMappedByPropertyName() {
return mappedByPropertyName; return mappedByPropertyName;
} }
public IdMapper getIdMapper() { public IdMapper getIdMapper() {
return idMapper; return idMapper;
} }
public PropertyMapper getFakeBidirectionalRelationMapper() { public PropertyMapper getFakeBidirectionalRelationMapper() {
return fakeBidirectionalRelationMapper; return fakeBidirectionalRelationMapper;
} }
public PropertyMapper getFakeBidirectionalRelationIndexMapper() { public PropertyMapper getFakeBidirectionalRelationIndexMapper() {
return fakeBidirectionalRelationIndexMapper; return fakeBidirectionalRelationIndexMapper;
} }
public boolean isInsertable() { public boolean isInsertable() {
return insertable; return insertable;
} }
public boolean isBidirectional() { public boolean isBidirectional() {
return bidirectional; return bidirectional;
} }
void setBidirectional(boolean bidirectional) { void setBidirectional(boolean bidirectional) {
this.bidirectional = bidirectional; this.bidirectional = bidirectional;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -26,30 +26,31 @@ package org.hibernate.envers.internal.entities;
/** /**
* Type of a relation between two entities. * Type of a relation between two entities.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public enum RelationType { public enum RelationType {
/** /**
* A single-reference-valued relation. The entity owns the relation. * A single-reference-valued relation. The entity owns the relation.
*/ */
TO_ONE, TO_ONE,
/** /**
* A single-reference-valued relation. The entity doesn't own the relation. It is directly mapped in the related * A single-reference-valued relation. The entity doesn't own the relation. It is directly mapped in the related
* entity. * entity.
*/ */
TO_ONE_NOT_OWNING, TO_ONE_NOT_OWNING,
/** /**
* A collection-of-references-valued relation. The entity doesn't own the relation. It is directly mapped in the * A collection-of-references-valued relation. The entity doesn't own the relation. It is directly mapped in the
* related entity. * related entity.
*/ */
TO_MANY_NOT_OWNING, TO_MANY_NOT_OWNING,
/** /**
* A collection-of-references-valued relation. The entity owns the relation. It is mapped using a middle table. * A collection-of-references-valued relation. The entity owns the relation. It is mapped using a middle table.
*/ */
TO_MANY_MIDDLE, TO_MANY_MIDDLE,
/** /**
* A collection-of-references-valued relation. The entity doesn't own the relation. It is mapped using a middle * A collection-of-references-valued relation. The entity doesn't own the relation. It is mapped using a middle
* table. * table.
*/ */
TO_MANY_MIDDLE_NOT_OWNING TO_MANY_MIDDLE_NOT_OWNING
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -32,78 +32,84 @@ import java.sql.Types;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.RevisionType; import org.hibernate.envers.RevisionType;
import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.type.IntegerType; import org.hibernate.type.IntegerType;
import org.hibernate.usertype.UserType; import org.hibernate.usertype.UserType;
/** /**
* A hibernate type for the {@link RevisionType} enum. * A hibernate type for the {@link RevisionType} enum.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class RevisionTypeType implements UserType, Serializable { public class RevisionTypeType implements UserType, Serializable {
private static final long serialVersionUID = -1053201518229282688L; private static final long serialVersionUID = -1053201518229282688L;
private static final int[] SQL_TYPES = { Types.TINYINT };
public int[] sqlTypes() { private static final int[] SQL_TYPES = {Types.TINYINT};
return SQL_TYPES;
}
public Class returnedClass() { @Override
return RevisionType.class; public int[] sqlTypes() {
} return SQL_TYPES;
}
public RevisionType nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { @Override
Integer representationInt = IntegerType.INSTANCE.nullSafeGet( resultSet, names[0], session ); public Class returnedClass() {
return RevisionType.class;
}
@Override
public RevisionType nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
final Integer representationInt = IntegerType.INSTANCE.nullSafeGet( resultSet, names[0], session );
return representationInt == null ? return representationInt == null ?
null : null :
RevisionType.fromRepresentation( representationInt.byteValue() ); RevisionType.fromRepresentation( representationInt.byteValue() );
} }
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { @Override
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
IntegerType.INSTANCE.nullSafeSet( IntegerType.INSTANCE.nullSafeSet(
preparedStatement, preparedStatement,
( value == null ? null : ((RevisionType) value).getRepresentation().intValue() ), (value == null ? null : ((RevisionType) value).getRepresentation().intValue()),
index, index,
session session
); );
} }
public Object deepCopy(Object value) throws HibernateException{ @Override
return value; public Object deepCopy(Object value) throws HibernateException {
} return value;
}
public boolean isMutable() { @Override
return false; public boolean isMutable() {
} return false;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException { @Override
return cached; public Object assemble(Serializable cached, Object owner) throws HibernateException {
} return cached;
}
public Serializable disassemble(Object value) throws HibernateException { @Override
return (Serializable)value; public Serializable disassemble(Object value) throws HibernateException {
} return (Serializable) value;
}
public Object replace(Object original, Object target, Object owner) throws HibernateException { @Override
return original; public Object replace(Object original, Object target, Object owner) throws HibernateException {
} return original;
}
public int hashCode(Object x) throws HibernateException { @Override
return x.hashCode(); public int hashCode(Object x) throws HibernateException {
} return x.hashCode();
}
public boolean equals(Object x, Object y) throws HibernateException { @Override
//noinspection ObjectEquality public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) { return EqualsHelper.equals( x, y );
return true; }
}
if (null == x || null == y) {
return false;
}
return x.equals(y);
}
} }

View File

@ -1,22 +1,25 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
*
* JBoss, Home of Professional Open Source
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* *
* This copyrighted material is made available to anyone wishing to use, * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* modify, copy, or redistribute it subject to the terms and conditions * indicated by the @author tags or express copyright attribution
* of the GNU Lesser General Public License, v. 2.1. * statements applied by the authors. All third-party contributions are
* This program is distributed in the hope that it will be useful, but WITHOUT A * distributed under license by Red Hat Inc.
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * This copyrighted material is made available to anyone wishing to use, modify,
* You should have received a copy of the GNU Lesser General Public License, * copy, or redistribute it subject to the terms and conditions of the GNU
* v.2.1 along with this distribution; if not, write to the Free Software * Lesser General Public License, as published by the Free Software Foundation.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities; package org.hibernate.envers.internal.entities;
@ -25,14 +28,17 @@ import org.hibernate.metamodel.spi.TypeContributor;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
/** /**
* Envers specific TypeContributor
*
* @author Brett Meyer * @author Brett Meyer
*/ */
public class TypeContributorImpl implements TypeContributor { public class TypeContributorImpl implements TypeContributor {
@Override @Override
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
typeContributions.contributeType( new RevisionTypeType(), typeContributions.contributeType(
new String[] { RevisionTypeType.class.getName() } ); new RevisionTypeType(),
new String[] { RevisionTypeType.class.getName() }
);
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -43,98 +43,127 @@ import org.hibernate.property.Setter;
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperBuilder { public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperBuilder {
private final PropertyData propertyData; private final PropertyData propertyData;
private final MultiPropertyMapper delegate; private final MultiPropertyMapper delegate;
private final Class componentClass; private final Class componentClass;
public ComponentPropertyMapper(PropertyData propertyData, Class componentClass) { public ComponentPropertyMapper(PropertyData propertyData, Class componentClass) {
this.propertyData = propertyData; this.propertyData = propertyData;
this.delegate = new MultiPropertyMapper(); this.delegate = new MultiPropertyMapper();
this.componentClass = componentClass; this.componentClass = componentClass;
} }
public void add(PropertyData propertyData) {
delegate.add(propertyData);
}
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
return delegate.addComponent(propertyData, componentClass);
}
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
delegate.addComposite(propertyData, propertyMapper);
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
return delegate.mapToMapFromEntity(session, data, newObj, oldObj);
}
@Override @Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) { public void add(PropertyData propertyData) {
if (propertyData.isUsingModifiedFlag()) { delegate.add( propertyData );
data.put(propertyData.getModifiedFlagPropertyName(), }
delegate.mapToMapFromEntity(session, new HashMap<String, Object>(), newObj, oldObj));
@Override
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
return delegate.addComponent( propertyData, componentClass );
}
@Override
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
delegate.addComposite( propertyData, propertyMapper );
}
@Override
public boolean mapToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
return delegate.mapToMapFromEntity( session, data, newObj, oldObj );
}
@Override
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
if ( propertyData.isUsingModifiedFlag() ) {
data.put(
propertyData.getModifiedFlagPropertyName(),
delegate.mapToMapFromEntity( session, new HashMap<String, Object>(), newObj, oldObj )
);
} }
} }
@Override @Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) { public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
if (propertyData.isUsingModifiedFlag()) { if ( propertyData.isUsingModifiedFlag() ) {
boolean hasModifiedCollection = false; boolean hasModifiedCollection = false;
for (PropertyData propData : delegate.getProperties().keySet()) { for ( PropertyData propData : delegate.getProperties().keySet() ) {
if (collectionPropertyName.equals(propData.getName())) { if ( collectionPropertyName.equals( propData.getName() ) ) {
hasModifiedCollection = true; hasModifiedCollection = true;
break; break;
} }
} }
data.put(propertyData.getModifiedFlagPropertyName(), hasModifiedCollection); data.put( propertyData.getModifiedFlagPropertyName(), hasModifiedCollection );
} }
} }
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) { @Override
if (data == null || obj == null) { public void mapToEntityFromMap(
return; AuditConfiguration verCfg,
} Object obj,
Map data,
Object primaryKey,
AuditReaderImplementor versionsReader,
Number revision) {
if ( data == null || obj == null ) {
return;
}
if (propertyData.getBeanName() == null) { if ( propertyData.getBeanName() == null ) {
// If properties are not encapsulated in a component but placed directly in a class // If properties are not encapsulated in a component but placed directly in a class
// (e.g. by applying <properties> tag). // (e.g. by applying <properties> tag).
delegate.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision); delegate.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
return; return;
} }
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData); final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
// If all properties are null and single, then the component has to be null also. // If all properties are null and single, then the component has to be null also.
boolean allNullAndSingle = true; boolean allNullAndSingle = true;
for (Map.Entry<PropertyData, PropertyMapper> property : delegate.getProperties().entrySet()) { for ( Map.Entry<PropertyData, PropertyMapper> property : delegate.getProperties().entrySet() ) {
if (data.get(property.getKey().getName()) != null || !(property.getValue() instanceof SinglePropertyMapper)) { if ( data.get(
property.getKey()
.getName()
) != null || !(property.getValue() instanceof SinglePropertyMapper) ) {
allNullAndSingle = false; allNullAndSingle = false;
break; break;
} }
} }
if (allNullAndSingle) { if ( allNullAndSingle ) {
// single property, but default value need not be null, so we'll set it to null anyway // single property, but default value need not be null, so we'll set it to null anyway
setter.set(obj, null, null); setter.set( obj, null, null );
} else { }
else {
// set the component // set the component
try { try {
Object subObj = ReflectHelper.getDefaultConstructor(componentClass).newInstance(); final Object subObj = ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
setter.set(obj, subObj, null); setter.set( obj, subObj, null );
delegate.mapToEntityFromMap(verCfg, subObj, data, primaryKey, versionsReader, revision); delegate.mapToEntityFromMap( verCfg, subObj, data, primaryKey, versionsReader, revision );
} catch (Exception e) { }
throw new AuditException(e); catch (Exception e) {
throw new AuditException( e );
} }
} }
} }
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName, @Override
PersistentCollection newColl, public List<PersistentCollectionChangeData> mapCollectionChanges(
Serializable oldColl, Serializable id) { SessionImplementor session, String referencingPropertyName,
return delegate.mapCollectionChanges(session, referencingPropertyName, newColl, oldColl, id); PersistentCollection newColl,
} Serializable oldColl, Serializable id) {
return delegate.mapCollectionChanges( session, referencingPropertyName, newColl, oldColl, id );
}
@Override
public Map<PropertyData, PropertyMapper> getProperties() { public Map<PropertyData, PropertyMapper> getProperties() {
return delegate.getProperties(); return delegate.getProperties();
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -30,8 +30,10 @@ import org.hibernate.envers.internal.entities.PropertyData;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public interface CompositeMapperBuilder extends SimpleMapperBuilder { public interface CompositeMapperBuilder extends SimpleMapperBuilder {
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass); public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass);
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
public Map<PropertyData, PropertyMapper> getProperties(); public Map<PropertyData, PropertyMapper> getProperties();
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper; package org.hibernate.envers.internal.entities.mapper;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
@ -30,5 +31,10 @@ import org.hibernate.engine.spi.SessionImplementor;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder { public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState); public boolean map(
SessionImplementor session,
Map<String, Object> data,
String[] propertyNames,
Object[] newState,
Object[] oldState);
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -43,148 +43,183 @@ import org.hibernate.property.Getter;
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public class MultiPropertyMapper implements ExtendedPropertyMapper { public class MultiPropertyMapper implements ExtendedPropertyMapper {
protected final Map<PropertyData, PropertyMapper> properties; protected final Map<PropertyData, PropertyMapper> properties;
private final Map<String, PropertyData> propertyDatas; private final Map<String, PropertyData> propertyDatas;
public MultiPropertyMapper() { public MultiPropertyMapper() {
properties = Tools.newHashMap(); properties = Tools.newHashMap();
propertyDatas = Tools.newHashMap(); propertyDatas = Tools.newHashMap();
}
public void add(PropertyData propertyData) {
SinglePropertyMapper single = new SinglePropertyMapper();
single.add(propertyData);
properties.put(propertyData, single);
propertyDatas.put(propertyData.getName(), propertyData);
}
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
if (properties.get(propertyData) != null) {
// This is needed for second pass to work properly in the components mapper
return (CompositeMapperBuilder) properties.get(propertyData);
}
ComponentPropertyMapper componentMapperBuilder = new ComponentPropertyMapper(propertyData, componentClass);
addComposite(propertyData, componentMapperBuilder);
return componentMapperBuilder;
}
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
properties.put(propertyData, propertyMapper);
propertyDatas.put(propertyData.getName(), propertyData);
}
private Object getAtIndexOrNull(Object[] array, int index) { return array == null ? null : array[index]; }
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
boolean ret = false;
for (int i=0; i<propertyNames.length; i++) {
String propertyName = propertyNames[i];
if (propertyDatas.containsKey(propertyName)) {
PropertyMapper propertyMapper = properties.get(propertyDatas.get(propertyName));
Object newObj = getAtIndexOrNull(newState, i);
Object oldObj = getAtIndexOrNull(oldState, i);
ret |= propertyMapper.mapToMapFromEntity(session, data, newObj, oldObj);
propertyMapper.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj);
}
}
return ret;
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
boolean ret = false;
for (PropertyData propertyData : properties.keySet()) {
Getter getter;
if (newObj != null) {
getter = ReflectionTools.getGetter(newObj.getClass(), propertyData);
} else if (oldObj != null) {
getter = ReflectionTools.getGetter(oldObj.getClass(), propertyData);
} else {
return false;
}
ret |= properties.get(propertyData).mapToMapFromEntity(session, data,
newObj == null ? null : getter.get(newObj),
oldObj == null ? null : getter.get(oldObj));
}
return ret;
}
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
for (PropertyData propertyData : properties.keySet()) {
Getter getter;
if (newObj != null) {
getter = ReflectionTools.getGetter(newObj.getClass(), propertyData);
} else if (oldObj != null) {
getter = ReflectionTools.getGetter(oldObj.getClass(), propertyData);
} else {
return;
}
properties.get(propertyData).mapModifiedFlagsToMapFromEntity(session, data,
newObj == null ? null : getter.get(newObj),
oldObj == null ? null : getter.get(oldObj));
}
} }
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, @Override
AuditReaderImplementor versionsReader, Number revision) { public void add(PropertyData propertyData) {
for (PropertyMapper mapper : properties.values()) { final SinglePropertyMapper single = new SinglePropertyMapper();
mapper.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision); single.add( propertyData );
} properties.put( propertyData, single );
} propertyDatas.put( propertyData.getName(), propertyData );
}
private Pair<PropertyMapper, String> getMapperAndDelegatePropName(String referencingPropertyName){ @Override
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
if ( properties.get( propertyData ) != null ) {
// This is needed for second pass to work properly in the components mapper
return (CompositeMapperBuilder) properties.get( propertyData );
}
final ComponentPropertyMapper componentMapperBuilder = new ComponentPropertyMapper( propertyData, componentClass );
addComposite( propertyData, componentMapperBuilder );
return componentMapperBuilder;
}
@Override
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
properties.put( propertyData, propertyMapper );
propertyDatas.put( propertyData.getName(), propertyData );
}
private Object getAtIndexOrNull(Object[] array, int index) {
return array == null ? null : array[index];
}
@Override
public boolean map(
SessionImplementor session,
Map<String, Object> data,
String[] propertyNames,
Object[] newState,
Object[] oldState) {
boolean ret = false;
for ( int i = 0; i < propertyNames.length; i++ ) {
final String propertyName = propertyNames[i];
if ( propertyDatas.containsKey( propertyName ) ) {
final PropertyMapper propertyMapper = properties.get( propertyDatas.get( propertyName ) );
final Object newObj = getAtIndexOrNull( newState, i );
final Object oldObj = getAtIndexOrNull( oldState, i );
ret |= propertyMapper.mapToMapFromEntity( session, data, newObj, oldObj );
propertyMapper.mapModifiedFlagsToMapFromEntity( session, data, newObj, oldObj );
}
}
return ret;
}
@Override
public boolean mapToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
boolean ret = false;
for ( PropertyData propertyData : properties.keySet() ) {
Getter getter;
if ( newObj != null ) {
getter = ReflectionTools.getGetter( newObj.getClass(), propertyData );
}
else if ( oldObj != null ) {
getter = ReflectionTools.getGetter( oldObj.getClass(), propertyData );
}
else {
return false;
}
ret |= properties.get( propertyData ).mapToMapFromEntity(
session, data,
newObj == null ? null : getter.get( newObj ),
oldObj == null ? null : getter.get( oldObj )
);
}
return ret;
}
@Override
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
for ( PropertyData propertyData : properties.keySet() ) {
Getter getter;
if ( newObj != null ) {
getter = ReflectionTools.getGetter( newObj.getClass(), propertyData );
}
else if ( oldObj != null ) {
getter = ReflectionTools.getGetter( oldObj.getClass(), propertyData );
}
else {
return;
}
properties.get( propertyData ).mapModifiedFlagsToMapFromEntity(
session, data,
newObj == null ? null : getter.get( newObj ),
oldObj == null ? null : getter.get( oldObj )
);
}
}
@Override
public void mapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
for ( PropertyMapper mapper : properties.values() ) {
mapper.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
}
}
private Pair<PropertyMapper, String> getMapperAndDelegatePropName(String referencingPropertyName) {
// Name of the property, to which we will delegate the mapping. // Name of the property, to which we will delegate the mapping.
String delegatePropertyName; String delegatePropertyName;
// Checking if the property name doesn't reference a collection in a component - then the name will containa a . // Checking if the property name doesn't reference a collection in a component - then the name will containa a .
int dotIndex = referencingPropertyName.indexOf('.'); final int dotIndex = referencingPropertyName.indexOf( '.' );
if (dotIndex != -1) { if ( dotIndex != -1 ) {
// Computing the name of the component // Computing the name of the component
String componentName = referencingPropertyName.substring(0, dotIndex); final String componentName = referencingPropertyName.substring( 0, dotIndex );
// And the name of the property in the component // And the name of the property in the component
String propertyInComponentName = MappingTools.createComponentPrefix(componentName) final String propertyInComponentName = MappingTools.createComponentPrefix( componentName )
+ referencingPropertyName.substring(dotIndex+1); + referencingPropertyName.substring( dotIndex + 1 );
// We need to get the mapper for the component. // We need to get the mapper for the component.
referencingPropertyName = componentName; referencingPropertyName = componentName;
// As this is a component, we delegate to the property in the component. // As this is a component, we delegate to the property in the component.
delegatePropertyName = propertyInComponentName; delegatePropertyName = propertyInComponentName;
} else { }
else {
// If this is not a component, we delegate to the same property. // If this is not a component, we delegate to the same property.
delegatePropertyName = referencingPropertyName; delegatePropertyName = referencingPropertyName;
} }
return Pair.make(properties.get(propertyDatas.get(referencingPropertyName)), delegatePropertyName); return Pair.make( properties.get( propertyDatas.get( referencingPropertyName ) ), delegatePropertyName );
} }
@Override @Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) { public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(collectionPropertyName); final Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName( collectionPropertyName );
PropertyMapper mapper = pair.getFirst(); final PropertyMapper mapper = pair.getFirst();
if (mapper != null) { if ( mapper != null ) {
mapper.mapModifiedFlagsToMapForCollectionChange(pair.getSecond(), data); mapper.mapModifiedFlagsToMapForCollectionChange( pair.getSecond(), data );
} }
} }
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, @Override
String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(
PersistentCollection newColl, SessionImplementor session,
Serializable oldColl, Serializable id) { String referencingPropertyName,
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName); PersistentCollection newColl,
PropertyMapper mapper = pair.getFirst(); Serializable oldColl, Serializable id) {
if (mapper != null) { final Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName( referencingPropertyName );
return mapper.mapCollectionChanges(session, pair.getSecond(), newColl, oldColl, id); final PropertyMapper mapper = pair.getFirst();
} else { if ( mapper != null ) {
return mapper.mapCollectionChanges( session, pair.getSecond(), newColl, oldColl, id );
}
else {
return null; return null;
} }
} }
@Override
public Map<PropertyData, PropertyMapper> getProperties() { public Map<PropertyData, PropertyMapper> getProperties() {
return properties; return properties;
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper; package org.hibernate.envers.internal.entities.mapper;
import java.util.Map; import java.util.Map;
import org.hibernate.envers.tools.Pair; import org.hibernate.envers.tools.Pair;
@ -29,58 +30,58 @@ import org.hibernate.envers.tools.Pair;
/** /**
* Data describing the change of a single object in a persistent collection (when the object was added, removed or * Data describing the change of a single object in a persistent collection (when the object was added, removed or
* modified in the collection). * modified in the collection).
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class PersistentCollectionChangeData { public class PersistentCollectionChangeData {
private final String entityName; private final String entityName;
private final Map<String, Object> data; private final Map<String, Object> data;
private final Object changedElement; private final Object changedElement;
public PersistentCollectionChangeData(String entityName, Map<String, Object> data, Object changedElement) { public PersistentCollectionChangeData(String entityName, Map<String, Object> data, Object changedElement) {
this.entityName = entityName; this.entityName = entityName;
this.data = data; this.data = data;
this.changedElement = changedElement; this.changedElement = changedElement;
} }
/** /**
* * @return Name of the (middle) entity that holds the collection data.
* @return Name of the (middle) entity that holds the collection data. */
*/ public String getEntityName() {
public String getEntityName() { return entityName;
return entityName; }
}
public Map<String, Object> getData() { public Map<String, Object> getData() {
return data; return data;
} }
/** /**
* @return The affected element, which was changed (added, removed, modified) in the collection. * @return The affected element, which was changed (added, removed, modified) in the collection.
*/ */
public Object getChangedElement() { public Object getChangedElement() {
if (changedElement instanceof Pair) { if ( changedElement instanceof Pair ) {
return ((Pair) changedElement).getSecond(); return ((Pair) changedElement).getSecond();
} }
if (changedElement instanceof Map.Entry) { if ( changedElement instanceof Map.Entry ) {
return ((Map.Entry) changedElement).getValue(); return ((Map.Entry) changedElement).getValue();
} }
return changedElement; return changedElement;
} }
/** /**
* @return Index of the affected element, or {@code null} if the collection isn't indexed. * @return Index of the affected element, or {@code null} if the collection isn't indexed.
*/ */
public Object getChangedElementIndex() { public Object getChangedElementIndex() {
if (changedElement instanceof Pair) { if ( changedElement instanceof Pair ) {
return ((Pair) changedElement).getFirst(); return ((Pair) changedElement).getFirst();
} }
if (changedElement instanceof Map.Entry) { if ( changedElement instanceof Map.Entry ) {
return ((Map.Entry) changedElement).getKey(); return ((Map.Entry) changedElement).getKey();
} }
return null; return null;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper; package org.hibernate.envers.internal.entities.mapper;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -36,41 +37,53 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public interface PropertyMapper { public interface PropertyMapper {
/** /**
* Maps properties to the given map, basing on differences between properties of new and old objects. * Maps properties to the given map, basing on differences between properties of new and old objects.
* @param session The current session. *
* @param session The current session.
* @param data Data to map to. * @param data Data to map to.
* @param newObj New state of the entity. * @param newObj New state of the entity.
* @param oldObj Old state of the entity. * @param oldObj Old state of the entity.
*
* @return True if there are any differences between the states represented by newObj and oldObj. * @return True if there are any differences between the states represented by newObj and oldObj.
*/ */
boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj); boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj);
/** /**
* Maps properties from the given map to the given object. * Maps properties from the given map to the given object.
* @param verCfg Versions configuration. *
* @param obj Object to map to. * @param verCfg Versions configuration.
* @param data Data to map from. * @param obj Object to map to.
* @param primaryKey Primary key of the object to which we map (for relations) * @param data Data to map from.
* @param versionsReader VersionsReader for reading relations * @param primaryKey Primary key of the object to which we map (for relations)
* @param revision Revision at which the object is read, for reading relations * @param versionsReader VersionsReader for reading relations
*/ * @param revision Revision at which the object is read, for reading relations
void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, */
AuditReaderImplementor versionsReader, Number revision); void mapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision);
/** /**
* Maps collection changes. * Maps collection changes.
*
* @param session The current session. * @param session The current session.
* @param referencingPropertyName Name of the field, which holds the collection in the entity. * @param referencingPropertyName Name of the field, which holds the collection in the entity.
* @param newColl New collection, after updates. * @param newColl New collection, after updates.
* @param oldColl Old collection, before updates. * @param oldColl Old collection, before updates.
* @param id Id of the object owning the collection. * @param id Id of the object owning the collection.
* @return List of changes that need to be performed on the persistent store. *
*/ * @return List of changes that need to be performed on the persistent store.
List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName, */
PersistentCollection newColl, List<PersistentCollectionChangeData> mapCollectionChanges(
Serializable oldColl, Serializable id); SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id);
void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj);
void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj);
void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data); void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data);
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,11 +22,12 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper; package org.hibernate.envers.internal.entities.mapper;
import org.hibernate.envers.internal.entities.PropertyData; import org.hibernate.envers.internal.entities.PropertyData;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public interface SimpleMapperBuilder { public interface SimpleMapperBuilder {
public void add(PropertyData propertyData); public void add(PropertyData propertyData);
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -43,40 +43,53 @@ import org.hibernate.property.Setter;
/** /**
* TODO: diff * TODO: diff
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder { public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder {
private PropertyData propertyData; private PropertyData propertyData;
public SinglePropertyMapper(PropertyData propertyData) { public SinglePropertyMapper(PropertyData propertyData) {
this.propertyData = propertyData; this.propertyData = propertyData;
} }
public SinglePropertyMapper() { } public SinglePropertyMapper() {
}
public void add(PropertyData propertyData) {
if (this.propertyData != null) {
throw new AuditException("Only one property can be added!");
}
this.propertyData = propertyData;
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
data.put(propertyData.getName(), newObj);
boolean dbLogicallyDifferent = true;
if ((session.getFactory().getDialect() instanceof Oracle8iDialect) && (newObj instanceof String || oldObj instanceof String)) {
// Don't generate new revision when database replaces empty string with NULL during INSERT or UPDATE statements.
dbLogicallyDifferent = !(StringTools.isEmpty(newObj) && StringTools.isEmpty(oldObj));
}
return dbLogicallyDifferent && !Tools.objectsEqual(newObj, oldObj);
}
@Override @Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) { public void add(PropertyData propertyData) {
if (propertyData.isUsingModifiedFlag()) { if ( this.propertyData != null ) {
data.put(propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual(newObj, oldObj)); throw new AuditException( "Only one property can be added!" );
}
this.propertyData = propertyData;
}
@Override
public boolean mapToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
data.put( propertyData.getName(), newObj );
boolean dbLogicallyDifferent = true;
if ( (session.getFactory()
.getDialect() instanceof Oracle8iDialect) && (newObj instanceof String || oldObj instanceof String) ) {
// Don't generate new revision when database replaces empty string with NULL during INSERT or UPDATE statements.
dbLogicallyDifferent = !(StringTools.isEmpty( newObj ) && StringTools.isEmpty( oldObj ));
}
return dbLogicallyDifferent && !Tools.objectsEqual( newObj, oldObj );
}
@Override
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
if ( propertyData.isUsingModifiedFlag() ) {
data.put( propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual( newObj, oldObj ) );
} }
} }
@ -84,43 +97,50 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) { public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
} }
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, @Override
AuditReaderImplementor versionsReader, Number revision) { public void mapToEntityFromMap(
if (data == null || obj == null) { AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
return; AuditReaderImplementor versionsReader, Number revision) {
} if ( data == null || obj == null ) {
return;
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
Object value = data.get(propertyData.getName());
// We only set a null value if the field is not primite. Otherwise, we leave it intact.
if (value != null || !isPrimitive(setter, propertyData, obj.getClass())) {
setter.set(obj, value, null);
} }
}
final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
final Object value = data.get( propertyData.getName() );
// We only set a null value if the field is not primite. Otherwise, we leave it intact.
if ( value != null || !isPrimitive( setter, propertyData, obj.getClass() ) ) {
setter.set( obj, value, null );
}
}
private boolean isPrimitive(Setter setter, PropertyData propertyData, Class<?> cls) { private boolean isPrimitive(Setter setter, PropertyData propertyData, Class<?> cls) {
if (cls == null) { if ( cls == null ) {
throw new HibernateException("No field found for property: " + propertyData.getName()); throw new HibernateException( "No field found for property: " + propertyData.getName() );
} }
if (setter instanceof DirectPropertyAccessor.DirectSetter) { if ( setter instanceof DirectPropertyAccessor.DirectSetter ) {
// In a direct setter, getMethod() returns null // In a direct setter, getMethod() returns null
// Trying to look up the field // Trying to look up the field
try { try {
return cls.getDeclaredField(propertyData.getBeanName()).getType().isPrimitive(); return cls.getDeclaredField( propertyData.getBeanName() ).getType().isPrimitive();
} catch (NoSuchFieldException e) {
return isPrimitive(setter, propertyData, cls.getSuperclass());
} }
} else { catch (NoSuchFieldException e) {
return isPrimitive( setter, propertyData, cls.getSuperclass() );
}
}
else {
return setter.getMethod().getParameterTypes()[0].isPrimitive(); return setter.getMethod().getParameterTypes()[0].isPrimitive();
} }
} }
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor sessionImplementor, @Override
String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(
PersistentCollection newColl, SessionImplementor sessionImplementor,
Serializable oldColl, Serializable id) { String referencingPropertyName,
return null; PersistentCollection newColl,
} Serializable oldColl,
Serializable id) {
return null;
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper; package org.hibernate.envers.internal.entities.mapper;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -36,84 +37,124 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
/** /**
* A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper * A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper
* should be the mapper of the subclass. * should be the mapper of the subclass.
*
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public class SubclassPropertyMapper implements ExtendedPropertyMapper { public class SubclassPropertyMapper implements ExtendedPropertyMapper {
private ExtendedPropertyMapper main; private ExtendedPropertyMapper main;
private ExtendedPropertyMapper parentMapper; private ExtendedPropertyMapper parentMapper;
public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMapper parentMapper) { public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMapper parentMapper) {
this.main = main; this.main = main;
this.parentMapper = parentMapper; this.parentMapper = parentMapper;
} }
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
boolean parentDiffs = parentMapper.map(session, data, propertyNames, newState, oldState);
boolean mainDiffs = main.map(session, data, propertyNames, newState, oldState);
return parentDiffs || mainDiffs;
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
boolean parentDiffs = parentMapper.mapToMapFromEntity(session, data, newObj, oldObj);
boolean mainDiffs = main.mapToMapFromEntity(session, data, newObj, oldObj);
return parentDiffs || mainDiffs;
}
@Override @Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) { public boolean map(
parentMapper.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj); SessionImplementor session,
main.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj); Map<String, Object> data,
String[] propertyNames,
Object[] newState,
Object[] oldState) {
final boolean parentDiffs = parentMapper.map( session, data, propertyNames, newState, oldState );
final boolean mainDiffs = main.map( session, data, propertyNames, newState, oldState );
return parentDiffs || mainDiffs;
}
@Override
public boolean mapToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
final boolean parentDiffs = parentMapper.mapToMapFromEntity( session, data, newObj, oldObj );
final boolean mainDiffs = main.mapToMapFromEntity( session, data, newObj, oldObj );
return parentDiffs || mainDiffs;
}
@Override
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
parentMapper.mapModifiedFlagsToMapFromEntity( session, data, newObj, oldObj );
main.mapModifiedFlagsToMapFromEntity( session, data, newObj, oldObj );
} }
@Override @Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) { public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
parentMapper.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data); parentMapper.mapModifiedFlagsToMapForCollectionChange( collectionPropertyName, data );
main.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data); main.mapModifiedFlagsToMapForCollectionChange( collectionPropertyName, data );
} }
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) { @Override
parentMapper.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision); public void mapToEntityFromMap(
main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision); AuditConfiguration verCfg,
} Object obj,
Map data,
Object primaryKey,
AuditReaderImplementor versionsReader,
Number revision) {
parentMapper.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
main.mapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
}
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName, @Override
PersistentCollection newColl, public List<PersistentCollectionChangeData> mapCollectionChanges(
Serializable oldColl, Serializable id) { SessionImplementor session, String referencingPropertyName,
List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges( PersistentCollection newColl,
session, referencingPropertyName, newColl, oldColl, id); Serializable oldColl, Serializable id) {
final List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
session,
referencingPropertyName,
newColl,
oldColl,
id
);
List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges( final List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
session, referencingPropertyName, newColl, oldColl, id); session,
referencingPropertyName,
newColl,
oldColl,
id
);
if (parentCollectionChanges == null) { if ( parentCollectionChanges == null ) {
return mainCollectionChanges; return mainCollectionChanges;
} else { }
if(mainCollectionChanges != null) { else {
parentCollectionChanges.addAll(mainCollectionChanges); if ( mainCollectionChanges != null ) {
} parentCollectionChanges.addAll( mainCollectionChanges );
}
return parentCollectionChanges; return parentCollectionChanges;
} }
} }
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) { @Override
return main.addComponent(propertyData, componentClass); public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
} return main.addComponent( propertyData, componentClass );
}
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) { @Override
main.addComposite(propertyData, propertyMapper); public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
} main.addComposite( propertyData, propertyMapper );
}
public void add(PropertyData propertyData) { @Override
main.add(propertyData); public void add(PropertyData propertyData) {
} main.add( propertyData );
}
@Override
public Map<PropertyData, PropertyMapper> getProperties() { public Map<PropertyData, PropertyMapper> getProperties() {
final Map<PropertyData, PropertyMapper> joinedProperties = new HashMap<PropertyData, PropertyMapper>(); final Map<PropertyData, PropertyMapper> joinedProperties = new HashMap<PropertyData, PropertyMapper>();
joinedProperties.putAll(parentMapper.getProperties()); joinedProperties.putAll( parentMapper.getProperties() );
joinedProperties.putAll(main.getProperties()); joinedProperties.putAll( main.getProperties() );
return joinedProperties; return joinedProperties;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -35,36 +35,39 @@ import org.hibernate.internal.util.ReflectHelper;
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public abstract class AbstractCompositeIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder { public abstract class AbstractCompositeIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
protected Map<PropertyData, SingleIdMapper> ids; protected Map<PropertyData, SingleIdMapper> ids;
protected Class compositeIdClass; protected Class compositeIdClass;
protected AbstractCompositeIdMapper(Class compositeIdClass) { protected AbstractCompositeIdMapper(Class compositeIdClass) {
ids = Tools.newLinkedHashMap(); ids = Tools.newLinkedHashMap();
this.compositeIdClass = compositeIdClass; this.compositeIdClass = compositeIdClass;
} }
public void add(PropertyData propertyData) { @Override
ids.put(propertyData, new SingleIdMapper(propertyData)); public void add(PropertyData propertyData) {
} ids.put( propertyData, new SingleIdMapper( propertyData ) );
}
public Object mapToIdFromMap(Map data) { @Override
if (data == null) { public Object mapToIdFromMap(Map data) {
return null; if ( data == null ) {
} return null;
}
Object ret; final Object ret;
try { try {
ret = ReflectHelper.getDefaultConstructor(compositeIdClass).newInstance(); ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
} catch (Exception e) { }
throw new AuditException(e); catch (Exception e) {
} throw new AuditException( e );
}
for (SingleIdMapper mapper : ids.values()) { for ( SingleIdMapper mapper : ids.values() ) {
if (!mapper.mapToEntityFromMap(ret, data)) { if ( !mapper.mapToEntityFromMap( ret, data ) ) {
return null; return null;
} }
} }
return ret; return ret;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper.id; package org.hibernate.envers.internal.entities.mapper.id;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -31,69 +32,96 @@ import org.hibernate.envers.internal.tools.query.Parameters;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public abstract class AbstractIdMapper implements IdMapper { public abstract class AbstractIdMapper implements IdMapper {
private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) { private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) {
if (paramDatas.size() > 1) { if ( paramDatas.size() > 1 ) {
return parameters.addSubParameters("and"); return parameters.addSubParameters( "and" );
} else { }
return parameters; else {
} return parameters;
} }
}
public void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2) { @Override
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null); public void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
final List<QueryParameterData> paramDatas = mapToQueryParametersFromId( null );
Parameters parametersToUse = getParametersToUse(parameters, paramDatas); final Parameters parametersToUse = getParametersToUse( parameters, paramDatas );
for (QueryParameterData paramData : paramDatas) { for ( QueryParameterData paramData : paramDatas ) {
parametersToUse.addWhere(paramData.getProperty(prefix1), false, "=", paramData.getProperty(prefix2), false); parametersToUse.addWhere(
} paramData.getProperty( prefix1 ),
} false,
"=",
paramData.getProperty( prefix2 ),
false
);
}
}
public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) { @Override
List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId(null); public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) {
List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId(null); final List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId( null );
final List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId( null );
Parameters parametersToUse = getParametersToUse(parameters, paramDatas1); final Parameters parametersToUse = getParametersToUse( parameters, paramDatas1 );
Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator(); final Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator();
Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator(); final Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
while (paramDataIter1.hasNext()) { while ( paramDataIter1.hasNext() ) {
QueryParameterData paramData1 = paramDataIter1.next(); final QueryParameterData paramData1 = paramDataIter1.next();
QueryParameterData paramData2 = paramDataIter2.next(); final QueryParameterData paramData2 = paramDataIter2.next();
parametersToUse.addWhere(paramData1.getProperty(prefix1), false, "=", paramData2.getProperty(prefix2), false); parametersToUse.addWhere(
} paramData1.getProperty( prefix1 ),
} false,
"=",
paramData2.getProperty( prefix2 ),
false
);
}
}
public void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals) { @Override
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(id); public void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals) {
final List<QueryParameterData> paramDatas = mapToQueryParametersFromId( id );
Parameters parametersToUse = getParametersToUse(parameters, paramDatas); final Parameters parametersToUse = getParametersToUse( parameters, paramDatas );
for (QueryParameterData paramData : paramDatas) { for ( QueryParameterData paramData : paramDatas ) {
if (paramData.getValue() == null) { if ( paramData.getValue() == null ) {
handleNullValue(parametersToUse, paramData.getProperty(prefix), equals); handleNullValue( parametersToUse, paramData.getProperty( prefix ), equals );
} else { }
parametersToUse.addWhereWithParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getValue()); else {
} parametersToUse.addWhereWithParam(
} paramData.getProperty( prefix ),
} equals ? "=" : "<>",
paramData.getValue()
);
}
}
}
public void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals) { @Override
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null); public void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals) {
final List<QueryParameterData> paramDatas = mapToQueryParametersFromId( null );
Parameters parametersToUse = getParametersToUse(parameters, paramDatas); final Parameters parametersToUse = getParametersToUse( parameters, paramDatas );
for (QueryParameterData paramData : paramDatas) { for ( QueryParameterData paramData : paramDatas ) {
parametersToUse.addWhereWithNamedParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getQueryParameterName()); parametersToUse.addWhereWithNamedParam(
} paramData.getProperty( prefix ),
} equals ? "=" : "<>",
paramData.getQueryParameterName()
);
}
}
private void handleNullValue(Parameters parameters, String propertyName, boolean equals) { private void handleNullValue(Parameters parameters, String propertyName, boolean equals) {
if (equals) { if ( equals ) {
parameters.addNullRestriction(propertyName, equals); parameters.addNullRestriction( propertyName, equals );
} else { }
parameters.addNotNullRestriction(propertyName, equals); else {
} parameters.addNotNullRestriction( propertyName, equals );
} }
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -39,85 +39,92 @@ import org.hibernate.property.Setter;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder { public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
private PropertyData idPropertyData; private PropertyData idPropertyData;
public EmbeddedIdMapper(PropertyData idPropertyData, Class compositeIdClass) { public EmbeddedIdMapper(PropertyData idPropertyData, Class compositeIdClass) {
super(compositeIdClass); super( compositeIdClass );
this.idPropertyData = idPropertyData; this.idPropertyData = idPropertyData;
} }
public void mapToMapFromId(Map<String, Object> data, Object obj) { @Override
for (IdMapper idMapper : ids.values()) { public void mapToMapFromId(Map<String, Object> data, Object obj) {
idMapper.mapToMapFromEntity(data, obj); for ( IdMapper idMapper : ids.values() ) {
} idMapper.mapToMapFromEntity( data, obj );
} }
}
public void mapToMapFromEntity(Map<String, Object> data, Object obj) { @Override
if (obj == null) { public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
return; if ( obj == null ) {
} return;
}
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyData); final Getter getter = ReflectionTools.getGetter( obj.getClass(), idPropertyData );
mapToMapFromId(data, getter.get(obj)); mapToMapFromId( data, getter.get( obj ) );
} }
public boolean mapToEntityFromMap(Object obj, Map data) { @Override
if (data == null || obj == null) { public boolean mapToEntityFromMap(Object obj, Map data) {
return false; if ( data == null || obj == null ) {
} return false;
}
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyData); final Getter getter = ReflectionTools.getGetter( obj.getClass(), idPropertyData );
Setter setter = ReflectionTools.getSetter(obj.getClass(), idPropertyData); final Setter setter = ReflectionTools.getSetter( obj.getClass(), idPropertyData );
try { try {
Object subObj = ReflectHelper.getDefaultConstructor( getter.getReturnType() ).newInstance(); final Object subObj = ReflectHelper.getDefaultConstructor( getter.getReturnType() ).newInstance();
boolean ret = true; boolean ret = true;
for (IdMapper idMapper : ids.values()) { for ( IdMapper idMapper : ids.values() ) {
ret &= idMapper.mapToEntityFromMap(subObj, data); ret &= idMapper.mapToEntityFromMap( subObj, data );
} }
if (ret) { if ( ret ) {
setter.set(obj, subObj, null); setter.set( obj, subObj, null );
} }
return ret; return ret;
} catch (Exception e) { }
throw new AuditException(e); catch (Exception e) {
} throw new AuditException( e );
} }
}
public IdMapper prefixMappedProperties(String prefix) { @Override
EmbeddedIdMapper ret = new EmbeddedIdMapper(idPropertyData, compositeIdClass); public IdMapper prefixMappedProperties(String prefix) {
final EmbeddedIdMapper ret = new EmbeddedIdMapper( idPropertyData, compositeIdClass );
for (PropertyData propertyData : ids.keySet()) { for ( PropertyData propertyData : ids.keySet() ) {
String propertyName = propertyData.getName(); final String propertyName = propertyData.getName();
ret.ids.put(propertyData, new SingleIdMapper(new PropertyData(prefix + propertyName, propertyData))); ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
} }
return ret; return ret;
} }
public Object mapToIdFromEntity(Object data) { @Override
if (data == null) { public Object mapToIdFromEntity(Object data) {
return null; if ( data == null ) {
} return null;
}
Getter getter = ReflectionTools.getGetter(data.getClass(), idPropertyData); final Getter getter = ReflectionTools.getGetter( data.getClass(), idPropertyData );
return getter.get(data); return getter.get( data );
} }
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) { @Override
Map<String, Object> data = new LinkedHashMap<String, Object>(); public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
mapToMapFromId(data, obj); final Map<String, Object> data = new LinkedHashMap<String, Object>();
mapToMapFromId( data, obj );
List<QueryParameterData> ret = new ArrayList<QueryParameterData>(); final List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
for (Map.Entry<String, Object> propertyData : data.entrySet()) { for ( Map.Entry<String, Object> propertyData : data.entrySet() ) {
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue())); ret.add( new QueryParameterData( propertyData.getKey(), propertyData.getValue() ) );
} }
return ret; return ret;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper.id; package org.hibernate.envers.internal.entities.mapper.id;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -31,73 +32,81 @@ import org.hibernate.envers.internal.tools.query.Parameters;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public interface IdMapper { public interface IdMapper {
void mapToMapFromId(Map<String, Object> data, Object obj); void mapToMapFromId(Map<String, Object> data, Object obj);
void mapToMapFromEntity(Map<String, Object> data, Object obj); void mapToMapFromEntity(Map<String, Object> data, Object obj);
/** /**
* @param obj Object to map to. * @param obj Object to map to.
* @param data Data to map. * @param data Data to map.
* @return True if data was mapped; false otherwise (when the id is {@code null}). *
*/ * @return True if data was mapped; false otherwise (when the id is {@code null}).
boolean mapToEntityFromMap(Object obj, Map data); */
boolean mapToEntityFromMap(Object obj, Map data);
Object mapToIdFromEntity(Object data); Object mapToIdFromEntity(Object data);
Object mapToIdFromMap(Map data); Object mapToIdFromMap(Map data);
/** /**
* Creates a mapper with all mapped properties prefixed. A mapped property is a property which * Creates a mapper with all mapped properties prefixed. A mapped property is a property which
* is directly mapped to values (not composite). * is directly mapped to values (not composite).
* @param prefix Prefix to add to mapped properties *
* @return A copy of the current property mapper, with mapped properties prefixed. * @param prefix Prefix to add to mapped properties
*/ *
IdMapper prefixMappedProperties(String prefix); * @return A copy of the current property mapper, with mapped properties prefixed.
*/
IdMapper prefixMappedProperties(String prefix);
/** /**
* @param obj Id from which to map. * @param obj Id from which to map.
* @return A set parameter data, needed to build a query basing on the given id. *
*/ * @return A set parameter data, needed to build a query basing on the given id.
List<QueryParameterData> mapToQueryParametersFromId(Object obj); */
List<QueryParameterData> mapToQueryParametersFromId(Object obj);
/** /**
* Adds query statements, which contains restrictions, which express the property that the id of the entity * Adds query statements, which contains restrictions, which express the property that the id of the entity
* with alias prefix1, is equal to the id of the entity with alias prefix2 (the entity is the same). * with alias prefix1, is equal to the id of the entity with alias prefix2 (the entity is the same).
* @param parameters Parameters, to which to add the statements. *
* @param prefix1 First alias of the entity + prefix to add to the properties. * @param parameters Parameters, to which to add the statements.
* @param prefix2 Second alias of the entity + prefix to add to the properties. * @param prefix1 First alias of the entity + prefix to add to the properties.
*/ * @param prefix2 Second alias of the entity + prefix to add to the properties.
void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2); */
void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2);
/** /**
* Adds query statements, which contains restrictions, which express the property that the id of the entity * Adds query statements, which contains restrictions, which express the property that the id of the entity
* with alias prefix1, is equal to the id of the entity with alias prefix2 mapped by the second mapper * with alias prefix1, is equal to the id of the entity with alias prefix2 mapped by the second mapper
* (the second mapper must be for the same entity, but it can have, for example, prefixed properties). * (the second mapper must be for the same entity, but it can have, for example, prefixed properties).
* @param parameters Parameters, to which to add the statements. *
* @param prefix1 First alias of the entity + prefix to add to the properties. * @param parameters Parameters, to which to add the statements.
* @param mapper2 Second mapper for the same entity, which will be used to get properties for the right side * @param prefix1 First alias of the entity + prefix to add to the properties.
* of the equation. * @param mapper2 Second mapper for the same entity, which will be used to get properties for the right side
* @param prefix2 Second alias of the entity + prefix to add to the properties. * of the equation.
*/ * @param prefix2 Second alias of the entity + prefix to add to the properties.
void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2); */
void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2);
/** /**
* Adds query statements, which contains restrictions, which express the property that the id of the entity * Adds query statements, which contains restrictions, which express the property that the id of the entity
* with alias prefix, is equal to the given object. * with alias prefix, is equal to the given object.
* @param parameters Parameters, to which to add the statements. *
* @param id Value of id. * @param parameters Parameters, to which to add the statements.
* @param prefix Prefix to add to the properties (may be null). * @param id Value of id.
* @param equals Should this query express the "=" relation or the "<>" relation. * @param prefix Prefix to add to the properties (may be null).
*/ * @param equals Should this query express the "=" relation or the "<>" relation.
void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals); */
void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals);
/** /**
* Adds query statements, which contains named parameters, which express the property that the id of the entity * Adds query statements, which contains named parameters, which express the property that the id of the entity
* with alias prefix, is equal to the given object. It is the responsibility of the using method to read * with alias prefix, is equal to the given object. It is the responsibility of the using method to read
* parameter values from the id and specify them on the final query object. * parameter values from the id and specify them on the final query object.
* @param parameters Parameters, to which to add the statements. *
* @param prefix Prefix to add to the properties (may be null). * @param parameters Parameters, to which to add the statements.
* @param equals Should this query express the "=" relation or the "<>" relation. * @param prefix Prefix to add to the properties (may be null).
*/ * @param equals Should this query express the "=" relation or the "<>" relation.
void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals); */
void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals);
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -36,69 +36,76 @@ import org.hibernate.internal.util.ReflectHelper;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder { public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
public MultipleIdMapper(Class compositeIdClass) { public MultipleIdMapper(Class compositeIdClass) {
super(compositeIdClass); super( compositeIdClass );
} }
public void mapToMapFromId(Map<String, Object> data, Object obj) { @Override
for (IdMapper idMapper : ids.values()) { public void mapToMapFromId(Map<String, Object> data, Object obj) {
idMapper.mapToMapFromEntity(data, obj); for ( IdMapper idMapper : ids.values() ) {
} idMapper.mapToMapFromEntity( data, obj );
} }
}
public void mapToMapFromEntity(Map<String, Object> data, Object obj) { @Override
mapToMapFromId(data, obj); public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
} mapToMapFromId( data, obj );
}
public boolean mapToEntityFromMap(Object obj, Map data) { @Override
boolean ret = true; public boolean mapToEntityFromMap(Object obj, Map data) {
for (IdMapper idMapper : ids.values()) { boolean ret = true;
ret &= idMapper.mapToEntityFromMap(obj, data); for ( IdMapper idMapper : ids.values() ) {
} ret &= idMapper.mapToEntityFromMap( obj, data );
}
return ret; return ret;
} }
public IdMapper prefixMappedProperties(String prefix) { @Override
MultipleIdMapper ret = new MultipleIdMapper(compositeIdClass); public IdMapper prefixMappedProperties(String prefix) {
final MultipleIdMapper ret = new MultipleIdMapper( compositeIdClass );
for (PropertyData propertyData : ids.keySet()) { for ( PropertyData propertyData : ids.keySet() ) {
String propertyName = propertyData.getName(); final String propertyName = propertyData.getName();
ret.ids.put(propertyData, new SingleIdMapper(new PropertyData(prefix + propertyName, propertyData))); ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
} }
return ret; return ret;
} }
public Object mapToIdFromEntity(Object data) { @Override
if (data == null) { public Object mapToIdFromEntity(Object data) {
return null; if ( data == null ) {
} return null;
}
Object ret; final Object ret;
try { try {
ret = ReflectHelper.getDefaultConstructor(compositeIdClass).newInstance(); ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
} catch (Exception e) { }
throw new AuditException(e); catch (Exception e) {
} throw new AuditException( e );
}
for (SingleIdMapper mapper : ids.values()) { for ( SingleIdMapper mapper : ids.values() ) {
mapper.mapToEntityFromEntity(ret, data); mapper.mapToEntityFromEntity( ret, data );
} }
return ret; return ret;
} }
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) { @Override
Map<String, Object> data = new LinkedHashMap<String, Object>(); public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
mapToMapFromId(data, obj); final Map<String, Object> data = new LinkedHashMap<String, Object>();
mapToMapFromId( data, obj );
List<QueryParameterData> ret = new ArrayList<QueryParameterData>(); final List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
for (Map.Entry<String, Object> propertyData : data.entrySet()) { for ( Map.Entry<String, Object> propertyData : data.entrySet() ) {
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue())); ret.add( new QueryParameterData( propertyData.getKey(), propertyData.getValue() ) );
} }
return ret; return ret;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,53 +22,58 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper.id; package org.hibernate.envers.internal.entities.mapper.id;
import org.hibernate.Query; import org.hibernate.Query;
import org.hibernate.internal.util.compare.EqualsHelper;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class QueryParameterData { public class QueryParameterData {
private String flatEntityPropertyName; private String flatEntityPropertyName;
private Object value; private Object value;
public QueryParameterData(String flatEntityPropertyName, Object value) { public QueryParameterData(String flatEntityPropertyName, Object value) {
this.flatEntityPropertyName = flatEntityPropertyName; this.flatEntityPropertyName = flatEntityPropertyName;
this.value = value; this.value = value;
} }
public String getProperty(String prefix) { public String getProperty(String prefix) {
if (prefix != null) { if ( prefix != null ) {
return prefix + "." + flatEntityPropertyName; return prefix + "." + flatEntityPropertyName;
} else { }
return flatEntityPropertyName; else {
} return flatEntityPropertyName;
} }
}
public Object getValue() { public Object getValue() {
return value; return value;
} }
public void setParameterValue(Query query) { public void setParameterValue(Query query) {
query.setParameter(flatEntityPropertyName, value); query.setParameter( flatEntityPropertyName, value );
} }
public String getQueryParameterName() { public String getQueryParameterName() {
return flatEntityPropertyName; return flatEntityPropertyName;
} }
public boolean equals(Object o) { @Override
if (this == o) return true; public boolean equals(Object o) {
if (!(o instanceof QueryParameterData)) return false; if ( this == o ) {
return true;
}
if ( !(o instanceof QueryParameterData) ) {
return false;
}
QueryParameterData that = (QueryParameterData) o; final QueryParameterData that = (QueryParameterData) o;
return EqualsHelper.equals( flatEntityPropertyName, that.flatEntityPropertyName );
}
if (flatEntityPropertyName != null ? !flatEntityPropertyName.equals(that.flatEntityPropertyName) : that.flatEntityPropertyName != null) @Override
return false; public int hashCode() {
return (flatEntityPropertyName != null ? flatEntityPropertyName.hashCode() : 0);
return true; }
}
public int hashCode() {
return (flatEntityPropertyName != null ? flatEntityPropertyName.hashCode() : 0);
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.internal.entities.mapper.id; package org.hibernate.envers.internal.entities.mapper.id;
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder; import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
/** /**

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -38,100 +38,111 @@ import org.hibernate.proxy.HibernateProxy;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder { public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
private PropertyData propertyData; private PropertyData propertyData;
public SingleIdMapper() { public SingleIdMapper() {
} }
public SingleIdMapper(PropertyData propertyData) { public SingleIdMapper(PropertyData propertyData) {
this.propertyData = propertyData; this.propertyData = propertyData;
} }
public void add(PropertyData propertyData) { @Override
if (this.propertyData != null) { public void add(PropertyData propertyData) {
throw new AuditException("Only one property can be added!"); if ( this.propertyData != null ) {
} throw new AuditException( "Only one property can be added!" );
}
this.propertyData = propertyData; this.propertyData = propertyData;
} }
public boolean mapToEntityFromMap(Object obj, Map data) { @Override
if (data == null || obj == null) { public boolean mapToEntityFromMap(Object obj, Map data) {
return false; if ( data == null || obj == null ) {
} return false;
}
Object value = data.get(propertyData.getName()); final Object value = data.get( propertyData.getName() );
if (value == null) { if ( value == null ) {
return false; return false;
} }
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData); final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
setter.set(obj, value, null); setter.set( obj, value, null );
return true; return true;
} }
public Object mapToIdFromMap(Map data) { @Override
if (data == null) { public Object mapToIdFromMap(Map data) {
return null; if ( data == null ) {
} return null;
}
return data.get(propertyData.getName()); return data.get( propertyData.getName() );
} }
public Object mapToIdFromEntity(Object data) { @Override
if (data == null) { public Object mapToIdFromEntity(Object data) {
return null; if ( data == null ) {
} return null;
}
if(data instanceof HibernateProxy) { if ( data instanceof HibernateProxy ) {
HibernateProxy hibernateProxy = (HibernateProxy) data; final HibernateProxy hibernateProxy = (HibernateProxy) data;
return hibernateProxy.getHibernateLazyInitializer().getIdentifier(); return hibernateProxy.getHibernateLazyInitializer().getIdentifier();
} else { }
Getter getter = ReflectionTools.getGetter(data.getClass(), propertyData); else {
return getter.get(data); final Getter getter = ReflectionTools.getGetter( data.getClass(), propertyData );
} return getter.get( data );
} }
}
public void mapToMapFromId(Map<String, Object> data, Object obj) { @Override
if (data != null) { public void mapToMapFromId(Map<String, Object> data, Object obj) {
data.put(propertyData.getName(), obj); if ( data != null ) {
} data.put( propertyData.getName(), obj );
} }
}
public void mapToMapFromEntity(Map<String, Object> data, Object obj) { @Override
if (obj == null) { public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
data.put(propertyData.getName(), null); if ( obj == null ) {
} else { data.put( propertyData.getName(), null );
if(obj instanceof HibernateProxy) { }
HibernateProxy hibernateProxy = (HibernateProxy)obj; else {
data.put(propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier()); if ( obj instanceof HibernateProxy ) {
} else { final HibernateProxy hibernateProxy = (HibernateProxy) obj;
Getter getter = ReflectionTools.getGetter(obj.getClass(), propertyData); data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier() );
data.put(propertyData.getName(), getter.get(obj)); }
} else {
} final Getter getter = ReflectionTools.getGetter( obj.getClass(), propertyData );
} data.put( propertyData.getName(), getter.get( obj ) );
}
}
}
public void mapToEntityFromEntity(Object objTo, Object objFrom) { public void mapToEntityFromEntity(Object objTo, Object objFrom) {
if (objTo == null || objFrom == null) { if ( objTo == null || objFrom == null ) {
return; return;
} }
Getter getter = ReflectionTools.getGetter(objFrom.getClass(), propertyData); final Getter getter = ReflectionTools.getGetter( objFrom.getClass(), propertyData );
Setter setter = ReflectionTools.getSetter(objTo.getClass(), propertyData); final Setter setter = ReflectionTools.getSetter( objTo.getClass(), propertyData );
setter.set(objTo, getter.get(objFrom), null); setter.set( objTo, getter.get( objFrom ), null );
} }
public IdMapper prefixMappedProperties(String prefix) { @Override
return new SingleIdMapper(new PropertyData(prefix + propertyData.getName(), propertyData)); public IdMapper prefixMappedProperties(String prefix) {
} return new SingleIdMapper( new PropertyData( prefix + propertyData.getName(), propertyData ) );
}
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) { @Override
List<QueryParameterData> ret = new ArrayList<QueryParameterData>(); public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
final List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
ret.add(new QueryParameterData(propertyData.getName(), obj)); ret.add( new QueryParameterData( propertyData.getName(), obj ) );
return ret; return ret;
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -53,43 +53,53 @@ import org.hibernate.property.Setter;
* @author Michal Skowronek (mskowr at o2 dot pl) * @author Michal Skowronek (mskowr at o2 dot pl)
*/ */
public abstract class AbstractCollectionMapper<T> implements PropertyMapper { public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
protected final CommonCollectionMapperData commonCollectionMapperData; protected final CommonCollectionMapperData commonCollectionMapperData;
protected final Class<? extends T> collectionClass; protected final Class<? extends T> collectionClass;
protected final boolean ordinalInId; protected final boolean ordinalInId;
protected final boolean revisionTypeInId; protected final boolean revisionTypeInId;
private final Constructor<? extends T> proxyConstructor; private final Constructor<? extends T> proxyConstructor;
protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, protected AbstractCollectionMapper(
CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass, boolean ordinalInId, Class<? extends T> collectionClass, Class<? extends T> proxyClass, boolean ordinalInId,
boolean revisionTypeInId) { boolean revisionTypeInId) {
this.commonCollectionMapperData = commonCollectionMapperData; this.commonCollectionMapperData = commonCollectionMapperData;
this.collectionClass = collectionClass; this.collectionClass = collectionClass;
this.ordinalInId = ordinalInId; this.ordinalInId = ordinalInId;
this.revisionTypeInId = revisionTypeInId; this.revisionTypeInId = revisionTypeInId;
try { try {
proxyConstructor = proxyClass.getConstructor(Initializor.class); proxyConstructor = proxyClass.getConstructor( Initializor.class );
} catch (NoSuchMethodException e) { }
throw new AuditException(e); catch (NoSuchMethodException e) {
} throw new AuditException( e );
} }
}
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection); protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
protected abstract Collection getOldCollectionContent(Serializable oldCollection);
/** protected abstract Collection getOldCollectionContent(Serializable oldCollection);
* Maps the changed collection element to the given map.
/**
* Maps the changed collection element to the given map.
*
* @param idData Map to which composite-id data should be added. * @param idData Map to which composite-id data should be added.
* @param data Where to map the data. * @param data Where to map the data.
* @param changed The changed collection element to map. * @param changed The changed collection element to map.
*/ */
protected abstract void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed); protected abstract void mapToMapFromObject(
SessionImplementor session,
Map<String, Object> idData,
Map<String, Object> data,
Object changed);
/** /**
* Creates map for storing identifier data. Ordinal parameter guarantees uniqueness of primary key. * Creates map for storing identifier data. Ordinal parameter guarantees uniqueness of primary key.
* Composite primary key cannot contain embeddable properties since they might be nullable. * Composite primary key cannot contain embeddable properties since they might be nullable.
*
* @param ordinal Iteration ordinal. * @param ordinal Iteration ordinal.
*
* @return Map for holding identifier data. * @return Map for holding identifier data.
*/ */
protected Map<String, Object> createIdMap(int ordinal) { protected Map<String, Object> createIdMap(int ordinal) {
@ -100,79 +110,113 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
return idMap; return idMap;
} }
private void addCollectionChanges(SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges, private void addCollectionChanges(
Set<Object> changed, RevisionType revisionType, Serializable id) { SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
Set<Object> changed, RevisionType revisionType, Serializable id) {
int ordinal = 0; int ordinal = 0;
for (Object changedObj : changed) { for ( Object changedObj : changed ) {
Map<String, Object> entityData = new HashMap<String, Object>(); final Map<String, Object> entityData = new HashMap<String, Object>();
Map<String, Object> originalId = createIdMap( ordinal++ ); final Map<String, Object> originalId = createIdMap( ordinal++ );
entityData.put(commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId); entityData.put( commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId );
collectionChanges.add(new PersistentCollectionChangeData( collectionChanges.add(
commonCollectionMapperData.getVersionsMiddleEntityName(), entityData, changedObj)); new PersistentCollectionChangeData(
// Mapping the collection owner's id. commonCollectionMapperData.getVersionsMiddleEntityName(), entityData, changedObj
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId(originalId, id); )
);
// Mapping the collection owner's id.
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId( originalId, id );
// Mapping collection element and index (if present). // Mapping collection element and index (if present).
mapToMapFromObject(session, originalId, entityData, changedObj); mapToMapFromObject( session, originalId, entityData, changedObj );
(revisionTypeInId ? originalId : entityData).put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType); (revisionTypeInId ? originalId : entityData).put(
} commonCollectionMapperData.getVerEntCfg()
} .getRevisionTypePropName(), revisionType
);
@SuppressWarnings({"unchecked"}) }
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, }
String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(referencingPropertyName)) {
return null;
}
List<PersistentCollectionChangeData> collectionChanges = new ArrayList<PersistentCollectionChangeData>();
// Comparing new and old collection content.
Collection newCollection = getNewCollectionContent(newColl);
Collection oldCollection = getOldCollectionContent(oldColl);
Set<Object> added = new HashSet<Object>();
if (newColl != null) { added.addAll(newCollection); }
// Re-hashing the old collection as the hash codes of the elements there may have changed, and the
// removeAll in AbstractSet has an implementation that is hashcode-change sensitive (as opposed to addAll).
if (oldColl != null) { added.removeAll(new HashSet(oldCollection)); }
addCollectionChanges(session, collectionChanges, added, RevisionType.ADD, id);
Set<Object> deleted = new HashSet<Object>();
if (oldColl != null) { deleted.addAll(oldCollection); }
// The same as above - re-hashing new collection.
if (newColl != null) { deleted.removeAll(new HashSet(newCollection)); }
addCollectionChanges(session, collectionChanges, deleted, RevisionType.DEL, id);
return collectionChanges;
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
// Changes are mapped in the "mapCollectionChanges" method.
return false;
}
@Override @Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) { @SuppressWarnings({"unchecked"})
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData(); public List<PersistentCollectionChangeData> mapCollectionChanges(
if (propertyData.isUsingModifiedFlag()) { SessionImplementor session,
if (isNotPersistentCollection(newObj) || isNotPersistentCollection(oldObj)) { String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
if ( !commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(
referencingPropertyName
) ) {
return null;
}
final List<PersistentCollectionChangeData> collectionChanges = new ArrayList<PersistentCollectionChangeData>();
// Comparing new and old collection content.
final Collection newCollection = getNewCollectionContent( newColl );
final Collection oldCollection = getOldCollectionContent( oldColl );
final Set<Object> added = new HashSet<Object>();
if ( newColl != null ) {
added.addAll( newCollection );
}
// Re-hashing the old collection as the hash codes of the elements there may have changed, and the
// removeAll in AbstractSet has an implementation that is hashcode-change sensitive (as opposed to addAll).
if ( oldColl != null ) {
added.removeAll( new HashSet( oldCollection ) );
}
addCollectionChanges( session, collectionChanges, added, RevisionType.ADD, id );
final Set<Object> deleted = new HashSet<Object>();
if ( oldColl != null ) {
deleted.addAll( oldCollection );
}
// The same as above - re-hashing new collection.
if ( newColl != null ) {
deleted.removeAll( new HashSet( newCollection ) );
}
addCollectionChanges( session, collectionChanges, deleted, RevisionType.DEL, id );
return collectionChanges;
}
@Override
public boolean mapToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
// Changes are mapped in the "mapCollectionChanges" method.
return false;
}
@Override
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
final PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
if ( propertyData.isUsingModifiedFlag() ) {
if ( isNotPersistentCollection( newObj ) || isNotPersistentCollection( oldObj ) ) {
// Compare POJOs. // Compare POJOs.
data.put(propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual(newObj, oldObj)); data.put( propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual( newObj, oldObj ) );
} else if (isFromNullToEmptyOrFromEmptyToNull((PersistentCollection) newObj, (Serializable) oldObj)) { }
data.put(propertyData.getModifiedFlagPropertyName(), true); else if ( isFromNullToEmptyOrFromEmptyToNull( (PersistentCollection) newObj, (Serializable) oldObj ) ) {
} else { data.put( propertyData.getModifiedFlagPropertyName(), true );
List<PersistentCollectionChangeData> changes = mapCollectionChanges(session, }
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(), else {
(PersistentCollection) newObj, (Serializable) oldObj, null); final List<PersistentCollectionChangeData> changes = mapCollectionChanges(
data.put(propertyData.getModifiedFlagPropertyName(), !changes.isEmpty()); session,
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
(PersistentCollection) newObj,
(Serializable) oldObj,
null
);
data.put( propertyData.getModifiedFlagPropertyName(), !changes.isEmpty() );
} }
} }
} }
@ -183,8 +227,8 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
private boolean isFromNullToEmptyOrFromEmptyToNull(PersistentCollection newColl, Serializable oldColl) { private boolean isFromNullToEmptyOrFromEmptyToNull(PersistentCollection newColl, Serializable oldColl) {
// Comparing new and old collection content. // Comparing new and old collection content.
Collection newCollection = getNewCollectionContent(newColl); final Collection newCollection = getNewCollectionContent( newColl );
Collection oldCollection = getOldCollectionContent(oldColl); final Collection oldCollection = getOldCollectionContent( oldColl );
return oldCollection == null && newCollection != null && newCollection.isEmpty() return oldCollection == null && newCollection != null && newCollection.isEmpty()
|| newCollection == null && oldCollection != null && oldCollection.isEmpty(); || newCollection == null && oldCollection != null && oldCollection.isEmpty();
@ -192,36 +236,53 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
@Override @Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) { public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData(); final PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
if (propertyData.isUsingModifiedFlag()) { if ( propertyData.isUsingModifiedFlag() ) {
data.put(propertyData.getModifiedFlagPropertyName(), propertyData.getName().equals(collectionPropertyName)); data.put(
propertyData.getModifiedFlagPropertyName(),
propertyData.getName().equals( collectionPropertyName )
);
} }
} }
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg, protected abstract Initializor<T> getInitializor(
AuditReaderImplementor versionsReader, Object primaryKey, AuditConfiguration verCfg,
Number revision, boolean removed); AuditReaderImplementor versionsReader, Object primaryKey,
Number revision, boolean removed);
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, @Override
AuditReaderImplementor versionsReader, Number revision) { public void mapToEntityFromMap(
Setter setter = ReflectionTools.getSetter(obj.getClass(), commonCollectionMapperData.getCollectionReferencingPropertyData()); AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
try { AuditReaderImplementor versionsReader, Number revision) {
final Setter setter = ReflectionTools.getSetter(
obj.getClass(),
commonCollectionMapperData.getCollectionReferencingPropertyData()
);
try {
setter.set( setter.set(
obj, obj,
proxyConstructor.newInstance( proxyConstructor.newInstance(
getInitializor( getInitializor(
verCfg, versionsReader, primaryKey, revision, verCfg, versionsReader, primaryKey, revision,
RevisionType.DEL.equals( data.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) ) RevisionType.DEL.equals(
data.get(
verCfg.getAuditEntCfg()
.getRevisionTypePropName()
)
)
) )
), ),
null null
); );
} catch (InstantiationException e) { }
throw new AuditException(e); catch (InstantiationException e) {
} catch (IllegalAccessException e) { throw new AuditException( e );
throw new AuditException(e); }
} catch (InvocationTargetException e) { catch (IllegalAccessException e) {
throw new AuditException(e); throw new AuditException( e );
} }
} catch (InvocationTargetException e) {
throw new AuditException( e );
}
}
} }

View File

@ -1,8 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.internal.entities.mapper.relation; package org.hibernate.envers.internal.entities.mapper.relation;
import javax.persistence.NoResultException;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
import javax.persistence.NoResultException;
import org.hibernate.NonUniqueResultException; import org.hibernate.NonUniqueResultException;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
@ -13,54 +36,69 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
/** /**
* Template class for property mappers that manage one-to-one relation. * Template class for property mappers that manage one-to-one relation.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public abstract class AbstractOneToOneMapper extends AbstractToOneMapper { public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
private final String entityName; private final String entityName;
private final String referencedEntityName; private final String referencedEntityName;
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) { protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
super(propertyData); super( propertyData );
this.entityName = entityName; this.entityName = entityName;
this.referencedEntityName = referencedEntityName; this.referencedEntityName = referencedEntityName;
} }
@Override @Override
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, public void nullSafeMapToEntityFromMap(
AuditReaderImplementor versionsReader, Number revision) { AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
EntityInfo referencedEntity = getEntityInfo(verCfg, referencedEntityName); AuditReaderImplementor versionsReader, Number revision) {
final EntityInfo referencedEntity = getEntityInfo( verCfg, referencedEntityName );
Object value = null; Object value;
try { try {
value = queryForReferencedEntity(versionsReader, referencedEntity, (Serializable) primaryKey, revision); value = queryForReferencedEntity( versionsReader, referencedEntity, (Serializable) primaryKey, revision );
} catch (NoResultException e) { }
value = null; catch (NoResultException e) {
} catch (NonUniqueResultException e) { value = null;
throw new AuditException("Many versions results for one-to-one relationship " + entityName + }
"." + getPropertyData().getBeanName() + ".", e); catch (NonUniqueResultException e) {
} throw new AuditException(
"Many versions results for one-to-one relationship " + entityName +
"." + getPropertyData().getBeanName() + ".", e
);
}
setPropertyValue(obj, value); setPropertyValue( obj, value );
} }
/** /**
* @param versionsReader Audit reader. * @param versionsReader Audit reader.
* @param referencedEntity Referenced entity descriptor. * @param referencedEntity Referenced entity descriptor.
* @param primaryKey Referenced entity identifier. * @param primaryKey Referenced entity identifier.
* @param revision Revision number. * @param revision Revision number.
* @return Referenced object or proxy of one-to-one relation. *
*/ * @return Referenced object or proxy of one-to-one relation.
protected abstract Object queryForReferencedEntity(AuditReaderImplementor versionsReader, EntityInfo referencedEntity, */
Serializable primaryKey, Number revision); protected abstract Object queryForReferencedEntity(
AuditReaderImplementor versionsReader, EntityInfo referencedEntity,
Serializable primaryKey, Number revision);
@Override @Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) { public void mapModifiedFlagsToMapFromEntity(
} SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
}
@Override @Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) { public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
if (getPropertyData().isUsingModifiedFlag()) { if ( getPropertyData().isUsingModifiedFlag() ) {
data.put(getPropertyData().getModifiedFlagPropertyName(), collectionPropertyName.equals(getPropertyData().getName())); data.put(
} getPropertyData().getModifiedFlagPropertyName(),
} collectionPropertyName.equals( getPropertyData().getName() )
);
}
}
} }

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.internal.entities.mapper.relation; package org.hibernate.envers.internal.entities.mapper.relation;
import java.io.Serializable; import java.io.Serializable;
@ -17,87 +40,109 @@ import org.hibernate.property.Setter;
/** /**
* Base class for property mappers that manage to-one relation. * Base class for property mappers that manage to-one relation.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public abstract class AbstractToOneMapper implements PropertyMapper { public abstract class AbstractToOneMapper implements PropertyMapper {
private final PropertyData propertyData; private final PropertyData propertyData;
protected AbstractToOneMapper(PropertyData propertyData) { protected AbstractToOneMapper(PropertyData propertyData) {
this.propertyData = propertyData; this.propertyData = propertyData;
} }
@Override @Override
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) { public boolean mapToMapFromEntity(
return false; SessionImplementor session,
} Map<String, Object> data,
Object newObj,
Object oldObj) {
return false;
}
@Override @Override
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, public void mapToEntityFromMap(
AuditReaderImplementor versionsReader, Number revision) { AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
if (obj != null) { AuditReaderImplementor versionsReader, Number revision) {
nullSafeMapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision); if ( obj != null ) {
} nullSafeMapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
} }
}
@Override @Override
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(
PersistentCollection newColl, Serializable oldColl, SessionImplementor session, String referencingPropertyName,
Serializable id) { PersistentCollection newColl, Serializable oldColl,
return null; Serializable id) {
} return null;
}
/** /**
* @param verCfg Audit configuration. * @param verCfg Audit configuration.
* @param entityName Entity name. * @param entityName Entity name.
* @return Entity class, name and information whether it is audited or not. *
*/ * @return Entity class, name and information whether it is audited or not.
protected EntityInfo getEntityInfo(AuditConfiguration verCfg, String entityName) { */
EntityConfiguration entCfg = verCfg.getEntCfg().get(entityName); protected EntityInfo getEntityInfo(AuditConfiguration verCfg, String entityName) {
boolean isRelationAudited = true; EntityConfiguration entCfg = verCfg.getEntCfg().get( entityName );
if (entCfg == null) { boolean isRelationAudited = true;
// a relation marked as RelationTargetAuditMode.NOT_AUDITED if ( entCfg == null ) {
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName); // a relation marked as RelationTargetAuditMode.NOT_AUDITED
isRelationAudited = false; entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
} isRelationAudited = false;
Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() ); }
return new EntityInfo(entityClass, entityName, isRelationAudited); final Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
} return new EntityInfo( entityClass, entityName, isRelationAudited );
}
protected void setPropertyValue(Object targetObject, Object value) { protected void setPropertyValue(Object targetObject, Object value) {
Setter setter = ReflectionTools.getSetter(targetObject.getClass(), propertyData); final Setter setter = ReflectionTools.getSetter( targetObject.getClass(), propertyData );
setter.set(targetObject, value, null); setter.set( targetObject, value, null );
} }
/** /**
* @return Bean property that represents the relation. * @return Bean property that represents the relation.
*/ */
protected PropertyData getPropertyData() { protected PropertyData getPropertyData() {
return propertyData; return propertyData;
} }
/** /**
* Parameter {@code obj} is never {@code null}. * Parameter {@code obj} is never {@code null}.
* @see PropertyMapper#mapToEntityFromMap(AuditConfiguration, Object, Map, Object, AuditReaderImplementor, Number) *
*/ * @see PropertyMapper#mapToEntityFromMap(AuditConfiguration, Object, Map, Object, AuditReaderImplementor, Number)
public abstract void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, */
AuditReaderImplementor versionsReader, Number revision); public abstract void nullSafeMapToEntityFromMap(
AuditConfiguration verCfg,
Object obj,
Map data,
Object primaryKey,
AuditReaderImplementor versionsReader,
Number revision);
/** /**
* Simple descriptor of an entity. * Simple descriptor of an entity.
*/ */
protected class EntityInfo { protected class EntityInfo {
private final Class entityClass; private final Class entityClass;
private final String entityName; private final String entityName;
private final boolean audited; private final boolean audited;
public EntityInfo(Class entityClass, String entityName, boolean audited) { public EntityInfo(Class entityClass, String entityName, boolean audited) {
this.entityClass = entityClass; this.entityClass = entityClass;
this.entityName = entityName; this.entityName = entityName;
this.audited = audited; this.audited = audited;
} }
public Class getEntityClass() { return entityClass; } public Class getEntityClass() {
public String getEntityName() { return entityName; } return entityClass;
public boolean isAudited() { return audited; } }
}
public String getEntityName() {
return entityName;
}
public boolean isAudited() {
return audited;
}
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -39,36 +39,50 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class BasicCollectionMapper<T extends Collection> extends AbstractCollectionMapper<T> implements PropertyMapper { public class BasicCollectionMapper<T extends Collection> extends AbstractCollectionMapper<T> implements PropertyMapper {
protected final MiddleComponentData elementComponentData; protected final MiddleComponentData elementComponentData;
public BasicCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, public BasicCollectionMapper(
CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass, Class<? extends T> collectionClass, Class<? extends T> proxyClass,
MiddleComponentData elementComponentData, boolean ordinalInId, boolean revisionTypeInId) { MiddleComponentData elementComponentData, boolean ordinalInId, boolean revisionTypeInId) {
super( commonCollectionMapperData, collectionClass, proxyClass, ordinalInId, revisionTypeInId ); super( commonCollectionMapperData, collectionClass, proxyClass, ordinalInId, revisionTypeInId );
this.elementComponentData = elementComponentData; this.elementComponentData = elementComponentData;
} }
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader, @Override
Object primaryKey, Number revision, boolean removed) { protected Initializor<T> getInitializor(
return new BasicCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(), AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
primaryKey, revision, removed, collectionClass, elementComponentData); Object primaryKey, Number revision, boolean removed) {
} return new BasicCollectionInitializor<T>(
verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, removed, collectionClass, elementComponentData
);
}
protected Collection getNewCollectionContent(PersistentCollection newCollection) { @Override
return (Collection) newCollection; protected Collection getNewCollectionContent(PersistentCollection newCollection) {
} return (Collection) newCollection;
}
protected Collection getOldCollectionContent(Serializable oldCollection) { @Override
if (oldCollection == null) { protected Collection getOldCollectionContent(Serializable oldCollection) {
return null; if ( oldCollection == null ) {
} else if (oldCollection instanceof Map) { return null;
return ((Map) oldCollection).keySet(); }
} else { else if ( oldCollection instanceof Map ) {
return (Collection) oldCollection; return ((Map) oldCollection).keySet();
} }
} else {
return (Collection) oldCollection;
}
}
protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) { @Override
elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, changed); protected void mapToMapFromObject(
} SessionImplementor session,
Map<String, Object> idData,
Map<String, Object> data,
Object changed) {
elementComponentData.getComponentMapper().mapToMapFromObject( session, idData, data, changed );
}
} }

Some files were not shown because too many files have changed in this diff Show More