JMRI Code: Introduction to JMRI Library Structure
This page is the top-level introduction to how the
JMRI software is organized.
At the highest level, we separate test source code from
distributed source code by putting both in separate directories
within the development directory: "java/test" and "java/src". This
makes it easy to compile a version without test code, to
apply different tools to the two types of code, etc.
In addition to the source code, JMRI expects to find
directories within the current directory:
- The in-program help files
- Various sample and
- Jar files and linkable libraries that JMRI relies on.
- Image and sound resources used by the library, and available for
user selection. These can be
- Files for JMRI's built-in web servers
- XML files for decoder and programmer definitions,
signal system definitions,
Schema and DTDs used to validate JMRI's
plus specific files used by the
to control logging
and containing the
Static Package and Class Structure
For interfaces in the
jmri package, which might be implemented by lots
of different layout hardware types,
satisfies these requests by providing access to
which you can get the hardware-specific items
that represent what you want to access on the layout.
we have different hardware implementations in
subpackages of the
those are also accessed via the
which provide access to generally-defined objects.
Other code should, in general, not reference
those specific implementations directly.
(The help/en/packages section of the in-program help files are also organized this way)
- Contains interfaces and base class implementations for
the common JMRI objects. This is the basic interface to the
overall JMRI library and its capabilities.
Code in the jmri package should depend on no other JMRI
code, though it may depend on externals (log4j, etc.)
There should be no AWT or Swing code here.
- Contains commonly useful tools and
It can depend on jmri.* and externals. It must not depend
- Contains code that is specific to a particular
external system. This includes
implementations of jmri interfaces that are specific to a
system, plus system-specific tools (in the long run, those
could certainly be separated).
jmrix can depend on jmri and externals, but not jmrit.
Only system-specific code should access within the
- contains all the code for the server implementation for
the JMRI interfaces.
- Abstract and default implementations of the various
JMRI type managers, e.g. the concrete classes from the
InstanceManager. It's a historical accident that these have
a package of their own, rather than being rolled into
- Abstract and default implementations of the jmri
objects; no system specific or Swing code allowed here.
These are in a separate package, rather than in jmri
itself, to make the jmri package simpler to understand for
people who just want to use the library.
- General service classes that are not user level
tools. Should not
depend on jmri.jmrit or jmri.jmrix packages. The
jmri.util.swing subpackage provides Swing utilities.
This is an exception to the idea that packages should
not directly reference classes across the tree: these utility
classes are generally available for use.
- Separate from the jmri package tree, this contains application classes
and base classes that can use jmri, jmrit,
and jmrix classes, along with anything else. By having this
here, we break the dependency between jmrix and jmrit
classes (somebody has to create the general and
system-specific tool objects for an application; that
dependency is from the apps package)
Although it's not always honored, the tree structure here is important:
Packages should not
reference across the tree.
is welcome to reference classes
package, but should not reference
directly to classes in
Classes should reference the interfaces in
not the specific details of classes in
It can be tempting
to violate this rule in the interest of expediency, but in the
long run it makes it much harder for JMRI to be maintained and
improved by a large group of people. We just can't allow lots of
tiny little special cases to make the code impossible to understand.
tests for this which can be
as part of
developer unit testing
(there is also a PowerShell script available, see the
developer unit testing
page for more information).
This will highlight many existing structure violations
in addition to new ones
because we haven't yet cleaned up some historical issues.
which is run as part of our
and catches new violations of a subset of the constraints.
Similarly, we have conventions for where to locate
Swing GUI code and
persistance (store/load) code
that limits how embedded in them main code they become.
Example: a Turnout
Turnouts involve multiple classes:
- Turnout - the basic interface. This is what you should
expect to deal with when writing your layout automation
code; its what you get when you make a request from the
- AbstractTurnout - provided for convenience when
implementing the Turnout interface for specific hardware,
this provides the basic implementation.
- LnTurnout - a specific implementation for
LocoNet-connected turnouts. There are many other implementations
for different layout connections.
Dynamic (Object) Structure
For many JMRI objects, once they have been created they can
be accessed either by type, i.e. "The default configuration manager", or
by name, i.e. "The East Yard Entrance turnout".
More information on how things (e.g. objects representing
items on the layout) are named
is available on a separate page.
as a key central point for this navigation.
- It provides access to key objects, particularly the Managers
that mediate access to Turnouts, Sensors, etc.
- It automatically handles creation of many parts of JMRI via
and, when needed, provides for their
at the end of their lifespan when the InstanceManager (or a particular collection in it)
Extensive use of Factory pattern via objects we call
Example: a Turnout
To get a specific Turnout instance that represents
something on the layout, you make a request of a
TurnoutManager. This is also an interface, with a similar
implementation pattern. In turn, you get that TurnoutManager
from the InstanceManager.
The role of the generic Manager<T> class
NamedBean and addressing as part of the Manager's role.
The role of NamedBeanHandle and the NamedBeanHandleManager.