org.deegree.test.services.wpvs.WPVSStressTest.java Source code

Java tutorial

Introduction

Here is the source code for org.deegree.test.services.wpvs.WPVSStressTest.java

Source

//$HeadURL: svn+ssh://aionita@svn.wald.intevation.org/deegree/base/trunk/resources/eclipse/files_template.xml $
/*----------------------------------------------------------------------------
 This file is part of deegree, http://deegree.org/
 Copyright (C) 2001-2009 by:
 Department of Geography, University of Bonn
 and
 lat/lon GmbH
    
 This library is free software; you can redistribute it and/or modify it under
 the terms of the GNU Lesser General Public License as published by the Free
 Software Foundation; either version 2.1 of the License, or (at your option)
 any later version.
 This library 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 Lesser General Public License for more
 details.
 You should have received a copy of the GNU Lesser General Public License
 along with this library; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 Contact information:
    
 lat/lon GmbH
 Aennchenstr. 19, 53177 Bonn
 Germany
 http://lat-lon.de/
    
 Department of Geography, University of Bonn
 Prof. Dr. Klaus Greve
 Postfach 1147, 53001 Bonn
 Germany
 http://www.geographie.uni-bonn.de/deegree/
    
 e-mail: info@deegree.org
 ----------------------------------------------------------------------------*/

package org.deegree.test.services.wpvs;

import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.imageio.ImageIO;

import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.deegree.commons.utils.Pair;
import org.deegree.protocol.wpvs.WPVSConstants.WPVSRequestType;
import org.deegree.protocol.wpvs.client.WPVSClient;
import org.deegree.tools.CommandUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The <code>WPVSStressTest</code> class generates the requests for the WPVSClient. The current command-line
 * parameters are:
 * <ul>
 * <li><b>capabilities</b> for the capabilities URL</li>
 * <li><b>threads</b> for the number of threads</li>
 * <li><b>requests</b> for the number of requests to be sent by each thread</li>
 * </ul>
 * 
 * @author <a href="mailto:ionita@lat-lon.de">Andrei Ionita</a>
 * 
 * @author last edited by: $Author: ionita $
 * 
 * @version $Revision: $, $Date: $
 * 
 */
public class WPVSStressTest {

    private final static Logger LOG = LoggerFactory.getLogger(WPVSStressTest.class);

    private int threads;

    private int requests;

    private String capabilities;

    private StringBuffer info;

    private WPVSClient client;

    private List<TestResultData> resultData;

    private List<String> imgLinks;

    private Map<String, String> paramsSet;

    // writer to a log file that describes how the tests ran (with statistics)
    private PrintWriter logWriter;

    public WPVSStressTest(int threads, int requests, String capabilities, Map<String, String> paramsSet) {
        this.requests = requests;
        this.threads = threads;
        this.capabilities = capabilities;
        this.paramsSet = paramsSet;
        System.out.println("the datasets received by the stressTest:" + paramsSet.get("datasets"));

        try {
            client = new WPVSClient(new URL(capabilities));
        } catch (MalformedURLException e) {
            LOG.error(e.getMessage(), e);
        }
    }

    /**
     * The <code>WPVSSender</code> class generates the requests to deegree3 WPVS in a thread
     * 
     * @author <a href="mailto:ionita@lat-lon.de">Andrei Ionita</a>
     * 
     * @author last edited by: $Author: ionita $
     * 
     * @version $Revision: $, $Date: $
     * 
     */
    private class WPVSSender implements Runnable {

        private int threadNo;

        // BBOX default values
        private int LOW_X = 423750;

        private int LOW_Y = 4512700;

        private int HIGH_X = 425500;

        private int HIGH_Y = 4513900;

        WPVSSender(int threadNo) {
            this.threadNo = threadNo;
        }

