/*******************************************************************************
* 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.xml;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.xml.namespace.QName;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWAbstractTransactionalPolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWAdvancedPropertyAdditionException;
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.descriptor.MWDescriptorPolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWNullTransactionalPolicy;
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.MWHandle;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWNamedSchemaComponentHandle;
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.MWMappingFactory;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWNullTransformer;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWAbstractAnyMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWAnyAttributeMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWAnyCollectionMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWAnyObjectMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWOXMappingFactory;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWXmlCollectionReferenceMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWXmlFragmentCollectionMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWXmlFragmentMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWXmlObjectReferenceMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassAttribute;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProjectDefaultsPolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.xml.MWOXProject;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.xml.MWXmlProject;
import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWComplexTypeDefinition;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
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.mappings.foundation.AbstractCompositeCollectionMapping;
import org.eclipse.persistence.mappings.foundation.AbstractCompositeDirectCollectionMapping;
import org.eclipse.persistence.mappings.foundation.AbstractCompositeObjectMapping;
import org.eclipse.persistence.mappings.foundation.AbstractDirectMapping;
import org.eclipse.persistence.mappings.foundation.AbstractTransformationMapping;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
import org.eclipse.persistence.oxm.mappings.XMLTransformationMapping;
public final class MWOXDescriptor
extends MWXmlDescriptor implements MWTransactionalDescriptor
{
private volatile boolean anyTypeDescriptor;
public final static String ANY_TYPE_PROPERTY = "anyTypeDescriptor";
private volatile boolean preserveDocument;
public final static String PRESERVE_DOCUMENT_PROPERTY= "preserveDocument";
private volatile boolean rootDescriptor;
public final static String ROOT_DESCRIPTOR_PROPERTY = "rootDescriptor";
private MWNamedSchemaComponentHandle defaultRootElementTypeHandle;
public final static String DEFAULT_ROOT_ELEMENT_TYPE_PROPERTY = "defaultRootElementType";
// **************** Constructors ******************************************
private MWOXDescriptor() {
super();
}
public MWOXDescriptor(MWXmlProject project, MWClass type, String name) {
super(project, type, name);
}
// **************** Initialization ****************************************
protected void initialize(Node parent) {
super.initialize(parent);
this.rootDescriptor = false;
this.defaultRootElementTypeHandle = new MWNamedSchemaComponentHandle(this, this.buildDefaultRootElementTypeScrubber());
}
public void postProjectBuild() {
super.postProjectBuild();
if (getTransactionalPolicy() instanceof MWNullTransactionalPolicy) {
this.transactionalPolicy = new MWOXTransactionalPolicy(this);
}
}
public void applyAdvancedPolicyDefaults(MWProjectDefaultsPolicy defaultsPolicy) {
defaultsPolicy.applyAdvancedPolicyDefaults(this);
}
private NodeReferenceScrubber buildDefaultRootElementTypeScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
MWOXDescriptor.this.setDefaultRootElementType(null);
}
public String toString() {
return "MWOXDescriptor.buildDefaultRootElementTypeScrubber()";
}
};
}
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
children.add(this.defaultRootElementTypeHandle);
}
// **************** Public ************************************************
public MWOXProject getOXProject() {
return (MWOXProject) this.getProject();
}
public MWMappingFactory mappingFactory() {
return MWOXMappingFactory.instance();
}
// **************** Root descriptor ***************************************
public boolean isRootDescriptor() {
return this.rootDescriptor;
}
@Override
public boolean isEisDescriptor() {
return false;
}
public void setRootDescriptor(boolean descriptorIsRoot) {
boolean oldValue = this.rootDescriptor;
this.rootDescriptor = descriptorIsRoot;
this.firePropertyChanged(ROOT_DESCRIPTOR_PROPERTY, oldValue, descriptorIsRoot);
if (oldValue != descriptorIsRoot) {
if (! descriptorIsRoot) {
this.setDefaultRootElement(null);
}
else {
this.setInitialDefaultRootElement();
}
}
}
// **************** Any type descriptor **********************************
public void setAnyTypeDescriptor(boolean newValue) {
boolean oldValue = this.anyTypeDescriptor;
this.anyTypeDescriptor = newValue;
this.firePropertyChanged(ANY_TYPE_PROPERTY, oldValue, newValue);
}
public boolean isAnyTypeDescriptor(){
return this.anyTypeDescriptor;
}
// **************** Default root element type ******************************
public MWComplexTypeDefinition getDefaultRootElementType() {
return (MWComplexTypeDefinition) this.defaultRootElementTypeHandle.getComponent();
}
public void setDefaultRootElementType(MWComplexTypeDefinition newDefaultRootElementType) {
MWComplexTypeDefinition oldDefaultRootElementType = this.getDefaultRootElementType();
this.defaultRootElementTypeHandle.setComponent(newDefaultRootElementType);
this.firePropertyChanged(DEFAULT_ROOT_ELEMENT_TYPE_PROPERTY, oldDefaultRootElementType, newDefaultRootElementType);
}
// **************** Preserve Docuement ***********************************
public void setPreserveDocument(boolean newValue){
boolean oldValue = this.preserveDocument;
this.preserveDocument = newValue;
this.firePropertyChanged(PRESERVE_DOCUMENT_PROPERTY, oldValue, newValue);
}
public boolean isPreserveDocument(){
return this.preserveDocument;
}
// **************** Inheritance policy ************************************
@Override
protected MWTransactionalPolicy buildDefaultTransactionalPolicy() {
return new MWOXTransactionalPolicy(this);
}
// **************** Inheritance policy ************************************
protected MWDescriptorInheritancePolicy buildInheritancePolicy() {
return new MWOXDescriptorInheritancePolicy(this);
}
// **************** Mapping creation **************************************
public MWAnyObjectMapping addAnyObjectMapping(MWClassAttribute attribute) {
MWAnyObjectMapping mapping =
((MWOXMappingFactory) this.mappingFactory()).createAnyObjectMapping(this, attribute, attribute.getName());
this.addMapping(mapping);
return mapping;
}
public MWAnyCollectionMapping addAnyCollectionMapping(MWClassAttribute attribute) {
MWAnyCollectionMapping mapping =
((MWOXMappingFactory) this.mappingFactory()).createAnyCollectionMapping(this, attribute, attribute.getName());
this.addMapping(mapping);
return mapping;
}
public MWAnyAttributeMapping addAnyAttributeMapping(MWClassAttribute attribute) {
MWAnyAttributeMapping mapping =
((MWOXMappingFactory) this.mappingFactory()).createAnyAttributeMapping(this, attribute, attribute.getName());
this.addMapping(mapping);
return mapping;
}
public MWXmlFragmentMapping addXmlFragmentMapping(MWClassAttribute attribute) {
MWXmlFragmentMapping mapping =
((MWOXMappingFactory) this.mappingFactory()).createXmlFragmentMapping(this, attribute, attribute.getName());
this.addMapping(mapping);
return mapping;
}
public MWXmlFragmentCollectionMapping addXmlFragmentCollectionMapping(MWClassAttribute attribute) {
MWXmlFragmentCollectionMapping mapping =
((MWOXMappingFactory) this.mappingFactory()).createXmlFragmentCollectionMapping(this, attribute, attribute.getName());
this.addMapping(mapping);
return mapping;
}
public MWXmlObjectReferenceMapping addXmlObjectReferenceMapping(MWClassAttribute attribute) {
MWXmlObjectReferenceMapping mapping =
((MWOXMappingFactory) this.mappingFactory()).createXmlObjectReferenceMapping(this, attribute, attribute.getName());
this.addMapping(mapping);
return mapping;
}
public MWXmlCollectionReferenceMapping addXmlCollectionReferenceMapping(MWClassAttribute attribute) {
MWXmlCollectionReferenceMapping mapping =
((MWOXMappingFactory) this.mappingFactory()).createXmlCollectionReferenceMapping(this, attribute, attribute.getName());
this.addMapping(mapping);
return mapping;
}
//***************** Morphing support **************************************
//currently there is no descriptor morhping for MWOXDescriptors
public void initializeOn(MWDescriptor newDescriptor) {
throw new UnsupportedOperationException();
}
// **************** Problem handling **************************************
protected void addProblemsTo(List newProblems) {
super.addProblemsTo(newProblems);
this.addAnyTypeDescriptorWithInheritanceProblemTo(newProblems);
this.addAnyTypeDescriptorWithNonAnyMappingsProblemTo(newProblems);
this.addDefaultRootElementTypeProblemTo(newProblems);
}
/** overridden from MWXmlDescriptor */
protected boolean schemaContextIsRequired() {
// any type descriptors do not require a schema context
return ! this.isAnyTypeDescriptor();
}
private void addAnyTypeDescriptorWithInheritanceProblemTo(List newProblems) {
if (this.isAnyTypeDescriptor() && this.getInheritancePolicy().isActive()) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_ANY_TYPE_WITH_INHERITANCE));
}
}
private void addAnyTypeDescriptorWithNonAnyMappingsProblemTo(List newProblems) {
// anyType descriptors may only support a single any mapping
if (this.isAnyTypeDescriptor()) {
// no mappings -> obviously no worries
if (this.mappingsSize() == 0) {
return;
}
// more than one mapping or only mapping not an any mapping
else if (
this.mappingsSize() > 1
|| ! (this.mappings().next() instanceof MWAbstractAnyMapping)
) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_ANY_TYPE_WITH_NON_ANY_MAPPINGS));
}
}
}
private void addDefaultRootElementTypeProblemTo(List newProblems) {
if (this.getDefaultRootElement() == null) {
if (this.getDefaultRootElementType() != null) {
newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_DEFAULT_ROOT_ELEMENT_TYPE));
}
}
}
// **************** Runtime conversion ************************************
protected ClassDescriptor buildBasicRuntimeDescriptor() {
XMLDescriptor runtimeDescriptor = new XMLDescriptor();
runtimeDescriptor.setJavaClassName(getMWClass().getName());
return runtimeDescriptor;
}
public ClassDescriptor buildRuntimeDescriptor() {
XMLDescriptor runtimeDescriptor = (XMLDescriptor) super.buildRuntimeDescriptor();
runtimeDescriptor.setSchemaReference(this.runtimeSchemaReference());
runtimeDescriptor.setNamespaceResolver(this.runtimeNamespaceResolver());
return runtimeDescriptor;
}
protected void adjustRuntimeDescriptorRootProperties(ClassDescriptor runtimeDescriptor) {
super.adjustRuntimeDescriptorRootProperties(runtimeDescriptor);
if (this.isRootDescriptor() && this.getDefaultRootElement() != null) {
((XMLDescriptor) runtimeDescriptor).setDefaultRootElement(this.getDefaultRootElement().qName());
if (this.getDefaultRootElementType() != null) {
((XMLDescriptor) runtimeDescriptor).setDefaultRootElementType(new QName(getDefaultRootElementType().qName()));
}
}
((XMLDescriptor) runtimeDescriptor).setShouldPreserveDocument(this.preserveDocument);
}
public AbstractDirectMapping buildDefaultRuntimeDirectMapping() {
return new XMLDirectMapping();
}
public AbstractCompositeDirectCollectionMapping buildDefaultRuntimeDirectCollectionMapping() {
return new XMLCompositeDirectCollectionMapping();
}
public AbstractCompositeObjectMapping buildDefaultRuntimeCompositeObjectMapping() {
return new XMLCompositeObjectMapping();
}
public AbstractCompositeCollectionMapping buildDefaultRuntimeCompositeCollectionMapping() {
return new XMLCompositeCollectionMapping();
}
public AbstractTransformationMapping buildDefaultRuntimeTransformationMapping() {
return new XMLTransformationMapping();
}
// **************** TopLink methods ***************************************
public static XMLDescriptor buildDescriptor() {
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(MWOXDescriptor.class);
descriptor.getInheritancePolicy().setParentClass(MWXmlDescriptor.class);
XMLDirectMapping anyTypeDescriptorMapping = (XMLDirectMapping) descriptor.addDirectMapping("anyTypeDescriptor", "any-type-descriptor/text()");
anyTypeDescriptorMapping.setNullValue(Boolean.FALSE);
descriptor.addDirectMapping("rootDescriptor", "root-descriptor/text()");
XMLDirectMapping preserveDocumentMapping = (XMLDirectMapping) descriptor.addDirectMapping("preserveDocument", "preserve-document/text()");
preserveDocumentMapping.setNullValue(Boolean.FALSE);
XMLCompositeObjectMapping defaultRootElementTypeHandleMapping = new XMLCompositeObjectMapping();
defaultRootElementTypeHandleMapping.setAttributeName("defaultRootElementTypeHandle");
defaultRootElementTypeHandleMapping.setGetMethodName("getDefaultRootElementTypeHandleForTopLink");
defaultRootElementTypeHandleMapping.setSetMethodName("setDefaultRootElementTypeHandleForTopLink");
defaultRootElementTypeHandleMapping.setReferenceClass(MWNamedSchemaComponentHandle.class);
defaultRootElementTypeHandleMapping.setXPath("default-root-element-type-handle");
descriptor.addMapping(defaultRootElementTypeHandleMapping);
return descriptor;
}
/**
* check for null
*/
private MWNamedSchemaComponentHandle getDefaultRootElementTypeHandleForTopLink() {
return (this.defaultRootElementTypeHandle.getComponent() == null) ? null : this.defaultRootElementTypeHandle;
}
private void setDefaultRootElementTypeHandleForTopLink(MWNamedSchemaComponentHandle handle) {
NodeReferenceScrubber scrubber = this.buildDefaultRootElementTypeScrubber();
this.defaultRootElementTypeHandle = ((handle == null) ? new MWNamedSchemaComponentHandle(this, scrubber) : handle.setScrubber(scrubber));
}
// **************** Primary key policy ************************************
public MWXmlPrimaryKeyPolicy primaryKeyPolicy() {
return ((MWOXTransactionalPolicy) this.getTransactionalPolicy()).getPrimaryKeyPolicy();
}
// - returns an iterator on the attributes mapped by all mappings obtained by
// getPrimaryKeyMappings()
public Iterator primaryKeyAttributes() {
return new TransformationIterator(this.primaryKeyMappings()) {
protected Object transform(Object next) {
return ((MWMapping) next).getInstanceVariable();
}
};
}
// - 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();
for (Iterator stream = primaryKeyPolicy().primaryKeyXpaths(); stream.hasNext(); ) {
CollectionTools.addAll(pkMappings, mappingsForXpath((String) stream.next()));
}
MWDescriptor parentDescriptor = getInheritancePolicy().getParentDescriptor();
//TODO remove the instanceof put the primaryKeyMapping() api on MWEisDescriptor and just return an empty collection
if (parentDescriptor != null && parentDescriptor instanceof MWRootEisDescriptor) {
CollectionTools.addAll(pkMappings, ((MWRootEisDescriptor) parentDescriptor).primaryKeyMappings());
}
return pkMappings.iterator();
}
/** - returns an iterator on all mappings that map to the given xpath */
private Iterator mappingsForXpath(String xpath) {
Collection mappings = new ArrayList();
for (Iterator stream = this.mappings(); stream.hasNext(); ) {
MWMapping mapping = (MWMapping) stream.next();
//TODO addWrittenFieldsTo(Collection) is not fully implemented in the mappings model
Collection writtenFields = new ArrayList();
mapping.addWrittenFieldsTo(writtenFields);
if (writtenFields.contains(xpath)) {
mappings.add(mapping);
}
}
return mappings.iterator();
}
//**************************** Returning Policy ***************************************************
public MWDescriptorPolicy getReturningPolicy() {
throw new UnsupportedOperationException("Returning Policy not supported on OX descriptor");
}
public void addReturningPolicy() throws MWAdvancedPropertyAdditionException {
throw new UnsupportedOperationException("Returning Policy not supported on OX descriptor");
}
public void removeReturningPolicy() {
throw new UnsupportedOperationException("Returning Policy not supported on OX descriptor");
}
}