Fork me on GitHub

Service Layer

Process configurable action

Services

Overview

A Service Object is a JRebirth Component (part of CSM pattern, Command-Service-Model).
It can be retrieved from theServiceFacade.

A Service can hold several Tasks defined by aWaveType. Each Task requires:

  1. Define Call Wave Type (entry point)
  2. Define Return Wave Type (exit point)
  3. Register the Callback
  4. Define the Task process into the right method name.

That's all ! You don't have to bother about threading issues and asynchronous tasks.

Warning:
You must pay attention to the lifecycle of your service instance. As a JRebirth Component, each service object is elligible to garbage collection if it isn't retained by another object currenlty used.
So your data stored or processed into your service can be loss if you didn't manage correctly your Service life.
The most easy way is to hold your service with a strong reference into a long-living object like a top-levelModel.

Short UML Diagram:

Service Class Diagram

Defining Wave Types

Entry Point Wave Type

This is the WaveType used to process a Wave generated anywhere into the application.

44
45
/** Wave type use to load events. */
public static final WaveTypeBase DO_LOAD_EVENTS = WaveTypeBase.build("LOAD_EVENTS", EditorWaves.EVENTS_FILE);

This WaveType uses only one WaveItem to store the file that must be loaded. WaveItem wrap the type of the object we want to use, thus it's possible to check that API contract isn't broken.

63
64
65
/** The file containing all events serialized. */
WaveItem<File> EVENTS_FILE = new WaveItem<File>() {
};

Exit Point Wave Type

47
48
/** Wave type to return events loaded. */
public static final WaveTypeBase RE_EVENTS_LOADED = WaveTypeBase.build("EVENTS_LOADED", EditorWaves.EVENTS);

This WaveType uses only one WaveItem to store the list of events loaded from the given file.

67
68
69
/** The name of the events. */
WaveItem<List<JRebirthEvent>> EVENTS = new WaveItem<List<JRebirthEvent>>() {
};

Task Registration

Each Task requires to be registered in order to generate the right WaveType that wrap the return value.
This registration must be done into the JRebirth's Component void ready() method like this:

56
57
58
59
60
61
@Override
public void ready() throws CoreException {
    super.ready();
 
    registerCallback(DO_LOAD_EVENTS, RE_EVENTS_LOADED);
}

If you don't declare the return WaveType a exception will be thrown at runtime when trying to send back the Service Task output.

If your Service Task doesn't return anything (void return) you can dismiss this step.

Perform the Job!

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
 * Parse the event file.
 *
 * @param selecteFile the event file selected
 * @param wave the wave that trigger the action
 *
 * @return the list of loaded events
 */
@Priority(RunnablePriority.High)
public List<JRebirthEvent> doLoadEvents(final File selecteFile, final Wave wave) {
    final List<JRebirthEvent> eventList = new ArrayList<>();
 
    updateMessage(wave, "Parsing events");
 
    try (BufferedReader br = new BufferedReader(new FileReader(selecteFile));)
    {
 
        int totalLines = 0;
        while (br.readLine() != null){
            totalLines++;
        }
 
        br.reset();
 
        int processedLines = 0;
 
        String strLine = br.readLine();
        // Read File Line By Line
        while (strLine != null) {
            processedLines++;
 
            updateProgress(wave, totalLines, processedLines);
 
            if (strLine.contains(JRebirthMarkers.JREVENT.getName())) {
                addEvent(eventList, strLine.substring(strLine.indexOf(">>") + 2));
            }
            strLine = br.readLine();
 
        }
 
    } catch (final IOException e) {
        LOGGER.error("Error while processing event file", e);
    }
    return eventList;
 
}

How to use the Service Feature

Call the Service

To call thisService Feature, you can use the returnData from any JRebirth's Component. It takes at least 2 mandatory arguments:

  1. The Service Class Object
  2. The WaveType that is related to the Service Feature
  3. An unordered list of WaveData objects that wrap values required by WaveType contract

Hereafter you will fin an example of service call with only one arguments passed:

58
59
60
returnData(LoadEdtFileService.class,
        LoadEdtFileService.DO_LOAD_EVENTS,
        WaveData.build(EditorWaves.EVENTS_FILE, selected));

Process the Service Result

The Service Feature Result is sent as a Wave that wrap returned value. So to be informed when the result is available, there is two things to do :

  • Let your component listening this WaveType.
  • Add Wave handler code to process the result.

Each JRebirth's Component are able to listen some WaveType's waves by calling the listen method with one or several Wave Types.
This call must be done into the ready method or into initModel for Model classes.

38
39
40
41
42
@Override
protected void initModel() {
    listen(LoadEdtFileService.RE_EVENTS_LOADED);
    listen(EditorWaves.DO_UNLOAD);
}

Add a method that suit the WaveType convention.
The name must used the predefined prefix (in our case DO_ converted to do), then the WaveType's name converted in a camel cased format.
Method parameters must be compliant with Wave Items defined into the Wave Type.
A final parameter must be added, the Wave itself taht could be useful to get extra data, for example when chained waves are used.

51
52
53
public void doEventsLoaded(final List<JRebirthEvent> eventList, final Wave wave) {
    getView().activateButtons(!eventList.isEmpty());
}

Threading

Which Thread is involved ?

Threading Priority

Each Service feature call will be processed by the JTP (JRebirth Thread Pool) or by the HPTP (High Priority Thread Pool) according to their predefined priority.
By default the Priority is set to RunnablePriority.Low (a level below Normal) to let other task to be performed into JTP before Service feature calls (like Command).

Its possible to increase or decrease this value by adding an annotation on the Service Feature method like this:

71
72
@Priority(RunnablePriority.High)
public List<JRebirthEvent> doLoadEvents(final File selecteFile, final Wave wave) {

Follow Task progression

Each Service Task are able to update a progress bar with integer value and message. In both cases you must provide the wave provided as a method argument, it will be used to link the associated ServiceTask and find the right ProgressBar and Text widgets to update.
You can update the message test by calling this method:

75
updateMessage(wave, "Parsing events");

You can update progress bar indicator by calling this method:

94
updateProgress(wave, totalLines, processedLines);