        /**
         * 
         * @return the URL constructed with random values for the getView parameters
         */
        private URL getGetViewURL() {
            Random generator = new Random();

            String stringURL = client.getAddress(WPVSRequestType.GetView, true);
            stringURL += "service=WPVS&request=GetView";

            // including a valid BBOX because it is required (although the actual values are not currently evaluated --
            // 26 Jun 2009)
            stringURL += "&BOUNDINGBOX=" + LOW_X + "," + LOW_Y + "," + HIGH_X + "," + HIGH_Y;

            List<String> datasets;
            if (paramsSet.containsKey("datasets")) {
                String datasetsStr = paramsSet.get("datasets");
                String[] datasetsAr = datasetsStr.split(",");
                datasets = Arrays.asList(datasetsAr);
            } else {
                // get the list of all (usable) datasets
                datasets = client.getQueryableDatasets();
            }
            Iterator<String> it = datasets.iterator();
            stringURL += "&DATASETS=";
            if (it.hasNext())
                stringURL += it.next();
            while (it.hasNext())
                stringURL += "," + it.next();

            String elevModel;
            if (paramsSet.containsKey("elevModel"))
                elevModel = paramsSet.get("elevModel");
            else {
                List<String> models = client.getElevationModels();
                int randomIndex = generator.nextInt(models.size());
                elevModel = models.get(randomIndex);
            }
            stringURL += "&ELEVATIONMODEL=" + elevModel;

            String pitch;
            if (paramsSet.containsKey("pitch")) {
                pitch = paramsSet.get("pitch");
                if (pitch.contains("_")) {
                    String[] interval = pitch.split("_");
                    int pitch1 = Integer.parseInt(interval[0]);
                    int pitch2 = Integer.parseInt(interval[1]);
                    pitch = String.valueOf(generator.nextInt(pitch2 - pitch1 + 1) + pitch1);
                }
            } else {
                int sign = generator.nextInt(2);
                pitch = String.valueOf(generator.nextInt(90));
                if (sign == 1)
                    pitch = "-" + pitch;
            }
            stringURL += "&PITCH=" + pitch;

            String yaw;
            if (paramsSet.containsKey("yaw")) {
                yaw = paramsSet.get("yaw");
                if (yaw.contains("_")) {
                    String[] interval = yaw.split("_");
                    int yaw1 = Integer.parseInt(interval[0]);
                    int yaw2 = Integer.parseInt(interval[1]);
                    yaw = String.valueOf(generator.nextInt(yaw2 - yaw1 + 1) + yaw1);
                }
            } else
                yaw = String.valueOf(generator.nextInt());
            stringURL += "&YAW=" + yaw;

            String roll;
            if (paramsSet.containsKey("roll")) {
                roll = paramsSet.get("roll");
                if (roll.contains("_")) {
                    String[] interval = roll.split("_");
                    int roll1 = Integer.parseInt(interval[0]);
                    int roll2 = Integer.parseInt(interval[1]);
                    roll = String.valueOf(generator.nextInt(roll2 - roll1 + 1) + roll1);
                }
            } else
                roll = String.valueOf(generator.nextInt());
            stringURL += "&ROLL=" + roll;

            String aov;
            if (paramsSet.containsKey("aov")) {
                aov = paramsSet.get("aov");
                if (aov.contains("_")) {
                    String[] interval = aov.split("_");
                    int aov1 = Integer.parseInt(interval[0]);
                    int aov2 = Integer.parseInt(interval[1]);
                    aov = String.valueOf(generator.nextInt(aov2 - aov1 + 1) + aov1);
                }
            } else
                aov = String.valueOf(generator.nextInt(181));
            stringURL += "&AOV=" + aov;

            if (paramsSet.containsKey("clipping"))
                stringURL += "&FARCLIPPINGPLANE=" + paramsSet.containsKey("clipping");
            else
                stringURL += "&FARCLIPPINGPLANE=10000";

            String width = "800";
            if (paramsSet.containsKey("width"))
                width = paramsSet.get("width");
            stringURL += "&WIDTH=" + width;

            String height = "600";
            if (paramsSet.containsKey("height"))
                height = paramsSet.get("height");
            stringURL += "&HEIGHT=" + height;

            String scale;
            if (paramsSet.containsKey("scale"))
                scale = paramsSet.get("scale");
            else
                scale = String.valueOf(generator.nextFloat());
            stringURL += "&SCALE=" + scale;

            stringURL += "&STYLES=default";
            stringURL += "&DATETIME=2007-03-21T12:00:00";
            stringURL += "&EXCEPTIONFORMAT=INIMAGE";
            stringURL += "&VERSION=" + "1.0.0";
            stringURL += "&OUTPUTFORMAT=" + "image/png";
            stringURL += "&BACKGROUND=" + "cirrus";

            Integer[] poiValues = new Integer[3];
            String crs = null;
            if (paramsSet.containsKey("poi")) {
                String poiStr = paramsSet.get("poi");
                String[] poiArray = poiStr.split(",");
                if (poiArray.length >= 3) {
                    for (int index = 0; index <= 2; index++) {
                        if (poiArray[index].contains("_")) {
                            String[] interval = poiArray[0].split("_");
                            float interval1 = Float.parseFloat(interval[0]);
                            float interval2 = Float.parseFloat(interval[1]);
                            poiValues[index] = generator.nextInt(Math.round(interval2 - interval1))
                                    + Math.round(interval1);
                        } else
                            poiValues[index] = Math.round(Float.parseFloat(poiArray[0]));
                    }
                    if (poiArray.length == 4)
                        crs = poiArray[3];
                }
            } else {
                poiValues[0] = 2568000 + generator.nextInt(2600768 - 2568000);
                poiValues[1] = 5606000 + generator.nextInt(5638768 - 5606000);
                poiValues[2] = 34 + generator.nextInt(400 - 34);
            }
            stringURL += "&POI=" + String.valueOf(poiValues[0]) + "," + String.valueOf(poiValues[1]) + ","
                    + String.valueOf(poiValues[2]);
            stringURL += "&CRS=" + crs;

            String distance;
            if (paramsSet.containsKey("distance")) {
                distance = paramsSet.get("distance");
                if (distance.contains("_")) {
                    String[] interval = distance.split("_");
                    int distance1 = Integer.parseInt(interval[0]);
                    int distance2 = Integer.parseInt(interval[1]);
                    distance = String.valueOf(generator.nextInt(distance2 - distance1 + 1) + distance1);
                }
            } else
                distance = String.valueOf(generator.nextInt(1000));
            stringURL += "&DISTANCE=" + distance;

            try {
                return new URL(stringURL);
            } catch (MalformedURLException e) {
                LOG.error(e.getMessage(), e);
                return null;
            }
        }

