org.uiautomation.ios.server.DOMContext.java Source code

Java tutorial

Introduction

Here is the source code for org.uiautomation.ios.server.DOMContext.java

Source

/*
 * Copyright 2012 ios-driver committers.
 * 
 * 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 org.uiautomation.ios.server;

import org.json.JSONArray;
import org.json.JSONObject;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriverException;
import org.uiautomation.ios.context.BaseWebInspector;
import org.uiautomation.ios.wkrdp.RemoteExceptionException;
import org.uiautomation.ios.wkrdp.events.ChildNodeRemoved;
import org.uiautomation.ios.wkrdp.events.Event;
import org.uiautomation.ios.wkrdp.events.EventHistory;
import org.uiautomation.ios.wkrdp.events.inserted.ChildIframeInserted;
import org.uiautomation.ios.wkrdp.message.WebkitPage;
import org.uiautomation.ios.wkrdp.model.NodeId;
import org.uiautomation.ios.wkrdp.model.RemoteWebElement;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;

// TODO freynaud revisit pageLoad, reset, setFrame and newContext and expose only 1 thing.
public class DOMContext {

    private static final Logger log = Logger.getLogger(DOMContext.class.getName());

    private volatile boolean pageLoaded = false;

    private volatile boolean isReady = true;
    private NodeId parent;

    private final BaseWebInspector inspector;

    private RemoteWebElement window;
    private RemoteWebElement document;
    private RemoteWebElement iframe;

    private boolean isOnMainFrame = true;
    private RemoteWebElement mainDocument;
    private RemoteWebElement mainWindow;

    private final EventHistory eventHistory = new EventHistory();
    private List<WebkitPage> windowHandles;
    private String windowHandle;
    private String id;

    private Lock eventsLock = new ReentrantLock();
    private Condition pageLoadEvent = eventsLock.newCondition();

    public DOMContext(BaseWebInspector inspector) {
        this.inspector = inspector;
        id = UUID.randomUUID().toString();
    }

    public RemoteWebElement getDocument() {
        int cpt = 0;
        while (!isReady) {
            cpt++;
            if (cpt > 20) {
                isReady = true;
                throw new TimeoutException("doc not ready.");
            }
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return document;
    }

    public RemoteWebElement getWindow() {
        return window;
    }

    public void newContext() {
        log.fine("newContext was called.");
        id = UUID.randomUUID().toString();
        window = null;
        document = null;
        iframe = null;
        mainDocument = null;
    }

    public String toString() {
        StringBuilder b = new StringBuilder();
        b.append("window " + window);
        b.append("document " + document);
        b.append("iframe " + iframe);
        b.append("mainDocument " + mainDocument);
        return b.toString();
    }

    // TODO freynaud reset() != pageLoad
    public void reset() {
        log.fine("reset called on " + toString());
        RemoteWebElement newDocument = null;
        RemoteWebElement newWindow = null;

        // check is what changed was the context for the current frame.
        if (iframe != null) {
            log.info("iframe was null");
            try {
                newDocument = iframe.getContentDocument();
                newWindow = iframe.getContentWindow();
                log.fine("newDoc=" + newDocument + " newWindow=" + newWindow);
                setCurrentFrame(iframe, newDocument, newWindow);

                return;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        log.fine("iframe ==null , no iframe selected, the page load must be from the main page,newContext()");
        // couldn't update the current frame. Reseting everything.
        newContext();
    }

    // TODO freynaud. Cleanup. A reference to the main document of the page needs
    // to be kept.
    // calling getDocument again to have the document after siwtching to an iframe
    // breaks the nodeId reference.
    public void setCurrentFrame(RemoteWebElement iframe, RemoteWebElement document, RemoteWebElement window) {
        this.iframe = iframe;
        this.document = document;
        this.window = window;

        if (iframe != null) {
            isOnMainFrame = false;
        } else {
            isOnMainFrame = true;
        }

        // switchToDefaultContent. revert to main document if it was set.
        if (iframe == null && document == null) {
            this.document = mainDocument;
            this.window = mainWindow;
        }

        // setting the main document for the first time
        if (iframe == null && document != null) {
            mainDocument = document;
            mainWindow = window;
        }
        isReady = true;

    }

    public boolean isOnMainFrame() {
        return isOnMainFrame;
    }

    public RemoteWebElement getCurrentFrame() {
        return iframe;
    }

    public void onPageLoad() {
        pageLoaded = true;
        reset();
    }

    public void waitForPageToLoad(long timeout) {
        long start = System.currentTimeMillis();
        long deadLine = start + timeout;
        while (!pageLoaded) {
            if (System.currentTimeMillis() > deadLine) {
                // TODO freynaud check for alert while page loads.
                throw new TimeoutException("failed to load the page after " + timeout + " ms.");
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // ignore
            }
        }

        pageLoaded = false;
        waitForDocumentReady(deadLine);
        return;
    }

    public boolean isLoading() {
        return !isReady();
    }

    public String getDocumentReadyState() {
        String state = null;
        try {
            state = (String) inspector.executeScript("var state = document.readyState; return state",
                    new JSONArray());
        } catch (RemoteExceptionException e) {
            // Arguments should belong to the same JavaScript world as the target object.
            System.err.println("error, reseting because " + e.getMessage());
            reset();
            return "unknown";
        }
        return state;
    }

    private boolean isReady() {
        return "complete".equals(getDocumentReadyState());
    }

    private void waitForDocumentReady(long deadLine) {
        while (!isReady()) {
            if (System.currentTimeMillis() > deadLine) {
                throw new TimeoutException("failed to load the page");
            }
        }
    }

    public synchronized void domHasChanged(Event e) {
        try {

            if (e instanceof ChildNodeRemoved) {
                ChildNodeRemoved removed = (ChildNodeRemoved) e;
                if (iframe != null ? removed.getNode().equals(iframe.getNodeId()) : false) {
                    isReady = false;
                    parent = removed.getParent();
                    log.fine("current frame " + iframe.getNodeId() + " is gone.Parent = " + parent);
                    List<ChildIframeInserted> newOnes = eventHistory.getInsertedFrames(parent);
                    if (newOnes.size() == 0) {
                        return;
                    } else if (newOnes.size() == 1) {
                        Event newFrame = newOnes.get(0);
                        assignNewFrameFromEvent((ChildIframeInserted) newFrame);
                        eventHistory.removeEvent(newFrame);
                    } else {
                        log.warning("there should be only 1 newly created frame with parent =" + parent + ". Found "
                                + newOnes.size());
                    }
                }
                return;
            }

            if (e instanceof ChildIframeInserted) {
                ChildIframeInserted newFrame = (ChildIframeInserted) e;
                // are we waiting for something ?
                if (isReady) {
                    eventHistory.add(newFrame);
                    return;
                } else {
                    // is it the new node we're looking for ?
                    if (parent.equals(newFrame.getParent())) {
                        log.fine("the new node is here :" + newFrame.getNode());
                        assignNewFrameFromEvent(newFrame);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void assignNewFrameFromEvent(ChildIframeInserted newFrameEvent) throws Exception {
        RemoteWebElement frame = new RemoteWebElement(newFrameEvent.getNode(), inspector);
        RemoteWebElement document = new RemoteWebElement(newFrameEvent.getContentDocument(), inspector);
        RemoteWebElement window = frame.getContentWindow();
        setCurrentFrame(frame, document, window);
        isReady = true;
    }

    public void frameDied(JSONObject message) {
        // if that's the one we're working on, deselect it.
        if (iframe != null) {
            if (!iframe.exists()) {
                log.fine(
                        "the current frame is dead. Will need to switch to default content or another frame before being able to do anything.");
                isReady = true;
            }
        }

    }

    public void setWindowHandles(List<WebkitPage> handles) {
        this.windowHandles = handles;

        for (WebkitPage page : handles) {
            if (page.getConnection() != null) {
                windowHandle = "" + page.getPageId();
                return;
            }
        }
        windowHandle = null;
    }

    public List<WebkitPage> getWindowHandles() {
        return windowHandles;
    }

    public String getWindowHandle() {
        if (windowHandle == null) {
            throw new WebDriverException("don't know the current window.");
        }
        return windowHandle;
    }

    public void setWindow(String pageId) throws Exception {
        newContext();
        //session.getRemoteWebDriver().getProtocol().switchTo(pageId);
        //session.getRemoteWebDriver().enablePageEvent();
    }

    public String getId() {
        return id;
    }

    public void waitForLoadEvent() {
        try {
            eventsLock.lock();
            pageLoadEvent.await(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new TimeoutException("timeout waiting for page load event.");
        } finally {
            eventsLock.unlock();
        }
    }

    public Lock eventsLock() {
        return eventsLock;
    }

    // needs to be static ?
    public void signallNewPageLoadRecieved() {
        try {
            eventsLock.lock();
            reset();
            pageLoadEvent.signalAll();
        } finally {
            eventsLock.unlock();
        }

    }
}