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

View File

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

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;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.persistence.MappedSuperclass;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
@ -10,43 +33,44 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* The {@code AuditingOverride} annotation is used to override the auditing
* behavior of a superclass or single property inherited from {@link MappedSuperclass}
* behavior of a superclass or single property inherited from {@link javax.persistence.MappedSuperclass}
* type, or attribute inside an embedded component.
*
* @author Erik-Berndt Scheper
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*
* @see javax.persistence.Embedded
* @see javax.persistence.Embeddable
* @see javax.persistence.MappedSuperclass
* @see javax.persistence.AssociationOverride
* @see AuditJoinTable
*/
@Target({ TYPE, METHOD, FIELD })
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface AuditOverride {
/**
* @return Name of the field (or property) whose mapping is being overridden. Allows empty value if
* Name of the field (or property) whose mapping is being overridden. Allows empty value if
* {@link AuditOverride} is used to change auditing behavior of all attributes inherited from
* {@link MappedSuperclass} type.
* {@link javax.persistence.MappedSuperclass} type.
*/
String name() default "";
/**
* @return Indicates if the field (or property) is audited; defaults to {@code true}.
* Indicates if the field (or property) is audited; defaults to {@code true}.
*/
boolean isAudited() default true;
/**
* @return New {@link AuditJoinTable} used for this field (or property). Its value
* New {@link AuditJoinTable} used for this field (or property). Its value
* is ignored if {@link #isAudited()} equals to {@code false}.
*/
AuditJoinTable auditJoinTable() default @AuditJoinTable;
/**
* @return Specifies class which field (or property) mapping is being overridden. <strong>Required</strong> if
* {@link AuditOverride} is used to change auditing behavior of attributes inherited from {@link MappedSuperclass}
* type.
* Specifies class which field (or property) mapping is being overridden. <strong>Required</strong> if
* {@link AuditOverride} is used to change auditing behavior of attributes inherited from
* {@link javax.persistence.MappedSuperclass} type.
*/
Class forClass() default void.class;
}

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;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@ -21,11 +45,11 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* @see AuditJoinTable
* @see AuditOverride
*/
@Target({ TYPE, METHOD, FIELD })
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface AuditOverrides {
/**
* @return An array of {@link AuditOverride} values, to define the new auditing
* An array of {@link AuditOverride} values, to define the new auditing
* behavior.
*/
AuditOverride[] value();

View File

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

View File

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

View File

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

View File

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

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;
import java.util.List;
@ -10,52 +33,67 @@ import org.hibernate.envers.tools.Pair;
* Queries that allow retrieving snapshots of all entities (regardless of their particular type) changed in the given
* revision. Note that this API can be legally used only when default mechanism of tracking modified entity names
* is enabled.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public interface CrossTypeRevisionChangesReader {
/**
* Find all entities changed (added, updated and removed) in a given revision. Executes <i>n+1</i> SQL queries,
* where <i>n</i> is a number of different entity classes modified within specified revision.
* @param revision Revision number.
* @return Snapshots of all audited entities changed in a given revision.
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
*/
public List<Object> findEntities(Number revision) throws IllegalStateException, IllegalArgumentException;
/**
* Find all entities changed (added, updated and removed) in a given revision. Executes <i>n+1</i> SQL queries,
* where <i>n</i> is a number of different entity classes modified within specified revision.
*
* @param revision Revision number.
*
* @return Snapshots of all audited entities changed in a given revision.
*
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
*/
public List<Object> findEntities(Number revision) throws IllegalStateException, IllegalArgumentException;
/**
* Find all entities changed (added, updated or removed) in a given revision. Executes <i>n+1</i> SQL queries,
* where <i>n</i> is a number of different entity classes modified within specified revision.
* @param revision Revision number.
* @param revisionType Type of modification.
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public List<Object> findEntities(Number revision, RevisionType revisionType) throws IllegalStateException,
IllegalArgumentException;
/**
* Find all entities changed (added, updated or removed) in a given revision. Executes <i>n+1</i> SQL queries,
* where <i>n</i> is a number of different entity classes modified within specified revision.
*
* @param revision Revision number.
* @param revisionType Type of modification.
*
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
*
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public List<Object> findEntities(Number revision, RevisionType revisionType) throws IllegalStateException,
IllegalArgumentException;
/**
* Find all entities changed (added, updated and removed) in a given revision grouped by modification type.
* Executes <i>mn+1</i> SQL queries, where:
* <ul>
* <li><i>n</i> - number of different entity classes modified within specified revision.
* <li><i>m</i> - number of different revision types. See {@link RevisionType} enum.
* </ul>
* @param revision Revision number.
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public Map<RevisionType, List<Object>> findEntitiesGroupByRevisionType(Number revision) throws IllegalStateException,
IllegalArgumentException;
/**
* Find all entities changed (added, updated and removed) in a given revision grouped by modification type.
* Executes <i>mn+1</i> SQL queries, where:
* <ul>
* <li><i>n</i> - number of different entity classes modified within specified revision.
* <li><i>m</i> - number of different revision types. See {@link RevisionType} enum.
* </ul>
*
* @param revision Revision number.
*
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
*
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public Map<RevisionType, List<Object>> findEntitiesGroupByRevisionType(Number revision)
throws IllegalStateException,
IllegalArgumentException;
/**
* Returns set of entity names and corresponding Java classes modified in a given revision.
* @param revision Revision number.
* @return Set of entity names and corresponding Java classes modified in a given revision.
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public Set<Pair<String, Class>> findEntityTypes(Number revision) throws IllegalStateException, IllegalArgumentException;
/**
* Returns set of entity names and corresponding Java classes modified in a given revision.
*
* @param revision Revision number.
*
* @return Set of entity names and corresponding Java classes modified in a given revision.
*
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
*/
public Set<Pair<String, Class>> findEntityTypes(Number revision)
throws IllegalStateException, IllegalArgumentException;
}

View File

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

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;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.MappedSuperclass;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
@ -16,45 +39,57 @@ import org.hibernate.annotations.FetchMode;
* Extension of standard {@link DefaultRevisionEntity} that allows tracking entity names changed in each revision.
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN)
@ModifiedEntityNames
private Set<String> modifiedEntityNames = new HashSet<String>();
@ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN)
@ModifiedEntityNames
private Set<String> modifiedEntityNames = new HashSet<String>();
public Set<String> getModifiedEntityNames() {
return modifiedEntityNames;
}
public Set<String> getModifiedEntityNames() {
return modifiedEntityNames;
}
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
this.modifiedEntityNames = modifiedEntityNames;
}
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
this.modifiedEntityNames = modifiedEntityNames;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity)) return false;
if (!super.equals(o)) return false;
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( !(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity) ) {
return false;
}
if ( !super.equals( o ) ) {
return false;
}
DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
final DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames)
: that.modifiedEntityNames != null) return false;
if ( modifiedEntityNames != null ? !modifiedEntityNames.equals( that.modifiedEntityNames )
: that.modifiedEntityNames != null ) {
return false;
}
return true;
}
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
return result;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
return result;
}
public String toString() {
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
}
@Override
public String toString() {
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
}
}

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;
import java.io.Serializable;
@ -5,19 +28,22 @@ import java.io.Serializable;
/**
* Extension of standard {@link RevisionListener} that notifies whenever an entity instance has been
* added, modified or removed within current revision boundaries.
* @see RevisionListener
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @see RevisionListener
*/
public interface EntityTrackingRevisionListener extends RevisionListener {
/**
* Called after audited entity data has been persisted.
* @param entityClass Audited entity class.
* @param entityName Name of the audited entity. May be useful when Java class is mapped multiple times,
* potentially to different tables.
* @param entityId Identifier of modified entity.
* @param revisionType Modification type (addition, update or removal).
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}.
*/
void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity);
/**
* Called after audited entity data has been persisted.
*
* @param entityClass Audited entity class.
* @param entityName Name of the audited entity. May be useful when Java class is mapped multiple times,
* potentially to different tables.
* @param entityId Identifier of modified entity.
* @param revisionType Modification type (addition, update or removal).
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}.
*/
void entityChanged(
Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity);
}

