Java Applet Development
Potlatch was deployed on the website in May 2007. This is a flash based alternative to the applet, targetted at the same audience. Since then there has been little development progress on the applet.
There is still some potential use for the applet, to provide an alternative editor for people who cannot run flash (might also run better on some devices)
The applet code will currently not work with API v0.5 (some major changes including no more 'segments') so that would be a priority for anyone wishing to revive this work.
Applet Design Goals
The applet is quite simplistic, especially compared with JOSM (standalone java app). The reasons...
- It should be an easy-to-learn editing environment for drawing ways and adding metadata to existing ways. A clear, uncluttered UI is paramount for this audience.
- It should be a fairly smooth transition from 'view' tab to 'edit' tab, as such we dont want to have lots of tool bars/panels appearing.
- We want it to load as fast as possible.
With simplicity in mind, a lot of new development ideas may be rejected, despite being good ideas.
Source Folders Overview
The source code and resources are under applications/editors/applet
To do a proper subversion checkout see Getting The Source
The applet directory includes build.xml - ant build script, and the following sub-directories
- html - page for local test.
- lib - JARs used by applet.
- src/org/openstreetmap/ - applet code.
- client - Guts of applet - tile downloader/renderer, server commands and comms. Including GPX parser.
- processing - Main app (OsmApplet - startup and screen drawing), edit/view mode handlers.
- gui - Handling of edit dialogs.
- test - Empty :(
- util - Zip-based HTTP wrappers, feature models.
Implemented as a Java applet - not directly on AWT, but using a library/framework from processing.org.
The UI has achieved simplicity in some ways, but maybe could do with some changes to make more intuitive - suggested enhancements are in trac.
There have been some major bugs that effectively crash the applet. Mainly these were due to a lack of appropriate synchronisation - fixes are committed and now under test - please see Concurrency below for detail on the new concurrency conventions.
The code has been tidied up somewhat recently, but the edit code is still a bit hit and miss. All the code's there though, and is eminently fixable/tidyable.
Following is what the applet's main classes do.
- OSMApplet - the main applet, extended from PApplet from processing.org. The startup, drawing layout (some delegated out to other objects, e.g. Tile), piecing together code (e.g. delegating to tile / mode manager) and holding the singleton MapData reference.
- ModeManager - responsible for selecting mode and drawing toolbar, as well as delegating mouse/key events to individual modes.
- *Mode - class per mode, e.g. handlers for mouse events. There is one mode per toolbar button (which is perhaps why zoom ended up the way it is!).
- Tile - Manages the image tiles - identifying the ones needed (based on mouse drags / zoom), queuing/requesting/caching them and also handles the redrawing of the tile background.
- ImFetch (in Tile.java) - Code to manage tile download queue and thread pool.
- VFetch (in Tile.java) - Thread/high-level code to manage OSM vector info - uses Adapter to pull down data (nodes, segments, ways) and then update's the applet's MapData instance with it.
- ImBundle (in Tile.java) - Represents a tile and generates a unique key for each (used for image cache / queue uniqueness).
- ServerCommand - interface for classes modelling edit operations.
- Adapter - Does all OSM server communication (getNodesLinesWays() and putXMLToURL(), with retries) and modelling of editing commands by ServerCommand inner-classes which udpate local data structures and send requests to server (by adding to CommandManager queue).
- CommandManager - Threaded server command queue.
- MapData - New class. Holds all low-level map data in single object, acting as lock object for map data synchronisation. Used as a singleton instance by applet, new map downloads only update the internal data of this instance. This allows the various parts of the applet code to refer to a consistent lock object.
Dialog-handling for editing of map and message boxes. NB: Not all GUI code is in this package.
- GzipAwareGetMethod - compression-enabled HTTP get used for OSM vector data download.
- GzipAwarePostMethod - not used (putXMLToURL() not compressed).
And some classes modelling map features (should probably be in a 'model' package, not util):
- OsmPrimitive - base for model classes
- OsmWriter - output of model classes to XML (string-based rendering).
- Line, Node, Point, Way etc. - feature representation classes.
There have previously been problems with handling of concurrency in applet - following these conventions should keep the applet in-order, reliable and responsive:
The threads used by the application, with their lock-order conventions:
- main thread - swallowed by container
- applet thread - started by PApplet super, runs applet initialization in setUp(), then calls applet draw() to paint window (well paints buffer that is used), following every redraw() call from applet. NB: when thread enters draw(), it already has applet instance lock.
- lock order - (1) OsmApplet instance (draw()) then (2) Tile instance (draw())
- ImFetch threads - a pool of threads used to download image tiles
- single locks only, either (A) ImFetch instance or (B) Tile instance or (C) OsmApplet instance (redraw())
- VFetch thread - vector map data fetch thread, downloads from API map resource
- single locks only, either (A) MapData instance (updateData()) or (B) OsmApplet instance (redraw()) or (C) Tile instance (updateChanged()) (or (D) temporary local MapData instance)
- AWT event thread - the main UI thread on which all mouse/key events arrive
- locks (A) (1) Tile instance (removeUnusedTiles()) then (2) ImFetch instance (add() for queuing image downloads) or (B) (1) CommandManager sleeper (add server command to q) then (2) MapData instance (change map) or (C) (1) OsmApplet instance then (2) MapData instance - in various edits of map after user clicks
- CommandManager thread - communicates instructions to server API
- locks (1) 'sleeper' lock (to pickup new commands from event thread) then (2) MapData instance (to change client map)
The synchronisation objects used in the applet, to be locked in orders specified in Threads above. The locks are listed below in a rough high->low order (rule of thumb: lock high level locks first, then lower, never obtain high level locks from within lowest level objects):
- OsmApplet instance 'applet' - sync on this protects draw() cycle & ensures draw variables updated from event thread before cycle starts
- Tile instance 'applet.tiles' - sync on this protects/makes available tiles in the 'images' vector
- ImFetch instance - protects imv vector of queued-for-download image handles/urls (ImBundle instances)
- CommandManager instance's sleeper object - used to queue server requests for CommandManager thread to wake-up and send them.
- MapData instance - help by applet, available via 'applet.getMapData()' - sync'ed on for edits (make map edits transactional by synchronising around all edits) and for draw() cycle access to map data.
There are a number of these, passed in html applet tag's param sub-tags (see map edit page source).
- 'clat', 'clon' - starting position
- 'user', 'pass' - openstreetmap login
- 'tileThreads' - number of image tile download threads, default 4, makes difference to increase if fast connection
- 'windowWidth', 'windowHeight' - applet's understanding of its size - sync with width/height attributes of applet tag
- 'debugToPage' - true = output debug to appletDebug() function - can be helpful for testing, default false
- 'abortable' - true = allows explicit abort of map download, from cheesy on-screen cancel button, default false
- 'timeout' - server connect timeout in seconds, default 15
- 'socketTimeout' - server post-connect socket timeout in seconds, default 120
- 'retries' - max number of server retries, default 5
- 'injectTimeouts' percent chance of (simulated) timeout, for testing, default = 0, i.e. no timeouts
There are a number of bugs in the java applet. We keep track of these using 'trac' (bug tracking system). Query to find all applet bugs. You can raise new bug 'tickets' directly if you create a trac account, alternatively discuss the issue via one of the Contact channels.
The applet will spew debugging information including java stack traces to the JVM console. This may be useful in diagnosing problems, particularly when the applet seems to crash. Look for a little java icon (blue coffee cup) in your system tray in the bottom right. Right click and choose 'Open console'. This may vary depending on JVM installation options and certainly operating system.