        public void run() {
            for (int i = 0; i < requests; i++) {
                URL url = getGetViewURL();
                LOG.info("URL: " + url);
                long startTime = System.currentTimeMillis();
                Pair<BufferedImage, String> response = null;
                try {
                    response = client.getView(url);
                } catch (IOException e) {
                    LOG.error(e.getLocalizedMessage(), e);
                }
                if (response != null) {
                    long currentTime = System.currentTimeMillis();

                    // store obtained info
                    long elapsed = currentTime - startTime;
                    resultData.add(new TestResultData(threadNo, i, elapsed));

                    // write into log file
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
                    Date date = new Date();
                    logWriter.print(dateFormat.format(date) + "     " + elapsed);

                    try {
                        if (response.first != null) {
                            File tempFile = File.createTempFile("wpvs", ".jpg");
                            ImageIO.write(response.first, "jpg", tempFile);
                            imgLinks.add(tempFile.getPath());

                            logWriter.println("     1     " + tempFile.getName() + "     " + url);

                        } else {
                            logWriter.println("     0 ");
                            // File tempFile = File.createTempFile( "wpvsOutXML", ".xml" );
                            // BufferedWriter writer = new BufferedWriter( new FileWriter( tempFile) );
                            // writer.write( response.second );
                            // info =
                            // new StringBuffer( "<a href=file://" + tempFile.getPath() +
                            // ">xml file</a>" );
                            // imgLinks.add( info.toString() );
                        }

                    } catch (IOException e) {
                        LOG.error(e.getMessage(), e);
                    }
                }
            }
        }
    }

    public List<TestResultData> getResultData() {
        return resultData;
    }

    public List<String> getImgLinks() {
        return imgLinks;
    }

    public void test() throws IOException {
        resultData = new ArrayList<TestResultData>();
        imgLinks = new ArrayList<String>();

        List<Thread> threadList = new LinkedList<Thread>();
        for (int i = 1; i <= threads; i++) {
            Thread t = new Thread(new WPVSSender(i));
            t.start();
            threadList.add(t);
        }

        // prepare Log file
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmss");
        Date date = new Date();
        String currentDate = dateFormat.format(date);
        logWriter = new PrintWriter(new BufferedWriter(new FileWriter("/tmp/" + currentDate + "-WPVS-stress.log")));
        logWriter.println("START_DATE      START_TIME      ELAPSED       SUCCESS       " + "IMAGEFILE       URL");

        try {
            for (Thread t : threadList)
                while (t.isAlive())
                    t.join();
        } catch (InterruptedException e) {
            LOG.error(e.getMessage(), e);
        }

        logWriter.close();
    }