View File

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

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;
import java.lang.annotation.ElementType;
@ -8,6 +31,7 @@ import java.lang.annotation.Target;
/**
* Marks a property which holds entity names that have been modified during each revision.
* This annotation expects field of <code>{@literal Set<String>}</code> type.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Retention(RetentionPolicy.RUNTIME)

View File

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

View File

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

View File

@ -40,9 +40,9 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RevisionEntity {
/**
* @return The optional listener that will be used to fill in the custom revision entity.
* May also be specified using the {@code org.hibernate.envers.revision_listener} configuration property.
*/
Class<? extends RevisionListener> value() default RevisionListener.class;
/**
* The optional listener that will be used to fill in the custom revision entity.
* May also be specified using the {@code org.hibernate.envers.revision_listener} configuration property.
*/
Class<? extends RevisionListener> value() default RevisionListener.class;
}

View File

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

View File

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

View File

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

View File

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

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;
import org.hibernate.envers.strategy.DefaultAuditStrategy;
/**
* Configuration property names.
*
@ -69,7 +90,7 @@ public interface EnversSettings {
public static final String AUDIT_TABLE_SUFFIX = "org.hibernate.envers.audit_table_suffix";
/**
* Audit strategy. Defaults to {@link DefaultAuditStrategy}.
* Audit strategy. Defaults to {@link org.hibernate.envers.strategy.DefaultAuditStrategy}.
*/
public static final String AUDIT_STRATEGY = "org.hibernate.envers.audit_strategy";

View File

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

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;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
@ -15,84 +39,100 @@ import org.hibernate.mapping.PersistentClass;
/**
* A helper class holding auditing meta-data for all persistent classes.
*
* @author Adam Warski (adam at warski dot org)
*/
public class ClassesAuditingData {
private static final EnversMessageLogger LOG = Logger.getMessageLogger(
EnversMessageLogger.class,
ClassesAuditingData.class.getName()
);
public static final EnversMessageLogger LOG = Logger.getMessageLogger(EnversMessageLogger.class, ClassesAuditingData.class.getName());
private final Map<String, ClassAuditingData> entityNameToAuditingData = new HashMap<String, ClassAuditingData>();
private final Map<PersistentClass, ClassAuditingData> persistentClassToAuditingData = new LinkedHashMap<PersistentClass, ClassAuditingData>();
private final Map<String, ClassAuditingData> entityNameToAuditingData = new HashMap<String, ClassAuditingData>();
private final Map<PersistentClass, ClassAuditingData> persistentClassToAuditingData = new LinkedHashMap<PersistentClass, ClassAuditingData>();
/**
* Stores information about auditing meta-data for the given class.
*
* @param pc Persistent class.
* @param cad Auditing meta-data for the given class.
*/
public void addClassAuditingData(PersistentClass pc, ClassAuditingData cad) {
entityNameToAuditingData.put( pc.getEntityName(), cad );
persistentClassToAuditingData.put( pc, cad );
}
/**
* Stores information about auditing meta-data for the given class.
* @param pc Persistent class.
* @param cad Auditing meta-data for the given class.
*/
public void addClassAuditingData(PersistentClass pc, ClassAuditingData cad) {
entityNameToAuditingData.put(pc.getEntityName(), cad);
persistentClassToAuditingData.put(pc, cad);
}
/**
* @return A collection of all auditing meta-data for persistent classes.
*/
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
return persistentClassToAuditingData.entrySet();
}
/**
* @return A collection of all auditing meta-data for persistent classes.
*/
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
return persistentClassToAuditingData.entrySet();
}
/**
* @param entityName Name of the entity.
*
* @return Auditing meta-data for the given entity.
*/
public ClassAuditingData getClassAuditingData(String entityName) {
return entityNameToAuditingData.get( entityName );
}
/**
* @param entityName Name of the entity.
* @return Auditing meta-data for the given entity.
*/
public ClassAuditingData getClassAuditingData(String entityName) {
return entityNameToAuditingData.get(entityName);
}
/**
* After all meta-data is read, updates calculated fields. This includes:
* <ul>
* <li>setting {@code forceInsertable} to {@code true} for properties specified by {@code @AuditMappedBy}</li>
* </ul>
*/
public void updateCalculatedFields() {
for ( Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet() ) {
final PersistentClass pc = classAuditingDataEntry.getKey();
final ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
for ( String propertyName : classAuditingData.getPropertyNames() ) {
final PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData( propertyName );
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
if ( propertyAuditingData.getAuditMappedBy() != null ) {
final String referencedEntityName = MappingTools.getReferencedEntityName(
pc.getProperty( propertyName ).getValue()
);
/**
* After all meta-data is read, updates calculated fields. This includes:
* <ul>
* <li>setting {@code forceInsertable} to {@code true} for properties specified by {@code @AuditMappedBy}</li>
* </ul>
*/
public void updateCalculatedFields() {
for (Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet()) {
PersistentClass pc = classAuditingDataEntry.getKey();
ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
for (String propertyName : classAuditingData.getPropertyNames()) {
PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData(propertyName);
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
if (propertyAuditingData.getAuditMappedBy() != null) {
String referencedEntityName = MappingTools.getReferencedEntityName(pc.getProperty(propertyName).getValue());
final ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get( referencedEntityName );
ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get(referencedEntityName);
forcePropertyInsertable(
referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
pc.getEntityName(), referencedEntityName
);
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
pc.getEntityName(), referencedEntityName);
forcePropertyInsertable(
referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
pc.getEntityName(), referencedEntityName
);
}
}
}
}
forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
pc.getEntityName(), referencedEntityName);
}
}
}
}
private void forcePropertyInsertable(
ClassAuditingData classAuditingData, String propertyName,
String entityName, String referencedEntityName) {
if ( propertyName != null ) {
if ( classAuditingData.getPropertyAuditingData( propertyName ) == null ) {
throw new MappingException(
"@AuditMappedBy points to a property that doesn't exist: " +
referencedEntityName + "." + propertyName
);
}
private void forcePropertyInsertable(ClassAuditingData classAuditingData, String propertyName,
String entityName, String referencedEntityName) {
if (propertyName != null) {
if (classAuditingData.getPropertyAuditingData(propertyName) == null) {
throw new MappingException("@AuditMappedBy points to a property that doesn't exist: " +
referencedEntityName + "." + propertyName);
}
LOG.debugf(
"Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
referencedEntityName,
propertyName,
entityName
);
LOG.debugf("Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
referencedEntityName,
propertyName,
entityName);
classAuditingData
.getPropertyAuditingData(propertyName)
.setForceInsertable(true);
}
}
classAuditingData
.getPropertyAuditingData( propertyName )
.setForceInsertable( true );
}
}
}

View File

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

View File

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

View File

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

