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 */
017package org.apache.camel.processor.resequencer;
018
019import java.util.Timer;
020
021import org.apache.camel.util.concurrent.ThreadHelper;
022
023/**
024 * Resequences elements based on a given {@link SequenceElementComparator}.
025 * This resequencer is designed for resequencing element streams. Stream-based
026 * resequencing has the advantage that the number of elements to be resequenced
027 * need not be known in advance. Resequenced elements are delivered via a
028 * {@link SequenceSender}.
029 * <p>
030 * The resequencer's behaviour for a given comparator is controlled by the
031 * <code>timeout</code> property. This is the timeout (in milliseconds) for a
032 * given element managed by this resequencer. An out-of-sequence element can
033 * only be marked as <i>ready-for-delivery</i> if it either times out or if it
034 * has an immediate predecessor (in that case it is in-sequence). If an
035 * immediate predecessor of a waiting element arrives the timeout task for the
036 * waiting element will be cancelled (which marks it as <i>ready-for-delivery</i>).
037 * <p>
038 * If the maximum out-of-sequence time difference between elements within a
039 * stream is known, the <code>timeout</code> value should be set to this
040 * value. In this case it is guaranteed that all elements of a stream will be
041 * delivered in sequence via the {@link SequenceSender}. The lower the
042 * <code>timeout</code> value is compared to the out-of-sequence time
043 * difference between elements within a stream the higher the probability is for
044 * out-of-sequence elements delivered by this resequencer. Delivery of elements
045 * must be explicitly triggered by applications using the {@link #deliver()} or
046 * {@link #deliverNext()} methods. Only elements that are <i>ready-for-delivery</i>
047 * are delivered by these methods. The longer an application waits to trigger a
048 * delivery the more elements may become <i>ready-for-delivery</i>.
049 * <p>
050 * The resequencer remembers the last-delivered element. If an element arrives
051 * which is the immediate successor of the last-delivered element it is
052 * <i>ready-for-delivery</i> immediately. After delivery the last-delivered
053 * element is adjusted accordingly. If the last-delivered element is
054 * <code>null</code> i.e. the resequencer was newly created the first arriving
055 * element needs <code>timeout</code> milliseconds in any case for becoming
056 * <i>ready-for-delivery</i>.
057 * <p>
058 *
059 * @version 
060 */
061public class ResequencerEngine<E> {
062
063    /**
064     * The element that most recently hash been delivered or <code>null</code>
065     * if no element has been delivered yet.
066     */
067    private Element<E> lastDelivered;
068
069    /**
070     * Minimum amount of time to wait for out-of-sequence elements.
071     */
072    private long timeout;
073
074    /**
075     * A sequence of elements for sorting purposes.
076     */
077    private Sequence<Element<E>> sequence;
078
079    /**
080     * A timer for scheduling timeout notifications.
081     */
082    private Timer timer;
083
084    /**
085     * A strategy for sending sequence elements.
086     */
087    private SequenceSender<E> sequenceSender;
088
089    /**
090     * Indicates whether an error should be thrown if message older (based on Comparator) than the last delivered message is received.
091     */
092    private Boolean rejectOld;
093
094    /**
095     * Creates a new resequencer instance with a default timeout of 2000
096     * milliseconds.
097     *
098     * @param comparator a sequence element comparator.
099     */
100    public ResequencerEngine(SequenceElementComparator<E> comparator) {
101        this.sequence = createSequence(comparator);
102        this.timeout = 2000L;
103        this.lastDelivered = null;
104    }
105
106    public void start() {
107        timer = new Timer(ThreadHelper.resolveThreadName("Camel Thread ${counter} - ${name}", "Stream Resequencer Timer"), true);
108    }
109
110    /**
111     * Stops this resequencer (i.e. this resequencer's {@link Timer} instance).
112     */
113    public void stop() {
114        timer.cancel();
115    }
116
117    /**
118     * Returns the number of elements currently maintained by this resequencer.
119     *
120     * @return the number of elements currently maintained by this resequencer.
121     */
122    public synchronized int size() {
123        return sequence.size();
124    }
125
126    /**
127     * Returns this resequencer's timeout value.
128     *
129     * @return the timeout in milliseconds.
130     */
131    public long getTimeout() {
132        return timeout;
133    }
134
135    /**
136     * Sets this sequencer's timeout value.
137     *
138     * @param timeout the timeout in milliseconds.
139     */
140    public void setTimeout(long timeout) {
141        this.timeout = timeout;
142    }
143
144    public Boolean getRejectOld() {
145        return rejectOld;
146    }
147
148    public void setRejectOld(Boolean rejectOld) {
149        this.rejectOld = rejectOld;
150    }
151
152    /**
153     * Returns the sequence sender.
154     *
155     * @return the sequence sender.
156     */
157    public SequenceSender<E> getSequenceSender() {
158        return sequenceSender;
159    }
160
161    /**
162     * Sets the sequence sender.
163     *
164     * @param sequenceSender a sequence element sender.
165     */
166    public void setSequenceSender(SequenceSender<E> sequenceSender) {
167        this.sequenceSender = sequenceSender;
168    }
169
170    /**
171     * Returns the last delivered element.
172     *
173     * @return the last delivered element or <code>null</code> if no delivery
174     *         has been made yet.
175     */
176    E getLastDelivered() {
177        if (lastDelivered == null) {
178            return null;
179        }
180        return lastDelivered.getObject();
181    }
182
183    /**
184     * Sets the last delivered element. This is for testing purposes only.
185     *
186     * @param o an element.
187     */
188    void setLastDelivered(E o) {
189        lastDelivered = new Element<E>(o);
190    }
191
192    /**
193     * Inserts the given element into this resequencer. If the element is not
194     * ready for immediate delivery and has no immediate presecessor then it is
195     * scheduled for timing out. After being timed out it is ready for delivery.
196     *
197     * @param o an element.
198     * @throws IllegalArgumentException if the element cannot be used with this resequencer engine
199     */
200    public synchronized void insert(E o) {
201        // wrap object into internal element
202        Element<E> element = new Element<E>(o);
203
204        // validate the exchange has no problem
205        if (!sequence.comparator().isValid(element)) {
206            throw new IllegalArgumentException("Element cannot be used in comparator: " + sequence.comparator());
207        }
208
209        // validate the exchange shouldn't be 'rejected' (if applicable)
210        if (rejectOld != null && rejectOld.booleanValue() && beforeLastDelivered(element)) {
211            throw new MessageRejectedException("rejecting message [" + element.getObject()
212                    + "], it should have been sent before the last delivered message [" + lastDelivered.getObject() + "]");
213        }
214
215        // add element to sequence in proper order
216        sequence.add(element);
217
218        Element<E> successor = sequence.successor(element);
219
220        // check if there is an immediate successor and cancel
221        // timer task (no need to wait any more for timeout)
222        if (successor != null) {
223            successor.cancel();
224        }
225
226        // start delivery if current element is successor of last delivered element
227        if (successorOfLastDelivered(element)) {
228            // nothing to schedule
229        } else if (sequence.predecessor(element) != null) {
230            // nothing to schedule
231        } else {
232            element.schedule(defineTimeout());
233        }
234    }
235
236    /**
237     * Delivers all elements which are currently ready to deliver.
238     *
239     * @throws Exception thrown by {@link SequenceSender#sendElement(Object)}.
240     *
241     * @see ResequencerEngine#deliverNext() 
242     */
243    public synchronized void deliver() throws Exception {
244        while (deliverNext()) {
245            // do nothing here
246        }
247    }
248
249    /**
250     * Attempts to deliver a single element from the head of the resequencer
251     * queue (sequence). Only elements which have not been scheduled for timing
252     * out or which already timed out can be delivered. Elements are delivered via
253     * {@link SequenceSender#sendElement(Object)}.
254     *
255     * @return <code>true</code> if the element has been delivered
256     *         <code>false</code> otherwise.
257     *
258     * @throws Exception thrown by {@link SequenceSender#sendElement(Object)}.
259     *
260     */
261    public boolean deliverNext() throws Exception {
262        if (sequence.size() == 0) {
263            return false;
264        }
265        // inspect element with lowest sequence value
266        Element<E> element = sequence.first();
267
268        // if element is scheduled do not deliver and return
269        if (element.scheduled()) {
270            return false;
271        }
272
273        // remove deliverable element from sequence
274        sequence.remove(element);
275
276        // set the delivered element to last delivered element
277        lastDelivered = element;
278
279        // deliver the sequence element
280        sequenceSender.sendElement(element.getObject());
281
282        // element has been delivered
283        return true;
284    }
285
286    /**
287     * Returns <code>true</code> if the given element is the immediate
288     * successor of the last delivered element.
289     *
290     * @param element an element.
291     * @return <code>true</code> if the given element is the immediate
292     *         successor of the last delivered element.
293     */
294    private boolean successorOfLastDelivered(Element<E> element) {
295        if (lastDelivered == null) {
296            return false;
297        }
298        if (sequence.comparator().successor(element, lastDelivered)) {
299            return true;
300        }
301        return false;
302    }
303
304    /**
305     * Retuns <code>true</code> if the given element is before the last delivered element.
306     *
307     * @param element an element.
308     * @return <code>true</code> if the given element is before the last delivered element.
309     */
310    private boolean beforeLastDelivered(Element<E> element) {
311        if (lastDelivered == null) {
312            return false;
313        }
314        if (sequence.comparator().compare(element, lastDelivered) < 0) {
315            return true;
316        }
317        return false;
318    }
319
320    /**
321     * Creates a timeout task based on the timeout setting of this resequencer.
322     *
323     * @return a new timeout task.
324     */
325    private Timeout defineTimeout() {
326        return new Timeout(timer, timeout);
327    }
328
329    private static <E> Sequence<Element<E>> createSequence(SequenceElementComparator<E> comparator) {
330        return new Sequence<Element<E>>(new ElementComparator<E>(comparator));
331    }
332
333}