[jboss-envers-commits] JBoss Envers SVN: r160 - in trunk/src/main/org/jboss/envers: entities/mapper/relation and 1 other directory.

jboss-envers-commits at lists.jboss.org jboss-envers-commits at lists.jboss.org
Mon Sep 22 11:33:45 EDT 2008


Author: adamw
Date: 2008-09-22 11:33:44 -0400 (Mon, 22 Sep 2008)
New Revision: 160

Removed:
   trunk/src/main/org/jboss/envers/entities/mapper/relation/AbstractOneToManyMapper.java
Modified:
   trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java
   trunk/src/main/org/jboss/envers/configuration/metadata/VersionsMetadataGenerator.java
   trunk/src/main/org/jboss/envers/entities/mapper/relation/OneToManyAttachedMapper.java
Log:
ENVERS-44: restructuring the collections mapper, making it statefull

Modified: trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java
===================================================================
--- trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java	2008-09-22 11:26:24 UTC (rev 159)
+++ trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java	2008-09-22 15:33:44 UTC (rev 160)
@@ -28,113 +28,104 @@
 import java.lang.annotation.Annotation;
 
 /**
- * Generates metadata for collection-valued properties.
+ * Generates metadata for a collection-valued property.
  * @author Adam Warski (adam at warski dot org)
  */
 public final class CollectionMetadataGenerator {
     private final VersionsMetadataGenerator mainGenerator;
+    private final String propertyName;
+    private final Collection propertyValue;
+    private final CompositeMapperBuilder currentMapper;
+    private final String referencingEntityName;
+    private final EntityXmlMappingData xmlMappingData;
+    private final VersionsJoinTable joinTable;
 
-    CollectionMetadataGenerator(VersionsMetadataGenerator versionsMetadataGenerator) {
-        mainGenerator = versionsMetadataGenerator;
-    }
+    private final EntityConfiguration referencingEntityConfiguration;
+    /**
+     * Null if this collection isn't a relation to another entity.
+     */
+    private final String referencedEntityName;
 
-    void addCollection(String name, Collection value, CompositeMapperBuilder currentMapper,
-                       String entityName, EntityXmlMappingData xmlMappingData,
-                       VersionsJoinTable joinTable) {
-        Type type = value.getType();
+    /**
+     * @param mainGenerator Main generator, giving access to configuration and the basic mapper.
+     * @param propertyName Name of the property that references the collection in the referencing entity.
+     * @param propertyValue Value of the collection, as mapped by Hibernate.
+     * @param currentMapper Mapper, to which the appropriate {@link org.jboss.envers.entities.mapper.PropertyMapper}
+     * will be added.
+     * @param referencingEntityName Name of the entity that owns this collection.
+     * @param xmlMappingData In case this collection requires a middle table, additional mapping documents will
+     * be created using this object.
+     * @param joinTable User data for the middle (join) table. <code>null</code> if the user didn't specify it.
+     */
+    public CollectionMetadataGenerator(VersionsMetadataGenerator mainGenerator, String propertyName,
+                                       Collection propertyValue, CompositeMapperBuilder currentMapper,
+                                       String referencingEntityName, EntityXmlMappingData xmlMappingData,
+                                       VersionsJoinTable joinTable) {
+        this.mainGenerator = mainGenerator;
+        this.propertyName = propertyName;
+        this.propertyValue = propertyValue;
+        this.currentMapper = currentMapper;
+        this.referencingEntityName = referencingEntityName;
+        this.xmlMappingData = xmlMappingData;
+        this.joinTable = joinTable == null ? getDefaultVersionsJoinTable() : joinTable;
 
-        if ((type instanceof BagType || type instanceof SetType) &&
-                (value.getElement() instanceof OneToMany) && (value.isInverse())) {
-            addOneToManyAttached(name, value, currentMapper, entityName);
-        } else {
-            addWithMiddleTable(name, value, currentMapper, entityName, xmlMappingData,
-                    joinTable == null ? getDefaultVersionsJoinTable() : joinTable);
+        referencingEntityConfiguration = mainGenerator.getEntitiesConfigurations().get(referencingEntityName);
+        if (referencingEntityConfiguration == null) {
+            throw new MappingException("Unable to read versioning configuration for " + referencingEntityName + "!");
         }
-    }
 
-    private VersionsJoinTable getDefaultVersionsJoinTable() {
-        return new VersionsJoinTable() {
-            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(); }
-        };
+        referencedEntityName = getReferencedEntityName(propertyValue.getElement());
     }
 
-    @SuppressWarnings({"unchecked"})
-    private String getMappedBy(Collection collectionValue) {
-        Iterator<Property> assocClassProps =
-                ((OneToMany) collectionValue.getElement()).getAssociatedClass().getPropertyIterator();
-
-        while (assocClassProps.hasNext()) {
-            Property property = assocClassProps.next();
-
-            if (Tools.iteratorsContentEqual(property.getValue().getColumnIterator(),
-                    collectionValue.getKey().getColumnIterator())) {
-                return property.getName();
-            }
+    private String getReferencedEntityName(Value value) {
+        if (value instanceof ToOne) {
+            return ((ToOne) value).getReferencedEntityName();
+        } else if (value instanceof OneToMany) {
+            return ((OneToMany) value).getReferencedEntityName();
+        } else {
+            return null;
         }
-
-        return null;
     }
 
-    @SuppressWarnings({"unchecked"})
-    private String getMappedBy(Table collectionTable, PersistentClass referencedClass) {
-        Iterator<Property> properties = referencedClass.getPropertyIterator();
-        while (properties.hasNext()) {
-            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
-                if (((Collection) property.getValue()).getCollectionTable() == collectionTable) {
-                    return property.getName();
-                }
-            }
+    void addCollection() {
+        Type type = propertyValue.getType();
+
+        if ((type instanceof BagType || type instanceof SetType) &&
+                (propertyValue.getElement() instanceof OneToMany) && (propertyValue.isInverse())) {
+            // A one-to-many relation mapped using @ManyToOne and @OneToMany(mappedBy="...")
+            addOneToManyAttached();
+        } else {
+            // All other kinds of relations require a middle (join) table).
+            addWithMiddleTable();
         }
-
-        return null;
     }
 
     @SuppressWarnings({"unchecked"})
-    private void addOneToManyAttached(String name, Collection value, CompositeMapperBuilder mapper, String entityName) {
-        String owningReferencePropertyName = getMappedBy(value);
-        if (owningReferencePropertyName == null) {
-            throw new MappingException("Unable to read the mapped by attribute for " + name + " in " + entityName + "!");
-        }
+    private void addOneToManyAttached() {
+        String owningReferencePropertyName = getMappedBy(propertyValue);
 
-        EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(entityName);
-        if (configuration == null) {
-            throw new MappingException("Unable to read versioning configuration for " + entityName + "!");
-        }
-
-        IdMappingData referencingIdMapping = configuration.getIdMappingData();
-
-        String owningEntityName = ((OneToMany) value.getElement()).getReferencedEntityName();
+        IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
         String lastPropertyPrefix = owningReferencePropertyName + "_";
 
         // Generating the id mapper for the relation
         IdMapper ownedIdMapper = referencingIdMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
 
         // Storing information about this relation
-        mainGenerator.getEntitiesConfigurations().get(entityName).addToManyNotOwningRelation(name, owningReferencePropertyName,
-                owningEntityName, ownedIdMapper);
+        referencingEntityConfiguration.addToManyNotOwningRelation(propertyName, owningReferencePropertyName,
+                referencedEntityName, ownedIdMapper);
 
         // Adding mapper for the id
-        mapper.addComposite(name, new OneToManyAttachedMapper(owningReferencePropertyName, owningEntityName,
-                name));
+        currentMapper.addComposite(propertyName, new OneToManyAttachedMapper(referencedEntityName, propertyName,
+                owningReferencePropertyName));
     }
 
-    private String getReferencedEntityName(Value value) {
-        if (value instanceof ToOne) {
-            return ((ToOne) value).getReferencedEntityName();
-        } else if (value instanceof OneToMany) {
-            return ((OneToMany) value).getReferencedEntityName();
-        } else {
-            return null;
-        }
-    }
-
+    /**
+     * 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,
                                         MetadataTools.ColumnNameIterator columnNameIterator,
@@ -159,17 +150,15 @@
     }
 
     @SuppressWarnings({"unchecked"})
-    private void addWithMiddleTable(String name, Collection value, CompositeMapperBuilder currentMapper,
-                                    String entityName, EntityXmlMappingData xmlMappingData, VersionsJoinTable joinTable) {
+    private void addWithMiddleTable() {
         // Generating the name of the middle table
-
         String versionsMiddleTableName;
         String versionsMiddleEntityName;
         if (!StringTools.isEmpty(joinTable.name())) {
             versionsMiddleTableName = joinTable.name();
             versionsMiddleEntityName = joinTable.name();
         } else {
-            String middleTableName = getMiddleTableName(value, entityName);
+            String middleTableName = getMiddleTableName(propertyValue, referencingEntityName);
             versionsMiddleTableName = mainGenerator.getVerEntCfg().getVersionsTableName(null, middleTableName);
             versionsMiddleEntityName = mainGenerator.getVerEntCfg().getVersionsEntityName(middleTableName);
         }
@@ -177,32 +166,18 @@
         // Generating the XML mapping for the middle entity, only if the relation isn't inverse.
         // If the relation is inverse, will be later checked by comparing middleEntityXml with null.
         Element middleEntityXml;
-        Element middleEntityXmlId;
-        if (!value.isInverse()) {
-            String schema = StringTools.isEmpty(joinTable.schema()) ? value.getCollectionTable().getSchema() : joinTable.schema();
-            String catalog = StringTools.isEmpty(joinTable.catalog()) ? value.getCollectionTable().getCatalog() : joinTable.catalog();
-
-            middleEntityXml = MetadataTools.createEntity(xmlMappingData.newAdditionalMapping(),
-                    versionsMiddleEntityName, versionsMiddleTableName, schema, catalog, null);
-            middleEntityXmlId = middleEntityXml.addElement("composite-id");
+        if (!propertyValue.isInverse()) {
+            middleEntityXml = createMiddleEntityXml(versionsMiddleTableName, versionsMiddleEntityName);
         } else {
             middleEntityXml = null;
-            middleEntityXmlId = null;
         }
 
         // ******
         // Generating the mapping for the referencing entity (it must be an entity).
         // ******
-        EntityConfiguration referencingConfiguration = mainGenerator.getEntitiesConfigurations().get(entityName);
-        if (referencingConfiguration == null) {
-            throw new MappingException("Unable to read versioning configuration for " + entityName + "!");
-        }
-
         // Getting the id-mapping data of the referencing entity (the entity that "owns" this collection).
-        IdMappingData referencingIdMapping = referencingConfiguration.getIdMappingData();
+        IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
 
-        // Null if this collection doesn't reference an entity.
-        String referencedEntityName = getReferencedEntityName(value.getElement());
         // Only valid for an inverse relation; null otherwise.
         String mappedBy;
 
@@ -210,28 +185,25 @@
         String referencingPrefixRelated;
         String referencedPrefix;
 
-        if (value.isInverse()) {
+        if (propertyValue.isInverse()) {
             // If the relation is inverse, then referencedEntityName is not null.
-            mappedBy = getMappedBy(value.getCollectionTable(), mainGenerator.getCfg().getClassMapping(referencedEntityName));
-            if (mappedBy == null) {
-                throw new MappingException("Unable to read the mapped by attribute for " + name);
-            }
+            mappedBy = getMappedBy(propertyValue.getCollectionTable(), mainGenerator.getCfg().getClassMapping(referencedEntityName));
 
             referencingPrefixRelated = mappedBy + "_";
             referencedPrefix = referencedEntityName == null ? "element" : StringTools.getLastComponent(referencedEntityName);
         } else {
             mappedBy = null;
 
-            referencingPrefixRelated = StringTools.getLastComponent(entityName) + "_";
-            referencedPrefix = referencedEntityName == null ? "element" : name;
+            referencingPrefixRelated = StringTools.getLastComponent(referencingEntityName) + "_";
+            referencedPrefix = referencedEntityName == null ? "element" : propertyName;
         }
 
         // Storing the id data of the referencing entity: original mapper, prefixed mapper and entity name.
         MiddleIdData referencingIdData = new MiddleIdData(
                 referencingIdMapping.getIdMapper(),
                 referencingIdMapping.getIdMapper().prefixMappedProperties(referencingPrefixRelated),
-                entityName,
-                mainGenerator.getVerEntCfg().getVersionsEntityName(entityName));
+                referencingEntityName,
+                mainGenerator.getVerEntCfg().getVersionsEntityName(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
@@ -241,34 +213,25 @@
 
         // Adding the XML mapping for the referencing entity, if the relation isn't inverse.
         if (middleEntityXml != null) {
-            middleEntityXmlId.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName());
-
             // Adding related-entity (in this case: the referencing's entity id) id mapping to the xml.
-            addRelatedToXmlMapping(middleEntityXmlId, referencingPrefixRelated,
-                    MetadataTools.getColumnNameIterator(value.getKey().getColumnIterator()),
+            addRelatedToXmlMapping(middleEntityXml, referencingPrefixRelated,
+                    MetadataTools.getColumnNameIterator(propertyValue.getKey().getColumnIterator()),
                     referencingIdMapping);
-
-            // Adding the revision number as a foreign key to the revision info entity to the composite id of the
-            // middle table.
-            mainGenerator.addRevisionInfoRelation(middleEntityXmlId);
-
-            // Adding the revision type property to the entity xml.
-            mainGenerator.addRevisionType(middleEntityXml);
         }
 
         // ******
         // Generating the element mapping.
         // ******
-        MiddleComponentData elementComponentData = addValueToMiddleTable(value.getElement(), middleEntityXmlId,
+        MiddleComponentData elementComponentData = addValueToMiddleTable(propertyValue.getElement(), middleEntityXml,
                 queryGeneratorBuilder, referencedPrefix, joinTable.inverseJoinColumns());
 
         // ******
         // Optionally, generating the index mapping.
         // ******
         MiddleComponentData indexComponentData;
-        if (value instanceof IndexedCollection) {
-            IndexedCollection indexedValue = (IndexedCollection) value;
-            indexComponentData = addValueToMiddleTable(indexedValue.getIndex(), middleEntityXmlId,
+        if (propertyValue instanceof IndexedCollection) {
+            IndexedCollection indexedValue = (IndexedCollection) propertyValue;
+            indexComponentData = addValueToMiddleTable(indexedValue.getIndex(), middleEntityXml,
                     queryGeneratorBuilder, "mapkey", null);
             // TODO: @MapKey support, @MapKeyManyToMany
         } else {
@@ -280,58 +243,27 @@
         // ******
         // Generating the property mapper.
         // ******
-
         // Building the query generator.
         MiddleTableQueryGenerator queryGenerator = queryGeneratorBuilder.build(elementComponentData, indexComponentData);
 
         // Creating common data
         CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
-                mainGenerator.getVerEntCfg(), versionsMiddleEntityName, name, referencingIdData, queryGenerator);
+                mainGenerator.getVerEntCfg(), versionsMiddleEntityName, propertyName, referencingIdData, queryGenerator);
 
         // Checking the type of the collection and adding an appropriate mapper.
-        Type type = value.getType();
-        if (type instanceof SortedSetType) {
-            currentMapper.addComposite(name, new BasicCollectionMapper<Set>(commonCollectionMapperData,
-                    TreeSet.class, SortedSetProxy.class, elementComponentData));
-        } else if (type instanceof SetType) {
-            currentMapper.addComposite(name, new BasicCollectionMapper<Set>(commonCollectionMapperData,
-                    HashSet.class, SetProxy.class, elementComponentData));
-        } else if (type instanceof SortedMapType) {
-            // Indexed collection, so <code>indexComponentData</code> is not null.
-            currentMapper.addComposite(name, new MapCollectionMapper<Map>(commonCollectionMapperData,
-                    TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData));
-        } else if (type instanceof MapType) {
-            // Indexed collection, so <code>indexComponentData</code> is not null.
-            currentMapper.addComposite(name, new MapCollectionMapper<Map>(commonCollectionMapperData,
-                    HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
-        } else if (type instanceof BagType) {
-            currentMapper.addComposite(name, new BasicCollectionMapper<List>(commonCollectionMapperData,
-                    ArrayList.class, ListProxy.class, elementComponentData));
-        } else {
-            throw new RuntimeException();
-        }
+        addMapper(commonCollectionMapperData, elementComponentData, indexComponentData);
 
         // ******
         // Storing information about this relation.
         // ******
-
-        // Only if this is a relation (when there is a referenced entity).
-        if (referencedEntityName != null) {
-            if (value.isInverse()) {
-                mainGenerator.getEntitiesConfigurations().get(entityName).addToManyMiddleNotOwningRelation(name, mappedBy,
-                        referencedEntityName);
-            } else {
-                mainGenerator.getEntitiesConfigurations().get(entityName).addToManyMiddleRelation(name,
-                        referencedEntityName);
-            }
-        }
+        storeMiddleEntityRelationInformation(mappedBy);
     }
 
     /**
      *
      * @param value Value, which should be mapped to the middle-table, either as a relation to another entity,
      * or as a simple value.
-     * @param middleEntityXml If not <code>null</code>, xml mapping for this value is added to this element.
+     * @param xmlMapping If not <code>null</code>, xml mapping for this value is added to this element.
      * @param queryGeneratorBuilder In case <code>value</code> is a relation to another entity, information about it
      * should be added to the given.
      * @param prefix Prefix for proeprty names of related entities identifiers.
@@ -339,7 +271,7 @@
      * @return Data for mapping this component.
      */
     @SuppressWarnings({"unchecked"})
-    private MiddleComponentData addValueToMiddleTable(Value value, Element middleEntityXml,
+    private MiddleComponentData addValueToMiddleTable(Value value, Element xmlMapping,
                                                       QueryGeneratorBuilder queryGeneratorBuilder,
                                                       String prefix, JoinColumn[] joinColumns) {
         Type type = value.getType();
@@ -351,9 +283,9 @@
                     referencedEntityName).getIdMappingData();
 
             // 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>middleEntityXml</code> is not null).
-            if (middleEntityXml != null) {
-                addRelatedToXmlMapping(middleEntityXml, prefixRelated,
+            // relation isn't inverse (so when <code>xmlMapping</code> is not null).
+            if (xmlMapping != null) {
+                addRelatedToXmlMapping(xmlMapping, prefixRelated,
                         joinColumns != null && joinColumns.length > 0
                                 ? MetadataTools.getColumnNameIterator(joinColumns)
                                 : MetadataTools.getColumnNameIterator(value.getColumnIterator()),
@@ -374,7 +306,7 @@
                     queryGeneratorBuilder.getCurrentIndex());
         } else if (type instanceof ImmutableType || type instanceof MutableType) {
             // TODO: add support for enums, components, custom types
-            mainGenerator.getBasicMetadataGenerator().addSimpleValue(middleEntityXml, prefix, value, null, ModificationStore.FULL, true);
+            mainGenerator.getBasicMetadataGenerator().addSimpleValue(xmlMapping, prefix, value, null, ModificationStore.FULL, true);
 
             // Simple values are always stored in the first entity read by the query generator.
             return new MiddleComponentData(new MiddleSimpleComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0);
@@ -383,4 +315,107 @@
             throw new RuntimeException();
         }
     }
+
+    private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData,
+                           MiddleComponentData indexComponentData) {
+        Type type = propertyValue.getType();
+        if (type instanceof SortedSetType) {
+            currentMapper.addComposite(propertyName, new BasicCollectionMapper<Set>(commonCollectionMapperData,
+                    TreeSet.class, SortedSetProxy.class, elementComponentData));
+        } else if (type instanceof SetType) {
+            currentMapper.addComposite(propertyName, new BasicCollectionMapper<Set>(commonCollectionMapperData,
+                    HashSet.class, SetProxy.class, elementComponentData));
+        } else if (type instanceof SortedMapType) {
+            // Indexed collection, so <code>indexComponentData</code> is not null.
+            currentMapper.addComposite(propertyName, new MapCollectionMapper<Map>(commonCollectionMapperData,
+                    TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData));
+        } else if (type instanceof MapType) {
+            // Indexed collection, so <code>indexComponentData</code> is not null.
+            currentMapper.addComposite(propertyName, new MapCollectionMapper<Map>(commonCollectionMapperData,
+                    HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
+        } else if (type instanceof BagType) {
+            currentMapper.addComposite(propertyName, new BasicCollectionMapper<List>(commonCollectionMapperData,
+                    ArrayList.class, ListProxy.class, elementComponentData));
+        } else {
+            mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
+        }
+    }
+
+    private void storeMiddleEntityRelationInformation(String mappedBy) {
+        // 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.addToManyMiddleRelation(propertyName, referencedEntityName);
+            }
+        }
+    }
+
+    private Element createMiddleEntityXml(String versionsMiddleTableName, String versionsMiddleEntityName) {
+        String schema = StringTools.isEmpty(joinTable.schema()) ? propertyValue.getCollectionTable().getSchema() : joinTable.schema();
+        String catalog = StringTools.isEmpty(joinTable.catalog()) ? propertyValue.getCollectionTable().getCatalog() : joinTable.catalog();
+
+        Element middleEntityXml = MetadataTools.createEntity(xmlMappingData.newAdditionalMapping(),
+                versionsMiddleEntityName, versionsMiddleTableName, schema, catalog, null);
+        Element middleEntityXmlId = middleEntityXml.addElement("composite-id");
+
+        middleEntityXmlId.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName());
+
+        // Adding the revision number as a foreign key to the revision info entity to the composite id of the
+        // middle table.
+        mainGenerator.addRevisionInfoRelation(middleEntityXmlId);
+
+        // Adding the revision type property to the entity xml.
+        mainGenerator.addRevisionType(middleEntityXml);
+
+        // All other properties should also be part of the primary key of the middle entity.
+        return middleEntityXmlId;
+    }
+
+    private VersionsJoinTable getDefaultVersionsJoinTable() {
+        return new VersionsJoinTable() {
+            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(); }
+        };
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private String getMappedBy(Collection collectionValue) {
+        Iterator<Property> assocClassProps =
+                ((OneToMany) collectionValue.getElement()).getAssociatedClass().getPropertyIterator();
+
+        while (assocClassProps.hasNext()) {
+            Property property = assocClassProps.next();
+
+            if (Tools.iteratorsContentEqual(property.getValue().getColumnIterator(),
+                    collectionValue.getKey().getColumnIterator())) {
+                return property.getName();
+            }
+        }
+
+        throw new MappingException("Unable to read the mapped by attribute for " + propertyName + " in "
+                + referencingEntityName + "!");
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private String getMappedBy(Table collectionTable, PersistentClass referencedClass) {
+        Iterator<Property> properties = referencedClass.getPropertyIterator();
+        while (properties.hasNext()) {
+            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
+                if (((Collection) property.getValue()).getCollectionTable() == collectionTable) {
+                    return property.getName();
+                }
+            }
+        }
+
+        throw new MappingException("Unable to read the mapped by attribute for " + propertyName + " in "
+                + referencingEntityName + "!");
+    }
 }

Modified: trunk/src/main/org/jboss/envers/configuration/metadata/VersionsMetadataGenerator.java
===================================================================
--- trunk/src/main/org/jboss/envers/configuration/metadata/VersionsMetadataGenerator.java	2008-09-22 11:26:24 UTC (rev 159)
+++ trunk/src/main/org/jboss/envers/configuration/metadata/VersionsMetadataGenerator.java	2008-09-22 15:33:44 UTC (rev 160)
@@ -55,7 +55,6 @@
 
     private final BasicMetadataGenerator basicMetadataGenerator;
     private final IdMetadataGenerator idMetadataGenerator;
-    private final CollectionMetadataGenerator collectionMetadataGenerator;
     private final ToOneRelationMetadataGenerator toOneRelationMetadataGenerator;
 
     private final Map<String, EntityConfiguration> entitiesConfigurations;
@@ -75,7 +74,6 @@
 
         this.basicMetadataGenerator = new BasicMetadataGenerator(this);
         this.idMetadataGenerator = new IdMetadataGenerator(this);
-        this.collectionMetadataGenerator = new CollectionMetadataGenerator(this);
         this.toOneRelationMetadataGenerator = new ToOneRelationMetadataGenerator(this);
 
         entitiesConfigurations = new HashMap<String, EntityConfiguration>();
@@ -166,17 +164,12 @@
         } else if (type instanceof CollectionType) {
             // only second pass
             if (!firstPass) {
-                collectionMetadataGenerator.addCollection(name, (Collection) value, currentMapper, entityName,
-                        xmlMappingData, joinTable);
+                CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
+                        name, (Collection) value, currentMapper, entityName, xmlMappingData, joinTable);
+                collectionMetadataGenerator.addCollection();
             }
         } else {
-            String message = "Type not supported for versioning: " + type.getClass().getName() +
-                    ", on entity " + entityName + ", property '" + name + "'.";
-            if (globalCfg.isWarnOnUnsupportedTypes()) {
-                log.warn(message);
-            } else {
-                throw new MappingException(message);
-            }
+            throwUnsupportedTypeException(type, entityName, name);
         }
     }
 
@@ -386,4 +379,14 @@
     VersionsEntitiesConfiguration getVerEntCfg() {
         return verEntCfg;
     }
+
+    void throwUnsupportedTypeException(Type type, String entityName, String propertyName) {
+        String message = "Type not supported for versioning: " + type.getClass().getName() +
+                ", on entity " + entityName + ", property '" + propertyName + "'.";
+        if (globalCfg.isWarnOnUnsupportedTypes()) {
+            log.warn(message);
+        } else {
+            throw new MappingException(message);
+        }
+    }
 }

Deleted: trunk/src/main/org/jboss/envers/entities/mapper/relation/AbstractOneToManyMapper.java
===================================================================
--- trunk/src/main/org/jboss/envers/entities/mapper/relation/AbstractOneToManyMapper.java	2008-09-22 11:26:24 UTC (rev 159)
+++ trunk/src/main/org/jboss/envers/entities/mapper/relation/AbstractOneToManyMapper.java	2008-09-22 15:33:44 UTC (rev 160)
@@ -1,84 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
- * by the @authors tag. All rights reserved.
- *
- * See the copyright.txt in the distribution for a  full listing of individual
- * contributors. This copyrighted material is made available to anyone wishing
- * to use,  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.
- *
- * Red Hat Author(s): Adam Warski
- */
-package org.jboss.envers.entities.mapper.relation;
-
-import org.jboss.envers.reader.VersionsReaderImplementor;
-import org.jboss.envers.tools.reflection.ReflectionTools;
-import org.jboss.envers.entities.mapper.relation.lazy.proxy.ListProxy;
-import org.jboss.envers.entities.mapper.relation.lazy.proxy.SetProxy;
-import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
-import org.jboss.envers.entities.mapper.relation.lazy.proxy.MapProxy;
-import org.jboss.envers.entities.mapper.PropertyMapper;
-import org.jboss.envers.exception.VersionsException;
-import org.jboss.envers.configuration.VersionsConfiguration;
-import org.hibernate.property.Getter;
-import org.hibernate.property.Setter;
-
-import java.util.*;
-
-/**
- * @author Adam Warski (adam at warski dot org)
- */
-public abstract class AbstractOneToManyMapper implements PropertyMapper {
-    private final String owningEntityName;
-    private final String propertyName;
-
-    protected AbstractOneToManyMapper(String owningEntityName, String propertyName) {
-        this.owningEntityName = owningEntityName;
-        this.propertyName = propertyName;
-    }
-
-    protected abstract <T> Initializor<T> getInitializator(VersionsConfiguration verCfg,
-                                                           VersionsReaderImplementor versionsReader,
-                                                           Class<?> entityClass, Object primaryKey,
-                                                           Number revision, Class<T> collectionClass);
-
-    @SuppressWarnings({"unchecked"})
-    public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey,
-                                   VersionsReaderImplementor versionsReader, Number revision) {
-        if (obj == null) {
-            return;
-        }
-
-        Class<?> entityClass = ReflectionTools.loadClass(owningEntityName);
-
-        Getter getter = ReflectionTools.getGetter(obj.getClass(), propertyName);
-        Class collectionClass = getter.getReturnType();
-
-        // todo: investigate generics
-        Object value;
-        if (List.class.isAssignableFrom(collectionClass)) {
-            value = new ListProxy(getInitializator(verCfg, versionsReader, entityClass, primaryKey, revision, ArrayList.class));
-        } else if (Set.class.isAssignableFrom(collectionClass) || Collection.class.isAssignableFrom(collectionClass)) {
-            value = new SetProxy(getInitializator(verCfg, versionsReader, entityClass, primaryKey, revision, HashSet.class));
-        } else if (Map.class.isAssignableFrom(collectionClass)) {
-            value = new MapProxy(getInitializator(verCfg, versionsReader, entityClass, primaryKey, revision, HashMap.class));
-        } else {
-            throw new VersionsException("Unsupported versioned collection type: " + collectionClass.getName());
-        }
-
-        Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyName);
-        setter.set(obj, value, null);
-    }
-}

