[hibernate-commits] Hibernate SVN: r18203 - in core/branches/envers-hibernate-3.3/src: main/java/org/hibernate/envers/configuration/metadata and 5 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri Dec 11 02:17:36 EST 2009


Author: adamw
Date: 2009-12-11 02:17:36 -0500 (Fri, 11 Dec 2009)
New Revision: 18203

Added:
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java
   core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java
   core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java
Removed:
   core/branches/envers-hibernate-3.3/src/main/java/org/jboss/
Modified:
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java
   core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java
Log:
svn merge -r 18152:18202 https://svn.jboss.org/repos/hibernate/core/trunk/envers .

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -40,6 +40,7 @@
 import org.hibernate.envers.entities.mapper.SubclassPropertyMapper;
 import org.hibernate.envers.tools.StringTools;
 import org.hibernate.envers.tools.Triple;
+import org.hibernate.envers.RelationTargetAuditMode;
 
 import org.hibernate.MappingException;
 import org.hibernate.cfg.Configuration;
@@ -380,7 +381,7 @@
 			String parentEntityName = null;
 			EntityConfiguration entityCfg = new EntityConfiguration(entityName, idMapper, propertyMapper,
 					parentEntityName);
-			notAuditedEntitiesConfigurations.put(pc.getEntityName(), entityCfg);
+			notAuditedEntitiesConfigurations.put(entityName, entityCfg);
 			return;
 		}
 
@@ -513,6 +514,36 @@
         throw new MappingException(message);
     }
 
