001/**
002 * Copyright (c) 2025-2026, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.gnu.org/licenses/lgpl-3.0.txt
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package dev.tinyflow.core.parser;
017
018
019import com.alibaba.fastjson.JSONArray;
020import com.alibaba.fastjson.JSONObject;
021import dev.tinyflow.core.chain.DataType;
022import dev.tinyflow.core.chain.JsCodeCondition;
023import dev.tinyflow.core.chain.Parameter;
024import dev.tinyflow.core.chain.RefType;
025import dev.tinyflow.core.node.BaseNode;
026import dev.tinyflow.core.util.StringUtil;
027
028import java.util.ArrayList;
029import java.util.Collections;
030import java.util.List;
031
032
033public abstract class BaseNodeParser<T extends BaseNode> implements NodeParser<T> {
034
035    private static final JSONObject EMPTY_JSON_OBJECT = new JSONObject(Collections.emptyMap());
036
037    private ChainParser chainParser;
038
039    @Override
040    public ChainParser getChainParser() {
041        return chainParser;
042    }
043
044    public JSONObject getData(JSONObject nodeObject) {
045        JSONObject jsonObject = nodeObject.getJSONObject("data");
046        return jsonObject != null ? jsonObject : EMPTY_JSON_OBJECT;
047    }
048
049    public void addParameters(BaseNode node, JSONObject data) {
050        List<Parameter> inputParameters = getParameters(data, "parameters");
051        node.setParameters(inputParameters);
052    }
053
054    public List<Parameter> getParameters(JSONObject data, String key) {
055        return getParameters(data.getJSONArray(key));
056    }
057
058    public List<Parameter> getParameters(JSONArray parametersJsonArray) {
059        if (parametersJsonArray == null || parametersJsonArray.isEmpty()) {
060            return Collections.emptyList();
061        }
062        List<Parameter> parameters = new ArrayList<>(parametersJsonArray.size());
063        for (int i = 0; i < parametersJsonArray.size(); i++) {
064            JSONObject parameterJsonObject = parametersJsonArray.getJSONObject(i);
065            Parameter parameter = new Parameter();
066            parameter.setId(parameterJsonObject.getString("id"));
067            parameter.setName(parameterJsonObject.getString("name"));
068            parameter.setDescription(parameterJsonObject.getString("description"));
069            parameter.setDataType(DataType.ofValue(parameterJsonObject.getString("dataType")));
070            parameter.setRef(parameterJsonObject.getString("ref"));
071            parameter.setValue(parameterJsonObject.getString("value"));
072            parameter.setDefaultValue(parameterJsonObject.getString("defaultValue"));
073            parameter.setRefType(RefType.ofValue(parameterJsonObject.getString("refType")));
074            parameter.setDataType(DataType.ofValue(parameterJsonObject.getString("dataType")));
075            parameter.setRequired(parameterJsonObject.getBooleanValue("required"));
076            parameter.setDefaultValue(parameterJsonObject.getString("defaultValue"));
077
078            //新增
079            parameter.setContentType(parameterJsonObject.getString("contentType"));
080            parameter.setEnums(parameterJsonObject.getJSONArray("enums"));
081            parameter.setFormType(parameterJsonObject.getString("formType"));
082            parameter.setFormLabel(parameterJsonObject.getString("formLabel"));
083            parameter.setFormPlaceholder(parameterJsonObject.getString("formPlaceholder"));
084            parameter.setFormAttrs(parameterJsonObject.getString("formAttrs"));
085            parameter.setFormDescription(parameterJsonObject.getString("formDescription"));
086
087            JSONArray children = parameterJsonObject.getJSONArray("children");
088            if (children != null && !children.isEmpty()) {
089                parameter.addChildren(getParameters(children));
090            }
091
092            parameters.add(parameter);
093        }
094
095        return parameters;
096    }
097
098
099    public void addOutputDefs(BaseNode node, JSONObject data) {
100        List<Parameter> outputDefs = getParameters(data, "outputDefs");
101        if (outputDefs == null || outputDefs.isEmpty()) {
102            return;
103        }
104        node.setOutputDefs(outputDefs);
105    }
106
107
108    @Override
109    public T parse(JSONObject nodeJSONObject, JSONObject chainJSONObject, ChainParser chainParser) {
110        this.chainParser = chainParser;
111        JSONObject data = getData(nodeJSONObject);
112        T node = doParse(nodeJSONObject, data, chainJSONObject);
113        if (node != null) {
114
115            node.setId(nodeJSONObject.getString("id"));
116            node.setParentId(nodeJSONObject.getString("parentId"));
117            node.setName(nodeJSONObject.getString("label"));
118            node.setDescription(nodeJSONObject.getString("description"));
119
120            if (!data.isEmpty()) {
121
122                addParameters(node, data);
123                addOutputDefs(node, data);
124
125                String conditionString = data.getString("condition");
126
127                if (StringUtil.hasText(conditionString)) {
128                    node.setCondition(new JsCodeCondition(conditionString.trim()));
129                }
130
131//                Boolean async = data.getBoolean("async");
132//                if (async != null) {
133//                    node.setAsync(async);
134//                }
135
136                String name = data.getString("title");
137                if (StringUtil.hasText(name)) {
138                    node.setName(name);
139                }
140
141                String description = data.getString("description");
142                if (StringUtil.hasText(description)) {
143                    node.setDescription(description);
144                }
145
146                // 循环执行 start =======
147                Boolean loopEnable = data.getBoolean("loopEnable");
148                if (loopEnable != null) {
149                    node.setLoopEnable(loopEnable);
150                }
151
152                if (loopEnable != null && loopEnable) {
153                    Long loopIntervalMs = data.getLong("loopIntervalMs");
154                    if (loopIntervalMs == null) {
155                        loopIntervalMs = 3000L;
156                    }
157                    node.setLoopIntervalMs(loopIntervalMs);
158
159                    Integer maxLoopCount = data.getInteger("maxLoopCount");
160                    if (maxLoopCount != null) {
161                        node.setMaxLoopCount(maxLoopCount);
162                    }
163
164                    String loopBreakCondition = data.getString("loopBreakCondition");
165                    if (StringUtil.hasText(loopBreakCondition)) {
166                        node.setLoopBreakCondition(new JsCodeCondition(loopBreakCondition.trim()));
167                    }
168                }
169                // 循环执行 end =======
170
171
172                // 错误重试 start =======
173                Boolean retryEnable = data.getBoolean("retryEnable");
174                if (retryEnable != null) {
175                    node.setRetryEnable(retryEnable);
176                }
177
178                if (retryEnable != null && retryEnable) {
179                    Boolean resetRetryCountAfterNormal = data.getBoolean("resetRetryCountAfterNormal");
180                    if (resetRetryCountAfterNormal == null) {
181                        resetRetryCountAfterNormal = true;
182                    }
183                    node.setResetRetryCountAfterNormal(resetRetryCountAfterNormal);
184
185                    Long retryIntervalMs = data.getLong("retryIntervalMs");
186                    if (retryIntervalMs == null) {
187                        retryIntervalMs = 1000L;
188                    }
189                    node.setRetryIntervalMs(retryIntervalMs);
190
191                    Integer maxRetryCount = data.getInteger("maxRetryCount");
192                    if (maxRetryCount == null) {
193                        maxRetryCount = 3;
194                    }
195                    node.setMaxRetryCount(maxRetryCount);
196                }
197                // 错误重试 end =======
198            }
199        }
200
201        return node;
202    }
203
204    protected abstract T doParse(JSONObject nodeJSONObject, JSONObject data, JSONObject chainJSONObject);
205}