/*******************************************************************************
* 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.schema;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.xerces.impl.xs.XSAttributeDecl;
import org.apache.xerces.impl.xs.XSAttributeUseImpl;
import org.apache.xerces.impl.xs.XSComplexTypeDecl;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSObject;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSTypeDefinition;
import org.eclipse.persistence.mappings.converters.ObjectTypeConverter;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.iterators.CompositeIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.NullIterator;
import org.eclipse.persistence.tools.workbench.utility.node.Node;
public final class ExplicitComplexTypeDefinition
extends ExplicitSchemaTypeDefinition
implements MWComplexTypeDefinition
{
/** The type from which this type is derived. *
* If not derived from an explicit type, it is derived from the ur-type or "anyType". */
private volatile ReferencedSchemaTypeDefinition baseType;
/** The complex type is derived from the base type by restriction or extension. */
private volatile String derivationMethod;
/** Abstract types are useful primarily as derivation points for other types. */
private volatile boolean abstractFlag;
/** We have no support for attribute groups from the XDK, so all attributes just get plopped here. *
* Key -> name; Value -> MWSchemaAttribute */
private Map attributes;
/** Content may be empty, simple, complex: element only, or complex: mixed */
private volatile Content content;
// **************** Constructors ******************************************
/** toplink use only */
protected ExplicitComplexTypeDefinition() {
super();
}
ExplicitComplexTypeDefinition(MWModel parent, String name) {
super(parent, name);
}
ExplicitComplexTypeDefinition(MWModel parent, String name, String namespace) {
super(parent, name, namespace);
}
ExplicitComplexTypeDefinition(MWModel parent, String name, String namespace, boolean builtIn) {
super(parent, name, namespace, builtIn);
}
// **************** Initialization ****************************************
protected void initialize() {
super.initialize();
this.attributes = new Hashtable();
}
protected void initialize(Node parent) {
super.initialize(parent);
this.baseType = ReferencedSchemaTypeDefinition.urType(this);
this.content = new EmptyContent(this);
}
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
children.add(this.baseType);
synchronized (this.attributes) { children.addAll(this.attributes.values()); }
if (this.content != null) {
children.add(this.content);
}
}
// **************** Public ************************************************
public MWAttributeDeclaration attribute(String namespaceUrl, String name) {
for (Iterator stream = this.attributes(); stream.hasNext(); ) {
MWAttributeDeclaration attribute = (MWAttributeDeclaration) stream.next();
if (namespaceUrl.equals(attribute.getNamespaceUrl())
&& name.equals(attribute.getName())) {
return attribute;
}
}
return null;
}
// **************** Attributes ********************************************
Iterator attributes() {
return this.attributes.values().iterator();
}
private Iterator attributeNames() {
return this.attributes.keySet().iterator();
}
private void addAttribute(String attributeName, MWAttributeDeclaration attribute) {
this.attributes.put(attributeName, attribute);
}
private ReferencedAttributeDeclaration addReferencedAttribute(String attributeName, String attributeNamespace) {
ReferencedAttributeDeclaration attributeRef = new ReferencedAttributeDeclaration(this, attributeName, attributeNamespace);
this.addAttribute(attributeName, attributeRef);
return attributeRef;
}
private ExplicitAttributeDeclaration addExplicitAttribute(String attributeName) {
ExplicitAttributeDeclaration attributeDef = new ExplicitAttributeDeclaration(this, attributeName);
this.addAttribute(attributeName, attributeDef);
return attributeDef;
}
private void removeAttribute(String attributeName) {
MWAttributeDeclaration attribute = (MWAttributeDeclaration) this.attributes.remove(attributeName);
this.getProject().nodeRemoved(attribute);
}
// **************** MWComplexTypeDefinition contract **********************
public String getDerivationMethod() {
return this.derivationMethod;
}
public boolean isAbstract() {
return this.abstractFlag;
}
public int totalElementCount() {
return this.content.totalElementCount();
}
public int attributeCount() {
return this.attributes.size();
}
// **************** MWSchemaTypeDefinition contract ***********************
public MWSchemaTypeDefinition getBaseType() {
return this.baseType;
}
public boolean isComplex() {
return true;
}
public Iterator baseBuiltInTypes() {
if (this.builtIn) {
return NullIterator.instance();
}
else {
return this.baseType.baseBuiltInTypes();
}
}
// **************** MWSchemaContextComponent contract *********************
public boolean containsText() {
return this.content.hasTextContent();
}
public boolean containsWildcard() {
return this.content.containsWildcard();
}
public int compareSchemaOrder(MWElementDeclaration element1, MWElementDeclaration element2) {
if (element1.isDescendantOf(this.baseType)) {
if (element2.isDescendantOf(this.baseType)) {
return this.baseType.compareSchemaOrder(element1, element2);
}
else {
return -1;
}
}
else if (element2.isDescendantOf(this.baseType)) {
return +1;
}
else {
return this.content.compareSchemaOrder(element1, element2);
}
}
// **************** MWNamedSchemaComponent contract ***********************
public String componentTypeName() {
return "complexType";
}
public void addDirectlyOwnedComponentsTo(Collection directlyOwnedComponents) {
directlyOwnedComponents.addAll(this.attributes.values());
this.content.addDirectlyOwnedComponentsTo(directlyOwnedComponents);
}
// **************** MWSchemaModel contract ********************************
public Iterator structuralComponents() {
return new CompositeIterator(this.content.structuralComponents(), this.attributes());
}
public Iterator descriptorContextComponents() {
return this.content.descriptorContextComponents();
}
public Iterator xpathComponents() {
return new CompositeIterator(this.attributes(), this.content.xpathComponents());
}
public MWAttributeDeclaration nestedAttribute(String namespaceUrl, String attributeName) {
return this.attribute(namespaceUrl, attributeName);
}
public MWElementDeclaration nestedElement(String namespaceUrl, String elementName) {
return this.content.nestedElement(namespaceUrl, elementName);
}
protected void reloadInternal(XSObject xsObject) {
super.reloadInternal(xsObject);
XSComplexTypeDecl complexTypeDecl = (XSComplexTypeDecl) xsObject;
this.reloadBaseType(complexTypeDecl.getBaseType());
this.abstractFlag = complexTypeDecl.getAbstract();
// derivation method
if (complexTypeDecl.getDerivationMethod() == XSConstants.DERIVATION_RESTRICTION) {
this.derivationMethod = RESTRICTION;
}
else {
this.derivationMethod = EXTENSION;
}
this.reloadContent(complexTypeDecl);
this.reloadAttributes(complexTypeDecl.getAttributeUses());
}
private void reloadBaseType(XSTypeDefinition complexTypeDecl) {
ReferencedSchemaTypeDefinition oldBaseType = this.baseType;
String baseTypeName = null;
String baseTypeNamespace = null;
baseTypeName = complexTypeDecl.getName();
baseTypeNamespace = complexTypeDecl.getNamespace();
this.baseType = ReferencedSchemaTypeDefinition.reloadedReferencedType(this, oldBaseType, baseTypeName, baseTypeNamespace, complexTypeDecl);
if (oldBaseType != this.baseType && oldBaseType != null) {
this.getProject().nodeRemoved(oldBaseType);
}
}
private void reloadContent(XSComplexTypeDecl complexTypeDecl) {
Content oldContent = this.content;
this.content = Content.reloadedContent(this, this.content, complexTypeDecl);
if (oldContent != this.content && oldContent != null) {
this.getProject().nodeRemoved(oldContent);
}
}
private void reloadAttributes(XSObjectList complexTypeAttributes) {
Collection removedAttributeNames = CollectionTools.collection(this.attributeNames());
for (int i = complexTypeAttributes.getLength() - 1; i >= 0; i --) {
MWAttributeDeclaration attribute = this.reloadAttribute((XSAttributeUseImpl)complexTypeAttributes.item(i));
removedAttributeNames.remove(attribute.getName());
}
for (Iterator stream = removedAttributeNames.iterator(); stream.hasNext(); ) {
this.removeAttribute((String) stream.next());
}
}
private MWAttributeDeclaration reloadAttribute(XSAttributeUseImpl attributeUse) {
String attributeName = attributeUse.getAttrDeclaration().getName();
MWAttributeDeclaration attribute = (MWAttributeDeclaration) this.attributes.get(attributeName);
if (attributeUse.getAttrDeclaration().getScope() == XSAttributeDecl.SCOPE_GLOBAL) {
//attribute is actually a ref to a global attribute
if (attribute == null || ! attribute.isReference()) {
attribute = this.addReferencedAttribute(attributeName, attributeUse.getAttrDeclaration().getNamespace());
}
}
else {
// attribute is defined locally
if (attribute == null || attribute.isReference()) {
attribute = this.addExplicitAttribute(attributeName);
}
}
if (attribute.isReference()) {
attribute.reload(attributeUse.getAttrDeclaration());
} else {
attribute.reload(attributeUse);
}
return attribute;
}
public void resolveReferences() {
super.resolveReferences();
this.baseType.resolveReferences();
this.content.resolveReferences();
for (Iterator stream = this.attributes.values().iterator(); stream.hasNext(); ) {
((MWAttributeDeclaration) stream.next()).resolveReferences();
}
}
// **************** Toplink methods ***************************************
public static XMLDescriptor buildDescriptor() {
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(ExplicitComplexTypeDefinition.class);
descriptor.getInheritancePolicy().setParentClass(ExplicitSchemaTypeDefinition.class);
descriptor.addDirectMapping("abstractFlag", "abstract/text()");
ObjectTypeConverter derivationMethodConverter = new ObjectTypeConverter();
derivationMethodConverter.addConversionValue(ExplicitComplexTypeDefinition.RESTRICTION, ExplicitComplexTypeDefinition.RESTRICTION);
derivationMethodConverter.addConversionValue(ExplicitComplexTypeDefinition.EXTENSION, ExplicitComplexTypeDefinition.EXTENSION);
XMLDirectMapping derivationMethodMapping = new XMLDirectMapping();
derivationMethodMapping.setAttributeName("derivationMethod");
derivationMethodMapping.setXPath("derivation-method/text()");
derivationMethodMapping.setConverter(derivationMethodConverter);
descriptor.addMapping(derivationMethodMapping);
XMLCompositeObjectMapping baseTypeMapping = new XMLCompositeObjectMapping();
baseTypeMapping.setAttributeName("baseType");
baseTypeMapping.setReferenceClass(ReferencedSchemaTypeDefinition.class);
baseTypeMapping.setXPath("base-type");
descriptor.addMapping(baseTypeMapping);
XMLCompositeCollectionMapping attributeDeclarationsMapping = new XMLCompositeCollectionMapping();
attributeDeclarationsMapping.setAttributeName("attributes");
attributeDeclarationsMapping.setGetMethodName("getAttributesForToplink");
attributeDeclarationsMapping.setSetMethodName("setAttributesForToplink");
attributeDeclarationsMapping.setXPath("attributes/attribute");
attributeDeclarationsMapping.setReferenceClass(AbstractNamedSchemaComponent.class);
attributeDeclarationsMapping.useMapClass(TreeMap.class, "getName");
descriptor.addMapping(attributeDeclarationsMapping);
XMLCompositeObjectMapping contentMapping = new XMLCompositeObjectMapping();
contentMapping.setAttributeName("content");
contentMapping.setXPath("content");
contentMapping.setReferenceClass(Content.class);
descriptor.addMapping(contentMapping);
return descriptor;
}
private Map getAttributesForToplink() {
return new TreeMap(attributes);
}
private void setAttributesForToplink(Map map) {
Map elementMap = new HashMap();
for (Iterator iter = map.values().iterator(); iter.hasNext(); ) {
AbstractNamedSchemaComponent element = (AbstractNamedSchemaComponent)iter.next();
elementMap.put(element.getName(), element);
}
this.attributes = elementMap;
}
}