11 Replies Latest reply on Jan 2, 2008 10:58 AM by viniciuscarvalho

    Architectural question: Service Aware endpoints

    viniciuscarvalho

      Hi again :)

      I'm facing an dilemma here, and I hope someone from the ESB team could help me out.

      I have a previous experience with ESBs (Websphere ESB, aka WESB), which in my own opinion, of use in a project (it sucks, expensive, buggy, not flexible... anyway)

      One thing that I found a good design though, is the way it exposes the bus to the world, we have imports and exports. It's easy to have an import and have your bus invoked using JMS or SOAP, and we manage the request/response message flow.


      Well, we are using Jboss ESB to have a service available through a different kind of protocols (so far JMS/SOAP and soon FTP)

      My WebService interface has only OneWay operations, so, I do not put anything on the response.

      Now, since the SOAPProcessor is an action, it takes the response from the WS and put on the body of the message, overriding what I've done before.

      Here's a snippet of my WS:

       public Source invoke(Source source) {
       Message message = SOAPProcessor.getMessage();
       try{
       Transformer transformer = TransformerFactory.newInstance().newTransformer();
       transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
       transformer.setOutputProperty(OutputKeys.METHOD, "xml");
       StringWriter writer = new StringWriter();
       StreamResult streamResult = new StreamResult(writer);
       transformer.transform(source, streamResult);
       message.getBody().add(writer.toString());
       }catch (Exception e) {
       e.printStackTrace();
       }
      
       return getResponseSource();
       }
      


      At this point my body contains the payload of the operation, this should be sent to the bus and other actions take place.
      The problem is that the SOAPProcessor overrides it and set the response of my service (I have not even started the flow of events that will build my response) to the default body location.
      Since I'm using one-way, all I need to return to my client at this point is an empty soap envelope.

      I was reading the programmers guide, and I do know that one should be careful when dealing with the default location of the body, but, summing all my story into one question:

      Wouldn't be a better choice, if the exposed Service should not be considered just another action on the flow, but just a listener that deliveries messages to the bus?

      If someone understand my bad-confusing English, would you mind to give me a hand here?




        • 1. Re: Architectural question: Service Aware endpoints
          marklittle

          In order to take an inbound payload and deliver it to ESB-aware endpoints, something needs to "adapt" the inbound so that it can be understood. I'm not sure what your precise problem is though. Do you want more control over where the payload goes in the Message? Do you want more control over the response?

          • 2. Re: Architectural question: Service Aware endpoints
            tfennelly

            I'm not sure I understand your question either so I'll just throw out some stuff and you can investigate from there.

            1. Look at MessageComposers... most/all of the Gateways allow you to override the default composer, which allows you control how the Message is composed on the way in and decomposed on the way out (for a request/response gateway).

            2. Look at the "mep" attribute on actions element of the config. It allows you to set it to "oneWay" or "requestResponse".

            3. Look at the MessagePayloadProxy class. It's used by all ESB actions to control where it gets the payload from the message and sets the response (defaulting to the default location).

            4. I think the jbr-listener supports a sync/async attribute, but I forget how/if it works and how/if it ties in with the "mep" attribute.

            Can't think of anything else at the moment.

            • 3. Re: Architectural question: Service Aware endpoints
              viniciuscarvalho

              Thanks for the responses! I'll take a look at the message composer.

              My message was pretty confusing sorry, was in a rush. My main problem is how jboss esb deals with WS endpoints. The SOAPProcessor is not an endpoint at my point of view, but an action that is called on the flow of the service. I'd like to have an service exposed as a WS not a service that intercepts a WS fetches its response and puts on the payload of the message :)

              For our service, the problem of this approach, is that it imposes the soap envelope schema that all my clients, no matter which protocol they use, they must send and SOAP envelope xml message, otherwise, an error is thrown!

              What I was hopping is to have one service, that listens to different listeners and handle the messages. That work for jms-listener, but when I use the SOAPProcessor, the message that was received from the jms-bus need to be wrapped inside a soap envelope (it is easier for my clients to create a non soap message, although I know that it is VERY simple to wrap inside an envelope, but they pay the bills :( ).

              I was able to solve this, by having 4 different services, one for each protocol, and one that gets the payload (the body of the soap envelope) and process the message.

              I'm still checking the hints from tfennely (thanks). This model changed a bit the way we were expecting to have things working, but so far the most important is that it is still working :)

              Thanks for all support.

              Best new year

              • 4. Re: Architectural question: Service Aware endpoints
                tfennelly

                 

                "viniciuscarvalho" wrote:
                What I was hopping is to have one service, that listens to different listeners and handle the messages. That work for jms-listener, but when I use the SOAPProcessor, the message that was received from the jms-bus need to be wrapped inside a soap envelope (it is easier for my clients to create a non soap message, although I know that it is VERY simple to wrap inside an envelope, but they pay the bills :( ).


                Still not totally sure I get you, but can't you do this by adding an action before the SOAPProcessor to "wrap" the non-SOAP message in a SOAP Envelope?

                • 5. Re: Architectural question: Service Aware endpoints
                  viniciuscarvalho

                   

                  "tfennelly" wrote:

                  Still not totally sure I get you, but can't you do this by adding an action before the SOAPProcessor to "wrap" the non-SOAP message in a SOAP Envelope?


                  Sure, I'll give it a try, but I'm affraid that this action will be called when the client invoke the WS as well, so I'll need to look if the message is already wrapped or not.

                  I'm checking right now your hints, so far mep="OneWay" did work :(. So I'm studying message composers/processors, in order to understand how can I change the way it deals with WS. How do they relate? Since the SOAPProcessor is a processor, wouldn't it be the one to define what to do with the message? The code bellow (extracted from the soap processor) shows that the SOAPProcessor will always put the response from the WS on the message payload:

                  try {
                   payloadProxy.setPayload(message, response);
                   }


                  Still trying to figure out things here :)

                  Regards

                  • 6. Re: Architectural question: Service Aware endpoints
                    tfennelly

                     

                    "viniciuscarvalho" wrote:
                    Sure, I'll give it a try, but I'm affraid that this action will be called when the client invoke the WS as well, so I'll need to look if the message is already wrapped or not.


                    Yep, or you could define multiple gateways i.e. 1+ for pre-wrapped SOAP message and 1+ for wrapped etc. and then define composers appropriately. Of course (ideally) we should be registering gateways in the reg too + arbitrary attributes of the endpoint that can be used in a reg query e.g. "requiresSoapEnv" (or whatever..). Alternatively, you could create a completely separate wrapper Service that wraps the message in an envelope before routing it to the Service that requires the message to be wrapped.

                    "viniciuscarvalho" wrote:
                    I'm checking right now your hints, so far mep="OneWay" did work :(. So I'm studying message composers/processors, in order to understand how can I change the way it deals with WS.


                    So did mep work or not? You said it "did work", but followed with a sad smiley. If you meant "didn't", then what happened? Maybe Kev can help on that, or maybe it's not relevant to what you're trying to do.

                    "viniciuscarvalho" wrote:
                    How do they relate? Since the SOAPProcessor is a processor, wouldn't it be the one to define what to do with the message? The code bellow (extracted from the soap processor) shows that the SOAPProcessor will always put the response from the WS on the message payload:

                    try {
                     payloadProxy.setPayload(message, response);
                     }


                    Still trying to figure out things here :)

                    Regards


                    • 7. Re: Architectural question: Service Aware endpoints
                      viniciuscarvalho

                       

                      "tfennelly" wrote:
                      Yep, or you could define multiple gateways i.e. 1+ for pre-wrapped SOAP message and 1+ for wrapped etc. and then define composers appropriately. Of course (ideally) we should be registering gateways in the reg too + arbitrary attributes of the endpoint that can be used in a reg query e.g. "requiresSoapEnv" (or whatever..). Alternatively, you could create a completely separate wrapper Service that wraps the message in an envelope before routing it to the Service that requires the message to be wrapped.

                      Yeah, what I'm doing so far is having different gateways :). One for "bare" messages, other for wrapped, both redirect to a 3rd service, which contains the routing/business logic.


                      "tfennelly" wrote:

                      So did mep work or not? You said it "did work", but followed with a sad smiley. If you meant "didn't", then what happened? Maybe Kev can help on that, or maybe it's not relevant to what you're trying to do.

                      Nope, it did not work. I think that it only marks the message to not be sent to a reply EPR (from what I've understood on the programmers guide). But, since SOAPProcessor is used, it puts the WS response on the body default location.

                      "viniciuscarvalho" wrote:
                      How do they relate? Since the SOAPProcessor is a processor, wouldn't it be the one to define what to do with the message? The code bellow (extracted from the soap processor) shows that the SOAPProcessor will always put the response from the WS on the message payload:

                      try {
                       payloadProxy.setPayload(message, response);
                       }


                      Still trying to figure out things here :)

                      Regards


                      "tfennelly" wrote:


                      Not sure what you're asking here.


                      • 8. Re: Architectural question: Service Aware endpoints
                        tfennelly

                         

                        "viniciuscarvalho" wrote:
                        But, since SOAPProcessor is used, it puts the WS response on the body default location.


                        Just to clarify... it puts it in the default body location *by default*!! This can be overridden on a per action config basis. See the javadocs for the MessagePayloadProxy.

                        • 9. Re: Architectural question: Service Aware endpoints
                          viniciuscarvalho

                           

                          "tfennelly" wrote:


                          Just to clarify... it puts it in the default body location *by default*!! This can be overridden on a per action config basis. See the javadocs for the <a href="http://labs.jboss.com/jbossesb/docs/4.2.1GA/javadoc/esb/org/jboss/soa/esb/message/MessagePayloadProxy.html">MessagePayloadProxy</a>.


                          Yes, yet, it does get the response and put it on the message payload :) Having the response of the WS operation on my message is what I was questioning about. I just need the operation parameters on it :)

                          But thanks for this anyway, Instead of moving in another action from a "com.acme.request" to default_location, I'll just ask SOAPProcessor to put it response on a not used body location, and my Service gets the message and puts the request on default_location

                          Thanks a lot Tom

                          Regards

                          • 10. Re: Architectural question: Service Aware endpoints
                            tfennelly

                             

                            "viniciuscarvalho" wrote:
                            Yes, yet, it does get the response and put it on the message payload :)


                            Ahh.

                            So you want the unmarshalled SOAP request params? You are aware that your Webservice endpoint impl has access to the ESB message, right? It has access to it via the static SOAPProcessor.getMessage() method.

                            • 11. Re: Architectural question: Service Aware endpoints
                              viniciuscarvalho

                               

                              "tfennelly" wrote:



                              Ahh.

                              So you want the unmarshalled SOAP request params? You are aware that your Webservice endpoint impl has access to the ESB message, right? It has access to it via the static SOAPProcessor.getMessage() method.


                              Yep, hehe, sorry, finally I could explain my self. Please have a look at my service implementation:

                              public class CSMService implements Provider<Source> {
                              
                               public Source invoke(Source source) {
                               Message message = SOAPProcessor.getMessage();
                               Source response = null;
                               if (message == null) {
                               response = createFaltResponse();
                               } else {
                              
                               try {
                               Transformer transformer = TransformerFactory.newInstance().newTransformer();
                               transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"yes");
                               transformer.setOutputProperty(OutputKeys.METHOD, "xml");
                               StringWriter writer = new StringWriter();
                               StreamResult streamResult = new StreamResult(writer);
                               transformer.transform(source, streamResult);
                               message.getBody().add(writer.toString());
                               response = getResponseSource();
                               } catch (Exception e) {
                               e.printStackTrace();
                               }
                               }
                               return response;
                               }
                              
                               private Source getResponseSource() {
                               Source source = null;
                               StringReader reader = new StringReader(
                               "<?xml version='1.0' encoding='UTF-8'?>");
                               source = new StreamSource(reader);
                               return source;
                               }
                              
                               private Source createFaltResponse() {
                               Source source = null;
                               StringReader reader = new StringReader("<fault>This endpoint should be called from inside ESB exposed interface.</fault>");
                               source = new StreamSource(reader);
                               return source;
                               }
                              


                              See, I'm putting the request param of the service inside my message. The only "problem" of SOAPProcessor, is that it takes the response of this endpoint and puts on the message as well.

                              When I think of how the jms listener works, it just put the received message on the esb's message body. the Soap processor uses the response, this is what making me so confused about the architecture.

                              Regards