/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.topic;
import com.hazelcast.core.MessageListener;
/**
* A {@link MessageListener} to better integrate with the reliable topic.
*
* If a regular MessageListener is registered on a reliable topic, the message listener works fine, but it can't do much
* more than listen to messages.
*
* If a ReliableMessageListener is registered on a normal topic, only the {@link MessageListener} methods will be called.
*
* <h1>Durable Subscription</h1>
* The ReliableMessageListener allows you to control where you want to start processing a message when the listener is
* registered. This makes it possible to create a durable subscription by storing the sequence of the last message and
* using this sequenceId as the sequenceId to start from.
*
* <h1>Exception handling</h1>
* The ReliableMessageListener also gives the ability to deal with exceptions using the {@link #isTerminal(Throwable)}
* method. If a plain MessageListener is used, then it won't terminate on exceptions and it will keep on running. But in some
* cases it is better to stop running.
*
* <h1>Global order</h1>
* The ReliableMessageListener will always get all events in order (global order). It will not get duplicates and
* there will only be gaps if it is too slow. For more information see {@link #isLossTolerant()}.
*
* <h1>Delivery guarantees</h1>
* Because the ReliableMessageListener controls which item it wants to continue from upon restart, it is very easy to provide
* an at-least-once or at-most-once delivery guarantee. The storeSequence is always called before a message is processed;
* so it can be persisted on some non-volatile storage. When the {@link #retrieveInitialSequence()} returns the stored
* sequence, then an at-least-once delivery is implemented since the same item is now being processed twice. To implement
* an at-most-once delivery guarantee, add 1 to the stored sequence when the {@link #retrieveInitialSequence()} is called.
*
* @param <E>
*/
public interface ReliableMessageListener<E> extends MessageListener<E> {
/**
* Retrieves the initial sequence from which this ReliableMessageListener should start.
*
* Return -1 if there is no initial sequence and you want to start from the next published message.
*
* If you intent to create a durable subscriber so you continue from where you stopped the previous
* time, load the previous sequence and add 1. If you don't add one, then you will be receiving the
* same message twice.
*
* @return the initial sequence
*/
long retrieveInitialSequence();
/**
* Informs the ReliableMessageListener that it should store the sequence. This method is called before the message is
* processed. Can be used to make a durable subscription.
*
* @param sequence the sequence
*/
void storeSequence(long sequence);
/**
* Checks if this ReliableMessageListener is able to deal with message loss. Even though the reliable topic promises to
* be reliable, it can be that a MessageListener is too slow. Eventually the message won't be available anymore.
*
* If the ReliableMessageListener is not loss tolerant and the topic detects that there are missing messages, it will
* terminate the ReliableMessageListener.
*
* @return true if the ReliableMessageListener is tolerant towards loosing messages.
*/
boolean isLossTolerant();
/**
* Checks if the ReliableMessageListener should be terminated based on an exception thrown while calling
* {@link #onMessage(com.hazelcast.core.Message)}.
*
* @param failure the exception thrown while calling {@link #onMessage(com.hazelcast.core.Message)}.
* @return true if the ReliableMessageListener should terminate itself, false if it should keep on running.
*/
boolean isTerminal(Throwable failure);
}