Code documentation

Development tools

Code Structure

Techniques and Standards

How To

Functional Info

Background Info

JMRI Code: Adding A New Data Type

This page describes the steps to add a new data-type, e.g. Turnouts, to the JMRI code.

It uses as an example the addition of the Reporter type in July, 2004. Reporter was added as a new type of NamedBean and is being used to bring complex information back from the layout.

Note that we don't do this very often, and the specifics are more important than the generalities here. You should should make sure you understand the intended system connection structure which is documented documented on another page.

This mostly talks about a type that connected to one or more system connections, e.g. represents hardware-specific items. It's also possible to have non-layout-specific types, which are somewhat different (and should also be documented). For example, Routes.

We list the files that are modified and created in the order they were done in this case; other orders may also work, and you might not need to do all these.

In this particular case, our first implementation is for only one hardware system (LocoNet). This effects how we ordered this, and reduced the need to have unit tests in place at the beginning. By working through the LocoNet implementation first, we could get a better idea of whether the proposed Reporter interface did what's needed. If you are creating a new type that several system will need at first, you should also create unit tests early in the process to encode what you think is the common behavior.

In general, the new classes and interfaces defined below can most easily be made by copying an existing one. In this case, we copy the "*Turnout*" file to make a corresponding "*Reporter*" file.

Define the new type and it's manager

Reporter

This interface defines the properties needed. It should inherit from NamedBean, though you can add new accessors as desired.

ReporterManager

This interface provides methods for getting a Reporter object, either just from the system name (preferred) or with additional parameters

At this point, make sure you can compile.

doc/Technical/Names.shtml

Update the discussion of naming to include the type-letter for your new type. While you're at it, update the system-specific naming pages as needed.

Provide the base for implementations

AbstractReporter

This is a basic implementation.

AbstractReporterManager

Basic implementation; stuff that's useful to all the system-specific implementations

At this point, make sure you can compile.

managers.ProxyReporterManager

This handles having more than one system providing Reporter objects. It takes zero or more ReporterManager implementations, and routes requests for Reporter access to the right one.

InstanceManager

There are several historical ways to install things in the InstanceManager. The current way is to use the getDefault(..) and getOptionalDefault(..) calls for a default and the getList(..) call to get access to all.

At this point, make sure you can compile.

Provide the first system-specific implementation

jmrix.loconet.LnReporterManager

This class listens for activity indicating a new LocoNet-specific Reporter, and calls for one to be created if needed. Other than that, and providing the right system-specific letter (e.g. 'L'), this is just a direct copy.

jmrix.loconet/LnReporter

Converts specific messages into reporter actions and report. All of the rest of the stuff is just to get this in place.

At this point, make sure you can compile. Nothing will happen when you run until the next step.

jmrix.loconet.LnPortController

Here (or perhaps somewhere else in another system) you create an instance of the correct ReporterManager class at system startup and install it in the InstanceManager. See the system structure page for more details.

Add to the scripting support

jython/jmri_defaults.py

Add a new variable to give easy access to the new manager.

doc/Technical/Jython.shtml

Update this to refer to the new Jython variable (There may be other web pages too!)

At this point, you should be able to compile and run, testing the new code from the jython command line.

Add a new table tool for access (optional)

jmrit.beantable.ReporterTableAction

Create a new "Table" for watching these in action.

In this particular case, the code had to be modified a little (instead of just copied) because a Reporter doesn't really have a way to support "click to change"

jmrit/beantable/BeanTableBundle.properties

Add strings for the new properties you defined in the previous step. You might also want to translate these in the other properties files when possible.

jmrit.ToolsMenu

Add the new ReporterTableAction class to the menu.

jmrit/JmritToolsBundle.properties

Add strings for the new property you defined in the previous step. You might also want to translate these in the other properties files when possible.

At this point, you should be able to compile and run to test the new table.

Provide for persistance of the manager and type objects

configxml.AbstractReporterManagerConfigXML

Loads and stores the configuration date for the ReporterManager implementations

jmrix.loconet.configurexml.LnReporterManagerXml

Load and store the system-specific LocoNet Reporter Manager info

xml/DTD/layout-config.dtd

Add any new XML elements and attributes to the DTD

Provide a suitable display icon class (optional)

jmrit.display.ReporterIcon

discussion

jmrit.display.configxml.ReporterIconXml

discussion

xml/DTD/layout-config.dtd

discussion

Complete the documentation

ant javadoc

Create the Javadocs, and fix any new (or old) problems.