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