blob: 14c785ec5a8592c759b6d3ec737465a9d94f7fb7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 SAP AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Emil Simeonov - initial API and implementation.
* Dimitar Donchev - initial API and implementation.
* Dimitar Tenev - initial API and implementation.
* Nevena Manova - initial API and implementation.
* Georgi Konstantinov - initial API and implementation.
* Keshav Veerapaneni - initial API and implementation.
*******************************************************************************/
package org.eclipse.wst.sse.sieditor.command.emf.xsd;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.wst.sse.sieditor.command.common.AbstractNotificationOperation;
import org.eclipse.wst.sse.sieditor.core.common.CollectionTypeUtils;
import org.eclipse.wst.sse.sieditor.core.common.Condition;
import org.eclipse.wst.sse.sieditor.core.common.Logger;
import org.eclipse.wst.sse.sieditor.model.api.IModelObject;
import org.eclipse.wst.sse.sieditor.model.api.IModelRoot;
import org.eclipse.wst.sse.sieditor.model.api.IWsdlModelRoot;
import org.eclipse.wst.sse.sieditor.model.api.IXSDModelRoot;
import org.eclipse.wst.sse.sieditor.model.i18n.Messages;
import org.eclipse.wst.sse.sieditor.model.utils.EmfWsdlUtils;
import org.eclipse.wst.sse.sieditor.model.utils.EmfXsdUtils;
import org.eclipse.wst.sse.sieditor.model.utils.ResourceUtils;
import org.eclipse.wst.sse.sieditor.model.wsdl.impl.Description;
import org.eclipse.wst.sse.sieditor.model.xsd.api.ISchema;
import org.eclipse.wst.sse.sieditor.model.xsd.impl.AbstractType;
import org.eclipse.wst.sse.sieditor.model.xsd.impl.Schema;
import org.eclipse.wst.wsdl.Definition;
import org.eclipse.wst.wsdl.Types;
import org.eclipse.wst.wsdl.XSDSchemaExtensibilityElement;
import org.eclipse.xsd.XSDAttributeDeclaration;
import org.eclipse.xsd.XSDAttributeGroupContent;
import org.eclipse.xsd.XSDAttributeGroupDefinition;
import org.eclipse.xsd.XSDAttributeUse;
import org.eclipse.xsd.XSDComplexTypeContent;
import org.eclipse.xsd.XSDComplexTypeDefinition;
import org.eclipse.xsd.XSDConcreteComponent;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDFactory;
import org.eclipse.xsd.XSDForm;
import org.eclipse.xsd.XSDImport;
import org.eclipse.xsd.XSDInclude;
import org.eclipse.xsd.XSDModelGroup;
import org.eclipse.xsd.XSDModelGroupDefinition;
import org.eclipse.xsd.XSDNamedComponent;
import org.eclipse.xsd.XSDParticle;
import org.eclipse.xsd.XSDParticleContent;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDSchemaContent;
import org.eclipse.xsd.XSDSchemaDirective;
import org.eclipse.xsd.XSDSimpleTypeDefinition;
import org.eclipse.xsd.XSDTypeDefinition;
import org.eclipse.xsd.util.XSDConstants;
public class CopyTypeCommand extends AbstractNotificationOperation {
private XSDNamedComponent typeForCopyThatIsUnderAnalysis;
private AbstractType clone;
private final IModelObject parent;
private Map<String, XSDSchema> schemasUsed;
private final ISchema targetSchema;
private List<XSDNamedComponent> objectsToBeCopied;
private Set<XSDConcreteComponent> copiedComponents;
// List of all the components copied to targetschema
private final HashSet<XSDNamedComponent> inconsistentClones = new HashSet<XSDNamedComponent>();
private XSDNamedComponent clonedComponent;
private static final String XMLNS_PREFIX_BASE = "imp"; //$NON-NLS-1$
public CopyTypeCommand(final IModelRoot root, final IModelObject modelObject, final List<XSDNamedComponent> typesToBeCopied,
final ISchema targetSchema) {
super(root, modelObject, Messages.CopyTypeCommand_copy_type_comand_label);
this.parent = modelObject;
this.targetSchema = targetSchema;
this.objectsToBeCopied = typesToBeCopied;
this.copiedComponents = new HashSet<XSDConcreteComponent>();
}
public CopyTypeCommand(final IModelRoot root, final IModelObject modelObject, final XSDNamedComponent typeToBeCopied,
final ISchema targetSchema) {
this(root, modelObject, Arrays.asList(new XSDNamedComponent[] { typeToBeCopied }), targetSchema);
}
@Override
public boolean canExecute() {
return null != getModelRoot() && null != parent && !objectsToBeCopied.isEmpty()
&& objectsToBeCopied.get(0).eResource() != null;
}
@SuppressWarnings("unchecked")
private ArrayList<XSDSchema> getInlineSchemas() {
final ArrayList<XSDSchema> inlineSchemas = new ArrayList<XSDSchema>();
if (getModelRoot() instanceof IXSDModelRoot) {
final IXSDModelRoot modelRoot = (IXSDModelRoot) getModelRoot();
final EList<XSDTypeDefinition> typeDefinitions = modelRoot.getSchema().getComponent().getTypeDefinitions();
for (final XSDTypeDefinition typeDef : typeDefinitions) {
final XSDSchema schema = typeDef.getSchema();
if (schema != null && !inlineSchemas.contains(schema)) {
inlineSchemas.add(schema);
}
}
} else {
final IWsdlModelRoot modelRoot = (IWsdlModelRoot) getModelRoot();
final Definition definition = ((Description) modelRoot.getDescription()).getComponent();
final Types types = definition.getETypes();
if (null != types) {
inlineSchemas.addAll(types.getSchemas());
}
}
return inlineSchemas;
}
@Override
public IStatus run(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
final boolean debug = Logger.isDebugEnabled();
if (debug)
Logger.getDebugTrace().traceEntry(""); //$NON-NLS-1$
schemasUsed = new HashMap<String, XSDSchema>();
for (XSDNamedComponent component : objectsToBeCopied) {
this.typeForCopyThatIsUnderAnalysis = component;
final boolean isGlobal = isGlobal(component);
final XSDSchema schema = isGlobal ? null : targetSchema.getComponent();
// source in visit methods can be null only when call is from this
// method
String componenetName = component.getName();
if (component instanceof XSDElementDeclaration) {
if (debug)
Logger.getDebugTrace().trace("", "Begin copy Element " + componenetName); //$NON-NLS-1$ //$NON-NLS-2$
visitElementDeclaration((XSDElementDeclaration) component, schema);
if (debug)
Logger.getDebugTrace().trace("", "End copy Element " + componenetName); //$NON-NLS-1$ //$NON-NLS-2$
} else if (component instanceof XSDTypeDefinition) {
if (debug)
Logger.getDebugTrace().trace("", "Begin copy Type " + componenetName); //$NON-NLS-1$ //$NON-NLS-2$
visitTypeDefinition((XSDTypeDefinition) component, schema);
if (debug)
Logger.getDebugTrace().trace("", "End copy Type " + componenetName); //$NON-NLS-1$ //$NON-NLS-2$
} else if (component instanceof XSDAttributeDeclaration) {
if (debug)
Logger.getDebugTrace().trace("", "Begin copy Attribute " + componenetName); //$NON-NLS-1$ //$NON-NLS-2$
visitAttributeDeclaration((XSDAttributeDeclaration) component, schema);
if (debug)
Logger.getDebugTrace().trace("", "End copy Attribute " + componenetName); //$NON-NLS-1$ //$NON-NLS-2$
}
// update all the references to the target schema components
if (debug)
Logger.getDebugTrace().trace("", "Update references"); //$NON-NLS-1$ //$NON-NLS-2$
updateComponents();
if (debug)
Logger.getDebugTrace().trace("", "Refresh Schemas"); //$NON-NLS-1$ //$NON-NLS-2$
if (getModelRoot() instanceof IWsdlModelRoot) {
final Description description = (Description) ((IWsdlModelRoot) getModelRoot()).getDescription();
description.refreshSchemas();
}
if (isGlobal && clonedComponent != null) {
if (debug)
Logger.getDebugTrace().trace("", "Get the copied Type"); //$NON-NLS-1$ //$NON-NLS-2$
clone = (AbstractType) targetSchema.getType(clonedComponent instanceof XSDElementDeclaration,
clonedComponent.getName());
}
}
return Status.OK_STATUS;
}
private boolean isGlobal(final XSDNamedComponent component) {
final boolean debug = Logger.isDebugEnabled();
if (debug)
Logger.getDebugTrace().traceEntry(""); //$NON-NLS-1$
if (component instanceof XSDTypeDefinition)
return null != component.getName();
else if (component instanceof XSDElementDeclaration)
return ((XSDElementDeclaration) component).isGlobal();
else if (component instanceof XSDAttributeDeclaration)
return ((XSDAttributeDeclaration) component).isGlobal();
else if (component instanceof XSDAttributeGroupDefinition)
return !((XSDAttributeGroupDefinition) component).isAttributeGroupDefinitionReference();
else if (component instanceof XSDModelGroupDefinition)
return !((XSDModelGroupDefinition) component).isModelGroupDefinitionReference();
if (debug)
Logger.getDebugTrace().traceExit(""); //$NON-NLS-1$
return false;
}
public AbstractType getCopiedType() {
final boolean debug = Logger.isDebugEnabled();
if (debug)
Logger.getDebugTrace().traceEntry(""); //$NON-NLS-1$
if (debug)
Logger.getDebugTrace().traceExit(""); //$NON-NLS-1$
return clone;
}
private boolean visitAttributeGroup(final XSDAttributeGroupDefinition attributeGroup, final XSDSchema source) {
final boolean debug = Logger.isDebugEnabled();
if (debug)
Logger.getDebugTrace().traceEntry(""); //$NON-NLS-1$
XSDSchema copiedTo;
boolean needsUpdate = false;
XSDNamedComponent clone = null;
if (isGlobal(attributeGroup)) {
// check if attributeGroup already exists
if (debug)
Logger.getDebugTrace().trace("", "transversing Global AttributeGroup " + attributeGroup.getName()); //$NON-NLS-1$ //$NON-NLS-2$
final boolean copyToTarget = isTargetSchemaComponent(attributeGroup);
if (copyToTarget)
if (debug)
Logger.getDebugTrace().trace("", "source schema component"); //$NON-NLS-1$ //$NON-NLS-2$
final XSDAttributeGroupDefinition match = contains(attributeGroup, XSDAttributeGroupDefinition.class, copyToTarget);
if (null != match) {
if (debug)
Logger.getDebugTrace().trace("", "component already exists"); //$NON-NLS-1$ //$NON-NLS-2$
// return if source is null
if (null == source || (copyToTarget && source.equals(targetSchema.getComponent()))) {
return needsUpdate;
} else {
// ensure import and return, no need to transverse type here
ensureImport(source, copyToTarget ? targetSchema.getNamespace() : attributeGroup.getTargetNamespace(), null);
return needsUpdate;
}
} else {
if ((!copyToTarget) && ensureImport(source, attributeGroup.getTargetNamespace(), attributeGroup))
return needsUpdate;
}
// copy and create reference in source
copiedTo = createClone(attributeGroup, copyToTarget);
clone = _recentClone;
if (null != source)
ensureImport(source, copiedTo.getTargetNamespace(), null);
} else {
// this is a local element so we need to add imports to
// @localvar(source)
copiedTo = source;
}
if (attributeGroup.isAttributeGroupDefinitionReference()) {
final XSDAttributeGroupDefinition resolvedAttributeGroupDefinition = attributeGroup
.getResolvedAttributeGroupDefinition();
if (!(null == resolvedAttributeGroupDefinition || isSynthetic(resolvedAttributeGroupDefinition))) {
visitAttributeGroup(resolvedAttributeGroupDefinition, copiedTo);
needsUpdate = isTargetSchemaComponent(resolvedAttributeGroupDefinition);
}
} else {
if (visitAttributeGroupContent(attributeGroup.getContents(), copiedTo))
inconsistentClones.add(clone);
}
if (debug)
Logger.getDebugTrace().traceExit(""); //$NON-NLS-1$
return needsUpdate;
}
private boolean visitAttributeDeclaration(final XSDAttributeDeclaration attribute, final XSDSchema source) {
XSDSchema copiedTo;
boolean needsUpdate = false;
XSDNamedComponent clone = null;
if (isGlobal(attribute)) {
// check if attributeGroup already exists
final boolean copyToTarget = isTargetSchemaComponent(attribute);
final XSDAttributeDeclaration match = contains(attribute, XSDAttributeDeclaration.class, copyToTarget);
if (null != match) {
// return if source is null
if (null == source || (copyToTarget && source.equals(targetSchema.getComponent()))) {
return needsUpdate;
} else {
// ensure import and return, no need to transverse type here
ensureImport(source, copyToTarget ? targetSchema.getNamespace() : attribute.getTargetNamespace(), null);
return needsUpdate;
}
} else {
if ((!copyToTarget) && ensureImport(source, attribute.getTargetNamespace(), attribute))
return needsUpdate;
}
// copy and create reference in source
copiedTo = createClone(attribute, copyToTarget);
clone = _recentClone;
if (null != source)
ensureImport(source, copiedTo.getTargetNamespace(), null);
} else {
// this is a local element so we need to add imports to
// @localvar(source)
copiedTo = source;
}
XSDSimpleTypeDefinition typeDefinition = attribute.getAnonymousTypeDefinition();
boolean refersTargetComp = false;
if (null == typeDefinition) {
typeDefinition = attribute.getTypeDefinition();
// If an attribute refers to a target schema type and is global then
// add to inconsistencies
// else its local attribute tell the parent of this attribute to add
// itself
if ((!(null == typeDefinition || isSynthetic(typeDefinition))) && isTargetSchemaComponent(typeDefinition)) {
if (attribute.isGlobal()) {
inconsistentClones.add(clone);
refersTargetComp = true;
} else
needsUpdate = true;
}
}
if (!(null == typeDefinition || isSynthetic(typeDefinition))) {
refersTargetComp = visitTypeDefinition(typeDefinition, copiedTo);
// If an attribute has anonymous type that refers to a target schema
// type
// and if attribute is global then add to inconsistencies
// else its local attribute tell the parent of this attribute to add
// itself
if (refersTargetComp && null != attribute.getAnonymousTypeDefinition()) {
if (attribute.isGlobal()) {
inconsistentClones.add(clone);
} else
needsUpdate = true;
}
}
// process referred element declaration if exists
if (attribute.isAttributeDeclarationReference()) {
final XSDAttributeDeclaration resolvedAttribute = attribute.getResolvedAttributeDeclaration();
if (!(null == resolvedAttribute || isSynthetic(resolvedAttribute))) {
visitAttributeDeclaration(resolvedAttribute, copiedTo);
if (isTargetSchemaComponent(resolvedAttribute))
needsUpdate = true;
}
}
return needsUpdate;
}
private boolean visitElementDeclaration(final XSDElementDeclaration element, final XSDSchema source) {
XSDSchema copiedTo;
boolean needsUpdate = false;
XSDNamedComponent clone = null;
if (isGlobal(element)) {
// check if element already exists
final boolean copyToTarget = isTargetSchemaComponent(element);
final XSDElementDeclaration match = contains(element, XSDElementDeclaration.class, copyToTarget);
if (null != match) {
// return if source is null
if (!(null == source || (copyToTarget && source.equals(targetSchema.getComponent())))) {
// ensure import and return, no need to transverse type here
ensureImport(source, copyToTarget ? targetSchema.getNamespace() : element.getTargetNamespace(), null);
}
} else {
if (!copyToTarget) {
ensureImport(source, element.getTargetNamespace(), element);
}
}
// copy and create reference in source
copiedTo = createClone(element, copyToTarget);
clone = _recentClone;
if (null != source)
ensureImport(source, copiedTo.getTargetNamespace(), null);
} else {
// this is a local element so we need to add imports to
// @localvar(source)
copiedTo = source;
}
// process type definition if exists
XSDTypeDefinition typeDefinition = element.getAnonymousTypeDefinition();
boolean refersTargetComp = false;
if (null == typeDefinition) {
typeDefinition = element.getTypeDefinition();
// If an element refers to a target schema type and is global then
// add element to
// inconsistencies else if its local element tell the parent of this
// element to add itself
if ((!(null == typeDefinition || isSynthetic(typeDefinition))) && isTargetSchemaComponent(typeDefinition)) {
if (element.isGlobal()) {
inconsistentClones.add(clone);
refersTargetComp = true;
} else
needsUpdate = true;
}
}
if (!(null == typeDefinition || isSynthetic(typeDefinition))) {
refersTargetComp = visitTypeDefinition(typeDefinition, copiedTo);
// If an element has anonymous type that refers to a target schema
// type
// and if element is global then add element to inconsistencies
// else it is local element tell the parent of this element to add
// itself
if (refersTargetComp && null != element.getAnonymousTypeDefinition()) {
if (element.isGlobal()) {
inconsistentClones.add(clone);
} else
needsUpdate = true;
}
}
// process referred element declaration if exists
if (element.isElementDeclarationReference()) {
final XSDElementDeclaration resolvedElementDeclaration = element.getResolvedElementDeclaration();
if (!(null == resolvedElementDeclaration || isSynthetic(resolvedElementDeclaration))) {
visitElementDeclaration(resolvedElementDeclaration, copiedTo);
if (isTargetSchemaComponent(resolvedElementDeclaration))
needsUpdate = true;
}
}
return needsUpdate;
}
private boolean visitModelGroupDefinition(final XSDModelGroupDefinition modelGroupDefinition, final XSDSchema source) {
XSDSchema copiedTo;
boolean needsUpdate = false;
XSDNamedComponent clone = null;
if (isGlobal(modelGroupDefinition)) {
// check if element already exists
final boolean copyToTarget = isTargetSchemaComponent(modelGroupDefinition);
final XSDModelGroupDefinition match = contains(modelGroupDefinition, XSDModelGroupDefinition.class, copyToTarget);
if (null != match) {
// return if source is null
if (null == source || (copyToTarget && source.equals(targetSchema.getComponent()))) {
return needsUpdate;
} else {
// ensure import and return, no need to transverse type here
ensureImport(source, copyToTarget ? targetSchema.getNamespace() : modelGroupDefinition.getTargetNamespace(),
null);
return needsUpdate;
}
} else {
if ((!copyToTarget) && ensureImport(source, modelGroupDefinition.getTargetNamespace(), modelGroupDefinition))
return needsUpdate;
}
// copy and create reference in source
copiedTo = createClone(modelGroupDefinition, copyToTarget);
clone = _recentClone;
if (null != source)
ensureImport(source, copiedTo.getTargetNamespace(), null);
} else {
// this is a local element so we need to add imports to
// @localvar(source)
copiedTo = source;
}
if (modelGroupDefinition.isModelGroupDefinitionReference()) {
final XSDModelGroupDefinition resolvedModelGroupDefinition = modelGroupDefinition.getResolvedModelGroupDefinition();
if (!(null == resolvedModelGroupDefinition.eContainer() || isSynthetic(resolvedModelGroupDefinition))) {
visitModelGroupDefinition(resolvedModelGroupDefinition, copiedTo);
needsUpdate = isTargetSchemaComponent(resolvedModelGroupDefinition);
}
} else {
final XSDModelGroup content = modelGroupDefinition.getModelGroup();
if (null != content && visitModelGroup(content, copiedTo))
inconsistentClones.add(clone);
}
return needsUpdate;
}
private boolean visitTypeDefinition(final XSDTypeDefinition type, final XSDSchema source) {
if (null != type) {
if (XSDConstants.isSchemaForSchemaNamespace(type.getTargetNamespace()))
return false;
}
if (type instanceof XSDSimpleTypeDefinition) {
return visitSimpleTypeDefinition((XSDSimpleTypeDefinition) type, source);
} else {
return visitComplexTypeDefinition((XSDComplexTypeDefinition) type, source);
}
}
private boolean visitSimpleTypeDefinition(final XSDSimpleTypeDefinition simpleType, final XSDSchema source) {
XSDSchema copiedTo;
boolean needsUpdate = false;
XSDNamedComponent clone = null;
final boolean globalType = isGlobal(simpleType);
if (globalType) {
// check if element already exists
final boolean copyToTarget = isTargetSchemaComponent(simpleType);
final XSDSimpleTypeDefinition match = contains(simpleType, XSDSimpleTypeDefinition.class, copyToTarget);
if (null != match) {
// return if source is null
if (!(null == source || (copyToTarget && source.equals(targetSchema.getComponent())))) {
ensureImport(source, copyToTarget ? targetSchema.getNamespace() : simpleType.getTargetNamespace(), null);
}
} else {
if (!copyToTarget) {
ensureImport(source, simpleType.getTargetNamespace(), simpleType);
}
}
// copy and create reference in source
copiedTo = createClone(simpleType, copyToTarget);
clone = _recentClone;
if (null != source)
ensureImport(source, copiedTo.getTargetNamespace(), null);
} else {
// this is a local element so we need to add imports to
// @localvar(source)
copiedTo = source;
}
final Collection<XSDTypeDefinition> types = new ArrayList<XSDTypeDefinition>();
final XSDTypeDefinition baseType = simpleType.getBaseType();
if (null != baseType)
types.add(baseType);
for (final XSDSimpleTypeDefinition type : simpleType.getMemberTypeDefinitions()) {
types.add(type);
}
if (null != simpleType.getItemTypeDefinition())
types.add(simpleType.getItemTypeDefinition());
for (final XSDTypeDefinition type : types) {
if (!isSynthetic(type)) {
final boolean refersTargetComp = visitTypeDefinition(type, copiedTo);
final boolean isTargetComp = null == type.getName() ? false : isTargetSchemaComponent(type);
if (globalType && (isTargetComp || refersTargetComp)) {
inconsistentClones.add(clone);
} else if (!globalType && (isTargetComp || refersTargetComp)) {
needsUpdate = true;
}
}
}
return needsUpdate;
}
private boolean visitComplexTypeDefinition(final XSDComplexTypeDefinition complexType, final XSDSchema source) {
XSDSchema copiedTo;
boolean needsUpdate = false;
XSDNamedComponent clone = null;
final boolean globalType = isGlobal(complexType);
if (null != complexType.getName()) {
// check if element already exists
final boolean copyToTarget = isTargetSchemaComponent(complexType);
final XSDComplexTypeDefinition match = contains(complexType, XSDComplexTypeDefinition.class, copyToTarget);
if (null != match) {
// return if source is null
if (!(null == source || (copyToTarget && source.equals(targetSchema.getComponent())))) {
// ensure import and return, no need to transverse type here
ensureImport(source, copyToTarget ? targetSchema.getNamespace() : complexType.getTargetNamespace(), null);
}
} else {
if (!copyToTarget) {
ensureImport(source, complexType.getTargetNamespace(), complexType);
}
}
// copy and create reference in source
copiedTo = createClone(complexType, copyToTarget);
clone = _recentClone;
if (null != source)
ensureImport(source, copiedTo.getTargetNamespace(), null);
} else {
// this is a local element so we need to add imports to
// @localvar(source)
copiedTo = source;
}
// process content
final XSDComplexTypeContent content = complexType.getContent();
boolean refersTargetComp = false;
boolean isTargetComp = false;
if (content != null) {
if (content instanceof XSDParticle) {
final XSDParticle particle = (XSDParticle) content;
refersTargetComp = visitParticle(particle, copiedTo);
final XSDTypeDefinition baseType = complexType.getBaseType();
if (!(null == baseType || isSynthetic(baseType))) {
refersTargetComp |= visitTypeDefinition(baseType, copiedTo);
isTargetComp |= null == baseType.getName() ? false : isTargetSchemaComponent(baseType);
}
} else {
refersTargetComp |= visitSimpleTypeDefinition((XSDSimpleTypeDefinition) content, copiedTo);
}
}
final List<XSDAttributeGroupContent> attributeContents = complexType.getAttributeContents();
refersTargetComp |= visitAttributeGroupContent(attributeContents, copiedTo);
if (globalType && (isTargetComp || refersTargetComp)) {
inconsistentClones.add(clone);
} else if (!globalType && (isTargetComp || refersTargetComp)) {
needsUpdate = true;
}
return needsUpdate;
}
private boolean visitParticle(final XSDParticle particle, final XSDSchema source) {
final XSDParticleContent content = particle.getContent();
if (content instanceof XSDModelGroup) {
return visitModelGroup((XSDModelGroup) content, source);
} else if (content instanceof XSDElementDeclaration) {
return visitElementDeclaration((XSDElementDeclaration) content, source);
} else if (content instanceof XSDModelGroupDefinition) {
return visitModelGroupDefinition((XSDModelGroupDefinition) content, source);
}
return false;
}
private boolean visitModelGroup(final XSDModelGroup modelGroup, final XSDSchema source) {
final List<XSDParticle> particles = (modelGroup).getContents();
boolean refersTargetComp = false;
for (final XSDParticle particle : particles) {
refersTargetComp |= visitParticle(particle, source);
}
return refersTargetComp;
}
private boolean visitAttributeGroupContent(final Collection<XSDAttributeGroupContent> attributeContents,
final XSDSchema source) {
boolean refersTargetComp = false;
for (final XSDAttributeGroupContent attributeGroupContent : attributeContents) {
if (attributeGroupContent instanceof XSDAttributeGroupDefinition) {
refersTargetComp |= visitAttributeGroup((XSDAttributeGroupDefinition) attributeGroupContent, source);
continue;
}
final XSDAttributeUse attributeUse = (XSDAttributeUse) attributeGroupContent;
final XSDAttributeDeclaration attributeDeclaration = attributeUse.getContent();
if (null != attributeDeclaration) {
refersTargetComp |= visitAttributeDeclaration(attributeDeclaration, source);
}
}
return refersTargetComp;
}
private XSDNamedComponent _recentClone = null;
/**
* Creates a clone of given component in given schema and returns the clone
*
* @param <T>
* @param schema
* @param component
* @return
*/
private XSDSchema createClone(final XSDNamedComponent component, final boolean copyToTarget) {
final XSDSchema schema = copyToTarget ? targetSchema.getComponent() : ensureSchema(component.getTargetNamespace());
if (copiedComponents.contains(component)) {
return schema;
}
final XSDNamedComponent clone = EmfXsdUtils.cloneWithAnnotation(component, schema);
clone.setTargetNamespace(copyToTarget ? targetSchema.getNamespace() : component.getTargetNamespace());
if (copyToTarget)
inconsistentClones.add(clone);
// Set new name to the cloned component if its a source component
if (copyToTarget && component == objectsToBeCopied.get(0)) {
Assert.isTrue(null == clonedComponent);
clonedComponent = clone;
}
_recentClone = clone;
copiedComponents.add(component);
return schema;
}
private <T extends XSDNamedComponent> T contains(final XSDNamedComponent component, final Class<T> metaClass,
final boolean copyToTarget) {
final String namespace = component.getTargetNamespace();
final Collection<XSDSchema> schemas;
if (copyToTarget) {
schemas = new ArrayList<XSDSchema>(1);
schemas.add(targetSchema.getComponent());
} else {
// Get schemas with same namespace
schemas = CollectionTypeUtils.findAll(getInlineSchemas(), new Condition<XSDSchema>() {
public boolean isSatisfied(final XSDSchema in) {
return namespace != null && namespace.equals(in.getTargetNamespace());
}
});
}
// Check is type is visible in contained schemas or included schemas in
// contained schemas
T result = null;
for (final XSDSchema schema : schemas) {
result = contains(schema, component, new ArrayList<String>(), metaClass, copyToTarget);
if (null != result)
return result;
}
return result;
}
@SuppressWarnings("unchecked")
private <T extends XSDNamedComponent> T contains(final XSDSchema schema, final XSDNamedComponent component,
final Collection<String> locations, final Class<T> metaClass, final boolean copyToTarget) {
String name = component.getName();
final EList<XSDSchemaContent> contents = schema.getContents();
final ArrayList<XSDInclude> includes = new ArrayList<XSDInclude>();
for (final XSDSchemaContent schemaContent : contents) {
if (metaClass.isInstance(schemaContent)) {
if (name.equals(((XSDNamedComponent) schemaContent).getName())) {
return (T) schemaContent;
}
}
}
T result = null;
if (!copyToTarget) {
for (final XSDInclude include : includes) {
final XSDSchema includedSchema = include.getResolvedSchema();
if (null != includedSchema && !locations.contains(includedSchema.getSchemaLocation())) {
locations.add(includedSchema.getSchemaLocation());
result = contains(includedSchema, component, locations, metaClass, copyToTarget);
if (null != result)
return result;
}
}
}
return result;
}
private boolean ensureImport(final XSDSchema schema, final String nameSpace, final XSDNamedComponent component) {
if (null == component) {
// for cloned components or visible components using includes
if (schema.getTargetNamespace().equals(nameSpace))
return false;
final Collection<XSDImport> imports = EmfXsdUtils.filterComponents(schema.getContents(), XSDImport.class);
for (final XSDImport importObj : imports) {
if (nameSpace.equals(importObj.getNamespace()) && null == importObj.getSchemaLocation()) {
// Import already exists
return true;
}
}
// we need to add an import
final XSDImport xsdImport = XSDFactory.eINSTANCE.createXSDImport();
xsdImport.setNamespace(nameSpace);
schema.getContents().add(0, xsdImport);
return true;
} else {
// for components in schemas
final EObject parent = component.eContainer();
if (null != parent && parent instanceof XSDSchema) {
final String sourceTypeSchemaLocation = ((XSDSchema) parent).getSchemaLocation();
final String targetSchemaLocation = schema.getSchemaLocation();
String schemaRelativePath = ResourceUtils.constructURI(targetSchemaLocation, sourceTypeSchemaLocation).toString();
if (schemaRelativePath.length() == 0) {
schemaRelativePath = null;
}
XSDSchemaDirective directive = null;
if (null == nameSpace || nameSpace.equals(schema.getTargetNamespace())) {
final Collection<XSDInclude> includes = EmfXsdUtils.filterComponents(schema.getContents(), XSDInclude.class);
for (final XSDInclude include : includes) {
if (null != schemaRelativePath && schemaRelativePath.equals(include.getSchemaLocation())) {
// Include already exists
return true;
}
}
directive = XSDFactory.eINSTANCE.createXSDInclude();
} else {
final Collection<XSDImport> imports = EmfXsdUtils.filterComponents(schema.getContents(), XSDImport.class);
for (final XSDImport importObj : imports) {
if (nameSpace.equals(importObj.getNamespace())
&& (null != schemaRelativePath && schemaRelativePath.equals(importObj.getSchemaLocation()))) {
// Import already exists
return true;
}
}
directive = XSDFactory.eINSTANCE.createXSDImport();
((XSDImport) directive).setNamespace(nameSpace);
}
directive.setSchemaLocation(schemaRelativePath);
XSDSchema resolvedSchema = directive.getResolvedSchema();
if (resolvedSchema == null && this.parent instanceof Description) {
final List<Schema> resolvedSchemas = ((Description) this.parent).getSchemaResolver().resolveSchema(nameSpace,
null);
if (!resolvedSchemas.isEmpty()) {
resolvedSchema = resolvedSchemas.get(0).getComponent();
}
}
if (null == resolvedSchema) {
URI parentSchemaURI = null;
try {
parentSchemaURI = URIUtil.fromString(sourceTypeSchemaLocation);
} catch (final URISyntaxException e) {
throw new IllegalArgumentException(e);
}
resolvedSchema = EmfXsdUtils.resolveSchema(parentSchemaURI);
if (null != resolvedSchema) {
directive.setResolvedSchema(resolvedSchema);
schema.getContents().add(0, directive);
return true;
}
} else {
directive.setResolvedSchema(resolvedSchema);
schema.getContents().add(0, directive);
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
private XSDSchema ensureSchema(final String namespace) {
XSDSchema schema = schemasUsed.get(namespace);
if (null == schema) {
final Collection<XSDSchema> schemas = CollectionTypeUtils.findAll(getInlineSchemas(), new Condition<XSDSchema>() {
public boolean isSatisfied(final XSDSchema in) {
return namespace != null && namespace.equals(in.getTargetNamespace());
}
});
if (schemas.size() > 0) {
schema = schemas.iterator().next();
} else if (getModelRoot() instanceof IWsdlModelRoot) {
schema = EmfXsdUtils.getXSDFactory().createXSDSchema();
schema.setElementFormDefault(XSDForm.UNQUALIFIED_LITERAL);
schema.setAttributeFormDefault(XSDForm.UNQUALIFIED_LITERAL);
schema.setSchemaForSchemaQNamePrefix(EmfXsdUtils.XSD_PREFIX);
schema.setTargetNamespace(namespace);
final Map<String, String> qNamePrefixToNamespaceMap = schema.getQNamePrefixToNamespaceMap();
qNamePrefixToNamespaceMap.put(schema.getSchemaForSchemaQNamePrefix(), EmfXsdUtils.getSchemaForSchemaNS());
final XSDSchemaExtensibilityElement schemaExtensibilityEntity = EmfWsdlUtils.getWSDLFactory()
.createXSDSchemaExtensibilityElement();
schemaExtensibilityEntity.setSchema(schema);
final Description description = (Description) ((IWsdlModelRoot) getModelRoot()).getDescription();
final Definition definition = description.getComponent();
schema.setSchemaLocation(definition.getDocumentBaseURI());
final String xmlnsPrefix = generateXmlnsPrefix(definition.getNamespaces(), qNamePrefixToNamespaceMap);
qNamePrefixToNamespaceMap.put(xmlnsPrefix, namespace);
Types types = definition.getETypes();
if (types == null) {
types = EmfWsdlUtils.getWSDLFactory().createTypes();
definition.setTypes(types);
}
types.addExtensibilityElement(schemaExtensibilityEntity);
schemaExtensibilityEntity.setEnclosingDefinition(definition);
schema.updateElement();
schema.getDocument().normalizeDocument();
final String wsdlXmlnsPrefix = generateXmlnsPrefix(definition.getNamespaces(), qNamePrefixToNamespaceMap);
definition.addNamespace(wsdlXmlnsPrefix, namespace);
}
schemasUsed.put(namespace, schema);
}
return schema;
}
private boolean isTargetSchemaComponent(final XSDNamedComponent component) {
boolean copy = true;
final XSDSchema schema = component.getSchema();
Assert.isTrue(null != schema, "Components schema is null"); //$NON-NLS-1$
final XSDSchema sourceSchema = typeForCopyThatIsUnderAnalysis.getSchema();
Assert.isTrue(null != schema, "Source schema is null"); //$NON-NLS-1$
copy = schema.getSchemaLocation().equals(sourceSchema.getSchemaLocation());
copy &= (null == component.getTargetNamespace() && null == sourceSchema.getTargetNamespace())
|| (null != component.getTargetNamespace() && component.getTargetNamespace().equals(
sourceSchema.getTargetNamespace()));
return copy;
}
private boolean isSynthetic(final XSDNamedComponent component) {
return null == component.eContainer();
}
private static String generateXmlnsPrefix(final Map<String, String> wsdlNamespacesMap,
final Map<String, String> xsdNamespaceMap) {
for (int i = 0; i < 10000; i++) {
final String key = XMLNS_PREFIX_BASE + String.valueOf(i);
if (wsdlNamespacesMap.containsKey(key) || xsdNamespaceMap.containsKey(key)) {
continue;
}
return key;
}
throw new IllegalStateException("Cannot generate xmlns prefix"); //$NON-NLS-1$
}
private void updateComponents() {
// DOIT fix cyclic reference for name change
for (final XSDNamedComponent component : inconsistentClones) {
if (component instanceof XSDTypeDefinition)
updateComponent((XSDTypeDefinition) component);
else if (component instanceof XSDElementDeclaration)
updateComponent((XSDElementDeclaration) component);
else if (component instanceof XSDAttributeDeclaration)
updateComponent((XSDAttributeDeclaration) component);
else if (component instanceof XSDAttributeGroupDefinition)
updateComponent((XSDAttributeGroupDefinition) component);
else if (component instanceof XSDModelGroupDefinition)
updateComponent((XSDModelGroupDefinition) component);
}
}
private void updateComponent(final XSDAttributeDeclaration attribute) {
XSDSimpleTypeDefinition typeDefinition = attribute.getAnonymousTypeDefinition();
if (null == typeDefinition) {
typeDefinition = getTargetSchemaComponent(attribute.getTypeDefinition(), XSDSimpleTypeDefinition.class);
if (null != typeDefinition)
attribute.setTypeDefinition(typeDefinition);
} else
updateComponent(typeDefinition);
// process referred element declaration if exists
if (attribute.isAttributeDeclarationReference()) {
final XSDAttributeDeclaration resolvedAttribute = getTargetSchemaComponent(
attribute.getResolvedAttributeDeclaration(), XSDAttributeDeclaration.class);
if (null != resolvedAttribute)
attribute.setResolvedAttributeDeclaration(resolvedAttribute);
}
}
private void updateComponent(final XSDAttributeGroupDefinition attributeGroup) {
if (attributeGroup.isAttributeGroupDefinitionReference()) {
final XSDAttributeGroupDefinition attrGroup = getTargetSchemaComponent(
attributeGroup.getResolvedAttributeGroupDefinition(), XSDAttributeGroupDefinition.class);
if (null != attrGroup)
attributeGroup.setResolvedAttributeGroupDefinition(attrGroup);
} else {
updateComponent(attributeGroup.getContents());
}
}
private void updateComponent(final XSDModelGroupDefinition modelGroupDefinition) {
if (modelGroupDefinition.isModelGroupDefinitionReference()) {
final XSDModelGroupDefinition modelGroupDef = getTargetSchemaComponent(
modelGroupDefinition.getResolvedModelGroupDefinition(), XSDModelGroupDefinition.class);
if (null != modelGroupDef)
modelGroupDefinition.setResolvedModelGroupDefinition(modelGroupDef);
} else {
final XSDModelGroup modelGroup = modelGroupDefinition.getModelGroup();
if (null != modelGroup)
updateComponent(modelGroup);
}
}
private void updateComponent(final XSDModelGroup modelGroup) {
final List<XSDParticle> particles = (modelGroup).getContents();
for (final XSDParticle particle : particles) {
updateComponent(particle);
}
}
private void updateComponent(final XSDParticle particle) {
final XSDParticleContent content = particle.getContent();
if (content instanceof XSDModelGroup) {
updateComponent((XSDModelGroup) content);
} else if (content instanceof XSDElementDeclaration) {
updateComponent((XSDElementDeclaration) content);
} else if (content instanceof XSDModelGroupDefinition) {
updateComponent((XSDModelGroupDefinition) content);
}
}
private void updateComponent(final XSDSimpleTypeDefinition simpleType) {
final XSDSimpleTypeDefinition baseType = simpleType.getBaseTypeDefinition();
if (null != baseType && null == baseType.getName())
updateComponent(baseType);
else {
final XSDSimpleTypeDefinition type = getTargetSchemaComponent(baseType, XSDSimpleTypeDefinition.class);
if (null != type)
simpleType.setBaseTypeDefinition(type);
}
}
private void updateComponent(final XSDComplexTypeDefinition complexType) {
// process content
final XSDComplexTypeContent content = complexType.getContent();
if (content != null) {
if (content instanceof XSDParticle) {
final XSDParticle particle = (XSDParticle) content;
updateComponent(particle);
final XSDTypeDefinition baseType = complexType.getBaseTypeDefinition();
if (null != baseType && null == baseType.getName())
updateComponent(baseType);
else {
final XSDTypeDefinition type = getTargetSchemaComponent(baseType, XSDTypeDefinition.class);
if (null != type)
complexType.setBaseTypeDefinition(type);
}
} else {
updateComponent((XSDSimpleTypeDefinition) content);
final XSDTypeDefinition baseType = complexType.getBaseTypeDefinition();
if (null != baseType && null == baseType.getName())
updateComponent(baseType);
else {
final XSDTypeDefinition type = getTargetSchemaComponent(baseType, XSDTypeDefinition.class);
if (null != type)
complexType.setBaseTypeDefinition(type);
}
}
}
final List<XSDAttributeGroupContent> attributeContents = complexType.getAttributeContents();
updateComponent(attributeContents);
}
private void updateComponent(final List<XSDAttributeGroupContent> contents) {
for (final XSDAttributeGroupContent content : contents) {
if (content instanceof XSDAttributeUse) {
updateComponent(((XSDAttributeUse) content).getContent());
} else {
updateComponent((XSDAttributeGroupDefinition) content);
}
}
}
private void updateComponent(final XSDElementDeclaration element) {
// process referred element declaration if exists
if (element.isElementDeclarationReference()) {
final XSDElementDeclaration resolvedElementDeclaration = getTargetSchemaComponent(
element.getResolvedElementDeclaration(), XSDElementDeclaration.class);
if (null != resolvedElementDeclaration)
element.setResolvedElementDeclaration(resolvedElementDeclaration);
}
// process type definition if exists
XSDTypeDefinition typeDefinition = element.getAnonymousTypeDefinition();
if (null == typeDefinition) {
typeDefinition = getTargetSchemaComponent(element.getTypeDefinition(), XSDTypeDefinition.class);
if (null != typeDefinition)
element.setTypeDefinition(typeDefinition);
} else {
updateComponent(typeDefinition);
}
}
private void updateComponent(final XSDTypeDefinition type) {
if (type instanceof XSDSimpleTypeDefinition) {
updateComponent((XSDSimpleTypeDefinition) type);
} else {
updateComponent((XSDComplexTypeDefinition) type);
}
}
@SuppressWarnings("unchecked")
private <T extends XSDNamedComponent> T getTargetSchemaComponent(final XSDNamedComponent component,
final Class<T> componentType) {
if (null == component)
return null;
final String name = component.getName();
final String namespace = component.getTargetNamespace();
if (null != namespace && namespace.equals(typeForCopyThatIsUnderAnalysis.getSchema().getTargetNamespace())) {
final XSDSchema schema = targetSchema.getComponent();
for (final XSDSchemaContent content : schema.getContents()) {
if (componentType.isInstance(content) && name.equals(((XSDNamedComponent) content).getName())) {
return (T) content;
}
}
}
return null;
}
public void updateReferences(final XSDNamedComponent component) {
inconsistentClones.add(component);
}
@Override
public boolean canRedo() {
return true;
}
@Override
public boolean canUndo() {
return true;
}
}