/******************************************************************************* * 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.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.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.descriptors.ClassDescriptor; import org.eclipse.persistence.descriptors.ReturningPolicy; public abstract class MWReturningPolicy extends MWAbstractDescriptorPolicy { /** each insert field has a "return only" flag */ private Collection insertFieldReturnOnlyFlags; public static final String INSERT_FIELD_RETURN_ONLY_FLAGS_COLLECTION = "insertFieldReturnOnlyFlags"; /** Subclasses control the implied collection "updateFields" */ public static final String UPDATE_FIELDS_COLLECTION = "updateFields"; // ********** constructors/initialization ********** /** Default constructor - for TopLink use only */ protected MWReturningPolicy() { super(); } protected MWReturningPolicy(MWMappingDescriptor parent) { super(parent); } protected void initialize(Node parent) { super.initialize(parent); this.insertFieldReturnOnlyFlags = new Vector(); } protected void addChildrenTo(List children) { super.addChildrenTo(children); synchronized (this.insertFieldReturnOnlyFlags) { children.addAll(this.insertFieldReturnOnlyFlags); } } // ********** insert fields/return-only flags ********** public Iterator insertFieldReturnOnlyFlags() { return new CloneIterator(this.insertFieldReturnOnlyFlags) { protected void remove(Object current) { MWReturningPolicy.this.removeInsertFieldReturnOnlyFlag((MWReturningPolicyInsertFieldReturnOnlyFlag) current); } }; } public int insertFieldReturnOnlyFlagsSize() { return this.insertFieldReturnOnlyFlags.size(); } public void addInsertFieldReadOnlyFlag(MWReturningPolicyInsertFieldReturnOnlyFlag insertFieldReturnOnlyFlag) { this.addItemToCollection(insertFieldReturnOnlyFlag, this.insertFieldReturnOnlyFlags, INSERT_FIELD_RETURN_ONLY_FLAGS_COLLECTION); } public void removeInsertFieldReturnOnlyFlag(MWReturningPolicyInsertFieldReturnOnlyFlag insertFieldReturnOnlyFlag) { this.removeItemFromCollection(insertFieldReturnOnlyFlag, this.insertFieldReturnOnlyFlags, INSERT_FIELD_RETURN_ONLY_FLAGS_COLLECTION); } /** Return only the fields (MWDataFields), less their flags */ public Iterator insertFields() { return new TransformationIterator(this.insertFieldReturnOnlyFlags()) { protected Object transform(Object next) { return ((MWReturningPolicyInsertFieldReturnOnlyFlag) next).getField(); } }; } // **************** Update fields ***************************************** public abstract Iterator updateFields(); public abstract int updateFieldsSize(); public abstract void removeUpdateField(MWDataField updateField); // ********** MWDescriptorPolicy implementation ********** public boolean isActive() { return true; } public MWDescriptorPolicy getPersistedPolicy() { return this; } // ********** problems ********** protected void addProblemsTo(List problems) { super.addProblemsTo(problems); this.checkTypeIndicatorField(problems); this.checkOptimisticLockingField(problems); this.checkReturningFieldIsmapped(problems); } private void checkTypeIndicatorField(List newProblems){ MWClassIndicatorPolicy classIndicatorPolicy = this.getOwningDescriptor().getInheritancePolicy().getClassIndicatorPolicy(); if (classIndicatorPolicy.getType() == MWClassIndicatorPolicy.CLASS_INDICATOR_FIELD_TYPE) { MWDataField classIndicatorField = ((MWClassIndicatorFieldPolicy) classIndicatorPolicy).getField(); if (CollectionTools.contains(this.updateFields(), classIndicatorField)) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_UPDATE_CLASS_INDICATOR_FIELD, classIndicatorField.fieldName())); } if (CollectionTools.contains(this.insertFields(), classIndicatorField)) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_INSERT_CLASS_INDICATOR_FIELD, classIndicatorField.fieldName())); } } } private void checkOptimisticLockingField(List newProblems) { MWLockingPolicy lockingPolicy = this.getOwningDescriptor().getLockingPolicy(); MWDataField lockingField = lockingPolicy.getVersionLockField(); if (lockingField != null) { if (CollectionTools.contains(this.updateFields(), lockingField)) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_UPDATE_LOCKING_FIELD, lockingField.fieldName())); } if (CollectionTools.contains(this.insertFields(), lockingField)) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_INSERT_LOCKING_FIELD, lockingField.fieldName())); } } } // TODO This message does not correspond to a DescriptorException. If we someday support // different levels of messages, this should be a warning. See the 10.1.3 returningPolicy spec for details private void checkReturningFieldIsmapped(List newProblems) { for (Iterator stream = this.updateFields(); stream.hasNext(); ) { MWDataField field = (MWDataField) stream.next(); if (this.getOwningDescriptor().allWritableMappingsForField(field).isEmpty()) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_UPDATE_UNMAPPED, field.fieldName())); } } for (Iterator stream = this.insertFields(); stream.hasNext(); ) { MWDataField field = (MWDataField) stream.next(); if (this.getOwningDescriptor().allWritableMappingsForField(field).isEmpty()) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_RETURNING_POLICY_INSERT_UNMAPPED, field.fieldName())); } } } // ********** runtime conversion ********** public void adjustRuntimeDescriptor(ClassDescriptor runtimeDescriptor) { ReturningPolicy returningPolicy = new ReturningPolicy(); runtimeDescriptor.setReturningPolicy(returningPolicy); for (Iterator stream = this.insertFieldReturnOnlyFlags(); stream.hasNext(); ) { ((MWReturningPolicyInsertFieldReturnOnlyFlag) stream.next()).adjustRuntimeReturningPolicy(returningPolicy); } for (Iterator stream = this.updateFields(); stream.hasNext(); ) { returningPolicy.addFieldForUpdate(((MWDataField) stream.next()).runtimeField()); } } // ********** TopLink methods ********** /** * sort the collection for TopLink */ private Collection getInsertFieldReturnOnlyFlagsForTopLink() { synchronized (this.insertFieldReturnOnlyFlags) { return new TreeSet(this.insertFieldReturnOnlyFlags); } } private void setInsertFieldReturnOnlyFlagsForTopLink(Collection insertFieldReturnOnlyFlags) { this.insertFieldReturnOnlyFlags = insertFieldReturnOnlyFlags; } }