Class EHistoricSubscribeFeed

  • All Implemented Interfaces:
    EObject, ERequestor, ESubscriber

    public final class EHistoricSubscribeFeed
    extends EAbstractHistoricFeed<IEHistoricSubscriber>
    implements ESubscriber, ERequestor
    The historic subscriber feed extends IESubscribeFeed's ability to receive live notification messages with the ability to seamlessly retrieve past notification messages from historic publishers. The historic subscribe feed accomplishes this merge by:
    1. On start-up, subscribing to live notification and PublishStatusEvent feeds (the publish status event reports each individual historic publisher status).
    2. Again on start-up, requesting previously published notification messages from historic publishers if historic subscriber requested them.
    3. Past notifications contained in historic replies and live notifications are placed into a single list with care taken to ensure each message appears only once in the list.
    4. Once all the replies are received the received notification message list is sorted by time (millisecond granularity), publisher identifier, and publisher-set message position and delivered to IEHistoricSubscriber.notify(ENotificationMessage, EHistoricSubscribeFeed) one at a time.
    5. After this all live notifications are forwarded to the historic subscriber as the messages arrive.

    Note: an historic subscriber may also receives live notification messages from EPublishers but, of course, none of the previously published messages. Further, an historic subscriber may receive past notification messages from any replier supporting HistoricRequest, HistoricReply messages.

    Using Historic Subscribe Feed

    Follow these steps for using an historic subscribe feed:

    Step 1: Implement IEHistoricSubscriber interface.

    Step 2: Use an EHistoricSubscribeFeed.Builder instance (obtained from builder(EMessageKey, IEHistoricSubscriber)) to create an historic subscribe feed for a given message key and historic subscriber instance. An ECondition may be associated with the feed and only those notification messages matching match the condition are forwarded to the historic subscriber. If no condition is defined, then all messages are forwarded to the subscriber.

    Use EHistoricSubscribeFeed.Builder.doneCallback(HistoricFeedDoneCallback), EHistoricSubscribeFeed.Builder.statusCallback(HistoricFeedStatusCallback) and EHistoricSubscribeFeed.Builder.notifyCallback(HistoricNotifyCallback) to set Java lambda expressions used in place of IEHistoricSubscriber interface methods.

    Step 3: Start up historic subscribe feed. Call this method directly rather than using EFeed.register(net.sf.eBus.client.EObject) and EFeed.startup(net.sf.eBus.client.EObject) because EHistoricSubscribeFeed is an eBus hybrid object and runs in the IEHistoricSubscriber's dispatcher. The underlying live notification and historic notification request feeds are created, subscribed, and historic notification request placed at this time.

    If the historic subscribe feed has fixed, future end time, a timer is set to terminate the feed at the future time.

    Step 4: Subscribe to open historic feed.

    Step 5: Wait for notification messages and publisher status events to arrive. Note that the historic subscriber receives feed status updates on a per publisher basis rather than for the entire feed. This allows the historic subscriber to know if a particular publisher's notification stream is interrupted.

    Step 6: When the historic subscribe feed reaches a fixed end point (see more on setting historic subscribe feed intervals below), IEHistoricSubscriber.feedDone(EHistoricSubscribeFeed.HistoricFeedState, EHistoricSubscribeFeed) is called to let the historic subscriber know that the feed is ended and no more callbacks will be issued. This is not the case if the historic subscribe feed end time is set to on-going.

    Step 7: When the historic subscriber is shutting down, shutdown the feed.

    Example use of EHistoricSubscribeFeed

    import java.time.Instant;
    import net.sf.eBus.client.EFeed.FeedScope;
    import net.sf.eBus.client.EFeedState;
    import net.sf.eBus.feed.historic.IEHistoricSubscriber;
    import net.sf.eBus.feed.historic.EHistoricSubscribeFeed;
    import net.sf.eBus.feed.historic.EHistoricSubscribeFeed.HistoricFeedState;
    import net.sf.eBus.messages.EMessageKey;
    import net.sf.eBus.messages.ENotificationMessage;
    import net.sf.eBusx.time.EInterval.Clusivity;
    
    Step 1: Implement the IEHistoricSubscriber interface.
    public class CatalogSubscriber implements IEHistoricSubscriber
    {
        // Subscribe to this notification message class/subject key and feed scope.
        private final EMessageKey mKey;
        private final FeedScope mScope;
    
        // Catalog subscriber name used for logging purposes.
        private final String mName;
    
        // Request historic messages from this time in the past
        // (inclusive) to a fixed time in the future (exclusive).
        private final Instant mBeginTime;
        private final Instant mEndTime;
    
        // Store the feed here so it can be used to unsubscribe.
        private EHistoricSubscribeFeed mFeed;
    
        public CatalogSubscriber(final String subject,
                                 final FeedScope scope,
                                 final String name,
                                 final Instant beginTime,
                                 final Instant endTime) {
            mKey = new EMessageKey(CatalogUpdate.class, subject);
            mScope = scope;
            mName = name;
            mBeginTime = beginTime;
            mEndTime = endTime;
            mFeed = null;
        }
    
        @Override public void startup() {
            try {
                Step 2: Open the EHistoricSubscribe feed.
                final EHistoricSubscribeFeed.Builder builder = EHistoricSubscribeFeed.builder(mKey, this);
    
                // This subscriber has no associated ECondition and uses IEHistoricSubscriber interface method overrides.
                mFeed = builder.name(mName)
                               .scope(mScope)
                               .from(mBeginTime, Clusivity.INCLUSIVE)
                               .to(mEndTime, Clusivity.EXCLUSIVE)
                               .build();
    
                Step 3: Start the feed.
                mFeed.startup();
    
                Step 4: Subscribe to the feed.
                mFeed.subscribe();
            } catch(IllegalArgumentException argex) {
                // Feed open failed. Place recovery code here.
            }
        }
    
        Step 7: When subscriber is shutting down, retract subscription feed.
        @Override public void shutdown() {
            // mFeed.unsubscribe() is not necessary since close() will unsubscribe.
            if (mFeed != null) {
                mFeed.close();
                mFeed = null;
            }
        }
    
        Step 5: Wait for feed status events and notifications to arrive.
        @Override public void feedStatus(final PublishStatusEvent msg, final EHistoricSubscribeFeed feed) {
            Publisher feed status handling code here.
        }
    
        @Override public void notify(final ENotificationMessage msg, final EHistoricSubscribeFeed feed) {
            Notification handling code here.
        }
    
        Step 6: Wait for historic subscribe feed to complete.
        @Override public void feedDone(final HistoricFeedState feedState, final EHistoricSubscribeFeed feed) {
            Feed completion code here.
        }
    }

    Setting historic subscribe feed interval

    An historic subscribe feed may be set to cover the following time intervals:

    • EHistoricSubscribeFeed.Builder.from(Instant, EInterval.Clusivity) and end times in the past. The historic subscribe feed only requests past notification messages for this time interval and does not subscribe to live notification feeds. Once the feed delivers historic notifications, the feed terminates, calling feedDone. Note that begin time must be prior to end time.
    • All historic notification messages from begin time until now. The historic subscribe feed operates in the same manner as above when begin and end time are in the past.
    • Begin time in the past and end time in the future. Historic subscribe feed requests past notification messages from begin time until now and subscribes to live notification feeds. Feed sets a timer expiring at the fixed end time. When timer expires, calls IEHistoricSubscriber.feedDone(EHistoricSubscribeFeed.HistoricFeedState, EHistoricSubscribeFeed).
    • All live notification messages from now until a fixed future end time. Historic subscribe feed subscribes to live notification feeds only. Sets timer to expire when end time is reached. Calls IEHistoricSubscriber.feedDone when timer expires.
    • All live notification messages from now with not fixed end time. This is essentially the same as a IESubscribeFeed with the exception that feed status updates are per publisher. Historic subscribe feed does not terminate until historic subscriber shuts down the feed.

    When an historic subscriber requests past and live notification messages, the historic subscribe feed attempts to make sure the message stream does not contain redundant or missing messages. But message stream correctness cannot be guaranteed.

    Author:
    Charles W. Rapp
    See Also:
    IEHistoricSubscriber, IESubscribeFeed, PublishStatusEvent
    • Field Detail

      • DEFAULT_SUBSCRIBE_FEED_NAME

        public static final String DEFAULT_SUBSCRIBE_FEED_NAME
        If historic publish feed name is not set, then defaults to "EHistoricSubscribeFeed-" appended with feed index.
        See Also:
        Constant Field Values
    • Method Detail

      • name

        public String name()
        Returns historic subscribe feed's eBus object name. Used for logging purposes only.
        Specified by:
        name in interface EObject
        Returns:
        eBus object name.
      • startup

        public void startup()
        Places subordinate live notification and publisher status subscriptions (if needed) and requests historic notification messages (again, if needed). If this feed has a fixed, future end time, then sets timer to expire at that end time.
        Specified by:
        startup in interface EObject
      • shutdown

        public void shutdown()
        Closes subordinate feeds if open.
        Specified by:
        shutdown in interface EObject
      • beginClusivity

        public EInterval.Clusivity beginClusivity()
        Returns begin time clusivity. Does not return null.
        Returns:
        non-null begin time clusivity.
      • endClusivity

        public EInterval.Clusivity endClusivity()
        Returns end time clusivity. Does not return null.
        Returns:
        non-null end time clusivity.
      • subscribe

        public void subscribe()
        Puts historic notification request and live notification feeds in place. If feed end time is in the past, then only historic notifications are requested. If begin time starts at the current time, then only live notification subscription is placed.

        Does nothing if historic subscribe feed already has subordinate feeds in place.

        Throws:
        IllegalStateException - if this feed is not open.