001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.model;
018
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import javax.xml.bind.annotation.XmlAccessType;
023 import javax.xml.bind.annotation.XmlAccessorType;
024 import javax.xml.bind.annotation.XmlAttribute;
025 import javax.xml.bind.annotation.XmlElement;
026 import javax.xml.bind.annotation.XmlElementRef;
027 import javax.xml.bind.annotation.XmlRootElement;
028 import javax.xml.bind.annotation.XmlTransient;
029
030 import org.apache.camel.Expression;
031 import org.apache.camel.Predicate;
032 import org.apache.camel.Processor;
033 import org.apache.camel.builder.ExpressionClause;
034 import org.apache.camel.model.language.ExpressionDefinition;
035 import org.apache.camel.processor.Aggregator;
036 import org.apache.camel.processor.aggregate.AggregationCollection;
037 import org.apache.camel.processor.aggregate.AggregationStrategy;
038 import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy;
039 import org.apache.camel.spi.RouteContext;
040
041 /**
042 * Represents an XML <aggregate/> element
043 *
044 * @version $Revision: 751373 $
045 */
046 @XmlRootElement(name = "aggregate")
047 @XmlAccessorType(XmlAccessType.FIELD)
048 public class AggregateDefinition extends ProcessorDefinition<AggregateDefinition> {
049 @XmlElement(name = "correlationExpression", required = false)
050 private ExpressionSubElementDefinition correlationExpression;
051 @XmlTransient
052 private ExpressionDefinition expression;
053 @XmlElementRef
054 private List<ProcessorDefinition> outputs = new ArrayList<ProcessorDefinition>();
055 @XmlTransient
056 private AggregationStrategy aggregationStrategy;
057 @XmlTransient
058 private AggregationCollection aggregationCollection;
059 @XmlAttribute(required = false)
060 private Integer batchSize;
061 @XmlAttribute(required = false)
062 private Integer outBatchSize;
063 @XmlAttribute(required = false)
064 private Long batchTimeout;
065 @XmlAttribute(required = false)
066 private String strategyRef;
067 @XmlAttribute(required = false)
068 private String collectionRef;
069 @XmlAttribute(required = false)
070 private Boolean groupExchanges;
071 @XmlElement(name = "completionPredicate", required = false)
072 private ExpressionSubElementDefinition completionPredicate;
073
074 public AggregateDefinition() {
075 }
076
077 public AggregateDefinition(Predicate predicate) {
078 if (predicate != null) {
079 setExpression(new ExpressionDefinition(predicate));
080 }
081 }
082
083 public AggregateDefinition(Expression correlationExpression) {
084 if (correlationExpression != null) {
085 setExpression(new ExpressionDefinition(correlationExpression));
086 }
087 }
088
089 public AggregateDefinition(ExpressionDefinition correlationExpression) {
090 this.expression = correlationExpression;
091 }
092
093 public AggregateDefinition(Expression correlationExpression, AggregationStrategy aggregationStrategy) {
094 this(correlationExpression);
095 this.aggregationStrategy = aggregationStrategy;
096 }
097
098 @Override
099 public String toString() {
100 String expressionString = (getExpression() != null) ? getExpression().getLabel() : "";
101 return "Aggregate[" + expressionString + " -> " + getOutputs() + "]";
102 }
103
104 @Override
105 public String getShortName() {
106 return "aggregate";
107 }
108
109 @Override
110 public Processor createProcessor(RouteContext routeContext) throws Exception {
111 return createAggregator(routeContext);
112 }
113
114 public ExpressionClause<AggregateDefinition> createAndSetExpression() {
115 ExpressionClause<AggregateDefinition> clause = new ExpressionClause<AggregateDefinition>(this);
116 this.setExpression(clause);
117 return clause;
118 }
119
120 protected Aggregator createAggregator(RouteContext routeContext) throws Exception {
121 final Processor processor = routeContext.createProcessor(this);
122
123 final Aggregator aggregator;
124 if (getAggregationCollection() == null) {
125 setAggregationCollection(createAggregationCollection(routeContext));
126 }
127
128 if (aggregationCollection != null) {
129 // create the aggregator using the collection
130 // pre configure the collection if its expression and strategy is not set, then
131 // use the ones that is pre configured with this type
132 if (aggregationCollection.getCorrelationExpression() == null) {
133 aggregationCollection.setCorrelationExpression(getExpression());
134 }
135 if (aggregationCollection.getAggregationStrategy() == null) {
136 AggregationStrategy strategy = createAggregationStrategy(routeContext);
137 aggregationCollection.setAggregationStrategy(strategy);
138 }
139 aggregator = new Aggregator(processor, aggregationCollection);
140 } else {
141 // create the aggregator using a default collection
142 AggregationStrategy strategy = createAggregationStrategy(routeContext);
143
144 if (getExpression() == null) {
145 throw new IllegalArgumentException("You need to specify an expression or "
146 + "aggregation collection for this aggregator: " + this);
147 }
148
149 Expression aggregateExpression = getExpression().createExpression(routeContext);
150
151 Predicate predicate = null;
152 if (getCompletionPredicate() != null) {
153 predicate = getCompletionPredicate().createPredicate(routeContext);
154 }
155 if (predicate != null) {
156 aggregator = new Aggregator(processor, aggregateExpression, strategy, predicate);
157 } else {
158 aggregator = new Aggregator(processor, aggregateExpression, strategy);
159 }
160 }
161
162 if (batchSize != null) {
163 aggregator.setBatchSize(batchSize);
164 }
165
166 if (batchTimeout != null) {
167 aggregator.setBatchTimeout(batchTimeout);
168 }
169
170 if (outBatchSize != null) {
171 aggregator.setOutBatchSize(outBatchSize);
172 }
173
174 if (groupExchanges != null) {
175 aggregator.setGroupExchanges(groupExchanges);
176 }
177
178 return aggregator;
179 }
180
181 private AggregationStrategy createAggregationStrategy(RouteContext routeContext) {
182 AggregationStrategy strategy = getAggregationStrategy();
183 if (strategy == null && strategyRef != null) {
184 strategy = routeContext.lookup(strategyRef, AggregationStrategy.class);
185 }
186 if (strategy == null) {
187 // fallback to use latest
188 strategy = new UseLatestAggregationStrategy();
189 }
190 return strategy;
191 }
192
193 private AggregationCollection createAggregationCollection(RouteContext routeContext) {
194 AggregationCollection collection = getAggregationCollection();
195 if (collection == null && collectionRef != null) {
196 collection = routeContext.lookup(collectionRef, AggregationCollection.class);
197 }
198 return collection;
199 }
200
201 public AggregationCollection getAggregationCollection() {
202 return aggregationCollection;
203 }
204
205 public void setAggregationCollection(AggregationCollection aggregationCollection) {
206 this.aggregationCollection = aggregationCollection;
207 }
208
209 public AggregationStrategy getAggregationStrategy() {
210 return aggregationStrategy;
211 }
212
213 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) {
214 this.aggregationStrategy = aggregationStrategy;
215 }
216
217 public Integer getBatchSize() {
218 return batchSize;
219 }
220
221 public void setBatchSize(Integer batchSize) {
222 this.batchSize = batchSize;
223 }
224
225 public Integer getOutBatchSize() {
226 return outBatchSize;
227 }
228
229 public void setOutBatchSize(Integer outBatchSize) {
230 this.outBatchSize = outBatchSize;
231 }
232
233 public Long getBatchTimeout() {
234 return batchTimeout;
235 }
236
237 public void setBatchTimeout(Long batchTimeout) {
238 this.batchTimeout = batchTimeout;
239 }
240
241 public String getStrategyRef() {
242 return strategyRef;
243 }
244
245 public void setStrategyRef(String strategyRef) {
246 this.strategyRef = strategyRef;
247 }
248
249 public String getCollectionRef() {
250 return collectionRef;
251 }
252
253 public void setCollectionRef(String collectionRef) {
254 this.collectionRef = collectionRef;
255 }
256
257 public void setCompletionPredicate(ExpressionSubElementDefinition completionPredicate) {
258 this.completionPredicate = completionPredicate;
259 }
260
261 public ExpressionSubElementDefinition getCompletionPredicate() {
262 return completionPredicate;
263 }
264
265 public Boolean getGroupExchanges() {
266 return groupExchanges;
267 }
268
269 public void setGroupExchanges(Boolean groupExchanges) {
270 this.groupExchanges = groupExchanges;
271 }
272
273 // Fluent API
274 //-------------------------------------------------------------------------
275
276 /**
277 * Sets the in batch size for number of exchanges received
278 *
279 * @param batchSize the batch size
280 * @return builder
281 */
282 public AggregateDefinition batchSize(int batchSize) {
283 setBatchSize(batchSize);
284 return this;
285 }
286
287 /**
288 * Sets the out batch size for number of exchanges sent
289 *
290 * @param batchSize the batch size
291 * @return builder
292 */
293 public AggregateDefinition outBatchSize(int batchSize) {
294 setOutBatchSize(batchSize);
295 return this;
296 }
297
298 /**
299 * Sets the batch timeout
300 *
301 * @param batchTimeout the timeout in millis
302 * @return the builder
303 */
304 public AggregateDefinition batchTimeout(long batchTimeout) {
305 setBatchTimeout(batchTimeout);
306 return this;
307 }
308
309 /**
310 * Sets the aggregate collection to use
311 *
312 * @param aggregationCollection the aggregate collection to use
313 * @return the builder
314 */
315 public AggregateDefinition aggregationCollection(AggregationCollection aggregationCollection) {
316 setAggregationCollection(aggregationCollection);
317 return this;
318 }
319
320 /**
321 * Sets the aggregate strategy to use
322 *
323 * @param aggregationStrategy the aggregate strategy to use
324 * @return the builder
325 */
326 public AggregateDefinition aggregationStrategy(AggregationStrategy aggregationStrategy) {
327 setAggregationStrategy(aggregationStrategy);
328 return this;
329 }
330
331 /**
332 * Sets the aggregate collection to use
333 *
334 * @param collectionRef reference to the aggregate collection to lookup in the registry
335 * @return the builder
336 */
337 public AggregateDefinition collectionRef(String collectionRef) {
338 setCollectionRef(collectionRef);
339 return this;
340 }
341
342 /**
343 * Sets the aggregate strategy to use
344 *
345 * @param strategyRef reference to the strategy to lookup in the registry
346 * @return the builder
347 */
348 public AggregateDefinition strategyRef(String strategyRef) {
349 setStrategyRef(strategyRef);
350 return this;
351 }
352
353 /**
354 * Enables grouped exchanges, so the aggregator will group all aggregated exchanges into a single
355 * combined {@link org.apache.camel.impl.GroupedExchange} class holding all the aggregated exchanges.
356 *
357 * @return the builder
358 */
359 public AggregateDefinition groupExchanges() {
360 setGroupExchanges(true);
361 return this;
362 }
363
364 /**
365 * Sets the predicate used to determine if the aggregation is completed
366 *
367 * @return the clause used to create the predicate
368 */
369 public ExpressionClause<AggregateDefinition> completionPredicate() {
370 checkNoCompletedPredicate();
371 ExpressionClause<AggregateDefinition> clause = new ExpressionClause<AggregateDefinition>(this);
372 setCompletionPredicate(new ExpressionSubElementDefinition((Expression)clause));
373 return clause;
374 }
375
376 /**
377 * Sets the predicate used to determine if the aggregation is completed
378 *
379 * @param predicate the predicate
380 */
381 public AggregateDefinition completionPredicate(Predicate predicate) {
382 checkNoCompletedPredicate();
383 setCompletionPredicate(new ExpressionSubElementDefinition(predicate));
384 return this;
385 }
386
387 protected void checkNoCompletedPredicate() {
388 if (getCompletionPredicate() != null) {
389 throw new IllegalArgumentException("There is already a completionPredicate defined for this aggregator: " + this);
390 }
391 }
392
393 public void setCorrelationExpression(ExpressionSubElementDefinition correlationExpression) {
394 this.correlationExpression = correlationExpression;
395 }
396
397 public ExpressionSubElementDefinition getCorrelationExpression() {
398 return correlationExpression;
399 }
400
401 // Section - Methods from ExpressionNode
402 // Needed to copy methods from ExpressionNode here so that I could specify the
403 // correlation expression as optional in JAXB
404
405 public ExpressionDefinition getExpression() {
406 if (expression == null && correlationExpression != null) {
407 expression = correlationExpression.getExpressionType();
408 }
409 return expression;
410 }
411
412 public void setExpression(ExpressionDefinition expression) {
413 this.expression = expression;
414 }
415
416 public List<ProcessorDefinition> getOutputs() {
417 return outputs;
418 }
419
420 public void setOutputs(List<ProcessorDefinition> outputs) {
421 this.outputs = outputs;
422 }
423
424 @Override
425 protected void configureChild(ProcessorDefinition output) {
426 super.configureChild(output);
427 if (isInheritErrorHandler()) {
428 output.setErrorHandlerBuilder(getErrorHandlerBuilder());
429 }
430 }
431 }