Class EReplyFeed

  • All Implemented Interfaces:
    IEFeed, IEReplyFeed

    public final class EReplyFeed
    extends EFeed
    implements IEReplyFeed
    EReplyFeed is the application entry point for posting replies to request messages to requesters. Follow these steps to use this feed:

    Step 1: Implement EReplier interface.

    Step 2: Build reply feed for EReplier instance and type+topic request message key. The condition is optional and may be null. If provided, then only request messages satisfying the condition are forwarded to the replier.

    Use EReplyFeed.Builder.cancelRequestCallback(CancelRequestCallback) and EReplyFeed.Builder.requestCallback(RequestCallback) to set Java lambda expressions used in place of EReplier interface methods.

    Step 3: Advertise this replier to eBus. This allows eBus to match repliers with requesters.

    Step 4: Wait for requests to arrive. Keep the given EReplyFeed.ERequest instance handy because ERequest is used to post reply messages back to the requester, not EReplyFeed.

    Step 5: Send one or more reply messages back to the requester.

    Step 6: When the replier is shutting down, retract the reply advertisement and close the feed.

    Example use of EReplyFeed

    import java.util.ArrayList;
    import java.util.List;
    import net.sf.eBus.client.EFeed.FeedScope;
    import net.sf.eBus.client.EReplier;
    import net.sf.eBus.client.EReplyFeed;
    import net.sf.eBus.messages.EMessageKey;
    import net.sf.eBus.messages.EReplyMessage;
    import net.sf.eBus.messages.EReplyMessage.ReplyStatus;
    import net.sf.eBus.messages.ERequestMessage;
    
    Step 1: Implement EReplier interface.
    public class CatalogReplier implements EReplier {
        private final EMessageKey mKey;
        private final FeedScope mScope;
        private EReplyFeed mFeed;
        private final List<EReplyFeed.ERequest> mRequests;
    
        public CatalogReplier(final String subject, final FeedScope scope) {
            mKey = new EMessageKey(com.acme.CatalogOrder.class, subject);
            mScope = scope;
            mRequests = new ArrayList<>();
        }
    
        @Override public void startup() {
            try {
                Step 2: Open a reply feed for reply message key. May override EReplier interfaces methods.
                // This advertisement has no associated ECondition and uses EReplier interface method overrides.
                mFeed = (EReplyFeed.builder()).target(this)
                                              .messageKey(mKey)
                                              .scope(mScope)
                                              .build();
    
                Step 3: Advertise reply feed.
                mFeed.advertise();
    
                mFeed.updateFeedState(EFeedState.UP);
            } catch (IllegalArgumentException argex) {
                // Advertisement failed. Place recovery code here.
            }
        }
    
        Step 4: Wait for requests to arrive.
        @Override public void request(final EReplyFeed.ERequest request, final EReplyFeed feed) {
            final ERequestMessage msg = request.request();
    
            try {
                mRequests.add(request);
                startOrderProcessing(msg, request);
            } catch (Exception jex) {
                request.reply(new CatalogOrderReply(ReplyStatus.ERROR, // reply status.
                                                     jex.getMessage())); // reply reason.
            }
        }
    
        @Override
        public void cancelRequest(final EReplyFeed.ERequest request, final boolean mayRespond) {
            // Is this request still active? It is if the request is listed.
            if (mRequests.remove(request)) {
                // Yes, try to stop the request processing.
                try {
                    // Throws an exception if the request cannot be stopped.
                    stopOrderProcessing(request);
                } catch (Exception jex) {
                    // Ignore since nothing else can be done.
                }
            }
        }
    
        Step 5: Send one or more reply messages back to requestor.
        public void orderReply(final EReplyFeed.ERequest request, final ReplyStatus status, final String reason) {
            final ERequestAd ad = mRequests.get(request);
    
            if (mRequests.contains(request) && request.isActive()) {
                request.reply((OrderReply.builder()).subject(mKey.subject())
                                                    .timestamp(Instant.now())
                                                    .replyStatus(status)
                                                    .replyReason(reason)
                                                    .build());
    
                // If the request processing is complete, remove the request.
                if (status.isFinal()) {
                    mRequests.remove(request);
                }
            }
        }
    
        @Override
        public void shutdown() {
            final String subject = mKey.subject();
    
            // While eBus will does this for us, it is better to do it ourselves.
            for (EReplyFeed.ERequest request : mRequests) {
                request.reply((EReplyMessage.builder()).subject(subject)
                                                       .timestamp(Instant.now())
                                                       .replyStatus(ReplyStatus.ERROR)
                                                       .replyReason("shutting down")
                                                       .build());
            }
    
            mRequests.clear();
    
            Step 6: When shutting down, either unadvertise or close reply feed.
            if (mFeed != null) {
                mFeed.close();
                mFeed = null;
            }
        }
    }
    Author:
    Charles Rapp
    See Also:
    EReplier, ERequestor, ERequestFeed
    • Field Detail

      • mFeedType

        protected final net.sf.eBus.client.ESingleFeed.FeedType mFeedType
        Specifies whether this is a publish, subscribe, request, or reply feed.
      • mSubject

        protected final net.sf.eBus.client.ESubject mSubject
        The feed interfaces with this eBus subject. The subject type is based on feed type.
      • mActivationCount

        protected int mActivationCount
        Tracks the number of contra-feeds matched to this feed. If this is a publisher feed, then counts subscriber feeds. If a subscriber feed, then counts publisher feeds.
    • Method Detail

      • inactivate

        protected void inactivate()
        If the advertisement is in place, then un-advertises it, sends a final error reply to all extant requests, and if this feed's scope is local & remote or remote only, removes this feed from the advertisers list.
        Specified by:
        inactivate in class EFeed
        See Also:
        EFeed.close()
      • isAdvertised

        public boolean isAdvertised()
        Returns true if this reply feed is both open and advertised; otherwise returns false.
        Specified by:
        isAdvertised in interface IEReplyFeed
        Returns:
        true if this reply feed is open and advertised.
      • updateFeedState

        public void updateFeedState​(EFeedState update)
        Updates the replier feed state to the given value. If update equals the currently stored reply feed state, nothing is done. Otherwise, the updated value is stored. If this feed is advertised to the server and the subscription feed is up, then this update is forwarded to subscribed requestors.
        Specified by:
        updateFeedState in interface IEReplyFeed
        Parameters:
        update - the new reply feed state.
        Throws:
        java.lang.NullPointerException - if update is null.
        java.lang.IllegalStateException - if this feed was closed and is inactive or is not advertised.
      • builder

        public static EReplyFeed.Builder builder()
        Returns a new EReplyFeed builder instance. This instance should be used to build a single reply feed instance and not used to create multiple such feeds.
        Returns:
        new reply feed builder.
      • unadvertise

        public void unadvertise()
        Retracts this replier feed from the associated request subject. Does nothing if this feed is not currently advertised.
        Specified by:
        unadvertise in interface IEReplyFeed
        Throws:
        java.lang.IllegalStateException - if this feed was closed and is inactive.
        See Also:
        advertise(), EFeed.close()
      • toString

        public java.lang.String toString()
        Returns a containing the feed message key and data member values.
        Overrides:
        toString in class EFeed
        Returns:
        textual representation of this feed.
      • key

        public final EMessageKey key()
        Returns the feed message key. The message key type matches the feed type. If this is a EPublishFeed, then a notification message key is returned.
        Returns:
        message key.
      • messageSubject

        public final java.lang.String messageSubject()
        Returns the feed message key subect.
        Returns:
        message key subject.
      • activationCount

        public final int activationCount()
        Returns the feed activation count.
        Returns:
        value ≥ zero.