/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWQueryKey; import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWColumn; import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWTable; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.InterfaceDescriptorCreationException; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWClassIndicatorFieldPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWClassIndicatorValue; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptorInheritancePolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWInheritancePolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWMappingDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMappingFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWReferenceMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWAggregateMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWDirectToXmlTypeMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWManyToManyMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWOneToManyMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWOneToOneMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWRelationalMappingFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWVariableOneToOneMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassAttribute; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassRefreshPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWMethod; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.relational.MWRelationalProject; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.MWQueryable; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassNotFoundException; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.filters.Filter; import org.eclipse.persistence.tools.workbench.utility.iterators.CloneIterator; import org.eclipse.persistence.tools.workbench.utility.iterators.CompositeIterator; import org.eclipse.persistence.tools.workbench.utility.iterators.NullIterator; import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.tools.workbench.utility.string.AffixStrippingPartialStringComparatorEngine; import org.eclipse.persistence.tools.workbench.utility.string.CollectionStringHolder; import org.eclipse.persistence.tools.workbench.utility.string.ExhaustivePartialStringComparatorEngine; import org.eclipse.persistence.tools.workbench.utility.string.PartialStringComparator; import org.eclipse.persistence.tools.workbench.utility.string.PartialStringComparatorEngine; import org.eclipse.persistence.tools.workbench.utility.string.PartialStringMatcher; import org.eclipse.persistence.tools.workbench.utility.string.SimplePartialStringMatcher; import org.eclipse.persistence.tools.workbench.utility.string.PartialStringMatcher.StringHolderScore; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping; public abstract class MWRelationalClassDescriptor extends MWMappingDescriptor implements MWRelationalDescriptor { // These are only the non-autogenerated query keys. The autogenerated query keys are always recalculated. private Collection userDefinedQueryKeys; public static final String QUERY_KEYS_COLLECTION = "userDefinedQueryKeys"; protected static final PartialStringMatcher PARTIAL_STRING_MATCHER = new SimplePartialStringMatcher(PartialStringComparator.DEFAULT_COMPARATOR); protected static final float PARTIAL_STRING_AFFIX_THRESHOLD = 0.80f; // ??? protected static final PartialStringComparatorEngine PARTIAL_STRING_COMPARATOR_ENGINE = AffixStrippingPartialStringComparatorEngine.forPrefixStripping( AffixStrippingPartialStringComparatorEngine.forSuffixStripping( new ExhaustivePartialStringComparatorEngine(PartialStringComparator.DEFAULT_COMPARATOR), PARTIAL_STRING_AFFIX_THRESHOLD ), PARTIAL_STRING_AFFIX_THRESHOLD ); public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWRelationalClassDescriptor.class); descriptor.getInheritancePolicy().setParentClass(MWMappingDescriptor.class); XMLCompositeCollectionMapping userDefinedQueryKeysMapping = new XMLCompositeCollectionMapping(); userDefinedQueryKeysMapping.setAttributeName("userDefinedQueryKeys"); userDefinedQueryKeysMapping.setGetMethodName("getUserDefinedQueryKeysForTopLink"); userDefinedQueryKeysMapping.setSetMethodName("setUserDefinedQueryKeysForTopLink"); userDefinedQueryKeysMapping.setReferenceClass(MWUserDefinedQueryKey.class); userDefinedQueryKeysMapping.setXPath("user-defined-query-keys/user-defined-query-key"); descriptor.addMapping(userDefinedQueryKeysMapping); return descriptor; } /** Default constructor - for TopLink use only */ protected MWRelationalClassDescriptor() { super(); } protected MWRelationalClassDescriptor(MWRelationalProject parent, MWClass type, String name) { super(parent, type, name); } // ********** Initialization ********** /** * initialize persistent state */ protected void initialize(Node parent) { super.initialize(parent); this.userDefinedQueryKeys = new Vector(); } protected void addChildrenTo(List children) { super.addChildrenTo(children); synchronized (this.userDefinedQueryKeys) { children.addAll(this.userDefinedQueryKeys); } } // ********** MWRelationalDescriptor implementation ********** public boolean isTableDescriptor() { return false; } public boolean isAggregateDescriptor() { return false; } public boolean isInterfaceDescriptor() { return false; } public Iterator implementors() { return NullIterator.instance(); } /** * Returns an Iterator of all columns in the primary table and associated tables. */ public Iterator allAssociatedColumns() { return new CompositeIterator( new TransformationIterator(associatedTables()) { protected Object transform(Object next) { return ((MWTable) next).columns(); } } ); } public int allAssociatedColumnsSize() { int numColumns = 0; for (Iterator i = associatedTables(); i.hasNext(); ) { numColumns += ((MWTable) i.next()).columnsSize(); } return numColumns; } /** * Return all tables associated with this descriptor and all descriptors * in its inheritance hierarchy */ public Iterator associatedTablesIncludingInherited() { return new CompositeIterator( new TransformationIterator(this.inheritanceHierarchy()) { protected Object transform(Object next) { return ((MWRelationalDescriptor) next).associatedTables(); } } ); } public int associatedTablesIncludingInheritedSize() { return CollectionTools.size(this.associatedTablesIncludingInherited()); } public Iterator candidateTables() { if (this.associatedTablesSize() == 0) { return this.getDatabase().tables(); } return this.associatedTables(); } public int candidateTablesSize() { return CollectionTools.size(this.candidateTables()); } public Iterator candidateTablesIncludingInherited() { if (this.associatedTablesIncludingInheritedSize() == 0) { return this.getDatabase().tables(); } return this.associatedTablesIncludingInherited(); } public int candidateTablesIncludingInheritedSize() { return CollectionTools.size(this.candidateTablesIncludingInherited()); } //************** Morphing ************** public MWAggregateDescriptor asMWAggregateDescriptor() { MWAggregateDescriptor newDescriptor = ((MWRelationalProject) this.getProject()).addAggregateDescriptorForType(this.getMWClass()); this.initializeDescriptorAfterMorphing(newDescriptor); return newDescriptor; } public MWTableDescriptor asMWTableDescriptor() throws InterfaceDescriptorCreationException{ MWTableDescriptor newDescriptor; try { newDescriptor = (MWTableDescriptor) this.getProject().addDescriptorForType(this.getMWClass()); } catch (InterfaceDescriptorCreationException e) { throw new RuntimeException(e); } this.initializeDescriptorAfterMorphing(newDescriptor); return newDescriptor; } /** * This really should only happen as the result of a class refresh */ public MWInterfaceDescriptor asMWInterfaceDescriptor() throws InterfaceDescriptorCreationException { MWInterfaceDescriptor newDescriptor = (MWInterfaceDescriptor) this.getProject().addDescriptorForType(getMWClass()); this.initializeDescriptorAfterMorphing(newDescriptor); return newDescriptor; } public void initializeFromMWAggregateDescriptor(MWAggregateDescriptor oldDescriptor) { // super.initializeFromMWAggregateDescriptor(oldDescriptor); this.initializeFromMWRelationalClassDescriptor(oldDescriptor); } public void initializeFromMWRelationalClassDescriptor(MWRelationalClassDescriptor oldDescriptor) { // super.initializeFromMWRelationalClassDescriptor(oldDescriptor); this.initializeFromMWMappingDescriptor(oldDescriptor); for (Iterator i = oldDescriptor.userDefinedQueryKeys(); i.hasNext(); ){ addQueryKey((MWUserDefinedQueryKey) i.next()); } } public void initializeFromMWTableDescriptor(MWTableDescriptor oldDescriptor) { // super.initializeFromMWTableDescriptor(oldDescriptor); this.initializeFromMWRelationalClassDescriptor(oldDescriptor); } public void initializeFromMWInterfaceDescriptor(MWInterfaceDescriptor oldDescriptor) { // super.initializeFromMWInterfaceDescriptor(oldDescriptor); this.initializeFromMWDescriptor(oldDescriptor); } protected void refreshClass(MWClassRefreshPolicy refreshPolicy) throws ExternalClassNotFoundException, InterfaceDescriptorCreationException { super.refreshClass(refreshPolicy); if (this.getMWClass().isInterface()) { this.asMWInterfaceDescriptor(); } } //************** Mapping Creation ************** public MWMappingFactory mappingFactory() { return MWRelationalMappingFactory.instance(); } public MWManyToManyMapping addManyToManyMapping(MWClassAttribute attribute) { MWManyToManyMapping mapping = ((MWRelationalMappingFactory) mappingFactory()).createManyToManyMapping(this, attribute, attribute.getName()); this.addMapping(mapping); return mapping; } public MWOneToManyMapping addOneToManyMapping(MWClassAttribute attribute) { MWOneToManyMapping mapping = ((MWRelationalMappingFactory) mappingFactory()).createOneToManyMapping(this, attribute, attribute.getName()); this.addMapping(mapping); return mapping; } public MWOneToOneMapping addOneToOneMapping(MWClassAttribute attribute) { MWOneToOneMapping mapping = ((MWRelationalMappingFactory) mappingFactory()).createOneToOneMapping(this, attribute, attribute.getName()); this.addMapping(mapping); return mapping; } public MWVariableOneToOneMapping addVariableOneToOneMapping(MWClassAttribute attribute) { MWVariableOneToOneMapping mapping = ((MWRelationalMappingFactory) mappingFactory()).createVariableOneToOneMapping(this, attribute, attribute.getName()); this.addMapping(mapping); return mapping; } public MWDirectToXmlTypeMapping addDirectToXmlTypeMapping(MWClassAttribute attribute) { MWDirectToXmlTypeMapping mapping = ((MWRelationalMappingFactory) mappingFactory()).createDirectToXmlTypeMapping(this, attribute, attribute.getName()); this.addMapping(mapping); return mapping; } public MWAggregateMapping addAggregateMapping(MWClassAttribute attribute) { MWAggregateMapping mapping = ((MWRelationalMappingFactory) mappingFactory()).createAggregateMapping(this, attribute, attribute.getName()); this.addMapping(mapping); return mapping; } // **************** Disorganized methods ********************************** public MWUserDefinedQueryKey addQueryKey(String name, MWColumn column) { checkQueryKeyName(name); MWUserDefinedQueryKey queryKey = new MWUserDefinedQueryKey(name, this, column); addQueryKey(queryKey); return queryKey; } /** * disallow duplicate user defined query key names in a descriptor */ void checkQueryKeyName(String queryKeyName) { if (queryKeyName == null || queryKeyName == "") { throw new NullPointerException(); } //TODO can there be 2 query keys with the same name? One an auto-generated and the other user defined? if (queryKeyNamed(queryKeyName) != null) { throw new IllegalArgumentException(queryKeyName); } } private void addQueryKey(MWUserDefinedQueryKey newQueryKey) { this.userDefinedQueryKeys.add(newQueryKey); this.fireItemAdded(QUERY_KEYS_COLLECTION, newQueryKey); this.getProject().recalculateAggregatePathsToColumn(this); } public void removeQueryKey(MWUserDefinedQueryKey queryKeyToRemove) { this.removeNodeFromCollection(queryKeyToRemove, this.userDefinedQueryKeys, QUERY_KEYS_COLLECTION); this.getProject().recalculateAggregatePathsToColumn(this); } public Iterator allQueryKeys() { return this.getAllQueryKeys().iterator(); } public Iterator allQueryKeysIncludingInherited() { return this.getAllQueryKeysIncludingInherited().iterator(); } public Iterator allQueryKeyNames() { return new TransformationIterator(allQueryKeys()) { protected Object transform(Object next) { return ((MWQueryKey) next).getName(); } }; } public Iterator userDefinedQueryKeys() { return new CloneIterator(this.userDefinedQueryKeys); } public SortedSet getAllQueryKeys() { SortedSet result = new TreeSet(); result.addAll(this.userDefinedQueryKeys); result.addAll(this.getAutoGeneratedQueryKeys()); return result; } public Collection getAutoGeneratedQueryKeys() { Collection queryKeys = new ArrayList(); Iterator i = mappings(); while(i.hasNext()){ MWMapping mapping = (MWMapping) i.next(); MWQueryKey bldrQueryKey = mapping.getAutoGeneratedQueryKey(); if(bldrQueryKey != null){ queryKeys.add(bldrQueryKey); } } return queryKeys; } public Collection getAutoGeneratedQueryKeysIncludingInherited() { Collection autoQueryKeys = super.getAutoGeneratedQueryKeysIncludingInherited(); if (getInheritancePolicy().isRoot()) { // i.e., this is the root descriptor, or there is no inheritance autoQueryKeys = getAutoGeneratedQueryKeys(); } else if(getInheritancePolicy().getParentDescriptor() != null){ //User might not have set a parent autoQueryKeys = getInheritancePolicy().getParentDescriptor().getAutoGeneratedQueryKeysIncludingInherited(); autoQueryKeys.addAll(getAutoGeneratedQueryKeys()); } return autoQueryKeys; } public Collection getAllQueryKeysIncludingInherited() { Collection allQueryKeys = super.getAllQueryKeysIncludingInherited(); allQueryKeys.addAll(getAllQueryKeys()); if(getInheritancePolicy().isActive() && getInheritancePolicy().getParentDescriptor() != null){ //I am checking this because the user might not have set a parent allQueryKeys.addAll(getInheritancePolicy().getParentDescriptor().getAllQueryKeysIncludingInherited()); } return allQueryKeys; } public MWQueryKey queryKeyNamed(String name) { for (Iterator stream = this.allQueryKeys(); stream.hasNext(); ) { MWQueryKey queryKey = (MWQueryKey) stream.next(); if (queryKey.getName().equals(name)) { return queryKey; } } return null; } public MWQueryKey queryKeyNamedIncludingInherited(String name) { for (Iterator stream = this.allQueryKeysIncludingInherited(); stream.hasNext(); ) { MWQueryKey queryKey = (MWQueryKey) stream.next(); if (queryKey.getName().equals(name)) { return queryKey; } } return null; } public MWTable getPrimaryTable() { return null; } public MWQueryable queryableNamed(String queryableName) { Iterator queryables = getQueryables(Filter.NULL_INSTANCE).iterator(); while (queryables.hasNext()) { MWQueryable queryable = (MWQueryable) queryables.next(); if (queryable.getName().equals(queryableName)) { return queryable; } } return null; } public List getQueryables(Filter queryableFilter) { List queryables = new ArrayList(); for (Iterator mappings = mappingsIncludingInherited(); mappings.hasNext();) { MWMapping mapping = (MWMapping) mappings.next(); if (queryableFilter.accept(mapping)) { queryables.add(mapping); } } for (Iterator i = userDefinedQueryKeys(); i.hasNext(); ) { MWUserDefinedQueryKey key = (MWUserDefinedQueryKey) i .next(); if (queryableFilter.accept(key)) { queryables.add(key); } } return queryables; } // ********** Behavior ********** protected MWDescriptorInheritancePolicy buildInheritancePolicy() { return new MWRelationalDescriptorInheritancePolicy(this); } public boolean supportsInterfaceAliasPolicy() { return false; } public boolean supportsMultitablePolicy() { return false; } /** * throw property change for the query key collection since the umapping changes the auto generated ones. */ public void unmap() { super.unmap(); fireCollectionChanged(QUERY_KEYS_COLLECTION); } // *************** Automap Support ************** /** * this is called by another descriptor when it discovers this descriptor * can be its parent and this descriptor is among the collection of * descriptors to be automapped, meaning that this descriptor can * be automapped also; * this method is called *before* the normal #automap() method */ protected void automapSuperDescriptorInheritance(Collection automapDescriptors) { this.automapInheritanceHierarchy(automapDescriptors); MWInheritancePolicy ip = this.getInheritancePolicy(); if ( ! ip.isActive()) { this.addInheritancePolicy(); ip = this.getInheritancePolicy(); } if (ip.getParentDescriptor() == null) { ((MWDescriptorInheritancePolicy) ip).setIsRoot(true); } if ((ip.getParentDescriptor() == null) && ! this.getMWClass().isAbstract()) { MWClassIndicatorFieldPolicy fieldPolicy = (MWClassIndicatorFieldPolicy) ip.getClassIndicatorPolicy(); MWClassIndicatorValue indicatorValue = fieldPolicy.getClassIndicatorValueForDescriptor(this); indicatorValue.setInclude(true); indicatorValue.setIndicatorValue(this.getName()); } } protected void automapInternal() { // automap the unmapped attributes *before* looping // through the mappings and automapping them this.automapUnmappedAttributes(); this.automapDirectMappingColumns(); super.automapInternal(); } private void automapUnmappedAttributes() { Set attributes = this.allAttributes(); CollectionTools.removeAll(attributes, this.mappedAttributes()); for (Iterator stream = attributes.iterator(); stream.hasNext(); ) { this.automapUnmappedAttribute((MWClassAttribute) stream.next()); } } private Set allAttributes() { Set attributes = CollectionTools.set(this.getMWClass().attributes()); CollectionTools.addAll(attributes, this.inheritedAttributes()); CollectionTools.addAll(attributes, this.getMWClass().ejb20Attributes()); return attributes; } private Iterator mappedAttributes() { return new TransformationIterator(this.mappings()) { protected Object transform(Object next) { return ((MWMapping) next).getInstanceVariable(); } }; } private void automapUnmappedAttribute(MWClassAttribute attribute) { if (attribute.getDimensionality() > 0) { // toplink doesn't support arrays return; } MWClass type = attribute.getType(); if (type.isValueHolder()) { type = attribute.getValueType(); if (type.isObject()) { // no 'valueType' is specified; use "get" method return type MWMethod getMethod = attribute.standardValueGetMethod(); if (getMethod != null) { type = getMethod.getReturnType(); } } } if (type.isContainer()) { MWDescriptor descriptor = this.findReferenceDescriptorForCollectionAttribute(attribute); if (descriptor == null) { this.automapAsDirectContainerMapping(attribute, type); } else { this.automapAsCollectionMapping(attribute, descriptor); } } else { MWDescriptor descriptor = this.findReferenceDescriptorForType(type); if (descriptor != null) { this.automapAsReferenceMapping(attribute, descriptor); } else { this.automapAsDirectMapping(attribute); } } } private MWDescriptor findReferenceDescriptorForCollectionAttribute(MWClassAttribute attribute) { CollectionStringHolder[] holders = this.buildMultiDescriptorStringHolders(); StringHolderScore shs = this.match(attribute.getName().toLowerCase(), holders); if (shs.getScore() < 0.80) { // ??? return null; } // look for a descriptor in the same package as this descriptor String packageName = this.packageName(); MWDescriptor descriptor = null; for (Iterator stream = ((CollectionStringHolder) shs.getStringHolder()).iterator(); stream.hasNext(); ) { descriptor = (MWDescriptor) stream.next(); if (descriptor.packageName().equals(packageName)) { return descriptor; } } // if none of the descriptors is in the same package, take the last one return descriptor; } /** * gather together all the descriptors that have the same "short" name * but different packages */ private CollectionStringHolder[] buildMultiDescriptorStringHolders() { Map holders = new HashMap(this.getProject().descriptorsSize()); for (Iterator stream = this.getProject().descriptors(); stream.hasNext(); ) { MWDescriptor descriptor = (MWDescriptor) stream.next(); String shortName = descriptor.shortName().toLowerCase(); CollectionStringHolder holder = (CollectionStringHolder) holders.get(shortName); if (holder == null) { holder = new CollectionStringHolder(shortName); holders.put(shortName, holder); } holder.add(descriptor); } return (CollectionStringHolder[]) holders.values().toArray(new CollectionStringHolder[holders.size()]); } private StringHolderScore match(String string, CollectionStringHolder[] multiDescriptorStringHolders) { return PARTIAL_STRING_MATCHER.match(string, multiDescriptorStringHolders); } private void automapAsDirectContainerMapping(MWClassAttribute attribute, MWClass type) { if (type.isAssignableToCollection()) { this.addDirectCollectionMapping(attribute); } else { this.addDirectMapMapping(attribute); } } private void automapAsCollectionMapping(MWClassAttribute attribute, MWDescriptor referenceDescriptor) { MWOneToManyMapping mapping = this.addOneToManyMapping(attribute); mapping.setReferenceDescriptor(referenceDescriptor); } private MWDescriptor findReferenceDescriptorForType(MWClass type) { MWDescriptor descriptor = this.getProject().descriptorForType(type); if (descriptor != null) { return descriptor; } if (type.isInterface()) { for (Iterator stream = this.getProject().descriptors(); stream.hasNext(); ) { descriptor = (MWDescriptor) stream.next(); if (descriptor.getMWClass().isAssignableTo(type)) { return descriptor; } } } return null; } private void automapAsReferenceMapping(MWClassAttribute attribute, MWDescriptor referenceDescriptor) { MWRelationalDescriptor relationalDescriptor = (MWRelationalDescriptor) referenceDescriptor; if (relationalDescriptor.isInterfaceDescriptor()) { MWClass referenceInterface = relationalDescriptor.getMWClass(); int numImplementors = 0; MWDescriptor implementorDescriptor = null; for (Iterator stream = this.getProject().descriptors(); stream.hasNext(); ) { MWDescriptor descriptor = (MWDescriptor) stream.next(); if ((descriptor != referenceDescriptor) && descriptor.getMWClass().allInterfacesContains(referenceInterface)) { implementorDescriptor = descriptor; numImplementors++; } } MWReferenceMapping mapping; if (numImplementors == 1) { mapping = this.addOneToOneMapping(attribute); mapping.setReferenceDescriptor(implementorDescriptor); } else { mapping = this.addVariableOneToOneMapping(attribute); mapping.setReferenceDescriptor(referenceDescriptor); } } else if (relationalDescriptor.isAggregateDescriptor()) { MWAggregateMapping mapping = this.addAggregateMapping(attribute); mapping.setReferenceDescriptor(referenceDescriptor); } else if (relationalDescriptor.isTableDescriptor()) { MWOneToOneMapping mapping = this.addOneToOneMapping(attribute); mapping.setReferenceDescriptor(referenceDescriptor); } } private void automapAsDirectMapping(MWClassAttribute attribute) { // we will assign the columns for our direct mappings when they're all in place this.addDirectMapping(attribute); } /** * match up any direct mapping that doesn't have a column * with an unmapped column */ protected void automapDirectMappingColumns() { // by default do nothing - aggregate descriptors // don't match direct mapping columns } // *************** aggregate mappings ************** public Collection buildAggregateFieldNameGenerators() { Collection generators = new ArrayList(); if (getInheritancePolicy().isRoot()) { getInheritancePolicy().getClassIndicatorPolicy().addToAggregateFieldNameGenerators(generators); } else if (getInheritancePolicy().getParentDescriptor() != null) {//TODO add test case for null parentDescriptor case generators.addAll(((MWRelationalDescriptor) getInheritancePolicy().getParentDescriptor()).buildAggregateFieldNameGenerators()); } for (Iterator i = userDefinedQueryKeys(); i.hasNext(); ) { MWUserDefinedQueryKey queryKey = (MWUserDefinedQueryKey) i.next(); generators.add(queryKey); } return generators; } //************** runtime conversion **************/ public ClassDescriptor buildRuntimeDescriptor() { ClassDescriptor runtimeDescriptor = super.buildRuntimeDescriptor(); adjustUserDefinedQueryKeys(runtimeDescriptor); return runtimeDescriptor; } protected abstract void adjustUserDefinedQueryKeys(ClassDescriptor runtimeDescriptor); // ********** TopLink methods ********** /** * sort the query keys for TopLink */ private Collection getUserDefinedQueryKeysForTopLink() { return CollectionTools.sort((List) this.userDefinedQueryKeys); } private void setUserDefinedQueryKeysForTopLink(Collection userDefinedQueryKeys) { this.userDefinedQueryKeys = userDefinedQueryKeys; } }