[MOBY-guts] biomoby commit
Paul Gordon
gordonp at dev.open-bio.org
Mon Jun 30 17:42:29 UTC 2008
gordonp
Mon Jun 30 13:42:29 EDT 2008
Update of /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util
In directory dev.open-bio.org:/tmp/cvs-serv9782/src/main/ca/ucalgary/services/util
Modified Files:
WSDLConfig.java
Added Files:
SourceMap.java
Log Message:
Changes to reflect full SAWSDL support
moby-live/Java/src/main/ca/ucalgary/services/util SourceMap.java,NONE,1.1 WSDLConfig.java,1.2,1.3
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util/WSDLConfig.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util/WSDLConfig.java 2008/06/10 21:59:57 1.2
+++ /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util/WSDLConfig.java 2008/06/30 17:42:29 1.3
@@ -1,5 +1,6 @@
package ca.ucalgary.services.util;
+import org.biomoby.shared.LSIDResolver;
import org.biomoby.shared.MobyPrefixResolver;
import org.biomoby.shared.NamespaceContextImpl;
import org.biomoby.shared.parser.MobyTags;
@@ -8,11 +9,16 @@
import javax.xml.namespace.QName;
import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.*;
import javax.xml.xpath.*;
+import javax.xml.ws.*;
-import java.io.InputStream;
+import java.io.*;
import java.net.URL;
import java.util.*;
+import java.util.logging.*;
/**
* Used to expose a WSDL file enhanced with SAWSDL and Moby markup as a Moby service.
@@ -29,7 +35,9 @@
public static final String SAWSDL_MODEL_ATTR = "modelReference";
public static final String SAWSDL_INMAP_ATTR = "loweringSchemaMapping";
public static final String SAWSDL_OUTMAP_ATTR = "liftingSchemaMapping";
+ public static final String MOBY_SECONDARY_SOURCE_ATTR = "secondaryParamSource";
+ private final String ARRAY_SENTINEL = "applyToEachXSIArrayItem";
private final String SERVICENAME_ATTR_XPATH = "//sawsdl:attrExtensions";
// note that XPath //@moby:"+SERVICE_NAME_ATTR doesn't work, not sure why at the moment, so we don't support WSDL2.0 yet...
@@ -40,11 +48,15 @@
private Map<String,QName> mobyServiceName2Service;
private Map<String,QName> mobyServiceName2Port;
- private Map<String,String> mobyServiceName2OpInput;
- private Map<String,String> mobyServiceName2OpOutput;
+ private Map<String,String> mobyServiceName2TargetNamespaceURI;
+ private Map<String,QName> mobyServiceName2OpInput;
+ private Map<String,QName> mobyServiceName2OpOutput;
private Map<String,String> mobyServiceName2Op;
private Map<String,Map<String,String>> mobyServiceName2InputXSDTypes;
private Map<String,Map<String,String>> mobyServiceName2OutputXSDTypes;
+ private LSIDResolver lsidResolver;
+
+ private static Logger logger = Logger.getLogger("ca.ucalgary.services.util.WSDLConfig");
static{
XPathFactory xPathFactory = XPathFactory.newInstance();
@@ -69,12 +81,14 @@
mobyServiceName2Service = new HashMap<String,QName>();
mobyServiceName2Port = new HashMap<String,QName>();
+ mobyServiceName2TargetNamespaceURI = new HashMap<String,String>();
mobyServiceName2Op = new HashMap<String,String>();
- mobyServiceName2OpInput = new HashMap<String,String>();
- mobyServiceName2OpOutput = new HashMap<String,String>();
+ mobyServiceName2OpInput = new HashMap<String,QName>();
+ mobyServiceName2OpOutput = new HashMap<String,QName>();
mobyServiceName2InputXSDTypes = new HashMap<String,Map<String,String>>();
mobyServiceName2OutputXSDTypes = new HashMap<String,Map<String,String>>();
+ lsidResolver = new LSIDResolver();
parse(wsdlURL.openStream());
}
@@ -103,8 +117,8 @@
public void parseSOAPMessageSpecs() throws Exception{
for(String serviceName: getServiceNames()){
setCurrentService(serviceName);
- String currentInputMessage = getOperationInputName();
- String currentOutputMessage = getOperationOutputName();
+ String currentInputMessage = getOperationInputQName().getLocalPart();
+ String currentOutputMessage = getOperationOutputQName().getLocalPart();
NodeList messageElements = wsdlDoc.getDocumentElement().getElementsByTagNameNS(MobyPrefixResolver.WSDL_NAMESPACE,
"message");
@@ -125,6 +139,7 @@
Map<String,String> inputs = new HashMap<String,String>();
Map<String,String> inputMappings = new HashMap<String,String>();
Map<String,String> inputTypes = new HashMap<String,String>();
+ Map<String,String> secondaryInputs = new HashMap<String,String>();
Map<String,String> outputs = new HashMap<String,String>();
Map<String,String> outputMappings = new HashMap<String,String>();
Map<String,String> outputTypes = new HashMap<String,String>();
@@ -152,9 +167,21 @@
throw new Exception("Part element " + partName + " of WSDL message " +
messageName + " has no SAWSDL " + SAWSDL_INMAP_ATTR + " attribute defined");
}
- inputs.put(partName, wsdlParam2MobyParam(partName, partType, modelReference));
- inputTypes.put(partName, partType);
- inputMappings.put(partName, schemaMapping);
+ String mobyParam = wsdlParam2MobyParam(partName, partType, modelReference);
+ if(mobyParam == null){
+ // Check if it's a secondary
+ mobyParam = wsdlParam2MobySecondaryParam(partName, partType, modelReference, partElement);
+ if(mobyParam == null){
+ throw new Exception("The LSID '" + modelReference +
+ "' is not a properly formed Moby primary or secondary param LSID as required");
+ }
+ secondaryInputs.put(partName, mobyParam);
+ }
+ else{
+ inputs.put(partName, mobyParam);
+ inputTypes.put(partName, partType);
+ inputMappings.put(partName, schemaMapping);
+ }
}
else{
schemaMapping = partElement.getAttributeNS(MobyPrefixResolver.SAWSDL_NAMESPACE, SAWSDL_OUTMAP_ATTR);
@@ -171,6 +198,7 @@
setPrimaryInputs(inputs);
setPrimaryInputFormats(inputMappings);
setInputXSDTypes(inputTypes);
+ setSecondaryInputs(secondaryInputs);
}
else{ // it's output
setPrimaryOutputs(outputs);
@@ -179,13 +207,12 @@
}
}
- public String wsdlParam2MobyParam(String paramName, String paramXSDType, String dataTypeLSID) throws Exception{
+ public String wsdlParam2MobyParam(String paramName, String paramXSDType, String dataTypeLSID){
String[] dataTypeLSIDFields = dataTypeLSID.split(":");
if(dataTypeLSIDFields.length != 5 && dataTypeLSIDFields.length != 6 ||
!dataTypeLSIDFields[0].equals("urn") || !dataTypeLSIDFields[1].equals("lsid") ||
(!dataTypeLSIDFields[3].equals("objectclass") && !dataTypeLSIDFields[3].equals("namespacetype"))){
- throw new Exception("The LSID '" + dataTypeLSID +
- "' is not a properly formed Moby objectclass LSID as required");
+ return null;
}
// Special case, if the LSID is a namespace, spec out a base object in the given namespace
if(dataTypeLSIDFields[3].equals("namespacetype")){
@@ -196,6 +223,350 @@
}
}
+ public String wsdlParam2MobySecondaryParam(String paramName, String paramXSDType, String dataTypeLSID, Element partElement) throws Exception{
+ String[] dataTypeLSIDFields = dataTypeLSID.split(":");
+ if(dataTypeLSIDFields.length != 5 && dataTypeLSIDFields.length != 6 ||
+ !dataTypeLSIDFields[0].equals("urn") || !dataTypeLSIDFields[1].equals("lsid") ||
+ !dataTypeLSIDFields[3].equals("secondaryParamClass")){
+ return null;
+ }
+ // the format for secondaries is "name:type:defaultValue:[min,max]", where [min,max] can be an enumeration as well
+ String restrictionsSpec = getSecondaryParamRestrictions(partElement);
+ return paramName+":"+dataTypeLSIDFields[4]+":"+restrictionsSpec;
+ }
+
+ /**
+ * Checks out the Moby secondary parameter source attribute. If it's a reference to another service,
+ * with a nullary c-tor, that service is executed and the returned values are used in the secondary param spec
+ * valid value range. The value could also be a literal pointed to by a Java-acceptable URL.
+ *
+ * The returned value is of the form "defaultValue:[min,max]", where [min,max] can be an enumeration as well
+ */
+ public String getSecondaryParamRestrictions(Element partElement) throws Exception{
+ String secondaryValueSource = partElement.getAttributeNS(MobyPrefixResolver.MOBY_XML_NAMESPACE,
+ MOBY_SECONDARY_SOURCE_ATTR);
+ try{
+ URL u = new URL(secondaryValueSource);
+ return getSecondaryParamRestrictionsFromURL(u);
+ } catch(Exception e){
+ // TODO: handle LSID case?
+ }
+ // we get here if the source was not a URL or LSID, assume it's a service (WSDL operation)
+ return getSecondaryParamRestrictionsFromService(partElement, secondaryValueSource);
+ }
+
+ public String getSecondaryParamRestrictionsFromURL(URL u){
+ // TODO
+ return "";
+ }
+
+ public String getSecondaryParamRestrictionsFromService(Element partElement, String opName) throws Exception{
+ String defaultValue = "";
+
+ Element wsdlRoot = partElement.getOwnerDocument().getDocumentElement();
+ // Find the operation element defining the op specified
+ Element opElement = null;
+ NodeList ops = wsdlRoot.getElementsByTagNameNS(MobyPrefixResolver.WSDL_NAMESPACE, "operation");
+ if(ops.getLength() == 0){
+ ops = wsdlRoot.getElementsByTagNameNS(MobyPrefixResolver.WSDL20_NAMESPACE, "operation");
+ }
+ for(int i = 0; i < ops.getLength(); i++){
+ Element opE = (Element) ops.item(i);
+ if(opName.equals(opE.getAttribute("name"))){
+ opElement = opE;
+ break;
+ }
+ }
+ if(opElement == null){
+ logger.log(Level.SEVERE,
+ "While trying to find a WSDL operation providing secondary parameter values, " +
+ "either the WSDL or the specified parameter source operation (" + opName + ") is wrong");
+ throw new IllegalArgumentException("While trying to find a WSDL operation providing secondary parameter values, " +
+ "either the WSDL or the specified parameter source operation (" + opName + ") is wrong");
+ }
+
+ QName[] specs = getServiceAndPortFromOperation(opElement, opName); //backtracks from the op to the qnames JAX-WS needs
+
+ Service service = null;
+ try{
+ service = Service.create(wsdlURL, specs[0]);
+ } catch(Exception e){
+ logger.log(Level.SEVERE,
+ e.getClass().getName() + " while using JAX-WS to create a handle for" +
+ "a service (" + specs[0] + ") providing secondary parameter values, either the WSDL or the " +
+ "specified parameter source operation (" + opName + ") is wrong",
+ e);
+ throw e;
+ }
+
+ Dispatch<Source> dispatch = null;
+ try{
+ dispatch = service.createDispatch(specs[1],
+ Source.class,
+ Service.Mode.PAYLOAD);
+ } catch(Exception e){
+ logger.log(Level.SEVERE,
+ e.getClass().getName() + " while using JAX-WS to create a dispatch for a port on " +
+ "the service " + specs[0] + ", either the WSDL or the WSDLConfig's " +
+ "portQName parsed (" + specs[1] + ") is wrong",
+ e);
+ }
+ Map<String,Object> context = dispatch.getRequestContext();
+ context.put(Dispatch.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
+ context.put(Dispatch.SOAPACTION_URI_PROPERTY, specs[0].getNamespaceURI()+"#"+opName);
+
+ URL liftingSchema = getLiftingSchemaFromOperation(opElement, opName);
+ // Cheating slightly, since we can't return a URL and a boolean, the ref part of
+ // the URL is set if we want to indicate the rule should be applied to all members of an XSI array
+ boolean isArrayRule = false;
+ if(ARRAY_SENTINEL.equals(liftingSchema.getRef())){
+ isArrayRule = true;
+ }
+
+ // we expect the method to have a nullary signature, so we just create a blank input map
+ SourceMap source = new SourceMap(new QName(specs[0].getNamespaceURI(), opName));
+
+ Source resultSource = dispatch.invoke(source);
+ // Parse the results into the datatype required
+ //System.err.println("Class of response is " + resultSource.getClass().getName());
+
+ String rangeValues = convertSourceToMobySecondaryValues(resultSource, liftingSchema, isArrayRule);
+ //System.err.println("Range values are:\n"+rangeValues);
+
+ if(rangeValues == null || rangeValues.length() == 0){
+ throw new Exception("No values for the Moby secondary paramater could " +
+ "be found from nullary operation "+opName);
+ }
+ if(rangeValues.indexOf(',') == -1){
+ defaultValue = rangeValues; // only one choice anyway
+ }
+ // Pick the first value as the default value, for lack of a better strategy
+ else{
+ defaultValue = rangeValues.substring(0, rangeValues.indexOf(','));
+ }
+ return defaultValue + ":[" + rangeValues + "]";
+ }
+
+ /**
+ * Goes from an operation, determines the output datatype, then sees if that datatype has a lifting schema
+ * that'll turn the response into a moby secondary param format.
+ */
+ protected URL getLiftingSchemaFromOperation(Element opElement, String opName) throws Exception{
+ QName[] ioMsgNames = getInputAndOutputMessageNamesFromOperation(opElement);
+ // ioMsgNames[1] is the output message name
+ String targetMessageName = ioMsgNames[1].getLocalPart();
+
+ // Now find the message definition in the WSDL
+ Element wsdlRoot = opElement.getOwnerDocument().getDocumentElement();
+ NodeList messageElements = wsdlRoot.getElementsByTagNameNS(MobyPrefixResolver.WSDL_NAMESPACE,
+ "message");
+ Element partElement = null;
+ for(int i = 0; i < messageElements.getLength(); i++){
+ String messageName = ((Element) messageElements.item(i)).getAttribute("name");
+
+ if(targetMessageName.equals(messageName)){
+ // Find the message part, and its datatype
+ NodeList partElements = ((Element) messageElements.item(i)).getElementsByTagNameNS(MobyPrefixResolver.WSDL_NAMESPACE,
+ "part");
+ if(partElements.getLength() != 1){
+ throw new Exception("The WSDL message (" + messageName+") containing the values " +
+ "for a Moby secondary param (operation "+opName+") did not have one part " +
+ "as expected, but rather "+partElements.getLength());
+ }
+ partElement = (Element) partElements.item(0);
+ break;
+ }
+ }
+ if(partElement == null){
+ throw new Exception("Could not find a message definition (" + targetMessageName +
+ ") for operation "+ opName);
+ }
+ // The lifting may be defijned at the "part" tag level, as it is for services
+ String schemaMapping = partElement.getAttributeNS(MobyPrefixResolver.SAWSDL_NAMESPACE, SAWSDL_OUTMAP_ATTR);
+ if(schemaMapping != null && schemaMapping.length() != 0){
+ return new URL(schemaMapping);
+ }
+
+ String partType = partElement.getAttribute("type");
+ if(partType == null || partType.length() == 0){
+ throw new Exception("The WSDL message (" + targetMessageName+") containing the values " +
+ "for a Moby secondary param (operation "+opName+") has a part element " +
+ "as expected, but no defined data type (type attribute missing)");
+ }
+ // See if the name is namespace qualified, and separate the local part if so
+ String partTypeNamespaceURI = "";
+ if(partType.contains(":")){
+ String nsPrefix = partType.substring(0, partType.indexOf(":")); //XML NS prefix
+ partType = partType.substring(partType.indexOf(":")+1); //local part
+ partTypeNamespaceURI = partElement.lookupNamespaceURI(nsPrefix); //prefix->URI
+ }
+
+ // Now find the definition of the part's data type, and see if it has a schema lifting mapping
+ // Usually, <xsd:schema> -> <xsd:complexType name="partType"/>
+ NodeList schemaElements = wsdlRoot.getElementsByTagNameNS(MobyPrefixResolver.XSD_NAMESPACE,
+ "schema");
+ for(int i = 0; i < schemaElements.getLength(); i++){
+ if(!partTypeNamespaceURI.equals(((Element) schemaElements.item(i)).getAttribute("targetNamespace"))){
+ continue; // only look as schema definitions in the correct namespace
+ }
+
+ NodeList schemaDefElements = ((Element) schemaElements.item(i)).getChildNodes();
+ for(int j = 0; j < schemaDefElements.getLength(); j++){
+
+ if(!(schemaDefElements.item(j) instanceof Element)){
+ continue;
+ }
+
+ Element schemaDefElement = (Element) schemaDefElements.item(j);
+ // If it's an XML Schema definition element with the same name as our part type, we're good to go...
+ if((MobyPrefixResolver.XSD_NAMESPACE.equals(schemaDefElement.getNamespaceURI())) &&
+ partType.equals(schemaDefElement.getAttribute("name"))){
+ // See if the SAWSDL lifting schema attribute is defined
+ schemaMapping = partElement.getAttributeNS(MobyPrefixResolver.SAWSDL_NAMESPACE, SAWSDL_OUTMAP_ATTR);
+ if(schemaMapping == null || schemaMapping.length() == 0){
+ // As a last-ditch effort, if the data type is just an array of another datatype,
+ // look up the other data type to see if it has a lifting schema mapping, and
+ // we will take care of the array iteration part opf the transformation
+ // The XML must look something like:
+ //<xsd:complexType name="ArrayOfThing">
+ // <xsd:complexContent>
+ // <xsd:restriction base="soapenc:Array">
+ // <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="typens:Thing[]"/>
+ // </xsd:restriction></xsd:complexContent></xsd:complexType>
+ NodeList contentElements = schemaDefElement.getElementsByTagNameNS(MobyPrefixResolver.XSD_NAMESPACE,
+ "complexContent");
+ if(contentElements.getLength() == 1){
+ NodeList restrictionElements =
+ ((Element) contentElements.item(0)).getElementsByTagNameNS(MobyPrefixResolver.XSD_NAMESPACE,
+ "restriction");
+ if(restrictionElements.getLength() == 1){
+ NodeList attributeElements = ((Element) restrictionElements.item(0)).getElementsByTagNameNS(MobyPrefixResolver.XSD_NAMESPACE,
+ "attribute");
+ if(attributeElements.getLength() == 1){
+ // NOTE: WSDL 1.1 only for now
+ String arrayType = ((Element) attributeElements.item(0)).getAttributeNS(MobyPrefixResolver.WSDL_NAMESPACE,
+ "arrayType");
+ if(arrayType.contains(":")){
+ arrayType = arrayType.substring(arrayType.indexOf(":")+1); //local part
+ }
+ if(!arrayType.endsWith("[]")){
+ throw new Exception("The definition of XML Schema type " + partType +
+ " used as the output of " +
+ opName + " has no SAWSDL " + SAWSDL_OUTMAP_ATTR +
+ " attribute defined, nor is" +
+ "it simply an array of a type with a lifting schema");
+ }
+ arrayType = arrayType.substring(0, arrayType.length()-2); // remove the array square brackets
+ for(int k = 0; k < schemaDefElements.getLength(); k++){
+ if(!(schemaDefElements.item(k) instanceof Element)){
+ continue;
+ }
+ Element sde = (Element) schemaDefElements.item(k);
+ if((MobyPrefixResolver.XSD_NAMESPACE.equals(sde.getNamespaceURI())) &&
+ arrayType.equals(sde.getAttribute("name"))){
+ // We're at the array's data type. This is the last chance to find a schema lifting mapping
+ schemaMapping = sde.getAttributeNS(MobyPrefixResolver.SAWSDL_NAMESPACE, SAWSDL_OUTMAP_ATTR);
+ if(schemaMapping != null && schemaMapping.length() != 0){
+ // The ARRAY_SENTINEL as a ref part of the URL indicates the rule should be
+ // applied to each members of the incoming array, not the once to the whole array
+ if(lsidResolver.isLSID(schemaMapping)){
+ return new URL(lsidResolver.resolveDataURL(schemaMapping).toString()+
+ "#"+ARRAY_SENTINEL);
+ }
+ else{
+ return new URL(schemaMapping+"#"+ARRAY_SENTINEL);
+ }
+ }
+ throw new Exception("Neither the array datatype ("+partType + ") nor the datatype " +
+ "it stores (" + arrayType + ") has a SAWSDL " + SAWSDL_OUTMAP_ATTR +
+ " attribute");
+ }
+ }
+ throw new Exception("Could not find XML Schema type definition for " + arrayType);
+ }
+ }
+ }
+
+ throw new Exception("The definition of XML Schema type " + partType + " used as the output of " +
+ opName + " has no SAWSDL " + SAWSDL_OUTMAP_ATTR + " attribute defined, nor is" +
+ "it simply an array of a type with a lifting schema");
+ }
+ if(lsidResolver.isLSID(schemaMapping)){
+ return lsidResolver.resolveDataURL(schemaMapping);
+ }
+ else{
+ return new URL(schemaMapping);
+ }
+ }
+ }
+ }
+ throw new Exception("Could not find the data type definition for " + partType + " in the WSDL");
+
+ }
+
+ protected String convertSourceToMobySecondaryValues(Source source, URL liftingSchema, boolean arrayRule) throws Exception{
+ // The source will contain an XML document, lets convert it to a string of the form val1,val2,val3 using a stylesheet
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = null;
+ //System.err.println("The lifting schema is " + liftingSchema);
+ try{
+ // Create the transformer that'll turn the soap payload into a moby secondary spec string
+ transformer = transformerFactory.newTransformer(new StreamSource(liftingSchema.openStream()));
+ } catch (TransformerConfigurationException tce){
+ logger.log(Level.SEVERE,
+ "Could not create an XSLT transformer: " + tce,
+ tce);
+ }
+ StringWriter stringWriter = new StringWriter();
+ // Apply the rule to each member of the array, rather than just once to the array
+ if(arrayRule){
+ // To simplify life (at the cost of inefficiency of processing),
+ // turn any source into a stream source (via a null XSLT transform)
+ // so we can parse it uniformily
+ if(!(source instanceof StreamSource)){
+ StringWriter verbatim = new StringWriter();
+ transformerFactory.newTransformer().transform(source, new StreamResult(verbatim));
+ //System.err.println("Verbatim source is:\n" + verbatim);
+ source = new StreamSource(new StringReader(verbatim.toString()));
+ }
+
+ Document arrayDoc = null;
+ if(((StreamSource) source).getInputStream() != null){
+ arrayDoc = docBuilder.parse(((StreamSource) source).getInputStream());
+ }
+ else if(((StreamSource) source).getReader() != null){
+ arrayDoc = docBuilder.parse(new org.xml.sax.InputSource(((StreamSource) source).getReader()));
+ }
+ else{
+ throw new Exception("Neither the InputStream or Reader was available from " +
+ "the StreamSource, cannot process the source");
+ }
+ NodeList arrayElements = arrayDoc.getElementsByTagName("item");
+ for(int i = 0; i < arrayElements.getLength(); i++){
+ if(i != 0){
+ stringWriter.write(','); //join values with a comma
+ }
+ transformer.transform(new DOMSource(arrayElements.item(i)), new StreamResult(stringWriter));
+ }
+ }
+ // Not an array rule, just apply the stylesheet as-is
+ else{
+ transformer.transform(source, new StreamResult(stringWriter));
+ }
+ //System.err.println("Response payload:\n"+stringWriter.toString());
+
+ return stringWriter.toString();
+ }
+
+ public static String join(Iterable i, String delimiter) {
+ StringBuffer buffer = new StringBuffer();
+ for(Object item: i){
+ buffer.append(item.toString());
+ buffer.append(delimiter);
+ }
+ return buffer.substring(0, buffer.length()-delimiter.length());
+ }
+
// Finds out the soap operations to wrap and the associated Moby metadata such as service name, authority, etc.
public void parseMobyServiceSpecs() throws Exception{
NodeList serviceNameAttrs = (NodeList) xPath.evaluate(SERVICENAME_ATTR_XPATH,
@@ -206,14 +577,6 @@
"Either this is not a Moby-oriented SAWSDL file, or the Moby namespace is not properly defined.");
}
for(int i = 0; i < serviceNameAttrs.getLength(); i++){
-// Node resultNode = serviceNameAttrs.item(i);
-// if(!(resultNode instanceof Attr)){
-// throw new Exception("The XPath to retrieve Moby serviceName attributes returned a non-Attr (" +
-// resultNode.getClass().getName() + "). XPath programming error?");
-// }
-// Attr serviceAttr = (Attr) resultNode;
-// // Make sure the service name is Moby Kosher
-// String serviceName = serviceAttr.getValue();
Element el = (Element) serviceNameAttrs.item(i);
String serviceName = el.getAttributeNS(MobyPrefixResolver.MOBY_XML_NAMESPACE, SERVICE_NAME_ATTR);
if(serviceName == null || serviceName.trim().length() == 0){
@@ -304,7 +667,21 @@
"of Moby service " + currentService + " is missing or blank");
}
soapOpName = soapOpName.trim();
-
+ QName[] names = getServiceAndPortFromOperation(opElement, soapOpName);
+ QName[] ioMsgNames = getInputAndOutputMessageNamesFromOperation(opElement);
+
+ setServiceQName(names[0]);
+ setPortQName(names[1]);
+ setTargetNamespaceURI(names[0].getNamespaceURI());
+ setOperationName(soapOpName);
+ setOperationInputQName(ioMsgNames[0]);
+ setOperationOutputQName(ioMsgNames[1]);
+ }
+
+ /**
+ * @return a two element array, with input message name, then output message name
+ */
+ protected QName[] getInputAndOutputMessageNamesFromOperation(Element opElement) throws Exception{
// Now that we have the operation, find the input and output children we need to note
NodeList inputElements = opElement.getElementsByTagNameNS(MobyPrefixResolver.WSDL_NAMESPACE, "input");
if(inputElements == null || inputElements.getLength() == 0){
@@ -318,15 +695,6 @@
throw new Exception("More than one WSDL input element is defined for the operation " +
"element defining the Moby service " + currentService);
}
- // Should have element or message attr for WSDL 2.0 and 1.1 respectively
- String inputName = ((Element) inputElements.item(0)).getAttribute("message");
- if(inputName == null || inputName.trim().length() == 0){
- inputName = ((Element) inputElements.item(0)).getAttribute("element");
- }
- if(inputName == null || inputName.trim().length() == 0){
- throw new Exception("Could not find the message or element attribute associated with " +
- "the WSDL input element for the Moby service " + currentService);
- }
NodeList outputElements = opElement.getElementsByTagNameNS(MobyPrefixResolver.WSDL_NAMESPACE, "output");
if(outputElements == null || outputElements.getLength() == 0){
@@ -340,6 +708,24 @@
throw new Exception("More than one WSDL output element is defined for the operation " +
"element defining the Moby service " + currentService);
}
+
+ // Should have element or message attr for WSDL 2.0 and 1.1 respectively
+ String inputName = ((Element) inputElements.item(0)).getAttribute("message");
+ if(inputName == null || inputName.trim().length() == 0){
+ inputName = ((Element) inputElements.item(0)).getAttribute("element");
+ }
+ if(inputName == null || inputName.trim().length() == 0){
+ throw new Exception("Could not find the message or element attribute associated with " +
+ "the WSDL input element for the Moby service " + currentService);
+ }
+ String nsURI = null;
+ if(inputName.contains(":")){ // convert ns:label to QName object
+ String nsPrefix = inputName.substring(0, inputName.indexOf(":")); //XML NS prefix
+ inputName = inputName.substring(inputName.indexOf(":")+1); //local part
+ nsURI = inputElements.item(0).lookupNamespaceURI(nsPrefix); //prefix->URI
+ }
+ QName inputQName = new QName(nsURI, inputName);
+
// Should have element or message attr for WSDL 2.0 and 1.1 respectively
String outputName = ((Element) outputElements.item(0)).getAttribute("message");
if(outputName == null || outputName.trim().length() == 0){
@@ -349,7 +735,21 @@
throw new Exception("Could not find the message or element attribute associated with " +
"the WSDL output element for the Moby service " + currentService);
}
-
+ if(outputName.contains(":")){ // convert ns:label to QName object
+ String nsPrefix = outputName.substring(0, outputName.indexOf(":")); //XML NS prefix
+ outputName = outputName.substring(outputName.indexOf(":")+1); //local part
+ nsURI = outputElements.item(0).lookupNamespaceURI(nsPrefix); //prefix->URI
+ }
+ QName outputQName = new QName(nsURI, outputName);
+
+ return new QName[]{inputQName, outputQName};
+ }
+
+ /**
+ * @return a two element array, with service, then port
+ */
+ protected QName[] getServiceAndPortFromOperation(Element opElement, String soapOpName) throws Exception{
+
// Now go up the DOM to find the port type (WSDL 1.1) or interface (WSDL 2.0) enclosing the operation
Element porttypeInterfaceElement = (Element) opElement.getParentNode();
for(; porttypeInterfaceElement != null;
@@ -443,7 +843,7 @@
if(serviceName == null || serviceName.length() == 0){
throw new Exception("The WSDL service element enclosing the port " + portName +
" does not have a name attribute");
- }
+ }
// find the target namespace for the service and port, as JAX-WS will need these later
String targetNamespace = wsdlDoc.getDocumentElement().getAttributeNS(MobyPrefixResolver.WSDL_NAMESPACE,
@@ -455,11 +855,10 @@
throw new Exception("No targetNamespace attribute was found in the root element of the WSDL document");
}
- setServiceQName(new QName(targetNamespace, serviceName));
- setPortQName(new QName(targetNamespace, portName));
- setOperationName(soapOpName);
- setOperationInputName(inputName);
- setOperationOutputName(outputName);
+ QName[] specs = new QName[2];
+ specs[0] = new QName(targetNamespace, serviceName);
+ specs[1] = new QName(targetNamespace, portName);
+ return specs;
}
public String getOperationName(){
@@ -470,6 +869,14 @@
mobyServiceName2Op.put(currentService, opName);
}
+ public String getTargetNamespaceURI(){
+ return mobyServiceName2TargetNamespaceURI.get(currentService);
+ }
+
+ public void setTargetNamespaceURI(String nsURI){
+ mobyServiceName2TargetNamespaceURI.put(currentService, nsURI);
+ }
+
public QName getPortQName(){
return mobyServiceName2Port.get(currentService);
}
@@ -486,25 +893,19 @@
mobyServiceName2Service.put(currentService, serviceName);
}
- public String getOperationInputName(){
+ public QName getOperationInputQName(){
return mobyServiceName2OpInput.get(currentService);
}
- public void setOperationInputName(String inputName){
- if(inputName.contains(":") && !inputName.endsWith(":")){
- inputName = inputName.substring(inputName.lastIndexOf(":")+1);
- }
+ public void setOperationInputQName(QName inputName){
mobyServiceName2OpInput.put(currentService, inputName);
}
- public String getOperationOutputName(){
+ public QName getOperationOutputQName(){
return mobyServiceName2OpOutput.get(currentService);
}
- public void setOperationOutputName(String outputName){
- if(outputName.contains(":") && !outputName.endsWith(":")){
- outputName = outputName.substring(outputName.lastIndexOf(":")+1);
- }
+ public void setOperationOutputQName(QName outputName){
mobyServiceName2OpOutput.put(currentService, outputName);
}
More information about the MOBY-guts
mailing list