From 327c11e23a02c3faba5fb056d08d904fa77eeb7d Mon Sep 17 00:00:00 2001 From: Nikolaus Krismer <niko@krismer.de> Date: Thu, 27 Feb 2014 13:23:39 +0100 Subject: [PATCH] reworked documentation --- doc/config.ad | 7 ------ doc/configWeb.ad | 26 +++++++++++++++++++ doc/index.ad | 11 ++++---- doc/packages.ad | 49 +++++++++++++----------------------- doc/runSimple.ad | 38 ---------------------------- doc/runtimeTest.ad | 32 ----------------------- doc/testing.ad | 12 +++++---- doc/webapp.ad | 22 ++++++++-------- doc/webapp_architecture.dia | Bin 4035 -> 0 bytes 9 files changed, 65 insertions(+), 132 deletions(-) create mode 100644 doc/configWeb.ad delete mode 100644 doc/runSimple.ad delete mode 100644 doc/runtimeTest.ad delete mode 100644 doc/webapp_architecture.dia diff --git a/doc/config.ad b/doc/config.ad index 6913ee59..94878032 100644 --- a/doc/config.ad +++ b/doc/config.ad @@ -31,13 +31,6 @@ connect * org.postgresql.password: The database password * org.postgresql.port: The port to which the database server listens -Geoserver configuration ------------------------ - -// TODO: Needs more documentation -A deticated workspace will be generated on application startup. -One should not configure a workspace where datastores are already defined - Configuration for the individual algorithms ------------------------------------------- diff --git a/doc/configWeb.ad b/doc/configWeb.ad new file mode 100644 index 00000000..c8f22394 --- /dev/null +++ b/doc/configWeb.ad @@ -0,0 +1,26 @@ +WebConfiguration +================ +Nikolaus Krismer <nikolaus.krismer@uibk.ac.at> +:date: 27 Feb 2014 + +In addition the the algorithm's configuration the web application needs +some more data. The information provided is used to connect to a geoserver +instance which is used to draw layers that can be viewed by a browser. In +cases the browser will utilize a map engine for doing so. To implement a +standardized interface in the server the geoserver is used. + +Geoserver configuration +----------------------- + +The geoserver is configured within the database configuration file. This +file is located in $PROJECT_ROOT/src/{test,main}/resources/config.xml. +The values to be configured are: + +* rendering.server.rest.url: The url where the webserver's rest interface can be found (e.g. http://localhost:8080/geoserver) +* rendering.server.rest.username: The name of the user that can connect to the geoserver (needs right to create ws, ds, layers) +* rendering.server.rest.password: The password for the specified user that is used for authentication +* rendering.server.rest.workspace: The workspace to create layers in. This will be created on applicatoin start (if it does not exist) +* rendering.server.rest.datastore: The datastore to create layers in. This will be created on applicatoin start (if it does not exist) + +On application starttup a dedicated workspace will be generated. +One should not configure a workspace where datastores are already defined \ No newline at end of file diff --git a/doc/index.ad b/doc/index.ad index f88ba38f..b87f0e60 100644 --- a/doc/index.ad +++ b/doc/index.ad @@ -1,8 +1,8 @@ Isochrone algorithm =================== -Thomas Gummerer <t.gummerer@gmail.com> -:date: 8 May 2013 -:website: http://www.inf.unibz.it/dis/projects/isochrone/index.html +Nikolaus Krismer <nikolaus.krismer@uibk.ac.at> +:date: 27 Feb 2014 +:website: http://dbis-isochrone.uibk.ac.at The Isochrone project currently consists of 3 Isochrone algorithms, which differ mostly in the way the data is loaded from the database. @@ -17,9 +17,8 @@ http://www.inf.unibz.it/dis/projects/isochrone/paper.html. * link:index.html[Overview of the Isochrone algorithm] * link:runtimeComparison.html[Comparison between the old and new code] * link:isochroneParameters.html[Parameters that define the isochrone] -* link:runSimple.html[How to run a simple test] -* link:runtimeTest.html[More advanced performance testing] -* link:config.html[Configuration of the database] +* link:config.html[Configuration of the database and datasets] +* link:configWeb.html[Configuration of the geoserver] * link:packages.html[Organization of the source code] * link:testing.html[Testing] diff --git a/doc/packages.ad b/doc/packages.ad index a1ccdb49..e37fd220 100644 --- a/doc/packages.ad +++ b/doc/packages.ad @@ -1,39 +1,36 @@ Organization of the source code =============================== -Thomas Gummerer <t.gummerer@gmail.com> -:date: 15 May 2013 +Nikolaus Krismer <nikolaus.krismer@uibk.ac.at> +:date: 27 Feb 2014 -The source code is organized in multiple packages listed below. The -prefix it.unibz.inf.isochrones will be omitted for simplicity. +The source code is organized in multiple packages listed below. +The prefix it.unibz.inf.isochrones will be omitted for simplicity. * algorithm -* datastructures +* config * db * network -* tests -* utils +* util Algorithm package ----------------- -Contains only the actual isochrone algorithm. +Contains the actual isochrone algorithm. -Datastructure package ---------------------- +Config package +-------------- -Contains all the datastructures necessary for the isochrone -algorithm. The package contains two classes, the GeoPoint and the -QueryPoint classes. +Contains the configuration files for the database and the datasets. Network package --------------- This package contains the network loading for all the different -algorithms. The algorithms only differ in the way the network is +algorithms. The algorithms only differ in the way the network is loaded, therefore we will have different classes for the MDijkstra, -MineX and MrneX network loading. In addition there is a Memory -network, which is used for testing the isochrone algorithm. These -classes all implement the Network interface. They can also implement +MineX and MrneX network loading. In addition there is a Memory +network, which is used for testing the isochrone algorithm. These +classes all implement the Network interface. They can also implement the ExpirableNetwork interface if the nodes should be deleted from the network when they are expired. @@ -60,25 +57,13 @@ class gets them from there. The ConnectionFactory class makes the actual connections to the database. -Tests package -------------- - -The test package contains all the tests that can be executed -(RunSimple and RuntimeTest). The package also includes the Parameters -class used to configure the tests. - - -Utils package +Util package ------------- The utils package contains various utilities for the calculation of the isochrones. The following classes are in the package: -* Config.java: Load the configuration files for the database. -* Enums.java: All the different enums (data sets, network mode and +* DistanceAlgorithm.java: Used to calculate interpolations between two points. +* EnumContainer.java: All the different enums (data sets, network mode and direction). * Point.java: Represents a point with x and y coordinate. -* Constants.java: All constants that are used in the algorithm. -* MathUtil.java: Used to calculate interpolations between two points. -* PointUtil.java: Used to calculate ranges and euclidian distances -between points. diff --git a/doc/runSimple.ad b/doc/runSimple.ad deleted file mode 100644 index cb0336cd..00000000 --- a/doc/runSimple.ad +++ /dev/null @@ -1,38 +0,0 @@ -RunSimple: Run the algorithm and measure the times -================================================== -Thomas Gummerer <t.gummerer@gmail.com> -:date: 9 May 2013 - -RunSimple is a very simplistic and minimal test class. To execute it, just use `gradle testSimple` -` in the command line from the project root. (For more -comprehensive testing see link:runtimeTests.html[RuntimeTests]). To -simplify it even more, you can also use the executeTests.sh script in -the root directory of the project. This script also sets the memory -parameters for the java virtual machine, because it might run out for -large networks with the default settings (Especially when using the -IT dataset and the MDijkstra algorithm). - -The test measures the time the algorithm needs to be executed in -milliseconds and displays it once it's done. Note that long execution -times can be expected for some tests. - -Running tests -------------- - -The test is relatively easy to configure (at the source code level, -there are no other configuration options yet). By default the MrneX -algorithm is executed, with the default parameters from the -link:isochroneParameters.html[Parameters] class. Those can be eider -modified by changing the default values in the Parameters class or by -instantiating the class differently on line 22 as shown in the -documentation. The algorithm that should be executed can easily be -changed by changing line 26 of the class to the runMinex() or -runMDijkstra(), depending on what algorithm should be executed. - -The default setting is to remove the nodes from the network once they -are expired, which can be changed for each algorithm in the -query.setExpireNodes() method call. - -The program doesn't accept any command line parameters at the time of -this writing, because it will be used purely as demonstration program, -therefore it's not really necessary for further development. diff --git a/doc/runtimeTest.ad b/doc/runtimeTest.ad deleted file mode 100644 index 6bb91cab..00000000 --- a/doc/runtimeTest.ad +++ /dev/null @@ -1,32 +0,0 @@ -RuntimeTest: More in depth performance testing -============================================== -Thomas Gummerer <t.gummerer@gmail.com> -:date: 13 May 2013 - -The RuntimeTest class is another test class, which executes a variety -of tests without the interaction of the user. To run it, change the -mainClass from `it.unibz.inf.isochrones.tests.RunSimple` to -`it.unibz.inf.isochrones.tests.RuntimeTest` in the pom.xml file in the -project root directory and then use the `executeTests.sh` script to -run it. Note that the whole test script takes a long time to execute, -but can be stopped any time. - -Testing -------- - -All algorithms (MDijkstra, MineX, MrneX) are tested as part of the -test program. They are all tested with all possible data sets (BZ, SF, -ST, IT), for different run times (1min, 2min, 4min, 8min, 20min, 1h, -2h, 4h and 10h). Each test is executed 5 times (simply changeable at -the source code level) and the best of the times is printed. The -multiple runs are done to account for discrepancies that are caused by -different loads, etc. - -Output ------- - -The test outputs all the progress information to stderr and all the -test results to stdout. This makes it easy to redirect the actual -information to a file, while having all the progress information on -the shell to be able to estimate how long the test will still take to -run. diff --git a/doc/testing.ad b/doc/testing.ad index 45fb6b1e..d559fa2f 100644 --- a/doc/testing.ad +++ b/doc/testing.ad @@ -1,13 +1,15 @@ Testing ======= -Thomas Gummerer <t.gummerer@gmail.com> -:date: 21 May 2013 +Nikolaus Krismer <nikolaus.krismer@uibk.ac.at> +:date: 27 Feb 2014 The algorithms are automatically tested using unit tests. All unit tests are found under the src/test/java directory and can be executed using the `gradle test` command. -The link:config.html[configuration] for the tests is separate +The link:config.html[configuration] for the tests can be separated from the configuration for the production code to allow different -database settings for testing and production. The directory for the -settings is: src/test/resources. +database settings for testing and production. The directory for these +separate settings is: src/test/resources. Here the database configuration +values can be (but do not have to be) overwritten. This can be done by +adding a config-test.xml with the new configuration values. diff --git a/doc/webapp.ad b/doc/webapp.ad index c64ba442..10518185 100644 --- a/doc/webapp.ad +++ b/doc/webapp.ad @@ -5,7 +5,7 @@ Thomas Gummerer<t.gummerer@gmail.com> The server for the Webapp can be started using `gradle jettyRun`. After starting the server, the website can then be opened in a web browser -under the address http://localhost:8080/isochrones/. +under the address http://localhost:8080/isochrone/. Everything belonging to ISOGA is in the `it.unibz.inf.isoga package`. @@ -16,19 +16,17 @@ When the user requests a new isochrone, the browser sends a new request to the server, which calculates the isochrone using the Isochrone class in the `it.unibz.inf.isochrone.algorithm` package. -When the isochrone is calculated, the server sends the new status to -the browser, in order to be able to notify the user. At the same -time, the data for the Isochrone is given to the CoverageBuilder -class, which calculates the coverage on the map, and writes that data -to specially created tables in the database. The CoverageBuilder then -notifies the IsochroneService, which in turn communicates the new -status (finished coveraging) and the names of the database tables to -the browser. +When the isochrone is calculated, the data for the Isochrone is given +to the CoverageBuilder class, which calculates the coverage on the map, +and writes that data to specially created tables in the database. +The CoverageBuilder then notifies the IsochroneService, which in turn +communicates the new status (finished coveraging) and the names of the +database tables to the browser. -The browser then creates a new request to the GeoServer. The +The browser then creates a new request to the GeoServer. The GeoServer is responsible for rendering the map overlay and sending the -images back to the browser. Finally the browser can show the -isochrone to the user. +images back to the browser. Finally the browser can show the isochrone +to the user. Additional Statistics ~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/webapp_architecture.dia b/doc/webapp_architecture.dia deleted file mode 100644 index b71bcad4fcfe764bcc001edc7e3f730c137923ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4035 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 -- GitLab