Skip to content

Commit

Permalink
Implement more sophisticated matching in ActiveSessionFactory
Browse files Browse the repository at this point in the history
Primarily because we want to tell the difference between
geckodriver and xpidriver.
  • Loading branch information
shs96c committed Aug 2, 2017
1 parent c87c0ea commit f0ec7d9
Showing 1 changed file with 71 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
package org.openqa.selenium.remote.server;

import static org.openqa.selenium.remote.BrowserType.CHROME;
import static org.openqa.selenium.remote.BrowserType.EDGE;
import static org.openqa.selenium.remote.BrowserType.FIREFOX;
import static org.openqa.selenium.remote.BrowserType.IE;
import static org.openqa.selenium.remote.BrowserType.SAFARI;
import static org.openqa.selenium.remote.CapabilityType.BROWSER_NAME;
import static org.openqa.selenium.remote.DesiredCapabilities.chrome;
import static org.openqa.selenium.remote.DesiredCapabilities.edge;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
Expand All @@ -27,7 +21,10 @@
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.function.Predicate;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
Expand All @@ -37,89 +34,99 @@ public class ActiveSessionFactory {

private final static Logger LOG = Logger.getLogger(ActiveSessionFactory.class.getName());

private final Map<String, SessionFactory> factories;
private final static Predicate<String> CLASS_EXISTS = name -> {
try {
Class.forName(name);
return true;
} catch (ClassNotFoundException cnfe) {
return false;
}
};

private final Map<Predicate<Capabilities>, SessionFactory> factories;

public ActiveSessionFactory() {
Map<String, SessionFactory> builder = new LinkedHashMap<>();

ImmutableMap.<String, String>builder()
.put(chrome().getBrowserName(), "org.openqa.selenium.chrome.ChromeDriverService")
.put(edge().getBrowserName(), "org.openqa.selenium.edge.EdgeDriverService")
.put(firefox().getBrowserName(), "org.openqa.selenium.firefox.GeckoDriverService")
.put(internetExplorer().getBrowserName(), "org.openqa.selenium.ie.InternetExplorerDriverService")
.put(opera().getBrowserName(), "org.openqa.selenium.opera.OperaDriverService")
.put(operaBlink().getBrowserName(), "org.openqa.selenium.ie.OperaDriverService")
.put(phantomjs().getBrowserName(), "org.openqa.selenium.phantomjs.PhantomJSDriverService")
.put(safari().getBrowserName(), "org.openqa.selenium.safari.SafariDriverService")
Map<Predicate<Capabilities>, SessionFactory> builder = new LinkedHashMap<>();

ImmutableMap.<Predicate<Capabilities>, String>builder()
.put(browserName(chrome()), "org.openqa.selenium.chrome.ChromeDriverService")
.put(containsKey("chromeOptions"), "org.openqa.selenium.chrome.ChromeDriverService")
.put(browserName(edge()), "org.openqa.selenium.edge.EdgeDriverService")
.put(containsKey("edgeOptions"), "org.openqa.selenium.edge.EdgeDriverService")
.put(browserName(firefox()), "org.openqa.selenium.firefox.GeckoDriverService")
.put(containsKey(Pattern.compile("^moz:.*")), "org.openqa.selenium.firefox.GeckoDriverService")
.put(browserName(internetExplorer()), "org.openqa.selenium.ie.InternetExplorerDriverService")
.put(containsKey("se:ieOptions"), "org.openqa.selenium.ie.InternetExplorerDriverService")
.put(browserName(opera()), "org.openqa.selenium.opera.OperaDriverService")
.put(browserName(operaBlink()), "org.openqa.selenium.ie.OperaDriverService")
.put(browserName(phantomjs()), "org.openqa.selenium.phantomjs.PhantomJSDriverService")
.put(browserName(safari()), "org.openqa.selenium.safari.SafariDriverService")
.put(containsKey(Pattern.compile("^safari\\..*")), "org.openqa.selenium.safari.SafariDriverService")
.build()
.entrySet().stream()
.filter(e -> {
try {
Class.forName(e.getValue());
return true;
} catch (ClassNotFoundException cnfe) {
return false;
}
})
.filter(e -> CLASS_EXISTS.test(e.getValue()))
.forEach(e -> builder.put(e.getKey(), new ServicedSession.Factory(e.getValue())));

// Attempt to bind the htmlunitdriver if it's present.
try {
Class<? extends WebDriver> clazz = Class.forName("org.openqa.selenium.htmlunit.HtmlUnitDriver")
Class<? extends WebDriver>
clazz =
Class.forName("org.openqa.selenium.htmlunit.HtmlUnitDriver")
.asSubclass(WebDriver.class);
builder.put(
htmlUnit().getBrowserName(),
browserName(htmlUnit()),
new InMemorySession.Factory(new DefaultDriverProvider(htmlUnit(), clazz)));
} catch (ReflectiveOperationException ignored) {
// Just carry on. Everything is fine.
}

// Allow user-defined factories to override default ones
StreamSupport.stream(ServiceLoader.load(DriverProvider.class).spliterator(), false)
.forEach(p -> builder.put(p.getProvidedCapabilities().getBrowserName(), new InMemorySession.Factory(p)));
.forEach(p -> builder
.put(browserName(p.getProvidedCapabilities()), new InMemorySession.Factory(p)));

// Finally, add a default factory.
Stream.of(
"org.openqa.selenium.chrome.ChromeDriverService",
"org.openqa.selenium.firefox.GeckoDriverService",
"org.openqa.selenium.edge.EdgeDriverService",
"org.openqa.selenium.ie.InternetExplorerDriverService",
"org.openqa.selenium.safari.SafariDriverService")
.filter(CLASS_EXISTS)
.findFirst()
.ifPresent(
serviceName -> {
LOG.info("Binding default provider to: " + serviceName);
builder.put(ignored -> true, new ServicedSession.Factory(serviceName));
});

this.factories = ImmutableMap.copyOf(builder);
}

private static Predicate<Capabilities> browserName(Capabilities caps) {
return toCompare -> caps.getBrowserName().equals(toCompare.getBrowserName());
}

private static Predicate<Capabilities> containsKey(String keyName) {
Objects.requireNonNull(keyName, "Key name must be set");
return toCompare -> toCompare.getCapability(keyName) != null;
}

private static Predicate<Capabilities> containsKey(Pattern pattern) {
return toCompare -> toCompare.asMap().keySet().stream().anyMatch(pattern.asPredicate());
}

public ActiveSession createSession(NewSessionPayload newSessionPayload) throws IOException {
return newSessionPayload.stream()
.map(this::determineBrowser)
.filter(Objects::nonNull)
.map(factory -> factory.apply(newSessionPayload))
.filter(Objects::nonNull)
.peek(caps -> LOG.info("Capabilities are: " + caps))
// Grab any factories that claim to be able to build each capability
.flatMap(caps -> factories.entrySet().stream()
.filter(e -> e.getKey().test(caps))
.peek(e -> LOG.info(String.format("%s matched %s", caps, e.getValue())))
.map(Map.Entry::getValue))
.findFirst()
.map(factory -> factory.apply(newSessionPayload))
.orElseThrow(() -> new SessionNotCreatedException(
"Unable to create a new session because of no configuration."));
}

private SessionFactory determineBrowser(Capabilities caps) {
return caps.asMap().entrySet().stream()
.map(entry -> guessBrowserName(entry.getKey(), entry.getValue()))
.filter(factories.keySet()::contains)
.map(factories::get)
.findFirst()
.orElse(null);
}

private String guessBrowserName(String capabilityKey, Object value) {
if (BROWSER_NAME.equals(capabilityKey)) {
return (String) value;
}
if ("chromeOptions".equals(capabilityKey)) {
return CHROME;
}
if ("edgeOptions".equals(capabilityKey)) {
return EDGE;
}
if (capabilityKey.startsWith("moz:")) {
return FIREFOX;
}
if (capabilityKey.startsWith("safari.")) {
return SAFARI;
}
if ("se:ieOptions".equals(capabilityKey)) {
return IE;
}
return null;
}
}

0 comments on commit f0ec7d9

Please sign in to comment.