Modified: trunk/src/main/org/jboss/envers/entities/mapper/relation/OneToManyAttachedMapper.java
===================================================================
--- trunk/src/main/org/jboss/envers/entities/mapper/relation/OneToManyAttachedMapper.java	2008-09-22 11:26:24 UTC (rev 159)
+++ trunk/src/main/org/jboss/envers/entities/mapper/relation/OneToManyAttachedMapper.java	2008-09-22 15:33:44 UTC (rev 160)
@@ -25,9 +25,16 @@
 import org.jboss.envers.entities.mapper.PersistentCollectionChangeData;
 import org.jboss.envers.reader.VersionsReaderImplementor;
 import org.jboss.envers.entities.mapper.relation.lazy.OneToManyAttachedInitializor;
+import org.jboss.envers.entities.mapper.relation.lazy.proxy.ListProxy;
+import org.jboss.envers.entities.mapper.relation.lazy.proxy.SetProxy;
+import org.jboss.envers.entities.mapper.relation.lazy.proxy.MapProxy;
 import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
 import org.jboss.envers.configuration.VersionsConfiguration;
+import org.jboss.envers.tools.reflection.ReflectionTools;
+import org.jboss.envers.exception.VersionsException;
 import org.hibernate.collection.PersistentCollection;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
 
 import java.util.*;
 import java.io.Serializable;
