/*******************************************************************************
* 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.Iterator;
import java.util.List;
import java.util.TreeSet;
import java.util.Vector;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWDataField;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWColumn;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWColumnPair;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWReturningPolicy;
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.MWOneToOneMapping;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.iterators.CloneIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator;
import org.eclipse.persistence.tools.workbench.utility.node.Node;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
public final class MWRelationalReturningPolicy
extends MWReturningPolicy
{
/** The implementation of the implied collection on the superclass */
private Collection updateFieldHandles;
private NodeReferenceScrubber updateFieldScrubber;
// ********** constructors/initialization **********
/** Default constructor - for TopLink use only */
private MWRelationalReturningPolicy() {
super();
}
MWRelationalReturningPolicy(MWRelationalClassDescriptor parent) {
super(parent);
}
protected void initialize(Node parent) {
super.initialize(parent);
this.updateFieldHandles = new Vector();
}
// **************** Insert fields *****************************************
public MWRelationalReturningPolicyInsertFieldReturnOnlyFlag addInsertFieldReadOnlyFlag(MWColumn insertColumn) {
MWRelationalReturningPolicyInsertFieldReturnOnlyFlag insertFieldReturnOnlyFlag = new MWRelationalReturningPolicyInsertFieldReturnOnlyFlag(this, insertColumn);
this.addInsertFieldReadOnlyFlag(insertFieldReturnOnlyFlag);
return insertFieldReturnOnlyFlag;
}
// **************** Update fields *****************************************
private Iterator updateFieldHandles() {
return new CloneIterator(this.updateFieldHandles) {
protected void remove(Object current) {
MWRelationalReturningPolicy.this.removeUpdateFieldHandle((MWColumnHandle) current);
}
};
}
void removeUpdateFieldHandle(MWColumnHandle handle) {
this.updateFieldHandles.remove(handle);
this.fireItemRemoved(UPDATE_FIELDS_COLLECTION, handle.getColumn());
}
public Iterator updateFields() {
return new TransformationIterator(this.updateFieldHandles()) {
protected Object transform(Object next) {
return ((MWColumnHandle) next).getColumn();
}
};
}
public int updateFieldsSize() {
return this.updateFieldHandles.size();
}
public void addUpdateField(MWColumn updateField) {
if (CollectionTools.contains(this.updateFields(), updateField)) {
throw new IllegalArgumentException(updateField.toString());
}
this.updateFieldHandles.add(new MWColumnHandle(this, updateField, this.updateFieldScrubber()));
this.fireItemAdded(UPDATE_FIELDS_COLLECTION, updateField);
}
public void removeUpdateField(MWDataField updateField) {
this.removeUpdateField((MWColumn) updateField);
}
public void removeUpdateField(MWColumn updateField) {
for (Iterator stream = this.updateFields(); stream.hasNext(); ) {
if (stream.next() == updateField) {
stream.remove();
return;
}
}
throw new IllegalArgumentException(updateField.toString());
}
// ********** convenience **********
private MWRelationalClassDescriptor relationalDescriptor() {
return (MWRelationalClassDescriptor) this.getParent();
}
// ********** problems **********
protected void addProblemsTo(List problems) {
super.addProblemsTo(problems);
this.checkPlatformForNativeReturningSupport(problems);
this.checkUpdateFields(problems);
this.checkSequenceColumn(problems);
this.checkOneToOneForeignKey(problems);
}
private void checkPlatformForNativeReturningSupport(List newProblems) {
if ( ! this.getProject().getDatabase().getDatabasePlatform().supportsNativeReturning()) {
newProblems.add(buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_NATIVE_RETURNING_NOT_SUPPORTED));
}
}
private void checkUpdateFields(List problems) {
for (Iterator stream = this.updateFields(); stream.hasNext(); ) {
MWDataField field = (MWDataField) stream.next();
if ( ! CollectionTools.contains(this.relationalDescriptor().allAssociatedColumns(), field)) {
problems.add(buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_UPDATE_FIELDS_NOT_VALID, field.fieldName()));
}
}
}
private void checkSequenceColumn(List newProblems) {
MWColumn sequenceColumn = ((MWTableDescriptor) this.getOwningDescriptor()).getSequenceNumberColumn();
if (CollectionTools.contains(this.updateFields(), sequenceColumn)) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_UPDATE_SEQUENCING_FIELD, sequenceColumn.qualifiedName()));
}
if (CollectionTools.contains(this.insertFields(), sequenceColumn)) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_INSERT_SEQUENCING_FIELD, sequenceColumn.qualifiedName()));
}
}
private void checkOneToOneForeignKey(List newProblems) {
for (Iterator stream = this.getProject().allMappings(); stream.hasNext(); ) {
MWMapping mapping = (MWMapping) stream.next();
if (mapping.isOneToOneMapping()) {
MWOneToOneMapping oneToOneMapping = (MWOneToOneMapping) mapping;
if ((oneToOneMapping.getReference() != null) && (oneToOneMapping.getReference().isForeignKeyReference())) {
for (Iterator stream2 = oneToOneMapping.getReference().columnPairs(); stream2.hasNext(); ) {
MWColumn sourceColumn = ((MWColumnPair) stream2.next()).getSourceColumn();
if (CollectionTools.contains(this.updateFields(), sourceColumn)) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_UPDATE_ONE_TO_ONE_FORIEGN_KEY, sourceColumn.qualifiedName(), oneToOneMapping.getName()));
}
if (CollectionTools.contains(this.insertFields(), sourceColumn)) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_INSERT_ONE_TO_ONE_FORIEGN_KEY, sourceColumn.qualifiedName(), oneToOneMapping.getName()));
}
}
}
}
}
}
// ********** Model synchronization **********
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
synchronized (this.updateFieldHandles) { children.addAll(this.updateFieldHandles); }
}
private NodeReferenceScrubber updateFieldScrubber() {
if (this.updateFieldScrubber == null) {
this.updateFieldScrubber = this.buildUpdateFieldScrubber();
}
return this.updateFieldScrubber;
}
private NodeReferenceScrubber buildUpdateFieldScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
MWRelationalReturningPolicy.this.removeUpdateFieldHandle((MWColumnHandle) handle);
}
public String toString() {
return "MWRelationalReturningPolicy.buildUpdateFieldScrubber()";
}
};
}
// ********** TopLink methods **********
public static XMLDescriptor buildDescriptor() {
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(MWRelationalReturningPolicy.class);
XMLCompositeCollectionMapping insertFieldReturnOnlyFlagsMapping = new XMLCompositeCollectionMapping();
insertFieldReturnOnlyFlagsMapping.setAttributeName("insertFieldReturnOnlyFlags");
insertFieldReturnOnlyFlagsMapping.setReferenceClass(MWRelationalReturningPolicyInsertFieldReturnOnlyFlag.class);
insertFieldReturnOnlyFlagsMapping.setGetMethodName("getInsertFieldReturnOnlyFlagsForTopLink");
insertFieldReturnOnlyFlagsMapping.setSetMethodName("setInsertFieldReturnOnlyFlagsForTopLink");
insertFieldReturnOnlyFlagsMapping.setXPath("insert-field-read-only-flags/insert-field-read-only-flag");
descriptor.addMapping(insertFieldReturnOnlyFlagsMapping);
XMLCompositeCollectionMapping updateFieldHandlesMapping = new XMLCompositeCollectionMapping();
updateFieldHandlesMapping.setAttributeName("updateFieldHandles");
updateFieldHandlesMapping.setGetMethodName("getUpdateFieldHandlesForTopLink");
updateFieldHandlesMapping.setSetMethodName("setUpdateFieldHandlesForTopLink");
updateFieldHandlesMapping.setReferenceClass(MWColumnHandle.class);
updateFieldHandlesMapping.setXPath("update-field-handles/column-handle");
descriptor.addMapping(updateFieldHandlesMapping);
return descriptor;
}
/**
* sort the collection for TopLink
*/
private Collection getUpdateFieldHandlesForTopLink() {
synchronized (this.updateFieldHandles) {
return new TreeSet(this.updateFieldHandles);
}
}
private void setUpdateFieldHandlesForTopLink(Collection handles) {
for (Iterator stream = handles.iterator(); stream.hasNext(); ) {
((MWColumnHandle) stream.next()).setScrubber(this.updateFieldScrubber());
}
this.updateFieldHandles = handles;
}
}