Based on postings in this group, if I want to expose 15 flow services using the default soap processor I need to write 15 wrapper services. Each wrapper service will extract the soap request and map the data into the target flow service. If I choose to use a custom soap processor, I still need to code the same extraction logic for all 15 services, it will just exist in one custom soap processor rather than 15 wrapper services. The bottom line… it’s the same amount of development it’s just centralized in one service.
What I don’t understand is why I have to develop ANY logic to extract the soap message and map it into the target flow service. It seems to me that as a developer I should be able to focus on creating target flow services, defining the inputs/outputs and generating WSDL files. webMethods IS should provide services that receive the SOAP request (which it does), validate the request against my input document (not sure if it does this) and map the request data into my target flow service (don’t think it does this).
Do I really have to write mapping logic for every flow service I want to expose as a web service? Some of these services will have large, complex inputs (arrays, arrays of arrays, etc) and writing these services to extract the payload could be quite time consuming.
Any suggestions of thoughts would be much appreciated!
It’s been over a year since Mark’s original postings, have there been any developments in wM IS 6.1 that will make my task easier?
I presume that my best option is to write a single custom soap processor that extracts the soap message request and uses a combination of flow and java services to dynamically call the appropriate target flow service. I don’t believe my processor needs to be as robust as the one Mark describes in his blog so I hope to avoid the need for a registry. I believe my difficulty will be dynamically parsing the XML as I’m completely unfamiliar with XQL.
Unfortunately, your best option is still to write a custom soap processor. If you don’t need to validate the payload of your messages against a schema and don’t need to process headers to support WS-Security, then your processor will be fairly straightforward.
A custom soap processor is just a Flow service that processes your soap message before invoking the target service. The tricky part is in determining which service to invoke. You can use the pub.xml:getXMLNodeType service to obtain the rootNamespace, rootNSPrefix and rootLocalName from the “body” node that is created by the pub.soap.utils:getBody service. That should be enough to let you use the built-in service pub.universalName:find service to locate the target service based on its UniversalName settings (set in the service properties page).
ServiceNet 6.5 is supposed to ship as a generally available product “any day now”. I’m interested to see how it could be used in conjunction with IS to help address the pain of doc/literal soap messaging in IS.
Thanks for your suggestions on how to locate the service that needs to be invoked. They’ll come in handy in the coming weeks.
Can you provide a suggestion on how to perform the “dynamic mapping” of data in the soap request to a document in the pipeline? By “dynamic mapping” I’m referring to the fact that my 15 services will have a wide-range of inputs from simple services (string inputs/output) to complex services (document lists, string lists, etc). Once I’ve determined the service to call, I’ll then need to dynamically build a document in the pipeline that represents the service input.
This appears to be the larger of the challenges to me.
In my opinion - the best way to make your system dynamic is to make each one of your target services have a consistent input/output signature (this would be like declaring an interface in java).
That way - you should be able to avoid building if-then logic in your custom soap processor.
Your custom processor simply does all the “soap” specific stuff, inspects the document to determine the target service to invoke (and then calls doInvoke with the service name and uses the input/output interface that you chose (perhaps an xml node as input and as output).
Your custom soap processer builds and returns the soap response.
The difficulty with that approach is that I would still need to code each target flow service to parse the XML input and map it into the pipeline.
I’m hoping to find suggestions on a way to implement a flow service that parses the XML body of the SOAP request and dynamically maps it into an instance of the appropriate document input signature. With this approach exposing new flow services through my custom SOAP processors would require no additional coding!
What we did was to use the fully qualified name of the rootNode in the soap message body to derive the corresponding document type. We used a simple XML registry, but if you structured your namespace names and your message names correctly you could probably derive the document type name from the namespace and local name alone.
For example if you received a soap body with the root node of “acct:AddAccountRequest” where the “acct” prefix was defined as “urn:myco.accounting.requests” you could derive a fully qualified document type name of “myco.accounting.requests:AddAccountRequest”.
Regardless of how you derive or lookup a document type name, once you have one you can map it to the documentTypeName parameter of the pub.xml:nodeToDocument service so that the payload of your soap document is mapped to the document type needed by your service.
I had to write a simple utility to rename the document so that it not only had the right structure but also the right name.
What Mark describes is exactly what we did in another project. Mapping a name from the XML to the doc type works reasonably well.
We also did what Haithem suggested in defining a specific signature that invoked servcies had to follow. The only thing that needs to be consistent is the name of the parameters. The type of the input parameter can vary by service. For example, serviceX would take a parm named theDoc of type XYZ, while serviceY would take a parm named theDoc as well but the type can be ABC–a sort of polymorphism.
I’m concerned that I’m not defining my services and document input correctly due to issues I’m having with the generation of a Web Connector. Here’s what I’ve done:
I’ve created a custom soap processor with the following goals:
Processor dynamically determines which target flow service to call from soapDataRequest
Processor dynamically creates input document for target flow service and invokes flow service
Processor dynamically maps target flow service output and formats into soapDataReply
I’ve assumed that I can accomplish this with the following naming conventions:
Target Service Name = “myService”
Input Document Type Name = “myServiceInput”
Output Document Type Name = “myServiceOutput”
I’ve performed the following:
Generated WSDL using documents types defined above
Created myService with a single doc reference as input (myServiceInput) and a single doc reference as output (myServiceOutput)
With these conventions, I assume that any client that uses my WSDL will have a root node named myService with child nodes containing the fields defined in myServiceInput. I can then use pub.xml:queryXMLNode to get the root node’s name (myService) and use that to build an instance of “myServiceInput” and to invoke “myService”.
To test the WSDL I’ve created a Web Connector and I’ve already run into problems. First, the flow service generated by Developer is wrong. It attempts to call the following sequence of services once for every field defined in myServiceInput. I have four string fields defined, and it attempts to call the following sequence four times:
Furthermore, pub.xml:documentToXMLString doesn’t even map anything. I resolved the problem by creating an instance of myServiceInput in the pipeline and mapping that into pub.xml:documentToXMLString with the namespace [url]mytest.com - This website is for sale! - my test Resources and Information.. The Web Connector now invokes my service correctly.
Since I’m not going to be developing the client(s) that consume my services (a sub-contractor on our project will be doing that) I’m very concerned that something is wrong with my WSDL as the result of how I’ve implemented the document types, services, etc. I’ve attempted to use Microsoft’s SOAP Toolkit and VBScript in an ASP page to import my WSDL file but the client generates errors indicating that the wrong number of parameters are provided (though I’ve confirmed that the XML document I’ve built is identical in structure to the SOAP request provided by the Web Connector). I have been able to successfully prototype the SOAP Toolkit by changing myServiceInput such that it contain a single document field named prefix:, where the document field contains all of my input fields.
Does anyone see anything wrong with my approach above?
Can anyone recommend a better way to test my WSDL file?
OK, so I’ve confirmed that there’s either something wrong with the WSDL Generator or my approach as outlined above (which I assume is the case!).
Attached are two files. One is the WSDL file generated by IS for the service I outline in the posting above and the other is my custom version of the WSDL file.
When I attempt to generate a Web Connector using the IS WSDL the connector doesn’t work (see description in posting above). The issue is that the and sections incorrectly describe the document types I provided when I generated the WSDL. The document types are “flat” documents that only contain string data types (with proper namespace definitions). I’ve also attempted to invoke my web service using a custom VBScript client and the MS SOAP Toolkit.
Now, when I generate a Web Connector using MY version of the WSDL file, which I believe correctly defines the document inputs/outputs, the Web Connector works fine. In addition, I have no problems with the VBScript client either.
What am I doing wrong when I generate the WSDL? Have I defined something in my document types incorrectly?
Not quite sure, but I think that you need a “container” document for each input and output message document type. The WSDL generator strips off this container when it creates the message types. I’m sure there was a reason for this once upon a time.
While painful, my recommendation is to use a WSDL editor like XML Spy Enterprise Edition or CapeClear SOA Editor to craft your WSDL’s. This lets you create WSDL files that contain more than one operation per service (a best practice) and lets you use import statements to import XML schema files containing your message definitions (another best practice).
Plus, you control all aspects of what goes into the WSDL and don’t have to live with any generated artifacts that you don’t want.
I think you’re on the right track with your WSDL-first approach. I would just back up a step and first design a schema containing elements for each input and output message (I use request/reponse).
I was doing this informally, but found that this approach is recommended by Thomas Erl’s SOA Concepts book.
In short, the Developer WSDL generator will not generate WSDL files that follow best practices although they may in fact work if you feed them the right document types.
Also, I don’t recommend using the Flow services generated by the Web Services Connectors beyond the prototyping / early development stage. See this post for a couple of reasons why.
BTW, XML Spy didn’t like the ISGenerated.wsdl file because the generated “types” section contained definitions that were “nondeterministic”. That’s what happens when you feed the Developer WSDL Generator doc types that are not containers or wrappers containing a single document that defines your actual message.
Regarding the “best practices” you mention above and the creation of multiple operations per service… the custom soap processor and web services I’m developing are essentially for a web service interface between two applications (for the time being anyway). I expect the interface to implement anywhere between 10-15 services that facilitate data retrieval, submission and synchronization between the systems.
Since this is a single interface, is it a best practice to implement the interface as one service with multiple operations, even though the operations do different things functionally? The design impact is that I would only need one WSDL and probably one schema (XSD) that defines all of the operations.
First, understand that an IS service equates roughly to a WSDL operation. A WSDL Service (capital ‘S’) can be thought of as a group of related operations in which the grouping can be done by entity (e.g. customer), application (e.g. Sales) or by some other logical approach.
Review the operations that you plan to include in your Service to ensure that they are at the appropriate level of granularity. Ideally, you are exposing more course-grained operations in the interface described by your WSDL and not method-level calls.
Once you’re satisfied that you need each proposed operation and that they are, in fact, logically related, then design the input and output (request and response) messages for each operation with an eye toward maximizing reuse of the data types. Define those data types in a small number of XML schemas that would be imported into the types section of your WSDL (rather than placing the definitions inline).
See Erl’s SOA Concepts book for more ideas on service analysis and design.
I’ve just about got my custom soap processor working and I’ve followed your suggestions and started by defining a schema (which defines the input/outputs for ALL of my operations) and importing that schema into my WSDL. I’ve also imported the schema into IS and have my custom soap processor validating the SOAP BODY against it.
To revisit my initial goal, my custom soap processor should be able to dynamically determine 1) the target service to invoke and 2) the document type to map into that service. I’ve got this working using the namespace suggestions you offered in this thread, but I’ve got a question regarding the document type definitions.
Now that I’m implementing more complex operations the SOAP Body contains prefixes at various levels, not just the root node (my initial prototype used very simple documents with xsd:string inputs and therefore only had a prefix at the root node). In order to invoke xmlNodeToDocument on the SOAP Body and then convert that to the appropriate document type, the document type must also define fields whose names contain a prefix. Of course, there’s no problem with this approach as IS includes the prefix when creating new document types by referencing a schema.
My question is if this is an appropriate approach? I’m used to developing flow services that use document types as input with more “standard” field names. In this implementation all of my target flow services will reference doc types with field names that include prefixes. Again, there’s not reason this won’t work, it just seems odd to me. I did read one work-around in another thread in which I can generate doc types without prefixes by loading the schema into IS first, however, my SOAP Body will still contain the prefixes and I won’t be able to use xmlNodeToDocument to create my document type.
(As a side-note, in addition to the schema generated document types containing prefixes, they also place all fields in “container” documents with the same name as the document itself. Another “feature” that makes me feel uneasy about this approach).
One thing that may help is to set the elementFormDefault to “unqualified” in your schemas. That way not every field name will be qualified.
Not quite sure what the “best” solution is here and am working through this on my current project as well.
Remember, in XML, this…
<ns1:order xmlns:ns1=“http://myco.com/ns1”> ns1:amount100.00</ns1:amount> ns1:date2005-05-05T15:00:00-06:00</ns1:date>
</ns1:order>
is the same as this
100.00
2005-05-05T15:00:00-06:00
But in IS they won’t generate the same documentType structure. However, if added an @xmlns attribute to your prefixed nodes you should be able to use pub.xml:xmlNodeToDocument.
I have created webservice connector in webMethods 95 to target system(Oraclefusion) using the WSDL URL provided by oraclefusion team.
In the connector flow service I do not find targetInputSignature , targetOutputSignature and wsdName fields are not having values.
When I test my connector , it is throwing an error saying the above fields are must.
Can any one tell is the above field values can be provided by oraclefusion team, or can i hardcode the values in webMethods side in connector flow service.
It would be helpful if any one help me here asap.