14 Replies Latest reply on Dec 6, 2011 2:34 AM by alanchen

    Passing XML contents via SOAP Gateway

    igarashitm

      Hi all,

       

      In the process of writing a quickstart for XSLT transform, I've got to know how I can get the XML contents in bean service using @OperationTypes. (Thanks, Keith!)

       

      https://github.com/igarashitm/quickstarts/commit/e58a35a0c3ccfa739af93a9d53cd24b8c925db28

       

      In this case, I'd like to generate the response by XSLT transformation from order to orderAck, so just return the XML as it is at bean service.

      public interface OrderService {

       

          @OperationTypes(in="{urn:switchyard-quickstart:transform-xslt:1.0}order",

                  out="{urn:switchyard-quickstart:transform-xslt:1.0}order")

          String submitOrder(String order);  

      }

       

      This works fine if I call the service via Invoker, however it didn't work with SOAP gateway.

      org.switchyard.exception.SwitchYardException: Cannot convert from 'javax.xml.transform.dom.DOMSource' to 'java.lang.String'.

        No registered Transformer available for transforming from 'java:javax.xml.transform.dom.DOMSource' to 'java:java.lang.String'.

        A Transformer must be registered.

       

      SOAP/InboundHandler sets inputMessageQName and outputMessageQName in SOAPUtil#getContracts() properly(saw with debugger), so I don't know why the input is not treated as "{urn:switchyard-quickstart:transform-xslt:1.0}order", but "java:javax.xml.transform.dom.DOMSource".

       

      Please let me know if you find any point I missed.

       

      Thanks,

      Tomo

        • 1. Re: Passing XML contents via SOAP Gateway
          kcbabo

          This is most likely due to the fact that we use the Camel converter for Source=>String and String=>Source instead of supplying our own.  So the message names are correct, but the Java types are not matched.  You can test this by adding your own DOMSource=>String transformer to the application, setting the input type on your Bean service interface to DOMSource, or (I think) by including the camel component as a dependency in your pom.xml.  Pretty sure that last one will work, but not 100% certain.

          • 2. Re: Passing XML contents via SOAP Gateway
            igarashitm

            It worked fine by adding dependency on Camel component. Thanks Keith!

            • 3. Re: Passing XML contents via SOAP Gateway
              alanchen

              I hope you can help me. Thank you first!

              I just try to use switchyard. and I may build workshop lab1 successfully. Now, I want to add the new service and expose it.
              for example: I add a new method (OrderAck submitOrder2(Order order);) in OrderService interface.

              And implement this method in OrderServiceBean.java.

              Then I build this updated project with previous lab1 build file

              and deploy this jar file into switchyard AS7.

              After I enable the AS, but I cannot see the new service (submitOrder2) from the admin console (I can see submitOrder service).

              I do not know I need to add any step to expose this new service? I just add a method in the OrderService interface

              and implement it in the OrderServiceBean.java. Thank you again.

              • 4. Re: Passing XML contents via SOAP Gateway
                kcbabo

                Adding another method to the OrderService interface adds an operation the existing OrderService.  In other words, you are effectively saying that an existing service (OrderService) can now accept two different input messages.  This is why you only see one service in the admin console after adding the additional method.

                 

                If you want to create a new service, then you'll want to create a new bean class and interface. 

                • 5. Re: Passing XML contents via SOAP Gateway
                  alanchen

                  Keith, thank you for your response quickly.

                   

                  • I need to distinguish one thing. "two different input messages" means two methods in OrderService interface and two related methods are implemented in the   OrderServiceBean.java. is it right? If it is. So there is only one method in one interface. I think it should not be like this. I believe I do not describe my question in detail. I just want to add a new method in OrderService interface and this method is implemented in OrderServiceBean.java. I hope this method will be exposed in the WSDL file so that other program can consume it.the attachments are just for demo testing.
                  • the OrderService.wsdl file located in the resources/wsdl directory is generated automatically by the switchyard internal tool or not. If it it, when I want to create a new sercie.  it means that I neet to create a interface and  implement this interface. The last thing I need to do is that I must add an annotation @Service to the class. Now this new service has been created. If I want to bind this new service with soap interface. According to switchyard.xml file, I need to config this service with a wsdl file and service port. So if we need another tool to generate this wsdl file, could you please let me know which tool I should use?

                   

                  Thank you again.

                  • 6. Re: Passing XML contents via SOAP Gateway
                    kcbabo

                     

                    • I need to distinguish one thing. "two different input messages" means two methods in OrderService interface and two related methods are implemented in the   OrderServiceBean.java. is it right? If it is. So there is only one method in one interface. I think it should not be like this. I believe I do not describe my question in detail. I just want to add a new method in OrderService interface and this method is implemented in OrderServiceBean.java. I hope this method will be exposed in the WSDL file so that other program can consume it.the attachments are just for demo testing.

                     

                    Each operation on a service represents a message that enters the service with an optional reply/fault (depending on the message exchange pattern).  You can choose to have a service interface with multiple operations (e.g. one bean with multiple methods) or multiple interfaces with a single operation each.  SwitchYard can support either option.  It sounds like you want a single service with multiple operations, which is no problem.

                     

                    The WSDL is not automatically generated by the runtime right now.  Magesh has implemented an initial version of this functionality and we will get some form of it in for our 0.4 release.  Personally, I think it's best to go with at static WSDL instead of one generated at runtime as the former fits better with design-time tooling and governance (more on this in 0.4).  In any case, generation of WSDL from a Java interface is quite easy with the wsconsume utility that comes with JBoss AS or any other generation tool out there.  This is your best bet for now and I hope that you'll provide feedback on our runtime generation approach when that's available.

                     

                    • the OrderService.wsdl file located in the resources/wsdl directory is generated automatically by the switchyard internal tool or not. If it it, when I want to create a new sercie.  it means that I neet to create a interface and  implement this interface. The last thing I need to do is that I must add an annotation @Service to the class. Now this new service has been created. If I want to bind this new service with soap interface. According to switchyard.xml file, I need to config this service with a wsdl file and service port. So if we need another tool to generate this wsdl file, could you please let me know which tool I should use?

                     

                    The WSDL is not generated automatically by the tooling or runtime.  You have to generate it with an outside tool like wsconsume or if you're simply adding an operation to an existing WSDL definition you can use the Eclipse WSDL editor or hack it by hand.

                    • 7. Re: Passing XML contents via SOAP Gateway
                      alanchen

                      Keith, Thank you. Now I know that the WSDL is not automatically generated by the tools or runtime in Switchyard 0.2 version and this function will be supported in switchyard 0.4 version. Thank you for your team effort. Let me know when this function is available and I would like to test it and give you feedback on your runtime generation approach. Furthermore it will be better if you could provide some information or documentation about how to use this function.

                       

                      Now I use jboss-sop-p-5.1 to generate the WSDL file. And I find that I just pass a simple message to switchyard (You will find the same code in the attachment). I still need to do transformation. It means that we must get the each element value from the message and assemble these elements to the input parameters. When we get the result from the service, then we need to generate the response of the soap message according to the result object. Is it right or not? If it is, it seems no good for users to generate the soap response message each time. The attachments are about the demo project based on lab1 (HelloService.java and HelloServiceBean.java are the service interface and its implementation. Its wsdl file is located in wsdl/HelloService.wsdl directory. The transformation methods are in the Transformers.java file). I hope I could get your feedback. Thank you!

                      • 8. Re: Passing XML contents via SOAP Gateway
                        kcbabo

                        You don't need to map the SOAP message to a Java object model for it to be processed in SwitchYard.  By default, the SOAP gateway simply takes the SOAP:Body and sticks it in the message payload as a DOM Source.  You can use this representation directly in your service implementation or you can transform it to something else.  The reason why the lab application uses transformers is that it's mapping from the SOAP gateways representation (DOM) to the service interface used by the implementation (which is a domain-specific Java object).  We need a transformation to make that happen. 

                         

                        Do you want to deal with the XML representation directly in your service implementation?  If so, you can annotate your service interface with

                        @OperationTypes(in = "[input message type]" , out = "[output message type]") 
                        

                         

                        I notice that our docs are missing details on how to do this, so I will add it as part of our 0.3 release doc work. 

                        • 9. Re: Passing XML contents via SOAP Gateway
                          alanchen

                          Keith, Thank you for your response!

                           

                          I follow your suggestion, but I can not get the right response from the service in the switchyard. The detail procedure is listed as following.

                           

                          • add the annotation in the service interface:

                           

                                  @OperationTypes(in = "java.lang.String" , out = "java.lang.String")

                                  String hello(String name);

                           

                          • remove the related transformation methods from transformers.java.
                          • send the resquest from soapUI.
                          • get the error response. the detail info shown as following. I think I need to do some other configuration in the switchyard project.

                           

                                 Transformations not applied.  Required payload type of 'java.lang.String'.  Actual payload type is '{urn:switchyard-wrkshop:lab1:1.0}hello'.  You   must define and register a Transformer to transform between these types.

                           

                          • the attachement is demo project based on lab1.
                          • 10. Re: Passing XML contents via SOAP Gateway
                            kcbabo

                            Hi Alan,

                             

                            I couldn't open your attachment, but the annotation values should look something like this:

                             

                             

                            @OperationTypes(in = "{urn:switchyard-wrkshop:lab1:1.0}hello" , out = "<out message type goes here>")
                             String hello(String name);
                            

                             

                            What you are basically doing is overriding the default service contract generation to supply a specific type name for the input and output messages.  With no annotation, the automatically generated values are "java.lang.String" for the input and output.  This forces a transformation when the SOAP gateway receives a message with an input type of "{urn:switchyard-wrkshop:lab1:1.0}hello".  If you want to process that content (XML in this case) directly in your service implementation, then override the 'in' message type using the annotation.  If you want to return XML directly that will not be transformed, then override the "out" message type as well.

                             

                            cheers,

                            keith

                            • 11. Re: Passing XML contents via SOAP Gateway
                              alanchen

                              Hi Keith,

                               

                              I follow your suggestion. But I do not get the right response from the service in the SwitchYard.

                               

                              I use the soapUI tool to send the following message to SwitchYard. As to the testing project, see the attachment (including HelloService.java, HelloServiceBean.java, switchyard.xml and wsdl file).

                               

                              <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:switchyard-workshop:lab1:1.0">

                                    <soapenv:Header/>

                                    <soapenv:Body>

                                         <urn:hello>

                                              <!--Optional:-->

                                              <arg0>tom</arg0>

                                         </urn:hello>

                                    </soapenv:Body>

                              </soapenv:Envelope>

                               

                              1) When I add the following annotation into the HelloService interface. And I send the request from soapUI.

                               

                              @OperationTypes(in = "{urn:switchyard-workshop:lab1:1.0}hello",

                                      out = "{urn:switchyard-workshop:lab1:1.0}helloResponse" )

                              String hello(String name);

                               

                              Then, I get the response from the SwitchYard. The detail information is shown as follow.

                               

                              <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

                                 <soap:Body>

                                    <soap:Fault>

                                        <faultcode>soap:Server</faultcode>

                                        <faultstring>Error parsing DOM source.</faultstring>

                                    </soap:Fault>

                                 </soap:Body>

                              </soap:Envelope>

                               
                               

                               

                               

                               

                              2) When I add the following annotation into the HelloService interface( I just remove the out parameter ).

                               

                                  @OperationTypes(in = "{urn:switchyard-workshop:lab1:1.0}hello")

                              String hello(String name);

                               

                              I get the response from the SwitchYard. The detail information is shown as follow.

                               

                              <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

                                 <SOAP-ENV:Header/>

                                 <SOAP-ENV:Body>

                                    <SOAP-ENV:Fault>

                                      <faultcode>SOAP-ENV:Server</faultcode>

                                       <faultstring>Transformations not applied.  Required payload type of '{urn:switchyard-workshop:lab1:1.0}helloResponse'.  Actual payload type is 'java:java.lang.String'.  You must define and register a Transformer to transform between these types.</faultstring>

                                    </SOAP-ENV:Fault>

                                 </SOAP-ENV:Body>

                              </SOAP-ENV:Envelope>

                               

                               

                              3) From the SwitchYard Server console, I know that the input parameter value of “name” is the following value. What I want is that the input parameter value of “name” is just “tom”. Does it mean that I need to modify the in parameter in OperationTypes annotation by using xpath or something else? Or I still need to parse the xml file in the hello method in HelloServiceBaen.java file.

                               

                                         <urn:hello>

                                              <!--Optional:-->

                                              <arg0>tom</arg0>

                                         </urn:hello>

                              4) Furthermore, the return value (for example: “Hello, tom”) from hello method will be assembled as an xml file automatically. So does it allow us to config the out parameter in OperationTypes annotation so that the hello method can return the string value(for example: “Hello, tom”) directly?

                               

                              Regards!

                              Alan

                              • 12. Re: Passing XML contents via SOAP Gateway
                                kcbabo

                                If you specify an output type name of "{urn:switchyard-workshop:lab1:1.0}helloResponse", you are telling SwitchYard that you are returning XML directly from your service implementation.  The error you got in (1) is due to the fact that you are returning non-XML when the SOAP gateway is expecting XML for the SOAP:Body.  There are several ways to proceed:

                                 

                                1) Return valid XML from your service implementation with the annotation values you listed in (1).

                                2) Add a transformer to transform between the non-XML string you are returning and an XML representation with the annotation values you have in (2).

                                3) If you don't want to write your own transformer, use JAXB-annotated objects in your service interface.  SwitchYard will automatically pick these up and register a transformer for you between XML and Java object.  In this case, no annotations are required.

                                 

                                An example of (3) can be found in the transform-jaxb quickstart.  In case you don't have that handy, it's available in our quickstarts repository:

                                https://github.com/jboss-switchyard/quickstarts/tree/master/transform-jaxb

                                • 13. Re: Passing XML contents via SOAP Gateway
                                  alanchen

                                  Keith, thank you very much. I will do it soon and let you know the result ASAP.

                                  • 14. Re: Passing XML contents via SOAP Gateway
                                    alanchen

                                    Keith, thank you very much!

                                     

                                    Now, I create a new service based on the sample project.  It works when I use the JAXB. It is the way that I want to use.

                                    btw, there is a package-info.java file in the sample project, it is generated by the switchyard or created by ourselves?

                                    I do not use JAXB before, I guess it will be used by JAXB engine to scan the annotation. is it right or not? If this file is created by ourselves, may we change the file name or not?

                                     

                                    Thank you again!