public void addFinalStageInfoListener(StateChangeListener<StageInfo> finalStatusListener)
    {
        AtomicBoolean done = new AtomicBoolean();
        StateChangeListener<Optional<StageInfo>> fireOnceStateChangeListener = finalStageInfo -> {
            if (finalStageInfo.isPresent() && done.compareAndSet(false, true)) {
                finalStatusListener.stateChanged(finalStageInfo.get());
            }
        };
        finalStageInfo.addStateChangeListener(fireOnceStateChangeListener);
    }
public void addFinalStageInfoListener ( StateChangeListener < StageInfo > finalStatusListener ) { AtomicBoolean done = new AtomicBoolean ( ) ; StateChangeListener < Optional < StageInfo > > fireOnceStateChangeListener = finalStageInfo -> { if ( finalStageInfo . isPresent ( ) && done . compareAndSet ( false , true ) ) { finalStatusListener . stateChanged ( finalStageInfo . get ( ) ) ; } } ; finalStageInfo . addStateChangeListener ( fireOnceStateChangeListener ) ; }
Add a listener for the final stage info.  This notification is guaranteed to be fired only once.
Listener is always notified asynchronously using a dedicated notification thread pool so, care should
be taken to avoid leaking {@code this} when adding a listener in a constructor. Additionally, it is
possible notifications are observed out of order due to the asynchronous execution.