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;
018    
019    import static org.apache.camel.util.ObjectHelper.notNull;
020    
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Collections;
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.concurrent.ThreadPoolExecutor;
027    
028    import org.apache.camel.Exchange;
029    import org.apache.camel.Expression;
030    import org.apache.camel.Message;
031    import org.apache.camel.Processor;
032    import org.apache.camel.processor.aggregate.AggregationStrategy;
033    import org.apache.camel.util.CollectionHelper;
034    import org.apache.camel.util.ObjectHelper;
035    
036    /**
037     * Implements a dynamic <a
038     * href="http://activemq.apache.org/camel/splitter.html">Splitter</a> pattern
039     * where an expression is evaluated to iterate through each of the parts of a
040     * message and then each part is then send to some endpoint.
041     *
042     * @version $Revision: 51106 $
043     */
044    public class Splitter extends MulticastProcessor implements Processor {
045        public static final String SPLIT_SIZE = "org.apache.camel.splitSize";
046        public static final String SPLIT_COUNTER = "org.apache.camel.splitCounter";
047    
048        private final Expression expression;
049        private final boolean streaming;
050    
051        public Splitter(Expression expression, Processor destination, AggregationStrategy aggregationStrategy) {
052            this(expression, destination, aggregationStrategy, false, null, false);
053        }
054    
055        public Splitter(Expression expression, Processor destination,
056                AggregationStrategy aggregationStrategy,
057                boolean parallelProcessing, ThreadPoolExecutor threadPoolExecutor, boolean streaming) {
058            super(Collections.singleton(destination), aggregationStrategy, parallelProcessing, threadPoolExecutor);
059    
060            this.expression = expression;
061            this.streaming = streaming;
062            notNull(expression, "expression");
063            notNull(destination, "destination");
064        }
065    
066        @Override
067        public String toString() {
068            return "Splitter[on: " + expression + " to: " + getProcessors().iterator().next() + " aggregate: " + getAggregationStrategy() + "]";
069        }
070    
071        @Override
072        protected Iterable<ProcessorExchangePair> createProcessorExchangePairs(Exchange exchange) {
073            Object value = expression.evaluate(exchange);
074            
075            if (streaming) {
076                return createProcessorExchangePairsIterable(exchange, value);
077            } else {
078                return createProcessorExchangePairsList(exchange, value);
079            }
080        }
081    
082        private Iterable<ProcessorExchangePair> createProcessorExchangePairsIterable(final Exchange exchange, Object value) {
083            final Iterator iterator = ObjectHelper.createIterator(value);
084            return new Iterable() {
085    
086                public Iterator iterator() {
087                    return new Iterator() {
088    
089                        public boolean hasNext() {
090                            return iterator.hasNext();
091                        }
092    
093                        public Object next() {
094                            Object part = iterator.next();
095                            Exchange newExchange = exchange.copy();
096                            Message in = newExchange.getIn();
097                            in.setBody(part);
098                            return new ProcessorExchangePair(getProcessors().iterator().next(), newExchange);
099                        }
100    
101                        public void remove() {
102                            throw new UnsupportedOperationException("remove is not supported by this iterator");
103                        }
104                    };
105                }
106                
107            };
108        }
109    
110        private Iterable<ProcessorExchangePair> createProcessorExchangePairsList(Exchange exchange, Object value) {
111            List<ProcessorExchangePair> result;
112            Integer collectionSize = CollectionHelper.size(value);
113            if (collectionSize != null) {
114                result = new ArrayList<ProcessorExchangePair>(collectionSize);
115            } else {
116                result = new ArrayList<ProcessorExchangePair>();
117            }
118            Iterator<Object> iter = ObjectHelper.createIterator(value);
119            while (iter.hasNext()) {
120                Object part = iter.next();
121                Exchange newExchange = exchange.copy();
122                Message in = newExchange.getIn();
123                in.setBody(part);
124                result.add(new ProcessorExchangePair(getProcessors().iterator().next(), newExchange));
125            }
126            return result;
127        }
128    
129        @Override
130        protected void updateNewExchange(Exchange exchange, int i, Iterable<ProcessorExchangePair> allPairs) {
131            exchange.getIn().setHeader(SPLIT_COUNTER, i);
132            if (allPairs instanceof Collection) {
133                exchange.getIn().setHeader(SPLIT_SIZE, ((Collection) allPairs).size());
134            }
135        }
136    }