1. Introduction

Allows controller actions to ve invoked as promises. Relies on JDeferred as promise implementation.

There are two ways to configure an action as a promise: implicit and explicit

Implicit Mode

Requires applying the @Promise annotation to the action method, making sure it returns a value. For example:

griffon-app/controllers/com/acme/SampleController.groovy
package com.acme

import griffon.core.artifact.GriffonController
import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor
import griffon.plugins.jdeferred.Promise
import org.codehaus.griffon.runtime.core.artifact.AbstractGriffonController
import javax.annotation.Nonnull

@ArtifactProviderFor(GriffonController)
class SampleController extends AbstractGriffonController {
    @MVCMember @Nonnull SampleModel model

    @Promise
    int implicitMode() {
        model.count = model.count + 1
        model.count
    }
}

The return value of the action will be set as the resolved value of the JDeferred Promise. Any exceptions that may occur during the action’s execution will set as the Promises rejected value.

Explicit Mode

This mode gives you further control on when a value may be resolved or rejected; it alos allows you to publish intermediate results by calling notify. For example

griffon-app/controllers/com/acme/SampleController.groovy
package com.acme

import griffon.core.artifact.GriffonController
import griffon.core.controller.ControllerAction
import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor
import org.codehaus.griffon.runtime.core.artifact.AbstractGriffonController
import org.jdeferred.Deferred
import javax.annotation.Nonnull

@ArtifactProviderFor(GriffonController)
class SampleController extends AbstractGriffonController {
    @MVCMember @Nonnull SampleModel model

    @ControllerAction
    void explicitMode(@Nonnull Deferred deferred) {
        model.count = model.count + 1
        1.upto(3) { deferred.notify(it) }
        deferred.resolve(model.count)
    }
}

Any exceptions that may occur during the action’s execution will be set as the Promises rejected value if the promise has not been resolved at that point.

1.1. Handling Results

Typically you’ll register callbacks on a Promise in order to handle results and errors delivered by the promise. However promises are not available until the action is about to bhe executed, that’s too late to register a callback. For this reason, the jdeferred plugin allows you to record callbacks ahead of time, using RecordingPromise in combination with PromiseManager. Here’s how callbacks can be set on a view during it’s intialization

griffon-app/views/com/acme/SampleView.java
package com.acme;

import griffon.core.artifact.GriffonView;
import griffon.inject.MVCMember;
import griffon.metadata.ArtifactProviderFor;
import griffon.plugins.jdeferred.RecordingPromise;
import org.codehaus.griffon.runtime.javafx.artifact.AbstractJavaFXGriffonView;

import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.Map;

@ArtifactProviderFor(GriffonView.class)
public class SampleView extends AbstractJavaFXGriffonView {
    @Inject private PromiseManager promiseManager;
    @MVCMember @Nonnull private SampleController controller;

    @Override
    public void mvcGroupInit(@Nonnull Map<String, Object> args) {
        RecordingPromise<String, Throwable, Void> promise = promiseManager.promiseFor(actionFor(controller, "click"));
        promise.done(r -> System.out.println("Result is " + r))
            .fail(Throwable::printStackTrace)
            .always((s, r, j) -> System.out.println("Finished!"));
    }

    @Override
    public void initUI() {
        // build the UI
    }
}

Griffon version: 2.11.0

2. Build JDeferred

2.1. Gradle

You have two options for configuring this plugin: automatic and manual.

2.1.1. Automatic

As long as the project has the org.codehaus.griffon.griffon plugin applied to it you may include the following snippet in build.gradle

dependencies {
    griffon 'org.codehaus.griffon.plugins:griffon-jdeferred-plugin:1.0.0'
}

The griffon plugin will take care of the rest given its configuration.

2.1.2. Manual

You will need to configure any of the following blocks depending on your setup

Core Support
dependencies {
    compile 'org.codehaus.griffon.plugins:griffon-jdeferred-core:1.0.0'
}
JavaFX Support
dependencies {
    compile 'org.codehaus.griffon.plugins:griffon-jdeferred-javafx:1.0.0'
}
Lanterna Support
dependencies {
    compile 'org.codehaus.griffon.plugins:griffon-jdeferred-lanterna:1.0.0'
}
Pivot Support
dependencies {
    compile 'org.codehaus.griffon.plugins:griffon-jdeferred-pivot:1.0.0'
}
Swing Support
dependencies {
    compile 'org.codehaus.griffon.plugins:griffon-jdeferred-swing:1.0.0'
}

2.2. Maven

First configure the griffon-jdeferred-plugin BOM in your POM file, by placing the following snippet before the <build> element

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.griffon.plugins</groupId>
            <artifactId>griffon-jdeferred-plugin</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Next configure dependencies as required by your particular setup

Core Support
<dependency>
    <groupId>org.codehaus.griffon.plugins</groupId>
    <artifactId>griffon-jdeferred-core</artifactId>
</dependency>
JavaFX Support
<dependency>
    <groupId>org.codehaus.griffon.plugins</groupId>
    <artifactId>griffon-jdeferred-javafx</artifactId>
</dependency>
Lanterna Support
<dependency>
    <groupId>org.codehaus.griffon.plugins</groupId>
    <artifactId>griffon-jdeferred-lanterna</artifactId>
</dependency>
Pivot Support
<dependency>
    <groupId>org.codehaus.griffon.plugins</groupId>
    <artifactId>griffon-jdeferred-pivot</artifactId>
</dependency>
Swing Support
<dependency>
    <groupId>org.codehaus.griffon.plugins</groupId>
    <artifactId>griffon-jdeferred-swing</artifactId>
</dependency>

3. Modules

The following sections display all bindings per module. Use this information to successfully override a binding on your own modules or to troubleshoot a module binding if the wrong type has been applied by the Griffon runtime.

3.1. JDeferred Core

Module name: jdeferred

bind(ActionManager.class)
    .to(JDeferredActionManager.class)
    .asSingleton();

bind(ActionHandler.class)
    .to(JDeferredActionHandler.class)
    .asSingleton();

bind(PromiseManager.class)
    .to(DefaultPromiseManager.class)
    .asSingleton();

3.2. JDeferred JavaFX

Module name: jdeferred-javafx

Depends on: jdeferred

bind(ActionManager.class)
    .to(JDeferredJavaFXActionManager.class)
    .asSingleton();

3.3. JDeferred Lanterna

Module name: jdeferred-lanterna

Depends on: jdeferred

bind(ActionManager.class)
    .to(JDeferredJavaLanternaManager.class)
    .asSingleton();

3.4. JDeferred Pivot

Module name: jdeferred-pivot

Depends on: jdeferred

bind(ActionManager.class)
    .to(JDeferredPivotActionManager.class)
    .asSingleton();

3.5. JDeferred Swing

Module name: jdeferred-swing

Depends on: jdeferred

bind(ActionManager.class)
    .to(JDeferredSwingActionManager.class)
    .asSingleton();