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.ArrayList;
020 import java.util.List;
021
022 import javax.xml.bind.annotation.XmlElement;
023 import javax.xml.bind.annotation.XmlElementRef;
024 import javax.xml.bind.annotation.XmlRootElement;
025 import javax.xml.bind.annotation.XmlTransient;
026
027 import org.apache.camel.Expression;
028 import org.apache.camel.Processor;
029 import org.apache.camel.model.config.BatchResequencerConfig;
030 import org.apache.camel.model.config.StreamResequencerConfig;
031 import org.apache.camel.model.language.ExpressionDefinition;
032 import org.apache.camel.processor.Resequencer;
033 import org.apache.camel.processor.StreamResequencer;
034 import org.apache.camel.processor.resequencer.ExpressionResultComparator;
035 import org.apache.camel.spi.RouteContext;
036
037 /**
038 * Represents an XML <resequence/> element
039 *
040 * @version $Revision: 881198 $
041 */
042 @XmlRootElement(name = "resequence")
043 public class ResequenceDefinition extends ProcessorDefinition<ProcessorDefinition> {
044 @XmlElementRef
045 private List<ExpressionDefinition> expressions = new ArrayList<ExpressionDefinition>();
046 @XmlElementRef
047 private List<ProcessorDefinition> outputs = new ArrayList<ProcessorDefinition>();
048 // Binding annotation at setter
049 private BatchResequencerConfig batchConfig;
050 // Binding annotation at setter
051 private StreamResequencerConfig streamConfig;
052 @XmlTransient
053 private List<Expression> expressionList;
054
055 public ResequenceDefinition() {
056 this(null);
057 }
058
059 public ResequenceDefinition(List<Expression> expressions) {
060 this.expressionList = expressions;
061 this.batch();
062 }
063
064 @Override
065 public String getShortName() {
066 return "resequence";
067 }
068
069 // Fluent API
070 // -------------------------------------------------------------------------
071 /**
072 * Configures the stream-based resequencing algorithm using the default
073 * configuration.
074 *
075 * @return the builder
076 */
077 public ResequenceDefinition stream() {
078 return stream(StreamResequencerConfig.getDefault());
079 }
080
081 /**
082 * Configures the batch-based resequencing algorithm using the default
083 * configuration.
084 *
085 * @return the builder
086 */
087 public ResequenceDefinition batch() {
088 return batch(BatchResequencerConfig.getDefault());
089 }
090
091 /**
092 * Configures the stream-based resequencing algorithm using the given
093 * {@link StreamResequencerConfig}.
094 *
095 * @param config the config
096 * @return the builder
097 */
098 public ResequenceDefinition stream(StreamResequencerConfig config) {
099 this.streamConfig = config;
100 this.batchConfig = null;
101 return this;
102 }
103
104 /**
105 * Configures the batch-based resequencing algorithm using the given
106 * {@link BatchResequencerConfig}.
107 *
108 * @param config the config
109 * @return the builder
110 */
111 public ResequenceDefinition batch(BatchResequencerConfig config) {
112 this.batchConfig = config;
113 this.streamConfig = null;
114 return this;
115 }
116
117 /**
118 * Sets the expression to use for reordering
119 *
120 * @param expression the expression
121 * @return the builder
122 */
123 public ResequenceDefinition expression(ExpressionDefinition expression) {
124 expressions.add(expression);
125 return this;
126 }
127
128 /**
129 * Sets the timeout
130 * @param timeout timeout in millis
131 * @return the builder
132 */
133 public ResequenceDefinition timeout(long timeout) {
134 if (batchConfig != null) {
135 batchConfig.setBatchTimeout(timeout);
136 } else {
137 streamConfig.setTimeout(timeout);
138 }
139 return this;
140 }
141
142 /**
143 * Sets the in batch size for number of exchanges received
144 * @param batchSize the batch size
145 * @return the builder
146 */
147 public ResequenceDefinition size(int batchSize) {
148 if (batchConfig == null) {
149 throw new IllegalStateException("size() only supported for batch resequencer");
150 }
151 batchConfig.setBatchSize(batchSize);
152 return this;
153 }
154
155 /**
156 * Sets the capacity for the stream resequencer
157 *
158 * @param capacity the capacity
159 * @return the builder
160 */
161 public ResequenceDefinition capacity(int capacity) {
162 if (streamConfig == null) {
163 throw new IllegalStateException("capacity() only supported for stream resequencer");
164 }
165 streamConfig.setCapacity(capacity);
166 return this;
167
168 }
169
170 /**
171 * Sets the comparator to use for stream resequencer
172 *
173 * @param comparator the comparator
174 * @return the builder
175 */
176 public ResequenceDefinition comparator(ExpressionResultComparator comparator) {
177 if (streamConfig == null) {
178 throw new IllegalStateException("comparator() only supported for stream resequencer");
179 }
180 streamConfig.setComparator(comparator);
181 return this;
182 }
183
184 @Override
185 public String toString() {
186 return "Resequencer[" + getExpressions() + " -> " + getOutputs() + "]";
187 }
188
189 @Override
190 public String getLabel() {
191 return ExpressionDefinition.getLabel(getExpressions());
192 }
193
194 public List<ExpressionDefinition> getExpressions() {
195 return expressions;
196 }
197
198 public List<Expression> getExpressionList() {
199 return expressionList;
200 }
201
202 public List<ProcessorDefinition> getOutputs() {
203 return outputs;
204 }
205
206 public void setOutputs(List<ProcessorDefinition> outputs) {
207 this.outputs = outputs;
208 }
209
210 public BatchResequencerConfig getBatchConfig() {
211 return batchConfig;
212 }
213
214 public BatchResequencerConfig getBatchConfig(BatchResequencerConfig defaultConfig) {
215 return batchConfig;
216 }
217
218 public StreamResequencerConfig getStreamConfig() {
219 return streamConfig;
220 }
221
222 @XmlElement(name = "batch-config", required = false)
223 public void setBatchConfig(BatchResequencerConfig batchConfig) {
224 batch(batchConfig);
225 }
226
227 @XmlElement(name = "stream-config", required = false)
228 public void setStreamConfig(StreamResequencerConfig streamConfig) {
229 stream(streamConfig);
230 }
231
232 @Override
233 public Processor createProcessor(RouteContext routeContext) throws Exception {
234 if (batchConfig != null) {
235 return createBatchResequencer(routeContext, batchConfig);
236 } else {
237 // streamConfig should be non-null if batchConfig is null
238 return createStreamResequencer(routeContext, streamConfig);
239 }
240 }
241
242 /**
243 * Creates a batch {@link Resequencer} instance applying the given
244 * <code>config</code>.
245 *
246 * @param routeContext route context.
247 * @param config batch resequencer configuration.
248 * @return the configured batch resequencer.
249 * @throws Exception can be thrown
250 */
251 protected Resequencer createBatchResequencer(RouteContext routeContext,
252 BatchResequencerConfig config) throws Exception {
253 Processor processor = routeContext.createProcessor(this);
254 Resequencer resequencer = new Resequencer(processor, resolveExpressionList(routeContext));
255 resequencer.setBatchSize(config.getBatchSize());
256 resequencer.setBatchTimeout(config.getBatchTimeout());
257 return resequencer;
258 }
259
260 /**
261 * Creates a {@link StreamResequencer} instance applying the given
262 * <code>config</code>.
263 *
264 * @param routeContext route context.
265 * @param config stream resequencer configuration.
266 * @return the configured stream resequencer.
267 * @throws Exception can be thrwon
268 */
269 protected StreamResequencer createStreamResequencer(RouteContext routeContext,
270 StreamResequencerConfig config) throws Exception {
271 config.getComparator().setExpressions(resolveExpressionList(routeContext));
272 Processor processor = routeContext.createProcessor(this);
273 StreamResequencer resequencer = new StreamResequencer(processor, config.getComparator());
274 resequencer.setTimeout(config.getTimeout());
275 resequencer.setCapacity(config.getCapacity());
276 return resequencer;
277
278 }
279
280 private List<Expression> resolveExpressionList(RouteContext routeContext) {
281 if (expressionList == null) {
282 expressionList = new ArrayList<Expression>();
283 for (ExpressionDefinition expression : expressions) {
284 expressionList.add(expression.createExpression(routeContext));
285 }
286 }
287 if (expressionList.isEmpty()) {
288 throw new IllegalArgumentException("No expressions configured for: " + this);
289 }
290 return expressionList;
291 }
292 }