8 Replies Latest reply on Jan 17, 2008 9:39 AM by mwax

    FaultTo Behavior Changed?

    mwax Newbie

      We have found that setting a faultTo address no longer seems to work. We had tested our code against 4.2GA, and were able to observe our message being sent to the faultTo address if we threw a test exception. Now, we see the log entry

      No fault address defined for fault message!...

      or nothing at all, depending on whether we set the mep attribute for the actions.

      We traced this to a change in code in the ActionProcessingPipeline faultTo method. The code in 4.2.2 is as follows:
      private void faultTo(final Call callDetails, final Message message)
      {
       if (!DefaultFaultTo.initialiseReply(message, callDetails))
       {
       if (defaultProcessing)
       {
       LOGGER.warn("No fault address defined for fault message! " + callDetails);
       sendToDLQ(callDetails, message, MessageType.fault) ;
       }
       }
       else
       {
       final EPR faultToEPR = message.getHeader().getCall().getTo() ;
       messageTo(faultToEPR, message, MessageType.fault);
       }
      }


      This is changed from the code in 4.2:

      private void faultTo(EPR faultToAddress, Message message)
      {
       Courier courier = null;
       EPR faultToEPR = DefaultFaultTo.getFaultToAddress(message);
      
       if (faultToEPR != null)
       faultToAddress = faultToEPR;
      
       if (faultToAddress == null)
       {
       LOGGER.warn("No fault address defined for fault message!");
       }
       else
       {
       try
       {
       courier = CourierFactory.getCourier(faultToAddress);
       courier.deliver(message);
       }



      What do we need to make the faultTo work now?


        • 1. Re: FaultTo Behavior Changed?
          Kevin Conner Master

          It sounds as if you are overriding the FaultTo within your pipeline, this is invalid. The 4.2 codebase allowed this to happen but has since been corrected.

          The FaultTo/ReplyTo EPR should be specified by the caller of your service and not within your service.

          • 2. Re: FaultTo Behavior Changed?
            mwax Newbie

            Messages enter our service through a file gateway. How would we set a faultTo address for these messages?

            • 3. Re: FaultTo Behavior Changed?
              Kevin Conner Master

              The fault message should go to the ReplyTo address by default. If you want to override this behaviour at the gateway then the best solution will be to override the composer and specify the new FaultTo address.

              Can you describe what you are trying to achieve?

              • 4. Re: FaultTo Behavior Changed?
                mwax Newbie

                After a message is created by the gateway, we would like that message to be sent to a faultTo address when an exception is thrown.

                Can you give me a little bit more detail on what you mean by overriding the composer?

                • 5. Re: FaultTo Behavior Changed?
                  Vinicius Carvalho Apprentice

                  mwax, I needed the exact same thing as you. You need to create a new messagecomposer, and define it on you listener:

                  <jms-listener name="inboundListener" busidref="CSMGateway" is-gateway="true" maxThreads="1">
                   <property name="composer-class" value="com.synos.csm.esb.message.CSMMessageComposer"></property>
                  
                   </jms-listener>
                  


                  You can use AbstractMessageComposer as your base class.

                  I have a class here that does that (sets a faultto) but its for JMS listeners only, I'm using properties from the jboss-esb to set the fault-to:

                  <jms-listener name="inboundListener" busidref="CSMGateway" is-gateway="true" maxThreads="1">
                   <property name="composer-class" value="com.synos.csm.esb.message.CSMMessageComposer"></property>
                   <property name="default-epr">
                   <fault-to dest-type="queue" dest-name="CSMFaultChannel"/>
                   <reply-to dest-type="queue" dest-name="ESBChannel_reply"/>
                   </property>
                   </jms-listener>
                  
                  



                  package com.synos.csm.esb.message;
                  
                  import java.io.ByteArrayOutputStream;
                  import java.io.IOException;
                  
                  import javax.jms.BytesMessage;
                  import javax.jms.JMSException;
                  import javax.jms.ObjectMessage;
                  import javax.jms.TextMessage;
                  
                  import org.jboss.soa.esb.actions.ActionUtils;
                  import org.jboss.soa.esb.addressing.eprs.JMSEpr;
                  import org.jboss.soa.esb.helpers.ConfigTree;
                  import org.jboss.soa.esb.listeners.gateway.DefaultESBPropertiesSetter;
                  import org.jboss.soa.esb.listeners.gateway.ESBPropertiesSetter;
                  import org.jboss.soa.esb.listeners.message.AbstractMessageComposer;
                  import org.jboss.soa.esb.listeners.message.MessageDeliverException;
                  import org.jboss.soa.esb.message.Body;
                  import org.jboss.soa.esb.message.Message;
                  import org.jboss.soa.esb.message.MessagePayloadProxy;
                  import org.jboss.soa.esb.message.body.content.BytesBody;
                  import org.jboss.soa.esb.message.format.MessageFactory;
                  
                  import com.synos.csm.esb.CSMConstants;
                  
                  public class CSMMessageComposer extends AbstractMessageComposer {
                   private ConfigTree config;
                   public CSMMessageComposer(ConfigTree config){
                   this.config = config;
                   payloadProxy = new MessagePayloadProxy(config);
                   }
                   private ESBPropertiesSetter esbPropertiesStrategy = new DefaultESBPropertiesSetter();
                   private MessagePayloadProxy payloadProxy;
                  
                   @Override
                   protected void populateMessage(Message message, Object messagePayload)
                   throws MessageDeliverException {
                   System.out.println("what da fuck should I do???");
                  
                   }
                  
                   public Message process(final Object obj) throws JMSException, IOException, MessageDeliverException {
                   if ( !(obj instanceof javax.jms.Message))
                   throw new IllegalArgumentException("Object must be instance of javax.jms.Message");
                   final javax.jms.Message jmsMessage = (javax.jms.Message) obj;
                  
                   final Message esbMessage = MessageFactory.getInstance().getMessage();
                  
                   setESBMessageBody( jmsMessage, esbMessage );
                   esbPropertiesStrategy.setPropertiesFromJMSMessage(jmsMessage, esbMessage);
                   ConfigTree[] replyTo = config.getChildren(CSMConstants.COMPOSER_DEFAULT_REPLY_TO);
                   ConfigTree[] faultTo = config.getChildren(CSMConstants.COMPOSER_DEFAULT_FAULT_TO);
                   if(replyTo != null && replyTo.length > 0){
                   esbMessage.getHeader().getCall().setReplyTo(new JMSEpr(replyTo[0].getAttribute("dest-type"),replyTo[0].getAttribute("dest-name"),"ConnectionFactory"));
                   }
                   if(faultTo != null && faultTo.length > 0){
                   esbMessage.getHeader().getCall().setFaultTo(new JMSEpr(faultTo[0].getAttribute("dest-type"),faultTo[0].getAttribute("dest-name"),"ConnectionFactory"));
                   }
                  
                   return esbMessage;
                   }
                  
                   private void setESBMessageBody( final javax.jms.Message fromJMSMessage, final Message toESBMessage ) throws JMSException, IOException, MessageDeliverException {
                   byte[] bodyAsBytes = null;
                  
                   if (fromJMSMessage instanceof TextMessage)
                   {
                   final String text = ((TextMessage) fromJMSMessage).getText();
                   payloadProxy.setPayload(toESBMessage, text);
                   }
                   else if (fromJMSMessage instanceof BytesMessage)
                   {
                   final BytesMessage jBytes = (BytesMessage) fromJMSMessage;
                   ByteArrayOutputStream out = new ByteArrayOutputStream();
                   byte[] ba = new byte[1000];
                   int iQread;
                   while (-1 != (iQread = jBytes.readBytes(ba)))
                   {
                   if (iQread > 0) out.write(ba, 0, iQread);
                   out.close();
                   }
                   bodyAsBytes = out.toByteArray();
                   payloadProxy.setPayload(toESBMessage, bodyAsBytes);
                   }
                   else if (fromJMSMessage instanceof ObjectMessage)
                   {
                   final Object object = ((ObjectMessage) fromJMSMessage).getObject();
                   payloadProxy.setPayload(toESBMessage, object);
                   }
                  
                   }
                  
                  
                  }
                  


                  PS: I did copy a lot of methods from the PackageJMSMessageContents (shame on me :P )

                  Regards

                  • 6. Re: FaultTo Behavior Changed?
                    Kevin Conner Master

                    The gateway composes the incoming messages using a default instance of MessageComposer but it is possible to override this class if it does not suit your purpose.

                    To override it you need to specify the composer-class property within your gateway and specify the value as your composer class name.

                    <property name="composer-class" value="composer class name"/>


                    The file gateway uses an instance of LocalFileMessageComposer as it's default so you could create a subclass to initialise the FaultTo address.

                    • 7. Re: FaultTo Behavior Changed?
                      Kevin Conner Master

                      Hiya viniciuscarvalho.

                      Thanks very much for providing the example code.

                      • 8. Re: FaultTo Behavior Changed?
                        mwax Newbie

                        Thanks, we created our own MessageComposer, and this works.