From 4f933606e0fa045116e70764dbf9d99c05484ccb Mon Sep 17 00:00:00 2001 From: slaws Date: Mon, 15 Aug 2011 14:21:23 +0000 Subject: TUSCANY-3916 - extend WSDL serialization code to deal with imports/includes git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1157857 13f79535-47bb-0310-9956-ffa450edef68 --- .../core/assembly/impl/RuntimeEndpointImpl.java | 87 +++++- .../tuscany/sca/core/assembly/impl/WSDLHelper.java | 298 ++++++++++++++++++++- .../runtime/impl/EndpointReferenceBinderImpl.java | 15 +- 3 files changed, 373 insertions(+), 27 deletions(-) (limited to 'sca-java-2.x/trunk/modules/core/src/main/java') diff --git a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java index 8e5e3f5dc7..021260c364 100644 --- a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java +++ b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java @@ -24,13 +24,17 @@ import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.io.OutputStream; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import javax.wsdl.Definition; +import javax.wsdl.factory.WSDLFactory; import javax.wsdl.xml.WSDLWriter; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; @@ -110,6 +114,11 @@ import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; import org.apache.tuscany.sca.work.WorkScheduler; +import org.apache.tuscany.sca.xsd.XSDefinition; +import org.apache.ws.commons.schema.XmlSchema; +import org.apache.ws.commons.schema.XmlSchemaImport; +import org.apache.ws.commons.schema.XmlSchemaInclude; +import org.apache.ws.commons.schema.XmlSchemaObject; import org.oasisopen.sca.ServiceRuntimeException; /** @@ -117,6 +126,8 @@ import org.oasisopen.sca.ServiceRuntimeException; */ public class RuntimeEndpointImpl extends EndpointImpl implements RuntimeEndpoint, Externalizable { private static final long serialVersionUID = 1L; + private static final byte separator[] = {'_', 'X', '_'}; + private transient CompositeContext compositeContext; private transient RuntimeWireProcessor wireProcessor; private transient ProviderFactoryExtensionPoint providerFactories; @@ -1037,27 +1048,85 @@ public class RuntimeEndpointImpl extends EndpointImpl implements RuntimeEndpoint return xml; } - private String getWsdl() { - InterfaceContract ic = getComponentServiceInterfaceContract(); - if (ic == null || ic.getInterface() == null || !!!ic.getInterface().isRemotable()) { + private String getWsdl() { + InterfaceContract ic = getBindingInterfaceContract(); + if (ic == null || ic.getInterface() == null || !ic.getInterface().isRemotable()) { return ""; } - WSDLInterfaceContract wsdlIC = (WSDLInterfaceContract)getGeneratedWSDLContract(getComponentServiceInterfaceContract()); + WSDLInterfaceContract wsdlIC = (WSDLInterfaceContract)getGeneratedWSDLContract(ic); if (wsdlIC == null) { return ""; } WSDLInterface wsdl = (WSDLInterface)wsdlIC.getInterface(); - WSDLDefinition d = wsdl.getWsdlDefinition(); + WSDLDefinition wsdlDefinition = wsdl.getWsdlDefinition(); + Definition definition = wsdlDefinition.getDefinition(); + + // write out a flattened WSDL along with XSD ByteArrayOutputStream outStream = new ByteArrayOutputStream(); try { - WSDLWriter writer = javax.wsdl.factory.WSDLFactory.newInstance().newWSDLWriter(); - writer.writeWSDL(d.getDefinition(), outStream); + WSDLWriter writer = WSDLFactory.newInstance().newWSDLWriter(); + String baseURI = null; + if (wsdlDefinition.getLocation() != null) { + baseURI = wsdlDefinition.getLocation().toString(); + } else { + baseURI = "generated.wsdl"; + } + outStream.write(baseURI.getBytes()); + outStream.write(separator); + writer.writeWSDL(definition, outStream); + for (WSDLDefinition importedWSDLDefintion : wsdlDefinition.getImportedDefinitions()){ + outStream.write(separator); + baseURI = importedWSDLDefintion.getLocation().toString(); + outStream.write(baseURI.getBytes()); + outStream.write(separator); + writer.writeWSDL(importedWSDLDefintion.getDefinition(), outStream); + } + for (XSDefinition xsdDefinition : wsdlDefinition.getXmlSchemas()){ + // we store a reference to the schema schema. We don't need to write that out. + if (!xsdDefinition.getNamespace().equals("http://www.w3.org/2001/XMLSchema") && + xsdDefinition.getSchema() != null){ + writeSchema(outStream, xsdDefinition.getSchema()); + } + } } catch (Exception e){ throw new RuntimeException(e); } - return outStream.toString(); - } + String wsdlString = outStream.toString(); +/* + System.out.println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\n" + + wsdlString + + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n"); +*/ + return wsdlString; + } + + public void writeSchema(OutputStream outStream, XmlSchema schema) throws IOException { + // TODO - this doesn't write schema in the non-namespace namespace + if (schema != null && + schema.getTargetNamespace() != null && + !schema.getTargetNamespace().equals("http://www.w3.org/2001/XMLSchema") && + schema.getNamespaceContext() != null){ + outStream.write(separator); + String baseURI = schema.getSourceURI(); + outStream.write(baseURI.getBytes()); + outStream.write(separator); + schema.write(outStream); + + for (Iterator i = schema.getIncludes().getIterator(); i.hasNext();) { + XmlSchemaObject obj = (XmlSchemaObject)i.next(); + XmlSchema ext = null; + if (obj instanceof XmlSchemaInclude) { + ext = ((XmlSchemaInclude)obj).getSchema(); + } + if (obj instanceof XmlSchemaImport) { + ext = ((XmlSchemaImport)obj).getSchema(); + } + writeSchema(outStream, ext); + } + } + } + private void setNormalizedWSDLContract() { if (wsdl == null || wsdl.length() < 1) { return; diff --git a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java index 18dd21220b..de3db760de 100644 --- a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java +++ b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java @@ -19,15 +19,25 @@ package org.apache.tuscany.sca.core.assembly.impl; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URI; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.wsdl.Definition; import javax.wsdl.PortType; +import javax.wsdl.Types; +import javax.wsdl.xml.WSDLLocator; +import javax.wsdl.xml.WSDLReader; import org.apache.tuscany.sca.contribution.Contribution; import org.apache.tuscany.sca.contribution.ContributionFactory; @@ -35,6 +45,7 @@ import org.apache.tuscany.sca.contribution.processor.ExtensibleURLArtifactProces import org.apache.tuscany.sca.contribution.processor.ProcessorContext; import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessorExtensionPoint; import org.apache.tuscany.sca.contribution.resolver.ExtensibleModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; import org.apache.tuscany.sca.contribution.resolver.ModelResolverExtensionPoint; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.core.FactoryExtensionPoint; @@ -42,10 +53,16 @@ import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; import org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory; import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface; import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; -import org.apache.tuscany.sca.interfacedef.wsdl.impl.InvalidWSDLException; +import org.apache.tuscany.sca.xsd.XSDFactory; +import org.apache.tuscany.sca.xsd.XSDefinition; +import org.apache.tuscany.sca.xsd.xml.XSDModelResolver; +import org.apache.ws.commons.schema.XmlSchema; +import org.apache.ws.commons.schema.XmlSchemaCollection; +import org.apache.ws.commons.schema.resolver.DefaultURIResolver; +import org.xml.sax.InputSource; public class WSDLHelper { - + /** * This creates a WSDLInterfaceContract from a WSDL document * TODO: Presently this writes the wsdl string to a temporary file which is then used by the Tuscany contribution @@ -53,7 +70,7 @@ public class WSDLHelper { * that happen without needing the external file but i've not been able to find the correct configuration to * get that to happen with all the schema objects created correctly. */ - public static WSDLInterfaceContract createWSDLInterfaceContract(ExtensionPointRegistry registry, String wsdl) { + public static WSDLInterfaceContract createWSDLInterfaceContractViaFile(ExtensionPointRegistry registry, String wsdl) { File wsdlFile = null; try { @@ -85,7 +102,7 @@ public class WSDLHelper { wsdlFile.delete(); return wsdlIC; - +/* } catch (InvalidWSDLException e) { //* TODO: Also, this doesn't seem to work reliably and sometimes the schema objects don't get built correctly //* org.apache.tuscany.sca.interfacedef.wsdl.impl.InvalidWSDLException: Element cannot be resolved: {http://sample/}sayHello @@ -94,6 +111,7 @@ public class WSDLHelper { // I'm still trying to track this down but committing like this to see if anyone has any ideas e.printStackTrace(); return null; +*/ } catch(Exception e) { throw new RuntimeException(e); } finally { @@ -114,4 +132,276 @@ public class WSDLHelper { } return f; } + + /* + * A rework of the above code that + * + * 1 - doesn't use a intermediate file + * 2 - takes care of imports/includes + * 3 - takes care of call and callback interfaces (It doesn't yet but needs to) + * + * Re. point 1 - In theory it's neater but the Tuscany processors/resolvers don't know how to do this + * so there is quite a bit of code here. I don't really like it but we can sleep on it + * and look at how to integrate it into the runtime or even take a different approach to + * moving the interface about + */ + + public static WSDLInterfaceContract createWSDLInterfaceContract(ExtensionPointRegistry registry, String wsdl) { + try { + // need to read all the WSDL and XSD in from the wsdl string. The WSDL and XSD appear sequentially in + // the following format: + // + // So we need to read each WSDL and XSD separately and then fix up the includes/imports as appropriate + String xmlArray[] = wsdl.split("_X_"); + + String topWSDLLocation = null; + Map xmlMap = new HashMap(); + + for (int i = 0; i < xmlArray.length; i = i + 2){ + String location = xmlArray[i]; + String xml = xmlArray[i+1]; + // strip the file name out of the location + location = location.substring(location.lastIndexOf("/") + 1); + + if (location.endsWith(".wsdl")){ + xmlMap.put(location, + new WSDLInfo(xmlArray[i], + xml)); + + if (topWSDLLocation == null){ + topWSDLLocation = location; + } + } else { + xmlMap.put(location, + new XSDInfo(xmlArray[i], + xml)); + } + } + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory wsdlFactory = modelFactories.getFactory(org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory.class); + XSDFactory xsdFactory = modelFactories.getFactory(XSDFactory.class); + XmlSchemaCollection schemaCollection = new XmlSchemaCollection(); + schemaCollection.setSchemaResolver(new XSDURIResolverImpl(xmlMap)); + ContributionFactory contributionFactory = modelFactories.getFactory(ContributionFactory.class); + final org.apache.tuscany.sca.contribution.Contribution contribution = contributionFactory.createContribution(); + ProcessorContext processorContext = new ProcessorContext(); + + ExtensibleModelResolver extensibleResolver = new ExtensibleModelResolver(contribution, registry.getExtensionPoint(ModelResolverExtensionPoint.class), modelFactories); + ModelResolver wsdlResolver = (ModelResolver)extensibleResolver.getModelResolverInstance(WSDLDefinition.class); + XSDModelResolver xsdResolver = (XSDModelResolver)extensibleResolver.getModelResolverInstance(XSDefinition.class); + contribution.setURI("temp"); + contribution.setLocation(topWSDLLocation); + contribution.setModelResolver(extensibleResolver); + + // read + for (XMLString xmlString : xmlMap.values()){ + if (xmlString instanceof WSDLInfo){ + WSDLReader reader = javax.wsdl.factory.WSDLFactory.newInstance().newWSDLReader(); + reader.setFeature("javax.wsdl.verbose", false); + reader.setFeature("javax.wsdl.importDocuments", true); + WSDLLocatorImpl locator = new WSDLLocatorImpl(xmlString.getBaseURI(), xmlMap); + Definition readDefinition = reader.readWSDL(locator); + + WSDLDefinition wsdlDefinition = wsdlFactory.createWSDLDefinition(); + wsdlDefinition.setDefinition(readDefinition); + wsdlDefinition.setLocation(new URI(xmlString.getBaseURI())); + + ((WSDLInfo)xmlString).setWsdlDefintion(wsdlDefinition); + wsdlResolver.addModel(wsdlDefinition, processorContext); + + } else { + InputStream inputStream = new ByteArrayInputStream(xmlString.getXmlString().getBytes()); + InputSource inputSource = new InputSource(inputStream); + inputSource.setSystemId(xmlString.getBaseURI()); + XmlSchema schema = schemaCollection.read(inputSource, null); + inputStream.close(); + + XSDefinition xsdDefinition = xsdFactory.createXSDefinition(); + xsdDefinition.setSchema(schema); + + ((XSDInfo)xmlString).setXsdDefinition(xsdDefinition); + xsdResolver.addModel(xsdDefinition, processorContext); + } + } + + // resolve + for (XMLString xmlString : xmlMap.values()){ + if (xmlString instanceof WSDLInfo){ + WSDLDefinition wsdlDefinition = ((WSDLInfo)xmlString).getWsdlDefintion(); + + // link to imports + for (Map.Entry> entry : + ((Map>)wsdlDefinition.getDefinition().getImports()).entrySet()) { + for (javax.wsdl.Import imp : entry.getValue()) { + String wsdlName = imp.getDefinition().getDocumentBaseURI(); + WSDLInfo wsdlInfo = (WSDLInfo)xmlMap.get(getFilenameWithoutPath(wsdlName)); + wsdlDefinition.getImportedDefinitions().add(wsdlInfo.getWsdlDefintion()); + } + } + + // link to in-line types + Types types = wsdlDefinition.getDefinition().getTypes(); + if ( types != null){ + for (int i=0; i < types.getExtensibilityElements().size(); i++){ + String schemaName = xmlString.getBaseURI() + "#" + i++; + XSDInfo xsdInfo = (XSDInfo)xmlMap.get(getFilenameWithoutPath(schemaName)); + if (xsdInfo != null){ + wsdlDefinition.getXmlSchemas().add(xsdInfo.getXsdDefinition()); + } + } + } + } else { + // Schema should already be linked via the schema model + } + } + + WSDLInfo topWSDL = (WSDLInfo)xmlMap.get(topWSDLLocation); + WSDLDefinition topWSDLDefinition = topWSDL.getWsdlDefintion(); + + PortType portType = (PortType)topWSDLDefinition.getDefinition().getAllPortTypes().values().iterator().next(); + WSDLInterface readWSDLInterface = wsdlFactory.createWSDLInterface(portType, topWSDLDefinition, extensibleResolver, null); + + WSDLInterfaceContract wsdlInterfaceContract = wsdlFactory.createWSDLInterfaceContract(); + wsdlInterfaceContract.setInterface(readWSDLInterface); + return wsdlInterfaceContract; + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + private static class XMLString { + private String baseURI; + private String xmlString; + + public XMLString(String baseURI, String xmlString){ + this.baseURI = baseURI; + this.xmlString = xmlString; + } + + public String getBaseURI() { + return baseURI; + } + + public String getXmlString() { + return xmlString; + } + } + + private static class XSDInfo extends XMLString { + + XSDefinition xsdDefinition; + + public XSDInfo(String baseURI, String xmlString) { + super(baseURI, xmlString); + } + + public void setXsdDefinition(XSDefinition xsdDefinition) { + this.xsdDefinition = xsdDefinition; + } + + public XSDefinition getXsdDefinition() { + return xsdDefinition; + } + } + + private static class WSDLInfo extends XMLString { + + WSDLDefinition wsdlDefintion; + + public WSDLInfo(String baseURI, String xmlString) { + super(baseURI, xmlString); + } + + public void setWsdlDefintion(WSDLDefinition wsdlDefintion) { + this.wsdlDefintion = wsdlDefintion; + } + + public WSDLDefinition getWsdlDefintion() { + return wsdlDefintion; + } + } + + private static class WSDLLocatorImpl implements WSDLLocator { + private Map xmlMap; + private String baseURI; + private String latestImportURI; + + public WSDLLocatorImpl(String baseURI, Map xmlMap) { + this.baseURI = baseURI; + this.xmlMap = xmlMap; + } + + public void close() { +/* + try { + inputStream.close(); + } catch (IOException e) { + // Ignore + } +*/ + } + + public InputSource getBaseInputSource() { + return getInputSource(getFilenameWithoutPath(baseURI), xmlMap); + } + + public String getBaseURI() { + return baseURI; + } + + public InputSource getImportInputSource(String parentLocation, String importLocation) { + latestImportURI = importLocation; + return getInputSource(getFilenameWithoutPath(importLocation), xmlMap); + } + + public String getLatestImportURI() { + return latestImportURI; + } + } + + private static class XSDURIResolverImpl extends DefaultURIResolver { + + private Map xmlMap; + + public XSDURIResolverImpl(Map xmlMap) { + this.xmlMap = xmlMap; + } + + @Override + protected URL getURL(URL contextURL, String spec) throws IOException { + return super.getURL(contextURL, spec); + } + @Override + public InputSource resolveEntity(String namespace, + String schemaLocation, + String baseUri) { + return getInputSource(getFilenameWithoutPath(schemaLocation), xmlMap); + } + } + + private static InputSource getInputSource(String uri, Map xmlMap){ + String xmlString = xmlMap.get(uri).getXmlString(); + InputStream inputStream = new ByteArrayInputStream(xmlString.getBytes()); + InputSource inputSource = new InputSource(inputStream); + inputSource.setSystemId(uri); + return inputSource; + } + + private static String getFilenameWithoutPath(String filename){ + // work out what the file name is that is being imported + // XSDs imports are written out by Tuscany with an relative web address such as + // /services/AccountService?xsd=wsdl-serialize.xsd + // for the time being just string the file name off the end. We are making + // assumption that the interface doesn't involve two files with the same + // name in different locations + int xsdIndex = filename.lastIndexOf("?xsd="); + int wsdlIndex = filename.lastIndexOf("/"); + if ( xsdIndex >= 0){ + return filename.substring(xsdIndex + 5); + } else { + return filename.substring(wsdlIndex + 1); + } + // What happens with generated WSDL? + } } diff --git a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java index 99d9cb464f..6b87b55afc 100644 --- a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java +++ b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java @@ -913,20 +913,7 @@ public class EndpointReferenceBinderImpl implements EndpointReferenceBinder { matchAudit.append("Match because there is no interface contract on the reference "); matchAudit.appendSeperator(); return true; - } - -// // TODO - is there a better test for this. Would have to cast to the -// // correct iface type to get to the resolved flag -// // We need to rely on normailzed interfaces in this case!! - if (endpointContract.getInterface().getOperations().size() == 0){ - // the interface contract is likely remote but unresolved - // we discussed this on the ML and decided that we could - // live with this for the case where there is no central matching of references - // to services. Any errors will be detected when the message flows. - matchAudit.append("Match because the endpoint is remote and we don't have a copy of it's interface contract "); - matchAudit.appendSeperator(); - return true; - } + } // If the contracts are not of the same type or normalized interfaces are available // use them -- cgit v1.2.3