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;
}
}