All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.nscuro.wdm.binary.edge.MicrosoftWebDriverBinaryProvider Maven / Gradle / Ivy

There is a newer version: 0.3.0
Show newest version
package com.github.nscuro.wdm.binary.edge;

import com.github.nscuro.wdm.Architecture;
import com.github.nscuro.wdm.Browser;
import com.github.nscuro.wdm.Os;
import com.github.nscuro.wdm.binary.BinaryProvider;
import com.github.nscuro.wdm.binary.util.MimeType;
import com.github.nscuro.wdm.binary.util.VersionComparator;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.github.nscuro.wdm.binary.util.HttpUtils.verifyContentTypeIsAnyOf;
import static com.github.nscuro.wdm.binary.util.HttpUtils.verifyStatusCodeIsAnyOf;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

/**
 * A {@link BinaryProvider} for Microsoft's WebDriver implementation.
 *
 * @see Microsoft WebDriver homepage
 * @since 0.2.0
 */
public class MicrosoftWebDriverBinaryProvider implements BinaryProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(MicrosoftWebDriverBinaryProvider.class);

    private static final Pattern VERSION_PATTERN = Pattern.compile("Version: ([0-9|.]+) \\|.*");

    private final HttpClient httpClient;

    private final String binaryDownloadPageUrl;

    public MicrosoftWebDriverBinaryProvider(final HttpClient httpClient) {
        this(requireNonNull(httpClient, "no HttpClient provided"),
                "https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/");
    }

    MicrosoftWebDriverBinaryProvider(final HttpClient httpClient, final String binaryDownloadPageUrl) {
        this.httpClient = httpClient;
        this.binaryDownloadPageUrl = binaryDownloadPageUrl;
    }

    /**
     * {@inheritDoc}
     *
     * @return {@code false} for every {@link Browser} except {@link Browser#EDGE},
     *         in which case {@code true} is returned
     */
    @Override
    public boolean providesBinaryForBrowser(final Browser browser) {
        return Browser.EDGE == browser;
    }

    /**
     * {@inheritDoc}
     *
     * @return {@link Optional#empty()} for every {@link Os} except {@link Os#WINDOWS},
     *         in which case the latest binary version is returned
     */
    @Nonnull
    @Override
    public Optional getLatestBinaryVersion(final Os os, final Architecture architecture) throws IOException {
        if (os != Os.WINDOWS) {
            LOGGER.warn("Microsoft WebDriver is only supported on Windows systems");
            return Optional.empty();
        }

        return getAvailableReleases()
                .stream()
                .map(MicrosoftWebDriverRelease::getVersion)
                .max(new VersionComparator());
    }

    /**
     * {@inheritDoc}
     *
     * @throws UnsupportedOperationException When requesting an {@link Os} other than {@link Os#WINDOWS}
     * @throws NoSuchElementException        When no binary is available for the requested version
     */
    @Nonnull
    @Override
    public File download(final String version, final Os os, final Architecture architecture, final Path binaryDestinationPath) throws IOException {
        if (os != Os.WINDOWS) {
            throw new UnsupportedOperationException("Microsoft WebDriver is only supported on Windows systems");
        }

        final MicrosoftWebDriverRelease matchingRelease = getAvailableReleases()
                .stream()
                .filter(release -> release.getVersion().equals(version))
                .findAny()
                .orElseThrow(NoSuchElementException::new);

        return httpClient.execute(new HttpGet(matchingRelease.getDownloadUrl()), httpResponse -> {
            verifyStatusCodeIsAnyOf(httpResponse, HttpStatus.SC_OK);
            verifyContentTypeIsAnyOf(httpResponse, MimeType.APPLICATION_OCTET_STREAM);

            final File binaryDestinationFile = binaryDestinationPath.toFile();

            try (final FileOutputStream fileOutputStream = new FileOutputStream(binaryDestinationFile)) {
                Optional
                        .ofNullable(httpResponse.getEntity())
                        .orElseThrow(() -> new IOException(format("Response body is empty. Response was:\n%s", httpResponse)))
                        .writeTo(fileOutputStream);
            }

            return binaryDestinationFile;
        });
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(Browser.EDGE);
    }

    @Override
    public boolean equals(final Object otherObject) {
        if (otherObject == null) {
            return false;
        } else if (otherObject == this) {
            return true;
        } else if (!BinaryProvider.class.isInstance(otherObject)) {
            return false;
        }

        return ((BinaryProvider) otherObject).providesBinaryForBrowser(Browser.EDGE);
    }

    @Nonnull
    private List getAvailableReleases() throws IOException {
        final List availableReleases = new ArrayList<>();

        return httpClient.execute(new HttpGet(binaryDownloadPageUrl), httpResponse -> {
            try (final InputStream inputStream = httpResponse.getEntity().getContent()) {
                final Document document = Jsoup.parse(inputStream, StandardCharsets.UTF_8.name(), binaryDownloadPageUrl);

                document.select("li.driver-download").forEach(releaseElement -> {
                    final Optional downloadUrl = Optional
                            .ofNullable(releaseElement.selectFirst("a"))
                            .map(linkElement -> linkElement.attr("href"));

                    final Optional downloadMeta = Optional
                            .ofNullable(releaseElement.selectFirst("p.driver-download__meta"))
                            .map(Element::text);

                    if (downloadUrl.isPresent() && downloadMeta.isPresent()) {
                        final Matcher versionMatcher = VERSION_PATTERN.matcher(downloadMeta.get());

                        if (!versionMatcher.matches()) {
                            LOGGER.warn("Unable to parse version from \"{}\"", downloadMeta.get());
                        } else {
                            availableReleases.add(new MicrosoftWebDriverRelease(versionMatcher.group(1), downloadUrl.get()));
                        }
                    }
                });
            }

            return availableReleases;
        });
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy