Programmer’s Guide to `profilegrid-app`
=======================================

Martin Stein &lt;<m.stein@gsi.de>&gt; v1.0, February, 3<sup>rd</sup>
2020

The `profilegrid-app` resources
-------------------------------

### Git based Source Code

You can find the source code for the `profilegrid-app` here:
<https://git.acc.gsi.de/fcc-applications/profilegrid-app>

### Logging

(would like to see Graylog link and good filtering options here)

Things to know when facing problems with the `profilegrid-app`
--------------------------------------------------------------

### Reading the logs might not helping a lot

Inside the `profilegrid-app` logging is done in many places (quantity)
but the quality is often not sufficient for taking immediately the right
conclusions. In most cases further analysis is needed. The main reason
for this is, that the exception handling is very basic, does normally
not provide messages with a higher level of (abstraction) information
than the underlying JAPC exceptions.

**NOTE!** This is something which should be improved in the future (more
reasons why this is still in a insufficient state could be given here,
eg. 90 % of problems are caused by the devices).

### Check the state of the involved devices

> **Important**
>
> To the time of writing the usual entry point of analysis is the status
> check of the involved devices (from outside the profilegrid-app).

Checking the status of the involved devices is usually done by calling
the devices with the help of external applications. The involved devices
are the profile grids **and** their actuators. They can be checked by
tools like `devstatus`, `prophelper` or `pdex`. You can execute these
programs in a terminal on the `asl-cluster`.

On the `asl-cluster` tools like `devstatus`, `prophelper` or `pdex` are
located in `/common/usr/cscofe/bin/`.

