All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.tp.workflow.atom.runtime.WMove Maven / Gradle / Ivy

The newest version!
package io.vertx.tp.workflow.atom.runtime;

import io.horizon.eon.VString;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.up.eon.KName;
import io.vertx.up.uca.sectio.AspectConfig;
import io.vertx.up.unity.Ux;
import io.vertx.up.util.Ut;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static io.vertx.tp.workflow.refine.Wf.LOG;

/**
 * @author Lang
 */
public class WMove implements Serializable {
    static final WRule RULE_EMPTY = new WRule();
    private final ConcurrentMap rules = new ConcurrentHashMap<>();
    /*
     * The data structure is as following:
     * {
     *     "node": {
     *         "type": "Standard | Fork | Multi"
     *         "data": {
     *         },
     *         "rule": [
     *             WRule,
     *             WRule
     *         ],
     *         "aspect": AspectConfig,
     *         "gateway": {
     *              "taskKey": "path of value"
     *         }
     *     }
     * }
     *
     * 1) When `Standard` Mode, the `fork` configuration will not be used.
     * 2) When `Multi` Mode, the `fork` configuration will not be used.
     * 3) 「Valid」When `Fork/Join` Mode, the `fork` configuration will help to create Todo Tickets
     */
    private final String node;

    private final JsonObject data = new JsonObject();
    private final Set required = new HashSet<>();
    private final AspectConfig aspect;

    private final JsonObject gateway = new JsonObject();

    private WMove(final String node, final JsonObject config) {
        // Node Name
        this.node = node;


        // Config for Camunda Engine
        /*
         * Here are some modification of data node definition
         *
         * From:
         * data:{
         *     "draft": "draft"
         * }
         *
         * To:
         * data:{
         *     "draft": "`${draft}`"
         * }
         *
         * Here are the config specification to set the original config running.
         * All these kind of configuration will be the same in future.
         * 1) `data` Part
         * 2) `rule` Part:
         *    -- record
         *    -- todo
         *    -- ticket
         *    -- extension
         * 3) `gateway` Part ( visitT method in future )
         */
        final JsonObject expression = new JsonObject();
        final JsonObject original = Ut.valueJObject(config.getJsonObject(KName.DATA));
        Ut.itJObject(original, (to, from) -> {
            this.required.add(to);
            final String valueExpr = "`${" + to + "}`";
            expression.put(from, valueExpr);
        });
        this.data.mergeIn(expression, true);
        // Ut.itJObject(data, (value, field) -> this.data.put(field, value));

        // Processing for left rules
        final JsonArray rules = Ut.valueJArray(config.getJsonArray(KName.RULE));
        Ut.itJArray(rules).forEach(json -> {
            final WRule rule = Ux.fromJson(json, WRule.class);
            if (rule.valid()) {
                this.rules.put(rule.key(), rule);
            } else {
                LOG.Move.warn(this.getClass(), "Rule invalid: {0}", rule.toString());
            }
        });

        // Processing for Aspect
        this.aspect = AspectConfig.create(Ut.valueJObject(config, KName.ASPECT));

        /*
         * Processing for NodeType configuration
         * 1. type = Standard
         * 2. type = Fork
         * 3. type = Multi
         *
         * The configuration node should be gateway, in current version, this
         * configuration is Ok for `Fork` only.
         */
        this.gateway.mergeIn(Ut.valueJObject(config, KName.GATEWAY));
    }

    public static WMove create(final String node, final JsonObject config) {
        return new WMove(node, config);
    }

    public static WMove empty() {
        return new WMove(null, new JsonObject());
    }

    AspectConfig configAop() {
        return this.aspect;
    }

    JsonObject configWay() {
        return this.gateway.copy();
    }

    /*
     * parameters for two components
     * 1. Movement Internal call `RunOn`, based on WRequest request
     * 2. Transfer will select `WRule` for process execution
     */
    JsonObject inputMovement(final JsonObject requestJ) {
        // Extract Data from `data` configuration
        // Fix Issue: 'toUser' exception error : failed to evaluate '${toUser}'
        this.required.forEach(fieldExpr -> {
            if (!requestJ.containsKey(fieldExpr)) {
                requestJ.putNull(fieldExpr);
            }
        });
        return Ut.fromExpression(this.data, requestJ);
    }

    WRule inputTransfer(final JsonObject params) {
        final Set keys = new TreeSet<>();
        params.fieldNames().forEach(field -> {
            final Object value = params.getValue(field);
            if (Objects.nonNull(value)) {
                final String key = field + VString.EQUAL + value;
                keys.add(key);
            }
        });
        final String key = Ut.fromJoin(keys);
        // Fix: java.lang.NullPointerException when `WRule` is null
        final WRule rule = this.rules.getOrDefault(key, RULE_EMPTY);
        LOG.Move.info(this.getClass(), "[ Rule ] The node `{0}` rule processed: {1}", this.node, rule);
        return rule;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy