1
2
3
4
5
6
7
8
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 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 this(name, muleContext, messageSource, outboundEndpoint, validationFilter, ackExpression,
59 nackExpression, null);
60 }
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 super(name, muleContext);
72
73 Validate.notNull(messageSource, "messageSource can't be null");
74 Validate.notNull(outboundEndpoint, "outboundEndpoint can't be null");
75 Validate.notNull(validationFilter, "validationFilter can't be null");
76 Validate.notEmpty(ackExpression, "ackExpression can't be empty");
77 Validate.notEmpty(nackExpression, "nackExpression can't be empty");
78
79 this.messageSource = messageSource;
80 this.outboundEndpoint = outboundEndpoint;
81 this.validationFilter = validationFilter;
82 this.ackExpression = ackExpression;
83 this.nackExpression = nackExpression;
84 this.errorExpression = errorExpression;
85 }
86
87 @Override
88 protected void configureMessageProcessors(InterceptingChainMessageProcessorBuilder builder)
89 {
90 builder.chain(new LoggingInterceptor());
91 builder.chain(new FlowConstructStatisticsMessageObserver());
92
93 final ErrorAwareEventReturningMessageProcessor outboundMessageProcessor = new ErrorAwareEventReturningMessageProcessor();
94 outboundMessageProcessor.setListener(outboundEndpoint);
95
96 final ResponseMessageProcessorAdapter ackResponseMessageProcessor = new ResponseMessageProcessorAdapter();
97 ackResponseMessageProcessor.setListener(outboundMessageProcessor);
98 ackResponseMessageProcessor.setProcessor(getExpressionTransformer(getName() + "-ack-expression",
99 ackExpression));
100
101 MessageProcessor validRouteMessageProcessor = ackResponseMessageProcessor;
102
103 if (hasErrorExpression())
104 {
105 final ErrorExpressionTransformerMessageProcessor errorResponseMessageProcessor = new ErrorExpressionTransformerMessageProcessor(
106 getExpressionTransformer(getName() + "-error-expression", errorExpression));
107 errorResponseMessageProcessor.setListener(ackResponseMessageProcessor);
108 validRouteMessageProcessor = errorResponseMessageProcessor;
109 }
110
111
112 final ChoiceRouter choiceRouter = new ChoiceRouter();
113 choiceRouter.addRoute(validRouteMessageProcessor, validationFilter);
114 choiceRouter.setDefaultRoute(getExpressionTransformer(getName() + "-nack-expression", nackExpression));
115 builder.chain(choiceRouter);
116 }
117
118 @Override
119 protected void validateConstruct() throws FlowConstructInvalidException
120 {
121 super.validateConstruct();
122
123 validateMessageSource();
124 validateOutboundEndpoint();
125 validateExpression(ackExpression);
126 validateExpression(nackExpression);
127
128 if (hasErrorExpression())
129 {
130 validateExpression(errorExpression);
131 }
132 }
133
134 private void validateMessageSource() throws FlowConstructInvalidException
135 {
136 if ((messageSource instanceof InboundEndpoint)
137 && (!((InboundEndpoint) messageSource).getExchangePattern().equals(
138 MessageExchangePattern.REQUEST_RESPONSE)))
139 {
140 throw new FlowConstructInvalidException(
141 MessageFactory.createStaticMessage("Validator only works with a request-response inbound endpoint."),
142 this);
143 }
144 }
145
146 private void validateOutboundEndpoint() throws FlowConstructInvalidException
147 {
148 if ((hasErrorExpression())
149 && (!outboundEndpoint.getExchangePattern().equals(MessageExchangePattern.REQUEST_RESPONSE)))
150 {
151 throw new FlowConstructInvalidException(
152 MessageFactory.createStaticMessage("Validator with an error expression only works with a request-response outbound endpoint."),
153 this);
154 }
155 }
156
157 protected boolean hasErrorExpression()
158 {
159 return StringUtils.isNotBlank(errorExpression);
160 }
161
162 private void validateExpression(String expression) throws FlowConstructInvalidException
163 {
164 if (!muleContext.getExpressionManager().isExpression(expression))
165 {
166 throw new FlowConstructInvalidException(
167 MessageFactory.createStaticMessage("Invalid expression in Validator: " + expression), this);
168 }
169 }
170
171 private ExpressionTransformer getExpressionTransformer(String name, String expression)
172 {
173 final ExpressionConfig expressionConfig = new ExpressionConfig();
174 expressionConfig.parse(expression);
175
176 final ExpressionArgument expressionArgument = new ExpressionArgument(name, expressionConfig, false);
177 expressionArgument.setMuleContext(muleContext);
178
179 final ExpressionTransformer expressionTransformer = new ExpressionTransformer();
180 expressionTransformer.setMuleContext(muleContext);
181 expressionTransformer.addArgument(expressionArgument);
182
183 try
184 {
185 expressionTransformer.initialise();
186 }
187 catch (final InitialisationException ie)
188 {
189 throw new MuleRuntimeException(ie);
190 }
191
192 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 {
202 this.errorExpressionTransformer = errorExpressionTransformer;
203 }
204
205 public MuleEvent process(MuleEvent event) throws MuleException
206 {
207 final MuleEvent nextResult = super.processNext(event);
208
209 final ExceptionPayload nextResultMessageExceptionPayload = getExceptionPayload(nextResult);
210
211 if (nextResultMessageExceptionPayload != null)
212 {
213 return errorExpressionTransformer.process(event);
214 }
215
216 return nextResult;
217 }
218 }
219
220 private static class ErrorAwareEventReturningMessageProcessor extends
221 AbstractInterceptingMessageProcessor
222 {
223
224
225
226
227
228 public MuleEvent process(MuleEvent event) throws MuleException
229 {
230 final MuleEvent result = RequestContext.cloneAndUpdateEventEndpoint(event, this);
231
232 try
233 {
234 final MuleEvent nextResult = super.processNext(event);
235
236 final ExceptionPayload nextResultMessageExceptionPayload = getExceptionPayload(nextResult);
237
238 if (nextResultMessageExceptionPayload != null)
239 {
240 result.getMessage().setExceptionPayload(nextResultMessageExceptionPayload);
241 }
242 }
243 catch (final MuleException me)
244 {
245 logger.error(me);
246 result.getMessage().setExceptionPayload(new DefaultExceptionPayload(me));
247 }
248
249 return result;
250 }
251 }
252
253 private static ExceptionPayload getExceptionPayload(MuleEvent event)
254 {
255 if (event == null)
256 {
257 return null;
258 }
259
260 final MuleMessage message = event.getMessage();
261 if (message == null)
262 {
263 return null;
264 }
265
266 return message.getExceptionPayload();
267 }
268 }