+    /**
+     * 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.
+     * @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,
+                                             PropertyAuditingData propertyAuditingData,
+                                             boolean allowNotAuditedTarget) {
+        EntityConfiguration configuration = getEntitiesConfigurations().get(referencedEntityName);
+		if (configuration == null) {
+            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 + "."
+						+ propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!"
+						+ (allowNotAuditedTarget ?
+                            " Such mapping is possible, but has to be explicitly defined using @Audited(targetAuditMode = NOT_AUDITED)." :
+                            ""));
+			}
+		}
+
+        return configuration.getIdMappingData();
+    }
+
 	/**
 	 * Get the notAuditedEntitiesConfigurations property.
 	 *

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -155,28 +155,26 @@
         }
     }
 
+    private MiddleIdData createMiddleIdData(IdMappingData idMappingData, String prefix, String entityName) {
+        return new MiddleIdData(mainGenerator.getVerEntCfg(), idMappingData, prefix, entityName,
+                mainGenerator.getEntitiesConfigurations().containsKey(entityName));
+    }
+
     @SuppressWarnings({"unchecked"})
     private void addOneToManyAttached() {
         String mappedBy = getMappedBy(propertyValue);
 
-        EntityConfiguration referencedEntityConfiguration = mainGenerator.getEntitiesConfigurations()
-                .get(referencedEntityName);
-
-		if (referencedEntityConfiguration == null) {
-			throwRelationNotAudited(referencedEntityName);
-			// Impossible to get here.
-            throw new AssertionError();
-		}
-        IdMappingData referencedIdMapping = referencedEntityConfiguration.getIdMappingData();
+        IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(referencingEntityName,
+                    referencedEntityName, propertyAuditingData, false);
         IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
 
         // Generating the id mappers data for the referencing side of the relation.
-        MiddleIdData referencingIdData = new MiddleIdData(mainGenerator.getVerEntCfg(), referencingIdMapping,
+        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 = new MiddleIdData(mainGenerator.getVerEntCfg(), referencedIdMapping,
+        MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping,
                 null, referencedEntityName);
 
         // Generating the element mapping.
@@ -293,7 +291,7 @@
         }
 
         // Storing the id data of the referencing entity: original mapper, prefixed mapper and entity name.
-        MiddleIdData referencingIdData = new MiddleIdData(mainGenerator.getVerEntCfg(), referencingIdMapping,
+        MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping,
                 referencingPrefixRelated, referencingEntityName);
 
         // Creating a query generator builder, to which additional id data will be added, in case this collection
@@ -390,15 +388,10 @@
             String prefixRelated = prefix + "_";
 
             String referencedEntityName = getReferencedEntityName(value);
-			EntityConfiguration referencedEntityConfiguration = mainGenerator.getEntitiesConfigurations()
-                    .get(referencedEntityName);
-			if (referencedEntityConfiguration == null) {
-				throwRelationNotAudited(referencedEntityName);
-				// Impossible to get here.
-                throw new AssertionError();
-			}
-            IdMappingData referencedIdMapping = referencedEntityConfiguration.getIdMappingData();
 
+            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) {
@@ -410,7 +403,7 @@
             }
 
             // Storing the id data of the referenced entity: original mapper, prefixed mapper and entity name.
-            MiddleIdData referencedIdData = new MiddleIdData(mainGenerator.getVerEntCfg(), referencedIdMapping,
+            MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping,
                     prefixRelated, referencedEntityName);
             // And adding it to the generator builder.
             queryGeneratorBuilder.addRelation(referencedIdData);
@@ -541,9 +534,4 @@
         throw new MappingException("Unable to read the mapped by attribute for " + propertyName + " in "
                 + referencingEntityName + "!");
     }
-
-	private void throwRelationNotAudited(String referencedEntityName) {
-		throw new MappingException("An audited relation from " + referencingEntityName +
-				" to a non-audited entity: " + referencedEntityName);
-	}
 }

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -30,10 +30,8 @@
 import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
 import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
 import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
-import org.hibernate.envers.entities.mapper.relation.query.OneEntityQueryGenerator;
-import org.hibernate.envers.entities.mapper.relation.query.RelationQueryGenerator;
-import org.hibernate.envers.entities.mapper.relation.query.ThreeEntityQueryGenerator;
-import org.hibernate.envers.entities.mapper.relation.query.TwoEntityQueryGenerator;
+import org.hibernate.envers.entities.mapper.relation.query.*;
+import org.hibernate.MappingException;
 
 /**
  * Builds query generators, for reading collection middle tables, along with any related entities.
@@ -66,9 +64,19 @@
             return new OneEntityQueryGenerator(verEntCfg, auditMiddleEntityName, referencingIdData,
                     componentDatas);
         } else if (idDatas.size() == 1) {
-            return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditMiddleEntityName, referencingIdData,
-                    idDatas.get(0), componentDatas);
+            if (idDatas.get(0).isAudited()) {
+                return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditMiddleEntityName, referencingIdData,
+                        idDatas.get(0), componentDatas);
+            } else {
+                return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditMiddleEntityName, referencingIdData,
+                        idDatas.get(0), componentDatas);
+            }
         } else if (idDatas.size() == 2) {
+            // All entities must be audited.
+            if (!idDatas.get(0).isAudited() || !idDatas.get(1).isAudited()) {
+                throw new MappingException("Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported.");
+            }
+
             return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditMiddleEntityName, referencingIdData,
                     idDatas.get(0), idDatas.get(1), componentDatas);
         } else {

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -24,7 +24,6 @@
 package org.hibernate.envers.configuration.metadata;
 
 import org.dom4j.Element;
-import org.hibernate.envers.RelationTargetAuditMode;
 import org.hibernate.envers.entities.EntityConfiguration;
 import org.hibernate.envers.entities.IdMappingData;
 import org.hibernate.envers.entities.PropertyData;
@@ -55,25 +54,9 @@
                   CompositeMapperBuilder mapper, String entityName, boolean insertable) {
         String referencedEntityName = ((ToOne) value).getReferencedEntityName();
 
-		EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(referencedEntityName);
-		if (configuration == null) {
-			configuration = mainGenerator.getNotAuditedEntitiesConfigurations().get(referencedEntityName);
-			if (configuration != null) {
-				RelationTargetAuditMode relationTargetAuditMode = propertyAuditingData.getRelationTargetAuditMode();
-				if (!RelationTargetAuditMode.NOT_AUDITED.equals(relationTargetAuditMode)) {
-					throw new MappingException("An audited relation from " + entityName + "."
-							+ propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!"
-							+ ". Such mapping is possible, but has to be strictly defined using RelationTargetAuditMode.NOT_AUDITED in @Audited.");
-				}
-			}
-		}
-		if (configuration == null) {
-			throw new MappingException("An audited relation from " + entityName + "."
-					+ propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!");
-		}
+        IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(entityName, referencedEntityName,
+                propertyAuditingData, true);
 
-        IdMappingData idMapping = configuration.getIdMappingData();
-
         String lastPropertyPrefix = propertyAuditingData.getName() + "_";
 
         // Generating the id mapper for the relation

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -33,44 +33,51 @@
  * @author Adam Warski (adam at warski dot org)
  */
 public final class MiddleIdData {
-    /**
-     * Original id mapper of the related entity.
-     */
     private final IdMapper originalMapper;
-    /**
-     * Prefixed id mapper (with the names for the id fields that are used in the middle table) of the related entity.
-     */
     private final IdMapper prefixedMapper;
-    /**
-     * Name of the related entity.
-     */
     private final String entityName;
-    /**
-     * Versions name of the related entity.
-     */
-    private final String versionsEntityName;
+    private final String auditEntityName;
 
     public MiddleIdData(AuditEntitiesConfiguration verEntCfg, IdMappingData mappingData, String prefix,
-                        String entityName) {
+                        String entityName, boolean audited) {
         this.originalMapper = mappingData.getIdMapper();
         this.prefixedMapper = mappingData.getIdMapper().prefixMappedProperties(prefix);
         this.entityName = entityName;
-        this.versionsEntityName = verEntCfg.getAuditEntityName(entityName);
+        this.auditEntityName = audited ? verEntCfg.getAuditEntityName(entityName) : null;
     }
 
+    /**
+     * @return Original id mapper of the related entity.
+     */
     public IdMapper getOriginalMapper() {
         return originalMapper;
     }
 
+    /**
+     * @return prefixed id mapper (with the names for the id fields that are used in the middle table) of the related entity.
+     */
     public IdMapper getPrefixedMapper() {
         return prefixedMapper;
     }
 
+    /**
+     * @return Name of the related entity (regular, not audited).
+     */
     public String getEntityName() {
         return entityName;
     }
 
-    public String getVersionsEntityName() {
-        return versionsEntityName;
+    /**
+     * @return Audit name of the related entity.
+     */
+    public String getAuditEntityName() {
+        return auditEntityName;
     }
+
+    /**
+     * @return Is the entity, to which this middle id data correspond, audited.
+     */
+    public boolean isAudited() {
+        return auditEntityName != null;
+    }
 }

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -66,8 +66,16 @@
     @SuppressWarnings({"unchecked"})
     protected void addToCollection(T collection, Object collectionRow) {
         Object elementData = ((List) collectionRow).get(elementComponentData.getComponentIndex());
-        Object element = elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
-                (Map<String, Object>) elementData, null, revision);
+
+        // If the target entity is not audited, the elements may be the entities already, so we have to check
+        // if they are maps or not.
+        Object element;
+        if (elementData instanceof Map) {
+            element = elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
+                    (Map<String, Object>) elementData, null, revision);
+        } else {
+            element = elementData;
+        }
         collection.add(element);
     }
 }

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -37,7 +37,7 @@
                                            MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
                                            String alias1, String alias2) {
         // SELECT max(e.revision) FROM versionsReferencedEntity e2
-        QueryBuilder maxERevQb = qb.newSubQueryBuilder(idData.getVersionsEntityName(), alias2);
+        QueryBuilder maxERevQb = qb.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
         maxERevQb.addProjection("max", revisionPropertyPath, false);
         // WHERE
         Parameters maxERevQbParameters = maxERevQb.getRootParameters();

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -28,6 +28,8 @@
 import org.hibernate.Query;
 
 /**
+ * TODO: cleanup implementations and extract common code
+ *
  * Implementations of this interface provide a method to generate queries on a relation table (a table used
  * for mapping relations). The query can select, apart from selecting the content of the relation table, also data of
  * other "related" entities.

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -85,8 +85,8 @@
 
         // SELECT new list(ee) FROM middleEntity ee
         QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
-        qb.addFrom(referencedIdData.getVersionsEntityName(), "e");
-        qb.addFrom(indexIdData.getVersionsEntityName(), "f");
+        qb.addFrom(referencedIdData.getAuditEntityName(), "e");
+        qb.addFrom(indexIdData.getAuditEntityName(), "f");
         qb.addProjection("new list", "ee, e, f", false, false);
         // WHERE
         Parameters rootParameters = qb.getRootParameters();

Copied: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java (from rev 18202, core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java)
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java	                        (rev 0)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -0,0 +1,108 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This 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.entities.mapper.relation.query;
+
+import java.util.Collections;
+
+import org.hibernate.envers.RevisionType;
+import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
+import org.hibernate.envers.entities.mapper.id.QueryParameterData;
+import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
+import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
+import org.hibernate.envers.reader.AuditReaderImplementor;
+import org.hibernate.envers.tools.query.Parameters;
+import org.hibernate.envers.tools.query.QueryBuilder;
+
+import org.hibernate.Query;
+
+/**
+ * Selects data from a relation middle-table and a related non-audited entity.
+ * @author Adam Warski (adam at warski dot org)
+ */
+public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGenerator {
+    private final String queryString;
+    private final MiddleIdData referencingIdData;
+
+    public TwoEntityOneAuditedQueryGenerator(
+                                   AuditEntitiesConfiguration verEntCfg,
+                                   String versionsMiddleEntityName,
+                                   MiddleIdData referencingIdData,
+                                   MiddleIdData referencedIdData,
+                                   MiddleComponentData... componentDatas) {
+        this.referencingIdData = referencingIdData;
+
+        /*
+         * The query that we need to create:
+         *   SELECT new list(ee, e) FROM referencedEntity e, middleEntity ee
+         *   WHERE
+         * (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
+         *     ee.id_ref_ed = e.id_ref_ed AND
+         * (only entities referenced by the association; id_ref_ing = id of the referencing entity)
+         *     ee.id_ref_ing = :id_ref_ing AND
+         * (the association at revision :revision)
+         *     ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
+         *       WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*) AND
+         * (only non-deleted entities and associations)
+         *     ee.revision_type != DEL
+         */
+        String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
+        String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
+
+        String eeOriginalIdPropertyPath = "ee." + originalIdPropertyName;
+
+        // SELECT new list(ee) FROM middleEntity ee
+        QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
+        qb.addFrom(referencedIdData.getEntityName(), "e");
+        qb.addProjection("new list", "ee, e", false, false);
+        // WHERE
+        Parameters rootParameters = qb.getRootParameters();
+        // ee.id_ref_ed = e.id_ref_ed
+        referencedIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters, eeOriginalIdPropertyPath,
+                referencedIdData.getOriginalMapper(), "e");
+        // ee.originalId.id_ref_ing = :id_ref_ing
+        referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
+
+        // ee.revision = (SELECT max(...) ...)
+        QueryGeneratorTools.addAssociationAtRevision(qb, rootParameters, referencingIdData, versionsMiddleEntityName,
+                eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
+
+        // ee.revision_type != DEL
+        rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
+
+        StringBuilder sb = new StringBuilder();
+        qb.build(sb, Collections.<String, Object>emptyMap());
+        queryString = sb.toString();
+    }
+
+    public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
+        Query query = versionsReader.getSession().createQuery(queryString);
+        query.setParameter("revision", revision);
+        query.setParameter("delrevisiontype", RevisionType.DEL);
+        for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
+            paramData.setParameterValue(query);
+        }
+
+        return query;
+    }
+}
\ No newline at end of file

