/******************************************************************************* * 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.Iterator; import java.util.List; import java.util.Vector; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel; import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants; import org.eclipse.persistence.tools.workbench.mappingsmodel.db.ColumnStringHolder; 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.MWAdvancedPropertyAdditionException; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWAdvancedPropertyRemovalException; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWCachingPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWClassIndicatorFieldPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWClassIndicatorPolicy; 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.MWDescriptorCachingPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptorInheritancePolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptorInterfaceAliasPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptorPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWInheritancePolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWInterfaceAliasDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWLockingPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWNullDescriptorPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWRefreshCachePolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWReturningPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWTransactionalDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWTransactionalPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWColumnHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWTableHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle.NodeReferenceScrubber; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MappingStringHolder; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWRelationalDirectMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProjectDefaultsPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.relational.MWRelationalProject; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.MWQuery; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.MWQueryable; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.relational.MWRelationalQueryManager; import org.eclipse.persistence.tools.workbench.utility.ClassTools; 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.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.StringTools; import org.eclipse.persistence.tools.workbench.utility.string.PartialStringComparatorEngine.StringHolderPair; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.RelationalDescriptor; import org.eclipse.persistence.descriptors.changetracking.AttributeChangeTrackingPolicy; import org.eclipse.persistence.descriptors.changetracking.ObjectChangeTrackingPolicy; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.mappings.DirectToFieldMapping; import org.eclipse.persistence.mappings.OneToOneMapping; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; import org.eclipse.persistence.oxm.mappings.XMLTransformationMapping; import org.eclipse.persistence.queries.ReadAllQuery; import org.eclipse.persistence.sessions.Record; public final class MWTableDescriptor extends MWRelationalClassDescriptor implements MWTransactionalDescriptor, MWInterfaceAliasDescriptor { private MWTableHandle primaryTableHandle; public final static String PRIMARY_TABLE_PROPERTY = "primaryTable"; //TODO This needs to be made into a policy ~kfm private volatile boolean usesSequencing; public final static String USES_SEQUENCING_PROPERTY = "usesSequencing"; private volatile String sequenceNumberName; public final static String SEQUENCE_NUMBER_NAME_PROPERTY = "sequenceNumberName"; private MWTableHandle sequenceNumberTableHandle; public final static String SEQUENCE_NUMBER_TABLE_PROPERTY = "sequenceNumberTable"; private MWColumnHandle sequenceNumberColumnHandle; public final static String SEQUENCE_NUMBER_COLUMN_PROPERTY = "sequenceNumberColumn"; private volatile MWDescriptorPolicy multiTableInfoPolicy; public final static String MULTI_TABLE_INFO_POLICY_PROPERTY = "multiTableInfoPolicy"; private volatile MWDescriptorPolicy interfaceAliasPolicy; public final static String INTERFACE_ALIAS_POLICY_PROPERTY = "interfaceAliasPolicy"; private volatile MWDescriptorPolicy returningPolicy; //This is purposefully not in the UI. you only get this functionality //if you migrate from cmp and you cannot change it once you have it. //Don't ask me why, ask Doug or Mike Keith :) - kfm private volatile String changeTrackingType; public final static String CHANGE_TRACKING_TYPE_PROPERTY = "changeTrackingType"; public final static String OBJECT_LEVEL_CHANGE_TRACKING = "objectLevelChangeTracking"; public final static String ATTRIBUTE_LEVEL_CHANGE_TRACKING = "attributeLevelChangeTracking"; // ********** Constructors ********** /** * Default constructor - for TopLink use only. */ private MWTableDescriptor() { super(); } public MWTableDescriptor(MWRelationalProject parent, MWClass type, String name) { super(parent, type, name); } // ********** Initialization ********** /** * initialize persistent state */ protected void initialize(Node parent) { super.initialize(parent); this.primaryTableHandle = new MWTableHandle(this, this.buildPrimaryTableScrubber()); this.sequenceNumberColumnHandle = new MWColumnHandle(this, this.buildSequenceNumberColumnScrubber()); this.sequenceNumberTableHandle = new MWTableHandle(this, this.buildSequenceNumberTableScrubber()); this.sequenceNumberName = ""; this.interfaceAliasPolicy = new MWNullDescriptorPolicy(this); this.multiTableInfoPolicy = new MWNullDescriptorPolicy(this); this.returningPolicy = new MWNullDescriptorPolicy(this); } // ********** Accessors ********** public MWTable getPrimaryTable() { return this.primaryTableHandle.getTable(); } public void setPrimaryTable(MWTable newValue) { MWTable oldValue = getPrimaryTable(); this.primaryTableHandle.setTable(newValue); this.firePropertyChanged(PRIMARY_TABLE_PROPERTY, oldValue, newValue); this.primaryKeyPolicy().descriptorPrimaryTableChanged(newValue); } public void notifyExpressionsToRecalculateQueryables() { getRelationalQueryManager().notifyExpressionsToRecalculateQueryables(); } // ********** Transactional Policy ********** /** override default behavior */ protected MWTransactionalPolicy buildDefaultTransactionalPolicy() { return new MWRelationalTransactionalPolicy(this); } public MWRelationalTransactionalPolicy getRelationalTransactionalPolicy() { return (MWRelationalTransactionalPolicy) getTransactionalPolicy(); } // **************** Primary key policy ************************************ public MWRelationalPrimaryKeyPolicy primaryKeyPolicy() { return this.getRelationalTransactionalPolicy().getPrimaryKeyPolicy(); } public Iterator primaryKeyChoices() { return this.primaryKeyPolicy().primaryKeyChoices(); } // - returns a collection of the attributes mapped by all mappings obtained by // getPrimaryKeyMappings() public Iterator primaryKeyAttributes() { Collection pkAttributes = new Vector(); for (Iterator it = this.primaryKeyMappings(); it.hasNext(); ) pkAttributes.add(((MWMapping) it.next()).getInstanceVariable()); return pkAttributes.iterator(); } // - returns an iterator on all mappings in this descriptor that map to primary key fields, // plus all mappings in this descriptor's superdescriptors that do the same public Iterator primaryKeyMappings() { Collection pkMappings = new Vector(); Iterator pkFieldIt = primaryKeyPolicy().primaryKeys(); while (pkFieldIt.hasNext()) { pkMappings.addAll(allWritableMappingsForField((MWColumn) pkFieldIt.next())); } return pkMappings.iterator(); } public Iterator primaryKeyNames() { return new TransformationIterator(primaryKeys()) { protected Object transform(Object next) { return ((MWColumn) next).getName(); } }; } public Iterator primaryKeys() { return primaryKeyPolicy().primaryKeys(); } public int primaryKeysSize() { return primaryKeyPolicy().primaryKeysSize(); } // ********** Sequencing ********** public boolean usesSequencing() { return this.usesSequencing; } public void setUsesSequencing(boolean usesSequencing) { boolean old = this.usesSequencing; this.usesSequencing = usesSequencing; if (old != usesSequencing) { if ( ! usesSequencing) { setSequenceNumberName(""); setSequenceNumberTable(null); } else { initializeDefaultSequenceTableInfo(); } this.firePropertyChanged(USES_SEQUENCING_PROPERTY, old, usesSequencing); } } private void initializeDefaultSequenceTableInfo() { setSequenceNumberName("SEQ"); if(getPrimaryTable() != null) { setSequenceNumberTable(getPrimaryTable()); if (getPrimaryTable().primaryKeyColumnsSize() > 0) { setSequenceNumberColumn((MWColumn) getPrimaryTable().primaryKeyColumns().next()); } } } /** * Return true if this descriptor, or any descriptor in the * inheritance hierarchy uses sequencing, as descriptors * inherit sequencing information */ public boolean usesSequencingInDescriptorHierarchy() { if (this.usesSequencing()) { return true; } MWDescriptor parent = this.getInheritancePolicy().getParentDescriptor(); return (parent == null) ? false : parent.usesSequencingInDescriptorHierarchy(); } public String getSequenceNumberName() { return this.sequenceNumberName; } public void setSequenceNumberName(String sequenceNumberName) { if (!usesSequencing() && !sequenceNumberName.equals("")) { throw new IllegalStateException("Must have useSequencing set to true to set the sequence number name"); } String old = this.sequenceNumberName; this.sequenceNumberName = sequenceNumberName; this.firePropertyChanged(SEQUENCE_NUMBER_NAME_PROPERTY, old, sequenceNumberName); } public MWColumn getSequenceNumberColumn() { return this.sequenceNumberColumnHandle.getColumn(); } public void setSequenceNumberColumn(MWColumn sequenceNumberColumn) { if ( ! this.usesSequencing() && sequenceNumberColumn != null) { throw new IllegalStateException("Must have useSequencing set to true to set the sequence column"); } if (this.getSequenceNumberTable() == null && sequenceNumberColumn != null) { throw new IllegalStateException("Must have the sequence table set to set the sequence column"); } if (sequenceNumberColumn != null && this.getSequenceNumberTable() != sequenceNumberColumn.getTable()) { throw new IllegalArgumentException("The column must be in the current sequence number table"); } Object old = this.sequenceNumberColumnHandle.getColumn(); this.sequenceNumberColumnHandle.setColumn(sequenceNumberColumn); this.firePropertyChanged(SEQUENCE_NUMBER_COLUMN_PROPERTY, old, sequenceNumberColumn); } public MWTable getSequenceNumberTable() { return this.sequenceNumberTableHandle.getTable(); } public void setSequenceNumberTable(MWTable sequenceNumberTable) { if (!usesSequencing() && sequenceNumberTable != null) { throw new IllegalStateException("Must have useSequencing set to true to set the sequence table"); } MWTable old = getSequenceNumberTable(); this.sequenceNumberTableHandle.setTable(sequenceNumberTable); setSequenceNumberColumn(null); firePropertyChanged(SEQUENCE_NUMBER_TABLE_PROPERTY, old, sequenceNumberTable); } // ********** RefreshCachePolicy ********** public MWRefreshCachePolicy getRefreshCachePolicy() { return getRelationalTransactionalPolicy().getRefreshCachePolicy(); } // *************** Queries ****************** public MWRelationalQueryManager getRelationalQueryManager() { return (MWRelationalQueryManager)getRelationalTransactionalPolicy().getQueryManager(); } public MWQueryable firstQueryable() { for (Iterator i = getQueryables(Filter.NULL_INSTANCE).iterator(); i.hasNext(); ) { MWQueryable queryable = (MWQueryable) i.next(); if (queryable.isLeaf(Filter.NULL_INSTANCE)) { return queryable; } } return null; } // ********** MultiTableInfoPolicy API********** private MWDescriptorMultiTableInfoPolicy getMultiTableInfoPolicyForTopLink() { return (MWDescriptorMultiTableInfoPolicy) this.multiTableInfoPolicy.getPersistedPolicy(); } private void setMultiTableInfoPolicyForTopLink(MWDescriptorMultiTableInfoPolicy multiTableInfoPolicy) { if (multiTableInfoPolicy == null) { this.multiTableInfoPolicy = new MWNullDescriptorPolicy(this); } else { this.multiTableInfoPolicy = multiTableInfoPolicy; } } private void setMultiTableInfoPolicy(MWDescriptorPolicy multiTableInfoPolicy) { Object old = this.multiTableInfoPolicy; this.multiTableInfoPolicy = multiTableInfoPolicy; firePropertyChanged(MULTI_TABLE_INFO_POLICY_PROPERTY, old, this.multiTableInfoPolicy); } public MWDescriptorPolicy getMultiTableInfoPolicy() { return this.multiTableInfoPolicy; } public void addMultiTableInfoPolicy() throws MWAdvancedPropertyAdditionException { if (this.multiTableInfoPolicy.isActive()) { throw new MWAdvancedPropertyAdditionException(MULTI_TABLE_INFO_POLICY_PROPERTY, "policy already exists on descriptor"); } setMultiTableInfoPolicy(new MWDescriptorMultiTableInfoPolicy(this)); } public void removeMultiTableInfoPolicy() { if (this.multiTableInfoPolicy.isActive()) { getMultiTableInfoPolicy().dispose(); setMultiTableInfoPolicy(new MWNullDescriptorPolicy(this)); } else { throw new MWAdvancedPropertyRemovalException(MULTI_TABLE_INFO_POLICY_PROPERTY, "policy does not exist on the descriptor"); } } // ********** IntefaceAliasPolicy API********** private void setInterfaceAliasPolicyForTopLink(MWDescriptorInterfaceAliasPolicy interfaceAliasPolicy) { if (interfaceAliasPolicy == null) { this.interfaceAliasPolicy = new MWNullDescriptorPolicy(this); } else { this.interfaceAliasPolicy = interfaceAliasPolicy; } } private MWDescriptorInterfaceAliasPolicy getInterfaceAliasPolicyForTopLink() { return (MWDescriptorInterfaceAliasPolicy) this.interfaceAliasPolicy.getPersistedPolicy(); } protected void setInterfaceAliasPolicy(MWDescriptorPolicy interfaceAliasPolicy) { Object old = this.interfaceAliasPolicy; this.interfaceAliasPolicy = interfaceAliasPolicy; firePropertyChanged(INTERFACE_ALIAS_POLICY_PROPERTY, old, this.interfaceAliasPolicy); } public MWDescriptorPolicy getInterfaceAliasPolicy() { return this.interfaceAliasPolicy; } public void removeInterfaceAliasPolicy() { if (this.interfaceAliasPolicy.isActive()) { setInterfaceAliasPolicy(new MWNullDescriptorPolicy(this)); } else { throw new MWAdvancedPropertyRemovalException(INTERFACE_ALIAS_POLICY_PROPERTY, "policy does not exist on the descriptor"); } } public void addInterfaceAliasPolicy() throws MWAdvancedPropertyAdditionException { if (this.interfaceAliasPolicy.isActive()) { throw new MWAdvancedPropertyAdditionException(INTERFACE_ALIAS_POLICY_PROPERTY, "policy already exists on descriptor"); } setInterfaceAliasPolicy(new MWDescriptorInterfaceAliasPolicy(this)); } public boolean supportsInterfaceAliasPolicy() { return true; } public boolean supportsMultitablePolicy() { return true; } // ********* Associated Tables API ************ public void addAssociatedTable(MWTable table) { if (!getMultiTableInfoPolicy().isActive()) { throw new IllegalStateException("Cannot add associated tables unless the descriptor has the Multitable info policy"); } ((MWDescriptorMultiTableInfoPolicy) getMultiTableInfoPolicy()).addSecondaryTable(table); } public void removeAssociatedTable(MWTable table) { ((MWDescriptorMultiTableInfoPolicy) getMultiTableInfoPolicy()).removeSecondaryTable(table); } public MWTable getAssociatedTableNamed(String tableName) { for (Iterator stream = associatedTables(); stream.hasNext(); ) { MWTable table = (MWTable) stream.next(); if (table.getName().equals(tableName)) { return table; } } return null; } public boolean hasAssociatedTable(MWTable table) { for (Iterator stream = associatedTables(); stream.hasNext(); ) { MWTable currTable = (MWTable) stream.next(); if (currTable == table) { return true; } } return false; } public Iterator associatedTables() { if (getPrimaryTable() != null && !CollectionTools.contains(secondaryTables(), getPrimaryTable())) { return new CompositeIterator(getPrimaryTable(), secondaryTables()); } return this.secondaryTables(); } public int associatedTablesSize() { return CollectionTools.size(associatedTables()); } public Iterator secondaryTables() { if (getMultiTableInfoPolicy().isActive()) { return ((MWDescriptorMultiTableInfoPolicy) getMultiTableInfoPolicy()).secondaryTables(); } return NullIterator.instance(); } // ********** Change Tracking Type API********** /** * @return Returns the changeTrackingType. */ public String getChangeTrackingType() { return this.changeTrackingType; } /** * @param changeTrackingType The changeTrackingType to set. */ public void setChangeTrackingType(String changeTrackingType) { String oldChangeTrackingType = this.changeTrackingType; this.changeTrackingType = changeTrackingType; firePropertyChanged(CHANGE_TRACKING_TYPE_PROPERTY, oldChangeTrackingType, changeTrackingType); } // ********** MWReturningPolicy API********** public MWDescriptorPolicy getReturningPolicy() { return this.returningPolicy; } private MWReturningPolicy getReturningPolicyForTopLink() { return (MWReturningPolicy) this.returningPolicy.getPersistedPolicy(); } private void setReturningPolicyForTopLink(MWReturningPolicy returningPolicy) { if (returningPolicy == null) { this.returningPolicy = new MWNullDescriptorPolicy(this); } else { this.returningPolicy = returningPolicy; } } private void setReturningPolicy(MWDescriptorPolicy returningPolicy) { Object old = this.returningPolicy; this.returningPolicy = returningPolicy; firePropertyChanged( RETURNING_POLICY_PROPERTY, old, returningPolicy); } public void addReturningPolicy() throws MWAdvancedPropertyAdditionException { if( this.returningPolicy.isActive()) { throw new MWAdvancedPropertyAdditionException( RETURNING_POLICY_PROPERTY, "policy already exists on descriptor"); } setReturningPolicy( new MWRelationalReturningPolicy( this)); } public void removeReturningPolicy() { if( this.returningPolicy.isActive()) { getReturningPolicy().dispose(); setReturningPolicy(new MWNullDescriptorPolicy(this)); } else { throw new MWAdvancedPropertyRemovalException( RETURNING_POLICY_PROPERTY, "policy does not exist on the descriptor"); } } public boolean supportsReturningPolicy() { return true; } public boolean supportsCachingPolicy() { return true; } // *************** morphing support ************** public MWTableDescriptor asMWTableDescriptor() { return this; } public void initializeOn(MWDescriptor newDescriptor) { ((MWRelationalDescriptor) newDescriptor).initializeFromMWTableDescriptor(this); } @Override public boolean isRootDescriptor() { return true; } public boolean isTableDescriptor() { return true; } public void applyAdvancedPolicyDefaults(MWProjectDefaultsPolicy defaultsPolicy) { defaultsPolicy.applyAdvancedPolicyDefaults(this); } // ************** containment hierarchy ************** protected void addChildrenTo(List children) { super.addChildrenTo(children); children.add(this.sequenceNumberColumnHandle); children.add(this.sequenceNumberTableHandle); children.add(this.primaryTableHandle); children.add(this.interfaceAliasPolicy); children.add(this.multiTableInfoPolicy); children.add(this.returningPolicy); } private NodeReferenceScrubber buildSequenceNumberColumnScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWTableDescriptor.this.setSequenceNumberColumn(null); } public String toString() { return "MWTableDescriptor.buildSequenceNumberColumnScrubber()"; } }; } private NodeReferenceScrubber buildSequenceNumberTableScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWTableDescriptor.this.setSequenceNumberTable(null); } public String toString() { return "MWTableDescriptor.buildSequenceNumberTableScrubber()"; } }; } private NodeReferenceScrubber buildPrimaryTableScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWTableDescriptor.this.setPrimaryTable(null); } public String toString() { return "MWTableDescriptor.buildPrimaryTableScrubber()"; } }; } // ************* Automap Support ************* /** * use class inheritance to find a parent descriptor; * if a parent descriptor is found, convert the descriptor to * an aggregate descriptor if necessary */ protected void automapInheritanceHierarchyInternal(Collection automapDescriptors) { super.automapInheritanceHierarchyInternal(automapDescriptors); MWRelationalClassDescriptor parentDescriptor = this.automapFindParentDescriptor(); if (parentDescriptor == null) { return; // nothing to do } if (automapDescriptors.contains(parentDescriptor)) { parentDescriptor.automapSuperDescriptorInheritance(automapDescriptors); } this.automapDescriptorInheritance(parentDescriptor); if (parentDescriptor.isAggregateDescriptor()) { this.asMWAggregateDescriptor(); } } /** * climb up the descriptor class hierarchy looking for a class with an * active descriptor */ private MWRelationalClassDescriptor automapFindParentDescriptor() { MWClass javaClass = this.getMWClass().getSuperclass(); while (javaClass != null) { if (javaClass.isInterface()) { // ???? something must be whacked: we have an interface as a superclass return null; } MWDescriptor parentDescriptor = this.getProject().descriptorForType(javaClass); if ((parentDescriptor != null) && parentDescriptor.isActive()) { return (MWRelationalClassDescriptor) parentDescriptor; } javaClass = javaClass.getSuperclass(); } return null; } private void automapDescriptorInheritance(MWRelationalClassDescriptor parentDescriptor) { MWInheritancePolicy ip = this.getInheritancePolicy(); if ( ! ip.isActive()) { this.addInheritancePolicy(); ip = this.getInheritancePolicy(); } ((MWDescriptorInheritancePolicy) ip).setIsRoot(false); ((MWDescriptorInheritancePolicy) ip).setParentDescriptor(parentDescriptor); if ( ! this.getMWClass().isAbstract()) { MWInheritancePolicy rootIP = ip.getRootDescriptor().getInheritancePolicy(); if (rootIP.isActive()) { MWClassIndicatorFieldPolicy fieldPolicy = (MWClassIndicatorFieldPolicy) rootIP.getClassIndicatorPolicy(); MWClassIndicatorValue indicatorValue = fieldPolicy.getClassIndicatorValueForDescriptor(this); if (indicatorValue == null) { indicatorValue = fieldPolicy.addIndicator(this.getName(), this); } else { indicatorValue.setIndicatorValue(this.getName()); } indicatorValue.setInclude(true); } } } protected boolean autoMapRequiresMetaDataInternal() { return (this.getPrimaryTable() == null); } protected void automapDirectMappingColumns() { MappingStringHolder[] mappingStringHolders = this.buildColumnlessDirectMappingStringHolders(); ColumnStringHolder[] columnStringHolders = this.buildAllUnmappedColumnStringHolders(); StringHolderPair[] pairs = PARTIAL_STRING_COMPARATOR_ENGINE.match(mappingStringHolders, columnStringHolders); for (int i = pairs.length; i-- > 0; ) { StringHolderPair pair = pairs[i]; MappingStringHolder mappingHolder = (MappingStringHolder) pair.getStringHolder1(); ColumnStringHolder columnHolder = (ColumnStringHolder) pair.getStringHolder2(); if ((mappingHolder == null) || (columnHolder == null)) { continue; } if (pair.getScore() > 0.50) { // ??? MWRelationalDirectMapping mapping = (MWRelationalDirectMapping) mappingHolder.getMapping(); mapping.setColumn(columnHolder.getColumn()); } } } private MappingStringHolder[] buildColumnlessDirectMappingStringHolders() { Collection columnlessDirectMappings = new ArrayList(); for (Iterator stream = this.mappings(); stream.hasNext(); ) { ((MWMapping) stream.next()).addColumnlessDirectMappingTo(columnlessDirectMappings); } return MappingStringHolder.buildHolders(columnlessDirectMappings); } private ColumnStringHolder[] buildAllUnmappedColumnStringHolders() { Collection unmappedColumns = new ArrayList(); for (Iterator stream = this.associatedTables(); stream.hasNext(); ) { CollectionTools.addAll(unmappedColumns, ((MWTable) stream.next()).columns()); } for (Iterator stream = this.mappings(); stream.hasNext(); ) { MWMapping mapping = (MWMapping) stream.next(); Collection writtenFields = new ArrayList(); mapping.addWrittenFieldsTo(writtenFields); unmappedColumns.removeAll(writtenFields); } return ColumnStringHolder.buildHolders(unmappedColumns); } //************* Problem Handling ************* /** Check for any problems and add them to the specified collection. */ protected void addProblemsTo(List newProblems) { super.addProblemsTo(newProblems); // primary table and primary keys this.checkPrimaryTable(newProblems); this.checkPrimaryKeys(newProblems); this.checkPrimaryKeysMapped(newProblems); this.checkPrimaryKeysMatchParent(newProblems); this.checkPrimaryKeyMappingsNotReadOnly(newProblems); // sequencing this.checkSequencing(newProblems); this.checkClassIndicatorFieldMapping(newProblems); // queries this.checkQueries(newProblems); } private void checkPrimaryTable(List newProblems) { if (this.getPrimaryTable() == null) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_NO_PRIMARY_TABLE_SPECIFIED)); } } private void checkPrimaryKeys(List newProblems) { boolean hasParent = this.getInheritancePolicy().getParentDescriptor() != null; if (! (hasParent || this.getPrimaryTable() == null || this.primaryKeyPolicy().primaryKeysSize() != 0)) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_NO_PRIMARY_KEYS_SPECIFIED)); } } private void checkPrimaryKeysMapped(List newProblems) { boolean hasParent = (this.getInheritancePolicy().getParentDescriptor() != null); boolean noTable = this.getPrimaryTable() == null; if (hasParent || noTable) { return; } for (Iterator stream = this.primaryKeyPolicy().primaryKeys(); stream.hasNext(); ) { MWColumn primaryKey = (MWColumn) stream.next(); Collection mappingsForField = this.allWritableMappingsForField(primaryKey); if (mappingsForField.size() == 0) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_PRIMARY_KEY_FIELD_UNMAPPED, primaryKey.getName())); } } } private void checkPrimaryKeysMatchParent(List newProblems) { boolean noParent = ! this.getInheritancePolicy().isActive() || this.getInheritancePolicy().getParentDescriptor() == null; boolean noPrimaryTable = this.getPrimaryTable() == null; if (noParent || noPrimaryTable) { return; } // if a multi table policy is defined, the primary keys don't // have to be the same as the parent if they define a reference // associating the differently named primary keys if (this.getMultiTableInfoPolicy().isActive() && ((MWDescriptorMultiTableInfoPolicy) this.getMultiTableInfoPolicy()).pksAcrossMultipleTablesTest(true)) { return; } if (this.getInheritancePolicy().getParentDescriptor() instanceof MWTableDescriptor) { Collection parentKeyNamesCollection = CollectionTools.collection(((MWTableDescriptor) this.getInheritancePolicy().getParentDescriptor()).primaryKeyNames()); // parent and child must at least have the same number of // keys. if (this.primaryKeysSize() != parentKeyNamesCollection.size()) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_PK_SIZE_DONT_MATCH)); } for (Iterator stream = this.primaryKeys(); stream.hasNext(); ) { MWColumn column = (MWColumn) stream.next(); if ( ! parentKeyNamesCollection.contains(column.getName())) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_PKS_DONT_MATCH_PARENT)); } } //bug #6619070 must check for duplicate pk mappings as well. MWTableDescriptor parentDescriptor = (MWTableDescriptor)this.getInheritancePolicy().getParentDescriptor(); for (Iterator stream = parentDescriptor.primaryKeyMappings(); stream.hasNext(); ) { MWMapping parentPkMapping = (MWMapping)stream.next(); MWMapping childMapping = this.mappingNamed(parentPkMapping.getInstanceVariable().getName()); if (childMapping != null) { if (CollectionTools.collection(this.primaryKeyMappings()).contains(childMapping)) { if (((MWRelationalDirectMapping)parentPkMapping).getColumn() == ((MWRelationalDirectMapping)childMapping).getColumn()) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_PRIMARY_KEY_MAPPING_DUPLICATED_IN_HIERARCHY, childMapping)); } } } } } } private void checkSequencing(List newProblems) { if ( ! this.usesSequencing()) { return; } if (StringTools.stringIsEmpty(this.getSequenceNumberName())) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_NO_SEQUENCE_NAME_SPECIFIED)); } if (this.getSequenceNumberTable() == null) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_SEQUENCE_TABLE_NOT_SPECIFIED)); return; } if (this.getSequenceNumberColumn() == null) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_NO_SEQUENCE_NUMBER_FIELD_SPECIFIED)); } if ( ! CollectionTools.contains(this.associatedTables(), this.getSequenceNumberTable())) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_SEQUENCE_TABLE_NOT_VALID)); } } private void checkQueries(List newProblems) { for (Iterator queriesOuter = this.getRelationalQueryManager().queries(); queriesOuter.hasNext(); ) { String queryOneSignature = ((MWQuery)queriesOuter.next()).signature(); boolean firstMatch = true; for (Iterator queriesInner = this.getRelationalQueryManager().queries(); queriesInner.hasNext(); ) { MWQuery query = (MWQuery) queriesInner.next(); if (query.signature().equals(queryOneSignature)) { if(!firstMatch) { String queryName = query.getName(); newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_MULTIPLE_QUERIES_WITH_SAME_SIGNATURE, queryName)); } else { firstMatch = false; } } } } } //TODO this test applies to root eis descriptors as well private void checkPrimaryKeyMappingsNotReadOnly(List newProblems) { // Test to see if there is at least one mapping for each field in the primary key that is writable." MWInheritancePolicy policy = getInheritancePolicy(); boolean hasParent = policy.getParentDescriptor() != null; boolean noTable = getPrimaryTable() == null; boolean noPrimaryKeyFields = getRelationalTransactionalPolicy().getPrimaryKeyPolicy().primaryKeysSize() == 0; if (hasParent || noTable || noPrimaryKeyFields) { return; } // Loop through all of the primary key fields to make sure // that each one has at least one writable mapping. for (Iterator stream = getRelationalTransactionalPolicy().getPrimaryKeyPolicy().primaryKeys(); stream.hasNext(); ) { MWColumn primaryKey = (MWColumn) stream.next(); if (allWritableMappingsForField(primaryKey).size() == 0) { newProblems.add(buildProblem(ProblemConstants.DESCRIPTOR_PRIMARY_KEY_MAPPING_READ_ONLY, primaryKey.getName())); } } } protected String multipleMappingsWriteFieldProblemResourceStringKey() { return ProblemConstants.MULTIPLE_MAPPINGS_WRITE_TO_COLUMN; } private void checkClassIndicatorFieldMapping(List newProblems) { MWInheritancePolicy inheritPolicy = getInheritancePolicy(); if (!inheritPolicy.isRoot()) { return; } MWClassIndicatorPolicy indicatorPolicy = inheritPolicy.getClassIndicatorPolicy(); if (indicatorPolicy.getType() == MWClassIndicatorPolicy.CLASS_EXTRACTION_METHOD_TYPE || indicatorPolicy.getType() == MWClassIndicatorPolicy.NULL_TYPE) { return; } MWColumn indicatorField = ((MWRelationalClassIndicatorFieldPolicy)indicatorPolicy).getColumn(); if (indicatorField == null || indicatorField.isPrimaryKey()) { return; } if(allWritableMappingsForField(indicatorField).size() != 0) { newProblems.add(buildProblem(ProblemConstants.WRITABLE_MAPPING_FOR_CLASS_INDICATOR_FIELD, indicatorField.getName())); } } //************** runtime conversion **************/ protected ClassDescriptor buildBasicRuntimeDescriptor() { RelationalDescriptor descriptor = new RelationalDescriptor(); descriptor.setJavaClassName(getMWClass().getName()); return descriptor; } public ClassDescriptor buildRuntimeDescriptor() { ClassDescriptor runtimeDescriptor = super.buildRuntimeDescriptor(); if (getPrimaryTable() != null) { runtimeDescriptor.setTableName(getPrimaryTable().getName()); } if (usesSequencing() && getSequenceNumberColumn() != null) { runtimeDescriptor.setSequenceNumberField(new DatabaseField(getSequenceNumberColumn().qualifiedName())); runtimeDescriptor.setSequenceNumberName(getSequenceNumberName()); } // Change tracking type String ctt = getChangeTrackingType(); if (ATTRIBUTE_LEVEL_CHANGE_TRACKING.equals(ctt)) { // set attr. level change tracking runtimeDescriptor.setObjectChangePolicy(new AttributeChangeTrackingPolicy()); } else if (OBJECT_LEVEL_CHANGE_TRACKING.equals(ctt)) { runtimeDescriptor.setObjectChangePolicy(new ObjectChangeTrackingPolicy()); } // else deferred. do not set this, it's implicit. We don't want to create an entry for this // case, as this element is only for the conversion case. this.interfaceAliasPolicy.adjustRuntimeDescriptor(runtimeDescriptor); this.multiTableInfoPolicy.adjustRuntimeDescriptor(runtimeDescriptor); this.returningPolicy.adjustRuntimeDescriptor(runtimeDescriptor); return runtimeDescriptor; } protected void adjustUserDefinedQueryKeys(ClassDescriptor runtimeDescriptor) { for (Iterator queryKeys = userDefinedQueryKeys(); queryKeys.hasNext();) { MWUserDefinedQueryKey queryKey = (MWUserDefinedQueryKey) queryKeys.next(); if (queryKey.getColumn() != null){ runtimeDescriptor.addDirectQueryKey(queryKey.getName(), queryKey.getColumn().qualifiedName()); } } } // ********** TopLink methods ********** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWTableDescriptor.class); descriptor.getInheritancePolicy().setParentClass(MWRelationalClassDescriptor.class); XMLCompositeObjectMapping primaryTableMapping = new XMLCompositeObjectMapping(); primaryTableMapping.setAttributeName("primaryTableHandle"); primaryTableMapping.setGetMethodName("getPrimaryTableHandleForTopLink"); primaryTableMapping.setSetMethodName("setPrimaryTableHandleForTopLink"); primaryTableMapping.setReferenceClass(MWTableHandle.class); primaryTableMapping.setXPath("primary-table-handle"); descriptor.addMapping(primaryTableMapping); XMLDirectMapping usesSequencingMapping = (XMLDirectMapping) descriptor.addDirectMapping("usesSequencing", "uses-sequencing/text()"); usesSequencingMapping.setNullValue(Boolean.FALSE); XMLDirectMapping sequenceNumberNameMapping = (XMLDirectMapping) descriptor.addDirectMapping("sequenceNumberName", "sequence-number-name/text()"); sequenceNumberNameMapping.setNullValue(""); XMLCompositeObjectMapping sequenceNumberTableHandleMapping = new XMLCompositeObjectMapping(); sequenceNumberTableHandleMapping.setAttributeName("sequenceNumberTableHandle"); sequenceNumberTableHandleMapping.setGetMethodName("getSequenceNumberTableHandleForTopLink"); sequenceNumberTableHandleMapping.setSetMethodName("setSequenceNumberTableHandleForTopLink"); sequenceNumberTableHandleMapping.setReferenceClass(MWTableHandle.class); sequenceNumberTableHandleMapping.setXPath("sequence-number-table-handle"); descriptor.addMapping(sequenceNumberTableHandleMapping); XMLCompositeObjectMapping sequenceNumberColumnHandleMapping = new XMLCompositeObjectMapping(); sequenceNumberColumnHandleMapping.setAttributeName("sequenceNumberColumnHandle"); sequenceNumberColumnHandleMapping.setGetMethodName("getSequenceNumberColumnHandleForTopLink"); sequenceNumberColumnHandleMapping.setSetMethodName("setSequenceNumberColumnHandleForTopLink"); sequenceNumberColumnHandleMapping.setReferenceClass(MWColumnHandle.class); sequenceNumberColumnHandleMapping.setXPath("sequence-number-column-handle"); descriptor.addMapping(sequenceNumberColumnHandleMapping); descriptor.addDirectMapping("changeTrackingType", "change-tracking-type/text()"); XMLCompositeObjectMapping interfaceAliasPolicyMapping = new XMLCompositeObjectMapping(); interfaceAliasPolicyMapping.setAttributeName("interfaceAliasPolicy"); interfaceAliasPolicyMapping.setReferenceClass(MWDescriptorInterfaceAliasPolicy.class); interfaceAliasPolicyMapping.setSetMethodName("setInterfaceAliasPolicyForTopLink"); interfaceAliasPolicyMapping.setGetMethodName("getInterfaceAliasPolicyForTopLink"); interfaceAliasPolicyMapping.setXPath("interface-alias-policy"); descriptor.addMapping(interfaceAliasPolicyMapping); XMLCompositeObjectMapping multiTableInfoPolicyMapping = new XMLCompositeObjectMapping(); multiTableInfoPolicyMapping.setAttributeName("multiTableInfoPolicy"); multiTableInfoPolicyMapping.setReferenceClass(MWDescriptorMultiTableInfoPolicy.class); multiTableInfoPolicyMapping.setSetMethodName("setMultiTableInfoPolicyForTopLink"); multiTableInfoPolicyMapping.setGetMethodName("getMultiTableInfoPolicyForTopLink"); multiTableInfoPolicyMapping.setXPath("multi-table-info-policy"); descriptor.addMapping(multiTableInfoPolicyMapping); XMLCompositeObjectMapping returningPolicyMapping = new XMLCompositeObjectMapping(); returningPolicyMapping.setAttributeName("returningPolicy"); returningPolicyMapping.setReferenceClass(MWRelationalReturningPolicy.class); returningPolicyMapping.setSetMethodName("setReturningPolicyForTopLink"); returningPolicyMapping.setGetMethodName("getReturningPolicyForTopLink"); returningPolicyMapping.setXPath("returning-policy"); descriptor.addMapping(returningPolicyMapping); return descriptor; } /** * check for null */ private MWTableHandle getPrimaryTableHandleForTopLink() { return (this.primaryTableHandle.getTable() == null) ? null : this.primaryTableHandle; } private void setPrimaryTableHandleForTopLink(MWTableHandle handle) { NodeReferenceScrubber scrubber = this.buildPrimaryTableScrubber(); this.primaryTableHandle = ((handle == null) ? new MWTableHandle(this, scrubber) : handle.setScrubber(scrubber)); } /** * check for null */ private MWTableHandle getSequenceNumberTableHandleForTopLink() { return (this.sequenceNumberTableHandle.getTable() == null) ? null : this.sequenceNumberTableHandle; } private void setSequenceNumberTableHandleForTopLink(MWTableHandle handle) { NodeReferenceScrubber scrubber = this.buildSequenceNumberTableScrubber(); this.sequenceNumberTableHandle = ((handle == null) ? new MWTableHandle(this, scrubber) : handle.setScrubber(scrubber)); } /** * check for null */ private MWColumnHandle getSequenceNumberColumnHandleForTopLink() { return (this.sequenceNumberColumnHandle.getColumn() == null) ? null : this.sequenceNumberColumnHandle; } private void setSequenceNumberColumnHandleForTopLink(MWColumnHandle handle) { NodeReferenceScrubber scrubber = this.buildSequenceNumberColumnScrubber(); this.sequenceNumberColumnHandle = ((handle == null) ? new MWColumnHandle(this, scrubber) : handle.setScrubber(scrubber)); } }