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