net.javacrumbs.webview.driver.Browser.java Source code

Java tutorial

Introduction

Here is the source code for net.javacrumbs.webview.driver.Browser.java

Source

/**
 * Copyright 2009-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.javacrumbs.webview.driver;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.FindsById;
import org.openqa.selenium.internal.FindsByXPath;
import org.w3c.dom.Node;

import javax.swing.*;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.awt.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;

class Browser extends JFrame implements SearchContext, FindsById, FindsByXPath {
    private final JFXPanel jfxPanel = new JFXPanel();
    private WebEngine engine;

    private final JPanel panel = new JPanel(new BorderLayout());
    private CountDownLatch latch = new CountDownLatch(1);

    public Browser() {
        super();
        initComponents();
        setVisible(true);
    }

    private void initComponents() {
        createScene();

        panel.add(jfxPanel, BorderLayout.CENTER);

        getContentPane().add(panel);

        setPreferredSize(new Dimension(1024, 600));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
    }

    /**
     * Waits for the URI to be loaded.
     *
     * @param url
     */
    public void loadURL(final String url) {
        WaitListener waitListener = new WaitListener();
        Platform.runLater(() -> {
            waitListener.register(engine);
            String tmp = toURL(url);

            if (url == null) {
                tmp = toURL("http://" + url);
            }
            engine.load(tmp);
        });
        waitListener.waitForIt();
        Platform.runLater(() -> waitListener.unregister(engine));
    }

    private static String toURL(String str) {
        try {
            return new URL(str).toExternalForm();
        } catch (MalformedURLException exception) {
            return null;
        }
    }

    private void createScene() {
        Platform.runLater(() -> {
            WebView view = new WebView();
            engine = view.getEngine();

            engine.titleProperty().addListener((observable, oldValue, newValue) -> {
                SwingUtilities.invokeLater(() -> {
                    Browser.this.setTitle(newValue);
                });
            });

            engine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
                System.out.println("webEngine result " + newState.toString());
            });
            StackPane root = new StackPane();
            root.getChildren().add(view);
            Scene scene = new Scene(root, 1200, 800);
            jfxPanel.setScene(scene);
        });
    }

    @Override
    public List<WebElement> findElements(By by) {
        return by.findElements(this);
    }

    public WebElement findElement(By by) {
        return by.findElement(this);
    }

    @Override
    public WebElement findElementById(String using) {
        return new NodeWebElement(engine.getDocument().getElementById(using));
    }

    @Override
    public List<WebElement> findElementsById(String using) {
        throw new UnsupportedOperationException();
    }

    @Override
    public WebElement findElementByXPath(String using) {
        try {
            XPath xPath = XPathFactory.newInstance().newXPath();
            Node node = (Node) xPath.evaluate(using, engine.getDocument(), XPathConstants.NODE);
            return new NodeWebElement(node);
        } catch (XPathExpressionException e) {
            //FIXME
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<WebElement> findElementsByXPath(String using) {
        return null;
    }

    private static final class WaitListener implements ChangeListener<Worker.State> {
        private static final Set<Worker.State> END_STATES = EnumSet.of(Worker.State.SUCCEEDED,
                Worker.State.CANCELLED, Worker.State.FAILED);
        private final CountDownLatch latch = new CountDownLatch(1);

        private void register(WebEngine engine) {
            engine.getLoadWorker().stateProperty().addListener(this);
        }

        private void unregister(WebEngine engine) {
            engine.getLoadWorker().stateProperty().removeListener(this);
        }

        @Override
        public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue,
                Worker.State newValue) {
            if (END_STATES.contains(newValue)) {
                latch.countDown();
            }
        }

        public void waitForIt() {
            try {
                latch.await();
            } catch (InterruptedException e) {
                //FIXME
                throw new RuntimeException(e);
            }
        }
    }
}