Files
2026-06-17 14:00:51 +02:00

305 lines
14 KiB
Plaintext

<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content="HTML Tidy for HTML5 for Apple macOS version 5.8.0">
<title>JMRI: Introduction to JMRI Library Structure</title>
<meta name="author" content="Bob Jacobsen">
<meta name="keywords" content="JMRI technical code"><!--#include virtual="/help/en/parts/Style.shtml" -->
</head>
<body>
<!--#include virtual="/help/en/parts/Header.shtml" -->
<div id="mBody">
<!--#include virtual="Sidebar.shtml" -->
<div id="mainContent">
<h1>JMRI Code: Introduction to JMRI Library Structure</h1>
<p>This page is the top-level introduction to how the JMRI software is organized.</p>
<h2>Static Structure</h2>
<p>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.</p>
<p>In addition to the source code, JMRI expects to find directories within the current
directory:</p>
<dl>
<dt>
<a href="https://github.com/JMRI/JMRI/tree/master/help">help/</a>
</dt>
<dd>
The <a href="Help.shtml">in-program help files</a>
</dd>
<dt>
<a href="https://github.com/JMRI/JMRI/tree/master/jython/">jython/</a>
</dt>
<dd>
Various <a href="https://www.jmri.org/jython/">sample</a> and <a href=
"https://www.jmri.org/jython/test/">test</a> scripts.
</dd>
<dt>
<a href="https://github.com/JMRI/JMRI/tree/master/lib">lib/</a>
</dt>
<dd>Jar files and linkable libraries that JMRI relies on.</dd>
<dt>
<a href="https://github.com/JMRI/JMRI/tree/master/resources">resources/</a>
</dt>
<dd>
Image and sound resources used by the library, and available for user selection. These
can be <a href="https://www.jmri.org/resources/">directly browsed</a>.
</dd>
<dt>
<a href="https://github.com/JMRI/JMRI/tree/master/web">web/</a>
</dt>
<dd>Files for JMRI's built-in web servers</dd>
<dt>
<a href="https://github.com/JMRI/JMRI/tree/master/xml">xml/</a>
</dt>
<dd>
XML files for decoder and programmer definitions, <a href=
"../../tools/signaling/AspectSignaling.shtml">signal system definitions</a>, <a href=
"XmlSchema.shtml">Schema</a> and DTDs used to validate JMRI's <a href=
"XmlPersistance.shtml">XML persistance</a>, and others.
</dd>
</dl>
<p>plus specific files used by the <a href="Ant.shtml">build process</a>, to <a href=
"Logging.shtml">control logging</a>, and containing the <a href="https://www.jmri.org/copyright.shtml">JMRI
license</a>.</p>
<h3>Static Package and Class Structure</h3>
<p>For interfaces in the <code>jmri</code> package, which might be implemented by lots of
different layout hardware types,
<a href="https://www.jmri.org/JavaDoc/doc/jmri/InstanceManager.html">jmri.InstanceManager</a>
satisfies requests for implemented objects by providing access to a hardware-specific
<a href="https://www.jmri.org/JavaDoc/doc/jmri/Manager.html">Manager</a>,
from which you can get the
hardware-specific items that represent what you want to access on the layout.</p>
<a href="images/OverallPackageStructure.png"><img src="images/OverallPackageStructure.png"
alt="package structure"></a>
<p>Because we have different hardware implementations in subpackages of the
<code>jmrix</code> package, those are also accessed via the
<a href="https://www.jmri.org/JavaDoc/doc/jmri/SystemConnectionMemo.html">SystemConnectionMemo</a>
classes, which provide access to generally-defined objects.</p>
<p>Other code should, in general, not reference those specific implementations directly.</p>
<p>(The <a href="https://www.jmri.org/help/en/package/">help/en/package</a>
section of the in-program help files are also organized this way)</p>
<a href="images/OverallImplementationStructure.png"><img src=
"images/OverallImplementationStructure.png" class="floatRight" alt="implementation structure"></a>
<p>More specifically:</p>
<dl>
<dt>jmri</dt>
<dd>Contains interfaces and base class implementations for the common JMRI objects. This is
the basic interface to the overall JMRI library and its capabilities.<br>
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.</dd>
<dt>jmrit</dt>
<dd>
Contains commonly useful <strong>t</strong>ools and extensions.<br>
It can depend on <code>jmri.*</code> and externals. It must not depend on
<code>jmrix.*</code>
</dd>
<dt>jmrix</dt>
<dd>Contains code that is specific to a particular e<strong>x</strong>ternal 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).<br>
jmrix can depend on jmri and externals, but not jmrit.<br>
Only system-specific code should access within the jmrix subpackages.</dd>
<dt>jmris</dt>
<dd>contains all the code for the server implementation for the JMRI interfaces.</dd>
<dt>managers</dt>
<dd>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 jmri.implementations.</dd>
<dt>implementations</dt>
<dd>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.</dd>
<dt>util</dt>
<dd>
General service classes that are <em>not</em> user level tools. Should not depend on
jmri.jmrit or jmri.jmrix packages. The jmri.util.swing subpackage provides Swing
utilities.
<p>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.</p>
</dd>
<dt>apps</dt>
<dd>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)</dd>
</dl>
<a href="images/OverallAppDependencies.png"><img src="images/OverallAppDependencies.png"
class="floatRight" alt="dependencies"></a>
<p>Although it's not always honored, the tree structure here is important: Packages should
<em>not</em> reference across the tree. Code in <code>jmri.jmrit</code> is welcome to
reference classes in the <code>jmri</code> package, but should not reference directly to
classes in <code>jmri.jmrix</code>. Classes should reference the interfaces in
<code>jmri</code>, not the specific details of classes in <code>jmri.managers</code> and
<code>jmri.implementations</code>. 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. We're developing <a href=
"https://www.archunit.org">ArchUnit</a> tests for this which can be run via
<code>./runtest.csh jmri.ArchitectureCheck</code> as part of <a href="JUnit.shtml">developer
unit testing</a> (there is also a PowerShell script available, see the <a href=
"JUnit.shtml">developer unit testing</a> 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. There's also <code>jmri.ArchitectureTest</code> which is run as part of
our <a href="ContinuousIntegration.shtml">CI tests</a>, and catches new violations of a
subset of the constraints.</p>
<p>Similarly, we have conventions for where to locate <a href="Swing.shtml">Swing GUI
code</a> and <a href="XmlPersistance.shtml">persistance (store/load) code</a> that limits how
embedded in them main code they become.</p>
<h4>Example: Implementing a Turnout</h4>
Turnouts involve multiple classes:
<ul>
<li><a href="https://www.jmri.org/JavaDoc/doc/jmri/Turnout.html">Turnout</a>
- the basic interface. This is what you should expect to deal with when writing
your layout automation code; it's what you get when you make a request from the
TurnoutManager, etc.</li>
<li><a href="https://www.jmri.org/JavaDoc/doc/jmri/implementation/AbstractTurnout.html">AbstractTurnout</a>
- provided for convenience when implementing the Turnout interface for
specific hardware, this provides the basic implementation.</li>
<li><a href="https://www.jmri.org/JavaDoc/doc/jmri/jmrix/loconet/LnTurnout.html">LnTurnout</a>
- a specific implementation for LocoNet-connected turnouts. There are many
other implementations for different layout connections.</li>
</ul>
<h2>Dynamic (Object) Structure</h2>
<p>For many JMRI objects, once they have been created they can be accessed either by type,
i.e. "The default configuration manager" via the InstanceManager,
or by name, i.e. "The East Yard Entrance turnout" via a type-specific Manager.
More information on how things (e.g. objects representing items on the layout) are named
<a href="Names.shtml">is available on a separate page</a>.</p>
<p>The <a href="https://www.jmri.org/JavaDoc/doc/jmri/InstanceManager.html">"InstanceManager"</a>
is a key central point for this navigation.</p>
<ul>
<li>It provides access to key objects, particularly the Managers that mediate access to
Turnouts, Sensors, etc.</li>
<li>It automatically handles initialization of many parts of JMRI via several mechanisms:
<ul>
<li>
<a href=
"https://www.jmri.org/JavaDoc/doc/jmri/InstanceManagerAutoDefault.html">InstanceManagerAutoDefault</a>
</li>
<li>
<a href=
"https://www.jmri.org/JavaDoc/doc/jmri/InstanceInitializer.html">InstanceInitializer</a>
</li>
</ul>
and, when needed, provides for their <a href=
"https://www.jmri.org/JavaDoc/doc/jmri/InstanceManagerAutoInitialize.html">post-creation
initialization</a>.
</li>
<li>It <a href=
"https://www.jmri.org/JavaDoc/doc/jmri/InstanceManager.html#dispose-jmri.Disposable-">disposes</a>
of <a href="https://www.jmri.org/JavaDoc/doc/jmri/Disposable.html">suitable objects</a> at the
end of their lifespan when the InstanceManager (or a particular collection in it) is
cleared.
</li>
</ul>
<p>JMRI makes extensive use of the Factory pattern via objects we call "Manager" objects.</p>
<h4>Example: Accessing a Turnout</h4>
<p>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 got that TurnoutManager from the InstanceManager.</p>
<div class="wide">
<pre style="font-family: monospace;">
TurnoutManager manager = InstanceManager.getDefault(TurnoutManager.class);
Turnout turnout = manager.getTurnout("IT12");
</pre>
</div>
<p>The generic <a href="https://www.jmri.org/JavaDoc/doc/jmri/Manager.html">Manager&lt;T&gt;</a> class provides the basic interface.
which is then extended for specifics i.e.
<a href="https://www.jmri.org/JavaDoc/doc/jmri/TurnoutManager.html">TurnoutManager</a>.
That then has specific implementations.</p>
<p>In many cases, there's one underlying implementation for a manager.
For example, there's one
<a href="https://www.jmri.org/JavaDoc/doc/jmri/LogixManager.html">LogixManager</a>, one
<a href="https://www.jmri.org/JavaDoc/doc/jmri/MemoryManager.html">MemoryManager</a>, etc.
<p>
In other cases, you might have multiple system-specific managers:
LnTurnoutManager for a LocoNet connection, NceTurnoutManager for an NCE
connection, and an InternalTurnoutManager for the internal turnouts.
These are handled by making them clients to a single
<a href="https://www.jmri.org/JavaDoc/doc/jmri/ProxyManager.html">ProxyManager</a>,
subclass i.e.
<a href="https://www.jmri.org/JavaDoc/doc/jmri/managers/ProxyTurnoutManager.html">ProxyTurnoutManager</a>
which uses name lookup to work with the individual managers.
<h2>Object Referencing</h2>
<p>Code can hold a direct java reference to a specific object.
In some cases, typically GUIs or
<a href="XmlPersistance.shtml">persistance</a>,
you'll want to refer to an object by its name. JMRI NamedBean objects
have both system names that can't change and user names that can.
For example, the user name "East Yard" for a turnout might refer to
"LI1" at some point and later refer to "NT12". The
<a href="https://www.jmri.org/JavaDoc/doc/jmri/NamedBeanHandle.html">NamedBeanHandle</a>
class takes care of this by remembering
which name is being used for an object, and keeping track of how
that name might be moved from one object to another.
For more information, see the description on the
<a href="Patterns.shtml">Patterns page</a>.
<!--#include virtual="/help/en/parts/Footer.shtml" -->
</div>
<!-- closes #mainContent-->
</div>
<!-- closes #mBody-->
<script src="/js/help.js"></script>
</body>
</html>