/* * Copyright 2004-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.compass.core.mapping.osem; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.compass.core.mapping.Mapping; import org.compass.core.mapping.ResourcePropertyMapping; import org.compass.core.util.Assert; /** * @author kimchy */ public abstract class OsemMappingIterator { public static interface ClassMappingCallback { boolean onBeginClassMapping(ClassMapping classMapping); void onEndClassMapping(ClassMapping classMapping); boolean onBeginMultipleMapping(ClassMapping classMapping, Mapping mapping); void onEndMultiplMapping(ClassMapping classMapping, Mapping mapping); void onBeginCollectionMapping(AbstractCollectionMapping collectionMapping); void onEndCollectionMapping(AbstractCollectionMapping collectionMapping); void onClassPropertyMapping(ClassMapping classMapping, ClassPropertyMapping classPropertyMapping); void onClassDynamicPropertyMapping(ClassMapping classMapping, ClassDynamicPropertyMapping dynamicPropertyMapping); void onComponentMapping(ClassMapping classMapping, ComponentMapping componentMapping); void onReferenceMapping(ClassMapping classMapping, ReferenceMapping referenceMapping); void onCascadeMapping(ClassMapping classMapping, PlainCascadeMapping cascadeMapping); void onParentMapping(ClassMapping classMapping, ParentMapping parentMapping); void onConstantMetaDataMappaing(ClassMapping classMapping, ConstantMetaDataMapping constantMetaDataMapping); void onClassPropertyMetaDataMapping(ClassPropertyMetaDataMapping classPropertyMetaDataMapping); void onDynamicMetaDataMapping(ClassMapping classMapping, DynamicMetaDataMapping dynamicMetaDataMapping); void onResourcePropertyMapping(ResourcePropertyMapping resourcePropertyMapping); } /** * <p>Gathers both {@link org.compass.core.mapping.osem.ClassPropertyMapping}s * and {@link org.compass.core.mapping.ResourcePropertyMapping}s. * * <p>Also performs duplicate detection for referenced aliases. Duplicate mappings might occur * when the referenced alias is referencing several mappings (in case of the referenced class * actually contructing an object tree). Mappings that exist in the base class will be travesrsed * twice without the duplicate detection. The {@link #onBeginMultipleMapping(ClassMapping,org.compass.core.mapping.Mapping)} * detects such mappings, processes only the first one, and returns <code>false</code> for the rest * (denoting not to continue the investigation of this referenced mapping). */ public static class ClassPropertyAndResourcePropertyGatherer implements ClassMappingCallback { private ArrayList<ClassPropertyMapping> classPropertyMappings = new ArrayList<ClassPropertyMapping>(); private ArrayList<ResourcePropertyMapping> resourcePropertyMappings = new ArrayList<ResourcePropertyMapping>(); private HashMap<Integer, HashMap<Object, HashMap<Object, ObjectMapping>>> ignoreInheritedDuplicatesClassMappings = new HashMap<Integer, HashMap<Object, HashMap<Object, ObjectMapping>>>(); public ClassPropertyAndResourcePropertyGatherer() { } public List<ClassPropertyMapping> getClassPropertyMappings() { return classPropertyMappings; } public List<ResourcePropertyMapping> getResourcePropertyMappings() { return resourcePropertyMappings; } public boolean onBeginClassMapping(ClassMapping classMapping) { return true; } public void onEndClassMapping(ClassMapping classMapping) { } public boolean onBeginMultipleMapping(ClassMapping classMapping, Mapping mapping) { // if it is ref alias mapping, mark its multiple ref class mappings as ones // to be considered for ignoring inherited duplicates if (mapping instanceof RefAliasObjectMapping) { ClassMapping[] classMappings = ((RefAliasObjectMapping) mapping).getRefClassMappings(); if (classMappings.length > 1) { HashMap<Object, HashMap<Object, ObjectMapping>> byAlias = new HashMap<Object, HashMap<Object, ObjectMapping>>(); for (ClassMapping classMapping1 : classMappings) { ignoreInheritedDuplicatesClassMappings.put(System.identityHashCode(classMapping1), byAlias); } } } // check if the class mapping is in the inherited duplicates checking // if so, only traverse the first one, and the rest of the duplicates // just ignore by returning false for drilling down HashMap<Object, HashMap<Object, ObjectMapping>> byAlias = ignoreInheritedDuplicatesClassMappings.get(new Integer(System.identityHashCode(classMapping))); if (byAlias != null && (mapping instanceof ObjectMapping)) { ObjectMapping objectMapping = (ObjectMapping) mapping; Assert.notNull(objectMapping.getDefinedInAlias(), "Internal Compass Error, Defined in Alias not found for [" + objectMapping.getPropertyName() + "] in alias [" + classMapping.getAlias() + "]"); HashMap<Object, ObjectMapping> propByAlias = byAlias.get(objectMapping.getDefinedInAlias()); if (propByAlias == null) { propByAlias = new HashMap<Object, ObjectMapping>(); byAlias.put(objectMapping.getDefinedInAlias(), propByAlias); } ObjectMapping actualObjectMapping = propByAlias.get(objectMapping.getPropertyName()); if (actualObjectMapping != null) { onDuplicateMapping(classMapping, actualObjectMapping, objectMapping); return false; } propByAlias.put(objectMapping.getPropertyName(), objectMapping); } return true; } protected void onDuplicateMapping(ClassMapping classMapping, ObjectMapping actualMapping, ObjectMapping duplicateMapping) { } public void onEndMultiplMapping(ClassMapping classMapping, Mapping mapping) { } public void onBeginCollectionMapping(AbstractCollectionMapping collectionMapping) { } public void onEndCollectionMapping(AbstractCollectionMapping collectionMapping) { } public void onClassPropertyMapping(ClassMapping classMapping, ClassPropertyMapping classPropertyMapping) { classPropertyMappings.add(classPropertyMapping); } public void onParentMapping(ClassMapping classMapping, ParentMapping parentMapping) { } public void onCascadeMapping(ClassMapping classMapping, PlainCascadeMapping cascadeMapping) { } public void onComponentMapping(ClassMapping classMapping, ComponentMapping componentMapping) { } public void onReferenceMapping(ClassMapping classMapping, ReferenceMapping referenceMapping) { } public void onConstantMetaDataMappaing(ClassMapping classMapping, ConstantMetaDataMapping constantMetaDataMapping) { } public void onClassPropertyMetaDataMapping(ClassPropertyMetaDataMapping classPropertyMetaDataMapping) { } public void onDynamicMetaDataMapping(ClassMapping classMapping, DynamicMetaDataMapping dynamicMetaDataMapping) { } public void onClassDynamicPropertyMapping(ClassMapping classMapping, ClassDynamicPropertyMapping dynamicPropertyMapping) { } public void onResourcePropertyMapping(ResourcePropertyMapping resourcePropertyMapping) { resourcePropertyMappings.add(resourcePropertyMapping); } } public static void iterateMappings(ClassMappingCallback callback, ClassMapping classMapping) { iterateMappings(callback, classMapping, true); } public static void iterateMappings(ClassMappingCallback callback, ClassMapping classMapping, boolean recursive) { if (!callback.onBeginClassMapping(classMapping)) { return; } for (Iterator mappingsIt = classMapping.mappingsIt(); mappingsIt.hasNext();) { Mapping m = (Mapping) mappingsIt.next(); if (m instanceof ClassPropertyMapping) { ClassPropertyMapping classPropertyMapping = (ClassPropertyMapping) m; iteratePropertyMapping(callback, classMapping, classPropertyMapping); } else if (m instanceof ClassDynamicPropertyMapping) { ClassDynamicPropertyMapping dynamicPropertyMapping = (ClassDynamicPropertyMapping) m; callback.onClassDynamicPropertyMapping(classMapping, dynamicPropertyMapping); } else if (m instanceof ParentMapping) { callback.onParentMapping(classMapping, (ParentMapping) m); } else if (m instanceof PlainCascadeMapping) { callback.onCascadeMapping(classMapping, (PlainCascadeMapping) m); } else if (m instanceof DynamicMetaDataMapping) { DynamicMetaDataMapping dynamicMetaDataMapping = (DynamicMetaDataMapping) m; callback.onDynamicMetaDataMapping(classMapping, dynamicMetaDataMapping); callback.onResourcePropertyMapping(dynamicMetaDataMapping); } else if (m instanceof ComponentMapping) { ComponentMapping componentMapping = (ComponentMapping) m; iterateComponentMapping(callback, classMapping, componentMapping, recursive); } else if (m instanceof ReferenceMapping) { ReferenceMapping referenceMapping = (ReferenceMapping) m; iterateReferenceMapping(callback, classMapping, referenceMapping, recursive); } else if (m instanceof ConstantMetaDataMapping) { ConstantMetaDataMapping constantMetaDataMapping = (ConstantMetaDataMapping) m; boolean drillDown = callback.onBeginMultipleMapping(classMapping, constantMetaDataMapping); if (drillDown) { callback.onConstantMetaDataMappaing(classMapping, constantMetaDataMapping); callback.onResourcePropertyMapping(constantMetaDataMapping); } callback.onEndMultiplMapping(classMapping, constantMetaDataMapping); } else if (m instanceof AbstractCollectionMapping) { // collection, add the internal element attributes AbstractCollectionMapping colMapping = (AbstractCollectionMapping) m; callback.onBeginCollectionMapping(colMapping); Mapping elementMapping = colMapping.getElementMapping(); if (elementMapping instanceof ClassPropertyMapping) { ClassPropertyMapping classPropertyMapping = (ClassPropertyMapping) elementMapping; iteratePropertyMapping(callback, classMapping, classPropertyMapping); } else if (elementMapping instanceof ClassDynamicPropertyMapping) { ClassDynamicPropertyMapping dynamicPropertyMapping = (ClassDynamicPropertyMapping) elementMapping; callback.onClassDynamicPropertyMapping(classMapping, dynamicPropertyMapping); } else if (elementMapping instanceof ComponentMapping) { ComponentMapping componentMapping = (ComponentMapping) elementMapping; iterateComponentMapping(callback, classMapping, componentMapping, recursive); } else if (elementMapping instanceof ReferenceMapping) { ReferenceMapping referenceMapping = (ReferenceMapping) elementMapping; iterateReferenceMapping(callback, classMapping, referenceMapping, recursive); } else if (elementMapping instanceof PlainCascadeMapping) { callback.onCascadeMapping(classMapping, (PlainCascadeMapping) elementMapping); } callback.onEndCollectionMapping(colMapping); } } callback.onEndClassMapping(classMapping); } private static void iterateReferenceMapping(ClassMappingCallback callback, ClassMapping classMapping, ReferenceMapping referenceMapping, boolean recursive) { boolean drillDown = callback.onBeginMultipleMapping(classMapping, referenceMapping); if (drillDown) { callback.onReferenceMapping(classMapping, referenceMapping); if (recursive) { ClassMapping[] refMappings = referenceMapping.getRefClassMappings(); for (ClassMapping refMapping : refMappings) { iterateMappings(callback, refMapping); } if (referenceMapping.getRefCompMapping() != null) { iterateMappings(callback, referenceMapping.getRefCompMapping()); } } } callback.onEndMultiplMapping(classMapping, referenceMapping); } private static void iterateComponentMapping(ClassMappingCallback callback, ClassMapping classMapping, ComponentMapping componentMapping, boolean recursive) { boolean drillDown = callback.onBeginMultipleMapping(classMapping, componentMapping); if (drillDown) { callback.onComponentMapping(classMapping, componentMapping); if (recursive) { ClassMapping[] refMappings = componentMapping.getRefClassMappings(); for (ClassMapping refMapping : refMappings) { iterateMappings(callback, refMapping); } } } callback.onEndMultiplMapping(classMapping, componentMapping); } private static void iteratePropertyMapping(ClassMappingCallback callback, ClassMapping classMapping, ClassPropertyMapping classPropertyMapping) { boolean drillDown = callback.onBeginMultipleMapping(classMapping, classPropertyMapping); if (drillDown) { callback.onClassPropertyMapping(classMapping, classPropertyMapping); for (Iterator resIt = classPropertyMapping.mappingsIt(); resIt.hasNext();) { ClassPropertyMetaDataMapping classPropertyMetaDataMapping = (ClassPropertyMetaDataMapping) resIt.next(); callback.onClassPropertyMetaDataMapping(classPropertyMetaDataMapping); callback.onResourcePropertyMapping(classPropertyMetaDataMapping); } } callback.onEndMultiplMapping(classMapping, classPropertyMapping); } }