content: package ru.yandex.qatools.allure.storages;
  
  import ru.yandex.qatools.allure.model.Status;
  import ru.yandex.qatools.allure.model.Step;
  
  import java.util.Deque;
  import java.util.LinkedList;
  
  /**
   * Using to storage information about current step context. How it works:
   * <pre>
   * create new step storage | root() -> null
   * start step1             | step1() -> root() -> null
   * finish step1            | root(step1()) -> null
   * start step2             | step2() -> root(step1()) -> null
   * finish step2            | root(step1() -> step2()) -> null
   * ...
   * </pre>
   * In the end just get all children of root step. It's step three which you can see in report
   *
   * @author Dmitry Baev charlie@yandex-team.ru
   *         Date: 13.12.13
   *         <p/>
   * @see ru.yandex.qatools.allure.Allure
   */
  public class StepStorage extends InheritableThreadLocal<Deque<Step>> {
  
      public static final Object LOCK = new Object();
  
      /**
       * Returns the current thread's "initial value". Construct an new
       * {@link java.util.Deque} with root step {@link #createRootStep()}
       *
       * @return the initial value for this thread-local
       */
      @Override
      protected Deque<Step> initialValue() {
          Deque<Step> queue = new LinkedList<>();
          queue.add(createRootStep());
          return queue;
      }
  
      /**
       * In case parent thread spawn thread we need create a new queue
       * for child thread but use the only one root step. In the end all steps will be
       * children of root step, all we need is sync adding steps
       * @param parentValue value from parent thread
       * @return local copy of queue in this thread with parent root as first element
       */
      @Override
      protected Deque<Step> childValue(Deque<Step> parentValue) {
          Deque<Step> queue = new LinkedList<>();
          queue.add(parentValue.getFirst());
          return queue;
      }
  
      /**
       * Retrieves, but does not remove, the last element of this deque.
       *
       * @return the tail of this deque
       */
      public Step getLast() {
          return get().getLast();
      }
  
      /**
       * Inserts the specified element into the queue represented by this deque
       *
       * @param step the element to add
       */
      public void put(Step step) {
          synchronized (LOCK) {
              get().add(step);
          }
      }
  
      /**
       * Removes the last element of deque in the current thread's copy of this
       * thread-local variable. If after this deque is empty add new root step
       * {@link #createRootStep()}
       *
       * @return the element removed from deque
       */
      public Step pollLast() {
          Deque<Step> queue = get();
          Step last = queue.pollLast();
          if (queue.isEmpty()) {
              queue.add(createRootStep());
          }
          return last;
      }
  
      /**
       * Move last step to children of previous step. How it works:
       * <pre>
       * before: step1(...) -> step2(child1 -> ... -> childN) -> step3(...) -> ... -> null
       * after:  step2(child1 -> ... -> childN -> step1(...)) -> step3(...) -> ... -> null
       * </pre>
       * @return ex-last step
       */
      public Step adopt() {
          Step step = pollLast();
          synchronized (LOCK) {
              getLast().getSteps().add(step);
          }
          return step;
      }
  
      /**
       * Construct new root step. Used for inspect problems with Allure lifecycle
       *
       * @return new root step marked as broken
       */
      public Step createRootStep() {
          return new Step()
                  .withName("Root step")
                  .withTitle("Allure step processing error: if you see this step something went wrong.")
                  .withStart(System.currentTimeMillis())
                  .withStatus(Status.BROKEN);
      }
  }
  