Skip to content

oskopek/TransportEditor

Repository files navigation

TransportEditor

build status

My Bachelor thesis and individual software project, TransportEditor.

TransportEditor aims to be a problem editor and plan visualizer for the Transport domain from the IPC 2008. The goal is to create an intuitive GUI desktop application for making quick changes and re-planning, but also designing a new problem dataset from scratch.

Screenshot

TransportEditor screenshot

Getting help

For users looking for help: a manual describing all possible features of TransportEditor is available in the app itself: in the upper menu bar item Help → Help.

Post any development questions or comments you may have on Stack Overflow and/or don’t hesitate to open an issue.

Running TransportEditor releases

  • Download a release from https://github.com/oskopek/TransportEditor/releases

  • To directly run TransportEditor, download the executable JAR file: TransportEditor-VERSION-jar-with-dependencies.jar

  • If you want to run a release, just try: java -jar TransportEditor-VERSION-jar-with-dependencies.jar

Building & running TransportEditor

  • See the section (further down) on How-to setup your build environment first.

  • Recommended: mvn clean install -DskipTests

  • To run unit tests: mvn clean install

  • To run integration tests: mvn clean install -Pit

  • To clean, run: mvn clean

  • To build docs too: mvn clean install -Pdocs

  • Run TransportEditor:

    • If you followed the build environment setup and want to run your version of TransportEditor, run mvn exec:java from the transport-editor module directory.

    • If you want to run a translated version of TransportEditor, set your system locale accordingly and restart TransportEditor. If you want to try out a translated version (on Linux), try: LC_ALL="LOCALE" java -jar TransportEditor.jar, where LOCALE is any locale available on your system (run locale -a to view all available).

TransportEditor uses semantic versioning.

Setup your build environment

Linux & Mac

  1. Install Git

    • Fedora: sudo dnf install git

    • Ubuntu: sudo apt-get install git

  2. Install git-lfs from https://git-lfs.github.com/

  3. Install Java8 JDK — Oracle JDK Downloads — Select: Java Platform (JDK)

    • NOTE: You need jdk-8u40 or newer (JavaFX 8 dependency).

  4. Install Maven — preferably the latest version you can. Usually, your distribution’s package management repository is enough:

    • Fedora: sudo dnf install mvn

    • Ubuntu: sudo apt-get install maven

  5. Fork the repository — Create a fork of the oskopek/TransportEditor repository (under the logo) on GitLab, usually the fork will be called: yourusername/TransportEditor.

  6. Clone the your fork — run git clone https://gitlab.com/yourusername/TransportEditor.git (or, preferably, use SSH: git clone [email protected]:yourusername/TransportEditor.git)

  7. Pull the LFS files — run git lfs pull

  8. Run the build (see the Building section)

Windows

  1. Install Java8 JDK — Oracle JDK Downloads — Select: Java Platform (JDK)

  2. Install Maven — (preferably the latest version you can). See: Maven on Windows and Maven Downloads.

  3. Download and install GitHub for Windows at http://windows.github.com/. If you encounter any problems, see the GitHub for Windows FAQ.

  4. Find the oskopek/TransportEditor repository on GitHub.

  5. Create a fork of the repository (right upper corner), usually the fork will be called yourusername/TransportEditor.

  6. Run the build (see the Building section)

  7. The following workflow may be useful for you, if you’re not familiar with Git/GitHub for Windows:

    1. In the upper left window, you can view all uncommitted changes. Write the name and description of your changes and click the check button.

    2. Once in a while, be sure to sync to send all commits to your GitHub fork.

    3. After testing your changes, submit a pull request to oskopek/TransportEditor through GitHub.

      1. Click on compare across forks.

      2. Set the following:

        • base fork: oskopek/TransportEditor

        • base: master

        • head fork: yourusername/TransportEditor

        • compare: branchname

    4. Click on Click to create a pull request for this comparison.

    5. Our GitLab/Travis continuous integration server will test the merge of your pull request. You can view the results in the thread of the pull request.

    6. Congratulations! Your pull request will get reviewed and probably be merged in.

Submitting an Issue

We use the GitLab issue tracker to track bugs and features. Before submitting a bug report or feature request, check to make sure it hasn’t already been submitted. When submitting a bug report, please include a public/internal Snippet that includes a stack trace and any details that may be necessary to reproduce the bug, including your Java version and operating system.

