edu.umd.cs.guitar.ripper.WebRipperMonitor.java Source code

Java tutorial

Introduction

Here is the source code for edu.umd.cs.guitar.ripper.WebRipperMonitor.java

Source

/*   
 *  Copyright (c) 2009-@year@. The GUITAR group at the University of Maryland. Names of owners of this group may
 *  be obtained by sending an e-mail to atif@cs.umd.edu
 * 
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
 *  documentation files (the "Software"), to deal in the Software without restriction, including without 
 *  limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 *   the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 
 *   conditions:
 * 
 *   The above copyright notice and this permission notice shall be included in all copies or substantial 
 *   portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
 *   LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 
 *   EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
 *   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 
 *   THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 */
package edu.umd.cs.guitar.ripper;

import java.awt.AWTException;
import java.io.IOException;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.io.FileUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.openqa.selenium.remote.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

import edu.umd.cs.guitar.event.EventManager;
import edu.umd.cs.guitar.event.GEvent;
import edu.umd.cs.guitar.event.GEventConfigurable;
import edu.umd.cs.guitar.event.WebEventConfiguration;
import edu.umd.cs.guitar.model.GComponent;
import edu.umd.cs.guitar.model.GWindow;
import edu.umd.cs.guitar.model.WebComponent;
import edu.umd.cs.guitar.model.WebConstants;
import edu.umd.cs.guitar.model.WebWindow;
import edu.umd.cs.guitar.model.WebWindowHandler;
import edu.umd.cs.guitar.model.WebDot;
import edu.umd.cs.guitar.model.WebDot.NodeType;
import edu.umd.cs.guitar.ripper.filter.WebExpandFilter;
import edu.umd.cs.guitar.util.GUITARLog;

/**
 * 
 * Monitor for the ripper to handle Web specific features
 * 
 * @see GRipperMonitor
 * 
 * @author Philip Anderson
 */
public class WebRipperMonitor extends GRipperMonitor {
    private WebRipperConfiguration config;
    private WebDriver driver;
    private HtmlUnitDriver driverHtml;
    private WebWindowHandler handler;
    private List<Integer> widths;
    private WebDot dotGraph;
    private String domainName;

    public WebRipperMonitor(NewGRipperConfiguration config) {
        super();
        this.config = (WebRipperConfiguration) config;
    }

    @Override
    public void cleanUp() {
        Set<String> copy = new TreeSet<String>();

        copy.addAll(driver.getWindowHandles());

        for (String handle : copy) {
            driver.switchTo().window(handle);
            driver.close();
            WebWindowHandler.findByDriver((RemoteWebDriver) driver).close(handle);
        }

        // Needed for DOT
        driverHtml.get(config.WEBSITE_URL);
        String correctRootUrl = driverHtml.getCurrentUrl();

        driver.quit();

        // Output DOT file and Graphviz graph as JPG
        dotGraph.outputGraph(config.DOT_FILE, correctRootUrl);
    }

    @Override
    public void closeWindow(GWindow window) {
        if (window instanceof WebWindow) {
            driver.switchTo().window(((WebWindow) window).getHandle());
            driver.close();
            driver.switchTo().window(handler.getLegalWindow());
            WebWindowHandler.findByDriver((RemoteWebDriver) driver).close(window);
            widths.remove(widths.size() - 1);
        }
    }

