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 }