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.concurrent.Executor;
020 import java.util.concurrent.LinkedBlockingQueue;
021 import java.util.concurrent.ThreadPoolExecutor;
022 import java.util.concurrent.TimeUnit;
023
024 import javax.xml.bind.annotation.XmlAccessType;
025 import javax.xml.bind.annotation.XmlAccessorType;
026 import javax.xml.bind.annotation.XmlAttribute;
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.Processor;
032 import org.apache.camel.builder.ExpressionClause;
033 import org.apache.camel.model.language.ExpressionDefinition;
034 import org.apache.camel.processor.Splitter;
035 import org.apache.camel.processor.aggregate.AggregationStrategy;
036 import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy;
037 import org.apache.camel.spi.RouteContext;
038
039 /**
040 * Represents an XML <split/> element
041 *
042 * @version $Revision: 751373 $
043 */
044 @XmlRootElement(name = "split")
045 @XmlAccessorType(XmlAccessType.FIELD)
046 public class SplitDefinition extends ExpressionNode {
047 @XmlTransient
048 private AggregationStrategy aggregationStrategy;
049 @XmlAttribute(required = false)
050 private Boolean parallelProcessing;
051 @XmlTransient
052 private Executor executor;
053 @XmlAttribute(required = false)
054 private String strategyRef;
055 @XmlAttribute(required = false)
056 private String threadPoolExecutorRef;
057 @XmlAttribute(required = false)
058 private Boolean streaming = false;
059
060 public SplitDefinition() {
061 }
062
063 public SplitDefinition(Expression expression) {
064 super(expression);
065 }
066
067 public SplitDefinition(ExpressionDefinition expression) {
068 super(expression);
069 }
070
071 @Override
072 public String toString() {
073 return "Split[" + getExpression() + " -> " + getOutputs() + "]";
074 }
075
076 @Override
077 public String getShortName() {
078 return "split";
079 }
080
081 @Override
082 public Processor createProcessor(RouteContext routeContext) throws Exception {
083 Processor childProcessor = routeContext.createProcessor(this);
084 aggregationStrategy = createAggregationStrategy(routeContext);
085 executor = createThreadPoolExecutor(routeContext);
086 return new Splitter(getExpression().createExpression(routeContext), childProcessor, aggregationStrategy,
087 isParallelProcessing(), executor, streaming);
088 }
089
090
091 private AggregationStrategy createAggregationStrategy(RouteContext routeContext) {
092 AggregationStrategy strategy = getAggregationStrategy();
093 if (strategy == null && strategyRef != null) {
094 strategy = routeContext.lookup(strategyRef, AggregationStrategy.class);
095 }
096 if (strategy == null) {
097 // fallback to use latest
098 strategy = new UseLatestAggregationStrategy();
099 }
100 return strategy;
101 }
102
103 private Executor createThreadPoolExecutor(RouteContext routeContext) {
104 Executor executor = getExecutor();
105 if (executor == null && threadPoolExecutorRef != null) {
106 executor = routeContext.lookup(threadPoolExecutorRef, ThreadPoolExecutor.class);
107 }
108 if (executor == null) {
109 // fall back and use default
110 executor = new ThreadPoolExecutor(4, 16, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
111 }
112 return executor;
113 }
114
115 // Fluent API
116 // -------------------------------------------------------------------------
117
118 /**
119 * Set the expression that the splitter will use
120 *
121 * @return the builder
122 */
123 public ExpressionClause<SplitDefinition> expression() {
124 return ExpressionClause.createAndSetExpression(this);
125 }
126 /**
127 * Set the aggregationStrategy
128 *
129 * @return the builder
130 */
131 public SplitDefinition aggregationStrategy(AggregationStrategy aggregationStrategy) {
132 setAggregationStrategy(aggregationStrategy);
133 return this;
134 }
135
136 /**
137 * Doing the splitting work in parallel
138 *
139 * @return the builder
140 */
141 public SplitDefinition parallelProcessing() {
142 setParallelProcessing(true);
143 return this;
144 }
145
146 /**
147 * Set the splitting action's thread model
148 *
149 * @param parallelProcessing <tt>true</tt> to use a thread pool, if <tt>false</tt> then work is done in the
150 * calling thread.
151 *
152 * @return the builder
153 */
154 public SplitDefinition parallelProcessing(boolean parallelProcessing) {
155 setParallelProcessing(parallelProcessing);
156 return this;
157 }
158
159 /**
160 * Enables streaming.
161 * See {@link SplitDefinition#setStreaming(boolean)} for more information
162 *
163 * @return the builder
164 */
165 public SplitDefinition streaming() {
166 setStreaming(true);
167 return this;
168 }
169
170 /**
171 * Setting the executor for executing the splitting action.
172 *
173 * @param executor the executor
174 * @return the builder
175 */
176 public SplitDefinition executor(Executor executor) {
177 setExecutor(executor);
178 return this;
179 }
180
181 public AggregationStrategy getAggregationStrategy() {
182 return aggregationStrategy;
183 }
184
185 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) {
186 this.aggregationStrategy = aggregationStrategy;
187 }
188
189 public boolean isParallelProcessing() {
190 return parallelProcessing != null ? parallelProcessing : false;
191 }
192
193 public void setParallelProcessing(boolean parallelProcessing) {
194 this.parallelProcessing = parallelProcessing;
195 }
196
197 /**
198 * The splitter should use streaming -- exchanges are being sent as the data for them becomes available.
199 * This improves throughput and memory usage, but it has a drawback:
200 * - the sent exchanges will no longer contain the {@link Splitter#SPLIT_SIZE} header property
201 *
202 * @return whether or not streaming should be used
203 */
204 public boolean isStreaming() {
205 return streaming != null ? streaming : false;
206 }
207
208 public void setStreaming(boolean streaming) {
209 this.streaming = streaming;
210 }
211
212 public Executor getExecutor() {
213 return executor;
214 }
215
216 public void setExecutor(Executor executor) {
217 this.executor = executor;
218 }
219 }