/******************************************************************************* * 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.wsdl; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; import org.eclipse.core.commands.ExecutionException; 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.wst.wsdl.Definition; import org.eclipse.wst.wsdl.Part; import org.eclipse.wst.wsdl.util.WSDLConstants; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDNamedComponent; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDTypeDefinition; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.eclipse.wst.sse.sieditor.command.common.AbstractCompositeNotificationOperation; import org.eclipse.wst.sse.sieditor.command.common.AbstractNotificationOperation; import org.eclipse.wst.sse.sieditor.command.common.AbstractWSDLNotificationOperation; import org.eclipse.wst.sse.sieditor.core.common.Logger; import org.eclipse.wst.sse.sieditor.model.Activator; 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.i18n.Messages; import org.eclipse.wst.sse.sieditor.model.search.DocumentType; 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.URIHelper; import org.eclipse.wst.sse.sieditor.model.wsdl.api.IDescription; import org.eclipse.wst.sse.sieditor.model.wsdl.api.IParameter; import org.eclipse.wst.sse.sieditor.model.wsdl.impl.Description; import org.eclipse.wst.sse.sieditor.model.wsdl.impl.OperationParameter; import org.eclipse.wst.sse.sieditor.model.xsd.api.ISchema; import org.eclipse.wst.sse.sieditor.model.xsd.api.IType; import org.eclipse.wst.sse.sieditor.model.xsd.impl.AbstractType; /** * Command for setting a parameter type * * */ public class SetParameterTypeCommand extends AbstractCompositeNotificationOperation { private final IType newType; private final IParameter parameter; public SetParameterTypeCommand(final IParameter parameter, final IType newType) { this(parameter.getModelRoot(), parameter, newType); } public SetParameterTypeCommand(final IModelRoot root, final IParameter parameter, final IType newType) { super(root, parameter, Messages.SetParameterTypeCommand_set_parameter_type_command_label); this.parameter = parameter; this.newType = newType; setTransactionPolicy(TransactionPolicy.MULTI); } @Override public AbstractNotificationOperation getNextOperation(final List<AbstractNotificationOperation> subOperations) { final IWsdlModelRoot wsdlModelRoot = (IWsdlModelRoot) root; if (subOperations.isEmpty()) { if (newType == null) { SetParameterTypeWithoutImportingCommand.sendTypeIsNull(modelObject); return null; } final IDescription description = wsdlModelRoot.getDescription(); final String errorMessage = "Failed to resolve type"; //$NON-NLS-1$ try { return new ImportSchemaCommand(wsdlModelRoot, description, URIHelper.createEncodedURI(description.getLocation()), URIHelper.createEncodedURI(newType.getParent().getComponent().getSchemaLocation()), (AbstractType) newType, DocumentType.XSD_SHEMA); } catch (final UnsupportedEncodingException e) { Logger.logError(errorMessage, e); } catch (final URISyntaxException e) { Logger.logError(errorMessage, e); } } else if (subOperations.size() == 1) { return new SetParameterTypeWithoutImportingCommand(wsdlModelRoot, parameter, newType); } return null; } private static class SetParameterTypeWithoutImportingCommand extends AbstractWSDLNotificationOperation { private final IType newType; private final IType oldType; private String xsdSchemaPrefix = null; private boolean emptyDefaultNSAdded; public SetParameterTypeWithoutImportingCommand(final IWsdlModelRoot root, final IParameter parameter, final IType newType) { super(root, parameter, Messages.SetParameterTypeCommand_set_parameter_type_command_label); this.newType = newType; this.oldType = parameter.getType(); emptyDefaultNSAdded = false; } protected static void sendTypeIsNull(final IModelObject modelObject) { final OperationParameter parameter = (OperationParameter) modelObject; final Part part = parameter.getComponent(); part.setElementDeclaration(null); part.setElementName(null); part.setTypeDefinition(null); part.setTypeName(null); } @Override public IStatus run(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException { return setType(monitor, info, newType); } private IStatus setType(final IProgressMonitor monitor, final IAdaptable info, final IType type) throws ExecutionException { if (type == null) { SetParameterTypeWithoutImportingCommand.sendTypeIsNull(modelObject); return Status.OK_STATUS; } // if both the type's schema targetNamespace and the Definition's // are null // then add an xmlns="" attribute to the definitions, in order for // the type // reference without prefix to be resolvable. if (type.getComponent().getTargetNamespace() == null) { final Definition definitions = ((Description) root.getModelObject()).getComponent(); final String EMPTY_STRING = "";//$NON-NLS-1$ if (definitions.getNamespace(EMPTY_STRING) == null) { definitions.getElement().setAttribute(EmfXsdUtils.XMLNS_PREFIX, EMPTY_STRING); emptyDefaultNSAdded = true; } } final OperationParameter parameter = (OperationParameter) modelObject; final Part part = parameter.getComponent(); final XSDNamedComponent typeToBeReferenced = type.getComponent(); // final NamedNodeMap partDomAttributes = // part.getElement().getAttributes(); final Definition definition = part.getEnclosingDefinition(); final String targetNamespace = typeToBeReferenced.getTargetNamespace(); final QName typeQname = new QName(/* * null == targetNamespace ? * definition.getTargetNamespace() * : */targetNamespace, typeToBeReferenced.getName()); if (definition.getPrefix(targetNamespace) == null) { EmfWsdlUtils.ensurePrefix(definition, targetNamespace); xsdSchemaPrefix = definition.getPrefix(targetNamespace); updateImportedSchemas(targetNamespace); } if (typeToBeReferenced instanceof XSDTypeDefinition) { if (part.getElementDeclaration() != null || part.getElement().hasAttribute(WSDLConstants.ELEMENT_ATTRIBUTE)) { part.getElement().getAttributes().removeNamedItem(WSDLConstants.ELEMENT_ATTRIBUTE); } final XSDTypeDefinition typeDefinition = (XSDTypeDefinition) typeToBeReferenced; part.setTypeName(typeQname); part.setTypeDefinition(typeDefinition); return Status.OK_STATUS; } else if (typeToBeReferenced instanceof XSDElementDeclaration) { if (part.getTypeDefinition() != null || part.getElement().hasAttribute(WSDLConstants.TYPE_ATTRIBUTE)) { part.getElement().getAttributes().removeNamedItem(WSDLConstants.TYPE_ATTRIBUTE); } final XSDElementDeclaration elementDeclaration = (XSDElementDeclaration) typeToBeReferenced; part.setElementDeclaration(elementDeclaration); part.setElementName(typeQname); return Status.OK_STATUS; } return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SetParameterTypeCommand_msg_only_definitions_and_element_can_be_referenced); } private void updateImportedSchemas(final String tns) { final IWsdlModelRoot wsdlRoot = getModelRoot(); final List<ISchema> containedSchemas = wsdlRoot.getDescription().getContainedSchemas(); for (final ISchema schema : containedSchemas) { if (schema.getNamespace() != null) { continue; } final Collection<ISchema> allReferredSchemas = schema.getAllReferredSchemas(); for (final ISchema referredSchema : allReferredSchemas) { if (tns == null || !tns.equals(referredSchema.getNamespace())) { continue; } final XSDSchema xsdSchema = schema.getComponent(); final Element shemaElement = xsdSchema.getElement(); if (shemaElement != null) { xsdSchema.elementChanged(shemaElement); } break; } } } @Override protected IStatus doRedo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException { return run(monitor, info); } @Override protected IStatus doUndo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException { if (emptyDefaultNSAdded) { // if the command added an xmlns="" attribute to definitions final Definition definitions = ((Description) root.getModelObject()).getComponent(); definitions.addNamespace(null, null); // This is workaround for a bug in the eclipse definitions api: definitions.getElement().removeAttribute(EmfXsdUtils.XMLNS_PREFIX); } if (xsdSchemaPrefix != null) { final Definition definition = ((Description) root.getModelObject()).getComponent(); definition.addNamespace(xsdSchemaPrefix, null); final Element element = definition.getElement(); final NamedNodeMap partDomAttributes = element.getAttributes(); final String qname = EmfXsdUtils.XMLNS_PREFIX + ":" + xsdSchemaPrefix; //$NON-NLS-1$ if (partDomAttributes.getNamedItem(qname) != null) { partDomAttributes.removeNamedItem(qname); } } return setType(monitor, info, oldType); } @Override public boolean canExecute() { return newType != null && newType instanceof AbstractType; } } }