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