@@ -35,24 +42,54 @@
 /**
  * @author Adam Warski (adam at warski dot org)
  */
-public class OneToManyAttachedMapper extends AbstractOneToManyMapper implements PropertyMapper {
+public class OneToManyAttachedMapper implements PropertyMapper {
+    private final String owningEntityName;
+    private final String propertyName;
     private final String owningReferencePropertyName;
 
-    public OneToManyAttachedMapper(String owningReferencePropertyName, String owningEntityName, String propertyName) {
-        super(owningEntityName, propertyName);
-
+    public OneToManyAttachedMapper(String owningEntityName, String propertyName, String owningReferencePropertyName) {
+        this.owningEntityName = owningEntityName;
+        this.propertyName = propertyName;
         this.owningReferencePropertyName = owningReferencePropertyName;
     }
 
+    @SuppressWarnings({"unchecked"})
+    public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey,
+                                   VersionsReaderImplementor versionsReader, Number revision) {
+        if (obj == null) {
+            return;
+        }
+
+        Class<?> entityClass = ReflectionTools.loadClass(owningEntityName);
+
+        Getter getter = ReflectionTools.getGetter(obj.getClass(), propertyName);
+        Class collectionClass = getter.getReturnType();
+
+        // todo: investigate generics
+        // todo: add support for @MapKey, sorted collections
+        Object value;
+        if (List.class.isAssignableFrom(collectionClass)) {
+            value = new ListProxy(getInitializator(versionsReader, entityClass, primaryKey, revision, ArrayList.class));
+        } else if (Set.class.isAssignableFrom(collectionClass) || Collection.class.isAssignableFrom(collectionClass)) {
+            value = new SetProxy(getInitializator(versionsReader, entityClass, primaryKey, revision, HashSet.class));
+        } else if (Map.class.isAssignableFrom(collectionClass)) {
+            value = new MapProxy(getInitializator(versionsReader, entityClass, primaryKey, revision, HashMap.class));
+        } else {
+            throw new VersionsException("Unsupported versioned collection type: " + collectionClass.getName());
+        }
+
+        Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyName);
+        setter.set(obj, value, null);
+    }
+
     public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
         return false;
     }
 
-    protected <T> Initializor<T> getInitializator(VersionsConfiguration verCfg,
-                                                                     VersionsReaderImplementor versionsReader,
-                                                                     Class<?> entityClass, Object primaryKey,
-                                                                     Number revision,
-                                                                     Class<T> collectionClass) {
+    protected <T> Initializor<T> getInitializator(VersionsReaderImplementor versionsReader,
+                                                  Class<?> entityClass, Object primaryKey,
+                                                  Number revision,
+                                                  Class<T> collectionClass) {
         return new OneToManyAttachedInitializor<T>(versionsReader, entityClass, owningReferencePropertyName, primaryKey,
                 revision, collectionClass);
     }




More information about the jboss-envers-commits mailing list