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.processor; 018 019 import java.util.concurrent.BlockingQueue; 020 import java.util.concurrent.LinkedBlockingQueue; 021 022 import org.apache.camel.Exchange; 023 import org.apache.camel.Processor; 024 import org.apache.camel.processor.resequencer.ResequencerEngine; 025 import org.apache.camel.processor.resequencer.SequenceElementComparator; 026 import org.apache.camel.processor.resequencer.SequenceSender; 027 028 /** 029 * A resequencer that re-orders a (continuous) stream of {@link Exchange}s. The 030 * algorithm implemented by {@link ResequencerEngine} is based on the detection 031 * of gaps in a message stream rather than on a fixed batch size. Gap detection 032 * in combination with timeouts removes the constraint of having to know the 033 * number of messages of a sequence (i.e. the batch size) in advance. 034 * <p> 035 * Messages must contain a unique sequence number for which a predecessor and a 036 * successor is known. For example a message with the sequence number 3 has a 037 * predecessor message with the sequence number 2 and a successor message with 038 * the sequence number 4. The message sequence 2,3,5 has a gap because the 039 * sucessor of 3 is missing. The resequencer therefore has to retain message 5 040 * until message 4 arrives (or a timeout occurs). 041 * 042 * @author Martin Krasser 043 * 044 * @version $Revision: 35332 $ 045 */ 046 public class StreamResequencer extends DelegateProcessor implements Processor { 047 048 private ResequencerEngine<Exchange> reseq; 049 private BlockingQueue<Exchange> queue; 050 private SequenceSender sender; 051 052 /** 053 * Creates a new {@link StreamResequencer} instance. 054 * 055 * @param processor 056 * the next processor that processes the re-ordered exchanges. 057 * @param comparator 058 * a {@link SequenceElementComparator} for comparing sequence 059 * number contained in {@link Exchange}s. 060 * @param capacity 061 * the capacity of the inbound queue. 062 */ 063 public StreamResequencer(Processor processor, SequenceElementComparator<Exchange> comparator, int capacity) { 064 super(processor); 065 queue = new LinkedBlockingQueue<Exchange>(); 066 reseq = new ResequencerEngine<Exchange>(comparator, capacity); 067 reseq.setOutQueue(queue); 068 } 069 070 @Override 071 protected void doStart() throws Exception { 072 super.doStart(); 073 sender = new SequenceSender(getProcessor()); 074 sender.setQueue(queue); 075 sender.start(); 076 077 } 078 079 @Override 080 protected void doStop() throws Exception { 081 reseq.stop(); 082 sender.cancel(); 083 super.doStop(); 084 } 085 086 @Override 087 public void process(Exchange exchange) throws Exception { 088 reseq.put(exchange); 089 } 090 091 public long getTimeout() { 092 return reseq.getTimeout(); 093 } 094 095 public void setTimeout(long timeout) { 096 reseq.setTimeout(timeout); 097 } 098 099 @Override 100 public String toString() { 101 return "StreamResequencer[to: " + getProcessor() + "]"; 102 } 103 104 }