    /**
     * 
     * @return command-line options object
     */
    private static Options initOptions() {
        Options opts = new Options();

        // Mandatory parameters
        Option opt = new Option("capabilities", true,
                "getCapabilites URL for the deegee3 WPVS; Please surround the URL with double quotes!");
        opt.setRequired(true);
        opts.addOption(opt);

        opt = new Option("threads", true, "number of Threads that will send requests to the deegee3 WPVS");
        opt.setRequired(true);
        opts.addOption(opt);

        opt = new Option("requests", true, "number of getView Requests PER Thread will sent to the deegee3 WPVS");
        opt.setRequired(true);
        opts.addOption(opt);

        // Optional parameters
        opt = new Option("datasets", true, "specify a list of datasets in "
                + "comma-separated format; by default value all datasets are used");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("elevModel", true, "specify an elevation-model; default is " + "a random elevation-model");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("width", true, "specify a width value for the resulting images; default is 800");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("height", true, "specify a height value for the resulting images; default is 600");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("pitch", true,
                "specify a Pitch value or interval " + "(using an underscore '_') between -90 and 90;"
                        + " unit of measure is degrees; the pitch is the "
                        + "angle that the direction of view makes with the Earth surface");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("yaw", true, "specify a Yaw value or inverval " + "(using an underscore '_')");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("roll", true, "specify a Roll value or interval " + "(using an underscore '_')");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("distance", true, "specify a distance to the point of interest;"
                + " an integer value or an interval (separated by underscore) are " + "valid inputs");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("aov", true, "specify an Angel-of-View value or an interval "
                + "(using an underscode '_') between 0 and 180 (measured in degrees)");
        opt.setRequired(false);
        opts.addOption(opt);

        // currently the Bounding Box is not evaluated; any valid description (xMin<xMax && yMin<yMax)
        // yields an image with having the maximum BBox coverage
        // opt = new Option( "bbox", true, "specify a fixed Bounding Box - in the format \"xLow, yLow, xHigh, yHigh\" "
        // );
        // opt.setRequired( false );
        // opts.addOption( opt );

        opt = new Option("poi", true,
                "specify a point-of-interest; valid inputs are"
                        + " 'x, y, z, crs', in which x, y and z can be fixed "
                        + "floating-point values or intervals specified using an underscore"
                        + " e.g. xMin_xMax; the crs value can be omitted ");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("scale", true,
                "specify a fixed scale for all tests; " + "by default scale values will be randomized ");
        opt.setRequired(false);
        opts.addOption(opt);

        opt = new Option("clipping", true, "specify a far-clipping-plane value, i.e "
                + " a maximum distance over which dataset is rendered; default is 10000");
        opt.setRequired(false);
        opts.addOption(opt);

        opts.addOption("?", "help", false, "print (this) usage information");

        return opts;
    }

    /**
     * 
     * @param options
     */
    private static void printHelp(Options options) {
        CommandUtils.printHelp(options, WPVSStressTest.class.getSimpleName(), "", "");
    }

    /**
     * @param args  mandatory arguments: -capabilities, -requests, -threads. To see the others, provide the argument 'help'.
     * @throws Exception    when the execution is aborted on the base of a wrong argument (or help was invoked),
     */
    public static void main(String args[]) throws Exception {
        Options options = initOptions();

        if (args != null && args.length > 0)
            if (args[0].contains("help") || args[0].contains("?")) {
                printHelp(options);
                throw new Exception("Help argument was provided. Argument support was shown.");
            }

        try {
            new PosixParser().parse(options, args);

            int noThreads = Integer.valueOf(options.getOption("threads").getValue());
            int noRequests = Integer.valueOf(options.getOption("requests").getValue());
            String getCapabilities = options.getOption("capabilities").getValue();

            Map<String, String> paramsSet = new HashMap<String, String>();
            String datasets = options.getOption("datasets").getValue();
            if (datasets != null && datasets.length() > 0)
                paramsSet.put("datasets", datasets);

            String elevModel = options.getOption("elevModel").getValue();
            if (elevModel != null && elevModel.length() > 0)
                paramsSet.put("elevModel", elevModel);

            String width = options.getOption("width").getValue();
            if (width != null) {
                Integer.parseInt(width);
                paramsSet.put("width", width);
            }

            String height = options.getOption("height").getValue();
            if (height != null) {
                Integer.parseInt(height);
                paramsSet.put("height", height);
            }

            String pitch = options.getOption("pitch").getValue();
            if (pitch != null) {
                checkIntegerOrBoundInterval(pitch, "pitch", -90, 90);
                paramsSet.put("pitch", pitch);
            }

            String yaw = options.getOption("yaw").getValue();
            if (yaw != null) {
                checkIntegerOrInterval(yaw, "yaw");
                paramsSet.put("yaw", yaw);
            }

            String roll = options.getOption("roll").getValue();
            if (roll != null) {
                checkIntegerOrInterval(roll, "roll");
                paramsSet.put("roll", roll);
            }

            String distance = options.getOption("distance").getValue();
            if (distance != null) {
                checkIntegerOrInterval(distance, "distance");
                paramsSet.put("distance", distance);
            }

            String aov = options.getOption("aov").getValue();
            if (aov != null) {
                checkIntegerOrBoundInterval(aov, "aov", 0, 180);
                paramsSet.put("aov", aov);
            }

            String poi = options.getOption("poi").getValue();
            String crs = null;
            if (poi != null) {
                String[] values = poi.split(",");
                if (values.length == 3) {
                    checkFloatOrInterval(values[0], "poi, x-value");
                    checkFloatOrInterval(values[1], "poi, y-value");
                    checkFloatOrInterval(values[2], "poi, z-value");
                } else if (values.length == 4) {
                    checkFloatOrInterval(values[0], "poi, x-value");
                    checkFloatOrInterval(values[1], "poi, y-value");
                    checkFloatOrInterval(values[2], "poi, z-value");
                    crs = values[3];
                } else {
                    System.err.println("ERROR: The poi argument must have 3 or 4 " + "comma-separated values");
                }
                paramsSet.put("poi", poi);

            }

            String scale = options.getOption("scale").getValue();
            if (scale != null && scale.length() > 0)
                paramsSet.put("scale", scale);

            String clipping = options.getOption("clipping").getValue();
            if (clipping != null) {
                Integer.parseInt(clipping);
                paramsSet.put("clipping", clipping);
            }

            WPVSStressTest current = new WPVSStressTest(noThreads, noRequests, getCapabilities, paramsSet);
            current.test();

        } catch (ParseException e) {
            System.err.println("ERROR: Invalid command line: " + e.getMessage());
        } catch (NumberFormatException e) {
            System.err.println("ERROR: " + e.getMessage());
        }
    }

