changeset 706:d84475508473

adding awtframework (without reproducers)
author Jana Fabrikova <jfabriko@redhat.com>
date Fri, 26 Apr 2013 20:24:55 +0200
parents 728cc3b2ab34
children c5e4fbd65bc0
files ChangeLog tests/test-extensions/net/sourceforge/jnlp/awt/AWTFrameworkException.java tests/test-extensions/net/sourceforge/jnlp/awt/AWTHelper.java tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/KeyboardActions.java tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/MouseActions.java tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentFinder.java tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentNotFoundException.java tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ImageSeeker.java tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java
diffstat 9 files changed, 1489 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Apr 26 20:11:33 2013 +0200
+++ b/ChangeLog	Fri Apr 26 20:24:55 2013 +0200
@@ -1,3 +1,27 @@
+2013-04-26  Jana Fabrikova  <jfabriko@redhat.com>
+
+	* /tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java:
+	added a getter method getRules 
+	* tests/test-extensions/net/sourceforge/jnlp/awt/AWTHelper.java:
+	the most important class of AWTFramework, combines closing listener and
+	possibility to use mouse and keyboard for input to tests
+	* tests/test-extensions/net/sourceforge/jnlp/awt/AWTFrameworkException.java:
+	exception that is raised in the framework whenever programmer did not
+	provide enough information
+	* tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/KeyboardActions.java:
+	class with utility keyboard methods
+	* tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/MouseActions.java:
+	class with utility mouse methods
+	* tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentFinder.java:
+	class for finding components in a screenshot
+	* tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentNotFoundException.java:
+	exception that can be raised if an important component could not be found
+	* tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ImageSeeker.java:
+	class for general image searching
+	* tests/reproducers/simple/AWTCommonResourcesOnly/resources/marker.png:
+	reproducer with resources only, contains the default icon marking
+	applets
+
 2013-04-26  Adam Domurad  <adomurad@redhat.com>
 
 	* netx/net/sourceforge/jnlp/cache/ResourceTracker.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extensions/net/sourceforge/jnlp/awt/AWTFrameworkException.java	Fri Apr 26 20:24:55 2013 +0200
