Announcement Announcement Module
Collapse
No announcement yet.
How to implement the web-service-proxy pattern Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to implement the web-service-proxy pattern

    Hi guys,

    It is possible to implement the web-service-proxy pattern in Spring Integration ?

    See the figure below.

    The caller invoke a service locate in a web service proxy, the web servie proxy redirect the request to remote web service and send the response back to the caller.

    The caller known nothing about the web service. In fact, the calle think that the web service is located in the web service proxy.


    Attachment
    Attached Files

  • #2
    Yes

    Code:
    ws:inbound-gateway->transformRequestIfNecessary->ws:outbound-gateway->transformResponseIfNecessary

    Comment


    • #3
      Hi Gary,

      There is a sample for this case ?

      I'am trying the configuration below (based in the ws-inbound-gateway and ws-outbound-gateway samples):

      Code:
      <int-ws:inbound-gateway id="ws-inbound-gateway" request-channel="wsRequestChannel" extract-payload="false" />
      <int-ws:outbound-gateway id="ws-outbound-gateway" uri="http://www.w3schools.com/webservices/tempconvert.asmx" request-channel="wsRequestChannel"/>
      <int:channel id="wsRequestChannel" />
      <int:channel id="wsResponseChannel" />
      But, this configuration does not work because:

      1. It is missing a transformer (What operations would need to do this transformer?)
      2. Doen not undestand a WSDL request (example: http://server/service?wsdl)

      I understand that it is possible to do a web-service-proxy using the Spring Integration. However, for a novice user (like me , these settings are difficult to do at first. More examples would be helpful.

      Thanks,

      Fabio

      Comment


      • #4
        I only suggested a transformer if the proxy wanted to change the data in any way.

        If you want full-blown WS support on the client side, including WSDL, security, etc, you can use Spring-WS on the inbound side

        http://static.springsource.org/spring-ws/site/

        The Spring WS documentation shows how to expose the WSDL.

        Then, from the @Endpoint, inject a messaging gateway and send the message to the outbound gateway.


        Code:
        SpringWSEndpoint->gw->ws:outbound-gateway

        Comment


        • #5
          Hi Gary,

          Originally posted by Gary Russell View Post
          Code:
          SpringWSEndpoint->gw->ws:outbound-gateway
          The quote above is exactly what I already do: In the ESB (Enterprise Service Bus), I have an SOAP Web Service (web-service-proxy) that redirect the income request to real web service.

          But, to add new Web Services in the ESB is very costly:
          1. Use the WSDL of the real WS to generate the artifacts that will be used in the ESB
          2. Add this generated code in the ESB
          3. Compile and deploy the new version of ESB

          I would like to use a better approach: Simply redirect the SOAP messages to the real web service. No generation of code neither compilation it is necessary.

          I could to do this using the MULE pattern:web-service-proxy, as shown below

          Code:
          <pattern:web-service-proxy name="productLine-ws-proxy"
          		inboundAddress="http://inbound-address/MyWebService"
          		outboundAddress="http://outbound-address/MyWebService"
          		/>
          With only this three lines of configuration, all requests to inbound-address was redirect to outbound-address.

          This is true to consume a service (SOAP messages send via POST) and also to access the service WSDL (http://inbound-address/MyWebService?WSDL)

          Is there something equivalent in the Spring Integration ?

          sorry for the insistence.

          My preference is to use the Spring Integration rather than migrate my current solution for the MULE. My current application is based on the Spring and I would like to continue.

          Thanks again,
          Fabio.

          Comment


          • #6
            Well, my first suggestion will work

            Code:
            ws:inbound-gateway->ws:outbound-gateway
            for normal requests/responses, but it won't proxy the request for the WSDL. You could still deploy the WSDL statically as described in WS documentation.

            Comment


            • #7
              I just ran a test and everything worked as expected.

              Code:
              <int-ws:inbound-gateway id="proxy" request-channel="toOutbound"/>
              
              <int:channel id="toOutbound" />
              
              <int-ws:outbound-gateway 
              	request-channel="toOutbound"
              	uri="http://localhost:18080/ws-inbound-gateway/echoservice" />
              To publish the wsdl from the proxied service on the proxy, download the wsdl, fix up the locationURI to point to the proxy, put it on the classpath, and add this bean to the servlet context...

              Code:
              <ws:static-wsdl id="thewebservice" location="classpath:my.wsdl"/>
              It's then available as

              Code:
              http://.../thewebservice.wsdl
              HTH

              Comment


              • #8
                Hi Gary,

                Thanks for the help.

                Using a SOAP remote web service like temperature converter, instead of POX approch (http://localhost:18080/ws-inbound-gateway/echoservice), result in the error below:

                Code:
                <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 xml:lang="en">Server did not recognize the value of HTTP Header SOAPAction: .</faultstring>
                      </SOAP-ENV:Fault>
                   </SOAP-ENV:Body>
                </SOAP-ENV:Envelope>
                This could be fixed using a <int-ws:header-enrich inside> inside a <int-chain> to add the soap-action. But, This should not be automatic (ws-outbound add the soap-action http, if any) ?

                Furthermore, using the <ws:static-wsdl> result in a non standard wsdl url. The default URL to download the WSDL follows the form http://<server>/webservice?wsdl instead of http://<server>/webservice.wsdl

                Of course this can also be corrected, but adds an additional overhead in the overall process.

                Finnaly, in the code below

                Code:
                 <int-ws:inbound-gateway id="proxy" request-channel="toOutbound"/>
                it will be necessary to add a filter to redirect only the desired service.

                It would be possible to create a namespace that solves these problems, as shown below?

                Code:
                <int-ws:soap-proxy 
                   wsdl-service-name="<wsdl:service@name>"  
                   target-web-service="http://<server>/serviceName" 
                   wsdl-location="classpath:META-INF/wsdl/serviceName.wsdl" 
                   wsdl-ulr-pattern="?|." 
                />
                Where:

                1. wsdl-service-name --> [optional] The name of the service that could be accepted by this endpoint. If not specified, all income request will be accepteds;
                2. target-web-service --> The url of the proxied web service
                3. wsdl-location --> The local copy of the target-web-service WSDL
                4. wsdl-ulr-pattern --> specify if the wsdl url is in the form http://../serviceName.wsdl or http://../serviceName?wsdl

                Explanation:

                A - The spring servlet MessageDispatcherServlet dispatch all requests to org.springframework.integration.ws.SimpleWebServic eInboundGateway;

                B - The attribute wsdl-service-name allows that the endpoint only accept the requests of the expected services (It checks the attribute wsdl:service@name of the income requests). This attribute also allows a modular programming: new proxied web services could be stored in the modules themselves, because it only accept the specified requests;

                C - The attribute wsdl-location turn the ESB (Enterprise Service Bus) independent of the remote wsdl;

                D - The attribute wsdl-ulr-pattern alow two common wsdl url: "?wsdl" or ".wsdl"

                Thank you very much,
                Fabio.
                Last edited by lisboa; Mar 9th, 2012, 07:35 AM. Reason: fix and add some clarification about the <int-ws:soap-proxy> proposal

                Comment


                • #9
                  You raise some interesting points.

                  We do have access to the Http header (soap action), so we could propagate it, if we decide to raise the support of a ws proxy to a first class citizen.

                  I don't believe ...?wsdl is a "standard" per se. In fact, there are lots of examples on the web using the .wsdl format...

                  http://developer.ebay.com/devzone/sh...tOverview.html

                  Please go ahead and open a new feature JIRA here https://jira.springsource.org/browse/INT and we'll consider being more friendly to WS proxying for an upcoming release.

                  Thanks.

                  Comment


                  • #10
                    Hello Gary,

                    beyond soap-action, the (1) caller IP (Internet Protocol of the caller), the (2) requested URI and the (3) wsdl:service@name would also be useful.

                    (1) The path of the requested URI is commonly used as web service selector. For example

                    http://server/service1
                    http://server/service2

                    If the requested URI is present in the Spring Integration WS-Message, then it is possible to use a publish-subcribe-channel + filters to redirect the income messages to the appropriate ws-outbound-gateway (in fact, the appropriate target-web-services).

                    Probably this could be made using the UriEndpointMapping.mapping properties, but it seems to me that this is not very modular, because new web-services-proxy requires modification in a centralized repository (the mapping) and, possibly, a server restart.

                    Using the publish-subcribe-channel + filters approch, allow the adition of new web service proxy in its own module (i.e. add a new spring configurarion file with the new filter + ws-outbound-gateway) in a OSGI module (perhaps ..).

                    (2) and (3) The caller IP and wsdl:service@name together with web service failure/success information turn easy to create usefull auditing:

                    (2.a) The Caller IP-A accessed the wsdl:service@name resulting in a success (or failure)
                    (2.b) The IP A could access the target-web-service-A, but could not access the target-web-service-B. This could be made using a servlet filter. In this case, it would be necessary to check if a income request is or is not a web service call, but that is exactly what is done by int-ws namespace...

                    Using a servlet filter I have access to requested URI and caller IP, but the status (success, failure) of the web service invokation is not available (At least, not as accessible as a Spring Integration SOAPMessage);

                    Note: In fact, the "?wsdl" is not a standard. I meant it is a common use for wsdl url (excuse me for my lack of precision).

                    Thanks!
                    Last edited by lisboa; Mar 10th, 2012, 12:18 AM.

                    Comment


                    • #11
                      Providing access to the soap action header is pretty simple (see my commont on the JIRA https://jira.springsource.org/browse...#comment-76711. A custom header mapper will get you there very quickly.

                      However, by the time we get to the Spring Integration Endpoint, we no longer have access to the original http request object so, unless I missed something, getting the remote host, for example, is not currently possible, and would require changes to Spring WS.

                      Changing the .wsdl to ?wsdl would also require changes in Spring WS. You could write a simple servlet that redirected ...xxx?wsdl requests to ...xxx.wsdl

                      Comment


                      • #12
                        @Fabio - if you just want a straight pass-through proxy, you might want to consider using http gateways instead of ws gateways - that way, you would avoid the overhead of SOAP and XML processing on the proxy.

                        Code:
                        <int-http:inbound-gateway 
                        	request-channel="toOutbound" path="/proxy"
                        	mapped-request-headers="soapaction, content-type"
                        	supported-methods="POST"/>
                        
                        <int:channel id="toOutbound" />
                        
                        <int-http:outbound-gateway request-channel="toOutbound" http-method="POST"
                        	url="http://www.w3schools.com/webservices/tempconvert.asmx"
                        	mapped-request-headers="soapaction, content-type"
                        	expected-response-type="java.lang.String"/>
                        The header mapper still doesn't (currently) give you full access to the http request object, though (but that would be under our control and wouldn't require changes to core spring).

                        Comment

                        Working...
                        X