/******************************************************************************* * 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. *******************************************************************************/ package org.eclipse.wst.sse.sieditor.model.xsd.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.workspace.AbstractEMFOperation; import org.eclipse.xsd.XSDAnnotation; import org.eclipse.xsd.XSDAttributeGroupContent; import org.eclipse.xsd.XSDAttributeUse; import org.eclipse.xsd.XSDComplexTypeContent; import org.eclipse.xsd.XSDComplexTypeDefinition; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDDerivationMethod; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDModelGroup; import org.eclipse.xsd.XSDNamedComponent; import org.eclipse.xsd.XSDParticle; import org.eclipse.xsd.XSDParticleContent; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSimpleTypeDefinition; import org.eclipse.xsd.XSDTypeDefinition; import org.eclipse.wst.sse.sieditor.command.emf.xsd.AddElementCommand; import org.eclipse.wst.sse.sieditor.command.emf.xsd.CopyElementCommand; import org.eclipse.wst.sse.sieditor.command.emf.xsd.DeleteElementCommand; import org.eclipse.wst.sse.sieditor.command.emf.xsd.RenameStructureTypeCommand; import org.eclipse.wst.sse.sieditor.command.emf.xsd.SetBaseTypeCommand; import org.eclipse.wst.sse.sieditor.command.emf.xsd.SetStructureTypeCommand; import org.eclipse.wst.sse.sieditor.core.common.Nil; import org.eclipse.wst.sse.sieditor.model.api.IModelObject; import org.eclipse.wst.sse.sieditor.model.api.IXSDModelRoot; import org.eclipse.wst.sse.sieditor.model.generic.DuplicateException; import org.eclipse.wst.sse.sieditor.model.generic.IllegalInputException; import org.eclipse.wst.sse.sieditor.model.impl.ModelChangeEvent; import org.eclipse.wst.sse.sieditor.model.utils.EmfXsdUtils; import org.eclipse.wst.sse.sieditor.model.xsd.api.IElement; import org.eclipse.wst.sse.sieditor.model.xsd.api.IStructureType; import org.eclipse.wst.sse.sieditor.model.xsd.api.IType; public class StructureType extends AbstractType implements IStructureType, org.eclipse.wst.sse.sieditor.model.write.xsd.api.IStructureType { public StructureType(final IXSDModelRoot modelRoot, final Schema schema, final XSDNamedComponent component) { this(modelRoot, schema, schema, component); } public StructureType(final IXSDModelRoot modelRoot, final Schema schema, final IModelObject parent, final XSDNamedComponent component) { super(modelRoot, component, schema, parent); if (!(component instanceof XSDElementDeclaration || component instanceof XSDComplexTypeDefinition)) { throw new RuntimeException("Component must be either XSDElementDeclaration or XSDComplexTypeDefinition"); //$NON-NLS-1$ } final XSDElementDeclaration _element = component instanceof XSDElementDeclaration ? (XSDElementDeclaration) component : null; if (null == _element) Assert.isTrue(component instanceof XSDComplexTypeDefinition); } public String getDocumentation() { final List<XSDAnnotation> annotations = new ArrayList<XSDAnnotation>(1); XSDAnnotation annotation = null; if (getComponent() instanceof XSDElementDeclaration) { annotation = ((XSDElementDeclaration) getComponent()).getAnnotation(); } else if (getComponent() instanceof XSDComplexTypeDefinition) { annotation = ((XSDTypeDefinition) getComponent()).getAnnotation(); } if (null != annotation) annotations.add(annotation); if (annotations.size() == 0) return ""; //$NON-NLS-1$ final org.w3c.dom.Element documentation = getFirstElement(annotations); return super.getDocumentation(documentation); } public IType getBaseType() { return getBaseType(getComponent(), getSchema()); } static IType getBaseType(final XSDConcreteComponent component, final Schema schema) { // deliberately not using the following line in order to preserve the // checks from the prev. implementation // XSDTypeDefinition baseType = getXSDTypeDefinition().getBaseType(); XSDTypeDefinition baseType = null; if (component instanceof XSDElementDeclaration) { final XSDTypeDefinition type = ((XSDElementDeclaration) component).getType(); if (type == null || type.getName() != null) { return null; } baseType = type.getBaseType(); } else if (component instanceof XSDComplexTypeDefinition) { baseType = ((XSDTypeDefinition) component).getBaseType(); } if (baseType == null) { return null; } // If type is not set which will not be the case, as the type will be // anyType return (IType) schema.resolveComponent(baseType, true); } public void setType(final IType type) throws ExecutionException { // if (null == _element) // return; IType resolvedType = null; if (type instanceof AbstractType) resolvedType = getSchema().resolveType((AbstractType) type); // DOIT Import if needed if (null != resolvedType && resolvedType.getComponent() instanceof XSDTypeDefinition) { final SetStructureTypeCommand command = new SetStructureTypeCommand(getModelRoot(), this, resolvedType); getModelRoot().getEnv().execute(command); } } public void setBaseType(final IType baseType) throws ExecutionException { /* * IType resolvedType = null; if (baseType instanceof AbstractType) * resolvedType = _schema.resolveType((AbstractType) baseType); * * if (null == resolvedType || ((AbstractType) * resolvedType).getComponent() instanceof XSDElementDeclaration) * return; */ final SetBaseTypeCommand command = new SetBaseTypeCommand(getModelRoot(), this, baseType); getModelRoot().getEnv().execute(command); } public Collection<IElement> getAllElements() { final List<IElement> elements = new ArrayList<IElement>(); final XSDTypeDefinition xsdTypeDefinition = getXSDTypeDefinition(); if (null != getElement() && (null == xsdTypeDefinition || xsdTypeDefinition instanceof XSDSimpleTypeDefinition || null != xsdTypeDefinition .getName())) { return Collections.emptyList(); } elements.addAll(processType((XSDComplexTypeDefinition) xsdTypeDefinition)); elements.addAll(processAttributeGroupContent((XSDComplexTypeDefinition) xsdTypeDefinition)); return elements; } private List<Element> processType(final XSDComplexTypeDefinition type) { final XSDComplexTypeContent content = type.getContent(); if (content instanceof XSDParticle) { final XSDParticle particle = (XSDParticle) content; final XSDParticleContent particleContent = particle.getContent(); if (particleContent instanceof XSDModelGroup) { return processModelGroup((XSDModelGroup) particleContent); } } return new ArrayList<Element>(); } private List<Element> processParticle(final XSDParticle particle, final XSDModelGroup container) { final XSDParticleContent content = particle.getContent(); if (content instanceof XSDModelGroup) return processModelGroup((XSDModelGroup) content); else if (content instanceof XSDElementDeclaration) { final List<Element> elements = new ArrayList<Element>(1); Element element = null; element = new Element(getModelRoot(), particle, container, this, getSchema()); elements.add(element); return elements; } return new ArrayList<Element>(); } private List<Element> processModelGroup(final XSDModelGroup modelGroup) { final List<XSDParticle> particles = modelGroup.getParticles(); final List<Element> result = new ArrayList<Element>(1); for (final XSDParticle particle : particles) { result.addAll(processParticle(particle, modelGroup)); } return result; } private List<Element> processAttributeGroupContent(final XSDComplexTypeDefinition type) { final List<XSDAttributeGroupContent> contents = type.getAttributeContents(); final List<Element> result = new ArrayList<Element>(contents.size()); for (final XSDAttributeGroupContent content : contents) { if (content instanceof XSDAttributeUse) { result.add(new Element(getModelRoot(), ((XSDAttributeUse) content).getContent(), null, this, getSchema())); } } return result; } public Collection<IElement> getElements(final String name) { final Collection<IElement> result = new ArrayList<IElement>(1); final Collection<IElement> elements = getAllElements(); if (name != null) { for (final IElement element : elements) { if (name.equals(element.getName())) { result.add(element); } } } return result; } public IElement addElement(final String name) throws IllegalInputException, ExecutionException { Nil.checkNil(name, "name"); //$NON-NLS-1$ if (!EmfXsdUtils.isValidNCName(name)) throw new IllegalInputException("Entered element name is not valid"); //$NON-NLS-1$ final AddElementCommand command = new AddElementCommand(getModelRoot(), this, name); getModelRoot().getEnv().execute(command); return command.getElement(); } public IElement copyElement(final IElement element) throws IllegalInputException, ExecutionException { Nil.checkNil(element, "element"); //$NON-NLS-1$ if (element instanceof Element) { final CopyElementCommand command; command = new CopyElementCommand(getModelRoot(), this, element, getSchema()); getModelRoot().getEnv().execute(command); return command.getCopiedElement(); } return null; } public void removeElement(final IElement element) throws ExecutionException { Nil.checkNil(element, "element"); //$NON-NLS-1$ final List<IElement> elements = (List<IElement>) getAllElements(); final int position = elements.indexOf(element); if (-1 != position) { final Element match = (Element) elements.get(position); getModelRoot().getEnv().execute(new DeleteElementCommand(getModelRoot(), this, match)); } } public void removeElement(final String name) throws ExecutionException { Nil.checkNil(name, "name"); //$NON-NLS-1$ final Collection<IElement> elements = getAllElements(); for (final IElement element : elements) { if (name.equals(element.getName())) { final DeleteElementCommand command = new DeleteElementCommand(getModelRoot(), this, element); getModelRoot().getEnv().execute(command); } } // notify listeners only once getModelRoot().notifyListeners(new ModelChangeEvent(this)); } public boolean isElement() { return getComponent() instanceof XSDElementDeclaration; } public boolean isComplexTypeSimpleContent() { if (isElement()) { final XSDElementDeclaration xsdElementDeclaration = (XSDElementDeclaration) getComponent(); if (xsdElementDeclaration.getType() == null) { return false; } final XSDTypeDefinition baseType = xsdElementDeclaration.getType().getBaseType(); if (baseType instanceof XSDSimpleTypeDefinition) { return true; } return isComplexTypeSimpleContentInternal((XSDComplexTypeDefinition) baseType, new HashSet<XSDTypeDefinition>()); } else { final XSDComplexTypeDefinition xsdComplexType = (XSDComplexTypeDefinition) getComponent(); return isComplexTypeSimpleContentInternal(xsdComplexType, new HashSet<XSDTypeDefinition>()); } } private boolean isComplexTypeSimpleContentInternal(final XSDComplexTypeDefinition xsdComplexType, final Collection<XSDTypeDefinition> visited) { if (xsdComplexType == null) { return false; } final XSDTypeDefinition baseType = xsdComplexType.getBaseType(); if (baseType instanceof XSDSimpleTypeDefinition) { return xsdComplexType.getDerivationMethod() == XSDDerivationMethod.EXTENSION_LITERAL; } else if (baseType instanceof XSDComplexTypeDefinition && !visited.contains(baseType)) { visited.add(baseType); return xsdComplexType.getDerivationMethod() == XSDDerivationMethod.EXTENSION_LITERAL && isComplexTypeSimpleContentInternal((XSDComplexTypeDefinition) baseType, visited); } return false; } public Schema getSchema() { return (Schema) getParent(); } public void setName(final String name) throws IllegalInputException, DuplicateException, ExecutionException { Nil.checkNil(name, "name"); //$NON-NLS-1$ if (!EmfXsdUtils.isValidNCName(name)) { throw new IllegalInputException("Entered Type name '" + name + "' is not valid"); //$NON-NLS-1$ //$NON-NLS-2$ } final XSDSchema schema = getSchema().getComponent(); if (isElement()) { if (schema.resolveElementDeclaration(name).eContainer() != null) { throw new DuplicateException("Element with name '" + name + "' already exists"); //$NON-NLS-1$ //$NON-NLS-2$ } } else { if (schema.resolveTypeDefinition(name).eContainer() != null) { throw new DuplicateException("Type with name '" + name + "' already exists"); //$NON-NLS-1$ //$NON-NLS-2$ } } final AbstractEMFOperation command = new RenameStructureTypeCommand(getModelRoot(), this, name); getModelRoot().getEnv().execute(command); } /* * public org.w3c.dom.Element setDocumentation(String description) throws * ExecutionException { Nil.checkNil(description, "description"); * //$NON-NLS-1$ XSDAnnotation annotation = null; if (null != _element) { * annotation = _element.getAnnotation(); if (null == annotation) { * AddAnotationCommand command = new AddAnotationCommand(_element, * getModelRoot(), this); if * (getModelRoot().getEnv().execute(command).isOK()) { annotation = * command.getAnnotation(); } } } else { annotation = _type.getAnnotation(); * if (null == annotation) { AddAnotationCommand command = new * AddAnotationCommand(_type, getModelRoot(), this); if * (getModelRoot().getEnv().execute(command).isOK()) { annotation = * command.getAnnotation(); } } } super.setDocumentation(annotation, * description); return null; } */ public void setNamespace(final String namespace) { // Do Nothing } public IType getType() { // not sure about the following condition if (getComponent() instanceof XSDTypeDefinition) { return null; } if (!(getComponent() instanceof XSDElementDeclaration)) { return null; } final XSDElementDeclaration element = (XSDElementDeclaration) getComponent(); XSDTypeDefinition type = element.getAnonymousTypeDefinition(); if (type != null) { // type is anonymous if (type instanceof XSDComplexTypeDefinition) { return new StructureType(getModelRoot(), getSchema(), this, type); } return new SimpleType(getModelRoot(), getSchema(), this, (XSDSimpleTypeDefinition) type); } type = element.getTypeDefinition(); if (null == type) { return null; } return (IType) getSchema().resolveComponent(type, true); } public static boolean isGlobalElement(final IType type) { return (type instanceof IStructureType) && ((IStructureType) type).isElement(); } public boolean isNillable() { final XSDElementDeclaration element = getElement(); if (element != null) { return element.isNillable(); } return false; } public XSDElementDeclaration getElement() { return getComponent() instanceof XSDElementDeclaration ? (XSDElementDeclaration) getComponent() : null; } public XSDTypeDefinition getXSDTypeDefinition() { final XSDElementDeclaration element = getElement(); return element == null ? (XSDComplexTypeDefinition) getComponent() : element.getType(); } }