    @Override
    public void expandGUI(GComponent component) {
        if (!(component instanceof WebComponent))
            return;

        WebElement el = ((WebComponent) component).getElement();

        if (!(el instanceof RemoteWebElement)) {
            return;
        } else {
            if (!((RemoteWebElement) el).isDisplayed())
                return;
        }

        //Check to see if this is a link of the form: <a href="URL"></a>
        if (el.getAttribute("href") != null && el.getTagName().equals("a")) {
            //New Window is opening, presumably
            String href = el.getAttribute("href");
            String finalURL = parseUrl(href);
            /*         String finalURL = "";
                         
                     //Not sure exactly how to do this. It would be nice if there was a robust way already written
                     //Needs to check domain, root links, etc.
                     if(href.startsWith("http://") || href.startsWith("https://"))
                        finalURL = href;
                     else {
                        //Must not be a full url
                        String current = driver.getCurrentUrl();
                            
                        if(href.startsWith("/")) {
                           //Link is a direct reference from root
                           //7 = "http://".length
                           int third = 7 + current.substring(7).indexOf('/');
                           finalURL = current.substring(0, third) + href;
                        } else {
                           //Not from root
                           String end = current.substring(0, current.lastIndexOf('/') + 1);
                           finalURL = end + href;
                        }
                     }
            */
            //Handle DOT stuff
            dotGraph.addNode(finalURL, NodeType.LINK);
            dotGraph.addRelation(((WebComponent) component).getWindow().getTitle(), finalURL);

            if (widths.get(widths.size() - 1) >= config.WIDTH || handler.getNumOpenWindows() >= config.DEPTH) {
                //Don't open the link since it would break out WIDTH and DEPTH constraints
                return;
            } else {
                //Load a new page with finalURL
                WebWindowHandler wwh = WebWindowHandler.findByDriver((RemoteWebDriver) driver);

                if (wwh.createNewWindow(finalURL) != null) {
                    widths.set(widths.size() - 1, widths.get(widths.size() - 1) + 1);
                    widths.add(0);
                }

                return;
            }
        } else {
            if (!((WebComponent) component).hasLinkParent()) {
                ((WebComponent) component).getElement().click();
            }

        }
    }

    /* Check if the URLS are not identical, but still point to the same page */
    @Override
    public boolean isRippedWindow(GWindow window) {

        String sWindowName = window.getTitle();

        if (lRippedWindow.contains(sWindowName))
            return true;

        for (String otherWindowName : lRippedWindow)
            if (areTwoUrlsTheSame(sWindowName, otherWindowName))
                return true;

        return false;
    }

    /* Compares two URLs and their variables*/
    public static boolean areTwoUrlsTheSame(String url1, String url2) {
        ArrayList<String> urlList1 = variablesInUrl(url1);
        ArrayList<String> urlList2 = variablesInUrl(url2);
        Collections.sort(urlList1);
        Collections.sort(urlList2);

        if (urlList1.equals(urlList2))
            return true;
        else
            return false;
    }

    /* Returns a list of the variables and their values in a URL */
    public static ArrayList<String> variablesInUrl(String url) {
        String[] tempList = null;
        ArrayList<String> variableList = new ArrayList<String>();

        url = url.substring(url.indexOf('?') + 1, url.length());
        tempList = url.split("&");

        for (String str : tempList)
            variableList.add(str);

        return variableList;
    }

    @Override
    public LinkedList<GWindow> getClosedWindowCache() {
        LinkedList<GWindow> l = new LinkedList<GWindow>();
        return l;
    }

    @Override
    public LinkedList<GWindow> getOpenedWindowCache() {
        return handler.getOpenedWindowCache();
    }

    @Override
    public List<GWindow> getRootWindows() {
        ArrayList<GWindow> arr = new ArrayList<GWindow>();

        WebWindow handle = handler.createNewWindow(config.WEBSITE_URL);
        driver.switchTo().window(handle.getHandle());
        arr.add(handle);
        widths.add(0);
        domainName = handle.getDomainName();

        WebWindowHandler.findByDriver((RemoteWebDriver) driver).setDomainName(domainName);
        return arr;
    }

    @Override
    public boolean isExpandable(GComponent component, GWindow window) {
        return true;/*
                    if(component instanceof WebComponent) {
                    if (((WebComponent) component).getElement().getTagName().equals("body"))
                    return true;
                        
                    if (((WebComponent) component).getElement().getTagName().equals("a"))
                    return true;
                    }
                    return false;*/
    }

    @Override
    public boolean isIgnoredWindow(GWindow window) {
        return false;
    }

    @Override
    public boolean isNewWindowOpened() {
        return !getOpenedWindowCache().isEmpty();
    }

    @Override
    public boolean isWindowClosed() {
        return false;
    }

    @Override
    public void resetWindowCache() {
        handler.resetWindowCache();
    }