Modified: core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java
===================================================================
--- core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java	2009-12-10 21:47:01 UTC (rev 18202)
+++ core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -78,7 +78,7 @@
 
         // SELECT new list(ee) FROM middleEntity ee
         QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
-        qb.addFrom(referencedIdData.getVersionsEntityName(), "e");
+        qb.addFrom(referencedIdData.getAuditEntityName(), "e");
         qb.addProjection("new list", "ee, e", false, false);
         // WHERE
         Parameters rootParameters = qb.getRootParameters();

Copied: core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java (from rev 18202, core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java)
===================================================================
--- core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java	                        (rev 0)
+++ core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -0,0 +1,116 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This 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.test.entities.manytomany.unidirectional;
+
+import javax.persistence.*;
+
+import org.hibernate.envers.Audited;
+import org.hibernate.envers.RelationTargetAuditMode;
+import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
+
+import java.util.List;
+
+/**
+ * Audited entity with a many-to-many-reference to not audited entity.
+ * @author Toamsz Bech
+ * @author Adam Warski
+ */
+ at Entity
+public class M2MTargetNotAuditedEntity {
+	@Id
+	private Integer id;
+
+	@Audited
+	private String data;
+
+	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
+	@ManyToMany(fetch = FetchType.LAZY)
+	private List<UnversionedStrTestEntity> references;
+
+	public M2MTargetNotAuditedEntity() { }
+
+	public M2MTargetNotAuditedEntity(Integer id, String data, List<UnversionedStrTestEntity> references) {
+		this.id = id;
+		this.data = data;
+		this.references = references;
+	}
+
+	public M2MTargetNotAuditedEntity(String data, List<UnversionedStrTestEntity> references) {
+		this.data = data;
+		this.references = references;
+	}
+
+	public M2MTargetNotAuditedEntity(Integer id, String data) {
+		this.id = id;
+		this.data = data;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getData() {
+		return data;
+	}
+
+	public void setData(String data) {
+		this.data = data;
+	}
+
+    public List<UnversionedStrTestEntity> getReferences() {
+        return references;
+    }
+
+    public void setReferences(List<UnversionedStrTestEntity> references) {
+        this.references = references;
+    }
+
+    public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof M2MTargetNotAuditedEntity)) return false;
+
+		M2MTargetNotAuditedEntity that = (M2MTargetNotAuditedEntity) o;
+
+		if (data != null ? !data.equals(that.getData()) : that.getData() != null) return false;
+        //noinspection RedundantIfStatement
+        if (id != null ? !id.equals(that.getId()) : that.getId() != null) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		int result;
+		result = (id != null ? id.hashCode() : 0);
+		result = 31 * result + (data != null ? data.hashCode() : 0);
+		return result;
+	}
+
+	public String toString() {
+		return "M2MTargetNotAuditedEntity(id = " + id + ", data = " + data + ")";
+	}
+}

