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 java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.concurrent.ExecutorService;
025    
026    import org.apache.camel.Exchange;
027    import org.apache.camel.Expression;
028    import org.apache.camel.Message;
029    import org.apache.camel.Processor;
030    import org.apache.camel.processor.aggregate.AggregationStrategy;
031    import org.apache.camel.util.CollectionHelper;
032    import org.apache.camel.util.ObjectHelper;
033    
034    import static org.apache.camel.util.ObjectHelper.notNull;
035    
036    /**
037     * Implements a dynamic <a
038     * href="http://camel.apache.org/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: 788621 $
043     */
044    public class Splitter extends MulticastProcessor implements Processor, Traceable {
045        private final Expression expression;
046    
047        public Splitter(Expression expression, Processor destination, AggregationStrategy aggregationStrategy) {
048            this(expression, destination, aggregationStrategy, false, null, false);
049        }
050    
051        public Splitter(Expression expression, Processor destination, AggregationStrategy aggregationStrategy,
052                        boolean parallelProcessing, ExecutorService executorService, boolean streaming) {
053            super(Collections.singleton(destination), aggregationStrategy, parallelProcessing, executorService, streaming);
054    
055            this.expression = expression;
056            notNull(expression, "expression");
057            notNull(destination, "destination");
058        }
059    
060        @Override
061        public String toString() {
062            return "Splitter[on: " + expression + " to: " + getProcessors().iterator().next() + " aggregate: " + getAggregationStrategy() + "]";
063        }
064    
065        @Override
066        public String getTraceLabel() {
067            return "Split[" + expression + "]";
068        }
069    
070        @Override
071        protected Iterable<ProcessorExchangePair> createProcessorExchangePairs(Exchange exchange) {
072            Object value = expression.evaluate(exchange, Object.class);
073    
074            if (isStreaming()) {
075                return createProcessorExchangePairsIterable(exchange, value);
076            } else {
077                return createProcessorExchangePairsList(exchange, value);
078            }
079        }
080    
081        @SuppressWarnings("unchecked")
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                            if (part instanceof Message) {
097                                newExchange.setIn((Message)part);
098                            } else {
099                                Message in = newExchange.getIn();
100                                in.setBody(part);
101                            }
102                            return new ProcessorExchangePair(getProcessors().iterator().next(), newExchange);
103                        }
104    
105                        public void remove() {
106                            throw new UnsupportedOperationException("Remove is not supported by this iterator");
107                        }
108                    };
109                }
110    
111            };
112        }
113    
114        private Iterable<ProcessorExchangePair> createProcessorExchangePairsList(Exchange exchange, Object value) {
115            List<ProcessorExchangePair> result;
116            Integer collectionSize = CollectionHelper.size(value);
117            if (collectionSize != null) {
118                result = new ArrayList<ProcessorExchangePair>(collectionSize);
119            } else {
120                result = new ArrayList<ProcessorExchangePair>();
121            }
122            Iterator iter = ObjectHelper.createIterator(value);
123            while (iter.hasNext()) {
124                Object part = iter.next();
125                Exchange newExchange = exchange.copy();
126                if (part instanceof Message) {
127                    newExchange.setIn((Message)part);
128                } else {
129                    Message in = newExchange.getIn();
130                    in.setBody(part);
131                }
132                result.add(new ProcessorExchangePair(getProcessors().iterator().next(), newExchange));
133            }
134            return result;
135        }
136    
137        @Override
138        protected void updateNewExchange(Exchange exchange, int index, Iterable<ProcessorExchangePair> allPairs) {
139            super.updateNewExchange(exchange, index, allPairs);
140            exchange.setProperty(Exchange.SPLIT_INDEX, index);
141            if (allPairs instanceof Collection) {
142                exchange.setProperty(Exchange.SPLIT_SIZE, ((Collection) allPairs).size());
143            }
144        }
145    
146        public Expression getExpression() {
147            return expression;
148        }
149    }