    @Override
    public void setUp() {
        EventManager em = EventManager.getInstance();

        WebEventConfiguration eventConfig = new WebEventConfiguration();
        eventConfig.setNoNavigateHrefs(config.NO_NAVIGATE_HREFS);
        for (Class<? extends GEvent> event : WebConstants.DEFAULT_SUPPORTED_EVENTS) {
            try {
                GEvent gevent = event.newInstance();
                if (gevent instanceof GEventConfigurable) {
                    GEventConfigurable configurable = (GEventConfigurable) gevent;
                    configurable.configure(eventConfig);
                }
                em.registerEvent(gevent);
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        if (config.PROFILE != null) {
            GUITARLog.Info("Configuring Firefox WebDriver to use desired profile name. "
                    + "If the program exits prematurely at this point, then the profile does not"
                    + "exist. Check your Firefox profiles directory, or open the Firefox profile"
                    + "manager to create a new profile.");
            System.setProperty("webdriver.firefox.profile", config.PROFILE);
            GUITARLog.Info("Profile found.");
        }
        System.out.println("Browser : " + config.BROWSER);
        if (config.BROWSER == null || config.BROWSER == WebRipperConfiguration.Browser.Firefox) {
            driver = new FirefoxDriver();
            GUITARLog.Info("Driver set to: FirefoxDriver()"); //DEBUG
        } else if (config.BROWSER == WebRipperConfiguration.Browser.Chrome) {
            if (config.BROWSER_PATH != null)
                System.setProperty("webdriver.chrome.bin", config.BROWSER_PATH);
            driver = new ChromeDriver();
        } else if (config.BROWSER == WebRipperConfiguration.Browser.HTMLUnit) {
            driver = new HtmlUnitDriver();
        } else {
            driver = new InternetExplorerDriver();
        }

        driverHtml = new HtmlUnitDriver();
        GUITARLog.Info("HMTL Driver set to: HtmlUnitDriver()");

        handler = new WebWindowHandler((RemoteWebDriver) driver);
        handler.setUp();

        GUITARLog.Info("Handler setup.");

        widths = new ArrayList<Integer>();
        dotGraph = new WebDot();

        if (ripper != null)
            ripper.addComponentFilter(new WebExpandFilter());
        else
            GUITARLog.Info("Ripper in WebRipperMonitor has not been assigned.");
    }

    /**
     * This is a placeholder for the selenium platform.
     */
    @Override
    public void captureImage(GComponent component, String strFilePath) throws AWTException, IOException {
        File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);

        int extIndex = (config.GUI_FILE).lastIndexOf('.');
        String dir = (config.GUI_FILE).substring(0, extIndex);
        String file = dir + "/screencaps/" + parseUrltoFileOutput(parseUrl(strFilePath));

        try {
            //Copy the file to screenshot folder 
            FileUtils.copyFile(screenshot, new File(file + ".png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void addRippedList(GWindow window) {
        String windowTitle = window.getTitle();
        this.lRippedWindow.add(windowTitle);

        //added capture image call
        try {
            if (windowTitle.endsWith("/"))
                windowTitle = windowTitle.substring(0, windowTitle.length() - 1);
            captureImage(null, windowTitle);
        } catch (AWTException e) {
            // Ignore AWT exceptions
        } catch (IOException e) {

        }
    }

    private String parseUrltoFileOutput(String url) {
        String file = url;
        String host = "";

        // remove http/ and host/ directories
        /*   try {
              URL u = new URL(url);
              host = u.getHost();
           } catch (MalformedURLException e) {
              e.printStackTrace();
           }   
               
           int startIndex = url.indexOf(host) + host.length();
               
           file = url.substring(startIndex);
        */
        int lastdot = file.lastIndexOf('.');
        if (lastdot >= file.length() - 6)
            file = file.substring(0, lastdot);

        return file;
    }

    private String parseUrl(String href) {
        String finalURL = "";

        //Not sure exactly how to do this. It would be nice if there was a robust way already written
        //Needs to check domain, root links, etc.
        if (href.startsWith("http://") || href.startsWith("https://"))
            finalURL = href;
        else {
            //Must not be a full url
            String current = driver.getCurrentUrl();

            if (href.startsWith("/")) {
                //Link is a direct reference from root
                //7 = "http://".length
                int third = 7 + current.substring(7).indexOf('/');
                finalURL = current.substring(0, third) + href;
            } else {
                //Not from root
                String end = current.substring(0, current.lastIndexOf('/') + 1);
                finalURL = end + href;
            }
        }
        return finalURL;
    }
}