/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.webservice.gen; import java.io.IOException; import java.io.OutputStream; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.xsd.XSDComplexTypeDefinition; import org.eclipse.xsd.XSDComponent; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDFactory; import org.eclipse.xsd.XSDImport; import org.eclipse.xsd.XSDInclude; import org.eclipse.xsd.XSDNamedComponent; import org.eclipse.xsd.XSDPackage; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSimpleTypeDefinition; import org.eclipse.xsd.util.XSDConstants; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.resource.EmfResource; import org.teiid.designer.core.types.DatatypeConstants; import org.teiid.designer.core.util.ModelContents; import org.teiid.designer.core.util.ModelVisitor; import org.teiid.designer.core.util.ModelVisitorProcessor; import org.teiid.designer.metamodels.core.Annotation; import org.teiid.designer.metamodels.webservice.Input; import org.teiid.designer.metamodels.webservice.Interface; import org.teiid.designer.metamodels.webservice.Output; import org.teiid.designer.metamodels.webservice.WebServiceComponent; import org.teiid.designer.metamodels.webservice.WebServicePackage; import org.teiid.designer.metamodels.webservice.impl.OperationImpl; import org.teiid.designer.metamodels.wsdl.Binding; import org.teiid.designer.metamodels.wsdl.BindingInput; import org.teiid.designer.metamodels.wsdl.BindingOperation; import org.teiid.designer.metamodels.wsdl.BindingOutput; import org.teiid.designer.metamodels.wsdl.Definitions; import org.teiid.designer.metamodels.wsdl.Documentation; import org.teiid.designer.metamodels.wsdl.Documented; import org.teiid.designer.metamodels.wsdl.Import; import org.teiid.designer.metamodels.wsdl.MessagePart; import org.teiid.designer.metamodels.wsdl.NamespaceDeclaration; import org.teiid.designer.metamodels.wsdl.Operation; import org.teiid.designer.metamodels.wsdl.Port; import org.teiid.designer.metamodels.wsdl.PortType; import org.teiid.designer.metamodels.wsdl.Service; import org.teiid.designer.metamodels.wsdl.Types; import org.teiid.designer.metamodels.wsdl.WsdlFactory; import org.teiid.designer.metamodels.wsdl.WsdlNameRequiredEntity; import org.teiid.designer.metamodels.wsdl.WsdlPackage; import org.teiid.designer.metamodels.wsdl.io.WsdlResourceFactoryImpl; import org.teiid.designer.metamodels.wsdl.io.WsdlWriter; import org.teiid.designer.metamodels.wsdl.soap.SoapAddress; import org.teiid.designer.metamodels.wsdl.soap.SoapBinding; import org.teiid.designer.metamodels.wsdl.soap.SoapBody; import org.teiid.designer.metamodels.wsdl.soap.SoapFactory; import org.teiid.designer.metamodels.wsdl.soap.SoapOperation; import org.teiid.designer.metamodels.wsdl.soap.SoapPackage; import org.teiid.designer.metamodels.wsdl.soap.SoapStyleType; import org.teiid.designer.metamodels.wsdl.soap.SoapUseType; import org.teiid.designer.metamodels.xml.XmlDocument; import org.teiid.designer.metamodels.xml.XmlRoot; import org.teiid.designer.webservice.IWsdlGenerator; import org.teiid.designer.webservice.WebServicePlugin; /** * Basic implementation of the {@link org.teiid.designer.webservice.IWsdlGenerator} interface. * * @since 8.0 */ public class BasicWsdlGenerator implements IWsdlGenerator { private static final String XML_LITERAL_TYPE_URI_STRING = URI.createURI(DatatypeConstants.BUILTIN_DATATYPES_URI).appendFragment(DatatypeConstants.BuiltInNames.XML_LITERAL).toString(); public static final String XSD_SCHEMA_FOR_SCHEMA_TARGET_NAMESPACE = XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001; public static final String XSD_SCHEMA_FOR_SCHEMA_PREFIX = XSDPackage.eNS_PREFIX; private Map operationToProcedureMap; private final List ports; private final List webServiceModels; private final List xmlSchemas; private final List webServiceModelsUnmodifiable; private final List xmlSchemasUnmodifiable; private final Resource wsdlResource; private final Resource.Factory wsdlResourceFactory; private final URI wsdlResourceUri; private final int wsdlVersion = WSDL_VERSION_DEFAULT; private final Map xmlSchemasToLocationPath; private String name; private String targetNamespace; private String urlRootForReferences; private String urlSuffixForReferences; private String urlForService; private String defaultNamespaceUri; private String xmlEncoding = WsdlWriter.ENCODING_UTF8; public static final int WSDL_VERSION_1_1 = 1; public static final int WSDL_VERSION_2_0 = 2; public static final int WSDL_VERSION_DEFAULT = WSDL_VERSION_1_1; public static final int ERROR_NO_WEB_SERVICES = 21301; public static final int MULTIPLE_MESSAGES = 21302; public static final int ERROR_NO_WEB_SERVICE_OBJECTS = 21303; public static final int INVALID_URL = 21304; public static final String DEFAULT_URI = "GeneratedWsdl.wsdl"; //$NON-NLS-1$ public BasicWsdlGenerator() { this(URI.createURI(DEFAULT_URI)); } public BasicWsdlGenerator( final URI uri ) { CoreArgCheck.isNotNull(uri); this.operationToProcedureMap = new HashMap(); this.webServiceModels = new ArrayList(); this.ports = new ArrayList(); this.xmlSchemas = new ArrayList(); this.xmlSchemasToLocationPath = new HashMap(); this.webServiceModelsUnmodifiable = Collections.unmodifiableList(this.webServiceModels); this.xmlSchemasUnmodifiable = Collections.unmodifiableList(this.xmlSchemas); // Create the WSDL resource ... this.wsdlResourceUri = uri; this.wsdlResourceFactory = new WsdlResourceFactoryImpl(); this.wsdlResource = wsdlResourceFactory.createResource(this.wsdlResourceUri); // Set the initial default ... this.defaultNamespaceUri = INITIAL_DEFAULT_NAMESPACE_URI; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getName() * @since 4.2 */ @Override public String getName() { return name; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getTargetNamespace() * @since 4.2 */ @Override public String getTargetNamespace() { return targetNamespace; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#setName(java.lang.String) * @since 4.2 */ @Override public void setName( String name ) { this.name = name; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#setTargetNamespace(java.lang.String) * @since 4.2 */ @Override public void setTargetNamespace( String targetNamspace ) { this.targetNamespace = targetNamspace; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getUrlRootForReferences() * @since 4.2 */ @Override public String getUrlRootForReferences() { return urlRootForReferences; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#setUrlRootForReferences(java.lang.String) * @since 4.2 */ @Override public void setUrlRootForReferences( String url ) { this.urlRootForReferences = url; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getUrlSuffixForReferences() * @since 4.2 */ @Override public String getUrlSuffixForReferences() { return this.urlSuffixForReferences; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#setUrlSuffixForReferences(java.lang.String) * @since 4.2 */ @Override public void setUrlSuffixForReferences( String suffix ) { this.urlSuffixForReferences = suffix; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getUrlForWsdlService() * @since 4.2 */ @Override public String getUrlForWsdlService() { return this.urlForService; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#setUrlForWsdlService(java.lang.String) * @since 4.2 */ @Override public void setUrlForWsdlService( final String serviceUrl ) { this.urlForService = serviceUrl; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getDefaultNamespaceUri() * @since 4.2 */ @Override public String getDefaultNamespaceUri() { return this.defaultNamespaceUri; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#setDefaultNamespaceUri(java.lang.String) * @since 4.2 */ @Override public void setDefaultNamespaceUri( String namespaceUri ) { this.defaultNamespaceUri = namespaceUri; } /** * @return ports */ public List getPorts() { return ports; } /** * @return operationToProcedureMap */ public Map getOperationToProcedureMap() { return operationToProcedureMap; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getXmlEncoding() * @since 4.2 */ @Override public String getXmlEncoding() { return this.xmlEncoding; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#setXmlEncoding(java.lang.String) * @since 4.2 */ @Override public void setXmlEncoding( String xmlEncoding ) { if (xmlEncoding == null || xmlEncoding.trim().length() == 0) { this.xmlEncoding = WsdlWriter.ENCODING_UTF8; } else { this.xmlEncoding = xmlEncoding; } } /** * @see org.teiid.designer.webservice.IWsdlGenerator#addWebServiceModel(org.eclipse.emf.ecore.resource.Resource) * @since 4.2 */ @Override public boolean addWebServiceModel( Resource resource ) { CoreArgCheck.isNotNull(resource); // See if already added ... if (this.webServiceModels.contains(resource)) { return false; } // Check whether it is a valid model, and add only if it is ... final boolean valid = (isValidWebServiceModel(resource)); if (valid) { this.webServiceModels.add(resource); } return valid; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#addXsdModel(org.eclipse.xsd.XSDSchema) * @since 4.2 */ @Override public boolean addXsdModel( XSDSchema xmlSchema, final IPath pathForLocation ) { CoreArgCheck.isNotNull(xmlSchema); // See if already added ... if (this.xmlSchemas.contains(xmlSchema)) { return false; } this.xmlSchemas.add(xmlSchema); this.xmlSchemasToLocationPath.put(xmlSchema, pathForLocation); return true; } public IPath getLocationPathForXsdModel( XSDSchema xmlSchema ) { return (IPath)this.xmlSchemasToLocationPath.get(xmlSchema); } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getWebServiceModels() * @since 4.2 */ @Override public List getWebServiceModels() { return this.webServiceModelsUnmodifiable; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#getXSDSchemas() * @since 4.2 */ @Override public List getXSDSchemas() { return this.xmlSchemasUnmodifiable; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#generate(org.eclipse.core.runtime.IProgressMonitor) * @since 4.2 */ @Override public IStatus generate( IProgressMonitor monitor ) { // See if there are any web service models ... if (this.webServiceModels.isEmpty()) { final String msg = WebServicePlugin.Util.getString("BasicWsdlGenerator.NoWebServiceModelsSupplied"); //$NON-NLS-1$ return new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, ERROR_NO_WEB_SERVICES, msg, null); } // Remove all existing objects from the existing resource ... this.wsdlResource.getContents().clear(); // Delegate to the internal method ... final List problems = new ArrayList(); doGenerate(monitor, this.wsdlResource, problems); // Construct the resulting MultiStatus ... IStatus result = null; if (problems.size() == 0) { final String msg = WebServicePlugin.Util.getString("BasicWsdlGenerator.NoErrorsOrWarningsWhileGenerating"); //$NON-NLS-1$ result = new Status(IStatus.OK, WebServicePlugin.PLUGIN_ID, 0, msg, null); } else if (problems.size() == 1) { result = (IStatus)problems.get(0); } else { // Iterate through the problems to see the worst case ... int errors = 0; int warnings = 0; final Iterator firstPastIter = problems.iterator(); while (firstPastIter.hasNext()) { final IStatus problem = (IStatus)firstPastIter.next(); if (problem.getSeverity() == IStatus.ERROR) { ++errors; } if (problem.getSeverity() == IStatus.WARNING) { ++warnings; } } // Create the MultiStatus ... String msg = null; if (errors != 0 || warnings != 0) { final Object[] params = new Object[] {new Integer(errors), new Integer(warnings)}; msg = WebServicePlugin.Util.getString("BasicWsdlGenerator.ErrorsAndWarningsWhileGenerating", params); //$NON-NLS-1$ } else { msg = WebServicePlugin.Util.getString("BasicWsdlGenerator.NoErrorsOrWarningsWhileGenerating"); //$NON-NLS-1$ } final IStatus[] children = (IStatus[])problems.toArray(new IStatus[problems.size()]); final MultiStatus multi = new MultiStatus(WebServicePlugin.PLUGIN_ID, MULTIPLE_MESSAGES, children, msg, null); result = multi; } return result; } /** * @see org.teiid.designer.webservice.IWsdlGenerator#write(java.io.OutputStream) * @since 4.2 */ @Override public void write( OutputStream stream ) throws IOException { if (this.wsdlResource != null && this.wsdlResource.getContents().size() != 0) { // Write out the resource to the supplied stream ... final Map options = new HashMap(); options.put(XMLResource.OPTION_ENCODING, xmlEncoding); this.wsdlResource.save(stream, options); } } /** * @see org.teiid.designer.webservice.IWsdlGenerator#close() * @since 4.2 */ @Override public void close() { this.webServiceModels.clear(); this.xmlSchemas.clear(); } // -------------------------------------------------------------------------------------------------------- // OVERRIDABLE METHODS // -------------------------------------------------------------------------------------------------------- protected IStatus doCheckValidUri( final String location ) { try { new java.net.URI(location); } catch (URISyntaxException err) { final IStatus problem = new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, INVALID_URL, err.getLocalizedMessage(), null); return problem; } return null; } protected boolean isValidWebServiceModel( Resource resource ) { // Look for root-level WebService objects ... final Iterator iter = resource.getContents().iterator(); while (iter.hasNext()) { final EObject root = (EObject)iter.next(); final EClass eclass = root.eClass(); if (eclass != null) { final EPackage epackage = eclass.getEPackage(); if (WebServicePackage.eINSTANCE.equals(epackage)) { return true; } } } return false; } /** * Generate the WSDL into the WSDL resource. This method may be overridden to supply specific behavior * * @param monitor * @param wsdlResource * @param problems * @since 4.2 */ protected void doGenerate( final IProgressMonitor monitor, final Resource wsdlResource, final List problems ) { // Obtain the list of all root-level WebService objects ... final List rootWsObjects = new ArrayList(); final Iterator iter = this.webServiceModels.iterator(); while (iter.hasNext()) { final Resource webServiceModel = (Resource)iter.next(); final List roots = webServiceModel.getContents(); final Iterator rootIter = roots.iterator(); while (rootIter.hasNext()) { final EObject root = (EObject)rootIter.next(); final EClass eclass = root.eClass(); if (eclass != null) { final EPackage epackage = eclass.getEPackage(); if (WebServicePackage.eINSTANCE.equals(epackage)) { rootWsObjects.add(root); } } } } if (rootWsObjects.isEmpty()) { // No objects were found ... final Object[] params = new Object[] {new Integer(this.webServiceModels.size())}; final String msg = WebServicePlugin.Util.getString("BasicWsdlGenerator.NoWebServiceObjectsFound", params); //$NON-NLS-1$ problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, ERROR_NO_WEB_SERVICE_OBJECTS, msg, null)); } else { // At least some objects were found ... // Create the correct visitor for the desired version ... Wsdl11Generator visitor = null; final String urlRoot = this.getUrlRootForReferences(); final String urlSuffix = this.getUrlSuffixForReferences(); final String urlService = this.getUrlForWsdlService(); final String defNsUri = this.getDefaultNamespaceUri(); switch (this.wsdlVersion) { case WSDL_VERSION_2_0: { visitor = new Wsdl20Generator(wsdlResource, getName(), getTargetNamespace(), defNsUri, urlRoot, urlSuffix, urlService, problems); break; } default: { visitor = new Wsdl11Generator(wsdlResource, getName(), getTargetNamespace(), defNsUri, urlRoot, urlSuffix, urlService, problems); } } // generate namespaces first so that they are available when generating the other WSDL elements visitor.doGenerateStandardNamespaceDeclarations(); // Walk the objects and use the generator ... final ModelVisitorProcessor processor = new ModelVisitorProcessor(visitor); try { processor.walk(rootWsObjects, ModelVisitorProcessor.DEPTH_INFINITE); } catch (ModelerCoreException e) { // handle the exception } visitor.doGenerateTargetNamespaceNamespaceDeclaration(); operationToProcedureMap = visitor.operationToProcedureMap; // Signal the generator to complete the WSDL (adding any binding information, etc.) visitor.complete(); } } // ======================================================================================================== // WSDL 1.1 Generator // ======================================================================================================== protected class Wsdl11Generator implements ModelVisitor { // extends WebServiceSwitch implements ModelVisitor { private final List problems; protected final Resource resource; protected final ModelContents contents; private final WsdlFactory factory; private final SoapFactory soapFactory; private final XSDFactory xsdFactory; final Map operationToProcedureMap; private Definitions definitions; // the one created ... private Service service; // the one created ... private PortType portType; // the last one created ... private Operation operation; // the last one created ... private Binding binding; // the last one created ... private BindingOperation bindingOp; // the last one created ... private final Set referencedXsds; private final Map xsdPrefixByTargetNamespace; private int schemaIndex; private final String urlRoot; private final String urlSuffix; private final String urlService; private final Map messagePartNameByWebServiceMessage; private String wsdlTnsPrefix = "tns"; //$NON-NLS-1$ private final String name; private final String targetNamespace; private final String defaultNamespace; private boolean xsdImportsAsWsdlImports = false; private final Set namespacePrefixes = new HashSet(); protected Wsdl11Generator( final Resource wsdlResource, final String name, final String targetNamespace, final String defaultNamespace, final String urlRoot, final String urlSuffix, final String urlService, final List problems ) { this.name = name; this.targetNamespace = targetNamespace; this.problems = problems; this.resource = wsdlResource; this.factory = WsdlFactory.eINSTANCE; this.soapFactory = SoapFactory.eINSTANCE; this.xsdFactory = XSDFactory.eINSTANCE; this.contents = new ModelContents(this.resource); this.referencedXsds = new HashSet(); this.xsdPrefixByTargetNamespace = new HashMap(); this.urlRoot = urlRoot; this.urlSuffix = urlSuffix; this.urlService = urlService; this.messagePartNameByWebServiceMessage = new HashMap(); this.defaultNamespace = defaultNamespace; this.operationToProcedureMap = new HashMap<String, String>(); } public Definitions getDefinitions() { if (this.definitions == null) { // Create the root definitions ... this.definitions = this.factory.createDefinitions(); this.definitions.setName(this.name); this.definitions.setTargetNamespace(this.targetNamespace); this.resource.getContents().add(this.definitions); // Add the service ... this.service = this.factory.createService(); this.service.setName(this.name); this.service.setDefinitions(this.definitions); } return this.definitions; } protected void addError( final int code, final String msg, final Throwable t ) { this.problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, code, msg, t)); } protected void addWarning( final int code, final String msg, final Throwable t ) { this.problems.add(new Status(IStatus.WARNING, WebServicePlugin.PLUGIN_ID, code, msg, t)); } @Override public boolean visit( EObject object ) { doSwitch(object); return true; } @Override public boolean visit( Resource resource ) { return true; } protected String getDescription( EObject eObj ) { Annotation annotation = null; final Resource eResource = eObj.eResource(); if (eResource instanceof EmfResource) { final ModelContents contents = ((EmfResource)eResource).getModelContents(); annotation = contents.getAnnotation(eObj); } if (annotation == null) { return null; } final String desc = annotation.getDescription(); return desc; } protected void addDocumentation( WebServiceComponent component, final Documented documented ) { final String desc = getDescription(component); addDocumentation(desc, documented); } protected void addDocumentation( String docText, final Documented documented ) { if (docText != null && docText.trim().length() != 0) { // Create a documentation under the documented ... final Documentation doc = this.factory.createDocumentation(); doc.setTextContent(docText); doc.setDocumented(documented); } } /** * Obtain the identifier by which the WSDL references the supplied XSD component. * * @param comp the named component * @return * @since 4.2 */ protected String getXsdComponentIdentifier( final XSDNamedComponent comp ) { final String name = comp.getName(); final String targetNsUri = comp.getTargetNamespace(); if (isDefaultNamespace(targetNsUri)) { return name; } final String prefix = (String)this.xsdPrefixByTargetNamespace.get(targetNsUri); return prefix + ':' + name; } protected boolean isDefaultNamespace( final String namespaceUri ) { if (this.defaultNamespace != null && this.defaultNamespace.equals(namespaceUri)) { return true; } return false; } protected void addReference( final XSDComponent xsdComp ) { final XSDSchema schema = xsdComp.getSchema(); final boolean added = schema != null && this.referencedXsds.add(schema); if (added) { // Add a prefix ... final String targetNamespace = schema.getTargetNamespace(); // See if it's the default ... if (isDefaultNamespace(targetNamespace)) { this.xsdPrefixByTargetNamespace.put(targetNamespace, null); } else { String prefix = "schema" + ++schemaIndex; //$NON-NLS-1$ if (this.xsdPrefixByTargetNamespace.put(targetNamespace, prefix) != null) { String msg = WebServicePlugin.Util.getString("BasicWsdlGenerator.NonUniqueNamespace", targetNamespace); //$NON-NLS-1$ addError(IStatus.ERROR, msg, null); } } } } private void addToOperationToProcedureMap( final EObject object ) { final IPath path = ModelerCore.getModelEditor().getModelRelativePathIncludingModel(object); final StringBuffer sb = new StringBuffer(); final String[] segments = path.segments(); for (int i = 0; i < segments.length; i++) { if (i != 0) { sb.append('.'); } final String segment = segments[i]; sb.append(segment); } this.operationToProcedureMap.put(((OperationImpl)object).getName(), sb.toString()); } protected String doGetFullyQualifiedName( final WsdlNameRequiredEntity object ) { if (this.isDefaultNamespace(this.targetNamespace)) { // Not qualified ... return object.getName(); } // Otherwise, prefix it ... return this.wsdlTnsPrefix + ':' + object.getName(); } protected void addNamespaceDeclaration( final String prefix, final String namespaceUri ) { final NamespaceDeclaration decl = this.factory.createNamespaceDeclaration(); this.namespacePrefixes.add(prefix); this.xsdPrefixByTargetNamespace.put(namespaceUri, prefix); // Add the namespace declaration ... if (!isDefaultNamespace(namespaceUri)) { decl.setPrefix(prefix); } decl.setUri(namespaceUri); decl.setOwner(getDefinitions()); } protected void doGenerateImports() { // Add (in sorted order) the details for each referenced XSD ... final List refedXsds = new LinkedList(this.referencedXsds); Collections.sort(refedXsds, new XsdComparator()); final Iterator iter = refedXsds.iterator(); while (iter.hasNext()) { final XSDSchema xsd = (XSDSchema)iter.next(); final String namespaceUri = xsd.getTargetNamespace(); String prefix = (String)this.xsdPrefixByTargetNamespace.get(namespaceUri); // Compute the location ... String location = null; final IPath xsdPath = BasicWsdlGenerator.this.getLocationPathForXsdModel(xsd); if (xsdPath != null) { location = xsdPath.toString(); } else { final Resource xsdResource = xsd.eResource(); if (xsdResource != null) { final URI xsdUri = xsd.eResource().getURI(); location = xsdUri.lastSegment(); } } // Add the tokens ... if (urlRoot != null) { location = urlRoot + location; } if (urlSuffix != null) { location = location + urlSuffix; } // Check that the URL location is a valid URI ... final IStatus problem = doCheckValidUri(location); if (problem != null) { problems.add(problem); } // Add the namespace declaration to the WSDL file (since the namespaces could be used in values) ... addNamespaceDeclaration(prefix, namespaceUri); // Construct the import if (xsdImportsAsWsdlImports) { // Add the import as a WSDL import ... final Import importObj = this.factory.createImport(); importObj.setNamespace(namespaceUri); importObj.setLocation(location); importObj.setDefinitions(getDefinitions()); } else { // Per the WS-I spec, schema imports should be done in // the wsdl:types section within the context of a xsd:schema element // Add the import as XSD imports ... final XSDSchema nestedSchema = getSchemaInTypes(true); if (namespaceUri != null && namespaceUri.trim().length() != 0) { // Create an import ... final XSDImport xsdImport = this.xsdFactory.createXSDImport(); xsdImport.setNamespace(namespaceUri); xsdImport.setSchemaLocation(location); nestedSchema.getContents().add(xsdImport); // Add the XML Namespace declaration for the imported namespace ... // (Skip this for now, since it really isn't needed) // Map qNamePrefixToNamespaceMap = nestedSchema.getQNamePrefixToNamespaceMap(); // qNamePrefixToNamespaceMap.put(prefix,namespaceUri); } else { // The namespace URI of the referenced XSD is null, meaning its global // Therefore, must include these! // Create an include ... final XSDInclude xsdInclude = this.xsdFactory.createXSDInclude(); xsdInclude.setSchemaLocation(location); nestedSchema.getContents().add(xsdInclude); } } } } protected Types getTypes( boolean createIfRequired ) { Types types = getDefinitions().getTypes(); if (types == null && createIfRequired) { types = this.factory.createTypes(); types.setDefinitions(getDefinitions()); } return types; } protected XSDSchema getSchemaInTypes( boolean createIfRequired ) { XSDSchema schema = null; final Types types = getTypes(createIfRequired); if (types != null) { final List schemas = types.getSchemas(); if (schemas.isEmpty()) { if (createIfRequired) { schema = this.xsdFactory.createXSDSchema(); // Initialize the schema ... schema.setSchemaForSchemaQNamePrefix("xsd"); //$NON-NLS-1$ schema.setTargetNamespace(types.getDefinitions().getTargetNamespace()); Map qNamePrefixToNamespaceMap = schema.getQNamePrefixToNamespaceMap(); qNamePrefixToNamespaceMap.put(schema.getSchemaForSchemaQNamePrefix(), XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001); qNamePrefixToNamespaceMap.put(WsdlPackage.eNS_PREFIX, WsdlPackage.eNS_URI); // Add the schema to the 'types' object ... types.getSchemas().add(schema); } } else { schema = (XSDSchema)types.getSchemas().get(0); } } return schema; } protected class XsdComparator implements Comparator { @Override public int compare( Object o1, Object o2 ) { if (o1 instanceof XSDSchema && o2 instanceof XSDSchema) { final String tn1 = ((XSDSchema)o1).getTargetNamespace(); final String tn2 = ((XSDSchema)o2).getTargetNamespace(); if (tn1 == null && tn2 == null) { return 0; } else if (tn1 == null) { return -1; } else if (tn2 == null) { return 1; } else { return tn1.compareTo(tn2); } } return 0; } } protected void doGenerateStandardNamespaceDeclarations() { // Add the namespace declarations for WSDL, SOAP and XSD ... addNamespaceDeclaration(XSD_SCHEMA_FOR_SCHEMA_PREFIX, XSD_SCHEMA_FOR_SCHEMA_TARGET_NAMESPACE); addNamespaceDeclaration(WsdlPackage.eNS_PREFIX, WsdlPackage.eNS_URI); addNamespaceDeclaration(SoapPackage.eNS_PREFIX, SoapPackage.eNS_URI); } protected void doGenerateTargetNamespaceNamespaceDeclaration() { if (this.xsdPrefixByTargetNamespace.put(this.targetNamespace, this.wsdlTnsPrefix) != null) { String msg = WebServicePlugin.Util.getString("BasicWsdlGenerator.NonUniqueWSDLNamespace", targetNamespace); //$NON-NLS-1$ addError(IStatus.ERROR, msg, null); } addNamespaceDeclaration(this.wsdlTnsPrefix, this.targetNamespace); } /** * Signals the generator to add the bindings, etc. * * @since 4.2 */ public void complete() { // Generate the imports to XSDs ... doGenerateImports(); } // -------------------------------------------------------------------------------------------------------- // Xml/Web Service Switches // -------------------------------------------------------------------------------------------------------- protected Object doSwitch( EObject theEObject ) { return doSwitch(theEObject.eClass(), theEObject); } protected Object doSwitch( EClass theEClass, EObject theEObject ) { if (theEClass.eContainer() == WebServicePackage.eINSTANCE) { return doWebServiceSwitch(theEClass.getClassifierID(), theEObject); } List eSuperTypes = theEClass.getESuperTypes(); return eSuperTypes.isEmpty() ? defaultCase(theEObject) : doSwitch((EClass)eSuperTypes.get(0), theEObject); } protected Object doWebServiceSwitch( int classifierID, EObject theEObject ) { switch (classifierID) { case WebServicePackage.OPERATION: { org.teiid.designer.metamodels.webservice.Operation operation = (org.teiid.designer.metamodels.webservice.Operation)theEObject; Object result = caseOperation(operation); return result; } case WebServicePackage.INPUT: { Input input = (Input)theEObject; Object result = caseInput(input); return result; } case WebServicePackage.OUTPUT: { Output output = (Output)theEObject; Object result = caseOutput(output); return result; } case WebServicePackage.INTERFACE: { Interface interface_ = (Interface)theEObject; Object result = caseInterface(interface_); return result; } default: return defaultCase(theEObject); } } // -------------------------------------------------------------------------------------------------------- // Web Service Processing Methods // -------------------------------------------------------------------------------------------------------- public Object defaultCase( EObject object ) { return null; } /** * @see org.teiid.designer.metamodels.webservice.util.WebServiceSwitch#caseInterface(org.teiid.designer.metamodels.webservice.Interface) * @since 4.2 */ public Object caseInterface( Interface object ) { final String interfaceName = object.getName(); ports.add(interfaceName); // Create a WSDL port type this.portType = this.factory.createPortType(); this.portType.setName(interfaceName); this.portType.setDefinitions(this.getDefinitions()); // adds to parent // Add the documentation, if it exists ... addDocumentation(object, this.portType); // -------------------------------------------------------------------------------------------------------- // Binding information // -------------------------------------------------------------------------------------------------------- final String bindingType = doGetFullyQualifiedName(this.portType); // Add a binding for this interface ... this.binding = this.factory.createBinding(); this.binding.setName(interfaceName); this.binding.setType(bindingType); this.binding.setDefinitions(getDefinitions()); // Add the SOAP binding ... final SoapBinding soapBinding = this.soapFactory.createSoapBinding(); soapBinding.setStyle(SoapStyleType.DOCUMENT_LITERAL); soapBinding.setTransport("http://schemas.xmlsoap.org/soap/http"); //$NON-NLS-1$ this.binding.setSoapBinding(soapBinding); // -------------------------------------------------------------------------------------------------------- // Port information // -------------------------------------------------------------------------------------------------------- final String portTypeName = this.doGetFullyQualifiedName(this.portType); final Port port = this.factory.createPort(); port.setName(interfaceName); port.setBinding(portTypeName); port.setService(this.service); String serviceUrlWithPortName = service.getName(); // Check that the URL location is a valid URI ... if (this.urlService != null) { serviceUrlWithPortName = this.urlService + port.getName(); final IStatus problem = doCheckValidUri(serviceUrlWithPortName); if (problem != null) { problems.add(problem); } } // Add the SOAP address ... final SoapAddress address = this.soapFactory.createSoapAddress(); address.setLocation(serviceUrlWithPortName); address.setPort(port); return object; // this method handled it, so return non-null } /** * @see org.teiid.designer.metamodels.webservice.util.WebServiceSwitch#caseOperation(org.teiid.designer.metamodels.webservice.Operation) * @since 4.2 */ public Object caseOperation( org.teiid.designer.metamodels.webservice.Operation object ) { final String opName = object.getName(); // Create a WSDL operation this.operation = this.factory.createOperation(); this.operation.setName(opName); this.operation.setPortType(this.portType); // adds to parent // Add the documentation, if it exists ... addDocumentation(object, this.operation); // Add the binding information ... this.bindingOp = this.factory.createBindingOperation(); this.bindingOp.setName(opName); this.bindingOp.setBinding(this.binding); // Add the SOAP operation information ... final SoapOperation soapOp = this.soapFactory.createSoapOperation(); final String action = opName; soapOp.setAction(action); addToOperationToProcedureMap(object); soapOp.setStyle(SoapStyleType.DOCUMENT_LITERAL); soapOp.setBindingOperation(this.bindingOp); // If the web service Operation we are processing has an Output but no corresponding Input // then we need to create a dummy WSDL Input/Message construct to make it WS-I compliant // (see defect 20554) if (object.getInput() == null) { createDummyInput(); } return object; // this method handled it, so return non-null } /** * @see org.teiid.designer.metamodels.webservice.util.WebServiceSwitch#caseInput(org.teiid.designer.metamodels.webservice.Input) * @since 4.2 */ public Object caseInput( Input object ) { // Create a WSDL input ... final org.teiid.designer.metamodels.wsdl.Input input = this.factory.createInput(); // Set the name on the input ... String inputName = object.getName(); if (inputName == null || inputName.trim().length() == 0) { inputName = WebServicePlugin.Util.getString("BasicWsdlGenerator.DefaultInputName"); //$NON-NLS-1$ } // Defect 22988 - Removed optional attribute "name" since it can cause problems // generating some clients if names are duplicated. // input.setName(inputName); // Create the corresponding message ... final Object[] params = new Object[] {this.portType.getName(), this.operation.getName(), inputName}; final String msgName = WebServicePlugin.Util.getString("BasicWsdlGenerator.InputMessageName_PortTypeName_OperationName_InputName", params); //$NON-NLS-1$ final org.teiid.designer.metamodels.wsdl.Message message = this.factory.createMessage(); message.setName(msgName); message.setDefinitions(getDefinitions()); // adds to parent // And the message part ... final MessagePart part = this.factory.createMessagePart(); final XSDElementDeclaration xsdElement = object.getContentElement(); final XSDComplexTypeDefinition xsdComplexType = object.getContentComplexType(); final XSDSimpleTypeDefinition xsdSimpleType = object.getContentSimpleType(); if (xsdElement != null) { this.addReference(xsdElement); final String value = getXsdComponentIdentifier(xsdElement); part.setElement(value); } else if (xsdComplexType != null) { this.addReference(xsdComplexType); final String value = getXsdComponentIdentifier(xsdComplexType); part.setType(value); } else if (xsdSimpleType != null) { this.addReference(xsdSimpleType); final String value = getXsdComponentIdentifier(xsdSimpleType); part.setType(value); } part.setName(msgName); part.setMessage(message); // Set the message name on the input ... this.messagePartNameByWebServiceMessage.put(object, msgName); input.setMessage(this.doGetFullyQualifiedName(message)); input.setOperation(this.operation); // adds to parent // Add the documentation, if it exists ... addDocumentation(object, input); // Add the documentation, if it exists ... String inputMsg = null; final String inputDesc = getDescription(object); if (inputDesc != null && inputDesc.trim().length() != 0) { final Object[] params2 = new Object[] {this.portType.getName(), this.operation.getName(), inputDesc}; inputMsg = WebServicePlugin.Util.getString("BasicWsdlGenerator.InputMsgDesc_PortTypeName_OperationName_InputDesc", params2); //$NON-NLS-1$ } else { final Object[] params2 = new Object[] {this.portType.getName(), this.operation.getName()}; inputMsg = WebServicePlugin.Util.getString("BasicWsdlGenerator.InputMsgDesc_PortTypeName_OperationName", params2); //$NON-NLS-1$ } addDocumentation(inputMsg, message); // Create the binding operation input ... final BindingInput bindingInput = this.factory.createBindingInput(); bindingInput.setBindingOperation(this.bindingOp); // Defect 22988 - Removed optional attribute "name" since it can cause problems // generating some clients if names are duplicated. // bindingInput.setName(inputName); // must match portType/operation/input/@name final SoapBody soapBody = this.soapFactory.createSoapBody(); // per Jim Poulsen this next line is not required. Also it doesn't need to be a qualified name. // soapBody.getParts().add(this.doGetFullyQualifiedName(message)); soapBody.setUse(SoapUseType.LITERAL_LITERAL); bindingInput.setSoapBody(soapBody); return object; // this method handled it, so return non-null } /** * @see org.teiid.designer.metamodels.webservice.util.WebServiceSwitch#caseOutput(org.teiid.designer.metamodels.webservice.Output) * @since 4.2 */ public Object caseOutput( Output object ) { // Create a WSDL output ... final org.teiid.designer.metamodels.wsdl.Output output = this.factory.createOutput(); // Set the name on the output ... String outputName = object.getName(); if (outputName == null || outputName.trim().length() == 0) { outputName = WebServicePlugin.Util.getString("BasicWsdlGenerator.DefaultOutputName"); //$NON-NLS-1$ } // Defect 22988 - Removed optional attribute "name" since it can cause problems // generating some clients if names are duplicated. // output.setName(outputName); // Create the corresponding message ... final Object[] params = new Object[] {this.portType.getName(), this.operation.getName(), outputName}; final String msgName = WebServicePlugin.Util.getString("BasicWsdlGenerator.OutputMessageName_PortTypeName_OperationName_OutputName", params); //$NON-NLS-1$ final org.teiid.designer.metamodels.wsdl.Message message = this.factory.createMessage(); message.setName(msgName); message.setDefinitions(getDefinitions()); // adds to parent // And the message part ... final MessagePart part = this.factory.createMessagePart(); XSDElementDeclaration xsdElement = object.getContentElement(); if (xsdElement == null) { // There should be an element ref, but if not look for it via the XML document ref final XmlDocument xmlDoc = object.getXmlDocument(); if (xmlDoc != null) { final XmlRoot root = xmlDoc.getRoot(); if (root != null) { final XSDComponent comp = root.getXsdComponent(); if (comp instanceof XSDElementDeclaration) { xsdElement = (XSDElementDeclaration)comp; } } } } if (xsdElement != null) { this.addReference(xsdElement); final String value = getXsdComponentIdentifier(xsdElement); part.setElement(value); } else { final XSDComplexTypeDefinition xsdComplexType = object.getContentComplexType(); final XSDSimpleTypeDefinition xsdSimpleType = object.getContentSimpleType(); if (xsdComplexType != null) { this.addReference(xsdComplexType); final String value = getXsdComponentIdentifier(xsdComplexType); part.setType(value); } else if (xsdSimpleType != null) { this.addReference(xsdSimpleType); final String value = getXsdComponentIdentifier(xsdSimpleType); part.setType(value); } } part.setName(msgName); part.setMessage(message); // Set the message name on the input ... this.messagePartNameByWebServiceMessage.put(object, msgName); output.setMessage(this.doGetFullyQualifiedName(message)); output.setOperation(this.operation); // adds to parent // Add the documentation, if it exists ... addDocumentation(object, output); // Add the documentation, if it exists ... String outputMsg = null; final String outputDesc = getDescription(object); if (outputDesc != null && outputDesc.trim().length() != 0) { final Object[] params2 = new Object[] {this.portType.getName(), this.operation.getName(), outputDesc}; outputMsg = WebServicePlugin.Util.getString("BasicWsdlGenerator.OutputMsgDesc_PortTypeName_OperationName_OutputDesc", params2); //$NON-NLS-1$ } else { final Object[] params2 = new Object[] {this.portType.getName(), this.operation.getName()}; outputMsg = WebServicePlugin.Util.getString("BasicWsdlGenerator.OutputMsgDesc_PortTypeName_OperationName", params2); //$NON-NLS-1$ } addDocumentation(outputMsg, message); // Create the binding operation input ... final BindingOutput bindingOutput = this.factory.createBindingOutput(); bindingOutput.setBindingOperation(this.bindingOp); // Defect 22988 - Removed optional attribute "name" since it can cause problems // generating some clients if names are duplicated. // bindingOutput.setName(outputName); // must match portType/operation/output/@name final SoapBody soapBody = this.soapFactory.createSoapBody(); // per Jim Poulsen this next line is not required. Also it doesn't need to be a qualified name. // soapBody.getParts().add(this.doGetFullyQualifiedName(message)); soapBody.setUse(SoapUseType.LITERAL_LITERAL); bindingOutput.setSoapBody(soapBody); return object; // this method handled it, so return non-null } /** * Create a dummy Input/Message construct in the WSDL with no �parts�. This should be valid per the WS-I profile which * states that "Use of wsdl:message elements with zero parts is permitted in Document styles to permit operations that can * send or receive envelopes with empty soap:Bodys. Use of wsdl:message elements with zero parts is permitted in RPC * styles to permit operations that have no (zero) parameters and/or a return value". The dummy Input/Message construct is * to allow users to create web services that require no input message whatsoever. */ protected void createDummyInput() { // Create a WSDL input ... final org.teiid.designer.metamodels.wsdl.Input input = this.factory.createInput(); // Set the name on the input ... final String inputName = WebServicePlugin.Util.getString("BasicWsdlGenerator.DefaultInputName"); //$NON-NLS-1$ // Defect 22988 - Removed optional attribute "name" since it can cause problems // generating some clients if names are duplicated. // input.setName(inputName); // Create the corresponding message ... final Object[] params = new Object[] {this.portType.getName(), this.operation.getName(), inputName}; final String msgName = WebServicePlugin.Util.getString("BasicWsdlGenerator.InputMessageName_PortTypeName_OperationName_InputName", params); //$NON-NLS-1$ final org.teiid.designer.metamodels.wsdl.Message message = this.factory.createMessage(); message.setName(msgName); message.setDefinitions(getDefinitions()); // adds to parent // Set the message name on the input ... input.setMessage(this.doGetFullyQualifiedName(message)); input.setOperation(this.operation); // adds to parent // Add the documentation, if it exists ... final Object[] params2 = new Object[] {this.portType.getName(), this.operation.getName()}; final String inputMsg = WebServicePlugin.Util.getString("BasicWsdlGenerator.InputMsgDesc_PortTypeName_OperationName", params2); //$NON-NLS-1$ addDocumentation(inputMsg, message); // Create the binding operation input ... final BindingInput bindingInput = this.factory.createBindingInput(); bindingInput.setBindingOperation(this.bindingOp); // Defect 22988 - Removed optional attribute "name" since it can cause problems // generating some clients if names are duplicated. // bindingInput.setName(inputName); // must match portType/operation/input/@name final SoapBody soapBody = this.soapFactory.createSoapBody(); soapBody.setUse(SoapUseType.LITERAL_LITERAL); bindingInput.setSoapBody(soapBody); } } // ======================================================================================================== // WSDL 2.0 Generator // ======================================================================================================== protected class Wsdl20Generator extends Wsdl11Generator { protected Wsdl20Generator( final Resource wsdlResource, final String name, final String targetNamespace, final String defaultNamespace, final String urlRoot, final String urlSuffix, final String urlService, final List problems ) { super(wsdlResource, name, targetNamespace, defaultNamespace, urlRoot, urlSuffix, urlService, problems); } } }