View File

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

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;
import org.dom4j.Document;
@ -23,11 +46,12 @@ public class RevisionInfoConfigurationResult {
private final Class<?> revisionInfoClass;
private final PropertyData revisionInfoTimestampData;
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
RevisionInfoConfigurationResult(
RevisionInfoGenerator revisionInfoGenerator,
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
this.revisionInfoGenerator = revisionInfoGenerator;
this.revisionInfoXmlMapping = revisionInfoXmlMapping;
this.revisionInfoQueryCreator = revisionInfoQueryCreator;

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;
import java.util.HashSet;
import java.util.Set;
@ -6,46 +30,49 @@ import org.hibernate.MappingException;
/**
* A register of all audit entity names used so far.
*
* @author Adam Warski (adam at warski dot org)
*/
public class AuditEntityNameRegister {
private final Set<String> auditEntityNames = new HashSet<String>();
private final Set<String> auditEntityNames = new HashSet<String>();
/**
* @param auditEntityName Name of the audit entity.
* @return True if the given audit entity name is already used.
*/
private boolean check(String auditEntityName) {
return auditEntityNames.contains(auditEntityName);
}
/**
* Register an audit entity name. If the name is already registered, an exception is thrown.
* @param auditEntityName Name of the audit entity.
*/
public void register(String auditEntityName) {
if (auditEntityNames.contains(auditEntityName)) {
throw new MappingException("The audit entity name '" + auditEntityName + "' is already registered.");
}
auditEntityNames.add(auditEntityName);
}
/**
* Creates a unique (not yet registered) audit entity name by appending consecutive numbers to the base
* name. If the base name is not yet used, it is returned unmodified.
/**
* @param auditEntityName Name of the audit entity.
*
* @param baseAuditEntityName The base entity name.
*
* @return A unique audit entity name
*/
public String createUnique(final String baseAuditEntityName) {
String auditEntityName = baseAuditEntityName;
int count = 1;
while (check(auditEntityName)) {
auditEntityName = baseAuditEntityName + count++;
}
* @return True if the given audit entity name is already used.
*/
private boolean check(String auditEntityName) {
return auditEntityNames.contains( auditEntityName );
}
return auditEntityName;
}
/**
* Register an audit entity name. If the name is already registered, an exception is thrown.
*
* @param auditEntityName Name of the audit entity.
*/
public void register(String auditEntityName) {
if ( auditEntityNames.contains( auditEntityName ) ) {
throw new MappingException( "The audit entity name '" + auditEntityName + "' is already registered." );
}
auditEntityNames.add( auditEntityName );
}
/**
* Creates a unique (not yet registered) audit entity name by appending consecutive numbers to the base
* name. If the base name is not yet used, it is returned unmodified.
*
* @param baseAuditEntityName The base entity name.
*
* @return A unique audit entity name
*/
public String createUnique(final String baseAuditEntityName) {
String auditEntityName = baseAuditEntityName;
int count = 1;
while ( check( auditEntityName ) ) {
auditEntityName = baseAuditEntityName + count++;
}
return auditEntityName;
}
}

View File

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

View File

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

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;
import java.util.Iterator;
@ -14,6 +37,7 @@ import org.hibernate.mapping.Value;
/**
* Generates metadata for components.
*
* @author Adam Warski (adam at warski dot org)
*/
public final class ComponentMetadataGenerator {
@ -24,29 +48,38 @@ public final class ComponentMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
public void addComponent(Element parent, PropertyAuditingData propertyAuditingData,
Value value, CompositeMapperBuilder mapper, String entityName,
EntityXmlMappingData xmlMappingData, boolean firstPass) {
Component prop_component = (Component) value;
public void addComponent(
Element parent, PropertyAuditingData propertyAuditingData,
Value value, CompositeMapperBuilder mapper, String entityName,
EntityXmlMappingData xmlMappingData, boolean firstPass) {
final Component propComponent = (Component) value;
Class componentClass = ReflectionTools.loadClass( prop_component.getComponentClassName(), mainGenerator.getClassLoaderService() );
CompositeMapperBuilder componentMapper = mapper.addComponent( propertyAuditingData.getPropertyData(), componentClass );
final Class componentClass = ReflectionTools.loadClass(
propComponent.getComponentClassName(),
mainGenerator.getClassLoaderService()
);
final CompositeMapperBuilder componentMapper = mapper.addComponent(
propertyAuditingData.getPropertyData(),
componentClass
);
// The property auditing data must be for a component.
ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
final ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
// Adding all properties of the component
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator();
while (properties.hasNext()) {
Property property = properties.next();
final Iterator<Property> properties = (Iterator<Property>) propComponent.getPropertyIterator();
while ( properties.hasNext() ) {
final Property property = properties.next();
PropertyAuditingData componentPropertyAuditingData =
componentAuditingData.getPropertyAuditingData(property.getName());
final PropertyAuditingData componentPropertyAuditingData =
componentAuditingData.getPropertyAuditingData( property.getName() );
// Checking if that property is audited
if (componentPropertyAuditingData != null) {
mainGenerator.addValue(parent, property.getValue(), componentMapper, entityName, xmlMappingData,
componentPropertyAuditingData, property.isInsertable(), firstPass, false);
if ( componentPropertyAuditingData != null ) {
mainGenerator.addValue(
parent, property.getValue(), componentMapper, entityName, xmlMappingData,
componentPropertyAuditingData, property.isInsertable(), firstPass, false
);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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;
/**
* Implementations hold other audited properties.
*
* @author Adam Warski (adam at warski dot org)
* @author Hern&aacut;n Chanfreau
*/
public interface AuditedPropertiesHolder {
/**
* Add an audited property.
*
* @param propertyName Name of the audited property.
* @param auditingData Data for the audited property.
*/
@ -16,6 +41,7 @@ public interface AuditedPropertiesHolder {
/**
* @param propertyName Name of a property.
*
* @return Auditing data for the property.
*/
PropertyAuditingData getPropertyAuditingData(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;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collections;
@ -7,10 +34,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
@ -65,12 +88,13 @@ public class AuditedPropertiesReader {
private final Set<XClass> overriddenAuditedClasses;
private final Set<XClass> overriddenNotAuditedClasses;
public AuditedPropertiesReader(ModificationStore defaultStore,
PersistentPropertiesSource persistentPropertiesSource,
AuditedPropertiesHolder auditedPropertiesHolder,
GlobalConfiguration globalCfg,
ReflectionManager reflectionManager,
String propertyNamePrefix) {
public AuditedPropertiesReader(
ModificationStore defaultStore,
PersistentPropertiesSource persistentPropertiesSource,
AuditedPropertiesHolder auditedPropertiesHolder,
GlobalConfiguration globalCfg,
ReflectionManager reflectionManager,
String propertyNamePrefix) {
this.defaultStore = defaultStore;
this.persistentPropertiesSource = persistentPropertiesSource;
this.auditedPropertiesHolder = auditedPropertiesHolder;
@ -93,245 +117,300 @@ public class AuditedPropertiesReader {
// First reading the access types for the persistent properties.
readPersistentPropertiesAccess();
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
// of currently mapped entity or itself.
XClass clazz = persistentPropertiesSource.getXClass();
readAuditOverrides(clazz);
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
// of currently mapped entity or itself.
final XClass clazz = persistentPropertiesSource.getXClass();
readAuditOverrides( clazz );
// Adding all properties from the given class.
addPropertiesFromClass(clazz);
// Adding all properties from the given class.
addPropertiesFromClass( clazz );
}
/**
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
* using {@link AuditOverride} annotation.
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
*/
private void readAuditOverrides(XClass clazz) {
/* TODO: Code to remove with @Audited.auditParents - start. */
Audited allClassAudited = clazz.getAnnotation(Audited.class);
if (allClassAudited != null && allClassAudited.auditParents().length > 0) {
for (Class c : allClassAudited.auditParents()) {
XClass parentClass = reflectionManager.toXClass(c);
checkSuperclass(clazz, parentClass);
if (!overriddenNotAuditedClasses.contains(parentClass)) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add(parentClass);
}
}
}
/**
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
* using {@link AuditOverride} annotation.
*
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
*/
private void readAuditOverrides(XClass clazz) {
/* TODO: Code to remove with @Audited.auditParents - start. */
final Audited allClassAudited = clazz.getAnnotation( Audited.class );
if ( allClassAudited != null && allClassAudited.auditParents().length > 0 ) {
for ( Class c : allClassAudited.auditParents() ) {
final XClass parentClass = reflectionManager.toXClass( c );
checkSuperclass( clazz, parentClass );
if ( !overriddenNotAuditedClasses.contains( parentClass ) ) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add( parentClass );
}
}
}
/* TODO: Code to remove with @Audited.auditParents - finish. */
List<AuditOverride> auditOverrides = computeAuditOverrides(clazz);
for (AuditOverride auditOverride : auditOverrides) {
if (auditOverride.forClass() != void.class) {
XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass());
checkSuperclass(clazz, overrideClass);
String propertyName = auditOverride.name();
if (!StringTools.isEmpty(propertyName)) {
// Override @Audited annotation on property level.
XProperty property = getProperty(overrideClass, propertyName);
if (auditOverride.isAudited()) {
if (!overriddenNotAuditedProperties.contains(property)) {
// If the property has not been marked as not audited by the subclass.
overriddenAuditedProperties.add(property);
}
} else {
if (!overriddenAuditedProperties.contains(property)) {
// If the property has not been marked as audited by the subclass.
overriddenNotAuditedProperties.add(property);
}
}
} else {
// Override @Audited annotation on class level.
if (auditOverride.isAudited()) {
if (!overriddenNotAuditedClasses.contains(overrideClass)) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add(overrideClass);
}
} else {
if (!overriddenAuditedClasses.contains(overrideClass)) {
// If the class has not been marked as audited by the subclass.
overriddenNotAuditedClasses.add(overrideClass);
}
}
}
}
}
XClass superclass = clazz.getSuperclass();
if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) {
readAuditOverrides(superclass);
}
}
final List<AuditOverride> auditOverrides = computeAuditOverrides( clazz );
for ( AuditOverride auditOverride : auditOverrides ) {
if ( auditOverride.forClass() != void.class ) {
final XClass overrideClass = reflectionManager.toXClass( auditOverride.forClass() );
checkSuperclass( clazz, overrideClass );
final String propertyName = auditOverride.name();
if ( !StringTools.isEmpty( propertyName ) ) {
// Override @Audited annotation on property level.
final XProperty property = getProperty( overrideClass, propertyName );
if ( auditOverride.isAudited() ) {
if ( !overriddenNotAuditedProperties.contains( property ) ) {
// If the property has not been marked as not audited by the subclass.
overriddenAuditedProperties.add( property );
}
}
else {
if ( !overriddenAuditedProperties.contains( property ) ) {
// If the property has not been marked as audited by the subclass.
overriddenNotAuditedProperties.add( property );
}
}
}
else {
// Override @Audited annotation on class level.
if ( auditOverride.isAudited() ) {
if ( !overriddenNotAuditedClasses.contains( overrideClass ) ) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add( overrideClass );
}
}
else {
if ( !overriddenAuditedClasses.contains( overrideClass ) ) {
// If the class has not been marked as audited by the subclass.
overriddenNotAuditedClasses.add( overrideClass );
}
}
}
}
}
final XClass superclass = clazz.getSuperclass();
if ( !clazz.isInterface() && !Object.class.getName().equals( superclass.getName() ) ) {
readAuditOverrides( superclass );
}
}
/**
* @param clazz Source class.
* @return List of @AuditOverride annotations applied at class level.
*/
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
AuditOverrides auditOverrides = clazz.getAnnotation(AuditOverrides.class);
AuditOverride auditOverride = clazz.getAnnotation(AuditOverride.class);
if (auditOverrides == null && auditOverride != null) {
return Arrays.asList(auditOverride);
} else if (auditOverrides != null && auditOverride == null) {
return Arrays.asList(auditOverrides.value());
} else if (auditOverrides != null && auditOverride != null) {
throw new MappingException("@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
"Please revise Envers annotations applied to class " + clazz.getName() + ".");
}
return Collections.EMPTY_LIST;
}
/**
* @param clazz Source class.
*
* @return List of @AuditOverride annotations applied at class level.
*/
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
final AuditOverrides auditOverrides = clazz.getAnnotation( AuditOverrides.class );
final AuditOverride auditOverride = clazz.getAnnotation( AuditOverride.class );
if ( auditOverrides == null && auditOverride != null ) {
return Arrays.asList( auditOverride );
}
else if ( auditOverrides != null && auditOverride == null ) {
return Arrays.asList( auditOverrides.value() );
}
else if ( auditOverrides != null && auditOverride != null ) {
throw new MappingException(
"@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
"Please revise Envers annotations applied to class " + clazz.getName() + "."
);
}
return Collections.emptyList();
}
/**
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
* @param child Subclass.
* @param parent Superclass.
*/
private void checkSuperclass(XClass child, XClass parent) {
if (!parent.isAssignableFrom(child)) {
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
"Please revise Envers annotations applied to " + child.getName() + " type.");
}
}
/**
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
*
* @param child Subclass.
* @param parent Superclass.
*/
private void checkSuperclass(XClass child, XClass parent) {
if ( !parent.isAssignableFrom( child ) ) {
throw new MappingException(
"Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
"Please revise Envers annotations applied to " + child.getName() + " type."
);
}
}
/**
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
* @param clazz Class.
* @param propertyName Property name.
* @return Property object.
*/
private XProperty getProperty(XClass clazz, String propertyName) {
XProperty property = ReflectionTools.getProperty(clazz, propertyName);
if (property == null) {
throw new MappingException("Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + ".");
}
return property;
}
/**
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
*
* @param clazz Class.
* @param propertyName Property name.
*
* @return Property object.
*/
private XProperty getProperty(XClass clazz, String propertyName) {
final XProperty property = ReflectionTools.getProperty( clazz, propertyName );
if ( property == null ) {
throw new MappingException(
"Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + "."
);
}
return property;
}
private void readPersistentPropertiesAccess() {
Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
while (propertyIter.hasNext()) {
Property property = propertyIter.next();
addPersistentProperty(property);
if ("embedded".equals(property.getPropertyAccessorName()) && property.getName().equals(property.getNodeName())) {
final Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
while ( propertyIter.hasNext() ) {
final Property property = propertyIter.next();
addPersistentProperty( property );
if ( "embedded".equals( property.getPropertyAccessorName() ) && property.getName()
.equals( property.getNodeName() ) ) {
// If property name equals node name and embedded accessor type is used, processing component
// has been defined with <properties> tag. See HHH-6636 JIRA issue.
createPropertiesGroupMapping(property);
createPropertiesGroupMapping( property );
}
}
}
private void addPersistentProperty(Property property) {
if ("field".equals(property.getPropertyAccessorName())) {
fieldAccessedPersistentProperties.add(property.getName());
} else {
propertyAccessedPersistentProperties.add(property.getName());
}
}
private void addPersistentProperty(Property property) {
if ( "field".equals( property.getPropertyAccessorName() ) ) {
fieldAccessedPersistentProperties.add( property.getName() );
}
else {
propertyAccessedPersistentProperties.add( property.getName() );
}
}
private void createPropertiesGroupMapping(Property property) {
Component component = (Component) property.getValue();
Iterator<Property> componentProperties = component.getPropertyIterator();
while (componentProperties.hasNext()) {
Property componentProperty = componentProperties.next();
propertiesGroupMapping.put(componentProperty.getName(), component.getNodeName());
}
}
@SuppressWarnings("unchecked")
private void createPropertiesGroupMapping(Property property) {
final Component component = (Component) property.getValue();
final Iterator<Property> componentProperties = component.getPropertyIterator();
while ( componentProperties.hasNext() ) {
final Property componentProperty = componentProperties.next();
propertiesGroupMapping.put( componentProperty.getName(), component.getNodeName() );
}
}
/**
* @param clazz Class which properties are currently being added.
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
* checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection.
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
* {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses}
* collection, the result is also {@code null}.
*/
private Audited computeAuditConfiguration(XClass clazz) {
Audited allClassAudited = clazz.getAnnotation(Audited.class);
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
// forced by any of its child entities configuration (@AuditedOverride.forClass).
if (allClassAudited == null && overriddenAuditedClasses.contains(clazz)) {
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
// currently mapped entity.
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation(Audited.class);
if (allClassAudited == null) {
// If parent class declares @Audited on the field/property level.
allClassAudited = DEFAULT_AUDITED;
}
} else if (allClassAudited != null && overriddenNotAuditedClasses.contains(clazz)) {
return null;
}
return allClassAudited;
}
/**
* @param clazz Class which properties are currently being added.
*
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
* checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection.
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
* {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses}
* collection, the result is also {@code null}.
*/
private Audited computeAuditConfiguration(XClass clazz) {
Audited allClassAudited = clazz.getAnnotation( Audited.class );
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
// forced by any of its child entities configuration (@AuditedOverride.forClass).
if ( allClassAudited == null && overriddenAuditedClasses.contains( clazz ) ) {
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
// currently mapped entity.
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation( Audited.class );
if ( allClassAudited == null ) {
// If parent class declares @Audited on the field/property level.
allClassAudited = DEFAULT_AUDITED;
}
}
else if ( allClassAudited != null && overriddenNotAuditedClasses.contains( clazz ) ) {
return null;
}
return allClassAudited;
}
/**
* Recursively adds all audited properties of entity class and its superclasses.
* @param clazz Currently processed class.
*/
private void addPropertiesFromClass(XClass clazz) {
Audited allClassAudited = computeAuditConfiguration(clazz);
/**
* Recursively adds all audited properties of entity class and its superclasses.
*
* @param clazz Currently processed class.
*/
private void addPropertiesFromClass(XClass clazz) {
final Audited allClassAudited = computeAuditConfiguration( clazz );
//look in the class
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited);
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited);
addFromProperties(
clazz.getDeclaredProperties( "field" ),
"field",
fieldAccessedPersistentProperties,
allClassAudited
);
addFromProperties(
clazz.getDeclaredProperties( "property" ),
"property",
propertyAccessedPersistentProperties,
allClassAudited
);
if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) {
XClass superclazz = clazz.getSuperclass();
if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) {
addPropertiesFromClass(superclazz);
if ( allClassAudited != null || !auditedPropertiesHolder.isEmpty() ) {
final XClass superclazz = clazz.getSuperclass();
if ( !clazz.isInterface() && !"java.lang.Object".equals( superclazz.getName() ) ) {
addPropertiesFromClass( superclazz );
}
}
}
private void addFromProperties(Iterable<XProperty> properties, String accessType, Set<String> persistentProperties, Audited allClassAudited) {
for (XProperty property : properties) {
private void addFromProperties(
Iterable<XProperty> properties,
String accessType,
Set<String> persistentProperties,
Audited allClassAudited) {
for ( XProperty property : properties ) {
// If this is not a persistent property, with the same access type as currently checked,
// it's not audited as well.
// If the property was already defined by the subclass, is ignored by superclasses
if ((persistentProperties.contains(property.getName()) && (!auditedPropertiesHolder
.contains(property.getName())))) {
Value propertyValue = persistentPropertiesSource.getProperty(property.getName()).getValue();
if (propertyValue instanceof Component) {
this.addFromComponentProperty(property, accessType, (Component)propertyValue, allClassAudited);
} else {
this.addFromNotComponentProperty(property, accessType, allClassAudited);
if ( persistentProperties.contains( property.getName() )
&& !auditedPropertiesHolder.contains( property.getName() ) ) {
final Value propertyValue = persistentPropertiesSource.getProperty( property.getName() ).getValue();
if ( propertyValue instanceof Component ) {
this.addFromComponentProperty( property, accessType, (Component) propertyValue, allClassAudited );
}
} else if (propertiesGroupMapping.containsKey(property.getName())) {
else {
this.addFromNotComponentProperty( property, accessType, allClassAudited );
}
}
else if ( propertiesGroupMapping.containsKey( property.getName() ) ) {
// Retrieve embedded component name based on class field.
final String embeddedName = propertiesGroupMapping.get(property.getName());
if (!auditedPropertiesHolder.contains(embeddedName)) {
final String embeddedName = propertiesGroupMapping.get( property.getName() );
if ( !auditedPropertiesHolder.contains( embeddedName ) ) {
// Manage properties mapped within <properties> tag.
Value propertyValue = persistentPropertiesSource.getProperty(embeddedName).getValue();
this.addFromPropertiesGroup(embeddedName, property, accessType, (Component)propertyValue, allClassAudited);
final Value propertyValue = persistentPropertiesSource.getProperty( embeddedName ).getValue();
this.addFromPropertiesGroup(
embeddedName,
property,
accessType,
(Component) propertyValue,
allClassAudited
);
}
}
}
}
private void addFromPropertiesGroup(String embeddedName, XProperty property, String accessType, Component propertyValue,
Audited allClassAudited) {
ComponentAuditingData componentData = new ComponentAuditingData();
boolean isAudited = fillPropertyData(property, componentData, accessType, allClassAudited);
if (isAudited) {
private void addFromPropertiesGroup(
String embeddedName,
XProperty property,
String accessType,
Component propertyValue,
Audited allClassAudited) {
final ComponentAuditingData componentData = new ComponentAuditingData();
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
if ( isAudited ) {
// EntityPersister.getPropertyNames() returns name of embedded component instead of class field.
componentData.setName(embeddedName);
componentData.setName( embeddedName );
// Marking component properties as placed directly in class (not inside another component).
componentData.setBeanName(null);
componentData.setBeanName( null );
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( reflectionManager, propertyValue );
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
reflectionManager,
propertyValue
);
final AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName)
propertyNamePrefix + MappingTools.createComponentPrefix( embeddedName )
);
audPropReader.read();
auditedPropertiesHolder.addPropertyAuditingData(embeddedName, componentData);
auditedPropertiesHolder.addPropertyAuditingData( embeddedName, componentData );
}
}
private void addFromComponentProperty(XProperty property, String accessType, Component propertyValue, Audited allClassAudited) {
ComponentAuditingData componentData = new ComponentAuditingData();
boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
private void addFromComponentProperty(
XProperty property,
String accessType,
Component propertyValue,
Audited allClassAudited) {
final ComponentAuditingData componentData = new ComponentAuditingData();
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
if ( propertyValue.isDynamic() ) {
if ( isAudited ) {
@ -343,12 +422,16 @@ public class AuditedPropertiesReader {
return;
}
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
final PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
reflectionManager, propertyValue
);
ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
final ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
ModificationStore.FULL,
componentPropertiesSource,
componentData,
globalCfg,
reflectionManager,
propertyNamePrefix + MappingTools.createComponentPrefix( property.getName() )
);
audPropReader.read();
@ -359,85 +442,102 @@ public class AuditedPropertiesReader {
}
}
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited){
PropertyAuditingData propertyData = new PropertyAuditingData();
boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited);
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited) {
final PropertyAuditingData propertyData = new PropertyAuditingData();
final boolean isAudited = fillPropertyData( property, propertyData, accessType, allClassAudited );
if (isAudited) {
if ( isAudited ) {
// Now we know that the property is audited
auditedPropertiesHolder.addPropertyAuditingData(property.getName(), propertyData);
auditedPropertiesHolder.addPropertyAuditingData( property.getName(), propertyData );
}
}
/**
* Checks if a property is audited and if yes, fills all of its data.
*
* @param property Property to check.
* @param propertyData Property data, on which to set this property's modification store.
* @param accessType Access type for the property.
*
* @return False if this property is not audited.
*/
private boolean fillPropertyData(XProperty property, PropertyAuditingData propertyData,
String accessType, Audited allClassAudited) {
private boolean fillPropertyData(
XProperty property,
PropertyAuditingData propertyData,
String accessType,
Audited allClassAudited) {
// check if a property is declared as not audited to exclude it
// useful if a class is audited but some properties should be excluded
NotAudited unVer = property.getAnnotation(NotAudited.class);
if ((unVer != null && !overriddenAuditedProperties.contains(property)) || overriddenNotAuditedProperties.contains(property)) {
final NotAudited unVer = property.getAnnotation( NotAudited.class );
if ( (unVer != null
&& !overriddenAuditedProperties.contains( property ))
|| overriddenNotAuditedProperties.contains( property ) ) {
return false;
} else {
}
else {
// if the optimistic locking field has to be unversioned and the current property
// is the optimistic locking field, don't audit it
if (globalCfg.isDoNotAuditOptimisticLockingField()) {
Version jpaVer = property.getAnnotation(Version.class);
if (jpaVer != null) {
if ( globalCfg.isDoNotAuditOptimisticLockingField() ) {
final Version jpaVer = property.getAnnotation( Version.class );
if ( jpaVer != null ) {
return false;
}
}
}
if(!this.checkAudited(property, propertyData, allClassAudited)){
if ( !this.checkAudited( property, propertyData, allClassAudited ) ) {
return false;
}
String propertyName = propertyNamePrefix + property.getName();
propertyData.setName(propertyName);
final String propertyName = propertyNamePrefix + property.getName();
propertyData.setName( propertyName );
propertyData.setModifiedFlagName(
MetadataTools.getModifiedFlagPropertyName(
propertyName,
globalCfg.getModifiedFlagSuffix()));
propertyData.setBeanName(property.getName());
propertyData.setAccessType(accessType);
MetadataTools.getModifiedFlagPropertyName(
propertyName,
globalCfg.getModifiedFlagSuffix()
)
);
propertyData.setBeanName( property.getName() );
propertyData.setAccessType( accessType );
addPropertyJoinTables(property, propertyData);
addPropertyAuditingOverrides(property, propertyData);
if (!processPropertyAuditingOverrides(property, propertyData)) {
return false; // not audited due to AuditOverride annotation
addPropertyJoinTables( property, propertyData );
addPropertyAuditingOverrides( property, propertyData );
if ( !processPropertyAuditingOverrides( property, propertyData ) ) {
// not audited due to AuditOverride annotation
return false;
}
addPropertyMapKey(property, propertyData);
setPropertyAuditMappedBy(property, propertyData);
setPropertyRelationMappedBy(property, propertyData);
addPropertyMapKey( property, propertyData );
setPropertyAuditMappedBy( property, propertyData );
setPropertyRelationMappedBy( property, propertyData );
return true;
}
protected boolean checkAudited(XProperty property,
protected boolean checkAudited(
XProperty property,
PropertyAuditingData propertyData, Audited allClassAudited) {
// Checking if this property is explicitly audited or if all properties are.
Audited aud = (property.isAnnotationPresent(Audited.class)) ? (property.getAnnotation(Audited.class)) : allClassAudited;
if (aud == null && overriddenAuditedProperties.contains(property) && !overriddenNotAuditedProperties.contains(property)) {
Audited aud = (property.isAnnotationPresent( Audited.class ))
? property.getAnnotation( Audited.class )
: allClassAudited;
if ( aud == null
&& overriddenAuditedProperties.contains( property )
&& !overriddenNotAuditedProperties.contains( property ) ) {
// Assigning @Audited defaults. If anyone needs to customize those values in the future,
// appropriate fields shall be added to @AuditOverride annotation.
aud = DEFAULT_AUDITED;
}
if (aud != null) {
propertyData.setStore(aud.modStore());
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
if ( aud != null ) {
propertyData.setStore( aud.modStore() );
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
return true;
} else {
}
else {
return false;
}
}
@ -447,79 +547,80 @@ public class AuditedPropertiesReader {
globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag();
}
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
OneToMany oneToMany = property.getAnnotation(OneToMany.class);
if (oneToMany != null && !"".equals(oneToMany.mappedBy())) {
propertyData.setRelationMappedBy(oneToMany.mappedBy());
}
}
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
final OneToMany oneToMany = property.getAnnotation( OneToMany.class );
if ( oneToMany != null && !"".equals( oneToMany.mappedBy() ) ) {
propertyData.setRelationMappedBy( oneToMany.mappedBy() );
}
}
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
if (auditMappedBy != null) {
propertyData.setAuditMappedBy(auditMappedBy.mappedBy());
if (!"".equals(auditMappedBy.positionMappedBy())) {
propertyData.setPositionMappedBy(auditMappedBy.positionMappedBy());
}
}
}
final AuditMappedBy auditMappedBy = property.getAnnotation( AuditMappedBy.class );
if ( auditMappedBy != null ) {
propertyData.setAuditMappedBy( auditMappedBy.mappedBy() );
if ( !"".equals( auditMappedBy.positionMappedBy() ) ) {
propertyData.setPositionMappedBy( auditMappedBy.positionMappedBy() );
}
}
}
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
MapKey mapKey = property.getAnnotation(MapKey.class);
if (mapKey != null) {
propertyData.setMapKey(mapKey.name());
final MapKey mapKey = property.getAnnotation( MapKey.class );
if ( mapKey != null ) {
propertyData.setMapKey( mapKey.name() );
}
}
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
// first set the join table based on the AuditJoinTable annotation
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class);
if (joinTable != null) {
propertyData.setJoinTable(joinTable);
} else {
propertyData.setJoinTable(DEFAULT_AUDIT_JOIN_TABLE);
final AuditJoinTable joinTable = property.getAnnotation( AuditJoinTable.class );
if ( joinTable != null ) {
propertyData.setJoinTable( joinTable );
}
else {
propertyData.setJoinTable( DEFAULT_AUDIT_JOIN_TABLE );
}
}
/***
/**
* Add the {@link AuditOverride} annotations.
*
* @param property the property being processed
* @param propertyData the Envers auditing data for this property
*/
private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
AuditOverride annotationOverride = property.getAnnotation(AuditOverride.class);
if (annotationOverride != null) {
propertyData.addAuditingOverride(annotationOverride);
final AuditOverride annotationOverride = property.getAnnotation( AuditOverride.class );
if ( annotationOverride != null ) {
propertyData.addAuditingOverride( annotationOverride );
}
AuditOverrides annotationOverrides = property.getAnnotation(AuditOverrides.class);
if (annotationOverrides != null) {
propertyData.addAuditingOverrides(annotationOverrides);
final AuditOverrides annotationOverrides = property.getAnnotation( AuditOverrides.class );
if ( annotationOverrides != null ) {
propertyData.addAuditingOverrides( annotationOverrides );
}
}
/**
* Process the {@link AuditOverride} annotations for this property.
*
* @param property
* the property for which the {@link AuditOverride}
* annotations are being processed
* @param propertyData
* the Envers auditing data for this property
* @param property the property for which the {@link AuditOverride}
* annotations are being processed
* @param propertyData the Envers auditing data for this property
*
* @return {@code false} if isAudited() of the override annotation was set to
*/
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
// if this property is part of a component, process all override annotations
if (this.auditedPropertiesHolder instanceof ComponentAuditingData) {
List<AuditOverride> overrides = ((ComponentAuditingData) this.auditedPropertiesHolder).getAuditingOverrides();
for (AuditOverride override : overrides) {
if (property.getName().equals(override.name())) {
if ( this.auditedPropertiesHolder instanceof ComponentAuditingData ) {
final List<AuditOverride> overrides = ( (ComponentAuditingData) this.auditedPropertiesHolder ).getAuditingOverrides();
for ( AuditOverride override : overrides ) {
if ( property.getName().equals( override.name() ) ) {
// the override applies to this property
if (!override.isAudited()) {
if ( !override.isAudited() ) {
return false;
} else {
if (override.auditJoinTable() != null) {
propertyData.setJoinTable(override.auditJoinTable());
}
else {
if ( override.auditJoinTable() != null ) {
propertyData.setJoinTable( override.auditJoinTable() );
}
}
}
@ -529,39 +630,89 @@ public class AuditedPropertiesReader {
return true;
}
private static Audited DEFAULT_AUDITED = new Audited() {
public ModificationStore modStore() { return ModificationStore.FULL; }
public RelationTargetAuditMode targetAuditMode() { return RelationTargetAuditMode.AUDITED; }
public Class[] auditParents() { return new Class[0]; }
public boolean withModifiedFlag() { return false; }
public Class<? extends Annotation> annotationType() { return this.getClass(); }
};
private static final Audited DEFAULT_AUDITED = new Audited() {
@Override
public ModificationStore modStore() {
return ModificationStore.FULL;
}
private static AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
public String name() { return ""; }
public String schema() { return ""; }
public String catalog() { return ""; }
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
public Class<? extends Annotation> annotationType() { return this.getClass(); }
@Override
public RelationTargetAuditMode targetAuditMode() {
return RelationTargetAuditMode.AUDITED;
}
@Override
public Class[] auditParents() {
return new Class[0];
}
@Override
public boolean withModifiedFlag() {
return false;
}
@Override
public Class<? extends Annotation> annotationType() {
return this.getClass();
}
};
public static class ComponentPropertiesSource implements PersistentPropertiesSource {
private static final AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
@Override
public String name() {
return "";
}
@Override
public String schema() {
return "";
}
@Override
public String catalog() {
return "";
}
@Override
public JoinColumn[] inverseJoinColumns() {
return new JoinColumn[0];
}
@Override
public Class<? extends Annotation> annotationType() {
return this.getClass();
}
};
public static class ComponentPropertiesSource implements PersistentPropertiesSource {
private final XClass xclass;
private final Component component;
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
try {
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass());
} catch (ClassNotFoundException e) {
throw new MappingException(e);
this.xclass = reflectionManager.classForName( component.getComponentClassName(), this.getClass() );
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
this.component = component;
}
@Override
@SuppressWarnings({"unchecked"})
public Iterator<Property> getPropertyIterator() { return component.getPropertyIterator(); }
public Property getProperty(String propertyName) { return component.getProperty(propertyName); }
public XClass getXClass() { return xclass; }
public Iterator<Property> getPropertyIterator() {
return component.getPropertyIterator();
}
@Override
public Property getProperty(String propertyName) {
return component.getProperty( propertyName );
}
@Override
public XClass getXClass() {
return xclass;
}
}
}

View File

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

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;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.envers.Audited;
@ -13,28 +37,34 @@ import org.hibernate.envers.configuration.internal.GlobalConfiguration;
*/
public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
public ComponentAuditedPropertiesReader(ModificationStore defaultStore,
public ComponentAuditedPropertiesReader(
ModificationStore defaultStore,
PersistentPropertiesSource persistentPropertiesSource,
AuditedPropertiesHolder auditedPropertiesHolder,
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
String propertyNamePrefix) {
super(defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
globalCfg, reflectionManager, propertyNamePrefix);
super(
defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
globalCfg, reflectionManager, propertyNamePrefix
);
}
@Override
protected boolean checkAudited(XProperty property,
PropertyAuditingData propertyData, Audited allClassAudited) {
protected boolean checkAudited(
XProperty property,
PropertyAuditingData propertyData,
Audited allClassAudited) {
// Checking if this property is explicitly audited or if all properties are.
Audited aud = property.getAnnotation(Audited.class);
if (aud != null) {
propertyData.setStore(aud.modStore());
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
} else {
propertyData.setStore(ModificationStore.FULL);
final Audited aud = property.getAnnotation( Audited.class );
if ( aud != null ) {
propertyData.setStore( aud.modStore() );
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
}
return true;
else {
propertyData.setStore( ModificationStore.FULL );
}
return true;
}
}

View File

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

View File

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

View File

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

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;
import org.hibernate.HibernateException;
@ -8,6 +31,7 @@ import org.hibernate.internal.util.StringHelper;
/**
* Revision number generator has to produce values in ascending order (gaps may occur).
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class OrderedSequenceGenerator extends SequenceStyleGenerator {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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;
import javax.persistence.NoResultException;
import java.io.Serializable;
import java.util.Map;
import javax.persistence.NoResultException;
import org.hibernate.NonUniqueResultException;
import org.hibernate.engine.spi.SessionImplementor;
@ -13,54 +36,69 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
/**
* Template class for property mappers that manage one-to-one relation.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
private final String entityName;
private final String referencedEntityName;
private final String entityName;
private final String referencedEntityName;
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
super(propertyData);
this.entityName = entityName;
this.referencedEntityName = referencedEntityName;
}
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
super( propertyData );
this.entityName = entityName;
this.referencedEntityName = referencedEntityName;
}
@Override
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
EntityInfo referencedEntity = getEntityInfo(verCfg, referencedEntityName);
@Override
public void nullSafeMapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
final EntityInfo referencedEntity = getEntityInfo( verCfg, referencedEntityName );
Object value = null;
try {
value = queryForReferencedEntity(versionsReader, referencedEntity, (Serializable) primaryKey, revision);
} catch (NoResultException e) {
value = null;
} catch (NonUniqueResultException e) {
throw new AuditException("Many versions results for one-to-one relationship " + entityName +
"." + getPropertyData().getBeanName() + ".", e);
}
Object value;
try {
value = queryForReferencedEntity( versionsReader, referencedEntity, (Serializable) primaryKey, revision );
}
catch (NoResultException e) {
value = null;
}
catch (NonUniqueResultException e) {
throw new AuditException(
"Many versions results for one-to-one relationship " + entityName +
"." + getPropertyData().getBeanName() + ".", e
);
}
setPropertyValue(obj, value);
}
setPropertyValue( obj, value );
}
/**
* @param versionsReader Audit reader.
* @param referencedEntity Referenced entity descriptor.
* @param primaryKey Referenced entity identifier.
* @param revision Revision number.
* @return Referenced object or proxy of one-to-one relation.
*/
protected abstract Object queryForReferencedEntity(AuditReaderImplementor versionsReader, EntityInfo referencedEntity,
Serializable primaryKey, Number revision);
/**
* @param versionsReader Audit reader.
* @param referencedEntity Referenced entity descriptor.
* @param primaryKey Referenced entity identifier.
* @param revision Revision number.
*
* @return Referenced object or proxy of one-to-one relation.
*/
protected abstract Object queryForReferencedEntity(
AuditReaderImplementor versionsReader, EntityInfo referencedEntity,
Serializable primaryKey, Number revision);
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
}
@Override
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
if (getPropertyData().isUsingModifiedFlag()) {
data.put(getPropertyData().getModifiedFlagPropertyName(), collectionPropertyName.equals(getPropertyData().getName()));
}
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
if ( getPropertyData().isUsingModifiedFlag() ) {
data.put(
getPropertyData().getModifiedFlagPropertyName(),
collectionPropertyName.equals( getPropertyData().getName() )
);
}
}
}

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;
import java.io.Serializable;
@ -17,87 +40,109 @@ import org.hibernate.property.Setter;
/**
* Base class for property mappers that manage to-one relation.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public abstract class AbstractToOneMapper implements PropertyMapper {
private final PropertyData propertyData;
private final PropertyData propertyData;
protected AbstractToOneMapper(PropertyData propertyData) {
this.propertyData = propertyData;
}
protected AbstractToOneMapper(PropertyData propertyData) {
this.propertyData = propertyData;
}
@Override
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
return false;
}
@Override
public boolean mapToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
return false;
}
@Override
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
if (obj != null) {
nullSafeMapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
}
}
@Override
public void mapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
if ( obj != null ) {
nullSafeMapToEntityFromMap( verCfg, obj, data, primaryKey, versionsReader, revision );
}
}
@Override
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl, Serializable oldColl,
Serializable id) {
return null;
}
@Override
public List<PersistentCollectionChangeData> mapCollectionChanges(
SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl, Serializable oldColl,
Serializable id) {
return null;
}
/**
* @param verCfg Audit configuration.
* @param entityName Entity name.
* @return Entity class, name and information whether it is audited or not.
*/
protected EntityInfo getEntityInfo(AuditConfiguration verCfg, String entityName) {
EntityConfiguration entCfg = verCfg.getEntCfg().get(entityName);
boolean isRelationAudited = true;
if (entCfg == null) {
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName);
isRelationAudited = false;
}
Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
return new EntityInfo(entityClass, entityName, isRelationAudited);
}
/**
* @param verCfg Audit configuration.
* @param entityName Entity name.
*
* @return Entity class, name and information whether it is audited or not.
*/
protected EntityInfo getEntityInfo(AuditConfiguration verCfg, String entityName) {
EntityConfiguration entCfg = verCfg.getEntCfg().get( entityName );
boolean isRelationAudited = true;
if ( entCfg == null ) {
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
isRelationAudited = false;
}
final Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
return new EntityInfo( entityClass, entityName, isRelationAudited );
}
protected void setPropertyValue(Object targetObject, Object value) {
Setter setter = ReflectionTools.getSetter(targetObject.getClass(), propertyData);
setter.set(targetObject, value, null);
}
protected void setPropertyValue(Object targetObject, Object value) {
final Setter setter = ReflectionTools.getSetter( targetObject.getClass(), propertyData );
setter.set( targetObject, value, null );
}
/**
* @return Bean property that represents the relation.
*/
protected PropertyData getPropertyData() {
return propertyData;
}
/**
* @return Bean property that represents the relation.
*/
protected PropertyData getPropertyData() {
return propertyData;
}
/**
* Parameter {@code obj} is never {@code null}.
* @see PropertyMapper#mapToEntityFromMap(AuditConfiguration, Object, Map, Object, AuditReaderImplementor, Number)
*/
public abstract void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision);
/**
* Parameter {@code obj} is never {@code null}.
*
* @see PropertyMapper#mapToEntityFromMap(AuditConfiguration, Object, Map, Object, AuditReaderImplementor, Number)
*/
public abstract void nullSafeMapToEntityFromMap(
AuditConfiguration verCfg,
Object obj,
Map data,
Object primaryKey,
AuditReaderImplementor versionsReader,
Number revision);
/**
* Simple descriptor of an entity.
*/
protected class EntityInfo {
private final Class entityClass;
private final String entityName;
private final boolean audited;
/**
* Simple descriptor of an entity.
*/
protected class EntityInfo {
private final Class entityClass;
private final String entityName;
private final boolean audited;
public EntityInfo(Class entityClass, String entityName, boolean audited) {
this.entityClass = entityClass;
this.entityName = entityName;
this.audited = audited;
}
public EntityInfo(Class entityClass, String entityName, boolean audited) {
this.entityClass = entityClass;
this.entityName = entityName;
this.audited = audited;
}
public Class getEntityClass() { return entityClass; }
public String getEntityName() { return entityName; }
public boolean isAudited() { return audited; }
}
public Class getEntityClass() {
return entityClass;
}
public String getEntityName() {
return entityName;
}
public boolean isAudited() {
return audited;
}
}
}

View File

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

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -22,48 +22,51 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.internal.entities.mapper.relation;
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
/**
* Data that is used by all collection mappers, regardless of the type.
*
* @author Adam Warski (adam at warski dot org)
*/
public final class CommonCollectionMapperData {
private final AuditEntitiesConfiguration verEntCfg;
private final String versionsMiddleEntityName;
private final PropertyData collectionReferencingPropertyData;
private final MiddleIdData referencingIdData;
private final RelationQueryGenerator queryGenerator;
private final AuditEntitiesConfiguration verEntCfg;
private final String versionsMiddleEntityName;
private final PropertyData collectionReferencingPropertyData;
private final MiddleIdData referencingIdData;
private final RelationQueryGenerator queryGenerator;
public CommonCollectionMapperData(AuditEntitiesConfiguration verEntCfg, String versionsMiddleEntityName,
PropertyData collectionReferencingPropertyData, MiddleIdData referencingIdData,
RelationQueryGenerator queryGenerator) {
this.verEntCfg = verEntCfg;
this.versionsMiddleEntityName = versionsMiddleEntityName;
this.collectionReferencingPropertyData = collectionReferencingPropertyData;
this.referencingIdData = referencingIdData;
this.queryGenerator = queryGenerator;
}
public CommonCollectionMapperData(
AuditEntitiesConfiguration verEntCfg, String versionsMiddleEntityName,
PropertyData collectionReferencingPropertyData, MiddleIdData referencingIdData,
RelationQueryGenerator queryGenerator) {
this.verEntCfg = verEntCfg;
this.versionsMiddleEntityName = versionsMiddleEntityName;
this.collectionReferencingPropertyData = collectionReferencingPropertyData;
this.referencingIdData = referencingIdData;
this.queryGenerator = queryGenerator;
}
public AuditEntitiesConfiguration getVerEntCfg() {
return verEntCfg;
}
public AuditEntitiesConfiguration getVerEntCfg() {
return verEntCfg;
}
public String getVersionsMiddleEntityName() {
return versionsMiddleEntityName;
}
public String getVersionsMiddleEntityName() {
return versionsMiddleEntityName;
}
public PropertyData getCollectionReferencingPropertyData() {
return collectionReferencingPropertyData;
}
public PropertyData getCollectionReferencingPropertyData() {
return collectionReferencingPropertyData;
}
public MiddleIdData getReferencingIdData() {
return referencingIdData;
}
public MiddleIdData getReferencingIdData() {
return referencingIdData;
}
public RelationQueryGenerator getQueryGenerator() {
return queryGenerator;
}
public RelationQueryGenerator getQueryGenerator() {
return queryGenerator;
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -43,45 +43,64 @@ import org.hibernate.envers.tools.Pair;
* @author Adam Warski (adam at warski dot org)
*/
public final class ListCollectionMapper extends AbstractCollectionMapper<List> implements PropertyMapper {
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
boolean revisionTypeInId) {
public ListCollectionMapper(
CommonCollectionMapperData commonCollectionMapperData,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
boolean revisionTypeInId) {
super( commonCollectionMapperData, List.class, ListProxy.class, false, revisionTypeInId );
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
protected Initializor<List> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
Object primaryKey, Number revision, boolean removed) {
return new ListCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, removed, elementComponentData, indexComponentData);
}
@Override
protected Initializor<List> getInitializor(
AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
Object primaryKey, Number revision, boolean removed) {
return new ListCollectionInitializor(
verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, removed, elementComponentData, indexComponentData
);
}
@SuppressWarnings({"unchecked"})
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
if (newCollection == null) {
return null;
} else {
return Tools.listToIndexElementPairList((List<Object>) newCollection);
}
}
@Override
@SuppressWarnings({"unchecked"})
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
if ( newCollection == null ) {
return null;
}
else {
return Tools.listToIndexElementPairList( (List<Object>) newCollection );
}
}
@SuppressWarnings({"unchecked"})
protected Collection getOldCollectionContent(Serializable oldCollection) {
if (oldCollection == null) {
return null;
} else {
return Tools.listToIndexElementPairList((List<Object>) oldCollection);
}
}
@Override
@SuppressWarnings({"unchecked"})
protected Collection getOldCollectionContent(Serializable oldCollection) {
if ( oldCollection == null ) {
return null;
}
else {
return Tools.listToIndexElementPairList( (List<Object>) oldCollection );
}
}
@SuppressWarnings({"unchecked"})
protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
Pair<Integer, Object> indexValuePair = (Pair<Integer, Object>) changed;
elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getSecond());
indexComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getFirst());
}
@Override
@SuppressWarnings({"unchecked"})
protected void mapToMapFromObject(
SessionImplementor session,
Map<String, Object> idData,
Map<String, Object> data,
Object changed) {
final Pair<Integer, Object> indexValuePair = (Pair<Integer, Object>) changed;
elementComponentData.getComponentMapper().mapToMapFromObject(
session,
idData,
data,
indexValuePair.getSecond()
);
indexComponentData.getComponentMapper().mapToMapFromObject( session, idData, data, indexValuePair.getFirst() );
}
}

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