Coverage Report - org.mule.construct.Validator
 
Classes in this File Line Coverage Branch Coverage Complexity
Validator
0%
0/69
0%
0/18
0
Validator$1
N/A
N/A
0
Validator$ErrorAwareEventReturningMessageProcessor
0%
0/11
0%
0/2
0
Validator$ErrorExpressionTransformerMessageProcessor
0%
0/8
0%
0/2
0
 
 1  
 /*
 2  
  * $Id$
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.construct;
 12  
 
 13  
 import org.apache.commons.lang.Validate;
 14  
 import org.mule.MessageExchangePattern;
 15  
 import org.mule.RequestContext;
 16  
 import org.mule.api.ExceptionPayload;
 17  
 import org.mule.api.MuleContext;
 18  
 import org.mule.api.MuleEvent;
 19  
 import org.mule.api.MuleException;
 20  
 import org.mule.api.MuleMessage;
 21  
 import org.mule.api.MuleRuntimeException;
 22  
 import org.mule.api.construct.FlowConstructInvalidException;
 23  
 import org.mule.api.endpoint.InboundEndpoint;
 24  
 import org.mule.api.endpoint.OutboundEndpoint;
 25  
 import org.mule.api.lifecycle.InitialisationException;
 26  
 import org.mule.api.processor.MessageProcessor;
 27  
 import org.mule.api.routing.filter.Filter;
 28  
 import org.mule.api.source.MessageSource;
 29  
 import org.mule.config.i18n.MessageFactory;
 30  
 import org.mule.construct.processor.FlowConstructStatisticsMessageObserver;
 31  
 import org.mule.expression.ExpressionConfig;
 32  
 import org.mule.expression.transformers.ExpressionArgument;
 33  
 import org.mule.expression.transformers.ExpressionTransformer;
 34  
 import org.mule.interceptor.LoggingInterceptor;
 35  
 import org.mule.message.DefaultExceptionPayload;
 36  
 import org.mule.processor.AbstractInterceptingMessageProcessor;
 37  
 import org.mule.processor.ResponseMessageProcessorAdapter;
 38  
 import org.mule.processor.builder.InterceptingChainMessageProcessorBuilder;
 39  
 import org.mule.routing.ChoiceRouter;
 40  
 import org.mule.util.StringUtils;
 41  
 
 42  0
 public class Validator extends AbstractFlowConstruct
 43  
 {
 44  
     private final OutboundEndpoint outboundEndpoint;
 45  
     private final Filter validationFilter;
 46  
     private final String ackExpression;
 47  
     private final String nackExpression;
 48  
     private final String errorExpression;
 49  
 
 50  
     public Validator(String name,
 51  
                      MuleContext muleContext,
 52  
                      MessageSource messageSource,
 53  
                      OutboundEndpoint outboundEndpoint,
 54  
                      Filter validationFilter,
 55  
                      String ackExpression,
 56  
                      String nackExpression)
 57  
     {
 58  0
         this(name, muleContext, messageSource, outboundEndpoint, validationFilter, ackExpression,
 59  
             nackExpression, null);
 60  0
     }
 61  
 
 62  
     public Validator(String name,
 63  
                      MuleContext muleContext,
 64  
                      MessageSource messageSource,
 65  
                      OutboundEndpoint outboundEndpoint,
 66  
                      Filter validationFilter,
 67  
                      String ackExpression,
 68  
                      String nackExpression,
 69  
                      String errorExpression)
 70  
     {
 71  0
         super(name, muleContext);
 72  
 
 73  0
         Validate.notNull(messageSource, "messageSource can't be null");
 74  0
         Validate.notNull(outboundEndpoint, "outboundEndpoint can't be null");
 75  0
         Validate.notNull(validationFilter, "validationFilter can't be null");
 76  0
         Validate.notEmpty(ackExpression, "ackExpression can't be empty");
 77  0
         Validate.notEmpty(nackExpression, "nackExpression can't be empty");
 78  
 
 79  0
         this.messageSource = messageSource;
 80  0
         this.outboundEndpoint = outboundEndpoint;
 81  0
         this.validationFilter = validationFilter;
 82  0
         this.ackExpression = ackExpression;
 83  0
         this.nackExpression = nackExpression;
 84  0
         this.errorExpression = errorExpression;
 85  0
     }
 86  
 
 87  
     @Override
 88  
     protected void configureMessageProcessors(InterceptingChainMessageProcessorBuilder builder)
 89  
     {
 90  0
         builder.chain(new LoggingInterceptor());
 91  0
         builder.chain(new FlowConstructStatisticsMessageObserver());
 92  
 
 93  0
         final ErrorAwareEventReturningMessageProcessor outboundMessageProcessor = new ErrorAwareEventReturningMessageProcessor();
 94  0
         outboundMessageProcessor.setListener(outboundEndpoint);
 95  
 
 96  0
         final ResponseMessageProcessorAdapter ackResponseMessageProcessor = new ResponseMessageProcessorAdapter();
 97  0
         ackResponseMessageProcessor.setListener(outboundMessageProcessor);
 98  0
         ackResponseMessageProcessor.setProcessor(getExpressionTransformer(getName() + "-ack-expression",
 99  
             ackExpression));
 100  
 
 101  0
         MessageProcessor validRouteMessageProcessor = ackResponseMessageProcessor;
 102  
 
 103  0
         if (hasErrorExpression())
 104  
         {
 105  0
             final ErrorExpressionTransformerMessageProcessor errorResponseMessageProcessor = new ErrorExpressionTransformerMessageProcessor(
 106  
                 getExpressionTransformer(getName() + "-error-expression", errorExpression));
 107  0
             errorResponseMessageProcessor.setListener(ackResponseMessageProcessor);
 108  0
             validRouteMessageProcessor = errorResponseMessageProcessor;
 109  
         }
 110  
 
 111  
         // a simple success/failure choice router determines which response to return
 112  0
         final ChoiceRouter choiceRouter = new ChoiceRouter();
 113  0
         choiceRouter.addRoute(validRouteMessageProcessor, validationFilter);
 114  0
         choiceRouter.setDefaultRoute(getExpressionTransformer(getName() + "-nack-expression", nackExpression));
 115  0
         builder.chain(choiceRouter);
 116  0
     }
 117  
 
 118  
     @Override
 119  
     protected void validateConstruct() throws FlowConstructInvalidException
 120  
     {
 121  0
         super.validateConstruct();
 122  
 
 123  0
         validateMessageSource();
 124  0
         validateOutboundEndpoint();
 125  0
         validateExpression(ackExpression);
 126  0
         validateExpression(nackExpression);
 127  
 
 128  0
         if (hasErrorExpression())
 129  
         {
 130  0
             validateExpression(errorExpression);
 131  
         }
 132  0
     }
 133  
 
 134  
     private void validateMessageSource() throws FlowConstructInvalidException
 135  
     {
 136  0
         if ((messageSource instanceof InboundEndpoint)
 137  
             && (!((InboundEndpoint) messageSource).getExchangePattern().equals(
 138  
                 MessageExchangePattern.REQUEST_RESPONSE)))
 139  
         {
 140  0
             throw new FlowConstructInvalidException(
 141  
                 MessageFactory.createStaticMessage("Validator only works with a request-response inbound endpoint."),
 142  
                 this);
 143  
         }
 144  0
     }
 145  
 
 146  
     private void validateOutboundEndpoint() throws FlowConstructInvalidException
 147  
     {
 148  0
         if ((hasErrorExpression())
 149  
             && (!outboundEndpoint.getExchangePattern().equals(MessageExchangePattern.REQUEST_RESPONSE)))
 150  
         {
 151  0
             throw new FlowConstructInvalidException(
 152  
                 MessageFactory.createStaticMessage("Validator with an error expression only works with a request-response outbound endpoint."),
 153  
                 this);
 154  
         }
 155  0
     }
 156  
 
 157  
     protected boolean hasErrorExpression()
 158  
     {
 159  0
         return StringUtils.isNotBlank(errorExpression);
 160  
     }
 161  
 
 162  
     private void validateExpression(String expression) throws FlowConstructInvalidException
 163  
     {
 164  0
         if (!muleContext.getExpressionManager().isExpression(expression))
 165  
         {
 166  0
             throw new FlowConstructInvalidException(
 167  
                 MessageFactory.createStaticMessage("Invalid expression in Validator: " + expression), this);
 168  
         }
 169  0
     }
 170  
 
 171  
     private ExpressionTransformer getExpressionTransformer(String name, String expression)
 172  
     {
 173  0
         final ExpressionConfig expressionConfig = new ExpressionConfig();
 174  0
         expressionConfig.parse(expression);
 175  
 
 176  0
         final ExpressionArgument expressionArgument = new ExpressionArgument(name, expressionConfig, false);
 177  0
         expressionArgument.setMuleContext(muleContext);
 178  
 
 179  0
         final ExpressionTransformer expressionTransformer = new ExpressionTransformer();
 180  0
         expressionTransformer.setMuleContext(muleContext);
 181  0
         expressionTransformer.addArgument(expressionArgument);
 182  
 
 183  
         try
 184  
         {
 185  0
             expressionTransformer.initialise();
 186  
         }
 187  0
         catch (final InitialisationException ie)
 188  
         {
 189  0
             throw new MuleRuntimeException(ie);
 190  0
         }
 191  
 
 192  0
         return expressionTransformer;
 193  
     }
 194  
 
 195  
     private static class ErrorExpressionTransformerMessageProcessor extends
 196  
         AbstractInterceptingMessageProcessor
 197  
     {
 198  
         private final ExpressionTransformer errorExpressionTransformer;
 199  
 
 200  
         public ErrorExpressionTransformerMessageProcessor(ExpressionTransformer errorExpressionTransformer)
 201  0
         {
 202  0
             this.errorExpressionTransformer = errorExpressionTransformer;
 203  0
         }
 204  
 
 205  
         public MuleEvent process(MuleEvent event) throws MuleException
 206  
         {
 207  0
             final MuleEvent nextResult = super.processNext(event);
 208  
 
 209  0
             final ExceptionPayload nextResultMessageExceptionPayload = getExceptionPayload(nextResult);
 210  
 
 211  0
             if (nextResultMessageExceptionPayload != null)
 212  
             {
 213  0
                 return errorExpressionTransformer.process(event);
 214  
             }
 215  
 
 216  0
             return nextResult;
 217  
         }
 218  
     }
 219  
 
 220  0
     private static class ErrorAwareEventReturningMessageProcessor extends
 221  
         AbstractInterceptingMessageProcessor
 222  
     {
 223  
         /*
 224  
          * Returns the incoming event whatever the outcome of the rest of the chain
 225  
          * maybe. Sets an exception payload on the incoming event if an error
 226  
          * occurred downstream.
 227  
          */
 228  
         public MuleEvent process(MuleEvent event) throws MuleException
 229  
         {
 230  0
             final MuleEvent result = RequestContext.cloneAndUpdateEventEndpoint(event, this);
 231  
 
 232  
             try
 233  
             {
 234  0
                 final MuleEvent nextResult = super.processNext(event);
 235  
 
 236  0
                 final ExceptionPayload nextResultMessageExceptionPayload = getExceptionPayload(nextResult);
 237  
 
 238  0
                 if (nextResultMessageExceptionPayload != null)
 239  
                 {
 240  0
                     result.getMessage().setExceptionPayload(nextResultMessageExceptionPayload);
 241  
                 }
 242  
             }
 243  0
             catch (final MuleException me)
 244  
             {
 245  0
                 logger.error(me);
 246  0
                 result.getMessage().setExceptionPayload(new DefaultExceptionPayload(me));
 247  0
             }
 248  
 
 249  0
             return result;
 250  
         }
 251  
     }
 252  
 
 253  
     private static ExceptionPayload getExceptionPayload(MuleEvent event)
 254  
     {
 255  0
         if (event == null)
 256  
         {
 257  0
             return null;
 258  
         }
 259  
 
 260  0
         final MuleMessage message = event.getMessage();
 261  0
         if (message == null)
 262  
         {
 263  0
             return null;
 264  
         }
 265  
 
 266  0
         return message.getExceptionPayload();
 267  
     }
 268  
 }