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)
@ -35,23 +36,23 @@ import javax.persistence.JoinColumn;
@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
* 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.
* 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.
* 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
* 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>
@ -22,15 +23,16 @@ import java.lang.annotation.Target;
@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
* 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)}.
* 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,11 +33,12 @@ 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
@ -26,27 +50,27 @@ import static java.lang.annotation.RetentionPolicy.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;
@ -25,7 +49,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@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
@ -42,12 +42,16 @@ import org.hibernate.envers.query.AuditQueryCreator;
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.
* @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.
@ -57,46 +61,59 @@ public interface AuditReader {
/**
* 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,
<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.
* @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,
<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.
@ -106,11 +123,14 @@ public interface AuditReader {
/**
* 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.
@ -121,8 +141,11 @@ public interface AuditReader {
/**
* 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.
@ -135,8 +158,11 @@ public interface AuditReader {
* 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>.
@ -146,9 +172,13 @@ public interface AuditReader {
/**
* 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.
@ -160,19 +190,19 @@ public interface AuditReader {
/**
* Find a map of revisions using the revision numbers specified.
*
* @param revisionEntityClass
* Class of the revision entity. Should be annotated with
* @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 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
*
* @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 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,16 +211,20 @@ 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);
/**
* 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
@ -203,8 +237,8 @@ public interface AuditReader {
* isEntityNameAudited() with the string of the class name will return the
* same value.
*
* @param entityClass
* Class of the entity asking for audit support
* @param entityClass Class of the entity asking for audit support
*
* @return true if the entityClass is audited.
*/
boolean isEntityClassAudited(Class<?> entityClass);
@ -213,15 +247,14 @@ public interface AuditReader {
* 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.
@ -232,6 +265,7 @@ public interface AuditReader {
/**
* @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>

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) ) {
sessionImpl = (SessionImplementor) session.getSessionFactory().getCurrentSession();
} else {
}
else {
sessionImpl = (SessionImplementor) session;
}
@ -61,7 +66,8 @@ 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(
@ -77,9 +83,12 @@ public class AuditReaderFactory {
/**
* 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.
*/

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 {
/**
* The name of the table
*/
String value();
/**
* @return The schema of the table. Defaults to the schema of the annotated entity.
* The schema of the table. Defaults to the schema of the annotated entity.
*/
String schema() default "";
/**
* @return The catalog of the table. Defaults to the catalog of the annotated entity.
* The catalog of the table. Defaults to the catalog of the annotated entity.
*/
String catalog() default "";
}

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,31 +40,35 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface Audited {
/**
* 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;
/**
* @return Specifies the superclasses for which properties should be audited, even if the superclasses are not
* Specifies the superclasses for which properties should be audited, even if the superclasses are not
* annotated with {@link Audited}. Causes all properties of the listed classes to be audited, just as if the
* 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
* 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.
*/

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,14 +33,18 @@ 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.
*/
@ -26,9 +53,12 @@ public interface CrossTypeRevisionChangesReader {
/**
* 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.
*/
@ -42,20 +72,28 @@ public interface CrossTypeRevisionChangesReader {
* <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,
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;
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)
@ -66,18 +67,21 @@ public class DefaultRevisionEntity implements Serializable {
this.timestamp = timestamp;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultRevisionEntity)) return false;
DefaultRevisionEntity that = (DefaultRevisionEntity) o;
if (id != that.id) return false;
if (timestamp != that.timestamp) return false;
if ( this == o ) {
return true;
}
if ( !(o instanceof DefaultRevisionEntity) ) {
return false;
}
final DefaultRevisionEntity that = (DefaultRevisionEntity) o;
return id == that.id
&& timestamp == that.timestamp;
}
@Override
public int hashCode() {
int result;
result = id;
@ -85,7 +89,9 @@ public class DefaultRevisionEntity implements Serializable {
return result;
}
@Override
public String toString() {
return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
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,6 +39,7 @@ 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
@ -35,25 +59,36 @@ public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisi
this.modifiedEntityNames = modifiedEntityNames;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity)) return false;
if (!super.equals(o)) return false;
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;
: that.modifiedEntityNames != null ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
return result;
}
@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,12 +28,14 @@ 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.
@ -18,6 +43,7 @@ public interface EntityTrackingRevisionListener extends RevisionListener {
* @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,
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

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

@ -41,7 +41,7 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
public @interface RevisionEntity {
/**
* @return The optional listener that will be used to fill in the custom revision entity.
* The optional listener that will be used to fill in the custom revision entity.
* May also be specified using the {@code org.hibernate.envers.revision_listener} configuration property.
*/
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,11 +27,13 @@ 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.
*/

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,6 +26,7 @@ package org.hibernate.envers;
/**
* Type of the revision.
*
* @author Adam Warski (adam at warski dot org)
*/
public enum RevisionType {
@ -58,11 +59,18 @@ public enum RevisionType {
}
switch ( (Byte) representation ) {
case 0: return ADD;
case 1: return MOD;
case 2: return DEL;
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;

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;

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,17 +39,21 @@ 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 {
public static final EnversMessageLogger LOG = Logger.getMessageLogger(EnversMessageLogger.class, ClassesAuditingData.class.getName());
private 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>();
/**
* Stores information about auditing meta-data for the given class.
*
* @param pc Persistent class.
* @param cad Auditing meta-data for the given class.
*/
@ -43,6 +71,7 @@ public class ClassesAuditingData {
/**
* @param entityName Name of the entity.
*
* @return Auditing meta-data for the given entity.
*/
public ClassAuditingData getClassAuditingData(String entityName) {
@ -57,38 +86,49 @@ public class ClassesAuditingData {
*/
public void updateCalculatedFields() {
for ( Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet() ) {
PersistentClass pc = classAuditingDataEntry.getKey();
ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
final PersistentClass pc = classAuditingDataEntry.getKey();
final ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
for ( String propertyName : classAuditingData.getPropertyNames() ) {
PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData(propertyName);
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 ) {
String referencedEntityName = MappingTools.getReferencedEntityName(pc.getProperty(propertyName).getValue());
final String referencedEntityName = MappingTools.getReferencedEntityName(
pc.getProperty( propertyName ).getValue()
);
ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get(referencedEntityName);
final 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,
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);
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",
LOG.debugf(
"Non-insertable property %s.%s will be made insertable because a matching @AuditMappedBy was found in the %s entity",
referencedEntityName,
propertyName,
entityName);
entityName
);
classAuditingData
.getPropertyAuditingData( propertyName )

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,28 +57,30 @@ import org.hibernate.mapping.PersistentClass;
* @author Adam Warski (adam at warski dot org)
*/
public class EntitiesConfigurator {
public EntitiesConfigurations configure(Configuration cfg, ReflectionManager reflectionManager,
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();
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();
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();
final PersistentClass pc = classes.next();
// Collecting information from annotations on the persistent class pc
AnnotationsMetadataReader annotationsMetadataReader =
final AnnotationsMetadataReader annotationsMetadataReader =
new AnnotationsMetadataReader( globalCfg, reflectionManager, pc );
ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
final ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
classesAuditingData.addClassAuditingData( pc, auditData );
}
@ -86,22 +88,25 @@ public class EntitiesConfigurator {
// 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();
final PersistentClass pc = pcDatasEntry.getKey();
final ClassAuditingData auditData = pcDatasEntry.getValue();
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
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 {
}
else {
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, false );
}
@ -110,7 +115,7 @@ public class EntitiesConfigurator {
// Second pass
for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey());
final EntityXmlMappingData xmlMappingData = xmlMappings.get( pcDatasEntry.getKey() );
if ( pcDatasEntry.getValue().isAudited() ) {
auditMetaGen.generateSecondPass( pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData );
@ -122,7 +127,8 @@ public class EntitiesConfigurator {
cfg.addDocument( writer.write( additionalMapping ) );
//writeDocument(additionalMapping);
}
} catch (DocumentException e) {
}
catch (DocumentException e) {
throw new MappingException( e );
}
}
@ -135,25 +141,29 @@ public class EntitiesConfigurator {
//writeDocument(revisionInfoXmlMapping);
cfg.addDocument( writer.write( revisionInfoXmlMapping ) );
}
} catch (DocumentException e) {
}
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);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Writer w = new PrintWriter( baos );
try {
XMLWriter xw = new XMLWriter(w, new OutputFormat(" ", true));
final XMLWriter xw = new XMLWriter( w, new OutputFormat( " ", true ) );
xw.write( e );
w.flush();
} catch (IOException e1) {
}
catch (IOException e1) {
e1.printStackTrace();
}

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 );
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,6 +35,7 @@ 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> {
@ -43,10 +45,12 @@ public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass
this.cfg = cfg;
}
@Override
public String getRepresentation(PersistentClass pc) {
return pc.getEntityName();
}
@Override
public PersistentClass getValue(String entityName) {
return cfg.getClassMapping( entityName );
}
@ -54,21 +58,23 @@ public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass
@SuppressWarnings({"unchecked"})
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
while ( subclassIterator.hasNext() ) {
PersistentClass subclass = subclassIterator.next();
final PersistentClass subclass = subclassIterator.next();
neighbours.add( subclass );
addNeighbours( neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator() );
}
}
@Override
@SuppressWarnings({"unchecked"})
public List<PersistentClass> getNeighbours(PersistentClass pc) {
List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
final List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
addNeighbours( neighbours, (Iterator<PersistentClass>) pc.getSubclassIterator() );
return neighbours;
}
@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;
@ -79,7 +80,8 @@ public class RevisionInfoConfiguration {
this.globalCfg = globalCfg;
if ( globalCfg.isUseRevisionEntityWithNativeId() ) {
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
} else {
}
else {
revisionInfoEntityName = "org.hibernate.envers.enhanced.SequenceIdRevisionEntity";
}
revisionInfoIdData = new PropertyData( "id", "id", "field", null );
@ -91,25 +93,46 @@ public class RevisionInfoConfiguration {
}
private Document generateDefaultRevisionInfoXmlMapping() {
Document document = XMLHelper.getDocumentFactory().createDocument();
final Document document = XMLHelper.getDocumentFactory().createDocument();
Element class_mapping = MetadataTools.createEntity(document, new AuditTableData(null, null, globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName()), null, null);
final Element classMapping = MetadataTools.createEntity(
document,
new AuditTableData( null, null, globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName() ),
null,
null
);
class_mapping.addAttribute("name", revisionInfoEntityName);
class_mapping.addAttribute("table", "REVINFO");
classMapping.addAttribute( "name", revisionInfoEntityName );
classMapping.addAttribute( "table", "REVINFO" );
Element idProperty = MetadataTools.addNativelyGeneratedId(class_mapping, revisionInfoIdData.getName(),
revisionPropType, globalCfg.isUseRevisionEntityWithNativeId());
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);
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");
generateEntityNamesTrackingTableMapping(
classMapping,
"modifiedEntityNames",
globalCfg.getDefaultSchemaName(),
globalCfg.getDefaultCatalogName(),
"REVCHANGES",
"REV",
"ENTITYNAME",
"string"
);
}
return document;
@ -127,11 +150,16 @@ public class RevisionInfoConfiguration {
* &lt;/set&gt;
* </code>
*/
private void generateEntityNamesTrackingTableMapping(Element class_mapping, String propertyName,
String joinTableSchema, String joinTableCatalog, String joinTableName,
String joinTablePrimaryKeyColumnName, String joinTableValueColumnName,
private void generateEntityNamesTrackingTableMapping(
Element classMapping,
String propertyName,
String joinTableSchema,
String joinTableCatalog,
String joinTableName,
String joinTablePrimaryKeyColumnName,
String joinTableValueColumnName,
String joinTableValueColumnType) {
Element set = class_mapping.addElement("set");
final Element set = classMapping.addElement( "set" );
set.addAttribute( "name", propertyName );
set.addAttribute( "table", joinTableName );
set.addAttribute( "schema", joinTableSchema );
@ -139,62 +167,70 @@ public class RevisionInfoConfiguration {
set.addAttribute( "cascade", "persist, delete" );
set.addAttribute( "fetch", "join" );
set.addAttribute( "lazy", "false" );
Element key = set.addElement("key");
final Element key = set.addElement( "key" );
key.addAttribute( "column", joinTablePrimaryKeyColumnName );
Element element = set.addElement("element");
final Element element = set.addElement( "element" );
element.addAttribute( "type", joinTableValueColumnType );
Element column = element.addElement("column");
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);
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);
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) {
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);
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!" );
}
XClass revisionNumberClass = property.getType();
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) ||
}
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");
}
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);
final Column revisionPropColumn = property.getAnnotation( Column.class );
if ( revisionPropColumn != null ) {
revisionPropSqlType = revisionPropColumn.columnDefinition();
}
@ -205,16 +241,24 @@ public class RevisionInfoConfiguration {
throw new MappingException( "Only one property may be annotated with @RevisionTimestamp!" );
}
XClass revisionTimestampClass = property.getType();
final XClass revisionTimestampClass = property.getType();
if ( reflectionManager.equals( revisionTimestampClass, Long.class ) ||
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);
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");
}
else {
throw new MappingException(
"The field annotated with @RevisionTimestamp must be of type " +
"long, Long, java.util.Date or java.sql.Date"
);
}
}
@ -222,49 +266,68 @@ public class RevisionInfoConfiguration {
if ( modifiedEntityNamesFound.isSet() ) {
throw new MappingException( "Only one property may be annotated with @ModifiedEntityNames!" );
}
XClass modifiedEntityNamesClass = property.getType();
final XClass modifiedEntityNamesClass = property.getType();
if ( reflectionManager.equals( modifiedEntityNamesClass, Set.class ) &&
reflectionManager.equals( property.getElementClass(), String.class ) ) {
modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null);
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.");
}
else {
throw new MappingException(
"The field annotated with @ModifiedEntityNames must be of Set<String> type."
);
}
}
}
}
private void searchForRevisionInfoCfg(XClass clazz, ReflectionManager reflectionManager,
private void searchForRevisionInfoCfg(
XClass clazz, ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityNamesFound) {
XClass superclazz = clazz.getSuperclass();
final XClass superclazz = clazz.getSuperclass();
if ( !"java.lang.Object".equals( superclazz.getName() ) ) {
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
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;
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) {
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
RevisionEntity revisionEntity = clazz.getAnnotation(RevisionEntity.class);
final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
if ( revisionEntity != null ) {
if ( revisionEntityFound ) {
throw new MappingException( "Only one entity may be annotated with @RevisionEntity!" );
@ -277,39 +340,56 @@ public class RevisionInfoConfiguration {
revisionEntityFound = true;
MutableBoolean revisionNumberFound = new MutableBoolean();
MutableBoolean revisionTimestampFound = new MutableBoolean();
MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
final MutableBoolean revisionNumberFound = new MutableBoolean();
final MutableBoolean revisionTimestampFound = new MutableBoolean();
final 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!");
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!");
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionTimestamp!"
);
}
revisionInfoEntityName = pc.getEntityName();
revisionInfoClass = pc.getMappedClass();
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(revisionEntity.value());
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))
|| (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,
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityName,
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityNamesData);
modifiedEntityNamesData
);
globalCfg.setTrackEntitiesChangedInRevision( true );
} else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
}
else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
}
}
@ -317,43 +397,57 @@ public class RevisionInfoConfiguration {
// In case of a custom revision info generator, the mapping will be null.
Document revisionInfoXmlMapping = null;
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(RevisionListener.class);
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( RevisionListener.class );
if ( revisionInfoGenerator == null ) {
if ( globalCfg.isTrackEntitiesChangedInRevision() ) {
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultTrackingModifiedEntitiesRevisionEntity.class
: SequenceIdTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ?
DefaultTrackingModifiedEntitiesRevisionEntity.class
:
SequenceIdTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = revisionInfoClass.getName();
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
} else {
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());
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
}
return new RevisionInfoConfigurationResult(
revisionInfoGenerator, revisionInfoXmlMapping,
new RevisionInfoQueryCreator(revisionInfoEntityName, revisionInfoIdData.getName(),
revisionInfoTimestampData.getName(), isTimestampAsDate()),
new RevisionInfoQueryCreator(
revisionInfoEntityName, revisionInfoIdData.getName(),
revisionInfoTimestampData.getName(), isTimestampAsDate()
),
generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader( revisionInfoClass, revisionInfoIdData ),
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData)
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(
revisionInfoClass,
modifiedEntityNamesData
)
: null,
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData);
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData
);
}
private boolean isTimestampAsDate() {
String typename = revisionInfoTimestampType.getName();
final 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) {

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,7 +46,8 @@ public class RevisionInfoConfigurationResult {
private final Class<?> revisionInfoClass;
private final PropertyData revisionInfoTimestampData;
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
RevisionInfoConfigurationResult(
RevisionInfoGenerator revisionInfoGenerator,
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,

View File

@ -1,4 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.internal.metadata;
import java.util.HashSet;
import java.util.Set;
@ -6,6 +30,7 @@ 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 {
@ -13,6 +38,7 @@ public class AuditEntityNameRegister {
/**
* @param auditEntityName Name of the audit entity.
*
* @return True if the given audit entity name is already used.
*/
private boolean check(String auditEntityName) {
@ -21,6 +47,7 @@ public class AuditEntityNameRegister {
/**
* 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) {

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,6 +28,7 @@ import java.util.Iterator;
import java.util.Map;
import org.dom4j.Element;
import org.jboss.logging.Logger;
import org.hibernate.MappingException;
@ -73,8 +74,10 @@ import org.hibernate.type.Type;
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public final class AuditMetadataGenerator {
public static final EnversMessageLogger LOG = Logger.getMessageLogger(EnversMessageLogger.class, AuditMetadataGenerator.class.getName());
private static final EnversMessageLogger LOG = Logger.getMessageLogger(
EnversMessageLogger.class,
AuditMetadataGenerator.class.getName()
);
private final Configuration cfg;
private final GlobalConfiguration globalCfg;
@ -102,7 +105,8 @@ public final class AuditMetadataGenerator {
// Map entity name -> (join descriptor -> element describing the "versioned" join)
private final Map<String, Map<Join, Element>> entitiesJoins;
public AuditMetadataGenerator(Configuration cfg, GlobalConfiguration globalCfg,
public AuditMetadataGenerator(
Configuration cfg, GlobalConfiguration globalCfg,
AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
Element revisionInfoRelationMapping,
@ -129,60 +133,100 @@ public final class AuditMetadataGenerator {
/**
* Clones the revision info relation mapping, so that it can be added to other mappings. Also, the name of
* the property and the column are set properly.
*
* @return A revision info mapping, which can be added to other mappings (has no parent).
*/
private Element cloneAndSetupRevisionInfoRelationMapping() {
Element rev_mapping = (Element) revisionInfoRelationMapping.clone();
rev_mapping.addAttribute("name", verEntCfg.getRevisionFieldName());
final Element revMapping = (Element) revisionInfoRelationMapping.clone();
revMapping.addAttribute( "name", verEntCfg.getRevisionFieldName() );
MetadataTools.addOrModifyColumn(rev_mapping, verEntCfg.getRevisionFieldName());
MetadataTools.addOrModifyColumn( revMapping, verEntCfg.getRevisionFieldName() );
return rev_mapping;
return revMapping;
}
void addRevisionInfoRelation(Element any_mapping) {
any_mapping.add(cloneAndSetupRevisionInfoRelationMapping());
void addRevisionInfoRelation(Element anyMapping) {
anyMapping.add( cloneAndSetupRevisionInfoRelationMapping() );
}
void addRevisionType(Element any_mapping, Element any_mapping_end) {
Element revTypeProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionTypePropName(),
verEntCfg.getRevisionTypePropType(), true, false);
void addRevisionType(Element anyMapping, Element anyMappingEnd) {
final Element revTypeProperty = MetadataTools.addProperty(
anyMapping,
verEntCfg.getRevisionTypePropName(),
verEntCfg.getRevisionTypePropType(),
true,
false
);
revTypeProperty.addAttribute( "type", "org.hibernate.envers.internal.entities.RevisionTypeType" );
// Adding the end revision, if appropriate
addEndRevision(any_mapping_end);
addEndRevision( anyMappingEnd );
}
private void addEndRevision(Element any_mapping ) {
private void addEndRevision(Element anyMapping) {
// Add the end-revision field, if the appropriate strategy is used.
if ( auditStrategy instanceof ValidityAuditStrategy ) {
Element end_rev_mapping = (Element) revisionInfoRelationMapping.clone();
end_rev_mapping.setName("many-to-one");
end_rev_mapping.addAttribute("name", verEntCfg.getRevisionEndFieldName());
MetadataTools.addOrModifyColumn(end_rev_mapping, verEntCfg.getRevisionEndFieldName());
final Element endRevMapping = (Element) revisionInfoRelationMapping.clone();
endRevMapping.setName( "many-to-one" );
endRevMapping.addAttribute( "name", verEntCfg.getRevisionEndFieldName() );
MetadataTools.addOrModifyColumn( endRevMapping, verEntCfg.getRevisionEndFieldName() );
any_mapping.add(end_rev_mapping);
anyMapping.add( endRevMapping );
if ( verEntCfg.isRevisionEndTimestampEnabled() ) {
// add a column for the timestamp of the end revision
String revisionInfoTimestampSqlType = TimestampType.INSTANCE.getName();
Element timestampProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionEndTimestampFieldName(), revisionInfoTimestampSqlType, true, true, false);
MetadataTools.addColumn(timestampProperty, verEntCfg.getRevisionEndTimestampFieldName(), null, null, null, null, null, null);
final String revisionInfoTimestampSqlType = TimestampType.INSTANCE.getName();
final Element timestampProperty = MetadataTools.addProperty(
anyMapping,
verEntCfg.getRevisionEndTimestampFieldName(),
revisionInfoTimestampSqlType,
true,
true,
false
);
MetadataTools.addColumn(
timestampProperty,
verEntCfg.getRevisionEndTimestampFieldName(),
null,
null,
null,
null,
null,
null
);
}
}
}
private void addValueInFirstPass(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean processModifiedFlag) {
Type type = value.getType();
private void addValueInFirstPass(
Element parent,
Value value,
CompositeMapperBuilder currentMapper,
String entityName,
EntityXmlMappingData xmlMappingData,
PropertyAuditingData propertyAuditingData,
boolean insertable,
boolean processModifiedFlag) {
final Type type = value.getType();
final boolean isBasic = basicMetadataGenerator.addBasic(
parent,
propertyAuditingData,
value,
currentMapper,
insertable,
false
);
if (basicMetadataGenerator.addBasic(parent, propertyAuditingData, value, currentMapper, insertable, false)) {
if ( isBasic ) {
// The property was mapped by the basic generator.
} else if (type instanceof ComponentType) {
componentMetadataGenerator.addComponent(parent, propertyAuditingData, value, currentMapper,
entityName, xmlMappingData, true);
} else {
}
else if ( type instanceof ComponentType ) {
componentMetadataGenerator.addComponent(
parent, propertyAuditingData, value, currentMapper,
entityName, xmlMappingData, true
);
}
else {
if ( !processedInSecondPass( type ) ) {
// If we got here in the first pass, it means the basic mapper didn't map it, and none of the
// above branches either.
@ -198,78 +242,142 @@ public final class AuditMetadataGenerator {
type instanceof OneToOneType || type instanceof CollectionType;
}
private void addValueInSecondPass(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean processModifiedFlag) {
Type type = value.getType();
private void addValueInSecondPass(
Element parent,
Value value,
CompositeMapperBuilder currentMapper,
String entityName,
EntityXmlMappingData xmlMappingData,
PropertyAuditingData propertyAuditingData,
boolean insertable,
boolean processModifiedFlag) {
final Type type = value.getType();
if ( type instanceof ComponentType ) {
componentMetadataGenerator.addComponent(parent, propertyAuditingData, value, currentMapper,
entityName, xmlMappingData, false);
return;// mod flag field has been already generated in first pass
} else if (type instanceof ManyToOneType) {
toOneRelationMetadataGenerator.addToOne(parent, propertyAuditingData, value, currentMapper,
entityName, insertable);
} else if (type instanceof OneToOneType) {
OneToOne oneToOne = (OneToOne) value;
if (oneToOne.getReferencedPropertyName() != null) {
toOneRelationMetadataGenerator.addOneToOneNotOwning(propertyAuditingData, value,
currentMapper, entityName);
} else {
// @OneToOne relation marked with @PrimaryKeyJoinColumn
toOneRelationMetadataGenerator.addOneToOnePrimaryKeyJoinColumn(propertyAuditingData, value,
currentMapper, entityName, insertable);
componentMetadataGenerator.addComponent(
parent,
propertyAuditingData,
value,
currentMapper,
entityName,
xmlMappingData,
false
);
// mod flag field has been already generated in first pass
return;
}
} else if (type instanceof CollectionType) {
CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
(Collection) value, currentMapper, entityName, xmlMappingData,
propertyAuditingData);
else if ( type instanceof ManyToOneType ) {
toOneRelationMetadataGenerator.addToOne(
parent,
propertyAuditingData,
value,
currentMapper,
entityName,
insertable
);
}
else if ( type instanceof OneToOneType ) {
final OneToOne oneToOne = (OneToOne) value;
if ( oneToOne.getReferencedPropertyName() != null ) {
toOneRelationMetadataGenerator.addOneToOneNotOwning(
propertyAuditingData,
value,
currentMapper,
entityName
);
}
else {
// @OneToOne relation marked with @PrimaryKeyJoinColumn
toOneRelationMetadataGenerator.addOneToOnePrimaryKeyJoinColumn(
propertyAuditingData,
value,
currentMapper,
entityName,
insertable
);
}
}
else if ( type instanceof CollectionType ) {
final CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(
this,
(Collection) value,
currentMapper,
entityName,
xmlMappingData,
propertyAuditingData
);
collectionMetadataGenerator.addCollection();
} else {
}
else {
return;
}
addModifiedFlagIfNeeded( parent, propertyAuditingData, processModifiedFlag );
}
private void addModifiedFlagIfNeeded(Element parent, PropertyAuditingData propertyAuditingData, boolean processModifiedFlag) {
private void addModifiedFlagIfNeeded(
Element parent,
PropertyAuditingData propertyAuditingData,
boolean processModifiedFlag) {
if ( processModifiedFlag && propertyAuditingData.isUsingModifiedFlag() ) {
MetadataTools.addModifiedFlagProperty(parent,
MetadataTools.addModifiedFlagProperty(
parent,
propertyAuditingData.getName(),
globalCfg.getModifiedFlagSuffix());
globalCfg.getModifiedFlagSuffix()
);
}
}
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
void addValue(
Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean firstPass, boolean processModifiedFlag) {
if ( firstPass ) {
addValueInFirstPass(parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag);
} else {
addValueInSecondPass(parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag);
addValueInFirstPass(
parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag
);
}
else {
addValueInSecondPass(
parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag
);
}
}
private void addProperties(Element parent, Iterator<Property> properties, CompositeMapperBuilder currentMapper,
ClassAuditingData auditingData, String entityName, EntityXmlMappingData xmlMappingData,
private void addProperties(
Element parent,
Iterator<Property> properties,
CompositeMapperBuilder currentMapper,
ClassAuditingData auditingData,
String entityName,
EntityXmlMappingData xmlMappingData,
boolean firstPass) {
while ( properties.hasNext() ) {
Property property = properties.next();
String propertyName = property.getName();
PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData(propertyName);
final Property property = properties.next();
final String propertyName = property.getName();
final PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData( propertyName );
if ( propertyAuditingData != null ) {
addValue(parent, property.getValue(), currentMapper, entityName, xmlMappingData, propertyAuditingData,
property.isInsertable(), firstPass, true);
addValue(
parent,
property.getValue(),
currentMapper,
entityName,
xmlMappingData,
propertyAuditingData,
property.isInsertable(),
firstPass,
true
);
}
}
}
private boolean checkPropertiesAudited(Iterator<Property> properties, ClassAuditingData auditingData) {
while ( properties.hasNext() ) {
Property property = properties.next();
String propertyName = property.getName();
PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData(propertyName);
final Property property = properties.next();
final String propertyName = property.getName();
final PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData( propertyName );
if ( propertyAuditingData == null ) {
return false;
}
@ -312,9 +420,8 @@ public final class AuditMetadataGenerator {
@SuppressWarnings({"unchecked"})
private void createJoins(PersistentClass pc, Element parent, ClassAuditingData auditingData) {
Iterator<Join> joins = pc.getJoinIterator();
Map<Join, Element> joinElements = new HashMap<Join, Element>();
final Iterator<Join> joins = pc.getJoinIterator();
final Map<Join, Element> joinElements = new HashMap<Join, Element>();
entitiesJoins.put( pc.getEntityName(), joinElements );
while ( joins.hasNext() ) {
@ -327,36 +434,48 @@ public final class AuditMetadataGenerator {
// Determining the table name. If there is no entry in the dictionary, just constructing the table name
// as if it was an entity (by appending/prepending configured strings).
String originalTableName = join.getTable().getName();
final String originalTableName = join.getTable().getName();
String auditTableName = auditingData.getSecondaryTableDictionary().get( originalTableName );
if ( auditTableName == null ) {
auditTableName = verEntCfg.getAuditEntityName( originalTableName );
}
String schema = getSchema(auditingData.getAuditTable().schema(), join.getTable());
String catalog = getCatalog(auditingData.getAuditTable().catalog(), join.getTable());
final String schema = getSchema( auditingData.getAuditTable().schema(), join.getTable() );
final String catalog = getCatalog( auditingData.getAuditTable().catalog(), join.getTable() );
Element joinElement = MetadataTools.createJoin(parent, auditTableName, schema, catalog);
final Element joinElement = MetadataTools.createJoin( parent, auditTableName, schema, catalog );
joinElements.put( join, joinElement );
Element joinKey = joinElement.addElement("key");
final Element joinKey = joinElement.addElement( "key" );
MetadataTools.addColumns( joinKey, join.getKey().getColumnIterator() );
MetadataTools.addColumn( joinKey, verEntCfg.getRevisionFieldName(), null, null, null, null, null, null );
}
}
@SuppressWarnings({"unchecked"})
private void addJoins(PersistentClass pc, CompositeMapperBuilder currentMapper, ClassAuditingData auditingData,
String entityName, EntityXmlMappingData xmlMappingData,boolean firstPass) {
Iterator<Join> joins = pc.getJoinIterator();
private void addJoins(
PersistentClass pc,
CompositeMapperBuilder currentMapper,
ClassAuditingData auditingData,
String entityName,
EntityXmlMappingData xmlMappingData,
boolean firstPass) {
final Iterator<Join> joins = pc.getJoinIterator();
while ( joins.hasNext() ) {
Join join = joins.next();
Element joinElement = entitiesJoins.get(entityName).get(join);
final Join join = joins.next();
final Element joinElement = entitiesJoins.get( entityName ).get( join );
if ( joinElement != null ) {
addProperties(joinElement, join.getPropertyIterator(), currentMapper, auditingData, entityName,
xmlMappingData, firstPass);
addProperties(
joinElement,
join.getPropertyIterator(),
currentMapper,
auditingData,
entityName,
xmlMappingData,
firstPass
);
}
}
}
@ -365,95 +484,120 @@ public final class AuditMetadataGenerator {
private Triple<Element, ExtendedPropertyMapper, String> generateMappingData(
PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
IdMappingData idMapper) {
Element class_mapping = MetadataTools.createEntity(xmlMappingData.getMainXmlMapping(), auditTableData,
pc.getDiscriminatorValue(), pc.isAbstract());
ExtendedPropertyMapper propertyMapper = new MultiPropertyMapper();
final Element classMapping = MetadataTools.createEntity(
xmlMappingData.getMainXmlMapping(),
auditTableData,
pc.getDiscriminatorValue(),
pc.isAbstract()
);
final ExtendedPropertyMapper propertyMapper = new MultiPropertyMapper();
// Checking if there is a discriminator column
if ( pc.getDiscriminator() != null ) {
Element discriminator_element = class_mapping.addElement("discriminator");
final Element discriminatorElement = classMapping.addElement( "discriminator" );
// Database column or SQL formula allowed to distinguish entity types
MetadataTools.addColumnsOrFormulas(discriminator_element, pc.getDiscriminator().getColumnIterator());
discriminator_element.addAttribute("type", pc.getDiscriminator().getType().getName());
MetadataTools.addColumnsOrFormulas( discriminatorElement, pc.getDiscriminator().getColumnIterator() );
discriminatorElement.addAttribute( "type", pc.getDiscriminator().getType().getName() );
}
// Adding the id mapping
class_mapping.add((Element) idMapper.getXmlMapping().clone());
classMapping.add( (Element) idMapper.getXmlMapping().clone() );
// Adding the "revision type" property
addRevisionType(class_mapping, class_mapping);
addRevisionType( classMapping, classMapping );
return Triple.make(class_mapping, propertyMapper, null);
return Triple.make( classMapping, propertyMapper, null );
}
private Triple<Element, ExtendedPropertyMapper, String> generateInheritanceMappingData(
PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
String inheritanceMappingType) {
String extendsEntityName = verEntCfg.getAuditEntityName(pc.getSuperclass().getEntityName());
Element class_mapping = MetadataTools.createSubclassEntity(xmlMappingData.getMainXmlMapping(),
inheritanceMappingType, auditTableData, extendsEntityName, pc.getDiscriminatorValue(), pc.isAbstract());
final String extendsEntityName = verEntCfg.getAuditEntityName( pc.getSuperclass().getEntityName() );
final Element classMapping = MetadataTools.createSubclassEntity(
xmlMappingData.getMainXmlMapping(),
inheritanceMappingType,
auditTableData,
extendsEntityName,
pc.getDiscriminatorValue(),
pc.isAbstract()
);
// The id and revision type is already mapped in the parent
// Getting the property mapper of the parent - when mapping properties, they need to be included
String parentEntityName = pc.getSuperclass().getEntityName();
final String parentEntityName = pc.getSuperclass().getEntityName();
EntityConfiguration parentConfiguration = entitiesConfigurations.get(parentEntityName);
final EntityConfiguration parentConfiguration = entitiesConfigurations.get( parentEntityName );
if ( parentConfiguration == null ) {
throw new MappingException("Entity '" + pc.getEntityName() + "' is audited, but its superclass: '" +
parentEntityName + "' is not.");
throw new MappingException(
"Entity '" + pc.getEntityName() + "' is audited, but its superclass: '" +
parentEntityName + "' is not."
);
}
ExtendedPropertyMapper parentPropertyMapper = parentConfiguration.getPropertyMapper();
ExtendedPropertyMapper propertyMapper = new SubclassPropertyMapper(new MultiPropertyMapper(), parentPropertyMapper);
final ExtendedPropertyMapper parentPropertyMapper = parentConfiguration.getPropertyMapper();
final ExtendedPropertyMapper propertyMapper = new SubclassPropertyMapper(
new MultiPropertyMapper(),
parentPropertyMapper
);
return Triple.make(class_mapping, propertyMapper, parentEntityName);
return Triple.make( classMapping, propertyMapper, parentEntityName );
}
@SuppressWarnings({"unchecked"})
public void generateFirstPass(PersistentClass pc, ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData, boolean isAudited) {
String schema = getSchema(auditingData.getAuditTable().schema(), pc.getTable());
String catalog = getCatalog(auditingData.getAuditTable().catalog(), pc.getTable());
public void generateFirstPass(
PersistentClass pc,
ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData,
boolean isAudited) {
final String schema = getSchema( auditingData.getAuditTable().schema(), pc.getTable() );
final String catalog = getCatalog( auditingData.getAuditTable().catalog(), pc.getTable() );
if ( !isAudited ) {
String entityName = pc.getEntityName();
IdMappingData idMapper = idMetadataGenerator.addId(pc, false);
final String entityName = pc.getEntityName();
final IdMappingData idMapper = idMetadataGenerator.addId( pc, false );
if ( idMapper == null ) {
// Unsupported id mapping, e.g. key-many-to-one. If the entity is used in auditing, an exception
// will be thrown later on.
LOG.debugf("Unable to create auditing id mapping for entity %s, because of an unsupported Hibernate id mapping (e.g. key-many-to-one)",
entityName);
LOG.debugf(
"Unable to create auditing id mapping for entity %s, because of an unsupported Hibernate id mapping (e.g. key-many-to-one)",
entityName
);
return;
}
ExtendedPropertyMapper propertyMapper = null;
String parentEntityName = null;
EntityConfiguration entityCfg = new EntityConfiguration(entityName, pc.getClassName(), idMapper, propertyMapper,
parentEntityName);
final ExtendedPropertyMapper propertyMapper = null;
final String parentEntityName = null;
final EntityConfiguration entityCfg = new EntityConfiguration(
entityName,
pc.getClassName(),
idMapper,
propertyMapper,
parentEntityName
);
notAuditedEntitiesConfigurations.put( entityName, entityCfg );
return;
}
String entityName = pc.getEntityName();
final String entityName = pc.getEntityName();
LOG.debugf( "Generating first-pass auditing mapping for entity %s", entityName );
String auditEntityName = verEntCfg.getAuditEntityName(entityName);
String auditTableName = verEntCfg.getAuditTableName(entityName, pc.getTable().getName());
final String auditEntityName = verEntCfg.getAuditEntityName( entityName );
final String auditTableName = verEntCfg.getAuditTableName( entityName, pc.getTable().getName() );
// Registering the audit entity name, now that it is known
auditEntityNameRegister.register( auditEntityName );
AuditTableData auditTableData = new AuditTableData(auditEntityName, auditTableName, schema, catalog);
final AuditTableData auditTableData = new AuditTableData( auditEntityName, auditTableName, schema, catalog );
// Generating a mapping for the id
IdMappingData idMapper = idMetadataGenerator.addId(pc, true);
final IdMappingData idMapper = idMetadataGenerator.addId( pc, true );
InheritanceType inheritanceType = InheritanceType.get(pc);
final InheritanceType inheritanceType = InheritanceType.get( pc );
// These properties will be read from the mapping data
final Element class_mapping;
final Element classMapping;
final ExtendedPropertyMapper propertyMapper;
final String parentEntityName;
@ -473,7 +617,7 @@ public final class AuditMetadataGenerator {
mappingData = generateInheritanceMappingData( pc, xmlMappingData, auditTableData, "joined-subclass" );
// Adding the "key" element with all id columns...
Element keyMapping = mappingData.getFirst().addElement("key");
final Element keyMapping = mappingData.getFirst().addElement( "key" );
MetadataTools.addColumns( keyMapping, pc.getTable().getPrimaryKey().columnIterator() );
// ... and the revision number column, read from the revision info relation mapping.
@ -488,40 +632,56 @@ public final class AuditMetadataGenerator {
throw new AssertionError( "Impossible enum value." );
}
class_mapping = mappingData.getFirst();
classMapping = mappingData.getFirst();
propertyMapper = mappingData.getSecond();
parentEntityName = mappingData.getThird();
xmlMappingData.setClassMapping(class_mapping);
xmlMappingData.setClassMapping( classMapping );
// Mapping unjoined properties
addProperties(class_mapping, pc.getUnjoinedPropertyIterator(), propertyMapper,
addProperties(
classMapping, pc.getUnjoinedPropertyIterator(), propertyMapper,
auditingData, pc.getEntityName(), xmlMappingData,
true);
true
);
// Creating and mapping joins (first pass)
createJoins(pc, class_mapping, auditingData);
createJoins( pc, classMapping, auditingData );
addJoins( pc, propertyMapper, auditingData, pc.getEntityName(), xmlMappingData, true );
// Storing the generated configuration
EntityConfiguration entityCfg = new EntityConfiguration(auditEntityName, pc.getClassName(), idMapper,
propertyMapper, parentEntityName);
final EntityConfiguration entityCfg = new EntityConfiguration(
auditEntityName,
pc.getClassName(),
idMapper,
propertyMapper,
parentEntityName
);
entitiesConfigurations.put( pc.getEntityName(), entityCfg );
}
@SuppressWarnings({"unchecked"})
public void generateSecondPass(PersistentClass pc, ClassAuditingData auditingData,
public void generateSecondPass(
PersistentClass pc,
ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData) {
String entityName = pc.getEntityName();
final String entityName = pc.getEntityName();
LOG.debugf( "Generating second-pass auditing mapping for entity %s", entityName );
CompositeMapperBuilder propertyMapper = entitiesConfigurations.get(entityName).getPropertyMapper();
final CompositeMapperBuilder propertyMapper = entitiesConfigurations.get( entityName ).getPropertyMapper();
// Mapping unjoined properties
Element parent = xmlMappingData.getClassMapping();
final Element parent = xmlMappingData.getClassMapping();
addProperties(parent, pc.getUnjoinedPropertyIterator(),
propertyMapper, auditingData, entityName, xmlMappingData, false);
addProperties(
parent,
pc.getUnjoinedPropertyIterator(),
propertyMapper,
auditingData,
entityName,
xmlMappingData,
false
);
// Mapping joins (second pass)
addJoins( pc, propertyMapper, auditingData, entityName, xmlMappingData, false );
@ -562,7 +722,7 @@ public final class AuditMetadataGenerator {
}
void throwUnsupportedTypeException(Type type, String entityName, String propertyName) {
String message = "Type not supported for auditing: " + type.getClass().getName() +
final String message = "Type not supported for auditing: " + type.getClass().getName() +
", on entity " + entityName + ", property '" + propertyName + "'.";
throw new MappingException( message );
@ -570,28 +730,36 @@ public final class AuditMetadataGenerator {
/**
* Reads the id mapping data of a referenced entity.
*
* @param entityName Name of the entity which is the source of the relation.
* @param referencedEntityName Name of the entity which is the target of the relation.
* @param propertyAuditingData Auditing data of the property that is the source of the relation.
* @param allowNotAuditedTarget Are not-audited target entities allowed.
*
* @return The id mapping data of the related entity.
*
* @throws MappingException If a relation from an audited to a non-audited entity is detected, which is not
* mapped using {@link RelationTargetAuditMode#NOT_AUDITED}.
* @return The id mapping data of the related entity.
*/
IdMappingData getReferencedIdMappingData(String entityName, String referencedEntityName,
IdMappingData getReferencedIdMappingData(
String entityName, String referencedEntityName,
PropertyAuditingData propertyAuditingData,
boolean allowNotAuditedTarget) {
EntityConfiguration configuration = getEntitiesConfigurations().get( referencedEntityName );
if ( configuration == null ) {
RelationTargetAuditMode relationTargetAuditMode = propertyAuditingData.getRelationTargetAuditMode();
final RelationTargetAuditMode relationTargetAuditMode = propertyAuditingData.getRelationTargetAuditMode();
configuration = getNotAuditedEntitiesConfigurations().get( referencedEntityName );
if (configuration == null || !allowNotAuditedTarget || !RelationTargetAuditMode.NOT_AUDITED.equals(relationTargetAuditMode)) {
throw new MappingException("An audited relation from " + entityName + "."
if ( configuration == null || !allowNotAuditedTarget || !RelationTargetAuditMode.NOT_AUDITED.equals(
relationTargetAuditMode
) ) {
throw new MappingException(
"An audited relation from " + entityName + "."
+ propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!"
+ (allowNotAuditedTarget ?
" Such mapping is possible, but has to be explicitly defined using @Audited(targetAuditMode = NOT_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) 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,13 +21,13 @@
* 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 {

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,
boolean addBasic(
Element parent, PropertyAuditingData propertyAuditingData,
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
Type type = value.getType();
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.
}
}
@SuppressWarnings({"unchecked"})
boolean addManyToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value, SimpleMapperBuilder mapper) {
Type type = value.getType();
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,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,6 +23,7 @@
*/
package org.hibernate.envers.configuration.internal.metadata;
import javax.persistence.JoinColumn;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@ -32,9 +33,9 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.persistence.JoinColumn;
import org.dom4j.Element;
import org.jboss.logging.Logger;
import org.hibernate.MappingException;
@ -102,12 +103,15 @@ import org.hibernate.type.Type;
/**
* Generates metadata for a collection-valued property.
*
* @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau
*/
public final class CollectionMetadataGenerator {
public static final EnversMessageLogger LOG = Logger.getMessageLogger(EnversMessageLogger.class, CollectionMetadataGenerator.class.getName());
private static final EnversMessageLogger LOG = Logger.getMessageLogger(
EnversMessageLogger.class,
CollectionMetadataGenerator.class.getName()
);
private final AuditMetadataGenerator mainGenerator;
private final String propertyName;
@ -134,7 +138,8 @@ public final class CollectionMetadataGenerator {
* property that references the collection in the referencing entity, the user data for middle (join)
* table and the value of the <code>@MapKey</code> annotation, if there was one.
*/
public CollectionMetadataGenerator(AuditMetadataGenerator mainGenerator,
public CollectionMetadataGenerator(
AuditMetadataGenerator mainGenerator,
Collection propertyValue, CompositeMapperBuilder currentMapper,
String referencingEntityName, EntityXmlMappingData xmlMappingData,
PropertyAuditingData propertyAuditingData) {
@ -156,52 +161,67 @@ public final class CollectionMetadataGenerator {
}
void addCollection() {
Type type = propertyValue.getType();
Value value = propertyValue.getElement();
final Type type = propertyValue.getType();
final Value value = propertyValue.getElement();
boolean oneToManyAttachedType = type instanceof BagType || type instanceof SetType || type instanceof MapType || type instanceof ListType;
boolean inverseOneToMany = (value instanceof OneToMany) && (propertyValue.isInverse());
boolean owningManyToOneWithJoinTableBidirectional = (value instanceof ManyToOne) && (propertyAuditingData.getRelationMappedBy() != null);
boolean fakeOneToManyBidirectional = (value instanceof OneToMany) && (propertyAuditingData.getAuditMappedBy() != null);
final boolean oneToManyAttachedType = type instanceof BagType || type instanceof SetType || type instanceof MapType || type instanceof ListType;
final boolean inverseOneToMany = (value instanceof OneToMany) && (propertyValue.isInverse());
final boolean owningManyToOneWithJoinTableBidirectional = (value instanceof ManyToOne) && (propertyAuditingData.getRelationMappedBy() != null);
final boolean fakeOneToManyBidirectional = (value instanceof OneToMany) && (propertyAuditingData.getAuditMappedBy() != null);
if ( oneToManyAttachedType && (inverseOneToMany || fakeOneToManyBidirectional || owningManyToOneWithJoinTableBidirectional) ) {
// A one-to-many relation mapped using @ManyToOne and @OneToMany(mappedBy="...")
addOneToManyAttached( fakeOneToManyBidirectional );
} else {
}
else {
// All other kinds of relations require a middle (join) table.
addWithMiddleTable();
}
}
private MiddleIdData createMiddleIdData(IdMappingData idMappingData, String prefix, String entityName) {
return new MiddleIdData(mainGenerator.getVerEntCfg(), idMappingData, prefix, entityName,
mainGenerator.getEntitiesConfigurations().containsKey(entityName));
return new MiddleIdData(
mainGenerator.getVerEntCfg(), idMappingData, prefix, entityName,
mainGenerator.getEntitiesConfigurations().containsKey( entityName )
);
}
@SuppressWarnings({"unchecked"})
private void addOneToManyAttached(boolean fakeOneToManyBidirectional) {
LOG.debugf("Adding audit mapping for property %s.%s: one-to-many collection, using a join column on the referenced entity",
LOG.debugf(
"Adding audit mapping for property %s.%s: one-to-many collection, using a join column on the referenced entity",
referencingEntityName,
propertyName);
propertyName
);
String mappedBy = getMappedBy(propertyValue);
final String mappedBy = getMappedBy( propertyValue );
IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(referencingEntityName,
referencedEntityName, propertyAuditingData, false);
IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
final IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(
referencingEntityName,
referencedEntityName,
propertyAuditingData,
false
);
final IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
// Generating the id mappers data for the referencing side of the relation.
MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping,
mappedBy + "_", referencingEntityName);
final MiddleIdData referencingIdData = createMiddleIdData(
referencingIdMapping,
mappedBy + "_",
referencingEntityName
);
// And for the referenced side. The prefixed mapper won't be used (as this collection isn't persisted
// in a join table, so the prefix value is arbitrary).
MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping,
null, referencedEntityName);
final MiddleIdData referencedIdData = createMiddleIdData(
referencedIdMapping,
null, referencedEntityName
);
// Generating the element mapping.
MiddleComponentData elementComponentData = new MiddleComponentData(
new MiddleRelatedComponentMapper(referencedIdData), 0);
final MiddleComponentData elementComponentData = new MiddleComponentData(
new MiddleRelatedComponentMapper( referencedIdData ), 0
);
// Generating the index mapping, if an index exists. It can only exists in case a javax.persistence.MapKey
// annotation is present on the entity. So the middleEntityXml will be not be used. The queryGeneratorBuilder
@ -209,45 +229,66 @@ public final class CollectionMetadataGenerator {
MiddleComponentData indexComponentData = addIndex( null, null );
// Generating the query generator - it should read directly from the related entity.
RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(),
referencingIdData, referencedEntityName, referencedIdData, isEmbeddableElementType());
final RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(
mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(),
mainGenerator.getAuditStrategy(),
referencingIdData,
referencedEntityName,
referencedIdData,
isEmbeddableElementType()
);
// Creating common mapper data.
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
final CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(), referencedEntityName,
propertyAuditingData.getPropertyData(),
referencingIdData, queryGenerator);
referencingIdData, queryGenerator
);
PropertyMapper fakeBidirectionalRelationMapper;
PropertyMapper fakeBidirectionalRelationIndexMapper;
if ( fakeOneToManyBidirectional ) {
// In case of a fake many-to-one bidirectional relation, we have to generate a mapper which maps
// the mapped-by property name to the id of the related entity (which is the owner of the collection).
String auditMappedBy = propertyAuditingData.getAuditMappedBy();
final String auditMappedBy = propertyAuditingData.getAuditMappedBy();
// Creating a prefixed relation mapper.
IdMapper relMapper = referencingIdMapping.getIdMapper().prefixMappedProperties(
MappingTools.createToOneRelationPrefix(auditMappedBy));
final IdMapper relMapper = referencingIdMapping.getIdMapper().prefixMappedProperties(
MappingTools.createToOneRelationPrefix( auditMappedBy )
);
fakeBidirectionalRelationMapper = new ToOneIdMapper(
relMapper,
// The mapper will only be used to map from entity to map, so no need to provide other details
// when constructing the PropertyData.
new PropertyData( auditMappedBy, null, null, null ),
referencingEntityName, false);
referencingEntityName, false
);
// Checking if there's an index defined. If so, adding a mapper for it.
if ( propertyAuditingData.getPositionMappedBy() != null ) {
String positionMappedBy = propertyAuditingData.getPositionMappedBy();
fakeBidirectionalRelationIndexMapper = new SinglePropertyMapper(new PropertyData(positionMappedBy, null, null, null));
final String positionMappedBy = propertyAuditingData.getPositionMappedBy();
fakeBidirectionalRelationIndexMapper = new SinglePropertyMapper(
new PropertyData(
positionMappedBy,
null,
null,
null
)
);
// Also, overwriting the index component data to properly read the index.
indexComponentData = new MiddleComponentData(new MiddleStraightComponentMapper(positionMappedBy), 0);
} else {
indexComponentData = new MiddleComponentData(
new MiddleStraightComponentMapper( positionMappedBy ),
0
);
}
else {
fakeBidirectionalRelationIndexMapper = null;
}
} else {
}
else {
fakeBidirectionalRelationMapper = null;
fakeBidirectionalRelationIndexMapper = null;
}
@ -256,23 +297,30 @@ public final class CollectionMetadataGenerator {
addMapper( commonCollectionMapperData, elementComponentData, indexComponentData );
// Storing information about this relation.
referencingEntityConfiguration.addToManyNotOwningRelation(propertyName, mappedBy,
referencedEntityName, referencingIdData.getPrefixedMapper(), fakeBidirectionalRelationMapper,
fakeBidirectionalRelationIndexMapper);
referencingEntityConfiguration.addToManyNotOwningRelation(
propertyName,
mappedBy,
referencedEntityName,
referencingIdData.getPrefixedMapper(),
fakeBidirectionalRelationMapper,
fakeBidirectionalRelationIndexMapper
);
}
/**
* Adds mapping of the id of a related entity to the given xml mapping, prefixing the id with the given prefix.
*
* @param xmlMapping Mapping, to which to add the xml.
* @param prefix Prefix for the names of properties which will be prepended to properties that form the id.
* @param columnNameIterator Iterator over the column names that will be used for properties that form the id.
* @param relatedIdMapping Id mapping data of the related entity.
*/
@SuppressWarnings({"unchecked"})
private void addRelatedToXmlMapping(Element xmlMapping, String prefix,
private void addRelatedToXmlMapping(
Element xmlMapping, String prefix,
MetadataTools.ColumnNameIterator columnNameIterator,
IdMappingData relatedIdMapping) {
Element properties = (Element) relatedIdMapping.getXmlRelationMapping().clone();
final Element properties = (Element) relatedIdMapping.getXmlRelationMapping().clone();
MetadataTools.prefixNamesInPropertyElement( properties, prefix, columnNameIterator, true, true );
for ( Element idProperty : (java.util.List<Element>) properties.elements() ) {
xmlMapping.add( (Element) idProperty.clone() );
@ -284,7 +332,11 @@ public final class CollectionMetadataGenerator {
if ( value.getElement() instanceof OneToMany && !value.isInverse() ) {
// This must be a @JoinColumn+@OneToMany mapping. Generating the table name, as Hibernate doesn't use a
// middle table for mapping this relation.
return StringTools.getLastComponent(entityName) + "_" + StringTools.getLastComponent(MappingTools.getReferencedEntityName(value.getElement()));
return StringTools.getLastComponent( entityName ) + "_" + StringTools.getLastComponent(
MappingTools.getReferencedEntityName(
value.getElement()
)
);
}
// Hibernate uses a middle table for mapping this relation, so we get it's name directly.
return value.getCollectionTable().getName();
@ -293,7 +345,11 @@ public final class CollectionMetadataGenerator {
@SuppressWarnings({"unchecked"})
private void addWithMiddleTable() {
LOG.debugf("Adding audit mapping for property %s.%s: collection with a join table", referencingEntityName, propertyName);
LOG.debugf(
"Adding audit mapping for property %s.%s: collection with a join table",
referencingEntityName,
propertyName
);
// Generating the name of the middle table
String auditMiddleTableName;
@ -301,8 +357,9 @@ public final class CollectionMetadataGenerator {
if ( !StringTools.isEmpty( propertyAuditingData.getJoinTable().name() ) ) {
auditMiddleTableName = propertyAuditingData.getJoinTable().name();
auditMiddleEntityName = propertyAuditingData.getJoinTable().name();
} else {
String middleTableName = getMiddleTableName(propertyValue, referencingEntityName);
}
else {
final String middleTableName = getMiddleTableName( propertyValue, referencingEntityName );
auditMiddleTableName = mainGenerator.getVerEntCfg().getAuditTableName( null, middleTableName );
auditMiddleEntityName = mainGenerator.getVerEntCfg().getAuditEntityName( middleTableName );
}
@ -319,8 +376,13 @@ public final class CollectionMetadataGenerator {
// Registering the generated name
mainGenerator.getAuditEntityNameRegister().register( auditMiddleEntityName );
middleEntityXml = createMiddleEntityXml(auditMiddleTableName, auditMiddleEntityName, propertyValue.getWhere());
} else {
middleEntityXml = createMiddleEntityXml(
auditMiddleTableName,
auditMiddleEntityName,
propertyValue.getWhere()
);
}
else {
middleEntityXml = null;
}
@ -328,7 +390,7 @@ public final class CollectionMetadataGenerator {
// Generating the mapping for the referencing entity (it must be an entity).
// ******
// Getting the id-mapping data of the referencing entity (the entity that "owns" this collection).
IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
final IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
// Only valid for an inverse relation; null otherwise.
String mappedBy;
@ -339,11 +401,15 @@ public final class CollectionMetadataGenerator {
if ( propertyValue.isInverse() ) {
// If the relation is inverse, then referencedEntityName is not null.
mappedBy = getMappedBy(propertyValue.getCollectionTable(), mainGenerator.getCfg().getClassMapping(referencedEntityName));
mappedBy = getMappedBy(
propertyValue.getCollectionTable(),
mainGenerator.getCfg().getClassMapping( referencedEntityName )
);
referencingPrefixRelated = mappedBy + "_";
referencedPrefix = StringTools.getLastComponent( referencedEntityName );
} else {
}
else {
mappedBy = null;
referencingPrefixRelated = StringTools.getLastComponent( referencingEntityName ) + "_";
@ -351,46 +417,64 @@ public final class CollectionMetadataGenerator {
}
// Storing the id data of the referencing entity: original mapper, prefixed mapper and entity name.
MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping,
referencingPrefixRelated, referencingEntityName);
final MiddleIdData referencingIdData = createMiddleIdData(
referencingIdMapping,
referencingPrefixRelated,
referencingEntityName
);
// Creating a query generator builder, to which additional id data will be added, in case this collection
// references some entities (either from the element or index). At the end, this will be used to build
// a query generator to read the raw data collection from the middle table.
QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData,
auditMiddleEntityName, isEmbeddableElementType());
final QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(
mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(),
mainGenerator.getAuditStrategy(),
referencingIdData,
auditMiddleEntityName,
isEmbeddableElementType()
);
// Adding the XML mapping for the referencing entity, if the relation isn't inverse.
if ( middleEntityXml != null ) {
// Adding related-entity (in this case: the referencing's entity id) id mapping to the xml.
addRelatedToXmlMapping(middleEntityXml, referencingPrefixRelated,
addRelatedToXmlMapping(
middleEntityXml, referencingPrefixRelated,
MetadataTools.getColumnNameIterator( propertyValue.getKey().getColumnIterator() ),
referencingIdMapping);
referencingIdMapping
);
}
// ******
// Generating the element mapping.
// ******
MiddleComponentData elementComponentData = addValueToMiddleTable(propertyValue.getElement(), middleEntityXml,
queryGeneratorBuilder, referencedPrefix, propertyAuditingData.getJoinTable().inverseJoinColumns());
final MiddleComponentData elementComponentData = addValueToMiddleTable(
propertyValue.getElement(),
middleEntityXml,
queryGeneratorBuilder,
referencedPrefix,
propertyAuditingData.getJoinTable().inverseJoinColumns()
);
// ******
// Generating the index mapping, if an index exists.
// ******
MiddleComponentData indexComponentData = addIndex(middleEntityXml, queryGeneratorBuilder);
final MiddleComponentData indexComponentData = addIndex( middleEntityXml, queryGeneratorBuilder );
// ******
// Generating the property mapper.
// ******
// Building the query generator.
RelationQueryGenerator queryGenerator = queryGeneratorBuilder.build(elementComponentData, indexComponentData);
final RelationQueryGenerator queryGenerator = queryGeneratorBuilder.build( elementComponentData, indexComponentData );
// Creating common data
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(), auditMiddleEntityName,
final CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(),
auditMiddleEntityName,
propertyAuditingData.getPropertyData(),
referencingIdData, queryGenerator);
referencingIdData,
queryGenerator
);
// Checking the type of the collection and adding an appropriate mapper.
addMapper( commonCollectionMapperData, elementComponentData, indexComponentData );
@ -403,34 +487,51 @@ public final class CollectionMetadataGenerator {
private MiddleComponentData addIndex(Element middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) {
if ( propertyValue instanceof IndexedCollection ) {
IndexedCollection indexedValue = (IndexedCollection) propertyValue;
String mapKey = propertyAuditingData.getMapKey();
final IndexedCollection indexedValue = (IndexedCollection) propertyValue;
final String mapKey = propertyAuditingData.getMapKey();
if ( mapKey == null ) {
// This entity doesn't specify a javax.persistence.MapKey. Mapping it to the middle entity.
return addValueToMiddleTable(indexedValue.getIndex(), middleEntityXml,
queryGeneratorBuilder, "mapkey", null);
} else {
IdMappingData referencedIdMapping = mainGenerator.getEntitiesConfigurations()
return addValueToMiddleTable(
indexedValue.getIndex(),
middleEntityXml,
queryGeneratorBuilder,
"mapkey",
null
);
}
else {
final IdMappingData referencedIdMapping = mainGenerator.getEntitiesConfigurations()
.get( referencedEntityName ).getIdMappingData();
int currentIndex = queryGeneratorBuilder == null ? 0 : queryGeneratorBuilder.getCurrentIndex();
final int currentIndex = queryGeneratorBuilder == null ? 0 : queryGeneratorBuilder.getCurrentIndex();
if ( "".equals( mapKey ) ) {
// The key of the map is the id of the entity.
return new MiddleComponentData(new MiddleMapKeyIdComponentMapper(mainGenerator.getVerEntCfg(),
referencedIdMapping.getIdMapper()), currentIndex);
} else {
return new MiddleComponentData(
new MiddleMapKeyIdComponentMapper(
mainGenerator.getVerEntCfg(),
referencedIdMapping.getIdMapper()
),
currentIndex
);
}
else {
// The key of the map is a property of the entity.
return new MiddleComponentData(new MiddleMapKeyPropertyComponentMapper(mapKey,
propertyAuditingData.getAccessType()), currentIndex);
return new MiddleComponentData(
new MiddleMapKeyPropertyComponentMapper(
mapKey,
propertyAuditingData.getAccessType()
),
currentIndex
);
}
}
} else {
}
else {
// No index - creating a dummy mapper.
return new MiddleComponentData( new MiddleDummyComponentMapper(), 0 );
}
}
/**
*
* @param value Value, which should be mapped to the middle-table, either as a relation to another entity,
* or as a simple value.
* @param xmlMapping If not <code>null</code>, xml mapping for this value is added to this element.
@ -438,44 +539,66 @@ public final class CollectionMetadataGenerator {
* should be added to the given.
* @param prefix Prefix for proeprty names of related entities identifiers.
* @param joinColumns Names of columns to use in the xml mapping, if this array isn't null and has any elements.
*
* @return Data for mapping this component.
*/
@SuppressWarnings({"unchecked"})
private MiddleComponentData addValueToMiddleTable(Value value, Element xmlMapping,
private MiddleComponentData addValueToMiddleTable(
Value value,
Element xmlMapping,
QueryGeneratorBuilder queryGeneratorBuilder,
String prefix, JoinColumn[] joinColumns) {
Type type = value.getType();
String prefix,
JoinColumn[] joinColumns) {
final Type type = value.getType();
if ( type instanceof ManyToOneType ) {
String prefixRelated = prefix + "_";
final String prefixRelated = prefix + "_";
String referencedEntityName = MappingTools.getReferencedEntityName(value);
final String referencedEntityName = MappingTools.getReferencedEntityName( value );
IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(referencingEntityName,
referencedEntityName, propertyAuditingData, true);
final IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(
referencingEntityName,
referencedEntityName,
propertyAuditingData,
true
);
// Adding related-entity (in this case: the referenced entities id) id mapping to the xml only if the
// relation isn't inverse (so when <code>xmlMapping</code> is not null).
if ( xmlMapping != null ) {
addRelatedToXmlMapping(xmlMapping, prefixRelated,
addRelatedToXmlMapping(
xmlMapping, prefixRelated,
joinColumns != null && joinColumns.length > 0
? MetadataTools.getColumnNameIterator( joinColumns )
: MetadataTools.getColumnNameIterator( value.getColumnIterator() ),
referencedIdMapping);
referencedIdMapping
);
}
// Storing the id data of the referenced entity: original mapper, prefixed mapper and entity name.
MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping,
prefixRelated, referencedEntityName);
final MiddleIdData referencedIdData = createMiddleIdData(
referencedIdMapping,
prefixRelated,
referencedEntityName
);
// And adding it to the generator builder.
queryGeneratorBuilder.addRelation( referencedIdData );
return new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData),
queryGeneratorBuilder.getCurrentIndex());
} else if ( type instanceof ComponentType ) {
return new MiddleComponentData(
new MiddleRelatedComponentMapper( referencedIdData ),
queryGeneratorBuilder.getCurrentIndex()
);
}
else if ( type instanceof ComponentType ) {
// Collection of embeddable elements.
final Component component = (Component) value;
final Class componentClass = ReflectionTools.loadClass( component.getComponentClassName(), mainGenerator.getClassLoaderService() );
final MiddleEmbeddableComponentMapper componentMapper = new MiddleEmbeddableComponentMapper( new MultiPropertyMapper(), componentClass );
final Class componentClass = ReflectionTools.loadClass(
component.getComponentClassName(),
mainGenerator.getClassLoaderService()
);
final MiddleEmbeddableComponentMapper componentMapper = new MiddleEmbeddableComponentMapper(
new MultiPropertyMapper(),
componentClass
);
final Element parentXmlMapping = xmlMapping.getParent();
final ComponentAuditingData auditData = new ComponentAuditingData();
@ -489,27 +612,40 @@ public final class CollectionMetadataGenerator {
// Emulating first pass.
for ( String auditedPropertyName : auditData.getPropertyNames() ) {
PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
final PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
mainGenerator.addValue(
parentXmlMapping, component.getProperty( auditedPropertyName ).getValue(), componentMapper,
prefix, xmlMappingData, nestedAuditingData, true, true, true
parentXmlMapping,
component.getProperty( auditedPropertyName ).getValue(),
componentMapper,
prefix, xmlMappingData,
nestedAuditingData,
true,
true,
true
);
}
// Emulating second pass so that the relations can be mapped too.
for ( String auditedPropertyName : auditData.getPropertyNames() ) {
PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
final PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
mainGenerator.addValue(
parentXmlMapping, component.getProperty( auditedPropertyName ).getValue(),
componentMapper, referencingEntityName, xmlMappingData, nestedAuditingData,
true, false, true
parentXmlMapping,
component.getProperty( auditedPropertyName ).getValue(),
componentMapper,
referencingEntityName,
xmlMappingData,
nestedAuditingData,
true,
false,
true
);
}
// Add an additional column holding a number to make each entry unique within the set.
// Embeddable properties may contain null values, so cannot be stored within composite primary key.
if ( propertyValue.isSet() ) {
final String setOrdinalPropertyName = mainGenerator.getVerEntCfg().getEmbeddableSetOrdinalPropertyName();
final String setOrdinalPropertyName = mainGenerator.getVerEntCfg()
.getEmbeddableSetOrdinalPropertyName();
final Element ordinalProperty = MetadataTools.addProperty(
xmlMapping, setOrdinalPropertyName, "integer", true, true
);
@ -519,16 +655,34 @@ public final class CollectionMetadataGenerator {
}
return new MiddleComponentData( componentMapper, 0 );
} else {
}
else {
// Last but one parameter: collection components are always insertable
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
new PropertyAuditingData(prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false),
value, null, true, true);
final boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(
xmlMapping,
new PropertyAuditingData(
prefix,
"field",
ModificationStore.FULL,
RelationTargetAuditMode.AUDITED,
null,
null,
false
),
value,
null,
true,
true
);
if ( mapped ) {
// Simple values are always stored in the first item of the array returned by the query generator.
return new MiddleComponentData(new MiddleSimpleComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0);
} else {
return new MiddleComponentData(
new MiddleSimpleComponentMapper( mainGenerator.getVerEntCfg(), prefix ),
0
);
}
else {
mainGenerator.throwUnsupportedTypeException( type, referencingEntityName, propertyName );
// Impossible to get here.
throw new AssertionError();
@ -536,39 +690,94 @@ public final class CollectionMetadataGenerator {
}
}
private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData,
private void addMapper(
CommonCollectionMapperData commonCollectionMapperData,
MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
Type type = propertyValue.getType();
boolean embeddableElementType = isEmbeddableElementType();
final Type type = propertyValue.getType();
final boolean embeddableElementType = isEmbeddableElementType();
if ( type instanceof SortedSetType ) {
currentMapper.addComposite( propertyAuditingData.getPropertyData(), new SortedSetCollectionMapper(
commonCollectionMapperData, TreeSet.class, SortedSetProxy.class, elementComponentData,
propertyValue.getComparator(), embeddableElementType, embeddableElementType ) );
} else if (type instanceof SetType) {
currentMapper.addComposite( propertyAuditingData.getPropertyData(), new BasicCollectionMapper<Set>(
commonCollectionMapperData, HashSet.class, SetProxy.class, elementComponentData,
embeddableElementType, embeddableElementType ) );
} else if (type instanceof SortedMapType) {
currentMapper.addComposite(
propertyAuditingData.getPropertyData(),
new SortedSetCollectionMapper(
commonCollectionMapperData,
TreeSet.class,
SortedSetProxy.class,
elementComponentData,
propertyValue.getComparator(),
embeddableElementType,
embeddableElementType
)
);
}
else if ( type instanceof SetType ) {
currentMapper.addComposite(
propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<Set>(
commonCollectionMapperData,
HashSet.class,
SetProxy.class,
elementComponentData,
embeddableElementType,
embeddableElementType
)
);
}
else if ( type instanceof SortedMapType ) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new SortedMapCollectionMapper(commonCollectionMapperData,
TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData, propertyValue.getComparator(),
embeddableElementType));
} else if (type instanceof MapType) {
currentMapper.addComposite(
propertyAuditingData.getPropertyData(),
new SortedMapCollectionMapper(
commonCollectionMapperData,
TreeMap.class,
SortedMapProxy.class,
elementComponentData,
indexComponentData,
propertyValue.getComparator(),
embeddableElementType
)
);
}
else if ( type instanceof MapType ) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new MapCollectionMapper<Map>(commonCollectionMapperData,
HashMap.class, MapProxy.class, elementComponentData, indexComponentData, embeddableElementType));
} else if (type instanceof BagType) {
currentMapper.addComposite( propertyAuditingData.getPropertyData(), new BasicCollectionMapper<List>(
commonCollectionMapperData, ArrayList.class, ListProxy.class, elementComponentData,
embeddableElementType, embeddableElementType ) );
} else if (type instanceof ListType) {
currentMapper.addComposite(
propertyAuditingData.getPropertyData(),
new MapCollectionMapper<Map>(
commonCollectionMapperData,
HashMap.class,
MapProxy.class,
elementComponentData,
indexComponentData,
embeddableElementType
)
);
}
else if ( type instanceof BagType ) {
currentMapper.addComposite(
propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<List>(
commonCollectionMapperData,
ArrayList.class,
ListProxy.class,
elementComponentData,
embeddableElementType,
embeddableElementType
)
);
}
else if ( type instanceof ListType ) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new ListCollectionMapper(commonCollectionMapperData,
elementComponentData, indexComponentData, embeddableElementType));
} else {
currentMapper.addComposite(
propertyAuditingData.getPropertyData(),
new ListCollectionMapper(
commonCollectionMapperData,
elementComponentData,
indexComponentData,
embeddableElementType
)
);
}
else {
mainGenerator.throwUnsupportedTypeException( type, referencingEntityName, propertyName );
}
}
@ -577,20 +786,33 @@ public final class CollectionMetadataGenerator {
// Only if this is a relation (when there is a referenced entity).
if ( referencedEntityName != null ) {
if ( propertyValue.isInverse() ) {
referencingEntityConfiguration.addToManyMiddleNotOwningRelation(propertyName, mappedBy, referencedEntityName);
} else {
referencingEntityConfiguration.addToManyMiddleNotOwningRelation(
propertyName,
mappedBy,
referencedEntityName
);
}
else {
referencingEntityConfiguration.addToManyMiddleRelation( propertyName, referencedEntityName );
}
}
}
private Element createMiddleEntityXml(String auditMiddleTableName, String auditMiddleEntityName, String where) {
String schema = mainGenerator.getSchema(propertyAuditingData.getJoinTable().schema(), propertyValue.getCollectionTable());
String catalog = mainGenerator.getCatalog(propertyAuditingData.getJoinTable().catalog(), propertyValue.getCollectionTable());
final String schema = mainGenerator.getSchema(
propertyAuditingData.getJoinTable().schema(),
propertyValue.getCollectionTable()
);
final String catalog = mainGenerator.getCatalog(
propertyAuditingData.getJoinTable().catalog(),
propertyValue.getCollectionTable()
);
Element middleEntityXml = MetadataTools.createEntity(xmlMappingData.newAdditionalMapping(),
new AuditTableData(auditMiddleEntityName, auditMiddleTableName, schema, catalog), null, null);
Element middleEntityXmlId = middleEntityXml.addElement("composite-id");
final Element middleEntityXml = MetadataTools.createEntity(
xmlMappingData.newAdditionalMapping(),
new AuditTableData( auditMiddleEntityName, auditMiddleTableName, schema, catalog ), null, null
);
final Element middleEntityXmlId = middleEntityXml.addElement( "composite-id" );
// If there is a where clause on the relation, adding it to the middle entity.
if ( where != null ) {
@ -604,7 +826,10 @@ public final class CollectionMetadataGenerator {
mainGenerator.addRevisionInfoRelation( middleEntityXmlId );
// Adding the revision type property to the entity xml.
mainGenerator.addRevisionType(isEmbeddableElementType() ? middleEntityXmlId : middleEntityXml, middleEntityXml);
mainGenerator.addRevisionType(
isEmbeddableElementType() ? middleEntityXmlId : middleEntityXml,
middleEntityXml
);
// All other properties should also be part of the primary key of the middle entity.
return middleEntityXmlId;
@ -620,16 +845,17 @@ public final class CollectionMetadataGenerator {
private String getMappedBy(Collection collectionValue) {
PersistentClass referencedClass = null;
if ( collectionValue.getElement() instanceof OneToMany ) {
OneToMany oneToManyValue = (OneToMany) collectionValue.getElement();
final OneToMany oneToManyValue = (OneToMany) collectionValue.getElement();
referencedClass = oneToManyValue.getAssociatedClass();
} else if (collectionValue.getElement() instanceof ManyToOne) {
}
else if ( collectionValue.getElement() instanceof ManyToOne ) {
// Case for bi-directional relation with @JoinTable on the owning @ManyToOne side.
ManyToOne manyToOneValue = (ManyToOne) collectionValue.getElement();
final ManyToOne manyToOneValue = (ManyToOne) collectionValue.getElement();
referencedClass = manyToOneValue.getMappings().getClass( manyToOneValue.getReferencedEntityName() );
}
// If there's an @AuditMappedBy specified, returning it directly.
String auditMappedBy = propertyAuditingData.getAuditMappedBy();
final String auditMappedBy = propertyAuditingData.getAuditMappedBy();
if ( auditMappedBy != null ) {
return auditMappedBy;
}
@ -638,9 +864,11 @@ public final class CollectionMetadataGenerator {
String mappedBy = this.searchMappedBy( referencedClass, collectionValue );
if ( mappedBy == null ) {
LOG.debugf("Going to search the mapped by attribute for %s in superclasses of entity: %s",
LOG.debugf(
"Going to search the mapped by attribute for %s in superclasses of entity: %s",
propertyName,
referencedClass.getClassName());
referencedClass.getClassName()
);
PersistentClass tempClass = referencedClass;
while ( (mappedBy == null) && (tempClass.getSuperclass() != null) ) {
@ -651,8 +879,10 @@ public final class CollectionMetadataGenerator {
}
if ( mappedBy == null ) {
throw new MappingException("Unable to read the mapped by attribute for " + propertyName + " in "
+ referencedClass.getClassName() + "!");
throw new MappingException(
"Unable to read the mapped by attribute for " + propertyName + " in "
+ referencedClass.getClassName() + "!"
);
}
return mappedBy;
@ -660,12 +890,14 @@ public final class CollectionMetadataGenerator {
@SuppressWarnings({"unchecked"})
private String searchMappedBy(PersistentClass referencedClass, Collection collectionValue) {
Iterator<Property> assocClassProps = referencedClass.getPropertyIterator();
final Iterator<Property> assocClassProps = referencedClass.getPropertyIterator();
while ( assocClassProps.hasNext() ) {
Property property = assocClassProps.next();
final Property property = assocClassProps.next();
if (Tools.iteratorsContentEqual(property.getValue().getColumnIterator(),
collectionValue.getKey().getColumnIterator())) {
if ( Tools.iteratorsContentEqual(
property.getValue().getColumnIterator(),
collectionValue.getKey().getColumnIterator()
) ) {
return property.getName();
}
}
@ -674,7 +906,7 @@ public final class CollectionMetadataGenerator {
private String getMappedBy(Table collectionTable, PersistentClass referencedClass) {
// If there's an @AuditMappedBy specified, returning it directly.
String auditMappedBy = propertyAuditingData.getAuditMappedBy();
final String auditMappedBy = propertyAuditingData.getAuditMappedBy();
if ( auditMappedBy != null ) {
return auditMappedBy;
}
@ -684,9 +916,11 @@ public final class CollectionMetadataGenerator {
// not found on referenced class, searching on superclasses
if ( mappedBy == null ) {
LOG.debugf("Going to search the mapped by attribute for %s in superclasses of entity: %s",
LOG.debugf(
"Going to search the mapped by attribute for %s in superclasses of entity: %s",
propertyName,
referencedClass.getClassName());
referencedClass.getClassName()
);
PersistentClass tempClass = referencedClass;
while ( (mappedBy == null) && (tempClass.getSuperclass() != null) ) {
@ -697,8 +931,10 @@ public final class CollectionMetadataGenerator {
}
if ( mappedBy == null ) {
throw new MappingException("Unable to read the mapped by attribute for " + propertyName + " in "
+ referencedClass.getClassName() + "!");
throw new MappingException(
"Unable to read the mapped by attribute for " + propertyName + " in "
+ referencedClass.getClassName() + "!"
);
}
return mappedBy;
@ -706,9 +942,9 @@ public final class CollectionMetadataGenerator {
@SuppressWarnings({"unchecked"})
private String searchMappedBy(PersistentClass referencedClass, Table collectionTable) {
Iterator<Property> properties = referencedClass.getPropertyIterator();
final Iterator<Property> properties = referencedClass.getPropertyIterator();
while ( properties.hasNext() ) {
Property property = properties.next();
final Property property = properties.next();
if ( property.getValue() instanceof Collection ) {
// The equality is intentional. We want to find a collection property with the same collection table.
//noinspection ObjectEquality

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,
public void addComponent(
Element parent, PropertyAuditingData propertyAuditingData,
Value value, CompositeMapperBuilder mapper, String entityName,
EntityXmlMappingData xmlMappingData, boolean firstPass) {
Component prop_component = (Component) value;
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();
final Iterator<Property> properties = (Iterator<Property>) propComponent.getPropertyIterator();
while ( properties.hasNext() ) {
Property property = properties.next();
final Property property = properties.next();
PropertyAuditingData componentPropertyAuditingData =
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);
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;

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,6 +48,7 @@ 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 {
@ -57,22 +59,35 @@ public final class IdMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
private boolean addIdProperties(Element parent, Iterator<Property> properties, SimpleMapperBuilder mapper, boolean key,
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();
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,
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(
parent,
getIdPersistentPropertyAuditingData( property ),
property.getValue(), mapper);
} else {
property.getValue(),
mapper
);
}
else {
// Last but one parameter: ids are always insertable
added = mainGenerator.getBasicMetadataGenerator().addBasic(parent,
added = mainGenerator.getBasicMetadataGenerator().addBasic(
parent,
getIdPersistentPropertyAuditingData( property ),
property.getValue(), mapper, true, key);
property.getValue(),
mapper,
true,
key
);
}
if ( !added ) {
// If the entity is audited, and a non-supported id component is used, throwing an exception.
@ -80,7 +95,8 @@ public final class IdMetadataGenerator {
// target relation mode not audited.
if ( audited ) {
throw new MappingException( "Type not supported: " + propertyType.getClass().getName() );
} else {
}
else {
return false;
}
}
@ -93,81 +109,120 @@ public final class IdMetadataGenerator {
@SuppressWarnings({"unchecked"})
IdMappingData addId(PersistentClass pc, boolean audited) {
// Xml mapping which will be used for relations
Element rel_id_mapping = new DefaultElement("properties");
final Element relIdMapping = new DefaultElement( "properties" );
// Xml mapping which will be used for the primary key of the versions table
Element orig_id_mapping = new DefaultElement("composite-id");
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) {
if ( idMapper == null && idProp == null ) {
return null;
}
SimpleIdMapperBuilder mapper;
if (id_mapper != null) {
if ( idMapper != null ) {
// Multiple id
Class componentClass = ReflectionTools.loadClass(
( (Component) pc.getIdentifier() ).getComponentClassName(), mainGenerator.getClassLoaderService()
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)) {
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)) {
if ( !addIdProperties(
origIdMapping,
(Iterator<Property>) idMapper.getPropertyIterator(),
null,
true,
audited
) ) {
return null;
}
} else if (id_prop.isComposite()) {
}
else if ( idProp.isComposite() ) {
// Embedded id
Component id_component = (Component) id_prop.getValue();
Class embeddableClass = ReflectionTools.loadClass(
id_component.getComponentClassName(), mainGenerator.getClassLoaderService()
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)) {
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)) {
if ( !addIdProperties(
origIdMapping,
(Iterator<Property>) idComponent.getPropertyIterator(),
null,
true,
audited
) ) {
return null;
}
} else {
}
else {
// Single id
mapper = new SingleIdMapper();
// Last but one parameter: ids are always insertable
mainGenerator.getBasicMetadataGenerator().addBasic(rel_id_mapping,
getIdPersistentPropertyAuditingData(id_prop),
id_prop.getValue(), mapper, true, false);
mainGenerator.getBasicMetadataGenerator().addBasic(
relIdMapping,
getIdPersistentPropertyAuditingData( idProp ),
idProp.getValue(),
mapper,
true,
false
);
// null mapper - the mapping where already added the first time, now we only want to generate the xml
mainGenerator.getBasicMetadataGenerator().addBasic(orig_id_mapping,
getIdPersistentPropertyAuditingData(id_prop),
id_prop.getValue(), null, true, true);
mainGenerator.getBasicMetadataGenerator().addBasic(
origIdMapping,
getIdPersistentPropertyAuditingData( idProp ),
idProp.getValue(),
null,
true,
true
);
}
orig_id_mapping.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName());
origIdMapping.addAttribute( "name", mainGenerator.getVerEntCfg().getOriginalIdPropName() );
// Adding a relation to the revision entity (effectively: the "revision number" property)
mainGenerator.addRevisionInfoRelation(orig_id_mapping);
mainGenerator.addRevisionInfoRelation( origIdMapping );
return new IdMappingData(mapper, orig_id_mapping, rel_id_mapping);
return new IdMappingData( mapper, origIdMapping, relIdMapping );
}
private PropertyData getIdPropertyData(Property property) {
return new PropertyData(property.getName(), property.getName(), property.getPropertyAccessorName(),
ModificationStore.FULL);
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);
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;
@ -40,23 +41,26 @@ public enum InheritanceType {
/**
* @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.
* another persistent class.
*/
public static InheritanceType get(PersistentClass pc) {
PersistentClass superclass = pc.getSuperclass();
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();
final Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
if ( subclass instanceof SingleTableSubclass ) {
return InheritanceType.SINGLE;
} else if (subclass instanceof JoinedSubclass) {
}
else if ( subclass instanceof JoinedSubclass ) {
return InheritanceType.JOINED;
} else if (subclass instanceof UnionSubclass) {
}
else if ( subclass instanceof UnionSubclass ) {
return InheritanceType.TABLE_PER_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
@ -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,44 +42,57 @@ import org.hibernate.mapping.Selectable;
*/
public class MetadataTools {
public static Element addNativelyGeneratedId(Element parent, String name, String type,
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);
final Element idMapping = parent.addElement( "id" );
idMapping.addAttribute( "name", name ).addAttribute( "type", type );
Element generator_mapping = id_mapping.addElement("generator");
final Element generatorMapping = idMapping.addElement( "generator" );
if ( useRevisionEntityWithNativeId ) {
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");
generatorMapping.addAttribute( "class", "native" );
}
// generator_mapping.addAttribute("class", "sequence");
// generator_mapping.addElement("param").addAttribute("name", "sequence").setText("custom");
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;
public static Element addProperty(
Element parent,
String name,
String type,
boolean insertable,
boolean updateable,
boolean key) {
final Element propMapping;
if ( key ) {
prop_mapping = parent.addElement("key-property");
} else {
prop_mapping = parent.addElement("property");
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);
propMapping.addAttribute( "type", type );
}
return prop_mapping;
return propMapping;
}
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) {
@ -86,7 +100,14 @@ public class MetadataTools {
}
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,10 +115,11 @@ public class MetadataTools {
}
private static void addOrModifyAttribute(Element parent, String name, String value) {
Attribute attribute = parent.attribute(name);
final Attribute attribute = parent.attribute( name );
if ( attribute == null ) {
parent.addAttribute( name, value );
} else {
}
else {
attribute.setValue( value );
}
}
@ -106,17 +128,17 @@ public class MetadataTools {
* Column name shall be wrapped with '`' signs if quotation required.
*/
public static Element addOrModifyColumn(Element parent, String name) {
Element column_mapping = parent.element("column");
final Element columnMapping = parent.element( "column" );
if (column_mapping == null) {
if ( columnMapping == null ) {
return addColumn( parent, name, null, null, null, null, null, null );
}
if ( !StringTools.isEmpty( name ) ) {
addOrModifyAttribute(column_mapping, "name", name);
addOrModifyAttribute( columnMapping, "name", name );
}
return column_mapping;
return columnMapping;
}
/**
@ -124,111 +146,147 @@ public class MetadataTools {
* 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) {
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");
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" );
column_mapping.addAttribute("name", quoted ? "`" + name + "`" : name);
columnMapping.addAttribute( "name", quoted ? "`" + name + "`" : name );
if ( length != null ) {
column_mapping.addAttribute("length", length.toString());
columnMapping.addAttribute( "length", length.toString() );
}
if ( scale != null ) {
column_mapping.addAttribute("scale", Integer.toString(scale));
columnMapping.addAttribute( "scale", Integer.toString( scale ) );
}
if ( precision != null ) {
column_mapping.addAttribute("precision", Integer.toString(precision));
columnMapping.addAttribute( "precision", Integer.toString( precision ) );
}
if ( !StringTools.isEmpty( sqlType ) ) {
column_mapping.addAttribute("sql-type", sqlType);
columnMapping.addAttribute( "sql-type", sqlType );
}
if ( !StringTools.isEmpty( customRead ) ) {
column_mapping.addAttribute("read", customRead);
columnMapping.addAttribute( "read", customRead );
}
if ( !StringTools.isEmpty( customWrite ) ) {
column_mapping.addAttribute("write", customWrite);
columnMapping.addAttribute( "write", customWrite );
}
return column_mapping;
return columnMapping;
}
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");
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" );
Element class_mapping = hibernate_mapping.addElement(type);
final Element classMapping = hibernateMapping.addElement( type );
if ( auditTableData.getAuditEntityName() != null ) {
class_mapping.addAttribute("entity-name", auditTableData.getAuditEntityName());
classMapping.addAttribute( "entity-name", auditTableData.getAuditEntityName() );
}
if ( discriminatorValue != null ) {
class_mapping.addAttribute("discriminator-value", discriminatorValue);
classMapping.addAttribute( "discriminator-value", discriminatorValue );
}
if ( !StringTools.isEmpty( auditTableData.getAuditTableName() ) ) {
class_mapping.addAttribute("table", auditTableData.getAuditTableName());
classMapping.addAttribute( "table", auditTableData.getAuditTableName() );
}
if ( !StringTools.isEmpty( auditTableData.getSchema() ) ) {
class_mapping.addAttribute("schema", auditTableData.getSchema());
classMapping.addAttribute( "schema", auditTableData.getSchema() );
}
if ( !StringTools.isEmpty( auditTableData.getCatalog() ) ) {
class_mapping.addAttribute("catalog", auditTableData.getCatalog());
classMapping.addAttribute( "catalog", auditTableData.getCatalog() );
}
if ( isAbstract != null ) {
class_mapping.addAttribute("abstract", isAbstract.toString());
classMapping.addAttribute( "abstract", isAbstract.toString() );
}
return class_mapping;
return classMapping;
}
public static Element createEntity(Document document, AuditTableData auditTableData, String discriminatorValue,
public static Element createEntity(
Document document,
AuditTableData auditTableData,
String discriminatorValue,
Boolean isAbstract) {
return createEntityCommon( document, "class", auditTableData, discriminatorValue, isAbstract );
}
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);
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
);
class_mapping.addAttribute("extends", extendsEntityName);
classMapping.addAttribute( "extends", extendsEntityName );
return class_mapping;
return classMapping;
}
public static Element createJoin(Element parent, String tableName,
String schema, String catalog) {
Element join_mapping = parent.addElement("join");
public static Element createJoin(
Element parent,
String tableName,
String schema,
String catalog) {
final Element joinMapping = parent.addElement( "join" );
join_mapping.addAttribute("table", tableName);
joinMapping.addAttribute( "table", tableName );
if ( !StringTools.isEmpty( schema ) ) {
join_mapping.addAttribute("schema", schema);
joinMapping.addAttribute( "schema", schema );
}
if ( !StringTools.isEmpty( catalog ) ) {
join_mapping.addAttribute("catalog", catalog);
joinMapping.addAttribute( "catalog", catalog );
}
return join_mapping;
return joinMapping;
}
public static void addColumns(Element any_mapping, Iterator selectables) {
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 );
addColumn( anyMapping, (Column) selectable );
}
}
@ -236,22 +294,32 @@ public class MetadataTools {
* 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 anyMapping 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());
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) {
Iterator<Element> properties = element.elementIterator();
final Iterator<Element> properties = element.elementIterator();
while ( properties.hasNext() ) {
Element property = properties.next();
final Element property = properties.next();
if ( "column".equals( property.getName() ) ) {
Attribute nameAttr = property.attribute("name");
final Attribute nameAttr = property.attribute( "name" );
if ( nameAttr != null ) {
nameAttr.setText( columnNameIterator.next() );
}
@ -260,14 +328,18 @@ public class MetadataTools {
}
@SuppressWarnings({"unchecked"})
public static void prefixNamesInPropertyElement(Element element, String prefix, ColumnNameIterator columnNameIterator,
boolean changeToKey, boolean insertable) {
Iterator<Element> properties = element.elementIterator();
public static void prefixNamesInPropertyElement(
Element element,
String prefix,
ColumnNameIterator columnNameIterator,
boolean changeToKey,
boolean insertable) {
final Iterator<Element> properties = element.elementIterator();
while ( properties.hasNext() ) {
Element property = properties.next();
final Element property = properties.next();
if ( "property".equals( property.getName() ) || "many-to-one".equals( property.getName() ) ) {
Attribute nameAttr = property.attribute("name");
final Attribute nameAttr = property.attribute( "name" );
if ( nameAttr != null ) {
nameAttr.setText( prefix + nameAttr.getText() );
}
@ -279,7 +351,7 @@ public class MetadataTools {
}
if ( "property".equals( property.getName() ) ) {
Attribute insert = property.attribute("insert");
final Attribute insert = property.attribute( "insert" );
insert.setText( Boolean.toString( insertable ) );
}
}
@ -288,6 +360,7 @@ public class MetadataTools {
/**
* Adds <code>formula</code> element.
*
* @param element Parent element.
* @param formula Formula descriptor.
*/
@ -297,16 +370,18 @@ public class MetadataTools {
/**
* 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();
final Object o = columnIterator.next();
if ( o instanceof Column ) {
addColumn( element, (Column) o );
} else if (o instanceof Formula) {
}
else if ( o instanceof Formula ) {
addFormula( element, (Formula) o );
}
}
@ -341,9 +416,18 @@ public class MetadataTools {
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 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,6 +41,7 @@ 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 {
@ -51,8 +53,12 @@ public final class QueryGeneratorBuilder {
private final List<MiddleIdData> idDatas;
private final boolean revisionTypeInId;
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy, MiddleIdData referencingIdData, String auditMiddleEntityName,
QueryGeneratorBuilder(
GlobalConfiguration globalCfg,
AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy,
MiddleIdData referencingIdData,
String auditMiddleEntityName,
boolean revisionTypeInId) {
this.globalCfg = globalCfg;
this.verEntCfg = verEntCfg;
@ -70,25 +76,39 @@ public final class QueryGeneratorBuilder {
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);
return new OneEntityQueryGenerator(
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
revisionTypeInId, componentDatas
);
}
} else if (idDatas.size() == 2) {
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.");
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 {
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." );
}
}

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,6 +42,7 @@ 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)
*/
@ -52,21 +54,34 @@ public final class ToOneRelationMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
void addToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value,
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
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);
final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
propertyAuditingData.getName(), referencedEntityName, relMapper, insertable);
propertyAuditingData.getName(),
referencedEntityName,
relMapper,
insertable
);
// If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
// that is, when the one side owns the relation (and is a collection), and the many side is non insertable.
@ -79,83 +94,114 @@ public final class ToOneRelationMetadataGenerator {
if ( !insertable && propertyAuditingData.isForceInsertable() ) {
nonInsertableFake = true;
insertable = true;
} else {
}
else {
nonInsertableFake = false;
}
// Adding an element to the mapping corresponding to the references entity id's
Element properties = (Element) idMapping.getXmlRelationMapping().clone();
final Element properties = (Element) idMapping.getXmlRelationMapping().clone();
properties.addAttribute( "name", propertyAuditingData.getName() );
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;
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;
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
EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(entityName);
final EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get( entityName );
if ( configuration == null ) {
throw new MappingException( "An audited relation to a non-audited entity " + entityName + "!" );
}
IdMappingData ownedIdMapping = configuration.getIdMappingData();
final IdMappingData ownedIdMapping = configuration.getIdMappingData();
if ( ownedIdMapping == null ) {
throw new MappingException( "An audited relation to a non-audited entity " + entityName + "!" );
}
String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(owningReferencePropertyName);
String referencedEntityName = propertyValue.getReferencedEntityName();
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( owningReferencePropertyName );
final String referencedEntityName = propertyValue.getReferencedEntityName();
// Generating the id mapper for the relation
IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
final IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneNotOwningRelation(
propertyAuditingData.getName(), owningReferencePropertyName,
referencedEntityName, ownedIdMapper);
propertyAuditingData.getName(),
owningReferencePropertyName,
referencedEntityName,
ownedIdMapper
);
// Adding mapper for the id
PropertyData propertyData = propertyAuditingData.getPropertyData();
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(entityName, referencedEntityName,
owningReferencePropertyName, propertyData));
final 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) {
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
void addOneToOnePrimaryKeyJoinColumn(
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);
final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(propertyAuditingData.getName(),
referencedEntityName, relMapper, insertable);
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));
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,7 +55,8 @@ public final class AnnotationsMetadataReader {
*/
private final ClassAuditingData auditData;
public AnnotationsMetadataReader(GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
public AnnotationsMetadataReader(
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
PersistentClass pc) {
this.globalCfg = globalCfg;
this.reflectionManager = reflectionManager;
@ -63,37 +66,43 @@ 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 ) {
return defaultAudited.modStore();
} else {
}
else {
return null;
}
}
private void addAuditTable(XClass clazz) {
AuditTable auditTable = clazz.getAnnotation(AuditTable.class);
final AuditTable auditTable = clazz.getAnnotation( AuditTable.class );
if ( auditTable != null ) {
auditData.setAuditTable( auditTable );
} else {
}
else {
auditData.setAuditTable( getDefaultAuditTable() );
}
}
private void addAuditSecondaryTables(XClass clazz) {
// Getting information on secondary tables
SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation(SecondaryAuditTable.class);
final SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation( SecondaryAuditTable.class );
if ( secondaryVersionsTable1 != null ) {
auditData.getSecondaryTableDictionary().put(secondaryVersionsTable1.secondaryTableName(),
secondaryVersionsTable1.secondaryAuditTableName());
auditData.getSecondaryTableDictionary().put(
secondaryVersionsTable1.secondaryTableName(),
secondaryVersionsTable1.secondaryAuditTableName()
);
}
SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation(SecondaryAuditTables.class);
final SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation( SecondaryAuditTables.class );
if ( secondaryAuditTables != null ) {
for ( SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value() ) {
auditData.getSecondaryTableDictionary().put(secondaryAuditTable2.secondaryTableName(),
secondaryAuditTable2.secondaryAuditTableName());
auditData.getSecondaryTableDictionary().put(
secondaryAuditTable2.secondaryTableName(),
secondaryAuditTable2.secondaryAuditTableName()
);
}
}
}
@ -104,19 +113,26 @@ public final class AnnotationsMetadataReader {
}
try {
XClass xclass = reflectionManager.classForName(pc.getClassName(), this.getClass());
final XClass xclass = reflectionManager.classForName( pc.getClassName(), this.getClass() );
ModificationStore defaultStore = getDefaultAudited(xclass);
final ModificationStore defaultStore = getDefaultAudited( xclass );
if ( defaultStore != null ) {
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) {
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
@ -124,10 +140,21 @@ public final class AnnotationsMetadataReader {
}
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,7 +88,8 @@ public class AuditedPropertiesReader {
private final Set<XClass> overriddenAuditedClasses;
private final Set<XClass> overriddenNotAuditedClasses;
public AuditedPropertiesReader(ModificationStore defaultStore,
public AuditedPropertiesReader(
ModificationStore defaultStore,
PersistentPropertiesSource persistentPropertiesSource,
AuditedPropertiesHolder auditedPropertiesHolder,
GlobalConfiguration globalCfg,
@ -95,7 +119,7 @@ public class AuditedPropertiesReader {
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
// of currently mapped entity or itself.
XClass clazz = persistentPropertiesSource.getXClass();
final XClass clazz = persistentPropertiesSource.getXClass();
readAuditOverrides( clazz );
// Adding all properties from the given class.
@ -105,14 +129,15 @@ public class AuditedPropertiesReader {
/**
* 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);
final Audited allClassAudited = clazz.getAnnotation( Audited.class );
if ( allClassAudited != null && allClassAudited.auditParents().length > 0 ) {
for ( Class c : allClassAudited.auditParents() ) {
XClass parentClass = reflectionManager.toXClass(c);
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.
@ -121,34 +146,37 @@ public class AuditedPropertiesReader {
}
}
/* TODO: Code to remove with @Audited.auditParents - finish. */
List<AuditOverride> auditOverrides = computeAuditOverrides(clazz);
final List<AuditOverride> auditOverrides = computeAuditOverrides( clazz );
for ( AuditOverride auditOverride : auditOverrides ) {
if ( auditOverride.forClass() != void.class ) {
XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass());
final XClass overrideClass = reflectionManager.toXClass( auditOverride.forClass() );
checkSuperclass( clazz, overrideClass );
String propertyName = auditOverride.name();
final String propertyName = auditOverride.name();
if ( !StringTools.isEmpty( propertyName ) ) {
// Override @Audited annotation on property level.
XProperty property = getProperty(overrideClass, propertyName);
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 {
}
else {
if ( !overriddenAuditedProperties.contains( property ) ) {
// If the property has not been marked as audited by the subclass.
overriddenNotAuditedProperties.add( property );
}
}
} else {
}
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 {
}
else {
if ( !overriddenAuditedClasses.contains( overrideClass ) ) {
// If the class has not been marked as audited by the subclass.
overriddenNotAuditedClasses.add( overrideClass );
@ -157,7 +185,7 @@ public class AuditedPropertiesReader {
}
}
}
XClass superclass = clazz.getSuperclass();
final XClass superclass = clazz.getSuperclass();
if ( !clazz.isInterface() && !Object.class.getName().equals( superclass.getName() ) ) {
readAuditOverrides( superclass );
}
@ -165,55 +193,68 @@ public class AuditedPropertiesReader {
/**
* @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);
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.EMPTY_LIST;
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.");
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);
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() + ".");
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();
final Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
while ( propertyIter.hasNext() ) {
Property property = propertyIter.next();
final Property property = propertyIter.next();
addPersistentProperty( property );
if ("embedded".equals(property.getPropertyAccessorName()) && property.getName().equals(property.getNodeName())) {
if ( "embedded".equals( property.getPropertyAccessorName() ) && property.getName()
.equals( property.getNodeName() ) ) {
// If property name equals node name and embedded accessor type is used, processing component
// has been defined with <properties> tag. See HHH-6636 JIRA issue.
createPropertiesGroupMapping( property );
@ -224,22 +265,25 @@ public class AuditedPropertiesReader {
private void addPersistentProperty(Property property) {
if ( "field".equals( property.getPropertyAccessorName() ) ) {
fieldAccessedPersistentProperties.add( property.getName() );
} else {
}
else {
propertyAccessedPersistentProperties.add( property.getName() );
}
}
@SuppressWarnings("unchecked")
private void createPropertiesGroupMapping(Property property) {
Component component = (Component) property.getValue();
Iterator<Property> componentProperties = component.getPropertyIterator();
final Component component = (Component) property.getValue();
final Iterator<Property> componentProperties = component.getPropertyIterator();
while ( componentProperties.hasNext() ) {
Property componentProperty = componentProperties.next();
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
@ -258,7 +302,8 @@ public class AuditedPropertiesReader {
// If parent class declares @Audited on the field/property level.
allClassAudited = DEFAULT_AUDITED;
}
} else if (allClassAudited != null && overriddenNotAuditedClasses.contains(clazz)) {
}
else if ( allClassAudited != null && overriddenNotAuditedClasses.contains( clazz ) ) {
return null;
}
return allClassAudited;
@ -266,60 +311,90 @@ public class AuditedPropertiesReader {
/**
* 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);
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();
final XClass superclazz = clazz.getSuperclass();
if ( !clazz.isInterface() && !"java.lang.Object".equals( superclazz.getName() ) ) {
addPropertiesFromClass( superclazz );
}
}
}
private void addFromProperties(Iterable<XProperty> properties, String accessType, Set<String> persistentProperties, Audited allClassAudited) {
private void addFromProperties(
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 ( 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 {
}
else {
this.addFromNotComponentProperty( property, accessType, allClassAudited );
}
} else if (propertiesGroupMapping.containsKey(property.getName())) {
}
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 ) ) {
// 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,
private void addFromPropertiesGroup(
String embeddedName,
XProperty property,
String accessType,
Component propertyValue,
Audited allClassAudited) {
ComponentAuditingData componentData = new ComponentAuditingData();
boolean isAudited = fillPropertyData(property, componentData, accessType, 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 );
// Marking component properties as placed directly in class (not inside another component).
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 )
);
@ -329,9 +404,13 @@ public class AuditedPropertiesReader {
}
}
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();
@ -360,8 +443,8 @@ public class AuditedPropertiesReader {
}
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited) {
PropertyAuditingData propertyData = new PropertyAuditingData();
boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited);
final PropertyAuditingData propertyData = new PropertyAuditingData();
final boolean isAudited = fillPropertyData( property, propertyData, accessType, allClassAudited );
if ( isAudited ) {
// Now we know that the property is audited
@ -372,24 +455,32 @@ public class AuditedPropertiesReader {
/**
* 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);
final Version jpaVer = property.getAnnotation( Version.class );
if ( jpaVer != null ) {
return false;
}
@ -401,19 +492,22 @@ public class AuditedPropertiesReader {
return false;
}
String propertyName = propertyNamePrefix + property.getName();
final String propertyName = propertyNamePrefix + property.getName();
propertyData.setName( propertyName );
propertyData.setModifiedFlagName(
MetadataTools.getModifiedFlagPropertyName(
propertyName,
globalCfg.getModifiedFlagSuffix()));
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
// not audited due to AuditOverride annotation
return false;
}
addPropertyMapKey( property, propertyData );
setPropertyAuditMappedBy( property, propertyData );
@ -423,11 +517,16 @@ public class AuditedPropertiesReader {
}
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;
@ -437,7 +536,8 @@ public class AuditedPropertiesReader {
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
return true;
} else {
}
else {
return false;
}
}
@ -448,14 +548,14 @@ public class AuditedPropertiesReader {
}
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
OneToMany oneToMany = property.getAnnotation(OneToMany.class);
final OneToMany oneToMany = property.getAnnotation( OneToMany.class );
if ( oneToMany != null && !"".equals( oneToMany.mappedBy() ) ) {
propertyData.setRelationMappedBy( oneToMany.mappedBy() );
}
}
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
final AuditMappedBy auditMappedBy = property.getAnnotation( AuditMappedBy.class );
if ( auditMappedBy != null ) {
propertyData.setAuditMappedBy( auditMappedBy.mappedBy() );
if ( !"".equals( auditMappedBy.positionMappedBy() ) ) {
@ -465,7 +565,7 @@ public class AuditedPropertiesReader {
}
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
MapKey mapKey = property.getAnnotation(MapKey.class);
final MapKey mapKey = property.getAnnotation( MapKey.class );
if ( mapKey != null ) {
propertyData.setMapKey( mapKey.name() );
}
@ -473,26 +573,27 @@ public class AuditedPropertiesReader {
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
// first set the join table based on the AuditJoinTable annotation
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class);
final AuditJoinTable joinTable = property.getAnnotation( AuditJoinTable.class );
if ( joinTable != null ) {
propertyData.setJoinTable( joinTable );
} else {
}
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);
final AuditOverride annotationOverride = property.getAnnotation( AuditOverride.class );
if ( annotationOverride != null ) {
propertyData.addAuditingOverride( annotationOverride );
}
AuditOverrides annotationOverrides = property.getAnnotation(AuditOverrides.class);
final AuditOverrides annotationOverrides = property.getAnnotation( AuditOverrides.class );
if ( annotationOverrides != null ) {
propertyData.addAuditingOverrides( annotationOverrides );
}
@ -501,23 +602,23 @@ public class AuditedPropertiesReader {
/**
* Process the {@link AuditOverride} annotations for this property.
*
* @param property
* the property for which the {@link AuditOverride}
* @param property the property for which the {@link AuditOverride}
* annotations are being processed
* @param propertyData
* the Envers auditing data for this property
* @param propertyData the Envers auditing data for this property
*
* @return {@code false} if isAudited() of the override annotation was set to
*/
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();
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() ) {
return false;
} else {
}
else {
if ( override.auditJoinTable() != null ) {
propertyData.setJoinTable( override.auditJoinTable() );
}
@ -529,20 +630,58 @@ 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;
}
@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();
}
};
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(); }
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 {
@ -552,16 +691,28 @@ public class AuditedPropertiesReader {
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
try {
this.xclass = reflectionManager.classForName( component.getComponentClassName(), this.getClass() );
} catch (ClassNotFoundException e) {
}
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;
@ -50,14 +51,17 @@ public class ClassAuditingData implements AuditedPropertiesHolder {
secondaryTableDictionary = newHashMap();
}
@Override
public boolean isEmpty() {
return properties.isEmpty();
}
@Override
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
properties.put( propertyName, auditingData );
}
@Override
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
return properties.get( propertyName );
}
@ -86,6 +90,7 @@ public class ClassAuditingData implements AuditedPropertiesHolder {
return defaultAudited || properties.size() > 0;
}
@Override
public boolean contains(String 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,25 +37,31 @@ 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);
final Audited aud = property.getAnnotation( Audited.class );
if ( aud != null ) {
propertyData.setStore( aud.modStore() );
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
} else {
}
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,18 +41,22 @@ 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 );
}
@Override
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
return properties.get( propertyName );
}
@Override
public boolean contains(String 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 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;
@ -56,7 +56,8 @@ public class PropertyAuditingData {
public PropertyAuditingData() {
}
public PropertyAuditingData(String name, String accessType, ModificationStore store,
public PropertyAuditingData(
String name, String accessType, ModificationStore store,
RelationTargetAuditMode relationTargetAuditMode,
String auditMappedBy, String positionMappedBy,
boolean forceInsertable) {
@ -119,8 +120,10 @@ public class PropertyAuditingData {
}
public PropertyData getPropertyData() {
return new PropertyData(name, beanName, accessType, store,
usingModifiedFlag, modifiedFlagName);
return new PropertyData(
name, beanName, accessType, store,
usingModifiedFlag, modifiedFlagName
);
}
public List<AuditOverride> getAuditingOverrides() {
@ -173,7 +176,7 @@ public class PropertyAuditingData {
public void addAuditingOverride(AuditOverride annotation) {
if ( annotation != null ) {
String overrideName = annotation.name();
final String overrideName = annotation.name();
boolean present = false;
for ( AuditOverride current : auditJoinTableOverrides ) {
if ( current.name().equals( overrideName ) ) {

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,7 +143,10 @@ 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();
}
@ -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;
@ -46,9 +46,11 @@ public class SequenceIdRevisionEntity implements Serializable {
@Id
@GeneratedValue(generator = "RevisionNumberSequenceGenerator")
@GenericGenerator(name = "RevisionNumberSequenceGenerator",
@GenericGenerator(
name = "RevisionNumberSequenceGenerator",
strategy = "org.hibernate.envers.enhanced.OrderedSequenceGenerator",
parameters = {@Parameter(name = "table_name", value = "REVISION_GENERATOR"),
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")
@ -77,29 +79,35 @@ public class SequenceIdRevisionEntity implements Serializable {
return timestamp;
}
@SuppressWarnings("UnusedDeclaration")
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SequenceIdRevisionEntity )) return false;
SequenceIdRevisionEntity that = (SequenceIdRevisionEntity) o;
if (id != that.id) return false;
if (timestamp != that.timestamp) return false;
if ( this == o ) {
return true;
}
if ( !(o instanceof SequenceIdRevisionEntity) ) {
return false;
}
final SequenceIdRevisionEntity that = (SequenceIdRevisionEntity) o;
return id == that.id && timestamp == that.timestamp;
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
return result;
}
@Override
public String toString() {
return "SequenceIdRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
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,6 +40,7 @@ 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
@ -51,34 +52,48 @@ public class SequenceIdTrackingModifiedEntitiesRevisionEntity extends SequenceId
@ModifiedEntityNames
private Set<String> modifiedEntityNames = new HashSet<String>();
@SuppressWarnings("UnusedDeclaration")
public Set<String> getModifiedEntityNames() {
return modifiedEntityNames;
}
@SuppressWarnings("UnusedDeclaration")
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
this.modifiedEntityNames = modifiedEntityNames;
}
@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;
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames)
: that.modifiedEntityNames != null) return false;
if ( this == o ) {
return true;
}
if ( !(o instanceof SequenceIdTrackingModifiedEntitiesRevisionEntity) ) {
return false;
}
if ( !super.equals( o ) ) {
return false;
}
final SequenceIdTrackingModifiedEntitiesRevisionEntity that = (SequenceIdTrackingModifiedEntitiesRevisionEntity) o;
if ( modifiedEntityNames == null ) {
return that.modifiedEntityNames == null;
}
else {
return modifiedEntityNames.equals( that.modifiedEntityNames );
}
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
return "SequenceIdTrackingModifiedEntitiesRevisionEntity(" + super.toString()
+ ", modifiedEntityNames = " + modifiedEntityNames + ")";
}
}

View File

@ -69,15 +69,15 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
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 );
final RelationDescription rd = searchForRelationDescription( entityName, referencingPropertyName );
if ( rd != null && rd.getMappedByPropertyName() != null ) {
generateFakeBidirecationalRelationWorkUnits(
auditProcess,
@ -90,7 +90,7 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
);
}
else {
PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(
final PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(
event.getSession(),
entityName,
getAuditConfiguration(),
@ -123,7 +123,9 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
/**
* 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) {
@ -153,8 +157,8 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
* be found.
*/
private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) {
EntityConfiguration configuration = getAuditConfiguration().getEntCfg().get( entityName );
RelationDescription rd = configuration.getRelationDescription(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 );
}
@ -171,31 +175,37 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
AbstractCollectionEvent event,
RelationDescription rd) {
// First computing the relation changes
List<PersistentCollectionChangeData> collectionChanges = getAuditConfiguration()
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
// Getting the id mapper for the related entity, as the work units generated will correspond to the related
// entities.
String relatedEntityName = rd.getToEntityName();
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get(relatedEntityName).getIdMapper();
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(
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);
final String realRelatedEntityName = event.getSession().bestGuessEntityName( relatedObj );
// By default, the nested work unit is a collection change work unit.
AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
final AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
event.getSession(),
realRelatedEntityName,
rd.getMappedByPropertyName(),
@ -247,16 +257,19 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
// 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();
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 );
final Object relatedObj = changeData.getChangedElement();
final Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
auditProcess.addWorkUnit(
new CollectionChangeWorkUnit(

View File

@ -73,16 +73,19 @@ public abstract class BaseEnversEventListener implements EnversListener {
// 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);
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 ) ) {
// We have to generate changes both in the old collection (size decreses) and new collection
@ -99,7 +102,8 @@ public abstract class BaseEnversEventListener implements EnversListener {
}
}
private void addCollectionChangeWorkUnit(AuditProcess auditProcess, SessionImplementor session,
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.
@ -107,24 +111,32 @@ public abstract class BaseEnversEventListener implements EnversListener {
Serializable id;
if ( value instanceof HibernateProxy ) {
HibernateProxy hibernateProxy = (HibernateProxy) value;
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 {
}
else {
toEntityName = session.guessEntityName( value );
IdMapper idMapper = enversConfiguration.getEntCfg().get(toEntityName).getIdMapper();
final IdMapper idMapper = enversConfiguration.getEntCfg().get( toEntityName ).getIdMapper();
id = (Serializable) idMapper.mapToIdFromEntity( value );
}
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) {

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,24 +59,54 @@ 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 ) );
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 )
);
}
}
@ -84,7 +121,8 @@ 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,
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,6 +29,8 @@ 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
@ -43,7 +45,7 @@ public class EnversPostCollectionRecreateEventListenerImpl
@Override
public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
CollectionEntry collectionEntry = getCollectionEntry( event );
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,14 +45,14 @@ 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() );
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(),

View File

@ -32,24 +32,27 @@ 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 );
}
@Override
public void onPostInsert(PostInsertEvent 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());
final AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get( event.getSession() );
AuditWorkUnit workUnit = new AddWorkUnit(
final AuditWorkUnit workUnit = new AddWorkUnit(
event.getSession(),
event.getPersister().getEntityName(),
getAuditConfiguration(),

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,16 +45,14 @@ 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());
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(),
@ -77,9 +77,9 @@ public class EnversPostUpdateEventListenerImpl extends BaseEnversEventListener i
}
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,7 +48,7 @@ public class EnversPreCollectionRemoveEventListenerImpl
@Override
public void onPreRemoveCollection(PreCollectionRemoveEvent event) {
CollectionEntry collectionEntry = getCollectionEntry( event );
final CollectionEntry collectionEntry = getCollectionEntry( event );
if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) {
Serializable oldColl = collectionEntry.getSnapshot();
if ( !event.getCollection().wasInitialized() && shouldGenerateRevision( event ) ) {

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,7 +45,7 @@ public class EnversPreCollectionUpdateEventListenerImpl
@Override
public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
CollectionEntry collectionEntry = getCollectionEntry( event );
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;
/**

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

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,17 +31,19 @@ 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;
this.date = null;
}
public RevisionDoesNotExistException(Date date) {
super( "There is no revision before or at " + date + "." );
this.date = date;
this.revision = null;
}
public Number getRevision() {

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.
@ -40,6 +40,9 @@ import static org.jboss.logging.Logger.Level.WARN;
@MessageLogger(projectCode = "HHH")
public interface EnversMessageLogger extends CoreMessageLogger {
/**
* 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,6 +32,7 @@ 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)
@ -42,7 +44,8 @@ public class EntitiesConfigurations {
// Map versions entity name -> entity name
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
public EntitiesConfigurations(Map<String, EntityConfiguration> entitiesConfigurations,
public EntitiesConfigurations(
Map<String, EntityConfiguration> entitiesConfigurations,
Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) {
this.entitiesConfigurations = entitiesConfigurations;
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
@ -55,22 +58,24 @@ public class EntitiesConfigurations {
entityNamesForVersionsEntityNames = new HashMap<String, String>();
for ( String entityName : entitiesConfigurations.keySet() ) {
entityNamesForVersionsEntityNames.put(entitiesConfigurations.get(entityName).getVersionsEntityName(),
entityName);
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);
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 ) {
EntityConfiguration entityConfiguration = entitiesConfigurations.get(relDesc.getToEntityName());
final EntityConfiguration entityConfiguration = entitiesConfigurations.get( relDesc.getToEntityName() );
if ( entityConfiguration != null ) {
for ( RelationDescription other : entityConfiguration.getRelationsIterator() ) {
if ( relDesc.getFromPropertyName().equals( other.getMappedByPropertyName() ) &&
@ -106,20 +111,22 @@ public class EntitiesConfigurations {
}
public RelationDescription getRelationDescription(String entityName, String propertyName) {
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
RelationDescription relDesc = entCfg.getRelationDescription(propertyName);
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
final RelationDescription relDesc = entCfg.getRelationDescription( propertyName );
if ( relDesc != null ) {
return relDesc;
} else if (entCfg.getParentEntityName() != null) {
}
else if ( entCfg.getParentEntityName() != null ) {
// The field may be declared in a superclass ...
return getRelationDescription( entCfg.getParentEntityName(), propertyName );
} else {
}
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 ) {
// collect descriptions from super classes
@ -133,7 +140,7 @@ public class EntitiesConfigurations {
private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
entityNames.add( entityName );
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
if ( entCfg.getParentEntityName() != null ) {
// collect descriptions from super classes
addWithParentEntityNames( entCfg.getParentEntityName(), entityNames );
@ -141,18 +148,19 @@ public class EntitiesConfigurations {
}
private Set<String> getEntityAndParentsNames(String entityName) {
Set<String> names = new HashSet<String>();
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>();
final Set<String> entityAndParentsNames = getEntityAndParentsNames( fromEntityName );
final 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)) {
final String relToEntityName = relationDescription.getToEntityName();
final String mappedByPropertyName = relationDescription.getMappedByPropertyName();
if ( entityAndParentsNames.contains( relToEntityName ) && mappedByPropertyName != null && mappedByPropertyName
.equals( fromPropertyName ) ) {
toPropertyNames.add( relationDescription.getFromPropertyName() );
}
}

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;
@ -35,7 +36,9 @@ import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
*/
public class EntityConfiguration {
private String versionsEntityName;
/** Holds the className for instantiation the configured entity */
/**
* Holds the className for instantiation the configured entity
*/
private String entityClassName;
private IdMappingData idMappingData;
private ExtendedPropertyMapper propertyMapper;
@ -43,7 +46,8 @@ public class EntityConfiguration {
private Map<String, RelationDescription> relations;
private String parentEntityName;
public EntityConfiguration(String versionsEntityName, String entityClassName, IdMappingData idMappingData,
public EntityConfiguration(
String versionsEntityName, String entityClassName, IdMappingData idMappingData,
ExtendedPropertyMapper propertyMapper, String parentEntityName) {
this.versionsEntityName = versionsEntityName;
this.entityClassName = entityClassName;
@ -55,32 +59,96 @@ public class EntityConfiguration {
}
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));
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_ONE,
toEntityName,
null,
idMapper,
null,
null,
insertable
)
);
}
public void addToOneNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
public void addToOneNotOwningRelation(
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));
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,
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));
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));
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) {

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
@ -54,9 +54,11 @@ public class EntityInstantiator {
/**
* 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.
*/
@ -66,22 +68,22 @@ public class EntityInstantiator {
}
// The $type$ property holds the name of the (versions) entity
String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName((String) versionsEntity.get("$type$"));
final String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName( (String) versionsEntity.get( "$type$" ) );
if ( type != null ) {
entityName = type;
}
// First mapping the primary key
IdMapper idMapper = verCfg.getEntCfg().get(entityName).getIdMapper();
Map originalId = (Map) versionsEntity.get(verCfg.getAuditEntCfg().getOriginalIdPropName());
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 );
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 ) ) {
@ -97,9 +99,10 @@ public class EntityInstantiator {
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
}
Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
final Class<?> cls = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
ret = ReflectHelper.getDefaultConstructor( cls ).newInstance();
} catch (Exception e) {
}
catch (Exception e) {
throw new AuditException( e );
}
@ -107,8 +110,14 @@ public class EntityInstantiator {
// 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);
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
@ -121,28 +130,46 @@ public class EntityInstantiator {
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);
final Object value = originalId.get( key );
if ( value instanceof HibernateProxy ) {
HibernateProxy hibernateProxy = (HibernateProxy) value;
LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
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 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));
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) {
public void addInstancesFromVersionsEntities(
String entityName,
Collection addTo,
List<Map> versionsEntities,
Number revision) {
for ( Map versionsEntity : versionsEntities ) {
addTo.add( createInstanceFromVersionsEntity( entityName, versionsEntity, revision ) );
}

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;

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,13 @@
* 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 {
@ -41,6 +44,7 @@ public class PropertyData {
/**
* Copies the given property data, except the name.
*
* @param newName New name.
* @param propertyData Property data to copy the rest of properties from.
*/
@ -71,7 +75,13 @@ public class PropertyData {
* @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) {
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;
@ -103,19 +113,20 @@ public class PropertyData {
@Override
public boolean equals(Object o) {
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;
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
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
public int hashCode() {

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;
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
@ -39,7 +40,8 @@ public class RelationDescription {
private final boolean insertable;
private boolean bidirectional;
public RelationDescription(String fromPropertyName, RelationType relationType, String toEntityName,
public RelationDescription(
String fromPropertyName, RelationType relationType, String toEntityName,
String mappedByPropertyName, IdMapper idMapper,
PropertyMapper fakeBidirectionalRelationMapper,
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) {

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,6 +26,7 @@ package org.hibernate.envers.internal.entities;
/**
* Type of a relation between two entities.
*
* @author Adam Warski (adam at warski dot org)
*/
public enum RelationType {

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,11 +32,13 @@ 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 {
@ -44,22 +46,28 @@ public class RevisionTypeType implements UserType, Serializable {
private static final int[] SQL_TYPES = {Types.TINYINT};
@Override
public int[] sqlTypes() {
return SQL_TYPES;
}
@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()),
@ -68,41 +76,39 @@ public class RevisionTypeType implements UserType, Serializable {
);
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
@Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
@Override
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);
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
@ -53,27 +53,41 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
this.componentClass = componentClass;
}
@Override
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 );
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
@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) {
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));
data.put(
propertyData.getModifiedFlagPropertyName(),
delegate.mapToMapFromEntity( session, new HashMap<String, Object>(), newObj, oldObj )
);
}
}
@ -91,7 +105,14 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
}
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
@Override
public void mapToEntityFromMap(
AuditConfiguration verCfg,
Object obj,
Map data,
Object primaryKey,
AuditReaderImplementor versionsReader,
Number revision) {
if ( data == null || obj == null ) {
return;
}
@ -103,12 +124,15 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
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)) {
if ( data.get(
property.getKey()
.getName()
) != null || !(property.getValue() instanceof SinglePropertyMapper) ) {
allNullAndSingle = false;
break;
}
@ -117,24 +141,29 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
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 {
}
else {
// set the component
try {
Object subObj = ReflectHelper.getDefaultConstructor(componentClass).newInstance();
final Object subObj = ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
setter.set( obj, subObj, null );
delegate.mapToEntityFromMap( verCfg, subObj, data, primaryKey, versionsReader, revision );
} catch (Exception e) {
}
catch (Exception e) {
throw new AuditException( e );
}
}
}
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
@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
@ -32,6 +32,8 @@ import org.hibernate.envers.internal.entities.PropertyData;
*/
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
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
@ -51,41 +51,52 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
propertyDatas = Tools.newHashMap();
}
@Override
public void add(PropertyData propertyData) {
SinglePropertyMapper single = new SinglePropertyMapper();
final SinglePropertyMapper single = new SinglePropertyMapper();
single.add( propertyData );
properties.put( propertyData, single );
propertyDatas.put( propertyData.getName(), propertyData );
}
@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 );
}
ComponentPropertyMapper componentMapperBuilder = new ComponentPropertyMapper(propertyData, componentClass);
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]; }
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) {
@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++ ) {
String propertyName = propertyNames[i];
final 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);
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 );
}
@ -94,45 +105,64 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
return ret;
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
@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) {
}
else if ( oldObj != null ) {
getter = ReflectionTools.getGetter( oldObj.getClass(), propertyData );
} else {
}
else {
return false;
}
ret |= properties.get(propertyData).mapToMapFromEntity(session, data,
ret |= properties.get( propertyData ).mapToMapFromEntity(
session, data,
newObj == null ? null : getter.get( newObj ),
oldObj == null ? null : getter.get(oldObj));
oldObj == null ? null : getter.get( oldObj )
);
}
return ret;
}
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
for ( PropertyData propertyData : properties.keySet() ) {
Getter getter;
if ( newObj != null ) {
getter = ReflectionTools.getGetter( newObj.getClass(), propertyData );
} else if (oldObj != null) {
}
else if ( oldObj != null ) {
getter = ReflectionTools.getGetter( oldObj.getClass(), propertyData );
} else {
}
else {
return;
}
properties.get(propertyData).mapModifiedFlagsToMapFromEntity(session, data,
properties.get( propertyData ).mapModifiedFlagsToMapFromEntity(
session, data,
newObj == null ? null : getter.get( newObj ),
oldObj == null ? null : getter.get(oldObj));
oldObj == null ? null : getter.get( oldObj )
);
}
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
@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 );
@ -144,19 +174,20 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
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('.');
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)
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;
}
@ -165,26 +196,30 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(collectionPropertyName);
PropertyMapper mapper = pair.getFirst();
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,
@Override
public List<PersistentCollectionChangeData> mapCollectionChanges(
SessionImplementor session,
String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName);
PropertyMapper mapper = pair.getFirst();
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 {
}
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,6 +30,7 @@ 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 {
@ -43,7 +45,6 @@ public class PersistentCollectionChangeData {
}
/**
*
* @return Name of the (middle) entity that holds the collection data.
*/
public String getEntityName() {

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;
@ -38,16 +39,19 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
public interface PropertyMapper {
/**
* 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);
/**
* 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.
@ -55,22 +59,31 @@ public interface PropertyMapper {
* @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,
void mapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision);
/**
* 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,
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,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.internal.entities.mapper;
import org.hibernate.envers.internal.entities.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,6 +43,7 @@ import org.hibernate.property.Setter;
/**
* TODO: diff
*
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
@ -53,8 +54,10 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
this.propertyData = propertyData;
}
public SinglePropertyMapper() { }
public SinglePropertyMapper() {
}
@Override
public void add(PropertyData propertyData) {
if ( this.propertyData != null ) {
throw new AuditException( "Only one property can be added!" );
@ -63,10 +66,16 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
this.propertyData = propertyData;
}
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
@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)) {
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 ));
}
@ -74,7 +83,11 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
}
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
Object oldObj) {
if ( propertyData.isUsingModifiedFlag() ) {
data.put( propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual( newObj, oldObj ) );
}
@ -84,14 +97,16 @@ 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,
@Override
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());
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 );
@ -108,18 +123,23 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
// Trying to look up the field
try {
return cls.getDeclaredField( propertyData.getBeanName() ).getType().isPrimitive();
} catch (NoSuchFieldException e) {
}
catch (NoSuchFieldException e) {
return isPrimitive( setter, propertyData, cls.getSuperclass() );
}
} else {
}
else {
return setter.getMethod().getParameterTypes()[0].isPrimitive();
}
}
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor sessionImplementor,
@Override
public List<PersistentCollectionChangeData> mapCollectionChanges(
SessionImplementor sessionImplementor,
String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
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,6 +37,7 @@ 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)
*/
@ -48,22 +50,37 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
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);
@Override
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 void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
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 );
}
@ -74,23 +91,43 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
main.mapModifiedFlagsToMapForCollectionChange( collectionPropertyName, data );
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number 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,
@Override
public List<PersistentCollectionChangeData> mapCollectionChanges(
SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
session, referencingPropertyName, newColl, oldColl, 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 {
}
else {
if ( mainCollectionChanges != null ) {
parentCollectionChanges.addAll( mainCollectionChanges );
}
@ -98,18 +135,22 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
}
}
@Override
public CompositeMapperBuilder addComponent(PropertyData propertyData, Class componentClass) {
return main.addComponent( propertyData, componentClass );
}
@Override
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
main.addComposite( propertyData, propertyMapper );
}
@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() );

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,19 +43,22 @@ public abstract class AbstractCompositeIdMapper extends AbstractIdMapper impleme
this.compositeIdClass = compositeIdClass;
}
@Override
public void add(PropertyData propertyData) {
ids.put( propertyData, new SingleIdMapper( propertyData ) );
}
@Override
public Object mapToIdFromMap(Map data) {
if ( data == null ) {
return null;
}
Object ret;
final Object ret;
try {
ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
} catch (Exception e) {
}
catch (Exception e) {
throw new AuditException( e );
}

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;
@ -34,65 +35,92 @@ public abstract class AbstractIdMapper implements IdMapper {
private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) {
if ( paramDatas.size() > 1 ) {
return parameters.addSubParameters( "and" );
} else {
}
else {
return parameters;
}
}
@Override
public void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
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);
parametersToUse.addWhere(
paramData.getProperty( prefix1 ),
false,
"=",
paramData.getProperty( prefix2 ),
false
);
}
}
@Override
public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) {
List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId(null);
List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId(null);
final List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId( null );
final List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId( null );
Parameters parametersToUse = getParametersToUse(parameters, paramDatas1);
final Parameters parametersToUse = getParametersToUse( parameters, paramDatas1 );
Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator();
Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
final Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator();
final Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
while ( paramDataIter1.hasNext() ) {
QueryParameterData paramData1 = paramDataIter1.next();
QueryParameterData paramData2 = paramDataIter2.next();
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
);
}
}
@Override
public void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals) {
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(id);
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());
}
else {
parametersToUse.addWhereWithParam(
paramData.getProperty( prefix ),
equals ? "=" : "<>",
paramData.getValue()
);
}
}
}
@Override
public void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals) {
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
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());
parametersToUse.addWhereWithNamedParam(
paramData.getProperty( prefix ),
equals ? "=" : "<>",
paramData.getQueryParameterName()
);
}
}
private void handleNullValue(Parameters parameters, String propertyName, boolean equals) {
if ( equals ) {
parameters.addNullRestriction( propertyName, equals );
} else {
}
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
@ -47,31 +47,34 @@ public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements Simpl
this.idPropertyData = idPropertyData;
}
@Override
public void mapToMapFromId(Map<String, Object> data, Object obj) {
for ( IdMapper idMapper : ids.values() ) {
idMapper.mapToMapFromEntity( data, obj );
}
}
@Override
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
if ( obj == null ) {
return;
}
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyData);
final Getter getter = ReflectionTools.getGetter( obj.getClass(), idPropertyData );
mapToMapFromId( data, getter.get( obj ) );
}
@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();
final Object subObj = ReflectHelper.getDefaultConstructor( getter.getReturnType() ).newInstance();
boolean ret = true;
for ( IdMapper idMapper : ids.values() ) {
@ -83,36 +86,40 @@ public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements Simpl
}
return ret;
} catch (Exception e) {
}
catch (Exception e) {
throw new AuditException( e );
}
}
@Override
public IdMapper prefixMappedProperties(String prefix) {
EmbeddedIdMapper ret = new EmbeddedIdMapper(idPropertyData, compositeIdClass);
final EmbeddedIdMapper ret = new EmbeddedIdMapper( idPropertyData, compositeIdClass );
for ( PropertyData propertyData : ids.keySet() ) {
String propertyName = propertyData.getName();
final String propertyName = propertyData.getName();
ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
}
return ret;
}
@Override
public Object mapToIdFromEntity(Object data) {
if ( data == null ) {
return null;
}
Getter getter = ReflectionTools.getGetter(data.getClass(), idPropertyData);
final Getter getter = ReflectionTools.getGetter( data.getClass(), idPropertyData );
return getter.get( data );
}
@Override
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
Map<String, Object> data = new LinkedHashMap<String, Object>();
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() ) );

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;
@ -38,6 +39,7 @@ public interface IdMapper {
/**
* @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);
@ -49,13 +51,16 @@ public interface IdMapper {
/**
* 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);
@ -63,6 +68,7 @@ public interface IdMapper {
/**
* 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.
@ -73,6 +79,7 @@ public interface IdMapper {
* 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
@ -84,6 +91,7 @@ public interface IdMapper {
/**
* 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).
@ -95,6 +103,7 @@ public interface IdMapper {
* 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.

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
@ -40,16 +40,19 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
super( compositeIdClass );
}
@Override
public void mapToMapFromId(Map<String, Object> data, Object obj) {
for ( IdMapper idMapper : ids.values() ) {
idMapper.mapToMapFromEntity( data, obj );
}
}
@Override
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
mapToMapFromId( data, obj );
}
@Override
public boolean mapToEntityFromMap(Object obj, Map data) {
boolean ret = true;
for ( IdMapper idMapper : ids.values() ) {
@ -59,26 +62,29 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
return ret;
}
@Override
public IdMapper prefixMappedProperties(String prefix) {
MultipleIdMapper ret = new MultipleIdMapper(compositeIdClass);
final MultipleIdMapper ret = new MultipleIdMapper( compositeIdClass );
for ( PropertyData propertyData : ids.keySet() ) {
String propertyName = propertyData.getName();
final String propertyName = propertyData.getName();
ret.ids.put( propertyData, new SingleIdMapper( new PropertyData( prefix + propertyName, propertyData ) ) );
}
return ret;
}
@Override
public Object mapToIdFromEntity(Object data) {
if ( data == null ) {
return null;
}
Object ret;
final Object ret;
try {
ret = ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
} catch (Exception e) {
}
catch (Exception e) {
throw new AuditException( e );
}
@ -89,11 +95,12 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
return ret;
}
@Override
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
Map<String, Object> data = new LinkedHashMap<String, Object>();
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() ) );

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,7 +22,9 @@
* 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)
@ -39,7 +41,8 @@ public class QueryParameterData {
public String getProperty(String prefix) {
if ( prefix != null ) {
return prefix + "." + flatEntityPropertyName;
} else {
}
else {
return flatEntityPropertyName;
}
}
@ -56,18 +59,20 @@ public class QueryParameterData {
return flatEntityPropertyName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof QueryParameterData)) return false;
QueryParameterData that = (QueryParameterData) o;
if (flatEntityPropertyName != null ? !flatEntityPropertyName.equals(that.flatEntityPropertyName) : that.flatEntityPropertyName != null)
return false;
if ( this == o ) {
return true;
}
if ( !(o instanceof QueryParameterData) ) {
return false;
}
final QueryParameterData that = (QueryParameterData) o;
return EqualsHelper.equals( flatEntityPropertyName, that.flatEntityPropertyName );
}
@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
@ -47,6 +47,7 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
this.propertyData = propertyData;
}
@Override
public void add(PropertyData propertyData) {
if ( this.propertyData != null ) {
throw new AuditException( "Only one property can be added!" );
@ -55,22 +56,24 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
this.propertyData = propertyData;
}
@Override
public boolean mapToEntityFromMap(Object obj, Map data) {
if ( data == null || obj == null ) {
return false;
}
Object value = data.get(propertyData.getName());
final Object value = data.get( propertyData.getName() );
if ( value == null ) {
return false;
}
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
final Setter setter = ReflectionTools.getSetter( obj.getClass(), propertyData );
setter.set( obj, value, null );
return true;
}
@Override
public Object mapToIdFromMap(Map data) {
if ( data == null ) {
return null;
@ -79,35 +82,41 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
return data.get( propertyData.getName() );
}
@Override
public Object mapToIdFromEntity(Object data) {
if ( data == null ) {
return null;
}
if ( data instanceof HibernateProxy ) {
HibernateProxy hibernateProxy = (HibernateProxy) data;
final HibernateProxy hibernateProxy = (HibernateProxy) data;
return hibernateProxy.getHibernateLazyInitializer().getIdentifier();
} else {
Getter getter = ReflectionTools.getGetter(data.getClass(), propertyData);
}
else {
final Getter getter = ReflectionTools.getGetter( data.getClass(), propertyData );
return getter.get( data );
}
}
@Override
public void mapToMapFromId(Map<String, Object> data, Object obj) {
if ( data != null ) {
data.put( propertyData.getName(), obj );
}
}
@Override
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
if ( obj == null ) {
data.put( propertyData.getName(), null );
} else {
}
else {
if ( obj instanceof HibernateProxy ) {
HibernateProxy hibernateProxy = (HibernateProxy)obj;
final HibernateProxy hibernateProxy = (HibernateProxy) obj;
data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier() );
} else {
Getter getter = ReflectionTools.getGetter(obj.getClass(), propertyData);
}
else {
final Getter getter = ReflectionTools.getGetter( obj.getClass(), propertyData );
data.put( propertyData.getName(), getter.get( obj ) );
}
}
@ -118,17 +127,19 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
return;
}
Getter getter = ReflectionTools.getGetter(objFrom.getClass(), propertyData);
Setter setter = ReflectionTools.getSetter(objTo.getClass(), propertyData);
final Getter getter = ReflectionTools.getGetter( objFrom.getClass(), propertyData );
final Setter setter = ReflectionTools.getSetter( objTo.getClass(), propertyData );
setter.set( objTo, getter.get( objFrom ), null );
}
@Override
public IdMapper prefixMappedProperties(String prefix) {
return new SingleIdMapper( new PropertyData( prefix + propertyData.getName(), propertyData ) );
}
@Override
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
final List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
ret.add( new QueryParameterData( propertyData.getName(), obj ) );

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
@ -60,7 +60,8 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
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;
@ -70,26 +71,35 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
try {
proxyConstructor = proxyClass.getConstructor( Initializor.class );
} catch (NoSuchMethodException e) {
}
catch (NoSuchMethodException e) {
throw new AuditException( e );
}
}
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
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);
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,78 +110,112 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
return idMap;
}
private void addCollectionChanges(SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
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++ );
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));
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 );
(revisionTypeInId ? originalId : entityData).put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType);
(revisionTypeInId ? originalId : entityData).put(
commonCollectionMapperData.getVerEntCfg()
.getRevisionTypePropName(), revisionType
);
}
}
@Override
@SuppressWarnings({"unchecked"})
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
public List<PersistentCollectionChangeData> mapCollectionChanges(
SessionImplementor session,
String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(referencingPropertyName)) {
if ( !commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(
referencingPropertyName
) ) {
return null;
}
List<PersistentCollectionChangeData> collectionChanges = new ArrayList<PersistentCollectionChangeData>();
final List<PersistentCollectionChangeData> collectionChanges = new ArrayList<PersistentCollectionChangeData>();
// Comparing new and old collection content.
Collection newCollection = getNewCollectionContent(newColl);
Collection oldCollection = getOldCollectionContent(oldColl);
final Collection newCollection = getNewCollectionContent( newColl );
final Collection oldCollection = getOldCollectionContent( oldColl );
Set<Object> added = new HashSet<Object>();
if (newColl != null) { added.addAll(newCollection); }
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)); }
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); }
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)); }
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) {
@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) {
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
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)) {
}
else if ( isFromNullToEmptyOrFromEmptyToNull( (PersistentCollection) newObj, (Serializable) oldObj ) ) {
data.put( propertyData.getModifiedFlagPropertyName(), true );
} else {
List<PersistentCollectionChangeData> changes = mapCollectionChanges(session,
}
else {
final List<PersistentCollectionChangeData> changes = mapCollectionChanges(
session,
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
(PersistentCollection) newObj, (Serializable) oldObj, null);
(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,35 +236,52 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
final PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
if ( propertyData.isUsingModifiedFlag() ) {
data.put(propertyData.getModifiedFlagPropertyName(), propertyData.getName().equals(collectionPropertyName));
data.put(
propertyData.getModifiedFlagPropertyName(),
propertyData.getName().equals( collectionPropertyName )
);
}
}
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg,
protected abstract Initializor<T> getInitializor(
AuditConfiguration verCfg,
AuditReaderImplementor versionsReader, Object primaryKey,
Number revision, boolean removed);
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
@Override
public void mapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
Setter setter = ReflectionTools.getSetter(obj.getClass(), commonCollectionMapperData.getCollectionReferencingPropertyData());
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) {
}
catch (InstantiationException e) {
throw new AuditException( e );
} catch (IllegalAccessException e) {
}
catch (IllegalAccessException e) {
throw new AuditException( e );
} catch (InvocationTargetException 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,6 +36,7 @@ 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 {
@ -26,18 +50,23 @@ public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
}
@Override
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
public void nullSafeMapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
EntityInfo referencedEntity = getEntityInfo(verCfg, referencedEntityName);
final EntityInfo referencedEntity = getEntityInfo( verCfg, referencedEntityName );
Object value = null;
Object value;
try {
value = queryForReferencedEntity( versionsReader, referencedEntity, (Serializable) primaryKey, revision );
} catch (NoResultException e) {
}
catch (NoResultException e) {
value = null;
} catch (NonUniqueResultException e) {
throw new AuditException("Many versions results for one-to-one relationship " + entityName +
"." + getPropertyData().getBeanName() + ".", e);
}
catch (NonUniqueResultException e) {
throw new AuditException(
"Many versions results for one-to-one relationship " + entityName +
"." + getPropertyData().getBeanName() + ".", e
);
}
setPropertyValue( obj, value );
@ -48,19 +77,28 @@ public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
* @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,
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) {
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()));
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,6 +40,7 @@ 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 {
@ -27,12 +51,17 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
}
@Override
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
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,
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 );
@ -40,7 +69,8 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
}
@Override
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
public List<PersistentCollectionChangeData> mapCollectionChanges(
SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl, Serializable oldColl,
Serializable id) {
return null;
@ -49,6 +79,7 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
/**
* @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) {
@ -59,12 +90,12 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration( entityName );
isRelationAudited = false;
}
Class entityClass = ReflectionTools.loadClass( entCfg.getEntityClassName(), verCfg.getClassLoaderService() );
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);
final Setter setter = ReflectionTools.getSetter( targetObject.getClass(), propertyData );
setter.set( targetObject, value, null );
}
@ -77,10 +108,16 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
/**
* 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);
public abstract void nullSafeMapToEntityFromMap(
AuditConfiguration verCfg,
Object obj,
Map data,
Object primaryKey,
AuditReaderImplementor versionsReader,
Number revision);
/**
* Simple descriptor of an entity.
@ -96,8 +133,16 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
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
@ -41,34 +41,48 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
public class BasicCollectionMapper<T extends Collection> extends AbstractCollectionMapper<T> implements PropertyMapper {
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;
}
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
@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);
return new BasicCollectionInitializor<T>(
verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, removed, collectionClass, elementComponentData
);
}
@Override
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
return (Collection) newCollection;
}
@Override
protected Collection getOldCollectionContent(Serializable oldCollection) {
if ( oldCollection == null ) {
return null;
} else if (oldCollection instanceof Map) {
}
else if ( oldCollection instanceof Map ) {
return ((Map) oldCollection).keySet();
} else {
}
else {
return (Collection) oldCollection;
}
}
protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object 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,12 +22,14 @@
* 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 {
@ -37,7 +39,8 @@ public final class CommonCollectionMapperData {
private final MiddleIdData referencingIdData;
private final RelationQueryGenerator queryGenerator;
public CommonCollectionMapperData(AuditEntitiesConfiguration verEntCfg, String versionsMiddleEntityName,
public CommonCollectionMapperData(
AuditEntitiesConfiguration verEntCfg, String versionsMiddleEntityName,
PropertyData collectionReferencingPropertyData, MiddleIdData referencingIdData,
RelationQueryGenerator queryGenerator) {
this.verEntCfg = verEntCfg;

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
@ -46,7 +46,8 @@ public final class ListCollectionMapper extends AbstractCollectionMapper<List> i
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
public ListCollectionMapper(
CommonCollectionMapperData commonCollectionMapperData,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
boolean revisionTypeInId) {
super( commonCollectionMapperData, List.class, ListProxy.class, false, revisionTypeInId );
@ -54,34 +55,52 @@ public final class ListCollectionMapper extends AbstractCollectionMapper<List> i
this.indexComponentData = indexComponentData;
}
protected Initializor<List> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
@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);
return new ListCollectionInitializor(
verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, removed, elementComponentData, indexComponentData
);
}
@Override
@SuppressWarnings({"unchecked"})
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
if ( newCollection == null ) {
return null;
} else {
}
else {
return Tools.listToIndexElementPairList( (List<Object>) newCollection );
}
}
@Override
@SuppressWarnings({"unchecked"})
protected Collection getOldCollectionContent(Serializable oldCollection) {
if ( oldCollection == null ) {
return null;
} else {
}
else {
return Tools.listToIndexElementPairList( (List<Object>) oldCollection );
}
}
@Override
@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());
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