| /******************************************************************************* |
| * 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; |
| } |
| } |