HHH-8159 - Apply fixups indicated by analysis tools
This commit is contained in:
parent
ad1d1ab8b4
commit
364a47f2c7
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,11 +22,12 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -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 {};
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() ) + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 + ")";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
@ -8,6 +31,7 @@ import java.lang.annotation.Target;
|
|||
/**
|
||||
* Marks a property which holds entity names that have been modified during each revision.
|
||||
* This annotation expects field of <code>{@literal Set<String>}</code> type.
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -29,6 +30,7 @@ import java.lang.annotation.Target;
|
|||
|
||||
/**
|
||||
* When applied to a field, indicates that this field should not be audited.
|
||||
*
|
||||
* @author Sebastian Komander
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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 {
|
|||
* </set>
|
||||
* </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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)." :
|
||||
""));
|
||||
"")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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." );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -1,4 +1,28 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
|
@ -6,10 +30,13 @@ import org.hibernate.mapping.Property;
|
|||
|
||||
/**
|
||||
* A source of data on persistent properties of a class or component.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public interface PersistentPropertiesSource {
|
||||
Iterator<Property> getPropertyIterator();
|
||||
|
||||
Property getProperty(String propertyName);
|
||||
|
||||
XClass getXClass();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,9 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -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 ) ) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.enhanced;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -8,6 +31,7 @@ import org.hibernate.internal.util.StringHelper;
|
|||
|
||||
/**
|
||||
* Revision number generator has to produce values in ascending order (gaps may occur).
|
||||
*
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class OrderedSequenceGenerator extends SequenceStyleGenerator {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -23,13 +23,13 @@
|
|||
*/
|
||||
package org.hibernate.envers.enhanced;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
@ -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()
|
||||
) + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -31,5 +31,10 @@ import org.hibernate.envers.configuration.spi.AuditConfiguration;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EnversListener {
|
||||
/**
|
||||
* Get the Envers AuditConfiguration
|
||||
*
|
||||
* @return The Envers AuditConfiguration
|
||||
*/
|
||||
public AuditConfiguration getAuditConfiguration();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ import org.hibernate.event.service.spi.DuplicationStrategy;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnversListenerDuplicationStrategy implements DuplicationStrategy {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final EnversListenerDuplicationStrategy INSTANCE = new EnversListenerDuplicationStrategy();
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,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 );
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ) ) {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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á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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() }
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
@ -30,5 +31,10 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
|
||||
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState);
|
||||
public boolean map(
|
||||
SessionImplementor session,
|
||||
Map<String, Object> data,
|
||||
String[] propertyNames,
|
||||
Object[] newState,
|
||||
Object[] oldState);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() ) );
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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() ) );
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.id;
|
||||
|
||||
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -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 ) );
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue