/******************************************************************************* * 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.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWDataField; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel; 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.MWAbstractClassIndicatorPolicy; 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.MWDescriptorInheritancePolicy; 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.MWHandle.NodeReferenceScrubber; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.AggregateFieldDescription; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.AggregateRuntimeFieldNameGenerator; 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.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.iterators.NullIterator; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.tools.workbench.utility.string.PartialStringComparator; 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.descriptors.InheritancePolicy; import org.eclipse.persistence.mappings.OneToOneMapping; import org.eclipse.persistence.mappings.VariableOneToOneMapping; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; /** * Class indicator that uses a relational database column */ public final class MWRelationalClassIndicatorFieldPolicy extends MWClassIndicatorFieldPolicy implements AggregateRuntimeFieldNameGenerator { private MWColumnHandle columnHandle; public final static String FIELD_PROPERTY = "field"; // ********** constructors ********** /** * Toplink use only */ private MWRelationalClassIndicatorFieldPolicy() { super(); } public MWRelationalClassIndicatorFieldPolicy(MWClassIndicatorPolicy.Parent parent) { this(parent, NullIterator.instance()); } public MWRelationalClassIndicatorFieldPolicy(MWClassIndicatorPolicy.Parent parent, Iterator descriptorsAvailableForIndication) { super(parent); setDescriptorsAvailableForIndicatorDictionary(descriptorsAvailableForIndication); } // ********** initialization ********** /** * initialize persistent state */ protected void initialize(Node parent) { super.initialize(parent); this.columnHandle = new MWColumnHandle(this, this.buildColumnScrubber()); } // ********** containment hierarchy ********** protected void addChildrenTo(List children) { super.addChildrenTo(children); children.add(this.columnHandle); } private NodeReferenceScrubber buildColumnScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWRelationalClassIndicatorFieldPolicy.this.setColumn(null); } public String toString() { return "MWRelationalClassIndicatorFieldPolicy.buildColumnScrubber()"; } }; } // ********** Accessors ********** public MWDataField getField() { return this.getColumn(); } public void setField(MWDataField field) { this.setColumn((MWColumn) field); } public MWColumn getColumn() { return this.columnHandle.getColumn(); } public void setColumn(MWColumn column) { Object old = this.columnHandle.getColumn(); this.columnHandle.setColumn(column); this.firePropertyChanged(FIELD_PROPERTY, old, column); } protected boolean fieldSpecified() { return ((MWRelationalDescriptor) this.getContainingDescriptor()).isAggregateDescriptor() || getField() != null; } // ********** Aggregate Support ********** public String fieldNameForRuntime() { return "CLASS_INDICATOR_FIELD"; } public AggregateFieldDescription fullFieldDescription() { return new AggregateFieldDescription() { public String getMessageKey() { if (getParent() instanceof MWDescriptorInheritancePolicy) { return "AGGREGATE_FIELD_DESCRIPTION_FOR_CLASS_INDICATOR_FIELD_FOR_INHERITANCE"; } return "AGGREGATE_FIELD_DESCRIPTION_FOR_CLASS_INDICATOR_FIELD"; } public Object[] getMessageArguments() { return new Object[] {}; } }; } public void parentDescriptorMorphedToAggregate() { setField(null); } public boolean fieldIsWritten() { return true; } public MWDescriptor owningDescriptor() { return this.getContainingDescriptor(); } public void addToAggregateFieldNameGenerators(Collection generators) { generators.add(this); } // ************* Automap Support ************* public void automap() { super.automap(); this.automapColumn(); } /** * look for a column named something like "TYPE" or "CLASS". */ private void automapColumn() { MWRelationalDescriptor descriptor = (MWRelationalDescriptor) this.getContainingDescriptor(); if ( ! descriptor.isAggregateDescriptor()) { return; } ColumnStringHolder[] columnStringHolders = this.allUnmappedColumnStringHolders((MWTableDescriptor) descriptor); if (columnStringHolders.length == 0) { return; } StringHolderScore shs1 = this.match("type", columnStringHolders); StringHolderScore shs2 = this.match("class", columnStringHolders); MWColumn column1 = ((ColumnStringHolder) shs1.getStringHolder()).getColumn(); MWColumn column2 = ((ColumnStringHolder) shs2.getStringHolder()).getColumn(); double score1 = shs1.getScore(); double score2 = shs2.getScore(); if (Math.max(score1, score2) > 0.50) { // 0.50 ??? this.setField((score1 >= score2) ? column1 : column2); } } private ColumnStringHolder[] allUnmappedColumnStringHolders(MWTableDescriptor descriptor) { Collection unmappedColumns = new HashSet(); for (Iterator stream = descriptor.associatedTables(); stream.hasNext(); ) { CollectionTools.addAll(unmappedColumns, ((MWTable) stream.next()).columns()); } Collection mappedColumns = new HashSet(); for (Iterator mappings = descriptor.mappings(); mappings.hasNext(); ) { MWMapping mapping = (MWMapping) mappings.next(); mapping.addWrittenFieldsTo(mappedColumns); } unmappedColumns.removeAll(mappedColumns); return ColumnStringHolder.buildHolders(unmappedColumns); } private StringHolderScore match(String string, ColumnStringHolder[] columnStringHolders) { return COLUMN_NAME_MATCHER.match(string, columnStringHolders); } private static final PartialStringMatcher COLUMN_NAME_MATCHER = new SimplePartialStringMatcher(PartialStringComparator.DEFAULT_COMPARATOR); // ********* Problems *************** protected void addProblemsTo(List newProblems) { super.addProblemsTo(newProblems); addClassIndicatorFieldNotSpecifiedProblemTo(newProblems); } public void addClassIndicatorFieldNotSpecifiedProblemTo(List newProblems) { ((Parent) getParent()).addClassIndicatorFieldNotSpecifiedProblemTo(newProblems); } // ********** Runtime Conversion ********** //runtime conversion for when this is used in MWRelationalInheritancePolicy public void adjustRuntimeInheritancePolicy(InheritancePolicy runtimeInheritancePolicy) { super.adjustRuntimeInheritancePolicy(runtimeInheritancePolicy); if (getColumn() != null) { runtimeInheritancePolicy.setClassIndicatorFieldName(getColumn().qualifiedName()); } else { runtimeInheritancePolicy.setClassIndicatorFieldName(fieldNameForRuntime()); } } //runtime conversion for when this is used in MWVariableOneToOneMapping //this make me like this sharing of the relationaClassIndicatorFieldPolicy less and less :( ~kfm public void adjustRuntimeMapping(VariableOneToOneMapping runtimeMapping) { String classIndicatorFieldName = null; if (getField() != null) { classIndicatorFieldName = getColumn().qualifiedName(); } else if (((MWVariableOneToOneMapping) getParent()).parentDescriptorIsAggregate()) { classIndicatorFieldName = runtimeMapping.getAttributeName() + "->" + fieldNameForRuntime(); } if (classIndicatorFieldName != null && ! classIndicatorFieldName.equals("")) { runtimeMapping.setTypeFieldName(classIndicatorFieldName); for (Iterator indicatorValues = includedClassIndicatorValues(); indicatorValues.hasNext(); ) { Object value = ((MWClassIndicatorValue) indicatorValues.next()).getIndicatorValue(); runtimeMapping.addClassNameIndicator(getDescriptorForIndicator(value).getMWClass().getName(), value); } } else runtimeMapping.setTypeFieldName(""); } // ********** TopLink methods ********** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWRelationalClassIndicatorFieldPolicy.class); descriptor.getInheritancePolicy().setParentClass(MWClassIndicatorFieldPolicy.class); XMLCompositeObjectMapping columnHandleMapping = new XMLCompositeObjectMapping(); columnHandleMapping.setAttributeName("columnHandle"); columnHandleMapping.setGetMethodName("getColumnHandleForTopLink"); columnHandleMapping.setSetMethodName("setColumnHandleForTopLink"); columnHandleMapping.setReferenceClass(MWColumnHandle.class); columnHandleMapping.setXPath("column-handle"); descriptor.addMapping(columnHandleMapping); return descriptor; } private MWColumnHandle getColumnHandleForTopLink() { return (this.columnHandle.getColumn() == null) ? null : this.columnHandle; } private void setColumnHandleForTopLink(MWColumnHandle handle) { NodeReferenceScrubber scrubber = this.buildColumnScrubber(); this.columnHandle = ((handle == null) ? new MWColumnHandle(this, scrubber) : handle.setScrubber(scrubber)); } public static interface Parent { void addClassIndicatorFieldNotSpecifiedProblemTo(List newProblems); } }