{"id":1211,"date":"2014-06-26T01:00:00","date_gmt":"2014-06-25T23:00:00","guid":{"rendered":"http:\/\/www.jensd.de\/wordpress\/?p=1211"},"modified":"2014-06-26T01:00:00","modified_gmt":"2014-06-25T23:00:00","slug":"at-your-service","status":"publish","type":"post","link":"https:\/\/www.jensd.de\/wordpress\/?p=1211","title":{"rendered":"At your Service!"},"content":{"rendered":"<p>The Service class (javafx.concurrency.Service) may not only be used to keep the UI reactive on long duration tasks but can also be used to change the state of controls or keep UI in a reasonable state on short term actions.<\/p>\n<p>Recall that a <code><strong>Service<\/strong><\/code> is like a reusable <code><strong>Task<\/strong><\/code>. A <code><strong>Task<\/strong><\/code> can be executed once and has to be re-instantiated to be started again. The <code><strong>Service<\/strong><\/code> class creates a new <code><strong>Task<\/strong><\/code> each time it is (re-)started (<code>createTask()<\/code> is called then). <\/p>\n<p>This is the <code><strong>start()<\/strong><\/code>-method from <code><strong>javafx.concurrency.Service<\/strong><\/code> class:<br \/>\n[java]<br \/>\npublic void start() {<\/p>\n<p>   checkThread();<\/p>\n<p>    if (getState() != State.READY) {<br \/>\n        throw new IllegalStateException(<br \/>\n                &#8220;Can only start a Service in the READY state. Was in state &#8221; + getState());<br \/>\n    }<\/p>\n<p>    \/\/ Create the task<br \/>\n    task = createTask();<\/p>\n<p>    \/\/ Wire up all the properties so they use this task<br \/>\n    state.bind(task.stateProperty());<br \/>\n    value.bind(task.valueProperty());<br \/>\n    exception.bind(task.exceptionProperty());<br \/>\n    workDone.bind(task.workDoneProperty());<br \/>\n    totalWorkToBeDone.bind(task.totalWorkProperty());<br \/>\n    progress.bind(task.progressProperty());<br \/>\n    running.bind(task.runningProperty());<br \/>\n    message.bind(task.messageProperty());<br \/>\n\ttitle.bind(task.titleProperty());<\/p>\n<p>    \/\/ Advance the task to the &#8220;SCHEDULED&#8221; state<br \/>\n    task.setState(State.SCHEDULED);<\/p>\n<p>    \/\/ Start the task<br \/>\n    executeTask(task);<br \/>\n}<br \/>\n[\/java]<\/p>\n<p>Note that the properties binding of the <code><strong>Task<\/strong><\/code> (<code>reset()<\/code> is cleaning up all stuff).<\/p>\n<p>In this post want to show how I&#8217;m using Services together with a JavaFX UI, like in <a href=\"http:\/\/www.jensd.de\/wordpress\/?p=1195\" title=\"MQTT.fx 0.0.3 released\" target=\"_blank\">MQTT.fx<\/a> to connect or disconnect to a MQTT broker.<\/p>\n<p><strong>A simple connection pane with 5 controls:<\/strong><\/p>\n<p><a href=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connectionPane.jpg\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1223\" data-permalink=\"https:\/\/www.jensd.de\/wordpress\/?attachment_id=1223\" data-orig-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connectionPane.jpg\" data-orig-size=\"889,213\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"connectionPane\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connectionPane-300x71.jpg\" data-large-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connectionPane.jpg\" tabindex=\"0\" role=\"button\" src=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connectionPane.jpg\" alt=\"connectionPane\" width=\"889\" height=\"213\" class=\"aligncenter size-full wp-image-1223\" srcset=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connectionPane.jpg 889w, https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connectionPane-300x71.jpg 300w\" sizes=\"(max-width: 889px) 100vw, 889px\" \/><\/a><\/p>\n<p><strong>Wanted appearance \/ behavior:<\/strong><br \/>\n<code><strong>connectButton<\/strong><\/code>: only enabled if: not connected AND no service is running<br \/>\n<code><strong>disconnectButton<\/strong><\/code>: only enabled if: connected AND no service is running<br \/>\n<code><strong>cancelButton & progressIndicator<\/strong><\/code>: only visible if: any service is running<br \/>\n<code><strong>serviceMessageLabel<\/strong><\/code>: user feedback about the states of the services and the application<\/p>\n<p><a href=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/start.jpg\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1226\" data-permalink=\"https:\/\/www.jensd.de\/wordpress\/?attachment_id=1226\" data-orig-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/start.jpg\" data-orig-size=\"693,92\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"start\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/start-300x39.jpg\" data-large-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/start.jpg\" tabindex=\"0\" role=\"button\" src=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/start.jpg\" alt=\"start\" width=\"693\" height=\"92\" class=\"aligncenter size-full wp-image-1226\" srcset=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/start.jpg 693w, https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/start-300x39.jpg 300w\" sizes=\"(max-width: 693px) 100vw, 693px\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connecting.jpg\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1227\" data-permalink=\"https:\/\/www.jensd.de\/wordpress\/?attachment_id=1227\" data-orig-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connecting.jpg\" data-orig-size=\"692,93\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"connecting\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connecting-300x40.jpg\" data-large-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connecting.jpg\" tabindex=\"0\" role=\"button\" src=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connecting.jpg\" alt=\"connecting\" width=\"692\" height=\"93\" class=\"aligncenter size-full wp-image-1227\" srcset=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connecting.jpg 692w, https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connecting-300x40.jpg 300w\" sizes=\"(max-width: 692px) 100vw, 692px\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connected.jpg\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1228\" data-permalink=\"https:\/\/www.jensd.de\/wordpress\/?attachment_id=1228\" data-orig-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connected.jpg\" data-orig-size=\"694,93\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"connected\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connected-300x40.jpg\" data-large-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connected.jpg\" tabindex=\"0\" role=\"button\" src=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connected.jpg\" alt=\"connected\" width=\"694\" height=\"93\" class=\"aligncenter size-full wp-image-1228\" srcset=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connected.jpg 694w, https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/connected-300x40.jpg 300w\" sizes=\"(max-width: 694px) 100vw, 694px\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/disconnecting.jpg\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1229\" data-permalink=\"https:\/\/www.jensd.de\/wordpress\/?attachment_id=1229\" data-orig-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/disconnecting.jpg\" data-orig-size=\"692,91\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"disconnecting\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/disconnecting-300x39.jpg\" data-large-file=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/disconnecting.jpg\" tabindex=\"0\" role=\"button\" src=\"http:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/disconnecting.jpg\" alt=\"disconnecting\" width=\"692\" height=\"91\" class=\"aligncenter size-full wp-image-1229\" srcset=\"https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/disconnecting.jpg 692w, https:\/\/www.jensd.de\/wordpress\/wp-content\/uploads\/2014\/06\/disconnecting-300x39.jpg 300w\" sizes=\"(max-width: 692px) 100vw, 692px\" \/><\/a><\/p>\n<p><strong>The controller has two properties and contains two services (inner classes):<\/strong><br \/>\n<code><strong><br \/>\nStringProperty statusMessagesProperty<br \/>\nBooleanProperty connectedProperty<br \/>\n<\/code><\/strong><\/p>\n<p><strong>ConnectService<\/strong><br \/>\n[java]<br \/>\nprivate class ConnectService extends Service<Void> {<\/p>\n<p>        @Override<br \/>\n        protected void succeeded() {<br \/>\n            statusMessagesProperty().set(&#8220;Connected.&#8221;);<br \/>\n            connectedProperty().set(true);<br \/>\n        }<\/p>\n<p>        @Override<br \/>\n        protected void failed() {<br \/>\n            statusMessagesProperty().set(&#8220;Connecting failed.&#8221;);<br \/>\n            LOGGER.severe(getException().getMessage());<br \/>\n            connectedProperty().set(false);<br \/>\n        }<\/p>\n<p>        @Override<br \/>\n        protected void cancelled() {<br \/>\n            statusMessagesProperty().set(&#8220;Connecting cancelled.&#8221;);<br \/>\n            connectedProperty().set(false);<br \/>\n        }<\/p>\n<p>        @Override<br \/>\n        protected Task<Void> createTask() {<br \/>\n            return new Task<Void>() {<br \/>\n                @Override<br \/>\n                protected Void call() throws Exception {<br \/>\n                    updateMessage(&#8220;Connecting&#8230;.&#8221;);<br \/>\n                    Thread.sleep(1000);<br \/>\n                    \/\/ DEMO: un-comment to provoke &#8220;Not on FX application thread&#8221;-Exception:<br \/>\n                    \/\/ connectButton.setVisible(false);<br \/>\n                    updateMessage(&#8220;Waiting for server feedback.&#8221;);<br \/>\n                    Thread.sleep(2000);<br \/>\n                    return null;<br \/>\n                }<br \/>\n            };<br \/>\n        }<\/p>\n<p>    }<br \/>\n[\/java]<\/p>\n<p><strong>DisconnectService <\/strong><\/p>\n<p>[java]<br \/>\n    private class DisconnectService extends Service<Void> {<\/p>\n<p>        @Override<br \/>\n        protected void succeeded() {<br \/>\n            statusMessagesProperty().set(&#8220;&#8221;);<br \/>\n            connectedProperty().set(false);<br \/>\n        }<\/p>\n<p>        @Override<br \/>\n        protected void cancelled() {<br \/>\n            statusMessagesProperty().set(&#8220;Disconnecting cancelled.&#8221;);<br \/>\n            connectedProperty().set(false);<br \/>\n        }<\/p>\n<p>        @Override<br \/>\n        protected Task<Void> createTask() {<br \/>\n            return new Task<Void>() {<br \/>\n                @Override<br \/>\n                protected Void call() throws Exception {<br \/>\n                    updateMessage(&#8220;Disconnecting&#8230;.&#8221;);<br \/>\n                    Thread.sleep(1000);<br \/>\n                    updateMessage(&#8220;Waiting for server feedback.&#8221;);<br \/>\n                    Thread.sleep(2000);<br \/>\n                    return null;<br \/>\n                }<br \/>\n            };<br \/>\n        }<\/p>\n<p>    }<br \/>\n[\/java]<\/p>\n<p><strong>The wanted UI-behavior can be accomplished just by some Bindings<\/strong><br \/>\n<code><br \/>\nBooleanBinding anyServiceRunning = connectService.runningProperty().or(disconnectService.runningProperty());<br \/>\nserviceRunningIndicator.visibleProperty().bind(anyServiceRunning);<br \/>\ncancelButton.visibleProperty().bind(anyServiceRunning);<br \/>\nconnectButton.disableProperty().bind(connectedProperty().or(anyServiceRunning));<br \/>\ndisconnectButton.disableProperty().bind(connectedProperty().not().or(anyServiceRunning));<br \/>\nmessagesLabel.textProperty().bind(statusMessagesProperty());<br \/>\n<\/code><\/p>\n<p><strong>ChangeListeners are passing the messages from the services to the statusMessagesProperty:<\/strong><br \/>\n<code><br \/>\nconnectService.messageProperty().addListener((ObservableValue<? extends String> observableValue, String oldValue, String newValue) -> {<br \/>\n            statusMessagesProperty().set(newValue);<br \/>\n        });<br \/>\ndisconnectService.messageProperty().addListener((ObservableValue<? extends String> observableValue, String oldValue, String newValue) -> {<br \/>\n\tstatusMessagesProperty().set(newValue);<br \/>\n});<br \/>\n<\/code><\/p>\n<p><strong>Three methods to control the services:<\/strong><\/p>\n<p>[java]<br \/>\n   @FXML<br \/>\n    public void cancel() {<br \/>\n        LOGGER.info(&#8220;cancel&#8221;);<br \/>\n        connectService.cancel();<br \/>\n        disconnectService.cancel();<br \/>\n    }<\/p>\n<p>    @FXML<br \/>\n    public void connect() {<br \/>\n        LOGGER.info(&#8220;connect&#8221;);<br \/>\n        disconnectService.cancel();<br \/>\n        connectService.restart();<br \/>\n    }<\/p>\n<p>    @FXML<br \/>\n    public void disconnect() {<br \/>\n        LOGGER.info(&#8220;disconnect&#8221;);<br \/>\n        connectService.cancel();<br \/>\n        disconnectService.restart();<br \/>\n    }<br \/>\n[\/java]<\/p>\n<p><strong>Nice &#038; convenient:<\/strong><br \/>\nInstead of verifying the state of the <code><strong>Service<\/strong><\/code> you can just call <code><strong>restart()<\/strong><\/code>.<br \/>\n<code><strong>restart()<\/strong><\/code> executes:<br \/>\n1. <code><strong>cancel()<\/strong><\/code> (if running): cancel the executed service-task<br \/>\n2. <code><strong>reset()<\/strong><\/code>: clear the <code><strong>Service<\/strong><\/code> (task=null and unbind all stuff)<br \/>\nand then<br \/>\n3. <code><strong>start()<\/strong><\/code>: create new <code><strong>Task<\/strong><\/code> and bind its properties<\/p>\n<p><iframe loading=\"lazy\" title=\"At your Service!\" width=\"900\" height=\"506\" src=\"https:\/\/www.youtube.com\/embed\/gvi0fvMi2kU?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/p>\n<p><strong>You can get the complete code of this tutorial in my BitBucket repo:<\/strong><\/p>\n<p><a href=\"https:\/\/bitbucket.org\/Jerady\/servicedemoapp\/src\" title=\"ServiceDemoApp\" target=\"_blank\">ServiceDemoApp<\/a><br \/>\n<a href=\"https:\/\/bitbucket.org\/Jerady\/servicedemoapp\/src\" title=\"https:\/\/bitbucket.org\/Jerady\/servicedemoapp\/src\" target=\"_blank\">https:\/\/bitbucket.org\/Jerady\/servicedemoapp\/src<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Service class (javafx.concurrency.Service) may not only be used to keep the UI reactive on long duration tasks but can also be used to change the state of controls or keep UI in a reasonable state on short term actions. Recall that a Service is like a reusable Task. A Task can be executed once&hellip; <span class=\"clear\"><\/span><a href=\"https:\/\/www.jensd.de\/wordpress\/?p=1211\" class=\"more-link read-more\" rel=\"bookmark\">Continue Reading <span class=\"screen-reader-text\">At your Service!<\/span><i class=\"fa fa-arrow-right\"><\/i><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false,"jetpack_publicize_message":"At your Service! http:\/\/wp.me\/p38FCL-jx","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[48,4],"tags":[104,76,105],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p38FCL-jx","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1211"}],"collection":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1211"}],"version-history":[{"count":25,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1211\/revisions"}],"predecessor-version":[{"id":1241,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1211\/revisions\/1241"}],"wp:attachment":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1211"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}