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: 751373 $
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<ProcessorDefinition> getOutputs() {
199 return outputs;
200 }
201
202 public void setOutputs(List<ProcessorDefinition> outputs) {
203 this.outputs = outputs;
204 }
205
206 public BatchResequencerConfig getBatchConfig() {
207 return batchConfig;
208 }
209
210 public BatchResequencerConfig getBatchConfig(BatchResequencerConfig defaultConfig) {
211 return batchConfig;
212 }
213
214 public StreamResequencerConfig getStreamConfig() {
215 return streamConfig;
216 }
217
218 @XmlElement(name = "batch-config", required = false)
219 public void setBatchConfig(BatchResequencerConfig batchConfig) {
220 batch(batchConfig);
221 }
222
223 @XmlElement(name = "stream-config", required = false)
224 public void setStreamConfig(StreamResequencerConfig streamConfig) {
225 stream(streamConfig);
226 }
227
228 @Override
229 public Processor createProcessor(RouteContext routeContext) throws Exception {
230 if (batchConfig != null) {
231 return createBatchResequencer(routeContext, batchConfig);
232 } else {
233 // streamConfig should be non-null if batchConfig is null
234 return createStreamResequencer(routeContext, streamConfig);
235 }
236 }
237
238 /**
239 * Creates a batch {@link Resequencer} instance applying the given
240 * <code>config</code>.
241 *
242 * @param routeContext route context.
243 * @param config batch resequencer configuration.
244 * @return the configured batch resequencer.
245 * @throws Exception can be thrown
246 */
247 protected Resequencer createBatchResequencer(RouteContext routeContext,
248 BatchResequencerConfig config) throws Exception {
249 Processor processor = routeContext.createProcessor(this);
250 Resequencer resequencer = new Resequencer(processor, resolveExpressionList(routeContext));
251 resequencer.setBatchSize(config.getBatchSize());
252 resequencer.setBatchTimeout(config.getBatchTimeout());
253 return resequencer;
254 }
255
256 /**
257 * Creates a {@link StreamResequencer} instance applying the given
258 * <code>config</code>.
259 *
260 * @param routeContext route context.
261 * @param config stream resequencer configuration.
262 * @return the configured stream resequencer.
263 * @throws Exception can be thrwon
264 */
265 protected StreamResequencer createStreamResequencer(RouteContext routeContext,
266 StreamResequencerConfig config) throws Exception {
267 config.getComparator().setExpressions(resolveExpressionList(routeContext));
268 Processor processor = routeContext.createProcessor(this);
269 StreamResequencer resequencer = new StreamResequencer(processor, config.getComparator());
270 resequencer.setTimeout(config.getTimeout());
271 resequencer.setCapacity(config.getCapacity());
272 return resequencer;
273
274 }
275
276 private List<Expression> resolveExpressionList(RouteContext routeContext) {
277 if (expressionList == null) {
278 expressionList = new ArrayList<Expression>();
279 for (ExpressionDefinition expression : expressions) {
280 expressionList.add(expression.createExpression(routeContext));
281 }
282 }
283 if (expressionList.isEmpty()) {
284 throw new IllegalArgumentException("No expressions configured for: " + this);
285 }
286 return expressionList;
287 }
288 }