@@ -0,0 +1,66 @@
+/* AWTFrameworkException.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+package net.sourceforge.jnlp.awt;
+
+/**
+ * Class AWTFrameworkException is thrown in the AWTFramework 
+ * whenever the framework encounters not enough data specified
+ * to perform an action (for example it is impossible to ascertain 
+ * the position of an applet in the screenshot if the width or height
+ * of the applet is not known.  
+ *
+ */
+
+public class AWTFrameworkException extends Exception {
+
+    public AWTFrameworkException() { 
+        super(); 
+    }
+    
+    public AWTFrameworkException(String s) { 
+        super(s); 
+    }
+    
+    public AWTFrameworkException(String s, Throwable throwable) { 
+        super(s, throwable); 
+    }
+    
+    public AWTFrameworkException(Throwable throwable) { 
+        super(throwable); 
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extensions/net/sourceforge/jnlp/awt/AWTHelper.java	Fri Apr 26 20:24:55 2013 +0200
@@ -0,0 +1,559 @@
+/* AWTHelper.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+package net.sourceforge.jnlp.awt;
+
+import java.awt.AWTException;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.event.InputEvent;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import net.sourceforge.jnlp.awt.awtactions.KeyboardActions;
+import net.sourceforge.jnlp.awt.awtactions.MouseActions;
+import net.sourceforge.jnlp.awt.imagesearch.ComponentFinder;
+import net.sourceforge.jnlp.awt.imagesearch.ComponentNotFoundException;
+import net.sourceforge.jnlp.awt.imagesearch.ImageSeeker;
+import net.sourceforge.jnlp.closinglisteners.Rule;
+import net.sourceforge.jnlp.closinglisteners.RulesFolowingClosingListener;
+
+public abstract class AWTHelper extends RulesFolowingClosingListener implements Runnable{
+
+    //attributes possibly set by user
+    private String initStr = "";        
+    private Color appletColor;
+    private BufferedImage marker;
+    private Rectangle markerPosition;
+    private int appletHeight;
+    private int appletWidth;
+    private int tryKTimes = DEFAULT_K;
+
+    //other 
+    protected StringBuilder sb = new StringBuilder();
+    private boolean actionStarted = false;
+    private Rectangle actionArea;
+    private BufferedImage screenshot;
+    private Robot robot;
+    private boolean appletFound = false;
+    private boolean initStrGiven = false; //impossible to find in the output if not given
+    private boolean appletColorGiven = false; //impossible to search for color difference if not given
+    private boolean markerGiven = false; //impossible to find the applet if marker not given
+    private boolean appletDimensionGiven = false;
+    private boolean screenshotTaken = false;
+    private int defaultWaitForApplet = 1000;
+    
+    //default number of times the screen is captured and the applet is searched for
+    //in the screenshot
+    public static final int DEFAULT_K = 3;
+   
+    
+    //several constructors
+    /**
+     * the minimal constructor - use:
+     *  - if we do not want to find the bounds of applet area first
+     *  - searching for buttons and other components is then done in the whole
+     *    screen, confusion with other icons on display is then possible
+     *  - less effective, deprecated (better bound the area first) 
+     */
+    @Deprecated
+    public AWTHelper() {
+        try {
+            this.robot = new Robot();
+        } catch (AWTException e) {
+            throw new RuntimeException("AWTHelper could not create its Robot instance.",e);
+        }
+    }
+    
+    /**
+     * the minimal constructor with initStr - use:
+     *  - we want to know from stdout that the applet (or sth else) is ready
+     *  - if we do not want to find the bounds of applet area first
+     *  - searching for buttons and other components is then done in the whole
+     *    screen, confusion with other icons on display is then possible
+     *  - less effective, deprecated (better bound the area first) 
+     */
+    @Deprecated
+    public AWTHelper(String initStr){
+        this();
+        
+        this.initStr = initStr;
+        this.initStrGiven = true;
+    }
+    
+    /**
+     * the constructor with icon and its position in applet of given dimension
+     * use:
+     *   - we want to find and activate the applet first
+     *   - the search for applet will be done via searching for icon
+     *     of given position(x,y,w,h) inside applet of given width and height
+     * 
+     * @param icon marker by which the applet will be found
+     * @param iconPosition relatively to applet (including icon width and height)
+     * @param appletWidth
+     * @param appletHeight
+     */
+   
+    public AWTHelper(BufferedImage icon, Rectangle iconPosition, int appletWidth, int appletHeight){
+        this();
+        this.marker = icon;
+        this.markerPosition = iconPosition;
+        this.markerGiven = true;
+        
+        this.appletWidth = appletWidth;
+        this.appletHeight = appletHeight;
+        this.appletDimensionGiven = true;
+    }
+    
+    public AWTHelper(String initString, BufferedImage icon, Rectangle iconPosition, int appletWidth, int appletHeight) throws AWTException{
+        this(icon, iconPosition, appletWidth, appletHeight);
+        
+        this.initStr = initString;
+        this.initStrGiven = true;
+    }
+    
+    /**
+     * the constructor with applet width and height only - use:
+     *  - we want to find the applet by finding the default icon
+     *    that is located in the upper left corner of applet
+     * 
+     * @param appletWidth
+     * @param appletHeight
+     */
+    public AWTHelper(int appletWidth, int appletHeight){
+        this();
+        String test_server_dir_path = System.getProperty("test.server.dir");
+
+        try {
+            this.marker = ImageIO.read(new File(test_server_dir_path + "/marker.png"));
+            this.markerPosition = new Rectangle(0,0,marker.getWidth(),marker.getHeight());
+            this.markerGiven = true;
+        } catch (IOException e) {
+            throw new RuntimeException("AWTHelper could not read marker.png.",e);
+        }
+        
+        this.appletWidth = appletWidth;
+        this.appletHeight = appletHeight;
+        this.appletDimensionGiven = true;
+    }
+    
+    public AWTHelper(String initString, int appletWidth, int appletHeight){
+        this(appletWidth, appletHeight);
+        this.initStr = initString;
+        this.initStrGiven = true;
+    }
+    
+    /**
+     * refers to AWTHelper functioning as RulesFolowingClosingListener
+     * 
+     * @param strs array of strings to be added as contains rules
+     */
+    public void addClosingRulesFromStringArray(String [] strs){
+        for(String s : strs){
+            this.addContainsRule(s);
+        }
+    }
+    
+    /**
+     * override of method charReaded (from RulesFolowingClosingListener)
+     * 
+     * waiting for the applet, when applet is ready run action thread
+     * when all the wanted strings are in the stdout, applet can be closed
+     * 
+     * @param ch 
+     */
+    @Override
+    public void charReaded(char ch) {
+        sb.append(ch);
+        //is applet ready to start clicking?
+        if (initStrGiven && !actionStarted && appletIsReady(sb.toString())) {
+            try{
+                actionStarted = true; 
+                this.findAndActivateApplet();
+                this.run();
+            } catch (ComponentNotFoundException e1) {
+                throw new RuntimeException("AWTHelper problems finding applet.",e1);
+            } catch (AWTFrameworkException e2){
+                throw new RuntimeException("AWTHelper problems with unset attributes.",e2);
+            }
+        }
+        //is all the wanted output in stdout?
+        super.charReaded(ch);
+    }
+    
+    /**
+     * method runAWTHelper - we can call run and declared the action as started
+     * without finding out if initStr is in the output, if this method is
+     * called
+     * 
+     */
+    public void runAWTHelper(){
+        actionStarted = true;
+        this.run();
+    }
+
+    /**
+     * implementation of AWTHelper should implement the run method
+     */
+    public abstract void run();
+
+
+    /**
+     * method getInitStrAsRule returns the initStr in the form
+     * of Contains rule that can be evaluated on a string 
+     * 
+     * @return
+     */
+    public Rule getInitStrAsRule(){
+        return new ContainsRule(this.initStr);
+    }
+    
+    //boolean controls getters
+    protected boolean appletIsReady(String content) {
+        return (content.contains(initStr));
+    }
+    
+    public boolean isActionStarted() {
+        return actionStarted;
+    }
+    
+    public boolean isInitStrGiven(){
+        return initStrGiven;
+    }
+    
+    public boolean isAppletColorGiven(){
+        return appletColorGiven;
+    }
+    
+    public boolean isAppletDimensionGiven(){
+        return appletDimensionGiven;
+    }
+    
+    public boolean isMarkerGiven(){
+        return markerGiven;
+    }
+    
+    //setters
+    /**
+     * method setDefaultWaitForApplet sets the time (in ms) for which the method
+     * captureScreenAndFindApplet will wait (for the applet to load) before it
+     * gets the screenshot the default time is 1000ms
+     * 
+     * @param defaultWaitForApplet
+     */
+    public void setDefaultWaitForApplet(int defaultWaitForApplet) {
+        this.defaultWaitForApplet = defaultWaitForApplet;
+    }
+
+    public void setTryKTimes(int tryKTimes) {
+        this.tryKTimes = tryKTimes;
+    }
+
+    public void setAppletColor(Color appletColor) {
+        this.appletColor = appletColor;
+        this.appletColorGiven = true;
+    }
+
+    public void setInitStr(String initStr) {
+        this.initStr = initStr;
+        this.initStrGiven = true;
+    }
+       
+    public void setMarker(BufferedImage marker, Rectangle markerPosition) {
+        this.marker = marker;
+        this.markerPosition = markerPosition;
+        this.markerGiven = true;
+    }
+    
+    public void setAppletDimension(int width, int height){
+        this.appletWidth = width;
+        this.appletHeight = height;
+        this.appletDimensionGiven = true;
+    }
+
+
+    //creating screenshots, searching for applet
+    /**
+     * method captureScreenAndFindAppletByIcon
+     * 1. checks that all needed attributes of AWTHelper are given
+     *    (marker, its position and applet width and height)
+     * 2. captures screen, 
+     * 3. finds the rectangle where applet is and saves it to the attribute
+     *    actionArea 
+     * 4. sets screenCapture indicator to true (after tryKTimes unsuccessfull
+     *    tries an exception "ComponentNotFound" will be raised)
+     * 
+     * @throws AWTException 
+     * @throws ComponentNotFoundException 
+     * @throws AWTFrameworkException 
+     */
+    public void captureScreenAndFindAppletByIcon() throws ComponentNotFoundException, AWTFrameworkException {
+        if(!appletDimensionGiven || !markerGiven){
+            throw new AWTFrameworkException("AWTFramework cannot find applet without dimension or marker!");
+        }
+        captureScreenAndFindAppletByIconTryKTimes(marker, markerPosition, appletWidth, appletHeight, tryKTimes);
+    }
+
+    /**
+     ** method captureScreenAndFindAppletByIcon
+     * 1. captures screen, 
+     * 2. finds the rectangle where applet is and saves it to the attribute
+     *    actionArea 
+     * 3. sets screenCapture indicator to true (after tryKTimes unsuccessfull
+     *    tries an exception "ComponentNotFound" will be raised) 
+     * 
+     * @param icon
+     * @param iconPosition
+     * @param width
+     * @param height
+     * @param K
+     * @throws ComponentNotFoundException
+     * @throws AWTFrameworkException
+     */
+    public void captureScreenAndFindAppletByIconTryKTimes(BufferedImage icon, Rectangle iconPosition, int width, int height, int K) throws ComponentNotFoundException, AWTFrameworkException {
+  
+        if(!markerGiven){
+            throw new AWTFrameworkException("AWTFramework cannot find applet without marker!");
+        }
+
+        int count = 0;
+        appletFound = false;
+        while ((count < K) && !appletFound) {
+                robot.delay(defaultWaitForApplet);
+                screenshot = robot.createScreenCapture( new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() ) );
+                screenshotTaken = true;
+                actionArea = ComponentFinder.findWindowByIcon(icon, iconPosition, width, height, screenshot);
+                if (ImageSeeker.isRectangleValid(actionArea)) {
+                    appletFound = true;
+                }
+                count++;
+        }
+
+        if (ImageSeeker.isRectangleValid(actionArea)) {
+            appletFound = true;
+        } else {
+            throw new ComponentNotFoundException("Applet not found in the screenshot!");
+        }
+
+    }
+    
+    /**
+     * auxiliary method writeAppletScreen for writing Buffered image into png
+     * 
+     * @param appletScreen
+     * @param filename
+     * @throws IOException
+     */
+    private void writeAppletScreen(BufferedImage appletScreen, String filename) throws IOException {// into png file
+            ImageIO.write(appletScreen, "png", new File(filename+".png"));
+    }
+
+    
+    /**
+     * method findAndActivateApplet finds the applet by icon 
+     * and clicks in the middle of applet area
+     * 
+     * @throws ComponentNotFoundException (applet not found) 
+     * @throws AWTFrameworkException 
+     */
+    public void findAndActivateApplet() throws ComponentNotFoundException, AWTFrameworkException
+    {
+        captureScreenAndFindAppletByIcon();
+        clickInTheMiddleOfApplet();
+    }
+
+
+    //methods for clicking and typing 
+    /**
+     * method clickInTheMiddleOfApplet focuses the applet by clicking in the
+     * middle of its location rectangle
+     */
+    public void clickInTheMiddleOfApplet() {
+        MouseActions.clickInside(this.actionArea, this.robot);
+    }
+    
+    /**
+     * Method clickOnIconExact - click in the middle of a rectangle with 
+     * given pattern (icon) using specified mouse key.
+     * If the applet has not been found yet, the search includes whole screen.
+     * 
+     * @param icon
+     * @param mouseKey
+     * @throws ComponentNotFoundException
+     */
+    public void clickOnIconExact(BufferedImage icon, int mouseKey) throws ComponentNotFoundException{
+        Rectangle areaOfSearch;
+        if(!appletFound){//searching whole screen, less effective
+            areaOfSearch = new Rectangle(0, 0, this.screenshot.getWidth(), this.screenshot.getHeight());
+        }else{
+            areaOfSearch = this.actionArea;
+        }
+        Rectangle iconRectangle = ImageSeeker.findExactImage(icon, this.screenshot, areaOfSearch);
+
+        if (ImageSeeker.isRectangleValid(iconRectangle)) {
+            MouseActions.clickInside(mouseKey, iconRectangle, this.robot);
+        }else{
+            throw new ComponentNotFoundException("Exact icon not found!");
+        }
+    }
+
+    /**
+     * Method clickOnIconBlurred - click in the middle of a rectangle with 
+     * given pattern (icon) using specified mouse key.
+     * If the applet has not been found yet, the search includes whole screen.
+     *  
+     * @param icon
+     * @param mouseKey
+     * @param precision tolerated minimal correlation (see ImageSeeker methods)
+     * @throws ComponentNotFoundException
+     */
+    public void clickOnIconBlurred(BufferedImage icon, int mouseKey, double precision) throws ComponentNotFoundException{
+        Rectangle areaOfSearch;
+        if(!appletFound){//searching whole screen, less effective
+            areaOfSearch = new Rectangle(0, 0, this.screenshot.getWidth(), this.screenshot.getHeight());
+        }else{
+            areaOfSearch = this.actionArea;
+        }    
+        Rectangle iconRectangle = ImageSeeker.findBlurredImage(icon, this.screenshot, precision, areaOfSearch);
+
+        if (ImageSeeker.isRectangleValid(iconRectangle)) {
+            MouseActions.clickInside(mouseKey, iconRectangle, this.robot);
+        }else{
+            throw new ComponentNotFoundException("Blurred icon not found!");
+        }
+    }
+    
+    /**
+     * Method clickOnColoredRectangle - click in the middle of a rectangle with
+     * given color (appletColor must be specified as the background) using
+     * specified mouse key.
+     * 
+     * @param c
+     * @param mouseKey
+     * @throws ComponentNotFoundException
+     * @throws AWTFrameworkException 
+     * 
+     */
+    public void clickOnColoredRectangle(Color c, int mouseKey) throws ComponentNotFoundException, AWTFrameworkException {
+        Rectangle buttonRectangle = findColoredRectangle(c);
+
+        if (ImageSeeker.isRectangleValid(buttonRectangle)) {
+            MouseActions.clickInside(mouseKey, buttonRectangle, this.robot);
+        }else{
+            throw new ComponentNotFoundException("Colored rectangle not found!");
+        }
+    }
+
+    public void moveToMiddleOfColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException {
+
+        Rectangle buttonRectangle = findColoredRectangle(c);
+
+        if (ImageSeeker.isRectangleValid(buttonRectangle)) {
+            MouseActions.moveMouseToMiddle(buttonRectangle, this.robot);
+        }else{
+            throw new ComponentNotFoundException("Colored rectangle not found!");
+        }
+    }
+
+    public void moveOutsideColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException {
+        Rectangle buttonRectangle = findColoredRectangle(c);
+
+        if (ImageSeeker.isRectangleValid(buttonRectangle)) {
+            MouseActions.moveMouseOutside(buttonRectangle, this.robot);
+        }else{
+            throw new ComponentNotFoundException("Colored rectangle not found!");
+        }
+    }
+
+    public void moveInsideColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException {
+        Rectangle buttonRectangle = findColoredRectangle(c);
+
+        if (ImageSeeker.isRectangleValid(buttonRectangle)) {
+            MouseActions.moveInsideRectangle(buttonRectangle, this.robot);
+        }else{
+            throw new ComponentNotFoundException("Colored rectangle not found!");
+        }
+    }
+
+    public void dragFromColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException {
+        Rectangle buttonRectangle = findColoredRectangle(c);
+
+        if (ImageSeeker.isRectangleValid(buttonRectangle)) {
+            MouseActions.dragFromRectangle(buttonRectangle, this.robot);
+        }else{
+            throw new ComponentNotFoundException("Colored rectangle not found!");
+        }
+    }
+
+    public Rectangle findColoredRectangle(Color c) throws AWTFrameworkException {
+        if(!appletColorGiven || !appletFound){
+            throw new AWTFrameworkException("AWTHelper could not search for colored rectangle, needs appletColor and applet position.");
+        }
+        
+        Rectangle result;
+
+        int gap = 5;
+        result = ImageSeeker.findColoredAreaGap(this.screenshot, c, appletColor, this.actionArea.y, this.actionArea.y + this.actionArea.height, gap);
+
+        return result;
+    }
+
+    /**
+     * method writeText writes string containing small letters and numbers and
+     * spaces like the keyboard input (using KeyboardActions so delays are
+     * inserted)
+     * 
+     * @param text
+     */
+    public void writeText(String text) {
+        KeyboardActions.writeText(this.robot, text);
+    }
+
+    /**
+     * method typeKey writes one key on the keyboard (again using
+     * KeyboardActions)
+     * 
+     * @param key
+     */
+    public void typeKey(int key) {
+        KeyboardActions.typeKey(this.robot, key);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/KeyboardActions.java	Fri Apr 26 20:24:55 2013 +0200
@@ -0,0 +1,111 @@
+/* KeyboardActions.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+
+package net.sourceforge.jnlp.awt.awtactions;
+
+import java.awt.Robot;
+import java.awt.event.KeyEvent;
+
+public class KeyboardActions {
+    
+    private static final int defaultDelay = 250;
+
+    /**
+     * method writeText for simulating typing the 
+     * given String text by a user with delays 
+     * allowed characters in the text: 0-9, a-z, the space
+     * between the keystrokes
+     *  
+     * @param robot
+     * @param text
+     * @param delayMs
+     */
+    public static void writeText(Robot robot, String text, int delayMs){
+        for (int i = 0; i < text.length(); i++){
+            char c = text.charAt(i);        
+            typeKey(robot, keyFromChar(c), delayMs);    
+        }
+    }
+    
+    public static void writeText(Robot robot, String text){
+        writeText(robot,text, defaultDelay);
+    }
+    
+    /**
+     * method typeKey for pressing and releasing given key
+     * with a reasonable delay 
+     *
+     * @param robot
+     * @param key
+     * @param delayMs
+     */
+     
+    public static void typeKey(Robot robot, int key, int delayMs){
+        robot.delay(delayMs);
+        robot.keyPress(key);
+        robot.delay(delayMs);
+        robot.keyRelease(key);
+    }
+    
+    public static void typeKey(Robot robot, int key){
+        typeKey(robot, key, defaultDelay);
+    }
+    
+    /**
+     * method returning the KeyInput event int
+     * if the character is not from a-b, 0-9, the returned value is
+     * KeyEvent.VK_SPACE
+     * 
+     * @param ch
+     * @return
+     */
+    public static int keyFromChar(char ch){
+        int key;
+        
+        if( ('0' <= ch) && ('9' >= ch) ){
+            key = (int)(ch - '0') + KeyEvent.VK_0; 
+        }else if( ( 'a' <= ch) && ('z' >= ch) ){
+            key = (int)(ch - 'a') + KeyEvent.VK_A;
+        }else{
+            key = KeyEvent.VK_SPACE;
+        }
+        
+        return key;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/MouseActions.java	Fri Apr 26 20:24:55 2013 +0200
@@ -0,0 +1,228 @@
+/* MouseActions.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+
+package net.sourceforge.jnlp.awt.awtactions;
+
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.event.InputEvent;
+
+/**
+ * class MouseActions 
+ * 
+ * static methods for manipulating the mouse via AWT robot
+ */
+public class MouseActions {
+    private static final int defaultDelay = 250;
+    
+    /**
+     * method click presses and releases given mouse keys
+     * with reasonable delay before the event
+     * 
+     * @param mouseKeyMask
+     * @param robot
+     * @param delayMs
+     */
+    public static void click(int mouseKeyMask, Robot robot, int delayMs){
+        robot.delay(delayMs);
+        robot.mousePress(mouseKeyMask);
+        robot.delay(delayMs);
+        robot.mouseRelease(mouseKeyMask);
+    }
+    
+    public static void click(int mouseKeyMask, Robot robot){
+        robot.delay(defaultDelay);
+        robot.mousePress(mouseKeyMask);
+        robot.delay(defaultDelay);
+        robot.mouseRelease(mouseKeyMask);
+    }
+    
+    /**
+     * method doubleClick presses and releases given mouse keys
+     * two times with reasonable delays
+     * 
+     * @param mouseKeyMask
+     * @param robot
+     * @param delayMs
+     */
+     
+    public static void doubleClick(int mouseKeyMask, Robot robot, int delayMs){
+        click(mouseKeyMask, robot, delayMs);
+        click(mouseKeyMask, robot, delayMs);
+    }
+    
+    public static void doubleClick(int mouseKeyMask, Robot robot){
+        click(mouseKeyMask, robot, defaultDelay);
+        click(mouseKeyMask, robot, defaultDelay);
+    }
+
+    /**
+     * method drag presses the right mouse key,
+     * drags the mouse to a point, and releases the mouse key  
+     * with reasonable delays
+     * 
+     * @param xTo
+     * @param yTo
+     * @param robot
+     * @param delayMs
+     */
+    public static void drag(int xTo, int yTo, Robot robot, int delayMs){
+        robot.delay(delayMs);
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        robot.delay(delayMs);
+        robot.mouseMove(xTo, yTo);
+    }
+    
+    public static void drag(int xTo, int yTo, Robot robot){
+        robot.delay(defaultDelay);
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        robot.delay(defaultDelay);
+        robot.mouseMove(xTo, yTo);
+    }
+    
+    /**
+     * method dragFromRectangle clicks in the middle
+     * of the given rectangle and drags the mouse from the rectangle
+     * with reasonable delays
+     * 
+     * @param rectangle
+     * @param robot
+     * @param delayMs
+     */
+
+    public static void dragFromRectangle(Rectangle rectangle, Robot robot, int delayMs){
+        int x1 = rectangle.x + rectangle.width/2;
+        int y1 = rectangle.y + rectangle.height/2;
+        int x2 = x1 + 2*rectangle.width;
+        int y2 = y1 + 2*rectangle.height;
+        robot.delay(delayMs);
+        robot.mouseMove(x1, y1);
+        drag(x2,y2, robot);
+    }
+    
+    public static void dragFromRectangle(Rectangle rectangle, Robot robot){
+        dragFromRectangle(rectangle, robot, defaultDelay);
+    }
+
+    /**
+     * method moveInsideRectangle places the mouse in the middle
+     * of the given rectangle and moves the mouse inside the rectangle
+     * with reasonable delays
+     * 
+     * @param rectangle
+     * @param robot
+     * @param delayMs
+     */
+
+    public static void moveInsideRectangle(Rectangle rectangle, Robot robot, int delayMs){
+        int x1 = rectangle.x + rectangle.width/2;
+        int y1 = rectangle.y + rectangle.height/2;
+        int x2 = x1 + rectangle.width/4;
+        int y2 = y1 + rectangle.height/4;
+        robot.delay(delayMs);
+        robot.mouseMove(x1, y1);
+        robot.delay(delayMs);
+        robot.mouseMove(x2, y2);
+    }
+    
+    public static void moveInsideRectangle(Rectangle rectangle, Robot robot){
+        moveInsideRectangle(rectangle, robot, defaultDelay);
+    }
+    
+    /**
+     * 
+     * @param rectangle
+     * @param robot
+     * @param delayMs
+     */
+    public static void moveMouseToMiddle(Rectangle rectangle, Robot robot, int delayMs){
+        robot.delay(delayMs);
+        int x = rectangle.x + (rectangle.width/2);
+        int y = rectangle.y + (rectangle.height/2);
+        robot.mouseMove(x,y);
+    }
+    
+    public static void moveMouseToMiddle(Rectangle rectangle, Robot robot){
+        moveMouseToMiddle(rectangle, robot, defaultDelay);
+    }
+
+    /**
+     * 
+     * @param rectangle
+     * @param robot
+     * @param delayMs
+     */
+    public static void moveMouseOutside(Rectangle rectangle, Robot robot, int delayMs){
+        robot.delay(delayMs);
+        int x = rectangle.x + 2*rectangle.width;
+        int y = rectangle.y + 2*rectangle.height;
+        robot.mouseMove(x,y);
+    }
+    
+    public static void moveMouseOutside(Rectangle rectangle, Robot robot){
+        moveMouseOutside(rectangle, robot, defaultDelay);
+    }
+    
+    
+    /**
+      * method clickInside moves the mouse in the middle point
+     * of a given rectangle and clicks with reasonable delay
+
+     * 
+     * @param rectangle
+     * @param robot
+     * @param delayMs
+     */
+    public static void clickInside(int mouseKey, Rectangle rectangle, Robot robot, int delayMs){
+        moveMouseToMiddle(rectangle, robot, delayMs);
+        robot.delay(delayMs);
+        click(mouseKey, robot, delayMs);
+    }
+    
+    public static void clickInside(int mouseKey, Rectangle rectangle, Robot robot){
+        clickInside(mouseKey, rectangle, robot, defaultDelay);
+    }
+    
+    public static void clickInside(Rectangle rectangle, Robot robot, int delayMs){
+        clickInside(InputEvent.BUTTON1_MASK, rectangle, robot, delayMs);
+    }
+    
+    public static void clickInside(Rectangle rectangle, Robot robot){
+        clickInside(rectangle, robot, defaultDelay);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentFinder.java	Fri Apr 26 20:24:55 2013 +0200
@@ -0,0 +1,107 @@
+/* ComponentFinder.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+
+package net.sourceforge.jnlp.awt.imagesearch;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+public class ComponentFinder {
+
+    /**
+     * method findColoredRectangle determines coordinates of a rectangle colored
+     * by rectangleColor surrounded by a neighbourhood of surroundingColor
+     * 
+     * @param rectangleColor
+     * @param surroundingColor
+     * @param screenshot
+     * @return
+     */
+    public static Rectangle findColoredRectangle(Color rectangleColor, Color surroundingColor, BufferedImage screenshot) {
+
+        Rectangle r = ImageSeeker.findColoredAreaGap(screenshot, rectangleColor, surroundingColor, 0, screenshot.getHeight(), 0);
+        return r;
+    }
+
+    /**
+     * method findColoredRectangle determines coordinates of a rectangle colored
+     * by rectangleColor surrounded by a neighbourhood of surroundingColor with
+     * possible gap of several pixels
+     * 
+     * @param rectangleColor
+     * @param surroundingColor
+     * @param screenshot
+     * @param gap
+     * @return
+     */
+    public static Rectangle findColoredRectangle(Color rectangleColor, Color surroundingColor, BufferedImage screenshot, int gap) {
+
+        Rectangle r = ImageSeeker.findColoredAreaGap(screenshot, rectangleColor, surroundingColor, 0, screenshot.getHeight(), gap);
+        return r;
+    }
+
+    
+    /**
+     * method findWindowByIcon finds the application area assuming there is a
+     * given icon in given position on the application window 
+     * (the left upper corner by default) the dimension of the window has to 
+     * be given
+     * 
+     * @param icon
+     * @param iconPosition
+     * @param appletWidth
+     * @param appletHeight
+     * @param screenshot
+     * @return Rectangle rectangle where the applet resides
+     */
+    public static Rectangle findWindowByIcon(BufferedImage icon, Rectangle iconPosition, int windowWidth, int windowHeight, BufferedImage screenshot) {
+        Rectangle r = ImageSeeker.findExactImage(icon, screenshot);
+        return windowPositionFromIconPosition(r, iconPosition, windowWidth, windowHeight);
+    }
+
+    public static Rectangle findWindowByIconBlurred(BufferedImage icon, Rectangle iconPosition, int windowWidth, int windowHeight, BufferedImage screenshot, double minCorrelation) {
+        Rectangle r = ImageSeeker.findBlurredImage(icon, screenshot, minCorrelation);
+        return windowPositionFromIconPosition(r, iconPosition, windowWidth, windowHeight);
+    }
+    
+    public static Rectangle windowPositionFromIconPosition(Rectangle iconAbsolute, Rectangle iconRelative, int windowWidth, int windowHeight){
+    	return new Rectangle( iconAbsolute.x - iconRelative.x, iconAbsolute.y - iconRelative.y,
+    						windowWidth, windowHeight);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentNotFoundException.java	Fri Apr 26 20:24:55 2013 +0200
@@ -0,0 +1,65 @@
+/* ComponentNotFoundException.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+package net.sourceforge.jnlp.awt.imagesearch;
+
+/**
+ * Class ComponentNotFoundException is thrown in the AWTFramework
+ * in such cases when a position of a component is needed for further
+ * action and the component is not found in the screenshot (for example
+ * a method should click on a button of given colour and the button
+ * is not found, then the method cannot perform its action and
+ * throws ComponentNotFoundException). 
+ *
+ */
+public class ComponentNotFoundException extends Exception {
+    
+    public ComponentNotFoundException() { 
+        super(); 
+    }
+    
+    public ComponentNotFoundException(String s) { 
+        super(s); 
+    }
+    
+    public ComponentNotFoundException(String s, Throwable throwable) { 
+        super(s, throwable); 
+    }
+    
+    public ComponentNotFoundException(Throwable throwable) {
+        super(throwable); 
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ImageSeeker.java	Fri Apr 26 20:24:55 2013 +0200
@@ -0,0 +1,325 @@
+/* ImageSeeker.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+
+package net.sourceforge.jnlp.awt.imagesearch;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+
+
+public class ImageSeeker
+{
+    public static Rectangle findExactImage(BufferedImage marker, BufferedImage screen){
+        return findExactImage(marker, screen, new Rectangle(0,0,screen.getWidth(), screen.getHeight()));
+    }
+    
+    public static Rectangle findExactImage(BufferedImage marker, BufferedImage screen, Rectangle actionArea){
+        Rectangle result = new Rectangle(0,0,0,0);
+        boolean found = false;
+        boolean ok = true;
+        
+        for(int x = actionArea.x; (x < (actionArea.x + actionArea.width - marker.getWidth()) ) && !found; x++){
+            for(int y= actionArea.y; (y < (actionArea.y + actionArea.height - marker.getHeight()) ) && !found; y++){
+                
+                for(int mx = 0; (mx < marker.getWidth()) && ok; mx++){
+                    for(int my = 0; (my < marker.getHeight()) && ok; my++){
+                        if(marker.getRGB(mx, my) != screen.getRGB(x+mx,y+my)){
+                            ok = false;
+                        }
+                    }
+                }
+                if( ok ){
+                    found = true;
+                    result.x = x;
+                    result.y = y;
+                    result.height = marker.getHeight();
+                    result.width = marker.getWidth();
+                }else{
+                    ok = true;
+                }
+                
+            }
+        }
+        
+        return result;
+    }
+    
+    public static Rectangle findBlurredImage(BufferedImage marker, BufferedImage testImage, double minCorrelation){
+        return findBlurredImage(marker, testImage, minCorrelation, new Rectangle(0,0,testImage.getWidth(), testImage.getHeight()));
+    }
+    
+    public static Rectangle findBlurredImage(BufferedImage marker, BufferedImage testImage, double minCorrelation, Rectangle actionArea)
+    {
+        int maxX = actionArea.width - marker.getWidth() - 1;
+        int maxY = actionArea.height - marker.getHeight() - 1;
+        int markerMaxX = marker.getWidth();
+        int markerMaxY = marker.getHeight();
+
+        // it is much faster to work directly with color components stored as float values
+        float[][][] testImageArray = createArrayForOneColorComponent(actionArea);
+        float[][][] markerImageArray = createArrayForOneColorComponent(marker);
+
+        convertImageToFloatArray(testImage, testImageArray, actionArea);
+        convertImageToFloatArray(marker, markerImageArray);
+
+        int bestX = -1;
+        int bestY = -1;
+        double bestCorrelation = -1;
+
+        for (int yoffset = 0; yoffset < maxY; yoffset++ )
+        {
+            for (int xoffset = 0; xoffset < maxX; xoffset++)
+            {
+                double correlation = computeCorrelation(markerMaxX, markerMaxY, testImageArray, markerImageArray, yoffset, xoffset);
+                if (correlation > bestCorrelation)
+                {
+                    bestCorrelation = correlation;
+                    bestX = xoffset + actionArea.x;
+                    bestY = yoffset + actionArea.y;
+                }
+            }
+        }
+        if(bestCorrelation > minCorrelation){
+            return new Rectangle(bestX, bestY, marker.getWidth(), marker.getHeight());
+        }else{
+            return new Rectangle(0,0,0,0);
+        }
+        
+    }
+
+    /**
+     * Create three-dimensional array with the same size as tested image
+     * dimensions (last dimension is used for storing RGB components).
+     * 
+     * @param testImage tested image
+     * @return newly created three-dimensional array
+     */
+    private static float[][][] createArrayForOneColorComponent(BufferedImage testImage)
+    {
+        return new float[testImage.getHeight()][testImage.getWidth()][3];
+    }
+    
+    /**
+     * Create three-dimensional array with the same size as the given area
+     * dimensions (last dimension is used for storing RGB components).
+     * 
+     * @param actionArea
+     * @return newly created three-dimensional array
+     */
+    private static float[][][] createArrayForOneColorComponent(Rectangle actionArea)
+    {
+        return new float[actionArea.height][actionArea.width][3];
+    }
+
+    /**
+     * Conversion from BufferedImage into three dimensional float arrays.
+     * It's much faster to work with float arrays even if it's memory ineficient.
+     *
+     * @param testImage tested image
+     * @param array array to fill
+     */
+    private static void convertImageToFloatArray(BufferedImage testImage, float[][][] array)
+    {
+        for (int y = 0; y < testImage.getHeight(); y++)
+        {
+            for (int x = 0; x < testImage.getWidth(); x++)
+            {
+                int c = testImage.getRGB(x, y);
+                // filter out alpha channel
+                c = c & 0xffffff;
+                array[y][x][0] = ((c >> 16) & 0xff) - 128f;
+                array[y][x][1] = ((c >> 8) & 0xff) - 128f;
+                array[y][x][2] = (c & 0xff) - 128f;
+            }
+        }
+    }
+
+    /**
+     * Conversion from BufferedImage into three dimensional float arrays.
+     * It's much faster to work with float arrays even if it's memory ineficient.
+     * This method converts only a given part of the image (actionArea)
+     * 
+     * @param testImage tested image
+     * @param array array to fill
+     * @param actionArea rectangle part of the image to convert
+     */
+    private static void convertImageToFloatArray(BufferedImage testImage, float[][][] array, Rectangle actionArea)
+    {
+        for (int y = actionArea.y; y < (actionArea.height + actionArea.y); y++)
+        {
+            for (int x = actionArea.x; x < (actionArea.width + actionArea.x); x++)
+            {
+                int c = testImage.getRGB(x, y);
+                // filter out alpha channel
+                c = c & 0xffffff;
+                array[y - actionArea.y][x - actionArea.x][0] = ((c >> 16) & 0xff) - 128f;
+                array[y - actionArea.y][x - actionArea.x][1] = ((c >> 8) & 0xff) - 128f;
+                array[y - actionArea.y][x - actionArea.x][2] = (c & 0xff) - 128f;
+            }
+        }
+    }
+    
+    /**
+     * Compute correlation for given two images and 2D offset.
+     *
+     * @param maxX
+     * @param maxY
+     * @param testImageArray
+     * @param markerImageArray
+     * @param yoffset
+     * @param xoffset
+     * @return
+     */
+    private static double computeCorrelation(int maxX, int maxY, float[][][] testImageArray,
+                    float[][][] markerImageArray, int yoffset, int xoffset)
+    {
+        double correlation = 0;
+        for (int y = 0; y < maxY; y++)
+        {
+            for (int x = 0; x < maxX; x++)
+            {
+                for (int rgbIndex = 0; rgbIndex < 3; rgbIndex++)
+                {
+                    float colorComponent1 = markerImageArray[y][x][rgbIndex];
+                    float colorComponent2 = testImageArray[yoffset + y][xoffset + x][rgbIndex];
+                    correlation += colorComponent1 * colorComponent2;
+                }
+            }
+        }
+        return correlation;
+    }
+
+    public static int findHorizontalRule(BufferedImage screen,
+            Color ruleColor, Color bgColor, boolean fromTop) {
+        final int height = screen.getHeight();
+        int gap = 0;
+
+        if (!fromTop) {
+            return findHorizontalEdgeGap(screen, ruleColor,
+                    bgColor, 1, height - 1, gap);
+        } else {
+            return findHorizontalEdgeGap(screen, bgColor,
+                    ruleColor, 1, height - 1, gap);
+        }
+    }
+
+    public static int findHorizontalEdgeGap(BufferedImage screen,
+            Color area1Color, Color area2Color, int y1, int y2, int gap) {
+        final int width = screen.getWidth(); 
+        final int area1RGB = area1Color.getRGB();
+        final int area2RGB = area2Color.getRGB();
+        int edgePosition = Integer.MIN_VALUE;
+        int lastFound = Integer.MIN_VALUE;
+        
+        for (int y = y1+1; y < y2 - gap; y++) {
+            int found = 0;
+            for (int x = 0; x < width; x++) {
+                int c1 = screen.getRGB(x, y - 1);
+                int c2 = screen.getRGB(x, y + gap);
+                if (c1 == area1RGB && c2 == area2RGB) {
+                    found++;
+                }
+            }
+            if (found > lastFound) {
+                lastFound = found;
+                edgePosition = y;
+            }
+            
+        }
+        
+        return edgePosition;
+    }
+
+    public static int findVerticalEdgeGap(BufferedImage screen,
+            Color area1Color, Color area2Color, int y1, int y2, int gap) {
+        final int width = screen.getWidth();
+        final int area1RGB = area1Color.getRGB();
+        final int area2RGB = area2Color.getRGB();
+        int edgePosition = Integer.MIN_VALUE;
+        int lastFound = Integer.MIN_VALUE;
+
+        for (int x = 1; x < width - 1 - gap; x++) {
+            int found = 0;
+            for (int y = y1; y < y2; y++) {
+                int c1 = screen.getRGB(x - 1, y);
+                int c2 = screen.getRGB(x + gap, y);
+                if (c1 == area1RGB && c2 == area2RGB) {
+                    found++;
+                }
+            }
+            if (found > lastFound) {
+                lastFound = found;
+                edgePosition = x;
+            }
+        }
+        
+        return edgePosition;
+    }
+
+    /**
+     * method findColoredAreaGap finds a rectangle of given color surrounded by
+     * area of the second color with a possible gap at the border
+     * 
+     * @param screen
+     * @param searchForColor
+     * @param surroundWithColor
+     * @param y1
+     * @param y2
+     * @param gap
+     * @return
+     */
+    public static Rectangle findColoredAreaGap(BufferedImage screen, Color searchForColor, Color surroundWithColor, int y1, int y2,    int gap) {
+        
+        int ymin = findHorizontalEdgeGap(screen, surroundWithColor, searchForColor, y1, y2, gap);
+        int ymax = findHorizontalEdgeGap(screen, searchForColor, surroundWithColor, y1, y2, gap);
+        int xmin = findVerticalEdgeGap(screen, surroundWithColor, searchForColor, ymin, ymax, gap);
+        int xmax = findVerticalEdgeGap(screen, searchForColor, surroundWithColor, ymin, ymax, gap);
+
+        return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin);
+    }
+    
+    public static boolean isRectangleValid(Rectangle r){
+        
+        if (r == null) return false;
+        
+        return (r.width != 0)&&(r.height != 0)&&(r.x != Integer.MIN_VALUE)&&(r.y != Integer.MIN_VALUE);
+    }
+
+}
--- a/tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java	Fri Apr 26 20:11:33 2013 +0200
+++ b/tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java	Fri Apr 26 20:24:55 2013 +0200
@@ -184,6 +184,10 @@
         addRules(l);
     }
 
+    public List<Rule> getRules() {
+        return rules;
+    }
+
     public void setRules(List<Rule> rules) {
         if (rules == null) {
             throw new NullPointerException("rules cant be null");