4 Replies Latest reply on Jan 2, 2009 8:14 AM by Kevin Conner

    faultTo and OneWay mep

    Kevin Richards Newbie

      Hi,

      I'm trying to get faultTo working when using OneWay actions.

      I tried the "exceptions_fault" quickstart to work, running the "callSync" test but I'm not getting the behaviour I expected.

      According to the readme.txt

      Your custom buiness logic exceptions will be wrapped by an ActionProcessingException but still
       be available on the client-side when using the
       ServiceInvoker.deliverSync(String myMessage,int timeout) option.
       SendEsbMessageSync.java demostrates ths when you run "ant callSync"
      

      Instead of the business exception I expect on the client, I get "MessageDeliverException".
      What seems to happen on the server is that it's trying to send the message to the DLQ.

      If I look at the code I find that in ActionProcessingPipeline it does the following on an exception
      if (ex instanceof ActionProcessingFaultException)
      {
       ActionProcessingFaultException fault = (ActionProcessingFaultException) ex;
      
       if (fault.getFaultMessage() == null)
       {
       faultTo(callDetails, Factory.createErrorMessage(Factory.PROCESSING_ERROR, message, ex));
       }
       else
       faultTo(callDetails, fault.getFaultMessage());
      }
      else if (!throwRuntime)
      {
       faultTo(callDetails, Factory.createErrorMessage(Factory.UNEXPECTED_ERROR, message, ex));
      }
      


      Factory.createErrorMessage then creates a new message, but doesn't copy the "faultTo" details, and I suspect this is where the problem lies.

      Has anyone managed to get a business fault (exception) on the client side when using "OneWay" ?



        • 1. Re: faultTo and OneWay mep
          Kevin Conner Master

          The faultTo details are contained in the callDetails variable and will be used within the faultTo method.

          The fault message will go to the DLQ if you have not configured the FaultTo on the *client* side. If that is the case then you should see a warning in the logs, something like 'No fault address defined for fault message!'.

          • 2. Re: faultTo and OneWay mep
            Kevin Richards Newbie

            Hi,

            Thanks for the reply. Just to make sure, are you saying the "exceptions_fault" quickstart should have the correct (business) exception thrown in the client? (If this is the case I probably need to get an update from the repo since the quickstart that came with the ESB4.4GA download does not behave this way)

            Currently I populate the faultTo as the first action in the service, where I have the second action throw the exception. On the client side I'm using ServiceInvoker.deliverSync. I want the fault to return to this "sevice invoker" call, but don' t know how to setup the fault on the client side.

            (This is just code I'm using to test how faults work, but setting fault this way doesn't seem to work either)

             try
             {
             String message="test";
             ServiceInvoker service = new ServiceInvoker("Test", "JmsEntry");
             Message reqMsg = MessageFactory.getInstance().getMessage();
             reqMsg.getBody().add(message);
             EPR faultEpr= reqMsg.getHeader().getCall().getFrom();
             reqMsg.getHeader().getCall().setFaultTo( faultEpr);
             Message respMsg = service.deliverSync(reqMsg, 50000);
             System.out.println(respMsg.getBody().get());
             return "AcmEntryPoint: " + respMsg.getBody().get() + " received";
             }
             catch (Exception err)
             {
             System.out.println( "Error: " + err.toString());
             return "ERROR";
             }
            


            Although I set the faultTo as the first action, somehow it gets "lost".

            I'm sure I'm missing something. If only I knew what :)

            • 3. Re: faultTo and OneWay mep
              Kevin Richards Newbie

              I think I "solved" the problem.
              If I put the action that sets the faultTo in a different service that gets invoked before the service containing the business logic, it seems to work

              The following jboss-esb.xml seems to do the trick

              <service name="Start" description="Configure" category="Test">
               <actions mep="OneWay">
               <action name="configureFault" class="za.co.xxxx.esb.SetFaultAction"/>
               <action name="routeAction"
               class="org.jboss.soa.esb.actions.StaticRouter">
               <property name="destinations">
               <route-to service-category="Test"
               service-name="Process" />
               </property>
               </action>
               </actions>
              </service>
              
              <service name="Process" description="Business Logic" category="Test">
               <actions mep="OneWay">
               <action name="testAction" class="za.co.xxxx.esb.TestAction"/>
               </actions>
              </service>
              


              BTW.

              The ActionProcessingPipeline.process starts with
              public boolean process(final Message message)
              {
               long start = System.nanoTime();
               serviceMessageCounter.incrementTotalCount();
               final Call callDetails = new Call() ;
               callDetails.copy(message.getHeader().getCall()) ;
              ...
              


              Further down, it then iterates through the actions and does
              for (int count = 0; count < numProcessors; count++)
              {
               final ActionPipelineProcessor processor = processors[count];
               messages[count] = currentMessage;
              
               try
               {
               LOGGER.debug("executing processor " + count+ " "+processor+" "+message.getHeader());
              
               currentMessage = processor.process(currentMessage);
              ...
              


              Would it be possible to get the "latest" call detail after an action is processed. E.g.
              for (int count = 0; count < numProcessors; count++)
              {
               final ActionPipelineProcessor processor = processors[count];
               messages[count] = currentMessage;
              
               try
               {
               LOGGER.debug("executing processor " + count+ " "+processor+" "+message.getHeader());
              
               currentMessage = processor.process(currentMessage);
               // get the latest call detail
              ...
              


              (The above code can be optimised to only get the call detail when actually required.)
              With this change, I would not have to seperate my "calldetail" manipulating code into a different service.

              Thanks for all your help

              • 4. Re: faultTo and OneWay mep
                Kevin Conner Master

                The specification of the ReplyTo/FaultTo is the responsibility of the caller and not the service being invoked. The service can determine whether it generates replies/faults but cannot dictate where they are sent to.

                Kev