/******************************************************************************* * Copyright (c) 2005, 2012 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.bpel.ui.util; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.bpel.model.messageproperties.MessagepropertiesPackage; import org.eclipse.bpel.model.messageproperties.Property; import org.eclipse.bpel.model.messageproperties.PropertyAlias; import org.eclipse.bpel.model.messageproperties.Query; import org.eclipse.bpel.model.messageproperties.util.MessagepropertiesConstants; import org.eclipse.bpel.model.partnerlinktype.PartnerLinkType; import org.eclipse.bpel.model.partnerlinktype.PartnerlinktypePackage; import org.eclipse.bpel.model.partnerlinktype.Role; import org.eclipse.bpel.model.partnerlinktype.util.PartnerlinktypeConstants; import org.eclipse.bpel.ui.details.providers.XSDTypeOrElementContentProvider; import org.eclipse.core.resources.IResource; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.wst.wsdl.Definition; import org.eclipse.wst.wsdl.ExtensibilityElement; import org.eclipse.wst.wsdl.Import; import org.eclipse.wst.wsdl.Message; import org.eclipse.wst.wsdl.PortType; import org.eclipse.wst.wsdl.Types; import org.eclipse.wst.wsdl.WSDLFactory; import org.eclipse.wst.wsdl.WSDLPackage; import org.eclipse.wst.wsdl.util.WSDLResourceImpl; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDTypeDefinition; /** * This class contains helpers to place the necessary <import> and <namespace> * declarations in a WSDL Definition so that it will serialize properly. */ public class WSDLImportHelper { static final String WSDL_PREFIX_KIND = "wsdl"; //$NON-NLS-1$ static final String XSD_PREFIX_KIND = "xsd"; //$NON-NLS-1$ public static void addAllImportsAndNamespaces(Definition definition, IResource contextObject) { String TNS = definition.getTargetNamespace(); if (TNS == null) { TNS = definition.getNamespace("tns"); //$NON-NLS-1$ if (TNS == null) throw new IllegalStateException(); definition.setTargetNamespace(TNS); } else { definition.addNamespace("tns", TNS); //$NON-NLS-1$ } addToolingNamespaces(definition); for (Iterator it = definition.getEExtensibilityElements().iterator(); it.hasNext(); ) { ExtensibilityElement ee = (ExtensibilityElement) it.next(); if (ee instanceof PartnerLinkType) { // for each <role> with a <portType>, import the file with the portType in it for (Role role : ((PartnerLinkType) ee).getRole()) { if (role.getPortType() != null) { PortType pt = (PortType) role.getPortType(); if (pt != null && pt.getQName() != null) { addImportAndNamespace(definition, pt.getEnclosingDefinition()); } } } } if (ee instanceof PropertyAlias) { Message msg = (Message) ((PropertyAlias) ee).getMessageType(); if (msg != null && msg.getQName() != null) { addImportAndNamespace(definition, msg.getEnclosingDefinition()); // add the namespaces of the propertyalias, message, part, type definition // for maybe the query of the propertyalias will use the elements in the namespaces // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330813 Query q = ((PropertyAlias) ee).getQuery(); if (q != null && q.getValue() != null && !"".equals(q.getValue())) { String query = ((PropertyAlias) ee).getQuery().getValue(); String[] queryArr = query.split("/"); List<String> prefixList = new LinkedList<String>(); for (String qname : queryArr) { String[] strs = qname.split(":"); if (strs.length > 1) { prefixList.add(strs[0]); } } if (prefixList.size() > 0) { Types types = (Types) msg.getEnclosingDefinition().getTypes(); if (types != null && types.getSchemas() != null) { XSDSchema xsd = null; for (int i = 0; i < types.getSchemas().size(); i++) { xsd = (XSDSchema) types.getSchemas().get(i); Map<String, String> map = xsd .getQNamePrefixToNamespaceMap(); if (map != null) { for (Object obj : map.keySet().toArray()) { if (prefixList.contains((String) obj)) { definition.addNamespace((String) obj, (String) map.get((String) obj)); } } } } } } } } } if (ee instanceof Property) { Object xsdType = ((Property) ee).getType(); if (xsdType instanceof XSDTypeDefinition) { XSDTypeDefinition td = (XSDTypeDefinition) xsdType; if (td.eResource() != null && !XSDTypeOrElementContentProvider.isBuiltInType(td)) { addImportAndNamespace(definition, td.getSchema(), contextObject); } else { // namespace only! addNamespace(definition,td.getTargetNamespace(), XSD_PREFIX_KIND ); } } else if (xsdType instanceof XSDElementDeclaration) { XSDElementDeclaration ed = (XSDElementDeclaration) xsdType; if (ed.eResource() != null) { addImportAndNamespace(definition, ed.getSchema(), contextObject); } else { // namespace only! addNamespace(definition, ed.getTargetNamespace(), XSD_PREFIX_KIND); } } } } } // TODO: is this truly necessary, or is the model doing it for us somewhere else? // TODO: michal.chmielewski@oracle.com: The partner link namespace was somehow getting placed twice in the WSDL // and so I have added the tooling namespace back to existence. I have no idea why at this point. protected static void addToolingNamespaces(Definition definition) { addNamespace(definition, PartnerlinktypeConstants.NAMESPACE, PartnerlinktypePackage.eNS_PREFIX ); addNamespace(definition, MessagepropertiesConstants.NAMESPACE, MessagepropertiesPackage.eNS_PREFIX ); // if (getEnclosingDefinition().getPrefix(MessagepropertiesConstants.NAMESPACE) == null) { // getEnclosingDefinition().addNamespace(MessagepropertiesPackage.eNS_PREFIX, MessagepropertiesConstants.NAMESPACE); // } // if (definition.getNamespace(PartnerlinktypePackage.eNS_PREFIX) == null) { // definition.addNamespace(PartnerlinktypePackage.eNS_PREFIX, // PartnerlinktypePackage.eNS_URI); // } // if (definition.getNamespace(MessagepropertiesPackage.eNS_PREFIX) == null) { // definition.addNamespace(MessagepropertiesPackage.eNS_PREFIX, // MessagepropertiesPackage.eNS_URI); // } } public static void addImportAndNamespace(Definition definition, XSDSchema importedSchema, IResource contextObject) { String namespace = importedSchema.getTargetNamespace(); // TODO LOGTHIS: need better error handling here! if (namespace == null) return; addNamespace(definition, namespace, XSD_PREFIX_KIND); addImport(namespace, definition, definition.eResource().getURI(), importedSchema, importedSchema.eResource().getURI(), contextObject); } public static void addImportAndNamespace(Definition definition, Definition importedDefinition) { if (importedDefinition == null || definition == null) return; if (definition == importedDefinition) return; String namespace = importedDefinition.getTargetNamespace(); // TODO LOGTHIS: need better error handling here! if (namespace == null) return; addNamespace(definition, namespace, WSDL_PREFIX_KIND); addImport(namespace, definition, definition.eResource().getURI(), importedDefinition, importedDefinition.eResource().getURI()); } protected static void addNamespace ( Definition definition, String namespace, String pfxRoot ) { String prefix = definition.getPrefix(namespace); if (prefix != null) { return; } // Find a suitable prefix prefix = pfxRoot; int idx = 1; do { if (definition.getNamespace(prefix) == null) { definition.addNamespace(prefix, namespace); break; } prefix = pfxRoot + idx; idx += 1; } while (true); } protected static void addImport(String namespace, Definition importingDefinition, URI importingUri, Definition importedDefinition, URI importedUri) { WSDLFactory wsdlFactory = WSDLPackage.eINSTANCE.getWSDLFactory(); List<Import> imports = importingDefinition.getImports(namespace); if (imports == null) { imports = new ArrayList<Import>(); } boolean found = false; for (int i = 0; i < imports.size() && !found; i++) { Import _import = imports.get(i); if (_import.getEDefinition() == importedDefinition) { found = true; } } if (!found) { String locationURI = createBuildPathRelativeReference(importingUri, importedUri); if (locationURI != null && locationURI.length() != 0) { // Create and add the import to the definition Import _import = wsdlFactory.createImport(); _import.setEDefinition(importedDefinition); _import.setLocationURI(locationURI); _import.setNamespaceURI(namespace); importingDefinition.addImport(_import); } else { // TODO handle errors here? throw new IllegalStateException(); } } } protected static void addImport(String namespace, Definition importingDefinition, URI importingUri, XSDSchema importedSchema, URI importedUri, IResource contextObject) { WSDLFactory wsdlFactory = WSDLPackage.eINSTANCE.getWSDLFactory(); List<Import> imports = importingDefinition.getImports(namespace); if (imports == null) { imports = new ArrayList<Import>(); } // WDG: do we need something here for handling duplicate imports? boolean found = false; for (int i = 0; i < imports.size() && !found; i++) { Import _import = imports.get(i); if (_import.getESchema() == importedSchema) { found = true; continue; } } if (found) return; URI locationURI = importedUri.deresolve(importingUri, true, true, false); if ("bundleentry".equals(locationURI.scheme())) { //$NON-NLS-1$ // Don't add this import! // It's not for something in the workspace. } else { String locationString = createBuildPathRelativeReference(importingUri, importedUri); if (locationString != null && locationString.length() != 0) { // Create and add the import to the definition Import _import = wsdlFactory.createImport(); _import.setESchema(importedSchema); _import.setLocationURI(locationString); _import.setNamespaceURI(namespace); // imports.add(_import); //importingDefinition.getImports().put(importedSchema.getTargetNamespace(), imports); importingDefinition.addImport(_import); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330813 // https://jira.jboss.org/browse/JBIDE-7107 // ignore an inconsequential error here else if ( !importingUri.equals(importedUri) ) { // TODO handle errors here? throw new IllegalStateException(); } } } /** * Builds the relative location of one URL with respect to another one. * @param sourceURI * @param targetURI * @return * FIXME: completely review the implementation and move it in *.common */ public static String createBuildPathRelativeReference(URI sourceURI, URI targetURI) { if (sourceURI == null || targetURI == null) throw new IllegalArgumentException(); // BaseURI source = new BaseURI(sourceURI); // return source.getRelativeURI(targetURI); // TODO: this is probably bogus. String result = targetURI.deresolve(sourceURI, true, true, true).toFileString(); // When absolute URLs // VZ // Bug #350540: files that are picked up anywhere on the disk are imported as absolute file locations (and not as relative or absolute URL) // FIXME: this is a temporary fix, a user should not be able to pick up a WSDL anywhere // FIXME: only allow WSDL that are in the same project and absolute URL try { File f; if( result != null && (f = new File( result )).exists()) result = f.toURI().toString(); } catch( Exception e ) { // nothing } // VZ return (result == null ? targetURI.toString() : result); } public static Definition getDefinition(org.eclipse.bpel.model.Import bpelImport) { Resource baseResource = bpelImport.eResource(); String location = bpelImport.getLocation(); if (!baseResource.getURI().isRelative()) { location = URI.createURI(location).resolve(baseResource.getURI()).toString(); } URI locationURI = URI.createURI(location); ResourceSet resourceSet = baseResource.getResourceSet(); Resource resource = resourceSet.getResource(locationURI, true); return (resource instanceof WSDLResourceImpl) ? ((WSDLResourceImpl)resource).getDefinition() : null; } }