Search:
Login
Preferences
Help/Guide
About Trac
Register
Forgot your password?
Wiki
Timeline
Changelog
Browse Source
View Tickets
New Ticket
Roadmap
Builds
Sonar
Search
Context Navigation
+6
Start Page
Index
History
Editing DevelopersGuide/DevelopingPlugins
Adjust edit area height:
8
12
16
20
24
28
32
36
40
Edit side-by-side
= Developing Plugins = This page gives a short introduction for developers how to create, deploy and develop plugins for JOSM. Any Questions left? Ask at the developers mailinglist. [[TOC(inline)]] == Setting up the environment == * Check out the plugin environment into an empty directory called {{{josm}}} {{{ svn co http://svn.openstreetmap.org/applications/editors/josm josm }}} * create a new plugin-directory {{{josm/plugins/yourpluginname}}}. You may create a copy of the template directory [http://svn.openstreetmap.org/applications/editors/josm/plugins/00_plugin_dir_template/ 00_plugin_dir_template]. It includes a directory layout, a [http://svn.openstreetmap.org/applications/editors/josm/plugins/00_plugin_dir_template/LICENSE license file] and a template for the [http://svn.openstreetmap.org/applications/editors/josm/plugins/00_plugin_dir_template/build.xml build.xml]. * Open the ant script ({{{build.xml}}}) in your plugin directory and configure the properties in the configuration section. The important thing of your build script is, that it places some attributes into the {{{MANIFEST.MF}}} of the jar file. See below. {{{build.xml}}} in the template directory takes care of this. * [http://svn.openstreetmap.org/applications/editors/josm/plugins/00_plugin_dir_template/README.template This readme] explains how your plugin is built and made available to other JOSM users. * Also note, that JOSM is compiled into Java5 compatible class files, so if you are using Java6 or Java7, specify "-target 1.5" as parameter to javac or your plugin will not be usable with the official josm builds. * If you need other OSM resources you can check out the complete osm - trunk: {{{svn co http://svn.openstreetmap.org/}}} == JOSM plugins == === A POJO as entry point === The entry point for a JOSM plugin, the '''plugin main class''' is a Plain Old Java Object (POJO) which provides a constructor with one parameter of type [source:/trunk/src/org/openstreetmap/josm/plugin/PluginInformation.java PluginInformation]. {{{ #!java public class MyPlugin { /** * Will be invoked by JOSM to bootstrap the plugin * * @param info information about the plugin and its local installation */ public MyPlugin(PluginInformation info) { } /* ... */ } }}} You don't have to derive the plugin main class from a common superclass but currently you are '''recommended''' to derive it from [source:/trunk/src/org/openstreetmap/josm/plugin/Plugin.java org.openstreetmap.josm.plugin.Plugin]. {{{ #!java import org.openstreetmap.josm.plugin.Plugin; import org.openstreetmap.josm.plugin.PluginInformation; public class MyPlugin extends Plugin { /** * Will be invoked by JOSM to bootstrap the plugin * * @param info information about the plugin and its local installation */ public MyPlugin(PluginInformation info) extends Plugin { super(info); // init your plugin } } }}} For legacy reasons, JOSM currently also allows POJOs with a no-arg constructor as plugin main classes. This approach is '''deprecated''' and will be disabled in Q2/2010. New plugins should provide a constructor with one parameter of type [source:/trunk/src/org/openstreetmap/josm/plugin/PluginInformation.java PluginInformation]. === Naming the plugin === Each plugin has a unique name to identify it. The name is a short identifier like {{{wmsplugin}}} or {{{validator}}}. * '''DONT''' use white space characters in the name. Call the plugin {{{BuildingUtility}}}, not {{{Jim's Building Utitlities}}} * '''DONT''' use special characters in the plugin name, stick to alphanumeric characters. Call the plugin {{{routing4all}}} not {{{routing 4 all :-) !}}}. Note that the plugin name is used to '''create file and directory names''' on the computer where plugins are installed. If it included special characters like /, ., \, etc. these operations may fail. You should use a Java package for the plugin main class and all other classes you need in the plugin, i.e. {{{org.foo.bar.routing4all}}}. Stick to the well-established naming conventions used in the Java world (lower case package name, camel case class names, etc.). Put the plugin code including the plugin main class '''in its own package'''. This allows JOSM to identify and temporarily disable a plugin which has thrown an exception. In short * choose a short plugin name {{{apluginame}}} * declare a unique Java package {{{foo.bar.apluginame}}} * implement a plugin main class {{{foo.bar.apluginame.APluginName}}} === The plugin interface === The plugin main class neither has to be derived from a common superclass nor does it have to implement a specific Java interface. There's nevertheless a plugin "interface" JOSM expects a plugin to provide. It consists of a collection of method signatures your plugin may implement. JOSM invokes the corresponding methods at some points in the application life cycle, provided the plugin actually implements these methods. * {{{public void mapFrameInitialized(MapFrame old, MapFrame new)}}} JOSM manages at most one [source:/trunk/src/org/openstreetmap/josm/gui/MapFrame.java MapFrame]. At startup, when JOSM displays the Message of the Day (MOTD) panel, the MapFrame is null. It is only created when the first [source:/trunk/src/org/openstreetmap/josm/layer/MapFrame.java Layer] is added and it is removed and reset to null if the last layer is removed. Plugins implementing a method {{{mapFrameInitialized}}} are notified about the change of the current map frame. * {{{public PreferenceSetting getPreferenceSetting()}}} The [source:/trunk/src/org/openstreetmap/josm/gui/preference/PreferenceDialog.java JOSM preference dialog] asks a plugin to supply an editor for its preferences. The editor must be a subclass of [source:/trunk/src/org/openstreetmap/josm/gui/preference/PreferenceSetting.java PreferenceSetting]. Return null from {{{getPreferenceSetting}}} or don't implement it if your plugin has no need to manage preferences. * {{{public void addDownloadSelection(List<DownloadSelection> list)}}} The [source:/trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java JOSM download dialog] asks a plugin to supply its own download method when the download dialog is created. The plugin must supply an object implementing [source:/trunk/src/org/openstreetmap/josm/gui/download/DownloadSelection.java DownloadSelection]. The download dialog also invokes {{{addGui(DownloadDialog gui)}}} on the supplied [source:/trunk/src/org/openstreetmap/josm/gui/download/DownloadSelection.java DownloadSelection] which gives you the chance to create an UI component (i.e. a JPanel) JOSM adds to the tabbed pane in the download dialog. Reply the unmodified {{{list}}} or don't implement the method if your plugin doesn't provide its own download method. Plugins shouldn't remove and or reorder elements in {{{list}}}. === The JOSM API === The initial JOSM author preferred public fields in Java classes over public methods, including public getters and setters. He justified this decision as follows: ''First some words about my style of accessing public variables. Most people find this annoying and bad coding style in Java. If this would be an enterprise project, where most of the code is glue code and had to work with objects in a generic way, I would agree with them. But as JOSM is not, I like to keep the classes as simple as possible, which includes, that I don't add standard getter/setter but make the variable public. Also, there are no or very few so-called ''singleton-factories'' in JOSM that became popular in the past years. I use to reference singleton objects as global statics. This is unusual but equivalent to having stuff like Dependency Injection or Factory Methods (except you want to make complex things like auto-distributing stuff as seen in some enterprise programs).'' Most of the current JOSM authors don't follow this approach and in 2008 and 2009 large parts of the JOSM code base have been refactored in order to improve the maintainability and stability of the code. You're encouraged to follow the well-established principles of encapsulation and information hiding in plugins too. There are still a couple of global objects accessible through [source:/trunk/src/org/openstreetmap/josm/Main Main], though. ||Main.parent||This is the parent of all GUI elements. Use this as first parameter to JOptionPane.show* if you want to popup a message|| ||Main.pref|| This is the global preferences file, loaded from {{{${josm.home}/preferences}}}. Use {{{Main.pref.get(...)}}} and {{{Main.pref.put(...)}}} to access the preferences. They will be saved immediately after a put, so don't put anything you dont want to have there. Please, prefix custom plugin preferences with your plugin name. || || Main.proj|| This is the current [source:/trunk/src/org/openstreetmap/josm/data/projection/Projection.java Projection] used in JOSM. If you want to translate between Lat/Lon and East/North, use {{{Main.proj.latlon2eastnorth}}} and {{{Main.proj.eastnorth2latlon}}}.|| ||Main.map.mapView||This is the main UI component in JOSM. It provides the the view with the rendered layers. You usually access this to call methods like {{{getCenter()}}}, {{{getScale()}}} or {{{zoomTo()}}}. '''Beware''': {{{Main.map}}} can be null when no layers are created yet.|| JOSM plugins can '''register''' for a couple of '''events''' emitted by JOSM. * '''layer change events''' Implement a [source:/trunk/src/org/openstreetmap/josm/gui/MapView.java org.openstreetmap.josm.gui.MapView.LayerChangeListener] and register is using [source:/trunk/src/org/openstreetmap/josm/gui/MapView.java addLayerChangeListener(LayerChangeListener listener)]. JOSM will then notify you about added, removed, and renamed layers. You may only or also register an [source:/trunk/src/org/openstreetmap/josm/gui/MapView.java org.openstreetmap.josm.gui.MapView.EditLayerChangeListener] in which case JOSM will notify the plugin about changes in the current edit layer, in particular whether there is or there isn't a current edit layer. * '''selection change listener''' If your plugin needs to respond to changes in the currently selected set of OSM objects it can implement a [source:/trunk/src/org/openstreetmap/josm/data/SelectionChangeListener.java org.openstreetmap.josm.data.SelectionChangeListener] and add it to the global list {{{org.openstreetmap.josm.data.osm.DataSet.selListeners}}}. * '''data change events''' If your plugin needs to respond to changes in the data managed by [source:/trunk/src/org/openstreetmap/josm/layer/OsmDataLayer.java org.openstreetmap.josm.layer.OsmDataLayer]s it can implement a [source:/trunk/src/org/openstreetmap/josm/data/osm/event/DataSetListener.java org.openstreetmap.josm.data.osm.event.DataSetListener] and register it on the data set of an OsmDataLayer using {{{layer.ds.addDataSetListener(yourlistener)}}}. JOSM will notify the listener about added, modified, and deleted objects in the dataset. Make sure your plugin also unregisters as data set listener when the respective OsmDataLayer is deleted. Listen to layer change events to and respond to layer deleted events. * ''' preference change listener''' If your plugin needs to respond to changes in the JOSM preferences it can implement a [source:/trunk/src/org/openstreetmap/josm/data/Preferences.java org.openstreetmap.josm.data.Preferences.PreferenceChangedListener]. Invoke {{{addPreferenceChangeListener(PreferenceChangedListener listener)}}} on {{{Main.pref}}}. === Accessing the local file system === JOSM plugins are currently allowed to read from and write to the local file system. Please write plugin specific files to {{{${josm.home}/preferences/${pluginname}}}}. If your plugin main class subclasses from [source:/trunk/src/org/openstreetmap/josm/plugin/Plugin.java Plugin] you can use the method {{{String getPluginDir()}}} to get the name of the plugin specific data directory. == Packaging a plugin == === A plugin is deployed as a single jar === A JOSM plugin is deployed as a single jar file. The jar files name must be equal to the plugin name, i.e. {{{routing4all.jar}}}. The jar file must include * the required java classes, including any additional libraries the plugin requires * icons, deployed data files, and other resources * a manifest file with JOSM specific entries (see below) === The manifest file for a JOSM plugin === You have to put some information into the manifest file of your jar. If you use ant, you can set these values within the {{{build.xml}}} file. ||'''Plugin-Mainversion'''||required|| The lowest JOSM version required by this plugin.|| ||'''Plugin-Version'''||required||The SVN revision of the plugin SVN repository the plugin was built against|| ||'''Plugin-Class'''||required||Points to the main class of the plugin|| ||'''Plugin-Description'''||required||Gives the description of the plugin visible in the preferences page. For line breaks, you have to use {{{<br>}}}, ''not'' {{{<br/>}}}|| ||'''Author'''||optional|| The name and or email address of the author of this plugin. This is used in the error report window, if an error is detected within the plugin code.|| ||'''Plugin-Date'''||optional||The creation date of the plugin in ISO format.|| ||'''Plugin-Early'''||optional||Can be set to {{{true}}}, in which case the plugin is loaded as early as possible, more specific before the GUI classes are loaded. This is usefull if your plugin alters the GUI or the JOSM-startup process in any way.|| ||'''Plugin-Link'''||optional||Informational URL to a webpage or other information source about that plugin. Is also used in the [wiki:Plugins plugins] information page.|| ||'''Plugin-Requires'''||optional||A list of other plugins which are required before plugin works. The list is separated by semi colons.|| ||'''Plugin-Stage'''||optional||An number of the order relative to other plugins, when the plugin is loaded. Smaller numbers gets loaded first, so if you have conflicts with other plugins, you can increase or decrease this number to get some control on the loading order. Defaults to 50.|| ||'''Class-Path'''||optional||An space-seperated list of additional classpaths your plugin wants to use when looking for ressources and classes. The plugin itself is added automatically. Don't forget to provide the additional jar's as well, if you add dependencies here. Note that all loaded plugins are in the class-path automatically, so don't specify plugin-dependencies here.|| ||'''<xxx>_Plugin-Url'''||optional||To support older JOSM version special entries may be added to supply older versions. This information is used by the internal plugin handler to select only matching version when updating. The entries are made like this ''<josm_version>_Plugin-Url: <plugin_version>;<url>''|| || '''<lang>_Plugin-Description'''||optional||The translated description text for the plugin. E.g. ''de_Plugin-Description'' contains the German translation.|| For SVN managed plugins, the links to old versions and the translated descriptions are automatically added to the [http://josm.openstreetmap.de/plugin plugin information], so JOSM can use that when it displays the list of plugins in the preference dialog. == Managing a plugin == There is an SVN repository for JOSM plugins in the main OSM SVN repository, see [http://svn.openstreetmap.org/applications/editors/josm/plugins/ here]. Note that this repository is different from the [http://josm.openstreetmap.de/svn/ main JOSM SVN repository] which only manages the JOSM core. You can easily get write access to the JOSM plugins repository by [http://wiki.openstreetmap.org/wiki/Accounts#SVN_access_.28OSM_software.29 following these steps]. If your plugin should be available for other users too and if you want to integrate it into the JOSM plugin update procedure you should submit it to the JOSM plugins repository. The following [http://svn.openstreetmap.org/applications/editors/josm/plugins/00_README readme file] might be helpful too. == Updating a plugin == You have found a bug in a plugin and you are able to fix it. Then your next steps are: '''Fixing the bug''' 1. fix the bug in the plugin, compile it, run it locally in JOSM, and test it '''Publishing the new plugin''' 1. Did you change something which will not work with every JOSM version? Then you should update '''Plugin-Mainversion''' in {{{build.xml}}} * look for the line {{{<attribute name="Plugin-Mainversion" value="..."/>}}} * replace the value by the lowest JOSM version required for the plugin after you've applied your fix [[BR]]Do not increase '''Plugin-Mainversion''' if not necessary, though. If you do, JOSM ''requires'' users to update to the new version, otherwise users can ''choose'' whether they want to upgrade. {{{Plugin-Mainversion}}} should always consist of the ''lowest possible revision''. 1. commit the new modified source 1. '''counter intuitive, but important - update again from the SVN''' - after having commited you '''must''' update the source again from the SVN. This ensures that {{{Plugin-Version}}} in the plugin {{{MANIFEST}}} will reflect the plugins SVN revision number 1. build the plugin using {{{ant clean}}} and {{{ant dist}}}. This creates the plugin jar file in the {{{/dist}}} directory. 1. commit the {{{.jar}}} file in the {{{dist}}} directory '''Closing trac ticket''' 1. Did you fix the bug based on a trac ticket? Please close it and leave a note. You can refer to the new plugin version using the macro {{{[o12345]}}}, where 12345 is a plugin revision number. Ready. The new plugin version is now available. If necessary, JOSM asks users to upgrade to the new version, when JOSM is started up. The steps describe above can be automated, see [http://svn.openstreetmap.org/applications/editors/josm/plugins/tageditor/build.xml build.xml of the tageditor plugin]. It includes an ant target {{{publish}}}. == Legal stuff (Imis opinion) == Just because I have been asked: JOSM is licensed under GPL and if any code is a "derived work" of JOSM, then it has to be under GPL too. It is my believe, that any JOSM-Plugin is a derived work of JOSM, so GPL is the only possible license for a JOSM-Plugin. If you want to include non-GPL code into a plugin, it has to be seperated from the classes that use JOSM. "Use" as in "import org.openstreetmap.josm...". See the 'Class-Path' - MANIFEST.MF attribute for a way to include other jar files.
Note:
See
WikiFormatting
and
TracWiki
for help on editing wiki content.
Change information
Your email or username:
E-mail address and name can be saved in the
Preferences
Comment about this change (optional):
Note:
See
TracWiki
for help on using the wiki.