/*******************************************************************************
* 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.model.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.eclipse.core.resources.IFile;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceFactoryRegistryImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.wsdl.Definition;
import org.eclipse.wst.wsdl.Fault;
import org.eclipse.wst.wsdl.Operation;
import org.eclipse.wst.wsdl.Part;
import org.eclipse.wst.wsdl.PortType;
import org.eclipse.wst.wsdl.Types;
import org.eclipse.wst.wsdl.WSDLElement;
import org.eclipse.wst.wsdl.WSDLFactory;
import org.eclipse.wst.wsdl.WSDLPackage;
import org.eclipse.wst.wsdl.XSDSchemaExtensibilityElement;
import org.eclipse.wst.wsdl.internal.util.WSDLResourceFactoryImpl;
import org.eclipse.wst.wsdl.util.WSDLResourceImpl;
import org.eclipse.wst.xml.core.internal.document.DocumentImpl;
import org.eclipse.wst.xml.core.internal.document.XMLModelNotifier;
import org.eclipse.xsd.XSDAnnotation;
import org.eclipse.xsd.XSDConcreteComponent;
import org.eclipse.xsd.XSDImport;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDSchemaContent;
import org.eclipse.xsd.util.XSDResourceFactoryImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.eclipse.wst.sse.sieditor.model.XMLModelNotifierWrapper;
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.wsdl.api.IDescription;
import org.eclipse.wst.sse.sieditor.model.wsdl.api.IFault;
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.xsd.api.ISchema;
/**
* EMF WSDL Utils
*
*
*/
public final class EmfWsdlUtils {
private static final String NAMESPACE_PREFIX_PREFIX = "ns"; //$NON-NLS-1$
private EmfWsdlUtils() {
// Stop any instance creation
}
/**
* Returns a {@link WSDLFactory} class for creating EMF WSDL Objects
*
* @return
*/
public static WSDLFactory getWSDLFactory() {
return WSDLFactory.eINSTANCE;
}
public static String makeMessageName(final String name, final String suffix, final Definition definition) {
int counter = 1;
final String opName = name + suffix;
QName qName = new QName(definition.getTargetNamespace(), opName);
while (true) {
if (null == definition.getMessage(qName) || counter == 0) {
if (counter == 0)
throw new IllegalStateException("Message Numbers limit reached"); //$NON-NLS-1$
break;
}
qName = new QName(definition.getTargetNamespace(), opName + counter++);
}
return qName.getLocalPart();
}
/**
* Return {@link WSDLPackage} instance for accessing all the EMF proxy
* classes
*
* @return
*/
public static WSDLPackage getWSDLPackage() {
return getWSDLFactory().getWSDLPackage();
}
/**
* Returns respt. {@link Definition} object for a given WSDL {@link IFile}
*
* @param file
* @return
*/
public static final Definition resolveWSDL(final java.net.URI uri) {
final URI emfUri = URI.createURI(uri.toString());
final ResourceSet rs = new ResourceSetImpl();
final WSDLResourceImpl wsdlr = (WSDLResourceImpl) rs.getResource(emfUri, true);
return wsdlr.getDefinition();
}
public static void applyFileExtensionForWSDLToResourceSet(final ResourceSet resourceSet, final String fileExtension) {
final Resource.Factory.Registry reg = resourceSet.getResourceFactoryRegistry();
final Map<String, Object> currentMap = reg.getExtensionToFactoryMap();
currentMap.put(fileExtension, new WSDLResourceFactoryImpl());
if ("xsd".equalsIgnoreCase(fileExtension)) { //$NON-NLS-1$
currentMap.put(fileExtension, new XSDResourceFactoryImpl());
}
}
public static ResourceSet getResourceSet() {
final ResourceSet resourceSet = new ResourceSetImpl();
final Resource.Factory.Registry reg = new ResourceFactoryRegistryImpl();
final Resource.Factory.Registry globalReg = Resource.Factory.Registry.INSTANCE;
final Map<String, Object> globalMap = globalReg.getExtensionToFactoryMap();
final Map<String, Object> newMap = new HashMap<String, Object>(globalMap);
reg.getExtensionToFactoryMap().putAll(newMap);
resourceSet.setResourceFactoryRegistry(reg);
return resourceSet;
}
/**
* Check whether the schema is just used to import another schema.
* http://ws-i.org/profiles/BasicProfile-1.2-WGD.html#WSDL_and_Schema_Import
* - R2105 All xsd:schema elements contained in a wsdl:types element of a
* DESCRIPTION MUST have a targetNamespace attribute with a valid and
* non-null value, UNLESS the xsd:schema element has xsd:import and/or
* xsd:annotation as its only child element(s).
*
* @return empty list if schema is not WS-I R2105, otherwise schema's
* imports are returned.
*/
public static List<XSDImport> getWsiImports(final XSDSchema schema) {
final List<XSDImport> importedSchemas = new ArrayList<XSDImport>();
if (schema == null || schema.getTargetNamespace() != null && !"".equals(schema.getTargetNamespace())) { //$NON-NLS-1$
return importedSchemas;
}
for (final XSDSchemaContent schemaContent : schema.getContents()) {
if (!(schemaContent instanceof XSDAnnotation) && !(schemaContent instanceof XSDImport)) {
// not WS-I R2105 complaint schema
importedSchemas.clear();
return importedSchemas;
}
if (schemaContent instanceof XSDImport) {
importedSchemas.add((XSDImport) schemaContent);
}
}
return importedSchemas;
}
/**
* Ensures a prefix exists on {@link Definition} for given namespace
*
* @param definition
* @param namespace
*/
public static void ensurePrefix(final Definition definition, final String namespace) {
if (isPrefixMissing(definition, namespace)) {
final String nsPrefix = generateNewNSAttribute(definition);
definition.addNamespace(nsPrefix, namespace);
}
}
/**
* A boolean expression determining if a prefix for this namespace exists in
* the definitions element.
*
* @param definition
* the definitions in which the ns will be searched
* @param namespace
* the namespace to find
* @return true if an ns prefix is defined, false otherwise
*/
public static boolean isPrefixMissing(final Definition definition, final String namespace) {
return !(namespace == null || namespace.trim().length() == 0 || definition.getPrefix(namespace) != null);
}
/**
* Generates a new unique xmlns:xxx namespace prefix for the given
* definition
*
* @param definition
* for which the prefix is generated
* @return the newly generated attribute name
*/
public static String generateNewNSAttribute(final Definition definition) {
return generateNewNSAttribute(definition.getNamespaces());
}
/**
* Generates new xmlns:xxx namespace prefix for the given map of such
*/
public static String generateNewNSAttribute(final Map<String, String> namespaceMap) {
for (int i = 0; i >= 0 && i < 10000; i++) {
final String prefix = new StringBuilder(NAMESPACE_PREFIX_PREFIX).append(i).toString();
if (!namespaceMap.containsKey(prefix)) {
return prefix;
}
}
// This point should never be reachable
throw new IllegalStateException(String.format("Cannot ensure unique prefix in WSDL document")); //$NON-NLS-1$
}
/**
* Adds a new EMF {@link XSDSchema} in {@link Definition} with the specified
* namespace
*
* @param definition
* - wsdl where new schema is to be added
* @param namespace
* - namespace of the new schema
* @return - added schema object
*/
public static XSDSchema addXSDSchema(final Definition definition, final String namespace) {
Types types = definition.getETypes();
if (null == types) {
types = EmfWsdlUtils.getWSDLFactory().createTypes();
definition.setTypes(types);
}
final XSDSchema xsdSchema = EmfXsdUtils.getXSDFactory().createXSDSchema();
xsdSchema.setSchemaForSchemaQNamePrefix(EmfXsdUtils.XSD_PREFIX); //$NON-NLS-1$
final Map<String, String> qNamePrefixToNamespaceMap = xsdSchema.getQNamePrefixToNamespaceMap();
qNamePrefixToNamespaceMap.put(xsdSchema.getSchemaForSchemaQNamePrefix(), EmfXsdUtils.getSchemaForSchemaNS());
final XSDSchemaExtensibilityElement schemaExtensibilityEntity = EmfWsdlUtils.getWSDLFactory()
.createXSDSchemaExtensibilityElement();
schemaExtensibilityEntity.setSchema(xsdSchema);
types.addExtensibilityElement(schemaExtensibilityEntity);
schemaExtensibilityEntity.setEnclosingDefinition(definition);
final String wsdlLocation = definition.getLocation();
xsdSchema.setSchemaLocation(wsdlLocation);
if (null != namespace && !"".equals(namespace.trim())) //$NON-NLS-1$
xsdSchema.setTargetNamespace(namespace);
return xsdSchema;
}
/**
* Use instead of {@link Definition#updateElement(boolean)} to prevent the
* DOM Model to notify thus change the EMF model, while the DOM it self is
* being updated from it.
*
* @param definition
* the definition whic's element is updated
* @param deep
* :
*
* @see WSDLElement#updateElement(boolean deep)
*/
public static void updateDefinition(final Definition definition, final boolean deep) {
XMLModelNotifier modelNotifier = null;
XMLModelNotifierWrapper notifierWrapper = null;
final Document document = definition.getDocument();
if (document instanceof DocumentImpl) {
modelNotifier = ((DocumentImpl) document).getModel().getModelNotifier();
}
try {
if (modelNotifier instanceof XMLModelNotifierWrapper) {
notifierWrapper = (XMLModelNotifierWrapper) modelNotifier;
notifierWrapper.setInterceptChanges(true);
}
definition.updateElement(deep);
} finally {
if (notifierWrapper != null) {
notifierWrapper.setInterceptChanges(false);
}
}
}
public static ISchema getDefaultSchema(final Description description) {
final Definition definition = description.getComponent();
final String targetNamespace = definition.getTargetNamespace();
final ISchema[] schemas = description.getSchema(targetNamespace);
ISchema schema = null;
if (schemas != null && schemas.length > 0) {
schema = schemas[0];
}
return schema;
}
/**
* Checks modelObject.getModelRoot() referred definitions, do match of
* modelObject's Definition
*
* @param modelObject
* which is supposed to be from referred definition.
* @return referred Description, or null
*/
public static IDescription getReferredDescription(IModelObject modelObject) {
if (modelObject instanceof IFault) {
final Collection<IParameter> parameters = ((IFault) modelObject).getParameters();
modelObject = parameters.isEmpty() ? null : parameters.iterator().next();
}
if (modelObject == null || !(modelObject.getModelRoot() instanceof IWsdlModelRoot)) {
return null;
}
final IWsdlModelRoot wsdlModelRoot = (IWsdlModelRoot) modelObject.getModelRoot();
final IDescription description = wsdlModelRoot.getDescription();
// get referred Definition
EObject referredDefinition = modelObject.getComponent();
while (referredDefinition != null && !(referredDefinition instanceof Definition)) {
referredDefinition = referredDefinition.eContainer();
}
if (referredDefinition != null) {
for (final IDescription referredDescription : description.getReferencedServices()) {
if (referredDefinition.equals(referredDescription.getComponent())) {
return referredDescription;
}
}
}
return null;
}
/**
* Checks modelObject.getModelRoot() referred schemas, do match
* modelObject's XSDSchema
*
* @param modelObject
* which is supposed to be from referred schema.
* @return referred ISchema, or null
*/
public static ISchema getReferredSchema(final IModelObject modelObject) {
if (modelObject == null || !(modelObject.getModelRoot() instanceof IXSDModelRoot)) {
return null;
}
final IXSDModelRoot xsdModelRoot = (IXSDModelRoot) modelObject.getModelRoot();
final ISchema schema = xsdModelRoot.getSchema();
// get referred XSDSchema
EObject referredXSDSchema = modelObject.getComponent();
while (referredXSDSchema != null && !(referredXSDSchema instanceof XSDSchema)) {
referredXSDSchema = referredXSDSchema.eContainer();
}
if (referredXSDSchema != null) {
for (final ISchema referredSchema : schema.getAllReferredSchemas()) {
if (referredXSDSchema.equals(referredSchema.getComponent())) {
return referredSchema;
}
}
}
return null;
}
/**
* Check whether 'modelObject' is part of 'modelRoot' resource.
*/
public static boolean isModelObjectPartOfModelRoot(final IModelRoot modelRoot, final IModelObject modelObject) {
if (modelObject == null) {
return false;
}
final EObject childComponent = modelObject.getComponent();
final EObject rootComponent = modelRoot.getModelObject().getComponent();
EObject currentComponent = childComponent;
while (currentComponent != null && !rootComponent.equals(currentComponent)) {
currentComponent = currentComponent.eContainer();
}
return currentComponent != null;
}
public static boolean isSchemaForSchemaMissingForAnySchema(final IModelRoot root) {
if (!(root instanceof IWsdlModelRoot)) {
return false;
}
final IWsdlModelRoot wsdlModelRoot = (IWsdlModelRoot) root;
final IDescription object = wsdlModelRoot.getDescription();
final List<ISchema> schemas = object.getAllVisibleSchemas();
for (final ISchema schema : schemas) {
// do not reload
if (EmfXsdUtils.isSchemaForSchemaMissing(schema)) {
return true;
}
}
return false;
}
/**
* Return the index in sourcePage for a given WSDLElement
*
* @param wsdlComponent
* must be NOT null
* @return the start index for a given WSDLElement, or -1 otherwise
*/
public static int getIndexInSourcePage(WSDLElement wsdlComponent) {
final Element element = wsdlComponent.getElement();
return EmfXsdUtils.getIndexInSourcePage(element);
}
/**
* Return true if the searched EMF object is represented in ServiceInterface
* UI tree
*
* @param searchedObject
* is an EMF object
* @return boolean flag which value depends on the type of the
* "searchObject" parameter
*/
public static boolean hasCorrespondingITreeNode(final EObject searchedObject) {
// Only these EMF objects are represented in the UI Tree
if (searchedObject instanceof PortType) {
return true;
}
if (searchedObject instanceof Part) {
return true;
}
if (searchedObject instanceof Fault) {
return true;
}
if (searchedObject instanceof Operation) {
return true;
}
return false;
}
public static boolean couldBeVisibleType(XSDConcreteComponent xsdComponent) {
EObject emfContainer = xsdComponent.eContainer();
if (!(emfContainer instanceof XSDSchema)) {
return false;
}
EObject parentEmfContainer = emfContainer.eContainer();
if (parentEmfContainer instanceof XSDSchemaExtensibilityElement) {
XSDSchemaExtensibilityElement exElement = (XSDSchemaExtensibilityElement) parentEmfContainer;
if (exElement == null) {
return false;
}
Definition definition = exElement.getEnclosingDefinition();
boolean locationMatches = definition.getLocation() != null
&& definition.getLocation().equals(xsdComponent.getSchema().getSchemaLocation());
boolean isSchemaPresentInDocument = definition.getETypes().getSchemas().contains(xsdComponent.getSchema());
if (locationMatches && isSchemaPresentInDocument) {
return true;
}
}
return xsdComponent.getSchema() != null;
}
}