Here you can see as an example a `pdex` call in [Screenshot
1](#anchor-1). Please note the `-d` after the command to specify the
device, here `gts1dg5`.

**Screenshot 1. pdex command.**

![pdex](./pdex01.png)

With the `pdex` call you are able to check the general status bits and
easily check if the device is powered on (Bit 0) or if there are
interlocks or errors (Bit 5-7). If the device is an `offline` state you
will see a message like shown in [Screenshot 2](#anchor-2) on the
command prompt. Here the example shows the `devstatus` application, best
suited for the `offline` check. You specify the device to analyse right
after the `devstatus` command.

**Screenshot 2. devicestatus command.**

![pdex](./devstatus01.png)

**NOTE!** In the future it should be possible the check the state of the
involved devices inside the profilegrid-app.

The way a profile grid is represented in the `profilegrid-app` is always
a combination (unit) of two devices, the profile grid device itself and
its acutator. In [Screenshot 3](#anchor-3) you can see which parts of
the control panel of a profile grid in the `profilegrid-app` belong to
its actuator.

**Screenshot 3. `profilegrid-app` panel actuator controls.**

![pdex](./profilegrid_one_control_panel_actuator.png)

> **Important**
>
> Check device status of both devices, the profile grid itself and its
> actuator.

To be able to check the status of an actuator of a profile grid you need
to know how the nomenclature of the actuator is called. One way to get
nomenclature is by using a wildcard \* with the `devstatus` tool on the
`asl-cluster` like shown in [Screenshot 4](#anchor-4). A typical command
would be eg. `devstatus GTE1DG1*`. `GTE1DG1` is the nomenclature for the
profile grid in question. The result would give you the nomenclature
`GTE1DG1_P`, the pneumatic actuator the profile grid `GTE1DG1` is
mounted on.

**Screenshot 4. Using wildcard syntax in `devstatus`.**

![devstatus with wildcard](./devstatus02.png)

The given example of profile grid `GTE1DG1` and its actuator `GTE1DG1_P`
showcases the most common combination in the means that the actuator is
from type pneumatic. More examples are given in the following table
including profile grid `GTS1DG5` which has two corresponding actuators,
where at the time of writing `GTS1DG5_S` is the actual one.

<table>
<caption>Typical Actuator Nomeclatures</caption>
<colgroup>
<col style="width: 33%" />
<col style="width: 33%" />
<col style="width: 33%" />
</colgroup>
<thead>
<tr class="header">
<th>Profile Grid Name</th>
<th>Corresponding Actuator Name</th>
<th>Actuator Type</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><p>GHTADG2G</p></td>
<td><p>GHTADG2GP</p></td>
<td><p>Pneumatic</p></td>
</tr>
<tr class="even">
<td><p>GTS1DG5</p></td>
<td><p>GTS1DG5_P, GTS1DG5_S</p></td>
<td><p>Pneumatic, Stepping (Stepping is the right)</p></td>
</tr>
<tr class="odd">
<td><p>GTS2DG2</p></td>
<td><p>GTS2DG2_S</p></td>
<td><p>Stepping</p></td>
</tr>
</tbody>
</table>

Which actions to consider if status messages indicate problems with a profile grid
----------------------------------------------------------------------------------

> **Important**
>
> 1.  If a profile grid or its actuator creates **error** or **offline**
>     messages, check again with the operators or the shift leader if
>     the device should really be in functional state.
>
> 2.  If 1. is confirmed and a profile grid or its actuator is
>     **offline** ask for Beam Diagnostics On Call support.
>
> 3.  If 1. is confirmed and a profile grid or its actuator shows an
>     **error** message ask for Frontend On Call and/or Beam Diagnostics
>     On Call support.
>
Software development insights
-----------------------------

### Starting `profilegrid-app` with `Maven`

From the command line start the application with `mvn -Prun,pro-3tier`.

Starting the application provokes a `Warning` because of the use of two
frameworks:

1.  the `CERN JavaFX Application Framework` (interface classes are
    `FxmlView` and `ApplicationBase`)

2.  and `Griffon`, further details see below

The `Warning` looks like this:

    java.lang.ClassCastException: class griffon.javafx.JavaFXGriffonApplication cannot be cast to class cern.accsoft.gui.application.ApplicationBase (griffon.javafx.JavaFXGriffonApplication and cern.accsoft.gui.application.ApplicationBase are in unnamed module of loader java.net.URLClassLoader

and is not critical to the time of writing.

### Update, Upgrade or Release Procedures and `Maven POM` file editing

The `profilegrid-app` uses two (2!) `Maven POM` files to profit from a
`Parent POM` the `Griffon framework` provides. Additionally it uses is
the normal `Parent POM`, the artifact `csco-parent-java-bundle`.

> **Important**
>
> 1.  `profilegrid-app/pom.xml` is the usual place for dependency
>     declarations like e.g. artifact `common-context-widget` but not
>     for the normal `Parent POM`, artifact `csco-parent-java-bundle`.
>
> 2.  `profilegrid-app/griffon-app/pom.xml` is where the `Parent POM`
>     `csco-parent-java-bundle` belongs to and nothing else.
>
To see the two `POM’S` in the directory tree, see the [full
directory](#anchor-5) of the`profilegrid-app`.

### `profilegrid-app` uses application framework `Griffon`

The [Griffon framework](http://griffon-framework.org/guide/2.15.1) is
the reference implementation of the
[JSR-377](https://jcp.org/en/jsr/detail?id=377) of the Java Community
Program (JCP).

The [JSR-377](https://jcp.org/en/jsr/detail?id=377) has the goal to
define an API for common behavior shared by many desktop and mobile
applications. Most applications require the following features:

-   **dependency injection via
    [JSR-330](https://github.com/javax-inject/javax-inject).**

-   **common application structure.**

-   **application life-cycle.**

-   localized resources.

-   resource injection.

-   localized configuration.

-   **decouple state from UI (binding).**

-   persistence session state (preferences).

-   **action management.**

-   **component life-cycle.**

-   light-weight event bus.

-   honor threading concerns (specific to UI toolkit).

-   application extensibility via plugins (implies modularity).

The `profilegrid-app` is using the **bold** features with the help of
the `Griffon` framework.

Another set of the advantages using `Griffon`
---------------------------------------------

-   Convention over Configuration

-   Don’t Repeat Yourself (DRY)

-   **Pervasive MVC**

-   Testing supported "out of the box"

### The 'common application structure used' by the `profilegrid-app`

**Full directory tree, pom files not mandatory.**

    ├── griffon-app
    │   ├── conf
    │   ├── controllers
    │   ├── i18n
    │   ├── lifecycle
    │   ├── models
    │   ├── resources
    │   ├── services
    │   ├── views
    │   └── pom.xml
    ├── pom.xml
    └── src
        ├── functional-test
        │   └── java
        ├── integration-test
        │   └── java
        ├── main
        │   ├── java
        │   └── resources
        └── test
            ├── java
            └── resources

**Directories supporting directly the Griffon framework.**

    ├── griffon-app
    │   ├── conf
    │   ├── controllers
    │   ├── models
    |   ├── resources
    │   ├── services
    │   ├── views

Further abstraction of the `Griffon framework` is the Griffon
`MVCGroup`, a composition of a view, a model and a controller. These
three members of a `MVCGroup` (here named sample) are stored in the
directories like this:

**Files involved in one `MVCGroup`.**

    ├── griffon-app
    │   ├── conf  ── Config.java
    │   ├── controllers ── SampleController.java
    │   ├── models ── SampleModel.java
    |   ├── resources ── (sample.fxml)
    │   ├── services ── (AService.java)
    │   ├── views ── SampleView.java

The file `Config.java` in directory `conf` serves the purpose to
configure the `MVCGroup` in the framework.

**Directory `conf` with this `Config.java` file for the
`MVCGroup sample` configuration:.**

    public class Config extends AbstractMapResourceBundle {
        @Override
        protected void initialize(@Nonnull final Map<String, Object> entries) {
            map(entries)
                .e("application",
                    map().e("name", "Profile Grid Application").e("title", "app-profilegrid")
                         .e("startupGroups", asList("sample")).e("autoShutdown", true))
                             .e("mvcGroups", map().e("sample",
                                 map().e("model", "SampleModel")
                                      .e("view", "SampleView")
                                      .e("controller", "SampleController"))
        }
    }

MVC Pattern used in the `profilegrid-app`
-----------------------------------------

The `PresentationModel View Controller` (PMVC) pattern used in the
`profilegrid-app` is a variation of the MVC. The `PresentationModel` is
responsible for holding the information needed to display the
application’s data and cares how data should be visualized, such as
colors, fonts, etc. The `View` benefits from the `FX Bindings` that tie
the data from the `PresentationModel` to the `View’s` UI elements. In
the `profilegrid-app` the `View` can also directly provoke visual
results and manipulate view aspects to optimize the visual user
experience. Nonetheless the `View` must delegate all data input or
output to its `Controller`. The `Controller` is the only one to
manipulate the `PresentationModel` directly, completely oblivious about
a specific `View`. This leads to a much more testable component, as the
`PresentationModel` and `Controller` are completely separated from the
`View`. [Figure 1](#anchor-6) shows visually how `PresentationModel`,
`View` and `Controller` interact.

**Figure 1. PMVC Pattern.**

![PMVC Pattern](./pmvc.png)

MVC Pattern realizations and `Model`, `Controller`, `Service` injections without `Griffon`
------------------------------------------------------------------------------------------

Finally I want to remember, that G. Krug, O. Alves, J. Molinari and E.
Roux with there CERN JavaFX work gave us everything in our hands to use
eg. a (PMVC) pattern with injection of a Controller. By naming
convention they resolve an existing half-developed controller and
generate and add automatically fields and event handlers.

See the article [Best practices for efficient development of JavaFX
applications](https://cds.cern.ch/record/2305503/files/thapl02.pdf) of
them to remember the features we already own in our codebase.
