Skip to content

Commit

Permalink
Add Component Manager and Events annotation support.
Browse files Browse the repository at this point in the history
  • Loading branch information
Toilal committed Aug 23, 2016
1 parent 2d3fdaa commit 17830df
Show file tree
Hide file tree
Showing 67 changed files with 2,436 additions and 298 deletions.
281 changes: 185 additions & 96 deletions README.md

Large diffs are not rendered by default.

Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import org.fluentlenium.configuration.WebDrivers; import org.fluentlenium.configuration.WebDrivers;
import org.fluentlenium.core.FluentDriver; import org.fluentlenium.core.FluentDriver;
import org.fluentlenium.core.FluentDriverControl; import org.fluentlenium.core.FluentDriverControl;
import org.fluentlenium.core.components.ComponentException;
import org.fluentlenium.core.components.ComponentsManager;
import org.fluentlenium.core.components.Components;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.events.EventFiringWebDriver; import org.openqa.selenium.support.events.EventFiringWebDriver;


Expand Down Expand Up @@ -83,7 +86,9 @@ public void initFluent(WebDriver webDriver) {
} }
} }


FluentDriver fluentDriver = new FluentDriver(webDriver, this); ComponentsManager componentsManager = Components.INSTANCE.getOrCreate(webDriver);

FluentDriver fluentDriver = new FluentDriver(webDriver, this, componentsManager);
setFluentDriver(fluentDriver); setFluentDriver(fluentDriver);
fluentDriver.inject(this); fluentDriver.inject(this);
} }
Expand All @@ -96,6 +101,7 @@ public void initFluent(WebDriver webDriver) {
public void releaseFluent() { public void releaseFluent() {
if (getFluentDriver() != null) { if (getFluentDriver() != null) {
getFluentDriver().releaseFluent(); getFluentDriver().releaseFluent();
Components.INSTANCE.release(getFluentDriver().getDriver());
setFluentDriver(null); setFluentDriver(null);
} }
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import org.fluentlenium.core.action.KeyboardActions; import org.fluentlenium.core.action.KeyboardActions;
import org.fluentlenium.core.action.MouseActions; import org.fluentlenium.core.action.MouseActions;
import org.fluentlenium.core.alert.Alert; import org.fluentlenium.core.alert.Alert;
import org.fluentlenium.core.components.ComponentsManager;
import org.fluentlenium.core.domain.FluentList; import org.fluentlenium.core.domain.FluentList;
import org.fluentlenium.core.domain.FluentWebElement; import org.fluentlenium.core.domain.FluentWebElement;
import org.fluentlenium.core.events.EventsRegistry; import org.fluentlenium.core.events.EventsRegistry;
import org.fluentlenium.core.events.AnnotationsComponentListener;
import org.fluentlenium.core.filter.Filter; import org.fluentlenium.core.filter.Filter;
import org.fluentlenium.core.inject.FluentInjector; import org.fluentlenium.core.inject.FluentInjector;
import org.fluentlenium.core.script.FluentJavascript; import org.fluentlenium.core.script.FluentJavascript;
Expand Down Expand Up @@ -42,8 +44,12 @@ public class FluentDriver implements FluentDriverControl {


private ConfigurationProperties configuration; private ConfigurationProperties configuration;


private final ComponentsManager componentsManager;

private EventsRegistry events; private EventsRegistry events;


private AnnotationsComponentListener eventsComponentsAnnotations;

@Delegate @Delegate
private FluentInjector fluentInjector; private FluentInjector fluentInjector;


Expand All @@ -54,10 +60,13 @@ public class FluentDriver implements FluentDriverControl {
private MouseActions mouseActions; private MouseActions mouseActions;


private KeyboardActions keyboardActions; private KeyboardActions keyboardActions;
;


public FluentDriver(WebDriver driver, ConfigurationProperties configuration) { public FluentDriver(WebDriver driver, ConfigurationProperties configuration, ComponentsManager componentsManager) {
initFluent(driver);
this.configuration = configuration; this.configuration = configuration;
this.componentsManager = componentsManager;

initFluent(driver);
configureDriver(); configureDriver();
} }


Expand Down Expand Up @@ -98,13 +107,15 @@ private void configureDriver() {


protected FluentDriver initFluent(WebDriver driver) { protected FluentDriver initFluent(WebDriver driver) {
this.driver = driver; this.driver = driver;
this.search = new Search(driver); this.search = new Search(driver, componentsManager);
if (driver instanceof EventFiringWebDriver) { if (driver instanceof EventFiringWebDriver) {
this.events = new EventsRegistry((EventFiringWebDriver) driver); this.events = new EventsRegistry((EventFiringWebDriver) driver);
this.eventsComponentsAnnotations = new AnnotationsComponentListener(componentsManager);
this.events.register(this.eventsComponentsAnnotations);
} }
this.mouseActions = new MouseActions(driver); this.mouseActions = new MouseActions(driver);
this.keyboardActions = new KeyboardActions(driver); this.keyboardActions = new KeyboardActions(driver);
this.fluentInjector = new FluentInjector(this); this.fluentInjector = new FluentInjector(this, componentsManager);
inject(this); inject(this);
return this; return this;
} }
Expand Down Expand Up @@ -469,5 +480,8 @@ public void quit() {


public void releaseFluent() { public void releaseFluent() {
fluentInjector.release(); fluentInjector.release();
if (this.events != null) {
this.events.unregister(this.eventsComponentsAnnotations);
}
} }
} }
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.fluentlenium.core.axes; package org.fluentlenium.core.axes;


import org.fluentlenium.core.components.ComponentInstantiator;
import org.fluentlenium.core.domain.FluentList; import org.fluentlenium.core.domain.FluentList;
import org.fluentlenium.core.domain.FluentListImpl; import org.fluentlenium.core.domain.FluentListImpl;
import org.fluentlenium.core.domain.FluentWebElement; import org.fluentlenium.core.domain.FluentWebElement;
Expand All @@ -14,14 +15,13 @@
* Handles XPath axes for an element (http://www.w3schools.com/xsl/xpath_axes.asp) * Handles XPath axes for an element (http://www.w3schools.com/xsl/xpath_axes.asp)
*/ */
public class Axes { public class Axes {

private final WebDriver driver;
private final WebElement webElement; private final WebElement webElement;
private final ComponentInstantiator instantiator;




public Axes(WebDriver driver, WebElement element) { public Axes(WebElement element, ComponentInstantiator instantiator) {
this.driver = driver;
this.webElement = element; this.webElement = element;
this.instantiator = instantiator;
} }




Expand All @@ -32,15 +32,15 @@ public Axes(WebDriver driver, WebElement element) {
*/ */
public FluentWebElement parent() { public FluentWebElement parent() {
WebElement parentRaw = this.webElement.findElement(By.xpath("parent::*")); WebElement parentRaw = this.webElement.findElement(By.xpath("parent::*"));
FluentWebElement parent = new FluentWebElement(parentRaw, driver); FluentWebElement parent = instantiator.newComponent(FluentWebElement.class, parentRaw);
return parent; return parent;
} }


protected FluentList<FluentWebElement> handleAxe(String axe) { protected FluentList<FluentWebElement> handleAxe(String axe) {
List<WebElement> ancestorsRaw = this.webElement.findElements(By.xpath(axe + "::*")); List<WebElement> ancestorsRaw = this.webElement.findElements(By.xpath(axe + "::*"));
List<FluentWebElement> elements = new ArrayList<FluentWebElement>(); List<FluentWebElement> elements = new ArrayList<FluentWebElement>();
for (WebElement ancestor : ancestorsRaw) { for (WebElement ancestor : ancestorsRaw) {
elements.add(new FluentWebElement(ancestor, driver)); elements.add(instantiator.newComponent(FluentWebElement.class, ancestor));
} }
return new FluentListImpl<>(elements); return new FluentListImpl<>(elements);
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.fluentlenium.core.components;

import org.openqa.selenium.WebElement;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public interface ComponentAccessor {
/**
* Get the related component from the given element.
*
* @param element
*
* @return
*/
Object getComponent(WebElement element);

}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.fluentlenium.core.components;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.openqa.selenium.WebElement;

/**
* Encapsulate a component and it's WebElement.
*/
@Getter
@Setter
@AllArgsConstructor
public class ComponentBean {
public Object component;
public WebElement element;
}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.fluentlenium.core.components;

public class ComponentException extends RuntimeException
{
public ComponentException() {
super();
}

public ComponentException(String message) {
super(message);
}

public ComponentException(String message, Throwable cause) {
super(message, cause);
}

public ComponentException(Throwable cause) {
super(cause);
}
}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.fluentlenium.core.components;

import org.openqa.selenium.WebElement;

public interface ComponentInstantiator {
/**
* Create and register a new component from the given element.
*
* @param componentClass type of the component
* @param element wrapped element
* @param <T> type of the component
*
* @return new instance of the component.
*/
<T> T newComponent(Class<T> componentClass, WebElement element);

/**
* Check if this class is a component class.
*
* @param componentClass
*/
public boolean isComponentClass(Class<?> componentClass);
}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.fluentlenium.core.components;

import lombok.experimental.Delegate;
import org.openqa.selenium.WebDriver;

import java.util.IdentityHashMap;
import java.util.Map;

/**
* Manage instances of {@link ComponentsManager}.
*/
public enum Components {
INSTANCE;

@Delegate
private final Impl impl = new Impl();

static class Impl {
private Map<WebDriver, ComponentsManager> driverManagers = new IdentityHashMap<>();

/**
* Create a {@link ComponentsManager} for given {@link WebDriver}
* @param driver
* @return a new registered instance of {@link ComponentsManager}
* @throws Components if a {@link ComponentsManager} is already registered.
*/
public synchronized ComponentsManager create(WebDriver driver) {
if (driverManagers.containsKey(driver)) throw new ComponentException("This WebDriver already have a Component Manager registered.");
return createImpl(driver);
}

private ComponentsManager createImpl(WebDriver driver) {
ComponentsManager driverManager = new ComponentsManager(driver);
driverManagers.put(driver, driverManager);
return driverManager;
}

public synchronized ComponentsManager getOrCreate(WebDriver driver) {
ComponentsManager componentsManager = get(driver);
if (componentsManager == null) {
componentsManager = createImpl(driver);
}
return componentsManager;
}

/**
* Get the existing {@link ComponentsManager} for given {@link WebDriver}
* @param driver
* @return existing registered instance of {@link ComponentsManager}, or null if not found.
*/
public synchronized ComponentsManager get(WebDriver driver) {
return driverManagers.get(driver);
}

/**
* Release the existing {@link ComponentsManager} for given {@link WebDriver}
* @param driver
*/
public synchronized void release(WebDriver driver) {
ComponentsManager remove = driverManagers.remove(driver);
if (remove != null) {
remove.release();
}
}
}



}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.fluentlenium.core.components;

import com.sun.jna.WeakIdentityHashMap;
import org.fluentlenium.utils.ReflectionUtils;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.WrapsElement;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
* Manage living components for a WebDriver instance.
*
* A component is an Object implementing no particular interface, but capable a wrapping
* a {@link org.openqa.selenium.WebElement}.
*
* {@link org.fluentlenium.core.domain.FluentWebElement} is the most common component.
*/
public class ComponentsManager implements ComponentInstantiator, ComponentAccessor {

private final WebDriver driver;
private final ComponentInstantiator instantiator;

//TODO: IdentityHashMap or WeakIdentityHashMap ?
private Map<WebElement, Object> components = new WeakIdentityHashMap();

public ComponentsManager(WebDriver driver) {
this.driver = driver;
this.instantiator = new DefaultComponentInstantiator(this.driver, this);
}

public ComponentsManager(WebDriver driver, ComponentInstantiator instantiator) {
this.driver = driver;
this.instantiator = instantiator;
}

public ComponentInstantiator getInstantiator() {
return instantiator;
}

/**
* Get the related component from the given element.
*
* @param element
*
* @return
*/
public Object getComponent(WebElement element) {
return components.get(unwrapElement(element));
}

/**
* Get all the component related to this webDriver.
* @return
*/
public Collection<ComponentBean> getAllComponents() {
List<ComponentBean> allComponents = new ArrayList<>();
for (Map.Entry<WebElement, Object> entry : components.entrySet()) {
allComponents.add(new ComponentBean(entry.getValue(), entry.getKey()));
}
return allComponents;
}

@Override
public boolean isComponentClass(Class<?> componentClass) {
return instantiator.isComponentClass(componentClass);
}

@Override
public <T> T newComponent(Class<T> componentClass, WebElement element) {
try {
T component = instantiator.newComponent(componentClass, element);
components.put(unwrapElement(element), component);
return component;
} catch (Exception e) {
throw new ComponentException(componentClass.getName()
+ " is not a valid component class. No valid constructor found (WebElement) or (WebElement, WebDriver)", e);
}
}

private WebElement unwrapElement(WebElement element) {
if (element instanceof WrapsElement) {
return unwrapElement(((WrapsElement)element).getWrappedElement());
}
return element;
}

/**
* Release this manager.
*/
public void release() {
components.clear();
}
}
Loading

0 comments on commit 17830df

Please sign in to comment.