Contributing

NO CONTRIBUTIONS ARE ACCEPTED AT THIS TIME, THIS IS A CLASSROOM PROJECT.

Everyone is encouraged to help improve this project.

Here are some ways you can contribute:

  • by using alpha, beta, and pre-release versions

  • by reporting bugs

  • by suggesting new features

  • by translating to a new language

  • by writing or editing documentation

  • by writing specifications

  • by writing code (no patch is too small: fix typos, add comments, clean up inconsistent whitespace)

  • by refactoring code

  • by closing issues

  • by reviewing patches

Submitting a Pull Request

  1. Fork the repository

  2. Create a topic branch

  3. Optional: To ease the process of contributing code back into TransportEditor, please set-up IDE coding templates first

  4. Implement your feature or bug fix

  5. If applicable, add tests and documentation for your feature or bug fix (see How-to write documentation)

  6. Run mvn clean install -Pit

  7. If the tests fail, return to step 3 and 4

  8. Add, commit, and push your changes

  9. Submit a pull request


Development documentation

Short design description

The model for the Transport domain is pretty complicated, because it handles:

  • Multiple variants of the Transport domain

  • Planning and visualization with the same model

That’s what this short section is for — describing the ideas behind the model, so that reading the code afterwards is easier.

The model is split into 4 parts:

  • Session

  • Domain

  • Problem

  • Plan

Plan

The plan consists of an ordered list of actions. There are two types of plans:

  • Sequential - these plans are strictly linear, actions do not overlap. (imagine simple linked list)

  • Temporal - every action in this plan has a time interval in which it takes place. This plan is basically a set of intervals with associated actions. For storing it, we use an Interval tree, which allows efficient access to actions given a time or time range.

Visualizing plans

There are currently two ways to visualize both plan types:

  • Simple list — both sequential and temporal versions look similar. Both are filterable by right clicking on the headers.

    • Sequential: uses a simple drag-and-drop reorderable table of action arguments. See the screenshot on the top of the README for a preview. Is redrawn completely after every change.

    • Temporal: in contrast to the sequential variant, this one cannot be reordered by dragging. The start times can however be edited, which will result in the table reordering itself. Is not redrawn completely, adjusts its internal state and redraws the necessary parts.

  • Gantt chart — both sequential and temporal versions look alike, resembling a XY chart, the X axis being the time axis and the Y axis having all action objects. Both are redrawn every time the plan changes or it’s filter in the simple list is changed.

    • Sequential: using it to visualize sequential plans is quite non-interesting, as it offers almost no added insights on top of the simple list

    • Temporal: when visualizing temporal plans with a Gantt, we can observe the synchronicity of planned actions and, to some extent, the cooperation of individual actors

Persisting plans

Using string manipulation and built-in constants and format, it is persisted into a VAL-like format. For parsing, we assume a correct and valid VAL-like plan. A very simple string manipulation and Regex-based approach is used for both temporal and sequential plans. Additionally, a simple ANTLR grammar is used in some places. See the persistence package for details.

Problem

The problem is basically a graph (with multiple possible "layers", f.e. fuel) and a vehicle and package map.

Currently we use GraphStream for both the data storage and visualization of the graph. Apart from nodes and edge arrows, everything else is visualized as "sprites".

Fuel is added as different graph edge type (FuelRoad instead of DefaultRoad) and a domain label change (see `PddlLabel`s in the domain). If the domain is fuel enabled, the fuel properties of locations, roads and vehicles else will be displayed.

Visualizing problems

Problem visualization does not fundamentally differ between different domains and problems. Some problem tooltips/properties might dis/appear when changing the domain type.

The graph is automatically laid out using a SpringBox algorithm from GraphStream for a given time and then switched to manual layout.

Persisting problems

Both rule pages of IPC-6 and IPC-8 specify PDDL 3.1 as their official modelling language (language for domain and problem specification). Daniel L. Kovacs proposed an updated and corrected BNF (Backus-Naur Form) definition of PDDL 3.1.

Using a Freemarker template and a lot of string manipulation it is persisted into PDDL. For parsing, we assume a correct and valid problem and use a formal grammar written in ANTLR to parse PDDL into a generated code structure provided by ANTLR and the maven-antlr-plugin. The same grammar as for domains is used. See the persistence package and the src/main/antlr4 folder for details.

