'Recursion using Flux

I have a scenario, where I am using the State pattern. Every Start has an Action defined. We start with an initial state and an initial Action and then keep going until the Action becomes null. If the action becomes null, then we stop the execution. Also, the transition between the states is not sequential. We execute the Action on the State that is returned by the previous state.

To replicate the same, I have implemented the below recursion -

SelectionMachine

    private Flux<SelectionState> run(OfferSelectionRequest request) {
        Flux<SelectionStateResult> initialSelectionStateResult = Flux.just(new SelectionStateResult(selectionRequested, ACTION_START, new SelectionContext(request)));
        return go(initialSelectionStateResult);
    }

    private Flux<SelectionState> go(Flux<SelectionStateResult> resultFlux) {
        val result = resultFlux.flatMap(selectionStateResult -> {
            if (selectionStateResult.getAction().isEmpty())
                return Flux.just(selectionStateResult);
            else {
                selectionStateResult.getAction().get();
                return go(move(selectionStateResult.getState(), selectionStateResult.getAction().orElse(null), selectionStateResult.getContext().getRequest()));
            }
        });

        return result;
    }

    private Flux<SelectionStateResult> move(SelectionState state, Action action, OfferSelectionRequest request) {
        Flux<SelectionStateResult> result = Flux.empty();

        if (ACTION_START.equals(action)) {
            result = state.start(request);
        } else if (ACTION_FETCH_OFFERS.equals(action)) {
            state.fetchOffers(request);
        } else {
            result = Flux.just(new SelectionStateResult(state));
        }

        return result;
    }

SelectionStateResult

package com.paytmlabs.adtech.adtechdecisionengine.domain.selection;

import com.paytmlabs.adtech.adtechdecisionengine.domain.result.OfferResult;
import com.paytmlabs.adtech.adtechdecisionengine.exception.SelectionError;
import com.paytmlabs.adtech.adtechdecisionengine.selection.machine.InternalSelectionStateMachine;
import com.paytmlabs.adtech.adtechdecisionengine.selection.state.SelectionState;
import lombok.Data;

import java.util.List;
import java.util.Optional;

@Data
public class SelectionStateResult {
    private SelectionState state;
    private Optional<InternalSelectionStateMachine.Action> action;
    private SelectionContext context;
    private SelectionError error;
    private List<OfferResult> selectedOffers; // TODO: OfferResult needs to be created

    public SelectionStateResult(SelectionState state) {
        this.state = state;
        this.action = Optional.empty();
    }

    public SelectionStateResult(SelectionState state, InternalSelectionStateMachine.Action action) {
        this.state = state;
        this.action = Optional.ofNullable(action);
    }

    public SelectionStateResult(SelectionState state, InternalSelectionStateMachine.Action action, SelectionContext context) {
        this.state = state;
        this.action = Optional.ofNullable(action);
        this.context = context;
    }

    public SelectionStateResult(SelectionState state, SelectionError error) {
        this.state = state;
        this.action = Optional.empty();
        this.context = null;
        this.error = error;
    }

    public SelectionStateResult(SelectionState state, SelectionContext context) {
        this.state = state;
        this.action = Optional.empty();
        this.context = context;
        this.error = null;
    }
}

When I try to do this, I am getting an error in the go method-

no instance(s) of type variable(s) R exist so that SelectionState conforms to Publisher<? extends R>

Need some guidance on how can I implement the following use case -

  1. We start from an initial state and action.
  2. After the state terminates, it returns a state and an action.
  3. If action and state are not null, we execute the action of the returned state.
  4. If the action is null, we just return the state and that is the end of the execution.


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source