content: package ru.yandex.qatools.allure.experimental;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import ru.yandex.qatools.allure.events.ClearStepStorageEvent;
  import ru.yandex.qatools.allure.events.ClearTestStorageEvent;
  import ru.yandex.qatools.allure.events.StepEvent;
  import ru.yandex.qatools.allure.events.StepFinishedEvent;
  import ru.yandex.qatools.allure.events.StepStartedEvent;
  import ru.yandex.qatools.allure.events.TestCaseEvent;
  import ru.yandex.qatools.allure.events.TestCaseFinishedEvent;
  import ru.yandex.qatools.allure.events.TestCaseStartedEvent;
  import ru.yandex.qatools.allure.events.TestSuiteEvent;
  import ru.yandex.qatools.allure.events.TestSuiteFinishedEvent;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import java.util.ServiceConfigurationError;
  import java.util.ServiceLoader;
  
  /**
   * This is an internal Allure component.
   * <p/>
   * {@link ru.yandex.qatools.allure.experimental.ListenersNotifier} used for notify
   * listeners {@link ru.yandex.qatools.allure.experimental.LifecycleListener} of
   * Allure events.
   * <p/>
   *
   * @author Dmitry Baev charlie@yandex-team.ru
   *         Date: 26.05.14
   * @see ru.yandex.qatools.allure.Allure
   */
  public class ListenersNotifier extends LifecycleListener {
  
      private static final Logger LOGGER = LoggerFactory.getLogger(ListenersNotifier.class);
  
      private List<LifecycleListener> listeners = new ArrayList<>();
  
      /**
       * Create instance of {@link ru.yandex.qatools.allure.experimental.ListenersNotifier}
       * using current context class loader.
       */
      public ListenersNotifier() {
          this(Thread.currentThread().getContextClassLoader());
      }
  
      /**
       * Create instance of {@link ru.yandex.qatools.allure.experimental.ListenersNotifier}
       * using specified class loader. This class loader will be used to find listeners
       * via Java SPI.
       *
       * @param classLoader given class loader to find {@link ru.yandex.qatools.allure.experimental.LifecycleListener}
       *                    services
       */
      public ListenersNotifier(ClassLoader classLoader) {
          loadListeners(ServiceLoader.load(
                  LifecycleListener.class,
                  classLoader
          ));
      }
  
      /**
       * Safely find all {@link ru.yandex.qatools.allure.experimental.LifecycleListener}
       * services.
       *
       * @param loader specified {@link java.util.ServiceLoader} to find our services
       */
      private void loadListeners(ServiceLoader<LifecycleListener> loader) {
          Iterator<LifecycleListener> iterator = loader.iterator();
          while (hasNextSafely(iterator)) {
              try {
                  LifecycleListener listener = iterator.next();
                  listeners.add(listener);
                  LOGGER.info(String.format("Found %s: %s", LifecycleListener.class, listener.getClass()));
              } catch (ServiceConfigurationError e) {
                  LOGGER.error("iterator.next() failed", e);
              }
          }
      }
  
      /**
       * Safely check for <pre>iterator.hasNext()</pre>.
       *
       * @param iterator specified iterator to check he presence of next element
       * @return {@code true} if the iteration has more elements, false otherwise
       */
      private boolean hasNextSafely(Iterator iterator) {
          try {
              /* Throw a ServiceConfigurationError if a provider-configuration file violates the specified format,
  +            or if it names a provider class that cannot be found and instantiated, or if the result of
  +            instantiating the class is not assignable to the service type, or if any other kind of exception
  +            or error is thrown as the next provider is located and instantiated.
  +            @see http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html#iterator()
  +            */
              return iterator.hasNext();
          } catch (Exception e) {
              LOGGER.error("iterator.hasNext() failed", e);
              return false;
          }
      }
  
      /**
       * Invoke to tell listeners that an step started event processed
       */
      @Override
      public void fire(StepStartedEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an custom step event processed
       */
      @Override
      public void fire(StepEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an step finished event processed
       */
      @Override
      public void fire(StepFinishedEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an test case started event processed
       */
      @Override
      public void fire(TestCaseStartedEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an custom test case event processed
       */
      @Override
      public void fire(TestCaseEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an test case finished event processed
       */
      @Override
      public void fire(TestCaseFinishedEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an custom test suite event processed
       */
      @Override
      public void fire(TestSuiteEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an test suite finished event processed
       */
      @Override
      public void fire(TestSuiteFinishedEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an clear step storage event processed
       */
      @Override
      public void fire(ClearStepStorageEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * Invoke to tell listeners that an clear test case storage event processed
       */
      @Override
      public void fire(ClearTestStorageEvent event) {
          for (LifecycleListener listener : listeners) {
              try {
                  listener.fire(event);
              } catch (Exception e) {
                  logError(listener, e);
              }
          }
      }
  
      /**
       * This method log given exception in specified listener
       */
      private void logError(LifecycleListener listener, Exception e) {
          LOGGER.error("Error for listener " + listener.getClass(), e);
      }
  
      /**
       * You can use this method to add listeners to this notifier.
       */
      public void addListener(LifecycleListener listener) {
          listeners.add(listener);
      }
  
      /**
       * Getter for {@link #listeners}
       */
      public List<LifecycleListener> getListeners() {
          return listeners;
      }
  }
  