Domain

There is basically only one domain type: VariableDomain (we also have the notion of a SequentialDomain, but it is basically just an in-code hardcoded equivalent of loading the sequential Transport domain PDDL into a VariableDomain).

The domain contains flags (labels), telling us which "layers" are enabled and which are not. The UI, validator, IO and planner all take these into account. It also contains methods for action creation using their correct domain-specified definitions and provides other useful data (predicates, functions, …​).

Visualizing domains

Domains are not visualizable per se.

Persisting domains

Using a Freemarker template and a lot of string manipulation it is persisted into PDDL. For parsing, we assume a correct and valid problem and use a formal grammar written in ANTLR to parse PDDL into a generated code structure provided by ANTLR and the maven-antlr-plugin. The same grammar as for problems is used.

TransportEditor doesn’t load the PDDL domain definitions directly — those are already built-in. We only read the domain files to check which subset of conditions the user has chosen to model.

In the UI, we can also create a domain using a dialog backed by the VariableDomainBuilder. It is essentially switchboard for gathering the appropriate flags and other properties the domain should have.

Session

The session is where everything comes together. It keeps an instance of the domain, problem and plan (and planner and validator, …​). We can use it to reason about what actions can be executed in the UI with the currently loaded objects and also as a quick persistence solution — if you save a session, you can then load it next time and do not have to open all the individual parts again.

Visualizing sessions

Sessions are visualized by visualizing all their (possible) parts.

Persisting sessions

Sessions are persisted automatically to XML using XStream. This means, all its properties should be reasonably serializable (by reflection).

Planning

Any class implementing the Planner interface can be set as the planner for a session and if it has all the properties that are needed (domain & problem), we can generate a plan using an instance of that class. TransportEditor supports external (executable) planners out of the box, given that the executable adhere to a few rules (for details, see ExternalPlanner). An end of planning event is raised after planning finishes, for UI redrawing purposes.

Validation

Any class implementing the Validator interface can be used as a validator for plans in a planning session. Validation happens automatically after planning in a session or it can be triggered manually. There are different validators with different strictness (used for different domain variants). Choosing a wrong combination of domain, problem and validator might cause false positives or false negatives, make sure to read the documentation of the individual validators. TransportEditor supports a popular external validator called VAL, out of the box.

General notes

There are few other small features of the project worth mentioning.

CDI & the EventBus

CDI (Context and Dependency Injection) using Weld is used for inversion of control and for communication without tight coupling. Should only be used in the UI part of the project.

For event-driven communication on the front end, Guava’s EventBus is used. Again, it enables persistent reactive handling without tight coupling.

JavaFX properties and bindings

The JavaFX based UI makes heavy use of bindings and properties, essential features of JavaFX. They enable reactive changes to the UI in an efficient manner, but can be a bit tricky when reading code that uses them. For even more power, we use the ControlsFX library, but try to avoid it, if possible.

Model immutability

The model (mainly the package com.oskopek.transport.model) is designed to be immutable (excluding a few exceptions). This makes it easier to reason about complex, possibly multithreaded operations on top of it. This note is useful to keep in mind when reading code that changes the model data.

Tests

The project aims to be well tested and verified. To stick to these goals, we have several levels of tests, that are run by a CI (Continuous Integration) system after every push and should also be run by developers (at least) after every commit. The displayed test coverage in the README is calculated as an average of unit and integration test coverage.

TransportEditor currently has 3 types of tests:

  • Unit tests (*Test.java) — simple and quick to run tests that test one thing and test it well.

  • Integration tests (*IT.java) — complex tests that handle multiple moving parts at once. Usually involving IO or other not easily mockable things. Try to avoid abusively writing these in favour of unit tests, if possible.

  • User interface tests (*UI.java) — test the UI using TestFX. Under-represented and run not very often. CI doesn’t run them by default at the moment.

Comments, code style

TransportEditor employs a rigorous code style checker called checkstyle that is run automatically at every build. Please adhere to that style when extending/editing the code base. Multiple other unwritten and unspecified rules might apply. Please, do not take any style comments personally  — they are in place so that the code remains in tact and readable in the long term.

As part of the checkstyle process, JavaDoc comments are enforced on every method and class (excluding tests). They should briefly describe the design/implementation choices, why they were made and any useful examples and or other quirks.