    private static void checkFloatOrInterval(String arg, String name) throws Exception {
        if (!arg.contains("_")) {
            Float.parseFloat(arg);
        } else {
            String[] argInterval = arg.split("_");
            if (argInterval.length != 2) {
                String msg = "ERROR: The " + name
                        + " interval should be two floating point numbers separated by an underscore ('_') ";
                LOG.error(msg);
                throw new Exception(msg);
            }

            float a = Float.parseFloat(argInterval[0]);
            float b = Float.parseFloat(argInterval[1]);
            if (a >= b) {
                String msg = "ERROR: The " + name + " interval should consist of two numbers a_b with a < b";
                LOG.error(msg);
                throw new Exception(msg);
            }
        }
    }

    private static void checkIntegerOrInterval(String arg, String name) throws Exception {
        if (!arg.contains("_")) {
            Integer.parseInt(arg);
        } else {
            String[] argInterval = arg.split("_");
            if (argInterval.length != 2) {
                String msg = "ERROR: The " + name
                        + " interval should be two integers separated by an underscore ('_') ";
                LOG.error(msg);
                throw new Exception(msg);
            }

            int a = Integer.parseInt(argInterval[0]);
            int b = Integer.parseInt(argInterval[1]);
            if (a >= b) {
                String msg = "ERROR: The " + name + " interval should consist of two numbers a_b with a < b";
                LOG.error(msg);
                throw new Exception(msg);
            }
        }
    }

    private static void checkIntegerOrBoundInterval(String arg, String name, int lowEnd, int highEnd)
            throws Exception {
        if (!arg.contains("_")) {
            int argInt = Integer.parseInt(arg);
            if (argInt < lowEnd || argInt > highEnd) {
                String msg = "ERROR: The " + name + " value should be between " + lowEnd + " and " + highEnd;
                LOG.error(msg);
                throw new Exception(msg);
            }
        } else {
            String[] argInterval = arg.split("_");
            if (argInterval.length != 2) {
                String msg = "ERROR: The " + name
                        + " interval should be two integers separated by an underscore ('_') ";
                LOG.error(msg);
                throw new Exception(msg);
            }

            int arg1 = Integer.parseInt(argInterval[0]);
            if (arg1 < lowEnd || arg1 > highEnd) {
                String msg = "ERROR: The " + name + " interval values should be " + "between " + lowEnd + " and "
                        + highEnd;
                LOG.error(msg);
                throw new Exception(msg);
            }

            int arg2 = Integer.parseInt(argInterval[1]);
            if (arg2 < lowEnd || arg2 > highEnd) {
                String msg = "ERROR: The " + name + " interval values should be " + "between " + lowEnd + " and "
                        + highEnd;
                LOG.error(msg);
                throw new Exception(msg);
            }

            if (arg1 >= arg2) {
                String msg = "ERROR: The " + name + " interval should consist of two numbers a_b with a < b";
                LOG.error(msg);
                throw new Exception(msg);
            }
        }
    }

}