All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.couchbase.client.core.util.SingleStateful Maven / Gradle / Ivy

There is a newer version: 2.7.0
Show newest version
/*
 * Copyright (c) 2019 Couchbase, Inc.
 *
 * 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.couchbase.client.core.util;

import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;
import reactor.core.publisher.ReplayProcessor;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;

import static com.couchbase.client.core.util.Validators.notNull;

/**
 * Represents a single stateful component.
 */
public class SingleStateful implements Stateful {

  private final ReplayProcessor states = ReplayProcessor.cacheLast();
  private final FluxSink statesSink = states.sink();
  private final AtomicReference currentState;
  private final BiConsumer beforeTransitionCallback;


  private SingleStateful(final S initialState, final BiConsumer beforeTransitionCallback) {
    notNull(initialState, "Initial Stateful Type");

    this.currentState = new AtomicReference<>(initialState);
    this.beforeTransitionCallback = beforeTransitionCallback;
    statesSink.next(initialState);
  }

  /**
   * Creates a new stateful component with an initial state.
   *
   * @param initialState the initial state of the component.
   * @return an initialized stateful component with the state provided.
   */
  public static  SingleStateful fromInitial(final S initialState) {
    return fromInitial(initialState, (oldState, newState) -> {});
  }

  /**
   * Creates a new stateful component with an initial state.
   *
   * @param initialState the initial state of the component.
   * @return an initialized stateful component with the state provided.
   */
  public static  SingleStateful fromInitial(final S initialState, final BiConsumer beforeTransitionCallback) {
    return new SingleStateful<>(initialState, beforeTransitionCallback);
  }

  @Override
  public S state() {
    return currentState.get();
  }

  @Override
  public Flux states() {
    return states;
  }

  /**
   * Transition into a new state, notifying consumers.
   *
   * 

Note that if the new state is identical to the old state no transition will be performed.

* * @param newState the new state to apply. */ public synchronized void transition(final S newState) { notNull(newState, "New Stateful Type"); if (!currentState.get().equals(newState)) { beforeTransitionCallback.accept(currentState.get(), newState); currentState.set(newState); statesSink.next(newState); } } /** * If the expected state is in place the new one is applied and consumers notified. * * @param expectedState the old expected state. * @param newState the new state to apply. * @return true if the comparison has been successful. */ public boolean compareAndTransition(final S expectedState, final S newState) { notNull(newState, "New Stateful Type"); notNull(expectedState, "Expected Stateful Type"); if (currentState.compareAndSet(expectedState, newState)) { beforeTransitionCallback.accept(expectedState, newState); statesSink.next(newState); return true; } return false; } /** * Doesn't have to be called, added for good measure. */ public void close() { statesSink.complete(); } }