/*******************************************************************************
* 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.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWTable;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational.MWRelationalDescriptorInheritancePolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.xml.MWEisDescriptorInheritancePolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.xml.MWOXDescriptorInheritancePolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWDescriptorHandle;
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.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.iterators.ChainIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.FilteringIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.TreeIterator;
import org.eclipse.persistence.tools.workbench.utility.node.Node;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.InheritancePolicy;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
/**
* Parent of MWRelationalInheritancePolicy and MWOXInheritancePolicy
*/
public abstract class MWDescriptorInheritancePolicy extends MWAbstractDescriptorPolicy implements MWInheritancePolicy {
private volatile boolean isRoot;
public static final String IS_ROOT_PROPERTY = "isRoot";
private MWDescriptorHandle parentDescriptorHandle;
public static final String PARENT_DESCRIPTOR_PROPERTY = "parentDescriptor";
private volatile MWClassIndicatorPolicy classIndicatorPolicy;
public static final String CLASS_INDICATOR_POLICY_PROPERTY = "classIndicatorPolicy";
// **************** Constructors ***************
protected MWDescriptorInheritancePolicy() {
// for TopLink use only
super();
}
protected MWDescriptorInheritancePolicy(MWMappingDescriptor descriptor) {
super(descriptor);
}
// **************** initialization ***************
/**
* initialize persistent state
*/
protected void initialize(Node parent) {
super.initialize(parent);
this.parentDescriptorHandle = new MWDescriptorHandle(this, this.buildParentDescriptorScrubber());
this.isRoot = false;
this.classIndicatorPolicy = new MWNullClassIndicatorPolicy(this);
}
void initializeParentDescriptor() {
MWDescriptor descriptor = getProject().descriptorForType(getOwningDescriptor().getMWClass().getSuperclass());
if (descriptor != null && descriptor.isActive()) {
setParentDescriptor(descriptor);
}
}
// **************** containment hierarchy ***************
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
children.add(this.classIndicatorPolicy);
children.add(this.parentDescriptorHandle);
}
private NodeReferenceScrubber buildParentDescriptorScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
MWDescriptorInheritancePolicy.this.setParentDescriptor(null);
}
public String toString() {
return "MWDescriptorInheritancePolicy.buildParentDescriptorScrubber()";
}
};
}
public void descriptorInheritanceChanged() {
for (Iterator stream = this.childDescriptors(); stream.hasNext(); ) {
((MWDescriptor) stream.next()).inheritanceChanged();
}
}
public void parentDescriptorMorphedToAggregate() {
getClassIndicatorPolicy().parentDescriptorMorphedToAggregate();
}
// **************** Parent descriptor *************************************
public MWDescriptor getParentDescriptor() {
return this.parentDescriptorHandle.getDescriptor();
}
public void setParentDescriptor(MWDescriptor newParentDescriptor) {
if (newParentDescriptor != null && this.isRoot()) {
throw new IllegalStateException("Unable to set a parent descriptor on a root descriptor");
}
MWDescriptor oldParentDescriptor = this.getParentDescriptor();
if (oldParentDescriptor != newParentDescriptor) {
MWInheritancePolicy rootInheritancePolicy = null;
rootInheritancePolicy = this.getRootDescriptor().getInheritancePolicy();
this.parentDescriptorHandle.setDescriptor(newParentDescriptor);
rootInheritancePolicy.buildClassIndicatorValues();
this.firePropertyChanged(PARENT_DESCRIPTOR_PROPERTY, oldParentDescriptor, newParentDescriptor);
this.getRootDescriptor().getInheritancePolicy().buildClassIndicatorValues();
this.getOwningDescriptor().inheritanceChanged();
}
}
public Iterator candidateParentDescriptors() {
final Set descendentDescriptors = CollectionTools.set(this.descendentDescriptors());
final MWDescriptor thisDescriptor = this.getOwningDescriptor();
return new FilteringIterator(this.getProject().descriptors()) {
protected boolean accept(Object o) {
MWDescriptor descriptor = (MWDescriptor) o;
return descriptor.canHaveInheritance()
&& descriptor != thisDescriptor
&& ! descendentDescriptors.contains(o);
}
};
}
// **************** Is root ***********************************************
public boolean isRoot() {
return this.isRoot;
}
public void setIsRoot(boolean newValue) {
MWInheritancePolicy rootInheritancePolicy = getRootDescriptor().getInheritancePolicy();
boolean oldValue = this.isRoot;
this.isRoot = newValue;
if (oldValue != newValue) {
if (this.isRoot) {
setParentDescriptor(null);
useClassIndicatorFieldPolicy();
buildClassIndicatorValues();
}
else {
setClassIndicatorPolicy(new MWNullClassIndicatorPolicy(this));
initializeParentDescriptor();
rootInheritancePolicy.buildClassIndicatorValues();
rootInheritancePolicy = getRootDescriptor().getInheritancePolicy();
}
rootInheritancePolicy.buildClassIndicatorValues();
firePropertyChanged(IS_ROOT_PROPERTY, oldValue, newValue);
}
}
public MWClassIndicatorPolicy getClassIndicatorPolicy() {
return this.classIndicatorPolicy;
}
public void useClassExtractionMethodIndicatorPolicy() {
if (getClassIndicatorPolicy().getType() == MWClassIndicatorPolicy.CLASS_EXTRACTION_METHOD_TYPE) {
return;
}
setClassIndicatorPolicy(new MWClassIndicatorExtractionMethodPolicy(this));
}
public void useClassIndicatorFieldPolicy() {
if (getClassIndicatorPolicy().getType() == MWClassIndicatorPolicy.CLASS_INDICATOR_FIELD_TYPE) {
return;
}
setClassIndicatorPolicy(buildClassIndicatorFieldPolicy());
}
protected abstract MWClassIndicatorFieldPolicy buildClassIndicatorFieldPolicy();
protected void setClassIndicatorPolicy(MWClassIndicatorPolicy classIndicatorPolicy) {
Object oldValue = getClassIndicatorPolicy();
this.classIndicatorPolicy = classIndicatorPolicy;
firePropertyChanged(CLASS_INDICATOR_POLICY_PROPERTY, oldValue, classIndicatorPolicy);
}
public HashSet getAllDescriptorsAvailableForIndicatorDictionary() {
HashSet result = new HashSet();
result.add(this.getOwningDescriptor());
CollectionTools.addAll(result, this.descendentDescriptors());
return result;
}
public Iterator descendentDescriptors() {
return new TreeIterator(this.childDescriptors()) {
protected Iterator children(Object next) {
return ((MWDescriptor) next).getInheritancePolicy().childDescriptors();
}
};
}
public boolean hasDescendentDescriptors() {
return this.descendentDescriptors().hasNext();
}
public Iterator childDescriptors() {
return new FilteringIterator(this.getProject().mappingDescriptors()) {
protected boolean accept(Object o) {
return ((MWDescriptor) o).getInheritancePolicy().getParentDescriptor()
== MWDescriptorInheritancePolicy.this.getOwningDescriptor();
}
};
}
public boolean hasChildDescriptors() {
return this.childDescriptors().hasNext();
}
/** Return a full inheritance lineage, starting with this policy's descriptor
* and continuing up until there is a descriptor with no parent descriptor */
public Iterator descriptorLineage() {
// using a chain iterator to traverse up the inheritance tree
return new ChainIterator(this.getOwningDescriptor()) {
protected Object nextLink(Object currentLink) {
return ((MWDescriptor) currentLink).getInheritancePolicy().getParentDescriptor();
}
};
}
public MWDescriptor getRootDescriptor() {
MWDescriptor rootDescriptor = null;
for (Iterator stream = this.descriptorLineage(); stream.hasNext(); ) {
rootDescriptor = (MWDescriptor) stream.next();
}
return rootDescriptor;
}
public void descriptorReplaced(MWDescriptor oldDescriptor, MWDescriptor newDescriptor) {
super.descriptorReplaced(oldDescriptor, newDescriptor);
if (this.getParentDescriptor() == oldDescriptor) {
this.setParentDescriptor(newDescriptor);
}
}
public MWTable getReadAllSubclassesView() {
return null;
}
public void buildClassIndicatorValues() {
getClassIndicatorPolicy().rebuildClassIndicatorValues(getAllDescriptorsAvailableForIndicatorDictionary());
}
// **************** MWClassIndicatorPolicy.Parent implementation **********
public MWMappingDescriptor getContainingDescriptor() {
return this.getOwningDescriptor();
}
//*************** Problem Handling *************
protected void addProblemsTo(List newProblems) {
super.addProblemsTo(newProblems);
if (this.isRoot()) {
this.checkClassIndicatorValues(newProblems);
this.descriptorTypeInheritanceMismatchTest(newProblems);
} else {
this.checkParentDescriptor(newProblems);
}
this.checkRootClassIndicatorFieldPolicy(newProblems);
}
private void checkClassIndicatorValues(List newProblems) {
MWClassIndicatorPolicy cip = this.getClassIndicatorPolicy();
if (cip.getType() != MWClassIndicatorPolicy.CLASS_INDICATOR_FIELD_TYPE) {
return;
}
MWClassIndicatorFieldPolicy cifp = (MWClassIndicatorFieldPolicy) this.getClassIndicatorPolicy();
if (cifp.classNameIsIndicator()) {
return;
}
for (Iterator stream = cifp.includedClassIndicatorValues(); stream.hasNext(); ) {
MWClassIndicatorValue value = (MWClassIndicatorValue) stream.next();
if (value.getDescriptorValue().getMWClass().isAbstract() && value.getIndicatorValue() != null) {
newProblems.add(this.buildProblem(ProblemConstants.CLASS_INDICATOR_FOR_ABSTRACT_CLASS, value.getDescriptorValue().getMWClass().shortName()));
}
if ( ! value.getDescriptorValue().isActive()) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_INHERITANCE_MAPPED_CHILD_DESCRIPTOR_INACTIVE, value.getDescriptorValue().getMWClass().shortName()));
}
}
if ((cifp.classIndicatorValuesSize() == 0) && this.hasDescendentDescriptors()) {
newProblems.add(this.buildProblem(ProblemConstants.NO_INDICATOR_MAPPINGS));
}
}
private void checkParentDescriptor(List newProblems) {
if (this.getParentDescriptor() == null) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_INHERITANCE_NO_PARENT));
} else {
if ( ! this.getParentDescriptor().isActive()) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_INHERITANCE_PARENT_DESCRIPTOR_INACTIVE));
}
if ( ! this.getParentDescriptor().getInheritancePolicy().isActive()) {
newProblems.add(buildProblem(ProblemConstants.MISSING_INHERITANCE_POLICY_IN_PARENT_DESCRIPTOR));
}
}
}
private void checkRootClassIndicatorFieldPolicy(List newProblems) {
if (this.getOwningDescriptor().getMWClass().isAbstract()) {
return;
}
if (this.getParentDescriptor() == null) {
return;
}
MWInheritancePolicy ip = this.getRootDescriptor().getInheritancePolicy();
if ( ! ip.isActive()) {
return;
}
MWDescriptorInheritancePolicy dip = (MWDescriptorInheritancePolicy) ip;
if ( ! (dip.getClassIndicatorPolicy().getType() == MWClassIndicatorPolicy.CLASS_INDICATOR_FIELD_TYPE)) {
return;
}
MWClassIndicatorFieldPolicy rootIndicatorPolicy = (MWClassIndicatorFieldPolicy) dip.getClassIndicatorPolicy();
if (rootIndicatorPolicy.classNameIsIndicator()) {
return;
}
MWClassIndicatorValue value = rootIndicatorPolicy.getClassIndicatorValueForDescriptor(this.getOwningDescriptor());
if ((value == null)
|| (value.getIndicatorValue() == null)
|| (value.getIndicatorValue().toString().length() == 0)) {
newProblems.add(this.buildProblem(ProblemConstants.NO_ROOT_CLASS_INDICATOR_MAPPING_FOR_CLASS));
}
}
private void descriptorTypeInheritanceMismatchTest(List newProblems) {
if (this.checkDescendantsForDescriptorTypeMismatch()) {
newProblems.add(this.buildProblem(this.descendantDescriptorTypeMismatchProblemString()));
}
}
protected abstract boolean checkDescendantsForDescriptorTypeMismatch();
protected abstract String descendantDescriptorTypeMismatchProblemString();
// *************** Automap Support *************
public void automap() {
// Nothing to do
}
// **************** Runtime Conversion ***************
public void adjustRuntimeDescriptor(ClassDescriptor runtimeDescriptor) {
InheritancePolicy runtimeInheritancePolicy = (InheritancePolicy)runtimeDescriptor.getInheritancePolicy();
if (this.getParentDescriptor() != null) {
runtimeInheritancePolicy.setParentClassName(this.getParentDescriptor().getMWClass().fullName());
}
this.classIndicatorPolicy.adjustRuntimeInheritancePolicy(runtimeInheritancePolicy);
}
// **************** display methods ***************
public void toString(StringBuffer sb) {
if (this.getParentDescriptor() != null) {
sb.append("Parent = " + getParentDescriptor().getMWClass().shortName() + " ");
} else if (getClassIndicatorPolicy() != null) {
sb.append("Root");
}
}
public boolean isActive() {
return true;
}
public MWDescriptorPolicy getPersistedPolicy() {
return this;
}
// **************** TopLink methods ***************
public static XMLDescriptor buildDescriptor() {
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(MWDescriptorInheritancePolicy.class);
InheritancePolicy ip = (InheritancePolicy)descriptor.getInheritancePolicy();
ip.setClassIndicatorFieldName("@type");
ip.addClassIndicator(MWRelationalDescriptorInheritancePolicy.class, "relational");
ip.addClassIndicator(MWOXDescriptorInheritancePolicy.class, "o-x");
ip.addClassIndicator(MWEisDescriptorInheritancePolicy.class, "eis");
XMLDirectMapping isRootMapping = (XMLDirectMapping) descriptor.addDirectMapping("isRoot", "is-root/text()");
isRootMapping.setNullValue(Boolean.TRUE);
XMLCompositeObjectMapping parentDescriptorMapping = new XMLCompositeObjectMapping();
parentDescriptorMapping.setAttributeName("parentDescriptorHandle");
parentDescriptorMapping.setGetMethodName("getParentDescriptorForTopLink");
parentDescriptorMapping.setSetMethodName("setParentDescriptorForTopLink");
parentDescriptorMapping.setReferenceClass(MWDescriptorHandle.class);
parentDescriptorMapping.setXPath("parent-descriptor-handle");
descriptor.addMapping(parentDescriptorMapping);
XMLCompositeObjectMapping classIndicatorPolicyMapping = new XMLCompositeObjectMapping();
classIndicatorPolicyMapping.setAttributeName("classIndicatorPolicy");
classIndicatorPolicyMapping.setGetMethodName("getClassIndicatorPolicyForTopLink");
classIndicatorPolicyMapping.setSetMethodName("setClassIndicatorPolicyForTopLink");
classIndicatorPolicyMapping.setReferenceClass(MWAbstractClassIndicatorPolicy.class);
classIndicatorPolicyMapping.setXPath("class-indicator-policy");
descriptor.addMapping(classIndicatorPolicyMapping);
return descriptor;
}
private MWDescriptorHandle getParentDescriptorForTopLink() {
return (this.parentDescriptorHandle.getDescriptor() == null) ? null : this.parentDescriptorHandle;
}
private void setParentDescriptorForTopLink(MWDescriptorHandle handle) {
NodeReferenceScrubber scrubber = this.buildParentDescriptorScrubber();
this.parentDescriptorHandle = ((handle == null) ? new MWDescriptorHandle(this, scrubber) : handle.setScrubber(scrubber));
}
private MWAbstractClassIndicatorPolicy getClassIndicatorPolicyForTopLink() {
return (this.classIndicatorPolicy.getValueForTopLink() == null) ? null : this.classIndicatorPolicy.getValueForTopLink();
}
private void setClassIndicatorPolicyForTopLink(MWAbstractClassIndicatorPolicy classIndicatorPolicy) {
this.classIndicatorPolicy = (classIndicatorPolicy == null) ? new MWNullClassIndicatorPolicy(this) : classIndicatorPolicy;
}
public void postProjectBuild() {
super.postProjectBuild();
if (isRoot()) {
getClassIndicatorPolicy().setDescriptorsAvailableForIndicatorDictionaryForTopLink(getAllDescriptorsAvailableForIndicatorDictionary().iterator());
}
}
}