/* * 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.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; 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.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xsd.XSDComplexTypeDefinition; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSimpleTypeDefinition; import org.eclipse.xsd.impl.XSDSchemaImpl; 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.resource.EmfResource; import org.teiid.designer.core.util.ModelContents; import org.teiid.designer.core.util.ModelResourceContainerFactory; import org.teiid.designer.core.util.ModelVisitor; import org.teiid.designer.core.util.ModelVisitorProcessor; import org.teiid.designer.core.util.NewModelObjectHelperManager; import org.teiid.designer.core.validation.rules.StringNameValidator; import org.teiid.designer.metamodels.core.Annotation; import org.teiid.designer.metamodels.core.ModelAnnotation; import org.teiid.designer.metamodels.core.ModelType; import org.teiid.designer.metamodels.webservice.Input; import org.teiid.designer.metamodels.webservice.Interface; import org.teiid.designer.metamodels.webservice.Operation; import org.teiid.designer.metamodels.webservice.Output; import org.teiid.designer.metamodels.webservice.WebServiceComponent; import org.teiid.designer.metamodels.webservice.WebServiceFactory; import org.teiid.designer.metamodels.webservice.WebServicePackage; 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.Message; import org.teiid.designer.metamodels.wsdl.MessagePart; import org.teiid.designer.metamodels.wsdl.NamespaceDeclaration; import org.teiid.designer.metamodels.wsdl.ParamType; import org.teiid.designer.metamodels.wsdl.PortType; import org.teiid.designer.metamodels.wsdl.util.WsdlSwitch; import org.teiid.designer.webservice.IWebServiceGenerator; import org.teiid.designer.webservice.WebServicePlugin; /** * @since 8.0 */ public class BasicWebServiceGenerator implements IWebServiceGenerator { private Resource webServiceResource; protected final List wsdlDefinitions; private final List xsdSchemas; Collection selectedWsdlOperations; /** * @since 4.2 */ public BasicWebServiceGenerator() { super(); this.wsdlDefinitions = new ArrayList(); this.xsdSchemas = new ArrayList(); this.selectedWsdlOperations = new HashSet(); } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#setWebServiceResource(org.eclipse.emf.ecore.resource.Resource) * @since 4.2 */ @Override public void setWebServiceResource( Resource wsModel ) { CoreArgCheck.isNotNull(wsModel); this.webServiceResource = wsModel; } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#getWebServiceResource() * @since 4.2 */ @Override public Resource getWebServiceResource() { return this.webServiceResource; } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#addWsdlDefinitions(org.teiid.designer.metamodels.wsdl.Definitions) * @since 4.2 */ @Override public void addWsdlDefinitions( final Definitions wsdlDefinitions ) { CoreArgCheck.isNotNull(wsdlDefinitions); if (!this.wsdlDefinitions.contains(wsdlDefinitions)) { this.wsdlDefinitions.add(wsdlDefinitions); } } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#addWsdlDefinitions(java.util.List) * @since 4.2 */ @Override public void addWsdlDefinitions( List wsdlDefinitions ) { CoreArgCheck.isNotNull(wsdlDefinitions); final Iterator iter = wsdlDefinitions.iterator(); while (iter.hasNext()) { final Object obj = iter.next(); if (obj instanceof Definitions) { addWsdlDefinitions((Definitions)obj); } } } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#getWsdlDefinitions() * @since 4.2 */ @Override public List getWsdlDefinitions() { return this.wsdlDefinitions; } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#addXsdSchema(org.eclipse.xsd.XSDSchema) * @since 4.2 */ @Override public void addXsdSchema( XSDSchema schema ) { CoreArgCheck.isNotNull(schema); if (!this.xsdSchemas.contains(schema)) { this.xsdSchemas.add(schema); } } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#addXsdSchemas(java.util.List) * @since 4.2 */ @Override public void addXsdSchemas( List schemas ) { CoreArgCheck.isNotNull(schemas); final Iterator iter = schemas.iterator(); while (iter.hasNext()) { final Object obj = iter.next(); if (obj instanceof XSDSchema) addXsdSchema((XSDSchema)obj); } } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#getXsdSchemas() * @since 4.2 */ @Override public List getXsdSchemas() { return this.xsdSchemas; } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#setSelectedOperations(java.util.Collection) * @since 5.0 */ @Override public void setSelectedOperations( Collection operations ) { this.selectedWsdlOperations = operations; } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#getSelectedOperations() * @since 5.0 */ @Override public Collection getSelectedOperations() { return this.selectedWsdlOperations; } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#generate(org.eclipse.core.runtime.IProgressMonitor) * @since 4.2 */ @Override public IStatus generate( IProgressMonitor monitor ) { final List problems = new ArrayList(); if (this.getWebServiceResource() == null) { final String msg = WebServicePlugin.Util.getString("BasicWebServiceGenerator.NoWebServiceModelSpecified"); //$NON-NLS-1$ problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, 0, msg, null)); } else { doGenerate(monitor, problems); } // Convert the problems to a status IStatus result = null; if (problems.size() == 0) { final String msg = WebServicePlugin.Util.getString("BasicWebServiceGenerator.GenerationOfWebServiceModelSucceeded"); //$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 over the problems and find the number of warnings and errors ... int errors = 0; int warnings = 0; final Iterator iter = problems.iterator(); while (iter.hasNext()) { final IStatus status = (IStatus)iter.next(); switch (status.getSeverity()) { case IStatus.ERROR: { ++errors; break; } case IStatus.WARNING: { ++warnings; break; } } } final Object[] params = new Object[] {new Integer(errors), new Integer(warnings)}; final String msg = WebServicePlugin.Util.getString("BasicWebServiceGenerator.GeneratedWebServiceModelWithErrorsAndWarnings", params); //$NON-NLS-1$ final IStatus[] children = (IStatus[])problems.toArray(new IStatus[problems.size()]); result = new MultiStatus(WebServicePlugin.PLUGIN_ID, 0, children, msg, null); } return result; } /** * @see org.teiid.designer.webservice.IWebServiceGenerator#generate(org.eclipse.core.runtime.IProgressMonitor, * java.util.List) * @since 4.2 */ @Override public void generate( IProgressMonitor monitor, List problems ) { doGenerate(monitor, problems); } // ======================================================================================================== // Overridable methods // ======================================================================================================== protected void doGenerate( IProgressMonitor monitor, final List problems ) { // Create the correct visitor for the desired version ... final ModelContents contents = doGetModelContents(); // Set up the correct model information ... final ModelAnnotation modelAnnotation = contents.getModelAnnotation(); modelAnnotation.setModelType(ModelType.VIRTUAL_LITERAL); modelAnnotation.setPrimaryMetamodelUri(WebServicePackage.eNS_URI); // Set up the description ... if (this.wsdlDefinitions.size() != 0) { final String desc = modelAnnotation.getDescription(); if (desc == null || desc.trim().length() == 0) { try { final StringBuffer sb = new StringBuffer(); final String msg = WebServicePlugin.Util.getString("BasicWebServiceGenerator.DescriptionStartingSection"); //$NON-NLS-1$ sb.append(msg); final Iterator iter = this.wsdlDefinitions.iterator(); while (iter.hasNext()) { final Definitions defns = (Definitions)iter.next(); final String name = defns.getTargetNamespace(); final String targetNs = defns.getTargetNamespace(); final String line = WebServicePlugin.Util.getString("BasicWebServiceGenerator.DescriptionWsdlNameAndTargetNS", name, targetNs); //$NON-NLS-1$ sb.append(CoreStringUtil.LINE_SEPARATOR); sb.append(line); } modelAnnotation.setDescription(sb.toString()); } catch (RuntimeException t) { final String msg = WebServicePlugin.Util.getString("BasicWebServiceGenerator.UnexpectedProblemBuildingDescription"); //$NON-NLS-1$ WebServicePlugin.Util.log(IStatus.WARNING, t, msg); } } } final WsdlVisitor visitor = new WsdlVisitor(this.webServiceResource, wsdlDefinitions, contents, problems); // Walk the objects and use the generator ... final ModelVisitorProcessor processor = new ModelVisitorProcessor(visitor); try { processor.walk(this.wsdlDefinitions, ModelVisitorProcessor.DEPTH_INFINITE); } catch (ModelerCoreException e) { final String msg = WebServicePlugin.Util.getString("BasicWebServiceGenerator.ErrorWhileProcessingWsdlAndCreatingWebServiceModel"); //$NON-NLS-1$ final IStatus status = new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, 0, msg, e); problems.add(status); } // Signal the generator to complete the WSDL (adding any binding information, etc.) visitor.complete(); } protected ModelContents doGetModelContents() { final ModelContents contents = this.webServiceResource instanceof EmfResource ? ((EmfResource)this.webServiceResource).getModelContents() : new ModelContents( this.webServiceResource); return contents; } /** * @param uri * @return * @since 4.2 */ protected List doFindSchemas( final String uri ) { final String uriStr = uri != null ? uri : ""; //$NON-NLS-1$ final Iterator iter = this.xsdSchemas.iterator(); final List schemas = new ArrayList(xsdSchemas.size()); while (iter.hasNext()) { final XSDSchema schema = (XSDSchema)iter.next(); if (uriStr.equals(schema.getTargetNamespace())) { schemas.add(schema); } } return schemas; } // ======================================================================================================== // Web Service Generator // ======================================================================================================== protected class WsdlVisitor extends WsdlSwitch implements ModelVisitor { private final String DEFAULT_NAMESPACE_PREFIX = "DEFAULT_NS_PREFIX_9485338"; //$NON-NLS-1$ private final List problems; protected final Resource resource; protected final ModelContents contents; private final WebServiceFactory factory; private final Map namespaceUrisByPrefix; private List definitions; private Interface iface; // the one created ... /* * Map of operation Qname to operation instance object. */ private Map operations; protected WsdlVisitor( final Resource webServiceResource, final List wsdlDefinitions, final ModelContents contents, final List problems ) { this.problems = problems; this.resource = webServiceResource; this.factory = WebServiceFactory.eINSTANCE; this.namespaceUrisByPrefix = new HashMap(); this.contents = contents != null ? contents : new ModelContents(this.resource); this.definitions = wsdlDefinitions; this.operations = new HashMap(); } 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 addDescription( WebServiceComponent component, Documented wsdlDocumented ) { if (wsdlDocumented != null) { final Documentation doc = wsdlDocumented.getDocumentation(); if (doc != null) { final String desc = doc.getTextContent(); if (desc != null && desc.trim().length() != 0) { // Find the model annotation and set the description ... Annotation annotation = this.contents.getAnnotation(component); if (annotation == null) { annotation = ModelResourceContainerFactory.createNewAnnotation(component, this.contents.getAnnotationContainer(true)); } if (annotation != null) { annotation.setDescription(desc); return desc; } } } } return null; } protected String getNamespaceUriForPrefix( final String prefix ) { if (prefix == null || prefix.trim().length() == 0) { return (String)this.namespaceUrisByPrefix.get(DEFAULT_NAMESPACE_PREFIX); } return (String)this.namespaceUrisByPrefix.get(prefix); } protected Identifier parseIdentifier( final String identifier ) { final List idParts = CoreStringUtil.split(identifier, ":"); //$NON-NLS-1$ if (idParts.isEmpty()) { return null; } String name = null; String prefix = null; if (idParts.size() == 1) { name = (String)idParts.get(0); } else { prefix = (String)idParts.get(0); name = (String)idParts.get(1); } // Look for the namespace URI ... final String uri = getNamespaceUriForPrefix(prefix); return new Identifier(prefix, name, uri); } protected Message findMessage( ParamType paramType ) { final String msgId = paramType.getMessage(); if (msgId == null || msgId.trim().length() == 0) { return null; } final Identifier identifier = parseIdentifier(msgId); final String uri = identifier.uri; for (Iterator iter = definitions.iterator(); iter.hasNext();) { final Definitions def = (Definitions)iter.next(); // See if the URI is the paramType's target namespace ... if (def.getTargetNamespace().equals(uri)) { // Look through the messages to find one with the same name ... final Iterator iter1 = def.getMessages().iterator(); while (iter1.hasNext()) { final Message msg = (Message)iter1.next(); if (msg.getName() != null && msg.getName().equals(identifier.name)) { return msg; } } } } return null; } /** * Signals the generator to add the bindings, etc. * * @since 4.2 */ public void complete() { } // -------------------------------------------------------------------------------------------------------- // WSDL Processing Methods // -------------------------------------------------------------------------------------------------------- /** * @see org.teiid.designer.metamodels.wsdl.util.WsdlSwitch#caseDefinitions(org.teiid.designer.metamodels.wsdl.Definitions) * @since 4.2 */ @Override public Object caseDefinitions( Definitions object ) { // Populate the prefix to namespace URI map ... final Iterator iter = object.getDeclaredNamespaces().iterator(); while (iter.hasNext()) { final NamespaceDeclaration nsDecl = (NamespaceDeclaration)iter.next(); String prefix = nsDecl.getPrefix(); if (prefix == null || prefix.trim().length() == 0) { prefix = DEFAULT_NAMESPACE_PREFIX; } final String uri = nsDecl.getUri(); this.namespaceUrisByPrefix.put(prefix, uri); // Look for one of the XSD Schema of Schemas ... if (XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001.equals(uri) || XSDConstants.SCHEMA_FOR_SCHEMA_URI_2000_10.equals(uri) || XSDConstants.SCHEMA_FOR_SCHEMA_URI_1999.equals(uri)) { final XSDSchema sos = XSDSchemaImpl.getSchemaForSchema(uri); if (sos != null) { BasicWebServiceGenerator.this.addXsdSchema(sos); } } } return object; } /** * @see org.teiid.designer.metamodels.wsdl.util.WsdlSwitch#casePortType(org.teiid.designer.metamodels.wsdl.PortType) * @since 4.2 */ @Override public Object casePortType( PortType object ) { // Check the operations under this PortType to see if any are in the selectedWsdlOperations if (selectedWsdlOperations != null && !selectedWsdlOperations.contains(object)) { boolean doCreate = false; for (Iterator iter = object.getOperations().iterator(); iter.hasNext();) { Object nextObj = iter.next(); if (nextObj instanceof org.teiid.designer.metamodels.wsdl.Operation) { doCreate = selectedWsdlOperations.contains(nextObj); } if (doCreate) { break; } } if (!doCreate) { return null; } } // Create the Interface ... this.iface = this.factory.createInterface(); StringNameValidator validator = new StringNameValidator(); String name = object.getName(); if (!validator.isValidName(name)) { name = validator.createValidName(name); } this.iface.setName(name); // Add the interface to the resource ... this.resource.getContents().add(this.iface); return object; } /** * @see org.teiid.designer.metamodels.wsdl.util.WsdlSwitch#caseOperation(org.teiid.designer.metamodels.wsdl.Operation) * @since 4.2 */ @Override public Object caseOperation( org.teiid.designer.metamodels.wsdl.Operation object ) { if (selectedWsdlOperations != null && !selectedWsdlOperations.contains(object)) { return null; } // Create the Interface ... final Operation operation = this.factory.createOperation(); final String name = object.getName(); final String namespace = object.getPortType().getDefinitions().getTargetNamespace(); final QName qname = new QName(namespace, name); operation.setName(name); // Add the operation to the interface ... operation.setInterface(this.iface); try { NewModelObjectHelperManager.helpCreate(operation, null); } catch (ModelerCoreException theException) { String message = WebServicePlugin.Util.getString("WebServiceBuilderHelper.createOperation.errMsg"); //$NON-NLS-1$ WebServicePlugin.Util.log(IStatus.ERROR, theException, message); } /* * add this operation to the Map of operations maintained by this visitor. */ operations.put(qname, operation); return object; } /** * @see org.teiid.designer.metamodels.wsdl.util.WsdlSwitch#caseInput(org.teiid.designer.metamodels.wsdl.Input) * @since 4.2 */ @Override public Object caseInput( org.teiid.designer.metamodels.wsdl.Input object ) { // Create the Interface ... final Input input = this.factory.createInput(); doProcessMessage(input, object); /* * find the operation that contains this Input */ final String operationName = object.getOperation().getName(); final String operationNamespace = object.getOperation().getPortType().getDefinitions().getTargetNamespace(); final Operation operation = (Operation)operations.get(new QName(operationNamespace, operationName)); // Add the input to the operation ... input.setOperation(operation); return object; } /** * @see org.teiid.designer.metamodels.wsdl.util.WsdlSwitch#caseOutput(org.teiid.designer.metamodels.wsdl.Output) * @since 4.2 */ @Override public Object caseOutput( org.teiid.designer.metamodels.wsdl.Output object ) { // Create the Interface ... final Output output = this.factory.createOutput(); doProcessMessage(output, object); /* * find the operation that contains this Input */ final String operationName = object.getOperation().getName(); final String operationNamespace = object.getOperation().getPortType().getDefinitions().getTargetNamespace(); final Operation operation = (Operation)operations.get(new QName(operationNamespace, operationName)); // Add the input to the operation ... output.setOperation(operation); return object; } /** * @see org.teiid.designer.metamodels.wsdl.util.WsdlSwitch#caseInput(org.teiid.designer.metamodels.wsdl.Input) * @since 4.2 */ public Object doProcessMessage( final org.teiid.designer.metamodels.webservice.Message message, final org.teiid.designer.metamodels.wsdl.ParamType object ) { // Create the Interface ... Message msg = null; String name = object.getName(); String xsdIdentifier = null; if (name == null || name.trim().length() == 0) { // Look for the corresponding message part, and get it's name msg = findMessage(object); if (msg != null) { name = msg.getName(); final boolean needName = (name == null || name.trim().length() == 0); // Iterate over the parts ... final Iterator iter = msg.getParts().iterator(); while (iter.hasNext()) { final MessagePart part = (MessagePart)iter.next(); if (needName) { name = part.getName(); } final String type = part.getType(); final String element = part.getElement(); if (type != null && type.trim().length() != 0) { xsdIdentifier = type; } else if (element != null && element.trim().length() != 0) { xsdIdentifier = element; } break; } } } else { msg = findMessage(object); if (msg != null) { if (msg.getParts() != null) { final Iterator mIter = msg.getParts().iterator(); while (mIter.hasNext()) { final MessagePart part = (MessagePart)mIter.next(); final String type = part.getType(); final String element = part.getElement(); if (type != null && type.trim().length() != 0) { xsdIdentifier = type; } else if (element != null && element.trim().length() != 0) { xsdIdentifier = element; } break; } } } } message.setName(name); // Find the XSD type ... if (xsdIdentifier != null && xsdIdentifier.trim().length() != 0) { final Identifier ident = parseIdentifier(xsdIdentifier); if (ident != null) { /* * HEre we must change the code that is finding the schema. Currently it is returning the first schema with * the target namespace that matches the XSD component that we are looking for. In many cases there can be * multiple XML schema files with the same target namespace. */ final List schemas = doFindSchemas(ident.uri); if (schemas.size() > 0) { for (Iterator iter = schemas.iterator(); iter.hasNext();) { XSDSchema schema = (XSDSchema)iter.next(); if (XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001.equals(ident.uri) || XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001.equals(ident.uri) || XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001.equals(ident.uri)) { // This is a reference to a Schema Of Schemas, so this reference // can only be to a built-in simple type, so resolve it ... final XSDSimpleTypeDefinition st = schema.resolveSimpleTypeDefinition(ident.uri, ident.name); if (st != null) { message.setContentSimpleType(st); } } else { // Look for an element declaration ... final XSDElementDeclaration ed = schema.resolveElementDeclaration(ident.uri, ident.name); if (ed != null) { // Try to resolve with our simple datatypes ... message.setContentElement(ed); } else { // Look for a complex type ... final XSDComplexTypeDefinition ct = schema.resolveComplexTypeDefinition(ident.uri, ident.name); if (ct != null) { message.setContentComplexType(ct); } else { // Look for a simple type ... final XSDSimpleTypeDefinition st = schema.resolveSimpleTypeDefinition(ident.uri, ident.name); if (st != null) { message.setContentSimpleType(st); } } } } } } } } // Set the description, if any ... String desc = addDescription(message, object); if (desc == null) { // Try setting the description to the message ... if (msg == null) { msg = findMessage(object); desc = addDescription(message, msg); } } return object; } } protected class Identifier { public final String prefix; public final String name; public final String uri; public Identifier( final String prefix, final String name, final String uri ) { this.prefix = prefix; this.name = name; this.uri = uri; } } }