Process configurable action
A Service Object is a JRebirth Component (part of CSM pattern, Command-Service-Model).
It can be retrieved from the ServiceFacade.
A Service can hold several Tasks defined by a WaveType. Each Task requires:
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 eligible
to garbage collection if it isn't retained by another object currently 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:
This is the
WaveType
used to process a Wave generated anywhere into the application.
41 42 43 44 45 | /** Wave type use to load events. */ WaveType DO_LOAD_EVENTS = Builders.waveType( "LOAD_EVENTS" ) .items(EditorWaves.EVENTS_FILE) .returnAction( "EVENTS_LOADED" ) .returnItem(EditorWaves.EVENTS); |
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.
67 68 69 | /** The file containing all events serialized. */ WaveItemBase<File> EVENTS_FILE = new WaveItemBase<File>() { }; |
The return Wave Type is automatically created with by the using the returnAction value with returnItem as WaveItem. The code above will generate a WaveType that uses only one WaveItem to store the list of events loaded from the given file.
71 72 73 | /** The name of the events. */ WaveItemBase<List<JRebirthEvent>> EVENTS = new WaveItemBase<List<JRebirthEvent>>() { }; |
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 initService()
method like this:
54 55 56 57 58 | @Override public void initService() { listen(DO_LOAD_EVENTS); } |
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 except if you want to receive an empty notification when the Job is done; just use JRebirthItems.voidItem.
55 56 57 58 59 60 61 62 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 | public void initService() { listen(DO_LOAD_EVENTS); } /** * {@inheritDoc} */ @Override @Priority (RunnablePriority.High) public List<JRebirthEvent> doLoadEvents( final File selecteFile, final Wave wave) { final List<JRebirthEvent> eventList = new ArrayList<>(); updateMessage(wave, "Parsing events" ); // Get number of line to calculate the task progression final int totalLines = ServiceUtility.countFileLines(selecteFile); try (BufferedReader br = new BufferedReader( new FileReader(selecteFile));) { int processedLines = 0 ; String strLine = br.readLine(); // Read File Line By Line while (strLine != null ) { processedLines++; updateProgress(wave, processedLines, totalLines); if (strLine.contains(JRebirthMarkers.JREVENT.getName())) { // Convert the string to a JRebirth event and add it to the list addEvent(eventList, strLine.substring(strLine.indexOf( ">>" ) + 2 )); } // Read the next line to process strLine = br.readLine(); } } catch ( final IOException e) { LOGGER.error( "Error while processing event file" , e); } return eventList; } |
To call this Service Feature, you can use the returnData from any JRebirth's Component. It takes at least 2 mandatory arguments:
Hereafter you will fin an example of service call with only one arguments passed:
58 59 60 | returnData(LoadEdtFileService. class , LoadEdtFileService.DO_LOAD_EVENTS, Builders.waveData(EditorWaves.EVENTS_FILE, selected)); |
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 :
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 one of the following method according to component used:
Each initXXX method is called into JRebirth Internal Thread by ready method.
38 39 40 41 42 | @Override protected void initModel() { listen(LoadEdtFileService.DO_LOAD_EVENTS.returnWaveType()); 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()); } |
All communications with Service Component is done into JIT and all Service Tasks are performed into one slot of JTP or HPTP according to priority defined with annotation.
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:
55 56 | @Priority (RunnablePriority.High) List<JRebirthEvent> doLoadEvents( final File selecteFile, final Wave wave); |
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:
You can update progress bar indicator by calling this method: