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    }