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.processor.aggregate;
018
019 import java.util.AbstractCollection;
020 import java.util.Iterator;
021 import java.util.LinkedHashMap;
022 import java.util.Map;
023 import java.util.concurrent.atomic.AtomicInteger;
024
025 import org.apache.camel.Exchange;
026 import org.apache.camel.Expression;
027 import org.apache.camel.util.ExchangeHelper;
028 import org.apache.camel.util.ObjectHelper;
029 import org.apache.commons.logging.Log;
030 import org.apache.commons.logging.LogFactory;
031
032 /**
033 * A {@link java.util.Collection} which aggregates exchanges together using a correlation
034 * expression so that there is only a single message exchange sent for a single
035 * correlation key.
036 *
037 * @version $Revision: 890339 $
038 */
039 public class DefaultAggregationCollection extends AbstractCollection<Exchange> implements AggregationCollection {
040
041 private static final transient Log LOG = LogFactory.getLog(DefaultAggregationCollection.class);
042 private Expression correlationExpression;
043 private AggregationStrategy aggregationStrategy;
044 private final Map<Object, Exchange> aggregated = new LinkedHashMap<Object, Exchange>();
045 private final AtomicInteger counter = new AtomicInteger();
046
047 public DefaultAggregationCollection() {
048 }
049
050 public DefaultAggregationCollection(Expression correlationExpression, AggregationStrategy aggregationStrategy) {
051 this.correlationExpression = correlationExpression;
052 this.aggregationStrategy = aggregationStrategy;
053 }
054
055 protected Map<Object, Exchange> getAggregated() {
056 return aggregated;
057 }
058
059 @Override
060 public boolean add(Exchange exchange) {
061 Object correlationKey = correlationExpression.evaluate(exchange, Object.class);
062 if (LOG.isTraceEnabled()) {
063 LOG.trace("Evaluated expression: " + correlationExpression + " as correlation key: " + correlationKey);
064 }
065
066 // TODO: correlationKey evaluated to null should be skipped by default
067
068 Exchange oldExchange = aggregated.get(correlationKey);
069 Exchange newExchange = exchange;
070
071 Integer size = 1;
072 if (oldExchange != null) {
073 size = oldExchange.getProperty(Exchange.AGGREGATED_SIZE, Integer.class);
074 ObjectHelper.notNull(size, Exchange.AGGREGATED_SIZE + " on " + oldExchange);
075 size++;
076 }
077
078 // prepare the exchanges for aggregation
079 ExchangeHelper.prepareAggregation(oldExchange, newExchange);
080 newExchange = aggregationStrategy.aggregate(oldExchange, newExchange);
081 newExchange.setProperty(Exchange.AGGREGATED_SIZE, size);
082
083 // update the index counter
084 newExchange.setProperty(Exchange.AGGREGATED_INDEX, counter.getAndIncrement());
085
086 // the strategy may just update the old exchange and return it
087 if (!newExchange.equals(oldExchange)) {
088 if (LOG.isTraceEnabled()) {
089 LOG.trace("Put exchange:" + newExchange + " with correlation key:" + correlationKey);
090 }
091 aggregated.put(correlationKey, newExchange);
092 }
093
094 onAggregation(correlationKey, newExchange);
095
096 return true;
097 }
098
099 public Iterator<Exchange> iterator() {
100 return aggregated.values().iterator();
101 }
102
103 public int size() {
104 return aggregated.size();
105 }
106
107 @Override
108 public void clear() {
109 aggregated.clear();
110 counter.set(0);
111 }
112
113 public void onAggregation(Object correlationKey, Exchange exchange) {
114 }
115
116 public Expression getCorrelationExpression() {
117 return correlationExpression;
118 }
119
120 public void setCorrelationExpression(Expression correlationExpression) {
121 this.correlationExpression = correlationExpression;
122 }
123
124 public AggregationStrategy getAggregationStrategy() {
125 return aggregationStrategy;
126 }
127
128 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) {
129 this.aggregationStrategy = aggregationStrategy;
130 }
131 }