1
2
3
4
5
6
7
8
9
10
11 package org.mule.construct;
12
13 import java.util.Collections;
14
15 import org.apache.commons.lang.Validate;
16 import org.mule.MessageExchangePattern;
17 import org.mule.RequestContext;
18 import org.mule.api.ExceptionPayload;
19 import org.mule.api.MuleContext;
20 import org.mule.api.MuleEvent;
21 import org.mule.api.MuleException;
22 import org.mule.api.MuleMessage;
23 import org.mule.api.MuleRuntimeException;
24 import org.mule.api.construct.FlowConstructInvalidException;
25 import org.mule.api.endpoint.InboundEndpoint;
26 import org.mule.api.endpoint.OutboundEndpoint;
27 import org.mule.api.lifecycle.InitialisationException;
28 import org.mule.api.processor.MessageProcessor;
29 import org.mule.api.processor.MessageProcessorChainBuilder;
30 import org.mule.api.routing.filter.Filter;
31 import org.mule.api.source.MessageSource;
32 import org.mule.config.i18n.MessageFactory;
33 import org.mule.expression.ExpressionConfig;
34 import org.mule.expression.transformers.ExpressionArgument;
35 import org.mule.expression.transformers.ExpressionTransformer;
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 public class Validator extends AbstractConfigurationPattern
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 @SuppressWarnings("unchecked")
63 public Validator(String name,
64 MuleContext muleContext,
65 MessageSource messageSource,
66 OutboundEndpoint outboundEndpoint,
67 Filter validationFilter,
68 String ackExpression,
69 String nackExpression,
70 String errorExpression)
71 {
72 super(name, muleContext, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
73
74 Validate.notNull(messageSource, "messageSource can't be null");
75 Validate.notNull(outboundEndpoint, "outboundEndpoint can't be null");
76 Validate.notNull(validationFilter, "validationFilter can't be null");
77 Validate.notEmpty(ackExpression, "ackExpression can't be empty");
78 Validate.notEmpty(nackExpression, "nackExpression can't be empty");
79
80 this.messageSource = messageSource;
81 this.outboundEndpoint = outboundEndpoint;
82 this.validationFilter = validationFilter;
83 this.ackExpression = ackExpression;
84 this.nackExpression = nackExpression;
85 this.errorExpression = errorExpression;
86 }
87
88 @Override
89 protected void configureMessageProcessorsBeforeTransformation(MessageProcessorChainBuilder builder)
90 {
91
92 }
93
94 @Override
95 protected void configureMessageProcessorsAfterTransformation(MessageProcessorChainBuilder builder)
96 {
97 final ErrorAwareEventReturningMessageProcessor outboundMessageProcessor = new ErrorAwareEventReturningMessageProcessor();
98 outboundMessageProcessor.setListener(outboundEndpoint);
99
100 final ResponseMessageProcessorAdapter ackResponseMessageProcessor = new ResponseMessageProcessorAdapter();
101 ackResponseMessageProcessor.setListener(outboundMessageProcessor);
102 ackResponseMessageProcessor.setProcessor(getExpressionTransformer(getName() + "-ack-expression",
103 ackExpression));
104
105 MessageProcessor validRouteMessageProcessor = ackResponseMessageProcessor;
106
107 if (hasErrorExpression())
108 {
109 final ErrorExpressionTransformerMessageProcessor errorResponseMessageProcessor = new ErrorExpressionTransformerMessageProcessor(
110 getExpressionTransformer(getName() + "-error-expression", errorExpression));
111 errorResponseMessageProcessor.setListener(ackResponseMessageProcessor);
112 validRouteMessageProcessor = errorResponseMessageProcessor;
113 }
114
115
116 final ChoiceRouter choiceRouter = new ChoiceRouter();
117 choiceRouter.addRoute(validRouteMessageProcessor, validationFilter);
118 choiceRouter.setDefaultRoute(getExpressionTransformer(getName() + "-nack-expression", nackExpression));
119 builder.chain(choiceRouter);
120 }
121
122 @Override
123 protected void validateConstruct() throws FlowConstructInvalidException
124 {
125 super.validateConstruct();
126
127 validateMessageSource();
128 validateOutboundEndpoint();
129 validateExpression(ackExpression);
130 validateExpression(nackExpression);
131
132 if (hasErrorExpression())
133 {
134 validateExpression(errorExpression);
135 }
136 }
137
138 private void validateMessageSource() throws FlowConstructInvalidException
139 {
140 if ((messageSource instanceof InboundEndpoint)
141 && (!((InboundEndpoint) messageSource).getExchangePattern().equals(
142 MessageExchangePattern.REQUEST_RESPONSE)))
143 {
144 throw new FlowConstructInvalidException(
145 MessageFactory.createStaticMessage("Validator only works with a request-response inbound endpoint."),
146 this);
147 }
148 }
149
150 private void validateOutboundEndpoint() throws FlowConstructInvalidException
151 {
152 if ((hasErrorExpression())
153 && (!outboundEndpoint.getExchangePattern().equals(MessageExchangePattern.REQUEST_RESPONSE)))
154 {
155 throw new FlowConstructInvalidException(
156 MessageFactory.createStaticMessage("Validator with an error expression only works with a request-response outbound endpoint."),
157 this);
158 }
159 }
160
161 protected boolean hasErrorExpression()
162 {
163 return StringUtils.isNotBlank(errorExpression);
164 }
165
166 private void validateExpression(String expression) throws FlowConstructInvalidException
167 {
168 if (!muleContext.getExpressionManager().isExpression(expression))
169 {
170 throw new FlowConstructInvalidException(
171 MessageFactory.createStaticMessage("Invalid expression in Validator: " + expression), this);
172 }
173 }
174
175 private ExpressionTransformer getExpressionTransformer(String name, String expression)
176 {
177 final ExpressionConfig expressionConfig = new ExpressionConfig();
178 expressionConfig.parse(expression);
179
180 final ExpressionArgument expressionArgument = new ExpressionArgument(name, expressionConfig, false);
181 expressionArgument.setMuleContext(muleContext);
182
183 final ExpressionTransformer expressionTransformer = new ExpressionTransformer();
184 expressionTransformer.setMuleContext(muleContext);
185 expressionTransformer.addArgument(expressionArgument);
186
187 try
188 {
189 expressionTransformer.initialise();
190 }
191 catch (final InitialisationException ie)
192 {
193 throw new MuleRuntimeException(ie);
194 }
195
196 return expressionTransformer;
197 }
198
199 private static class ErrorExpressionTransformerMessageProcessor extends
200 AbstractInterceptingMessageProcessor
201 {
202 private final ExpressionTransformer errorExpressionTransformer;
203
204 public ErrorExpressionTransformerMessageProcessor(ExpressionTransformer errorExpressionTransformer)
205 {
206 this.errorExpressionTransformer = errorExpressionTransformer;
207 }
208
209 public MuleEvent process(MuleEvent event) throws MuleException
210 {
211 final MuleEvent nextResult = super.processNext(event);
212
213 final ExceptionPayload nextResultMessageExceptionPayload = getExceptionPayload(nextResult);
214
215 if (nextResultMessageExceptionPayload != null)
216 {
217 return errorExpressionTransformer.process(event);
218 }
219
220 return nextResult;
221 }
222 }
223
224 private static class ErrorAwareEventReturningMessageProcessor extends
225 AbstractInterceptingMessageProcessor
226 {
227
228
229
230
231 public MuleEvent process(MuleEvent event) throws MuleException
232 {
233 final MuleEvent result = RequestContext.setEvent(event);
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 }