package org.fluentlenium.core.events;
import org.fluentlenium.core.FluentControl;
import org.fluentlenium.core.components.DefaultComponentInstantiator;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.internal.WrapsDriver;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import org.openqa.selenium.support.events.WebDriverEventListener;
import java.awt.event.ContainerListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Registry of event listeners.
*/
public class EventsRegistry implements WrapsDriver { // NOPMD TooManyFields
private final EventFiringWebDriver eventDriver;
private final EventsSupport support;
private final DefaultComponentInstantiator instantiator;
/* default */ final List<NavigateToListener> beforeNavigateTo = new ArrayList<>();
/* default */ final List<NavigateToListener> afterNavigateTo = new ArrayList<>();
/* default */ final List<NavigateListener> beforeNavigateBack = new ArrayList<>();
/* default */ final List<NavigateListener> afterNavigateBack = new ArrayList<>();
/* default */ final List<NavigateListener> beforeNavigateForward = new ArrayList<>();
/* default */ final List<NavigateListener> afterNavigateForward = new ArrayList<>();
/* default */ final List<NavigateAllListener> beforeNavigate = new ArrayList<>();
/* default */ final List<NavigateAllListener> afterNavigate = new ArrayList<>();
/* default */ final List<NavigateListener> beforeNavigateRefresh = new ArrayList<>();
/* default */ final List<NavigateListener> afterNavigateRefresh = new ArrayList<>();
/* default */ final List<FindByListener> beforeFindBy = new ArrayList<>();
/* default */ final List<FindByListener> afterFindBy = new ArrayList<>();
/* default */ final List<ElementListener> beforeClickOn = new ArrayList<>();
/* default */ final List<ElementListener> afterClickOn = new ArrayList<>();
/* default */ final List<ElementListener> beforeChangeValueOf = new ArrayList<>();
/* default */ final List<ElementListener> afterChangeValueOf = new ArrayList<>();
/* default */ final List<ScriptListener> beforeScript = new ArrayList<>();
/* default */ final List<ScriptListener> afterScript = new ArrayList<>();
/* default */ final List<AlertListener> beforeAlertAccept = new ArrayList<>();
/* default */ final List<AlertListener> afterAlertAccept = new ArrayList<>();
/* default */ final List<AlertListener> beforeAlertDismiss = new ArrayList<>();
/* default */ final List<AlertListener> afterAlertDismiss = new ArrayList<>();
/* default */ final List<ExceptionListener> onException = new ArrayList<>();
/**
* Creates a new registry of event listeners.
*
* @param control control interface
*/
public EventsRegistry(FluentControl control) {
eventDriver = (EventFiringWebDriver) control.getDriver();
support = new EventsSupport(this);
instantiator = new DefaultComponentInstantiator(control);
eventDriver.register(new EventAdapter(support, instantiator));
}
/**
* Register a new event listener.
*
* @param eventListener event listener to register
* @return {@code this} to chain method calls
*/
public EventsRegistry register(WebDriverEventListener eventListener) {
eventDriver.register(eventListener);
return this;
}
/**
* Unregister an existing event listener.
*
* @param eventListener existing event listener to unregister
* @return {@code this} to chain method calls
*/
public EventsRegistry unregister(WebDriverEventListener eventListener) {
eventDriver.unregister(eventListener);
return this;
}
/**
* Register a new event listener.
*
* @param eventListener event listener to register
* @return {@code this} to chain method calls
*/
public EventsRegistry register(EventListener eventListener) {
eventDriver.register(new EventAdapter(eventListener, instantiator));
return this;
}
/**
* Unregister an existing event listener.
*
* @param eventListener existing event listener to unregister
* @return {@code this} to chain method calls
*/
public EventsRegistry unregister(EventListener eventListener) {
eventDriver.unregister(new EventAdapter(eventListener, instantiator));
return this;
}
/**
* Unregister all event listeners.
*/
public void close() {
unregister(support);
}
@Override
public WebDriver getWrappedDriver() {
return eventDriver.getWrappedDriver();
}
/**
* Add a listener that will be invoked before navigating to an url.
*
* @param listener listener invoked before navigating to an url.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeNavigateTo(NavigateToListener listener) {
beforeNavigateTo.add(listener);
return this;
}
/**
* Add a listener that will be invoked after navigation.
*
* @param listener listener invoked after navigation.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterNavigateTo(NavigateToListener listener) {
afterNavigateTo.add(listener);
return this;
}
/**
* Add a listener that will be invoked before navigating back.
*
* @param listener listener invoked before navigating back.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeNavigateBack(NavigateListener listener) {
beforeNavigateBack.add(listener);
return this;
}
/**
* Add a listener that will be invoked after navigating back.
*
* @param listener listener invoked after navigating back.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterNavigateBack(NavigateListener listener) {
afterNavigateBack.add(listener);
return this;
}
/**
* Add a listener that will be invoked before navigating forward.
*
* @param listener listener invoked before navigating forward.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeNavigateForward(NavigateListener listener) {
beforeNavigateForward.add(listener);
return this;
}
/**
* Add a listener that will be invoked after navigating forward.
*
* @param listener listener invoked after navigating forward.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterNavigateForward(NavigateListener listener) {
afterNavigateForward.add(listener);
return this;
}
/**
* Add a listener that will be invoked before navigating.
*
* @param listener listener invoked before navigating.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeNavigate(NavigateAllListener listener) {
beforeNavigate.add(listener);
return this;
}
/**
* Add a listener that will be invoked after navigating.
*
* @param listener listener invoked after navigating.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterNavigate(NavigateAllListener listener) {
afterNavigate.add(listener);
return this;
}
/**
* Add a listener that will be invoked before refresh.
*
* @param listener listener invoked before refresh.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeNavigateRefresh(NavigateListener listener) {
beforeNavigateRefresh.add(listener);
return this;
}
/**
* Add a listener that will be invoked after refresh.
*
* @param listener listener invoked after refresh.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterNavigateRefresh(NavigateListener listener) {
afterNavigateRefresh.add(listener);
return this;
}
/**
* Add a listener that will be invoked before finding an element.
*
* @param listener listener invoked before finding an element.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeFindBy(FindByListener listener) {
beforeFindBy.add(listener);
return this;
}
/**
* Add a listener that will be invoked after finding an element.
*
* @param listener listener invoked after finding an element.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterFindBy(FindByListener listener) {
afterFindBy.add(listener);
return this;
}
/**
* Add a listener that will be invoked before clicking an element.
*
* @param listener listener invoked before clicking an element.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeClickOn(ElementListener listener) {
beforeClickOn.add(listener);
return this;
}
/**
* Add a listener that will be invoked after clicking an element.
*
* @param listener listener invoked after clicking an element.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterClickOn(ElementListener listener) {
afterClickOn.add(listener);
return this;
}
/**
* Add a listener that will be invoked before changing value of an element.
*
* @param listener listener invoked before changing value of an element.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeChangeValueOf(ElementListener listener) {
beforeChangeValueOf.add(listener);
return this;
}
/**
* Add a listener that will be invoked after changing value of an element.
*
* @param listener listener invoked after changing value of an element.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterChangeValueOf(ElementListener listener) {
afterChangeValueOf.add(listener);
return this;
}
/**
* Add a listener that will be invoked before executing a script.
*
* @param listener listener invoked before executing a script.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeScript(ScriptListener listener) {
beforeScript.add(listener);
return this;
}
/**
* Add a listener that will be invoked after executing a script.
*
* @param listener listener invoked after executing a script.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterScript(ScriptListener listener) {
afterScript.add(listener);
return this;
}
/**
* Add a listener that will be invoked before an alert is accepted.
*
* @param listener listener invoked before an alert is accepted.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeAlertAccept(AlertListener listener) {
beforeAlertAccept.add(listener);
return this;
}
/**
* Add a listener that will be invoked after an alert is accepted.
*
* @param listener listener invoked after an alert is accepted.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterAlertAccept(AlertListener listener) {
afterAlertAccept.add(listener);
return this;
}
/**
* Add a listener that will be invoked before an alert is dismissed.
*
* @param listener listener invoked before an alert is dismissed.
* @return {@code this} to chain method calls
*/
public EventsRegistry beforeAlertDismiss(AlertListener listener) {
beforeAlertDismiss.add(listener);
return this;
}
/**
* Add a listener that will be invoked after an alert is dismissed.
*
* @param listener listener invoked after an alert is dismissed.
* @return {@code this} to chain method calls
*/
public EventsRegistry afterAlertDismiss(AlertListener listener) {
afterAlertDismiss.add(listener);
return this;
}
/**
* Add a listener that will be invoked after an exception occurred.
*
* @param listener listener invoked after an exception occurred.
* @return {@code this} to chain method calls
*/
public EventsRegistry onException(ExceptionListener listener) {
onException.add(listener);
return this;
}
/**
* Sort listeners based on priority.
*
* @see ListenerPriorityComparator
*/
protected void sortListeners() {
ListenerPriorityComparator comparator = new ListenerPriorityComparator();
Collections.sort(beforeNavigateTo, comparator);
Collections.sort(afterNavigateTo, comparator);
Collections.sort(beforeNavigateBack, comparator);
Collections.sort(afterNavigateBack, comparator);
Collections.sort(beforeNavigateForward, comparator);
Collections.sort(afterNavigateForward, comparator);
Collections.sort(beforeNavigate, comparator);
Collections.sort(afterNavigate, comparator);
Collections.sort(beforeNavigateRefresh, comparator);
Collections.sort(afterNavigateRefresh, comparator);
Collections.sort(beforeFindBy, comparator);
Collections.sort(afterFindBy, comparator);
Collections.sort(beforeClickOn, comparator);
Collections.sort(afterClickOn, comparator);
Collections.sort(beforeChangeValueOf, comparator);
Collections.sort(afterChangeValueOf, comparator);
Collections.sort(beforeScript, comparator);
Collections.sort(afterScript, comparator);
Collections.sort(onException, comparator);
}
/**
* Unregister all listeners attached to a given container.
*
* @param container container
*/
public void unregisterContainer(Object container) {
unregisterContainer(beforeNavigateTo, container);
unregisterContainer(afterNavigateTo, container);
unregisterContainer(beforeNavigateBack, container);
unregisterContainer(afterNavigateBack, container);
unregisterContainer(beforeNavigateForward, container);
unregisterContainer(afterNavigateForward, container);
unregisterContainer(beforeNavigate, container);
unregisterContainer(afterNavigate, container);
unregisterContainer(beforeNavigateRefresh, container);
unregisterContainer(afterNavigateRefresh, container);
unregisterContainer(beforeFindBy, container);
unregisterContainer(afterFindBy, container);
unregisterContainer(beforeClickOn, container);
unregisterContainer(afterClickOn, container);
unregisterContainer(beforeChangeValueOf, container);
unregisterContainer(afterChangeValueOf, container);
unregisterContainer(beforeScript, container);
unregisterContainer(afterScript, container);
unregisterContainer(onException, container);
}
private void unregisterContainer(Iterable iterable, Object container) {
Iterator<?> iterator = iterable.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
if (next instanceof ContainerListener && next == container) { // NOPMD CompareObjectsWithEquals
iterator.remove();
}
}
}
}