com.ariatemplates.seleniumjavarobot.executor.Executor.java Source code

Java tutorial

Introduction

Here is the source code for com.ariatemplates.seleniumjavarobot.executor.Executor.java

Source

/*
 * Copyright 2014 Amadeus s.a.s.
 * 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 com.ariatemplates.seleniumjavarobot.executor;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.IOUtils;
import org.openqa.selenium.NoSuchWindowException;
import org.openqa.selenium.Point;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UnhandledAlertException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.UnreachableBrowserException;

import com.ariatemplates.seleniumjavarobot.IBrowser;
import com.ariatemplates.seleniumjavarobot.IRobot;
import com.ariatemplates.seleniumjavarobot.RobotizedBrowser;
import com.ariatemplates.seleniumjavarobot.SeleniumJavaRobot;

public class Executor {
    private static final String EXECUTOR_SCRIPT;
    static {
        try {
            EXECUTOR_SCRIPT = IOUtils.toString(Executor.class.getResource("executor.js"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static interface Method {
        Object run(Executor executor, List<Object> arguments) throws InterruptedException;
    }

    private static int toInt(Object value) {
        return ((Number) value).intValue();
    }

    private static final Map<String, Method> methods;
    static {
        methods = new HashMap<String, Executor.Method>();
        methods.put("mouseMove", new Method() {
            public Object run(Executor executor, List<Object> arguments) {
                int x = toInt(arguments.get(0));
                int y = toInt(arguments.get(1));
                executor.robot.mouseMove(x, y);
                return null;
            }
        });

        methods.put("smoothMouseMove", new Method() {
            public Object run(Executor executor, List<Object> arguments) throws InterruptedException {
                int fromX = toInt(arguments.get(0));
                int fromY = toInt(arguments.get(1));
                int toX = toInt(arguments.get(2));
                int toY = toInt(arguments.get(3));
                int duration = toInt(arguments.get(4));
                SmoothMouseMove.smoothMouseMove(executor.robot, fromX, fromY, toX, toY, duration);
                return null;
            }
        });

        methods.put("mousePress", new Method() {
            public Object run(Executor executor, List<Object> arguments) {
                int buttons = toInt(arguments.get(0));
                executor.robot.mousePress(buttons);
                return null;
            }
        });

        methods.put("mouseRelease", new Method() {
            public Object run(Executor executor, List<Object> arguments) {
                int buttons = toInt(arguments.get(0));
                executor.robot.mouseRelease(buttons);
                return null;
            }
        });

        methods.put("mouseWheel", new Method() {
            public Object run(Executor executor, List<Object> arguments) {
                int amount = toInt(arguments.get(0));
                executor.robot.mouseWheel(amount);
                return null;
            }
        });

        methods.put("keyPress", new Method() {
            public Object run(Executor executor, List<Object> arguments) {
                int keyCode = toInt(arguments.get(0));
                executor.robot.keyPress(keyCode);
                return null;
            }
        });

        methods.put("keyRelease", new Method() {
            public Object run(Executor executor, List<Object> arguments) {
                int keyCode = toInt(arguments.get(0));
                executor.robot.keyRelease(keyCode);
                return null;
            }
        });

        methods.put("getOffset", new Method() {
            public Object run(Executor executor, List<Object> arguments) {
                Point point = executor.driver.getWindowPosition();
                Map<String, Number> map = new HashMap<String, Number>();
                map.put("x", executor.offset.x + point.x);
                map.put("y", executor.offset.y + point.y);
                return map;
            }
        });

    }

    private static final Map<String, String> knownExceptions;
    static {
        knownExceptions = new HashMap<String, String>();

        // Exceptions when DevTools are opened in Chrome:
        // this one (what's after "disconnected: " may vary) happens at the time
        // the DevTools are opened
        knownExceptions.put("disconnected: ",
                "DevTools are opened. The Selenium Java Robot is paused until DevTools are closed. For easier debugging, please use: --browser chrome-debug");
        // the following one happens for each call until the DevTools are
        // closed:
        knownExceptions.put(
                "unknown error: Runtime.evaluate threw exception: TypeError: Cannot read property 'click' of null",
                null);

        // Exceptions when unloading the page:
        String unloadingPage = "Page was unloaded.";
        knownExceptions.put("javascript error: document unloaded", unloadingPage); // Chrome
        knownExceptions.put("Detected a page unload event", unloadingPage); // Firefox
        knownExceptions.put("Page reload detected", unloadingPage); // IE
    }

    private static final boolean handleException(WebDriverException exception) {
        String message = exception.getMessage();
        for (Entry<String, String> entry : knownExceptions.entrySet()) {
            if (message.startsWith(entry.getKey())) {
                String replacementMessage = entry.getValue();
                if (replacementMessage != null) {
                    SeleniumJavaRobot.log(replacementMessage);
                }
                return true;
            }
        }
        return false;
    }

    private final RobotizedBrowser robotizedBrowser;
    private final IRobot robot;
    private final IBrowser driver;
    private Point offset;

    public Executor(RobotizedBrowser robotizedBrowser, Point offset) {
        this.robotizedBrowser = robotizedBrowser;
        this.robot = robotizedBrowser.robot;
        this.driver = robotizedBrowser.browser;
        this.offset = offset;
    }

    public void run() throws InterruptedException {
        driver.setScriptTimeout(1, TimeUnit.SECONDS);
        boolean expectsStatus = true;
        while (true) {
            try {
                if (robotizedBrowser.isStopped()) {
                    return;
                }
                @SuppressWarnings("unchecked")
                Map<String, Object> curCall = (Map<String, Object>) driver.executeAsyncScript(EXECUTOR_SCRIPT,
                        expectsStatus);
                if (expectsStatus) {
                    expectsStatus = false;
                    SeleniumJavaRobot.log("The Selenium Java Robot is now enabled in the current page.");
                }
                if (curCall != null) {
                    executeCall(curCall);
                }
            } catch (TimeoutException e) {
                continue;
            } catch (UnhandledAlertException e) {
                SeleniumJavaRobot.log("Alert in the page: " + e.getAlertText());
                continue;
            } catch (UnreachableBrowserException e) {
                SeleniumJavaRobot.log("The browser exited.");
                return;
            } catch (NoSuchWindowException e) {
                SeleniumJavaRobot.log("The browser window was closed.");
                return;
            } catch (WebDriverException e) {
                if (handleException(e)) {
                    Thread.sleep(100);
                } else {
                    System.err.println(e);
                    if (expectsStatus) {
                        return;
                    }
                }
                expectsStatus = true;
                continue;
            } catch (RuntimeException e) {
                System.err.println(e);
                return;
            }
        }
    }

    private void executeCall(Map<String, Object> curCall) throws InterruptedException {
        try {
            String curEventName = (String) curCall.get("name");
            String id = (String) curCall.get("id");
            @SuppressWarnings("unchecked")
            List<Object> args = (List<Object>) curCall.get("args");
            Method curMethod = methods.get(curEventName);
            SeleniumJavaRobot.log(String.format("Executing %s (%s)", curEventName, args));
            Object result;
            boolean success = false;
            try {
                result = curMethod.run(this, args);
                success = true;
            } catch (RuntimeException e) {
                result = e.toString();
            }
            synchronized (robotizedBrowser) {
                driver.executeScript(
                        "try { window.SeleniumJavaRobot.__callback(arguments[0], arguments[1], arguments[2]); } catch(e){}",
                        id, success, result);
            }
        } catch (RuntimeException e) {
            System.err.println(e);
        }
    }
}