public MutableSet<Entry<K, V>> entrySet() {
   synchronized (this.lock) {
     return SynchronizedMutableSet.of(this.getSortedMap().entrySet(), this.lock);
   }
 }
 public MutableSet<K> keySet() {
   synchronized (this.lock) {
     return SynchronizedMutableSet.of(this.getSortedMap().keySet(), this.lock);
   }
 }
/**
 * Implementation of {@link reactor.data.core.state.StateMachine} that uses an {@link
 * reactor.core.Observable} to notify states of new values.
 *
 * @author Jon Brisbin
 */
public class ObservableStateMachine<T> implements StateMachine<T> {

  private final MutableSet<Object> states = SynchronizedMutableSet.of(UnifiedSet.newSet());
  private final MutableMultimap<Object, Tuple2<?, Predicate<T>>> transitions =
      SynchronizedPutFastListMultimap.newMultimap();

  private final boolean strict;
  private final Observable observable;

  /**
   * Create an new {@code ObservableStateMachine} using the given {@link reactor.core.Observable}
   * and denoting whether this {@link reactor.data.core.state.StateMachine} should operate in strict
   * mode.
   *
   * @param observable {@code Observable} to use
   * @param strict whether or not to operate in strict mode
   * @see {@link StateMachine#strict()}
   */
  public ObservableStateMachine(Observable observable, boolean strict) {
    this.observable = observable;
    this.strict = strict;
  }

  @Override
  public Observable observable() {
    return observable;
  }

  @Override
  public StateMachine<T> define(Object... states) {
    for (Object state : states) {
      define(state);
    }
    return this;
  }

  @Override
  public <V> StateMachine<T> define(V state) {
    states.add(state);
    return this;
  }

  @Override
  public <V> boolean contains(V state) {
    return states.contains(state);
  }

  @Override
  public boolean strict() {
    return strict;
  }

  @Override
  public <FROM, TO> StateMachine<T> connect(FROM from, TO to) {
    return connect(from, to, null);
  }

  @Override
  public <FROM, TO> StateMachine<T> connect(FROM from, TO to, Predicate<T> predicate) {
    transitions.put(from, Tuple.of(to, predicate));
    return this;
  }

  @Override
  public <FROM, TO> StateMachine<T> disconnect(FROM from, TO to) {
    transitions.remove(from, to);
    return this;
  }

  @Override
  public <V, X extends Throwable> StateMachine<T> when(
      Class<X> errorType, final Consumer<Tuple3<V, T, X>> errorConsumer) {
    observable.on(
        Selectors.type(errorType),
        new Consumer<Event<Throwable>>() {
          @SuppressWarnings("unchecked")
          @Override
          public void accept(Event<Throwable> ev) {
            if (null != errorConsumer && ev.getData() instanceof StateException) {
              V state = (V) ((StateException) ev.getData()).state;
              X cause = (X) ev.getData().getCause();
              T data = (T) ((StateException) ev.getData()).data;
              errorConsumer.accept(Tuple.of(state, data, cause));
            }
          }
        });
    return this;
  }

  @Override
  public <V> StateMachine<T> on(final V state, final Function<T, T> fn) {
    if (strict) {
      Assert.isTrue(states.contains(state), "State " + state + " has not been defined");
    }
    observable.on(
        (state instanceof Selector ? (Selector) state : Selectors.object(state)),
        new Consumer<Event<T>>() {
          @SuppressWarnings("unchecked")
          @Override
          public void accept(final Event<T> data) {
            try {
              data.setData(fn.apply(data.getData()));
            } catch (Throwable t) {
              observable.notify(
                  t.getClass(), Event.wrap(new StateException(t, state, data.getData())));
            }
          }
        });
    return this;
  }

  @Override
  public <V> StateMachine<T> notify(V state) {
    return notify(state, null);
  }

  @SuppressWarnings("unchecked")
  @Override
  public <V> StateMachine<T> notify(final V state, final T value) {
    if (strict) {
      Assert.isTrue(states.contains(state), "State " + state + " has not been defined");
    }
    Event<T> ev = Event.wrap(value instanceof Event ? ((Event<T>) value).getData() : value);
    observable.notify(
        state,
        ev,
        new Consumer<Event<T>>() {
          @Override
          public void accept(final Event<T> ev) {
            transition(state, ev.getData());
          }
        });
    return this;
  }

  private <V> void transition(V from, final T data) {
    MutableCollection<Tuple2<?, Predicate<T>>> ts = transitions.get(from);
    if (ts.isEmpty()) {
      return;
    }
    ts.forEach(
        new Procedure<Tuple2<?, Predicate<T>>>() {
          @SuppressWarnings("unchecked")
          @Override
          public void value(Tuple2<?, Predicate<T>> tup) {
            if (null == tup.getT2() || tup.getT2().test(data)) {
              ObservableStateMachine.this.notify(tup.getT1(), data);
            }
          }
        });
  }

  private static class StateException extends Exception {
    private final Object state;
    private final Object data;

    private StateException(Throwable cause, Object state, Object data) {
      super(cause);
      this.state = state;
      this.data = data;
    }

    @Override
    public String toString() {
      return "StateException{" + "state=" + state + ", data=" + data + '}';
    }
  }
}