Copied: core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java (from rev 18202, core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java)
===================================================================
--- core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java	                        (rev 0)
+++ core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java	2009-12-11 07:17:36 UTC (rev 18203)
@@ -0,0 +1,167 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This 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.test.integration.manytomany.unidirectional;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.ejb.Ejb3Configuration;
+import org.hibernate.envers.test.AbstractEntityTest;
+import static org.hibernate.envers.test.tools.TestTools.*;
+import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
+import org.hibernate.envers.test.entities.manytomany.unidirectional.M2MTargetNotAuditedEntity;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * A test for auditing a many-to-many relation where the target entity is not audited.
+ * @author Adam Warski
+ */
+public class M2MRelationNotAuditedTarget extends AbstractEntityTest {
+	private Integer tnae1_id;
+	private Integer tnae2_id;
+
+	private Integer uste1_id;
+	private Integer uste2_id;
+
+	public void configure(Ejb3Configuration cfg) {
+		cfg.addAnnotatedClass(M2MTargetNotAuditedEntity.class);
+		cfg.addAnnotatedClass(UnversionedStrTestEntity.class);
+	}
+
+	@BeforeClass(dependsOnMethods = "init")
+	public void initData() {
+		EntityManager em = getEntityManager();
+
+		UnversionedStrTestEntity uste1 = new UnversionedStrTestEntity("str1");
+		UnversionedStrTestEntity uste2 = new UnversionedStrTestEntity("str2");
+
+		// No revision
+		em.getTransaction().begin();
+
+		em.persist(uste1);
+		em.persist(uste2);
+
+		em.getTransaction().commit();
+
+		// Revision 1
+		em.getTransaction().begin();
+
+		uste1 = em.find(UnversionedStrTestEntity.class, uste1.getId());
+		uste2 = em.find(UnversionedStrTestEntity.class, uste2.getId());
+
+		M2MTargetNotAuditedEntity tnae1 = new M2MTargetNotAuditedEntity(1, "tnae1", new ArrayList<UnversionedStrTestEntity>());
+		M2MTargetNotAuditedEntity tnae2 = new M2MTargetNotAuditedEntity(2, "tnae2", new ArrayList<UnversionedStrTestEntity>());
+        tnae2.getReferences().add(uste1);
+        tnae2.getReferences().add(uste2);
+		em.persist(tnae1);
+		em.persist(tnae2);
+
+		em.getTransaction().commit();
+
+		// Revision 2
+		em.getTransaction().begin();
+
+		tnae1 = em.find(M2MTargetNotAuditedEntity.class, tnae1.getId());
+		tnae2 = em.find(M2MTargetNotAuditedEntity.class, tnae2.getId());
+
+		tnae1.getReferences().add(uste1);
+		tnae2.getReferences().remove(uste1);
+
+		em.getTransaction().commit();
+
+		// Revision 3
+		em.getTransaction().begin();
+
+		tnae1 = em.find(M2MTargetNotAuditedEntity.class, tnae1.getId());
+		tnae2 = em.find(M2MTargetNotAuditedEntity.class, tnae2.getId());
+
+		//field not changed!!!
+		tnae1.getReferences().add(uste1);
+		tnae2.getReferences().remove(uste2);
+
+		em.getTransaction().commit();
+
+		// Revision 4
+		em.getTransaction().begin();
+
+		tnae1 = em.find(M2MTargetNotAuditedEntity.class, tnae1.getId());
+		tnae2 = em.find(M2MTargetNotAuditedEntity.class, tnae2.getId());
+
+		tnae1.getReferences().add(uste2);
+		tnae2.getReferences().add(uste1);
+
+		em.getTransaction().commit();
+
+		//
+		tnae1_id = tnae1.getId();
+		tnae2_id = tnae2.getId();
+		uste1_id = uste1.getId();
+		uste2_id = uste2.getId();
+	}
+
+	@Test
+	public void testRevisionsCounts() {
+		List<Number> revisions = getAuditReader().getRevisions(M2MTargetNotAuditedEntity.class, tnae1_id);
+		assert Arrays.asList(1, 2, 4).equals(revisions);
+		revisions = getAuditReader().getRevisions(M2MTargetNotAuditedEntity.class, tnae2_id);
+		assert Arrays.asList(1, 2, 3, 4).equals(revisions);
+	}
+
+	@Test
+	public void testHistoryOfTnae1_id() {
+		UnversionedStrTestEntity uste1 = getEntityManager().find(UnversionedStrTestEntity.class, uste1_id);
+		UnversionedStrTestEntity uste2 = getEntityManager().find(UnversionedStrTestEntity.class, uste2_id);
+
+		M2MTargetNotAuditedEntity rev1 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae1_id, 1);
+		M2MTargetNotAuditedEntity rev2 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae1_id, 2);
+		M2MTargetNotAuditedEntity rev3 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae1_id, 3);
+		M2MTargetNotAuditedEntity rev4 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae1_id, 4);
+
+		checkList(rev1.getReferences());
+		checkList(rev2.getReferences(), uste1);
+		checkList(rev3.getReferences(), uste1);
+		checkList(rev4.getReferences(), uste1, uste2);
+	}
+
+	@Test
+	public void testHistoryOfTnae2_id() {
+		UnversionedStrTestEntity uste1 = getEntityManager().find(UnversionedStrTestEntity.class, uste1_id);
+		UnversionedStrTestEntity uste2 = getEntityManager().find(UnversionedStrTestEntity.class, uste2_id);
+
+		M2MTargetNotAuditedEntity rev1 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae2_id, 1);
+		M2MTargetNotAuditedEntity rev2 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae2_id, 2);
+		M2MTargetNotAuditedEntity rev3 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae2_id, 3);
+		M2MTargetNotAuditedEntity rev4 = getAuditReader().find(M2MTargetNotAuditedEntity.class, tnae2_id, 4);
+
+		checkList(rev1.getReferences(), uste1, uste2);
+		checkList(rev2.getReferences(), uste2);
+		checkList(rev3.getReferences());
+		checkList(rev4.getReferences(), uste1);
+	}
+}



More information about the hibernate-commits mailing list