/******************************************************************************* * 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; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import java.util.Vector; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWDataField; import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational.MWInterfaceDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWAttributeHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle.NodeReferenceScrubber; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWDirectCollectionMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWDirectMapMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWDirectMapping; 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.MWTransformationMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.DefaultMWClassRefreshPolicy; 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.MWProject; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.MWQueryManager; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.HashBag; import org.eclipse.persistence.tools.workbench.utility.iterators.CloneIterator; import org.eclipse.persistence.tools.workbench.utility.iterators.CloneListIterator; import org.eclipse.persistence.tools.workbench.utility.iterators.FilteringIterator; 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.node.Problem; public abstract class MWMappingDescriptor extends MWDescriptor { private Collection mappings; public static final String MAPPINGS_COLLECTION = "mappings"; private Collection inheritedAttributeHandles; public static final String INHERITED_ATTRIBUTES_COLLECTION = "inheritedAttributes"; private NodeReferenceScrubber inheritedAttributeScrubber; private volatile MWInheritancePolicy inheritancePolicy; public static final String INHERITANCE_POLICY_PROPERTY = "inheritancePolicy"; private volatile MWDescriptorPolicy copyPolicy; public static final String COPY_POLICY_PROPERTY = "copyPolicy"; private volatile MWDescriptorPolicy eventsPolicy; public static final String EVENTS_POLICY_PROPERTY = "eventsPolicy"; private volatile MWDescriptorPolicy afterLoadingPolicy; public static final String AFTER_LOADING_POLICY_PROPERTY = "afterLoadingPolicy"; private volatile MWDescriptorPolicy instantiationPolicy; public static final String INSTANTIATION_POLICY_PROPERTY = "instantiationPolicy"; // ********** static methods ********** /** * Default constructor - for TopLink use only. */ protected MWMappingDescriptor() { super(); } protected MWMappingDescriptor(MWProject parent, MWClass type, String name) { super(parent, type, name); } // ********** Initialization ********** /** * initialize persistent state */ protected void initialize(Node parent) { super.initialize(parent); this.mappings = new Vector(); this.inheritedAttributeHandles = new Vector(); this.inheritancePolicy = new MWNullInheritancePolicy(this); this.copyPolicy = new MWNullDescriptorPolicy(this); this.eventsPolicy = new MWNullDescriptorPolicy(this); this.afterLoadingPolicy = new MWNullDescriptorPolicy(this); this.instantiationPolicy = new MWNullDescriptorPolicy(this); } protected void addChildrenTo(List children) { super.addChildrenTo(children); synchronized (this.mappings) { children.addAll(this.mappings); } synchronized (this.inheritedAttributeHandles) { children.addAll(this.inheritedAttributeHandles); } children.add(this.inheritancePolicy); children.add(this.copyPolicy); children.add(this.eventsPolicy); children.add(this.afterLoadingPolicy); children.add(this.instantiationPolicy); } private NodeReferenceScrubber inheritedAttributeScrubber() { if (this.inheritedAttributeScrubber == null) { this.inheritedAttributeScrubber = this.buildInheritedAttributeScrubber(); } return this.inheritedAttributeScrubber; } private NodeReferenceScrubber buildInheritedAttributeScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWMappingDescriptor.this.removeInheritedAttributeHandle((MWAttributeHandle) handle); } public String toString() { return "MWMappingDescriptor.buildInheritedAttributeScrubber()"; } }; } /** * Overridden from MWRDescriptor */ public MWClassRefreshPolicy buildMWClassRefreshPolicy() { return DefaultMWClassRefreshPolicy.instance(); } protected MWDescriptorPolicy buildLockingPolicy() { return new MWNullDescriptorPolicy(this); } public boolean isReferencedBy(Collection mappingDescriptors) { for (Iterator it = mappingDescriptors.iterator(); it.hasNext(); ) { for (Iterator it2 = ((MWMappingDescriptor) it.next()).mappings(); it2.hasNext(); ) { MWMapping mapping = (MWMapping) it2.next(); if (mapping.isReferenceMapping() && ((MWReferenceMapping) mapping).getReferenceDescriptor() == this) return true; } } return false; } public void addUnknownPrimaryKeyMapping(MWClassAttribute unknownPkAttribute) { this.addDirectMapping(unknownPkAttribute).setUsesMethodAccessing(false); } public MWQueryManager getQueryManager() { return getTransactionalPolicy().getQueryManager(); } public MWCachingPolicy getCachingPolicy() { return getTransactionalPolicy().getCachingPolicy(); } // ********** CopyPolicy API********** private void setCopyPolicy(MWDescriptorPolicy copyPolicy) { Object old = this.copyPolicy; this.copyPolicy = copyPolicy; firePropertyChanged(COPY_POLICY_PROPERTY, old, this.copyPolicy); } public MWDescriptorPolicy getCopyPolicy() { return this.copyPolicy; } public void addCopyPolicy() throws MWAdvancedPropertyAdditionException { if (this.copyPolicy.isActive()) { throw new MWAdvancedPropertyAdditionException(COPY_POLICY_PROPERTY, "policy already exists on descriptor"); } setCopyPolicy(new MWDescriptorCopyPolicy(this)); } public void removeCopyPolicy() throws MWAdvancedPropertyRemovalException { if (this.copyPolicy.isActive()) { this.copyPolicy.dispose(); setCopyPolicy(new MWNullDescriptorPolicy(this)); } else { throw new MWAdvancedPropertyRemovalException(COPY_POLICY_PROPERTY, "policy does not exist on descriptor"); } } // **************** LockingPolicy API ************************************* public MWLockingPolicy getLockingPolicy() { return getTransactionalPolicy().getLockingPolicy(); } // **************** EventsPolicy API ************************************** public MWDescriptorPolicy getEventsPolicy() { return this.eventsPolicy; } protected void setEventsPolicy(MWDescriptorPolicy eventsPolicy) { Object old = this.eventsPolicy; this.eventsPolicy = eventsPolicy; firePropertyChanged(EVENTS_POLICY_PROPERTY, old, this.eventsPolicy); } public void addEventsPolicy() throws MWAdvancedPropertyAdditionException { if (this.eventsPolicy.isActive()) { throw new MWAdvancedPropertyAdditionException(EVENTS_POLICY_PROPERTY, "policy already exists on descriptor"); } setEventsPolicy(new MWDescriptorEventsPolicy(this)); } public void removeEventsPolicy() throws MWAdvancedPropertyRemovalException { if (this.eventsPolicy.isActive()) { this.eventsPolicy.dispose(); setEventsPolicy(new MWNullDescriptorPolicy(this)); } else { throw new MWAdvancedPropertyRemovalException(EVENTS_POLICY_PROPERTY, "policy does not exist on descriptor"); } } // ********** AfterLoadingPolicy API********** private void setAfterLoadingPolicy(MWDescriptorPolicy afterLoadingPolicy) { Object old = this.afterLoadingPolicy; this.afterLoadingPolicy = afterLoadingPolicy; firePropertyChanged(AFTER_LOADING_POLICY_PROPERTY, old, this.afterLoadingPolicy); } public MWDescriptorPolicy getAfterLoadingPolicy() { return this.afterLoadingPolicy; } public void addAfterLoadingPolicy() throws MWAdvancedPropertyAdditionException { if (this.afterLoadingPolicy.isActive()) { throw new MWAdvancedPropertyAdditionException(AFTER_LOADING_POLICY_PROPERTY, "Policy already exists on descriptor"); } setAfterLoadingPolicy(new MWDescriptorAfterLoadingPolicy(this)); } public void removeAfterLoadingPolicy() throws MWAdvancedPropertyRemovalException { if (this.afterLoadingPolicy.isActive()) { this.afterLoadingPolicy.dispose(); setAfterLoadingPolicy(new MWNullDescriptorPolicy(this)); } else { throw new MWAdvancedPropertyRemovalException(AFTER_LOADING_POLICY_PROPERTY, "policy does not exist on descriptor"); } } // ********** InstantiationPolicy API********** protected void setInstantiationPolicy(MWDescriptorPolicy instantiationPolicy) { Object old = this.instantiationPolicy; this.instantiationPolicy = instantiationPolicy; firePropertyChanged(INSTANTIATION_POLICY_PROPERTY, old, this.instantiationPolicy); } public MWDescriptorPolicy getInstantiationPolicy() { return this.instantiationPolicy; } public void addInstantiationPolicy() throws MWAdvancedPropertyAdditionException { if (this.instantiationPolicy.isActive()) { throw new MWAdvancedPropertyAdditionException(INSTANTIATION_POLICY_PROPERTY, "policy already exists on descriptor"); } setInstantiationPolicy(new MWDescriptorInstantiationPolicy(this)); } public void removeInstantiationPolicy() { if (this.instantiationPolicy.isActive()) { this.instantiationPolicy.dispose(); setInstantiationPolicy(new MWNullDescriptorPolicy(this)); } else { throw new MWAdvancedPropertyRemovalException(INSTANTIATION_POLICY_PROPERTY, "property does not exist on descriptor"); } } public boolean supportsReturningPolicy() { return false; } // ********** Mapping API ********** public MWDirectMapping addDirectMapping(MWClassAttribute attribute) { MWDirectMapping mapping = mappingFactory().createDirectMapping(this, attribute, attribute.getName()); addMapping(mapping); return mapping; } public MWDirectCollectionMapping addDirectCollectionMapping(MWClassAttribute attribute) { MWDirectCollectionMapping mapping = mappingFactory().createDirectCollectionMapping(this, attribute, attribute.getName()); this.addMapping((MWMapping) mapping); return mapping; } public MWDirectMapMapping addDirectMapMapping(MWClassAttribute attribute) { MWDirectMapMapping mapping = mappingFactory().createDirectMapMapping(this, attribute, attribute.getName()); this.addMapping((MWMapping)mapping); return mapping; } public MWTransformationMapping addTransformationMapping(MWClassAttribute attribute) { MWTransformationMapping mapping = mappingFactory().createTransformationMapping(this, attribute, attribute.getName()); this.addMapping(mapping); return mapping; } public abstract MWMappingFactory mappingFactory(); public Iterator mappings() { return new CloneIterator(this.mappings); } public int mappingsSize() { return this.mappings.size(); } public Iterator tableReferenceMappings() { return new FilteringIterator(this.mappings()) { protected boolean accept(Object next) { return ((MWMapping) next).isTableReferenceMapping(); } }; } public void removeMappingForAttribute(MWClassAttribute attribute) { MWMapping mapping = mappingForAttribute(attribute); if (mapping != null) { removeMapping(mapping); } else { removeInheritedAttribute(attribute); } } protected void addMapping(MWMapping mapping) { if (CollectionTools.contains(this.inheritedAttributes(), mapping.getInstanceVariable())) { mapping.setInherited(true); } addItemToCollection(mapping, this.mappings, MAPPINGS_COLLECTION); } public void removeMapping(MWMapping mapping) { this.removeNodeFromCollection(mapping, this.mappings, MAPPINGS_COLLECTION); } private void removeMappings(Collection c) { for (Iterator stream = new CloneIterator(c); stream.hasNext(); ) { removeMapping((MWMapping) stream.next()); } } public MWMapping mappingForAttribute(MWClassAttribute attribute) { for (Iterator stream = mappings(); stream.hasNext(); ) { MWMapping mapping = (MWMapping) stream.next(); if (mapping.getInstanceVariable() == attribute) { return mapping; } } return null; } public MWMapping mappingNamed(String name) { if (name == null) { throw new NullPointerException(); } for (Iterator stream = mappings(); stream.hasNext(); ) { MWMapping mapping = (MWMapping) stream.next(); if(name.equals(mapping.getName())) { return mapping; } } return null; } //TODO add this in to the addWrittenFieldsTo() method??? public Collection allWritableMappingsForField(MWDataField field) { // Answer all mappings that map to the database field whose name is aString Collection mappingsForField = new ArrayList(); for (Iterator stream = mappings(); stream.hasNext(); ) { MWMapping mapping = (MWMapping) stream.next(); if (! mapping.isReadOnly()) { Collection writtenFields = new ArrayList(); mapping.addWrittenFieldsTo(writtenFields); if (writtenFields.contains(field)) { mappingsForField.add(mapping); } } } if (! writableMappingsForField(field).isEmpty() && ! getInheritancePolicy().isRoot() && getInheritancePolicy().getParentDescriptor() != null) { for (Iterator stream = getInheritancePolicy().getParentDescriptor().writableMappingsForField(field).iterator(); stream.hasNext(); ) { // do not add mappings that are overwritten in this descriptor MWMapping nextInheritedMapping = (MWMapping) stream.next(); MWMapping inheritedMappingInThisDescriptor = mappingNamed(nextInheritedMapping.getName()); if (inheritedMappingInThisDescriptor == null) { mappingsForField.add(nextInheritedMapping); } } } return mappingsForField; } public Collection writableMappingsForField( MWDataField field ) { // Answer all mappings that map to the database field Collection mappingsForField = new ArrayList(); for (Iterator stream = mappings(); stream.hasNext(); ) { MWMapping mapping = (MWMapping) stream.next(); Collection writtenFields = new ArrayList(); mapping.addWrittenFieldsTo(writtenFields); if (writtenFields.contains(field)) { mappingsForField.add( mapping ); } } return mappingsForField; } public Iterator attributes() { return new TransformationIterator(mappings()) { protected Object transform(Object next) { return ((MWMapping) next).getInstanceVariable(); } }; } //TODO should this remove advanced properties as well? //what about regular descriptor settings like sequencingPolicy? //should we prompt the user and make it a preference whether to remove the advanced props? public void unmap() { super.unmap(); Collection mappingsCopy = new ArrayList(this.mappings); for (Iterator stream = this.mappings(); stream.hasNext(); ) { MWMapping mapping = ((MWMapping) stream.next()); this.removeItemFromCollection(mapping, this.mappings, MAPPINGS_COLLECTION); } // performance tuning: instead of calling #nodeRemoved(Node) for every mapping that is // unmapped, we just finish removing all the mappings and then call #descriptorUnmapped(Collection) this.getProject().descriptorUnmapped(mappingsCopy); } /** * Note that these methods cascade up the hierarchy tree. */ protected void initializeFromMWMappingDescriptor(MWMappingDescriptor oldDescriptor) { super.initializeFromMWMappingDescriptor(oldDescriptor); for (Iterator i = oldDescriptor.inheritedAttributes(); i.hasNext(); ) { addInheritedAttribute((MWClassAttribute) i.next()); } for (Iterator i = oldDescriptor.mappings(); i.hasNext(); ) { addMapping((MWMapping) i.next()); } this.setAfterLoadingPolicy(oldDescriptor.getAfterLoadingPolicy()); this.setCopyPolicy(oldDescriptor.getCopyPolicy()); this.setEventsPolicy(oldDescriptor.getEventsPolicy()); this.setInheritancePolicy(oldDescriptor.getInheritancePolicy()); this.setInstantiationPolicy(oldDescriptor.getInstantiationPolicy()); } // assumes mwClass is in hierarchy // mwClass can not be for java.lang.Object public void mapInheritedAttributesToClass(MWClass mwClass) throws ClassNotFoundException { Collection inheritedAttributes = new ArrayList(); MWClass hierarchyClass = getMWClass(); while ((hierarchyClass != mwClass) && (hierarchyClass.getSuperclass() != typeFor(java.lang.Object.class))) { hierarchyClass = hierarchyClass.getSuperclass(); CollectionTools.addAll(inheritedAttributes, hierarchyClass.attributes()); } for (Iterator it = inheritedAttributes.iterator(); it.hasNext(); ) { MWClassAttribute attribute = (MWClassAttribute) it.next(); MWMapping existingMapping = mappingForAttribute(attribute); if (existingMapping == null && !CollectionTools.contains(this.inheritedAttributes(), attribute)) { addInheritedAttribute(attribute); } } } public void mapInheritedAttributesToRootMinusOne() throws ClassNotFoundException { MWClass bldrClass = getMWClass(); while (bldrClass.getSuperclass() != typeFor(Object.class)) { bldrClass = bldrClass.getSuperclass(); } mapInheritedAttributesToClass(bldrClass); } public void mapInheritedAttributesToSuperclass() throws ClassNotFoundException { mapInheritedAttributesToClass(getMWClass().getSuperclass()); } public void removeInheritedAttributes() { for (Iterator stream = this.mappings(); stream.hasNext(); ) { MWMapping mapping = (MWMapping) stream.next(); if (mapping.isInherited()) { this.removeMapping(mapping); } } for (Iterator stream = this.inheritedAttributes(); stream.hasNext(); ) { stream.next(); stream.remove(); } } private Iterator inheritedAttributeHandles() { return new CloneIterator(this.inheritedAttributeHandles) { protected void remove(Object current) { MWMappingDescriptor.this.removeInheritedAttributeHandle((MWAttributeHandle) current); } }; } void removeInheritedAttributeHandle(MWAttributeHandle handle) { this.inheritedAttributeHandles.remove(handle); this.fireItemRemoved(INHERITED_ATTRIBUTES_COLLECTION, handle.getAttribute()); } public Iterator inheritedAttributes() { return new TransformationIterator(this.inheritedAttributeHandles()) { protected Object transform(Object next) { return ((MWAttributeHandle) next).getAttribute(); } }; } public int inheritedAttributesSize() { return this.inheritedAttributeHandles.size(); } public void addInheritedAttribute(MWClassAttribute inheritedAttribute) { this.inheritedAttributeHandles.add(new MWAttributeHandle(this, inheritedAttribute, this.inheritedAttributeScrubber())); this.fireItemAdded(INHERITED_ATTRIBUTES_COLLECTION, inheritedAttribute); } public void removeInheritedAttribute(MWClassAttribute inheritedAttribute) { for (Iterator stream = this.inheritedAttributes(); stream.hasNext(); ) { if (stream.next() == inheritedAttribute) { stream.remove(); return; } } throw new IllegalArgumentException(inheritedAttribute.toString()); } public void removeInheritedAttributes(Collection attributes) { this.removeInheritedAttributes(attributes.iterator()); } public void removeInheritedAttributes(Iterator attributes) { while (attributes.hasNext()) { this.removeInheritedAttribute((MWClassAttribute) attributes.next()); } } public MWClassAttribute inheritedAttributeNamed(String name) { for (Iterator stream = this.inheritedAttributes(); stream.hasNext(); ) { MWClassAttribute attribute = (MWClassAttribute) stream.next(); if (attribute.getName().equals(name)) { return attribute; } } return null; } public boolean containsInheritedAttributeNamed(String name) { return this.inheritedAttributeNamed(name) != null; } //TODO this should probably be done differently //only the MappingDecriptors that are a part of the hierarchy //need to be notified. Need some good unit tests before changing this //functionality public void hierarchyChanged(MWClass type) { Collection mappingsToRemove = new ArrayList(); for (Iterator stream = this.mappings(); stream.hasNext(); ) { MWMapping mapping = (MWMapping) stream.next(); if (mapping.isInherited() && ! this.getMWClass().isSubclassOf(mapping.getInstanceVariable().getDeclaringType())) { mappingsToRemove.add(mapping); } } this.removeMappings(mappingsToRemove); Collection attributesToRemove = new ArrayList(); for (Iterator stream = this.inheritedAttributes(); stream.hasNext(); ) { MWClassAttribute attribute = (MWClassAttribute) stream.next(); if ( ! this.getMWClass().isSubclassOf(attribute.getDeclaringType())) { attributesToRemove.add(attribute); } } this.removeInheritedAttributes(attributesToRemove); } public MWMapping replaceMapping(MWMapping oldMapping, MWMapping newMapping) { if (oldMapping == newMapping) { return oldMapping; } if (oldMapping == null) { this.addMapping(newMapping); return newMapping; } else if (newMapping == null) { this.removeMapping(oldMapping); return null; } // don't want to call #nodeRemoved(Node), this will be taken care of by calling #mappingReplaced(...) this.removeItemFromCollection(oldMapping, this.mappings, MAPPINGS_COLLECTION); this.addMapping(newMapping); this.getProject().mappingReplaced(oldMapping, newMapping); return newMapping; } // ********** Inheritance ************************************************* public MWInheritancePolicy getInheritancePolicy() { return this.inheritancePolicy; } public void addInheritancePolicy() { if (this.getInheritancePolicy().isActive()) { throw new MWAdvancedPropertyAdditionException(INHERITANCE_POLICY_PROPERTY, "Policy already exists on descriptor: "); } MWDescriptorInheritancePolicy ip = buildInheritancePolicy(); setInheritancePolicy(ip); ip.initializeParentDescriptor(); if (ip.getParentDescriptor() == null) { ip.setIsRoot(true); } getInheritancePolicy().getRootDescriptor().getInheritancePolicy().buildClassIndicatorValues(); } protected abstract MWDescriptorInheritancePolicy buildInheritancePolicy(); public void removeInheritancePolicy() throws MWAdvancedPropertyRemovalException { if (this.inheritancePolicy.isActive() == false) { throw new MWAdvancedPropertyRemovalException(INHERITANCE_POLICY_PROPERTY, "property does not exist on descriptor"); } MWDescriptor oldRootDescriptor = this.getInheritancePolicy().getRootDescriptor(); this.inheritancePolicy.dispose(); this.setInheritancePolicy(new MWNullInheritancePolicy(this)); oldRootDescriptor.getInheritancePolicy().buildClassIndicatorValues(); // if this used to have a parent descriptor, its inheritance has now certainly changed this.inheritanceChanged(); } protected void setInheritancePolicy(MWInheritancePolicy newInheritancePolicy) { Object oldInheritancePolicy = this.inheritancePolicy; this.inheritancePolicy = newInheritancePolicy; firePropertyChanged(INHERITANCE_POLICY_PROPERTY, oldInheritancePolicy, newInheritancePolicy); } public boolean canHaveInheritance() { return true; } public boolean hasDefinedInheritance() { MWInheritancePolicy ip = this.getInheritancePolicy(); return ip.isRoot() || (ip.getParentDescriptor() != null); } public boolean hasActiveInstantiationPolicy() { return getInstantiationPolicy().isActive(); } /** Use this method if other descriptor settings or policies depend upon inheritance */ void inheritanceChanged() { super.inheritanceChanged(); this.inheritancePolicy.descriptorInheritanceChanged(); } public Iterator mappingsIncludingInherited() { return new CloneListIterator(getMappingsIncludingInherited()); } protected List getMappingsIncludingInherited() { List allMappings = new Vector(); if (this.getInheritancePolicy().getParentDescriptor() != null) { allMappings.addAll(this.getInheritancePolicy().getParentDescriptor().getMappingsIncludingInherited()); } // add this descriptor's mappings allMappings.addAll(this.mappings); return allMappings; } public void implementorsChangedFor(MWInterfaceDescriptor descriptor) { for (Iterator stream = this.mappings(); stream.hasNext(); ) { ((MWMapping) stream.next()).implementorsChangedFor(descriptor); } } //*************** Aggregate Support ************* public Collection buildAggregateFieldNameGenerators() { return new ArrayList(); } //*************** Problem Handling ************* /** Check for any problems and add them to the specified collection. */ protected void addProblemsTo(List newProblems) { super.addProblemsTo(newProblems); this.checkMultipleMappingsWriteField(newProblems); this.checkForDuplicateMethods(newProblems); } protected void checkMultipleMappingsWriteField(List newProblems) { HashBag writtenFields = new HashBag(); HashMap fieldToMappings = new HashMap(); for (Iterator mappingStream = this.mappingsIncludingInherited(); mappingStream.hasNext(); ) { MWMapping mapping = (MWMapping) mappingStream.next(); if (mapping.getParentDescriptor().getTransactionalPolicy().isReadOnly()) { continue; // skip to next mapping } Collection writtenFieldsForMapping = new ArrayList(); mapping.addWrittenFieldsTo(writtenFieldsForMapping); for (Iterator fieldStream = writtenFieldsForMapping.iterator(); fieldStream.hasNext(); ) { MWDataField field = (MWDataField) fieldStream.next(); Collection fieldMappings = (Collection) fieldToMappings.get(field); if (fieldMappings == null) { fieldMappings = new ArrayList(); fieldToMappings.put(field, fieldMappings); } fieldMappings.add(mapping); } writtenFields.addAll(writtenFieldsForMapping); } for (Iterator stream = writtenFields.uniqueIterator(); stream.hasNext(); ) { Object field = stream.next(); if (writtenFields.count(field) > 1) { newProblems.add(this.buildMultipleMappingsWriteFieldProblem((Collection) fieldToMappings.get(field), (MWDataField) field)); } } } private Problem buildMultipleMappingsWriteFieldProblem(Collection problemMappings, MWDataField field) { StringBuffer sb = new StringBuffer(); for (Iterator stream = problemMappings.iterator(); stream.hasNext(); ) { sb.append('"'); sb.append(((MWMapping) stream.next()).getName()); sb.append('"'); if (stream.hasNext()) { sb.append(", "); } } return this.buildProblem(multipleMappingsWriteFieldProblemResourceStringKey(), sb.toString(), field.fieldName()); } protected abstract String multipleMappingsWriteFieldProblemResourceStringKey(); private void checkForDuplicateMethods(List newProblems) { for (Iterator stream1 = this.getMWClass().methods(); stream1.hasNext(); ) { MWMethod method1 = (MWMethod) stream1.next(); boolean firstMatch = true; for (Iterator stream2 = this.getMWClass().methods(); stream2.hasNext(); ) { MWMethod method2 = (MWMethod) stream2.next(); if (method2.hasSameSignatureAs(method1)) { if (firstMatch) { firstMatch = false; } else { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_CLASS_MULTIPLE_METHODS_WITH_SAME_SIGNATURE, method1.signature())); } } } } } // ********** Automap Support ********** protected void automapInternal() { super.automapInternal(); this.getInheritancePolicy().automap(); // find a "type" column this.automapMappings(); } private void automapMappings() { for (Iterator stream = this.mappings(); stream.hasNext();) { ((MWMapping) stream.next()).automap(); } } // ********** Runtime Conversion ********** public ClassDescriptor buildRuntimeDescriptor() { ClassDescriptor runtimeDescriptor = super.buildRuntimeDescriptor(); this.inheritancePolicy.adjustRuntimeDescriptor(runtimeDescriptor); this.copyPolicy.adjustRuntimeDescriptor(runtimeDescriptor); this.instantiationPolicy.adjustRuntimeDescriptor(runtimeDescriptor); this.afterLoadingPolicy.adjustRuntimeDescriptor(runtimeDescriptor); this.eventsPolicy.adjustRuntimeDescriptor(runtimeDescriptor); for (Iterator i = getProject().interfaceDescriptorsThatImplement(this); i.hasNext(); ) { MWInterfaceDescriptor implementor = (MWInterfaceDescriptor) i.next(); runtimeDescriptor.getInterfacePolicy().addParentInterfaceName(implementor.getMWClass().getName()); } for (Iterator mappings = this.orderedMappings(); mappings.hasNext(); ) { runtimeDescriptor.addMapping(((MWMapping) mappings.next()).runtimeMapping()); } return runtimeDescriptor; } private Iterator orderedMappings() { return CollectionTools.sort(new Vector(this.mappings), this.orderedMappingComparator()).iterator(); } /** The default comparator - no sorting is done */ protected Comparator orderedMappingComparator() { return new Comparator() { public int compare(Object o1, Object o2) { return 0; } }; } // ********** TopLink methods ********** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWMappingDescriptor.class); descriptor.getInheritancePolicy().setParentClass(MWDescriptor.class); XMLCompositeCollectionMapping mappingsMapping = new XMLCompositeCollectionMapping(); mappingsMapping.setAttributeName("mappings"); mappingsMapping.setGetMethodName("getMappingsForTopLink"); mappingsMapping.setSetMethodName("setMappingsForTopLink"); mappingsMapping.setReferenceClass(MWMapping.class); mappingsMapping.setXPath("mappings/mapping"); descriptor.addMapping(mappingsMapping); XMLCompositeCollectionMapping inheritedAttributeHandlesMapping = new XMLCompositeCollectionMapping(); inheritedAttributeHandlesMapping.setAttributeName("inheritedAttributeHandles"); inheritedAttributeHandlesMapping.setGetMethodName("getInheritedAttributeHandlesForTopLink"); inheritedAttributeHandlesMapping.setSetMethodName("setInheritedAttributeHandlesForTopLink"); inheritedAttributeHandlesMapping.setReferenceClass(MWAttributeHandle.class); inheritedAttributeHandlesMapping.setXPath("inherited-attribute-handles/attribute-handle"); descriptor.addMapping(inheritedAttributeHandlesMapping); XMLCompositeObjectMapping inheritancePolicyMapping = new XMLCompositeObjectMapping(); inheritancePolicyMapping.setAttributeName("inheritancePolicy"); inheritancePolicyMapping.setGetMethodName("getInheritancePolicyForTopLink"); inheritancePolicyMapping.setSetMethodName("setInheritancePolicyForTopLink"); inheritancePolicyMapping.setReferenceClass(MWDescriptorInheritancePolicy.class); inheritancePolicyMapping.setXPath("inheritance-policy"); descriptor.addMapping(inheritancePolicyMapping); XMLCompositeObjectMapping copyPolicyMapping = new XMLCompositeObjectMapping(); copyPolicyMapping.setAttributeName("copyPolicy"); copyPolicyMapping.setSetMethodName("setCopyPolicyForTopLink"); copyPolicyMapping.setGetMethodName("getCopyPolicyForTopLink"); copyPolicyMapping.setReferenceClass(MWDescriptorCopyPolicy.class); copyPolicyMapping.setXPath("copy-policy"); descriptor.addMapping(copyPolicyMapping); XMLCompositeObjectMapping eventsPolicyMapping = new XMLCompositeObjectMapping(); eventsPolicyMapping.setAttributeName("eventsPolicy"); eventsPolicyMapping.setReferenceClass(MWDescriptorEventsPolicy.class); eventsPolicyMapping.setXPath("events-policy"); eventsPolicyMapping.setSetMethodName("setEventsPolicyForTopLink"); eventsPolicyMapping.setGetMethodName("getEventsPolicyForTopLink"); descriptor.addMapping(eventsPolicyMapping); XMLCompositeObjectMapping afterLoadPolicyMapping = new XMLCompositeObjectMapping(); afterLoadPolicyMapping.setAttributeName("afterLoadingPolicy"); afterLoadPolicyMapping.setSetMethodName("setAfterLoadingPolicyForTopLink"); afterLoadPolicyMapping.setGetMethodName("getAfterLoadingPolicyForTopLink"); afterLoadPolicyMapping.setReferenceClass(MWDescriptorAfterLoadingPolicy.class); afterLoadPolicyMapping.setXPath("after-loading-policy"); descriptor.addMapping(afterLoadPolicyMapping); XMLCompositeObjectMapping instantiationPolicyMapping = new XMLCompositeObjectMapping(); instantiationPolicyMapping.setAttributeName("instantiationPolicy"); instantiationPolicyMapping.setReferenceClass(MWDescriptorInstantiationPolicy.class); instantiationPolicyMapping.setGetMethodName("getInstantiationPolicyForTopLink"); instantiationPolicyMapping.setSetMethodName("setInstantiationPolicyForTopLink"); instantiationPolicyMapping.setXPath("instantiation-policy"); descriptor.addMapping(instantiationPolicyMapping); return descriptor; } /** * sort the mappings for TopLink */ private Collection getMappingsForTopLink() { return CollectionTools.sort((List) mappings); } private void setMappingsForTopLink(Collection mappings) { this.mappings = mappings; } /** * sort the inherited attributes for TopLink */ private Collection getInheritedAttributeHandlesForTopLink() { synchronized (this.inheritedAttributeHandles) { return new TreeSet(this.inheritedAttributeHandles); } } private void setInheritedAttributeHandlesForTopLink(Collection handles) { for (Iterator stream = handles.iterator(); stream.hasNext(); ) { ((MWAttributeHandle) stream.next()).setScrubber(this.inheritedAttributeScrubber()); } this.inheritedAttributeHandles = handles; } private MWDescriptorInheritancePolicy getInheritancePolicyForTopLink() { return (MWDescriptorInheritancePolicy) this.inheritancePolicy.getPersistedPolicy(); } protected void setInheritancePolicyForTopLink(MWDescriptorInheritancePolicy policy) { if (policy == null) { this.inheritancePolicy = new MWNullInheritancePolicy(this); } else { this.inheritancePolicy = policy; } } private MWDescriptorCopyPolicy getCopyPolicyForTopLink() { return (MWDescriptorCopyPolicy) getCopyPolicy().getPersistedPolicy(); } private void setCopyPolicyForTopLink(MWDescriptorCopyPolicy policy) { if (policy == null) { this.copyPolicy = new MWNullDescriptorPolicy(this); } else { this.copyPolicy = policy; } } private MWDescriptorEventsPolicy getEventsPolicyForTopLink() { return (MWDescriptorEventsPolicy) getEventsPolicy().getPersistedPolicy(); } private void setEventsPolicyForTopLink(MWDescriptorEventsPolicy policy) { if (policy == null) { this.eventsPolicy = new MWNullDescriptorPolicy(this); } else { this.eventsPolicy = policy; } } private MWDescriptorAfterLoadingPolicy getAfterLoadingPolicyForTopLink() { return (MWDescriptorAfterLoadingPolicy) this.afterLoadingPolicy.getPersistedPolicy(); } private void setAfterLoadingPolicyForTopLink(MWDescriptorAfterLoadingPolicy policy) { if (policy == null) { this.afterLoadingPolicy = new MWNullDescriptorPolicy(this); } else { this.afterLoadingPolicy = policy; } } private MWDescriptorInstantiationPolicy getInstantiationPolicyForTopLink() { return (MWDescriptorInstantiationPolicy) instantiationPolicy.getPersistedPolicy(); } private void setInstantiationPolicyForTopLink(MWDescriptorInstantiationPolicy policy) { if (policy == null) { this.instantiationPolicy = new MWNullDescriptorPolicy(this); } else { this.instantiationPolicy = policy; } } }