开张大吉。
This commit is contained in:
53
src/main/java/com/wehotel/fizz/AggregateResource.java
Normal file
53
src/main/java/com/wehotel/fizz/AggregateResource.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.wehotel.fizz;
|
||||
|
||||
import com.wehotel.fizz.input.Input;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
public class AggregateResource {
|
||||
|
||||
private Pipeline pipeline;
|
||||
private Input input;
|
||||
|
||||
public AggregateResource(Pipeline pipeline, Input input) {
|
||||
super();
|
||||
this.pipeline = pipeline;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public Pipeline getPipeline() {
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
public void setPipeline(Pipeline pipeline) {
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
public Input getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(Input input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
}
|
||||
51
src/main/java/com/wehotel/fizz/AggregateResult.java
Normal file
51
src/main/java/com/wehotel/fizz/AggregateResult.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
public class AggregateResult {
|
||||
|
||||
private MultiValueMap<String, String> headers;
|
||||
|
||||
private Map<String, Object> body;
|
||||
|
||||
public MultiValueMap<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(MultiValueMap<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public Map<String, Object> getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(Map<String, Object> body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
}
|
||||
393
src/main/java/com/wehotel/fizz/ConfigLoader.java
Normal file
393
src/main/java/com/wehotel/fizz/ConfigLoader.java
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.wehotel.config.AppConfigProperties;
|
||||
import com.wehotel.fizz.input.ClientInputConfig;
|
||||
import com.wehotel.fizz.input.Input;
|
||||
import com.wehotel.fizz.input.InputType;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.noear.snack.ONode;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.wehotel.listener.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE;
|
||||
import static com.wehotel.util.Constants.Symbol.FORWARD_SLASH;
|
||||
/**
|
||||
*
|
||||
* @author francis
|
||||
* @author zhongjie
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class ConfigLoader {
|
||||
/**
|
||||
* 聚合配置存放Hash的Key
|
||||
*/
|
||||
private static final String AGGREGATE_HASH_KEY = "fizz_aggregate_config";
|
||||
|
||||
private static Map<String, String> aggregateResources = null;
|
||||
private static Map<String, ConfigInfo> resourceKey2ConfigInfoMap = null;
|
||||
private static Map<String, String> aggregateId2ResourceKeyMap = null;
|
||||
|
||||
@Resource
|
||||
private AppConfigProperties appConfigProperties;
|
||||
@Resource(name = AGGREGATE_REACTIVE_REDIS_TEMPLATE)
|
||||
private ReactiveStringRedisTemplate reactiveStringRedisTemplate;
|
||||
|
||||
@Value("${fizz.aggregate.read-local-config-flag:false}")
|
||||
private Boolean readLocalConfigFlag;
|
||||
|
||||
public Input createInput(String configStr) throws IOException {
|
||||
ONode cfgNode = ONode.loadStr(configStr);
|
||||
|
||||
Input input = new Input();
|
||||
input.setName(cfgNode.select("$.name").getString());
|
||||
|
||||
ClientInputConfig clientInputConfig = new ClientInputConfig();
|
||||
clientInputConfig.setDataMapping(cfgNode.select("$.dataMapping").toObject(Map.class));
|
||||
clientInputConfig.setHeaders(cfgNode.select("$.headers").toObject(Map.class));
|
||||
clientInputConfig.setMethod(cfgNode.select("$.method").getString());
|
||||
clientInputConfig.setPath(cfgNode.select("$.path").getString());
|
||||
if(cfgNode.select("$.debug") != null) {
|
||||
clientInputConfig.setDebug(cfgNode.select("$.debug").getBoolean());
|
||||
}
|
||||
clientInputConfig.setType(InputType.valueOf(cfgNode.select("$.type").getString()));
|
||||
clientInputConfig.setLangDef(cfgNode.select("$.langDef").toObject(Map.class));
|
||||
clientInputConfig.setBodyDef(cfgNode.select("$.bodyDef").toObject(Map.class));
|
||||
clientInputConfig.setHeadersDef(cfgNode.select("$.headersDef").toObject(Map.class));
|
||||
clientInputConfig.setParamsDef(cfgNode.select("$.paramsDef").toObject(Map.class));
|
||||
clientInputConfig.setScriptValidate(cfgNode.select("$.scriptValidate").toObject(Map.class));
|
||||
clientInputConfig.setValidateResponse(cfgNode.select("$.validateResponse").toObject(Map.class));
|
||||
input.setConfig(clientInputConfig);
|
||||
return input;
|
||||
}
|
||||
|
||||
public Pipeline createPipeline(String configStr) throws IOException {
|
||||
ONode cfgNode = ONode.loadStr(configStr);
|
||||
Pipeline pipeline = new Pipeline();
|
||||
|
||||
List<Map<String, Object>> stepConfigs = cfgNode.select("$.stepConfigs").toObject(List.class);
|
||||
for (Map<String, Object> stepConfig : stepConfigs) {
|
||||
// set the specified env URL
|
||||
this.handleRequestURL(stepConfig);
|
||||
|
||||
Step step = new Step.Builder().read(stepConfig);
|
||||
step.setName((String) stepConfig.get("name"));
|
||||
if (stepConfig.get("stop") != null) {
|
||||
step.setStop((Boolean) stepConfig.get("stop"));
|
||||
} else {
|
||||
step.setStop(false);
|
||||
}
|
||||
step.setDataMapping((Map<String, Object>) stepConfig.get("dataMapping"));
|
||||
pipeline.addStep(step);
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
public List<ConfigInfo> getConfigInfo() {
|
||||
if (aggregateResources == null) {
|
||||
try {
|
||||
this.init();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(resourceKey2ConfigInfoMap.values());
|
||||
}
|
||||
|
||||
public String getConfigStr(String configId) {
|
||||
if (aggregateResources == null) {
|
||||
try {
|
||||
this.init();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
String resourceKey = aggregateId2ResourceKeyMap.get(configId);
|
||||
if (resourceKey == null) {
|
||||
return null;
|
||||
}
|
||||
return aggregateResources.get(resourceKey);
|
||||
}
|
||||
|
||||
private void handleRequestURL(Map<String, Object> stepConfig) {
|
||||
List<Object> requests = (List<Object>) stepConfig.get("requests");
|
||||
for (Object obj : requests) {
|
||||
Map<String, Object> request = (Map<String, Object>) obj;
|
||||
String envUrl = (String) request.get(appConfigProperties.getEnv() + "Url");
|
||||
if(!StringUtils.isEmpty(envUrl)) {
|
||||
request.put("url", request.get(appConfigProperties.getEnv() + "Url"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void init() throws Exception {
|
||||
if (aggregateResources == null) {
|
||||
aggregateResources = new ConcurrentHashMap<>(1024);
|
||||
resourceKey2ConfigInfoMap = new ConcurrentHashMap<>(1024);
|
||||
aggregateId2ResourceKeyMap = new ConcurrentHashMap<>(1024);
|
||||
}
|
||||
|
||||
if (readLocalConfigFlag) {
|
||||
File dir = new File("json");
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
if (!file.exists()) {
|
||||
throw new IOException("File not found");
|
||||
}
|
||||
String configStr = FileUtils.readFileToString(file, Charset.forName("UTF-8"));
|
||||
this.addConfig(configStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 从Redis缓存中获取配置
|
||||
reactiveStringRedisTemplate.opsForHash().scan(AGGREGATE_HASH_KEY).subscribe(entry -> {
|
||||
String configStr = (String) entry.getValue();
|
||||
this.addConfig(configStr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void addConfig(String configStr) {
|
||||
if (aggregateResources == null) {
|
||||
try {
|
||||
this.init();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
ONode cfgNode = ONode.loadStr(configStr);
|
||||
String method = cfgNode.select("$.method").getString();
|
||||
String path = cfgNode.select("$.path").getString();
|
||||
String resourceKey = method.toUpperCase() + ":" + path;
|
||||
String configId = cfgNode.select("$.id").getString();
|
||||
String configName = cfgNode.select("$.name").getString();
|
||||
long version = cfgNode.select("$.version").getLong();
|
||||
if (StringUtils.hasText(configId)) {
|
||||
String existResourceKey = aggregateId2ResourceKeyMap.get(configId);
|
||||
if (StringUtils.hasText(existResourceKey)) {
|
||||
// 删除旧有的配置
|
||||
aggregateResources.remove(existResourceKey);
|
||||
resourceKey2ConfigInfoMap.remove(existResourceKey);
|
||||
}
|
||||
aggregateId2ResourceKeyMap.put(configId, resourceKey);
|
||||
}
|
||||
aggregateResources.put(resourceKey, configStr);
|
||||
resourceKey2ConfigInfoMap.put(resourceKey, this.buildConfigInfo(configId, configName, method, path, version));
|
||||
}
|
||||
|
||||
public synchronized void deleteConfig(String configIds) {
|
||||
if (CollectionUtils.isEmpty(aggregateId2ResourceKeyMap)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSONArray idArray = JSON.parseArray(configIds);
|
||||
idArray.forEach(it -> {
|
||||
String configId = (String) it;
|
||||
String existResourceKey =aggregateId2ResourceKeyMap.get(configId);
|
||||
if (StringUtils.hasText(existResourceKey)) {
|
||||
aggregateResources.remove(existResourceKey);
|
||||
resourceKey2ConfigInfoMap.remove(existResourceKey);
|
||||
aggregateId2ResourceKeyMap.remove(configId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public AggregateResource matchAggregateResource(String method, String path) {
|
||||
if (aggregateResources == null) {
|
||||
try {
|
||||
init();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
String key = method.toUpperCase() + ":" + path;
|
||||
if(aggregateResources.containsKey(key) && aggregateResources.get(key) != null) {
|
||||
String configStr = aggregateResources.get(key);
|
||||
Input input = null;
|
||||
Pipeline pipeline = null;
|
||||
try {
|
||||
input = createInput(configStr);
|
||||
pipeline = createPipeline(configStr);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
if (pipeline != null && input != null) {
|
||||
ClientInputConfig cfg = (ClientInputConfig) input.getConfig();
|
||||
return new AggregateResource(pipeline, input);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private ConfigInfo buildConfigInfo(String configId, String configName, String method, String path, long version) {
|
||||
String serviceName = this.extractServiceName(path);
|
||||
ConfigInfo configInfo = new ConfigInfo();
|
||||
configInfo.setConfigId(configId);
|
||||
configInfo.setConfigName(configName);
|
||||
configInfo.setServiceName(serviceName);
|
||||
configInfo.setMethod(method);
|
||||
configInfo.setPath(path);
|
||||
configInfo.setVersion(version == 0 ? null : version);
|
||||
return configInfo;
|
||||
}
|
||||
|
||||
private static final String FORMAL_PATH_PREFIX = "/proxy/";
|
||||
private static final int FORMAL_PATH_SERVICE_NAME_START_INDEX = 7;
|
||||
private static final String TEST_PATH_PREFIX = "/proxytest/";
|
||||
private static final int TEST_PATH_SERVICE_NAME_START_INDEX = 11;
|
||||
private String extractServiceName(String path) {
|
||||
if (path != null) {
|
||||
if (path.startsWith(FORMAL_PATH_PREFIX)) {
|
||||
int endIndex = path.indexOf(FORWARD_SLASH, FORMAL_PATH_SERVICE_NAME_START_INDEX);
|
||||
if (endIndex > FORMAL_PATH_SERVICE_NAME_START_INDEX) {
|
||||
return path.substring(FORMAL_PATH_SERVICE_NAME_START_INDEX, endIndex);
|
||||
}
|
||||
} else if (path.startsWith(TEST_PATH_PREFIX)) {
|
||||
int endIndex = path.indexOf(FORWARD_SLASH, TEST_PATH_SERVICE_NAME_START_INDEX);
|
||||
if (endIndex > TEST_PATH_SERVICE_NAME_START_INDEX) {
|
||||
return path.substring(TEST_PATH_SERVICE_NAME_START_INDEX, endIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class ConfigInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 配置ID
|
||||
*/
|
||||
private String configId;
|
||||
|
||||
/**
|
||||
* 配置名
|
||||
*/
|
||||
private String configName;
|
||||
|
||||
/**
|
||||
* 服务名
|
||||
*/
|
||||
private String serviceName;
|
||||
/**
|
||||
* 接口请求method类型
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 接口请求路径
|
||||
*/
|
||||
private String path;
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private Long version;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ConfigInfo that = (ConfigInfo) o;
|
||||
return Objects.equals(configId, that.configId) &&
|
||||
Objects.equals(configName, that.configName) &&
|
||||
Objects.equals(serviceName, that.serviceName) &&
|
||||
Objects.equals(method, that.method) &&
|
||||
Objects.equals(path, that.path) &&
|
||||
Objects.equals(version, that.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(configId, configName, serviceName, method, path, version);
|
||||
}
|
||||
|
||||
public String getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public void setConfigId(String configId) {
|
||||
this.configId = configId;
|
||||
}
|
||||
|
||||
public String getConfigName() {
|
||||
return configName;
|
||||
}
|
||||
|
||||
public void setConfigName(String configName) {
|
||||
this.configName = configName;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
public void setServiceName(String serviceName) {
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
351
src/main/java/com/wehotel/fizz/Pipeline.java
Normal file
351
src/main/java/com/wehotel/fizz/Pipeline.java
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import com.wehotel.fizz.input.ClientInputConfig;
|
||||
import com.wehotel.fizz.input.InputConfig;
|
||||
import com.wehotel.schema.util.I18nUtils;
|
||||
import com.wehotel.util.JsonSchemaUtils;
|
||||
|
||||
import org.noear.snack.ONode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.wehotel.flume.clients.log4j2appender.LogService;
|
||||
import com.wehotel.fizz.input.Input;
|
||||
import com.wehotel.fizz.input.PathMapping;
|
||||
import com.wehotel.fizz.input.ScriptHelper;
|
||||
import com.wehotel.util.MapUtil;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
* @author francis
|
||||
* @author zhongjie
|
||||
*
|
||||
*/
|
||||
public class Pipeline {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Pipeline.class);
|
||||
private LinkedList<Step> steps = new LinkedList<Step>();
|
||||
private StepContext<String, Object> stepContext= new StepContext<>();
|
||||
public void addStep(Step step) {
|
||||
steps.add(step);
|
||||
}
|
||||
|
||||
static void displayValue(String n) {
|
||||
System.out.println("input : " + n);
|
||||
}
|
||||
|
||||
public StepContext<String, Object> getStepContext(){
|
||||
return this.stepContext;
|
||||
}
|
||||
|
||||
public Mono<AggregateResult> run(Input input, Map<String, Object> clientInput, String traceId) {
|
||||
ClientInputConfig config = (ClientInputConfig)input.getConfig();
|
||||
this.initialStepContext(clientInput);
|
||||
this.stepContext.setDebug(config.isDebug());
|
||||
|
||||
if(traceId != null) {
|
||||
this.stepContext.setTraceId(traceId);
|
||||
}
|
||||
|
||||
long t1 = System.currentTimeMillis();
|
||||
List<String> validateErrorList = inputValidate(input, clientInput);
|
||||
this.stepContext.addElapsedTime("入参校验", System.currentTimeMillis()-t1);
|
||||
|
||||
if (!CollectionUtils.isEmpty(validateErrorList)) {
|
||||
long t2 = System.currentTimeMillis();
|
||||
String validateMsg = StringUtils.collectionToCommaDelimitedString(validateErrorList);
|
||||
// 将验证错误信息放入上下文
|
||||
stepContext.put("validateMsg", validateMsg);
|
||||
Map<String, Object> validateResponse = config.getValidateResponse();
|
||||
// 数据转换
|
||||
AggregateResult aggregateResult = this.doInputDataMapping(input, validateResponse);
|
||||
this.stepContext.addElapsedTime("入参校验结果转换", System.currentTimeMillis() - t2);
|
||||
return Mono.just(aggregateResult);
|
||||
}
|
||||
|
||||
LinkedList<Step> opSteps = (LinkedList<Step>) steps.clone();
|
||||
Step step1 = opSteps.removeFirst();
|
||||
step1.beforeRun(stepContext, null);
|
||||
Mono<List<StepResponse>> result = createStep(step1).expand(response -> {
|
||||
if (opSteps.isEmpty() || response.isStop()) {
|
||||
return Mono.empty();
|
||||
}
|
||||
Step step = opSteps.pop();
|
||||
step.beforeRun(stepContext, response);
|
||||
return createStep(step);
|
||||
}).flatMap(response -> Flux.just(response)).collectList();
|
||||
return result.flatMap(clientResponse -> {
|
||||
// 数据转换
|
||||
long t3 = System.currentTimeMillis();
|
||||
AggregateResult aggResult = this.doInputDataMapping(input, null);
|
||||
this.stepContext.addElapsedTime(input.getName()+"聚合接口响应结果数据转换", System.currentTimeMillis() - t3);
|
||||
if(this.stepContext.isDebug()) {
|
||||
LogService.setBizId(this.stepContext.getTraceId());
|
||||
String jsonString = JSON.toJSONString(aggResult);
|
||||
LOGGER.info("aggResult {}", jsonString);
|
||||
LOGGER.info("stepContext {}", JSON.toJSONString(stepContext));
|
||||
}
|
||||
return Mono.just(aggResult);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Mono<StepResponse> createStep(Step step) {
|
||||
long start = System.currentTimeMillis();
|
||||
List<Mono> monos = step.run();
|
||||
Mono<Map>[] monoArray = monos.stream().toArray(Mono[]::new);
|
||||
Mono<StepResponse>result = Flux.merge(monoArray).reduce(new HashMap(), (item1, item2)-> {
|
||||
Input input = (Input)item2.get("request");
|
||||
item1.put(input.getName() , item2.get("data"));
|
||||
return item1;
|
||||
}).flatMap(item -> {
|
||||
// stepResult 数据转换
|
||||
long t1 = System.currentTimeMillis();
|
||||
StepResponse stepResponse = this.doStepDataMapping(step);
|
||||
stepResponse.setStop(step.isStop());
|
||||
long t2 = System.currentTimeMillis();
|
||||
this.stepContext.addElapsedTime(step.getName() + "结果数据转换", t2 - t1);
|
||||
this.stepContext.addElapsedTime(step.getName() + "耗时", System.currentTimeMillis() - start);
|
||||
|
||||
return Mono.just(stepResponse);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化上下文
|
||||
* @param clientInput 客户端提交上来的信息
|
||||
*/
|
||||
public void initialStepContext(Map<String,Object> clientInput) {
|
||||
Map<String,Object> input = new HashMap<>();
|
||||
Map<String,Object> inputRequest = new HashMap<>();
|
||||
Map<String,Object> inputResponse = new HashMap<>();
|
||||
input.put("request", inputRequest);
|
||||
input.put("response", inputResponse);
|
||||
if(clientInput != null) {
|
||||
inputRequest.put("path", clientInput.get("path"));
|
||||
inputRequest.put("method", clientInput.get("method"));
|
||||
inputRequest.put("headers", clientInput.get("headers"));
|
||||
inputRequest.put("params", clientInput.get("params"));
|
||||
inputRequest.put("body", clientInput.get("body"));
|
||||
}
|
||||
stepContext.put("input", input);
|
||||
}
|
||||
|
||||
|
||||
private StepResponse doStepDataMapping(Step step) {
|
||||
StepResponse stepResponse = (StepResponse)stepContext.get(step.getName());
|
||||
if (step.getDataMapping() != null) {
|
||||
Map<String, Object> responseMapping = (Map<String, Object>) step.getDataMapping().get("response");
|
||||
if(responseMapping != null && !StringUtils.isEmpty(responseMapping)) {
|
||||
ONode ctxNode = PathMapping.toONode(stepContext);
|
||||
|
||||
// body
|
||||
stepResponse.setResult(PathMapping.transform(ctxNode, stepContext,
|
||||
(Map<String, Object>) responseMapping.get("fixedBody"),
|
||||
(Map<String, Object>) responseMapping.get("body")));
|
||||
|
||||
// script
|
||||
if(responseMapping.get("script") != null) {
|
||||
Map<String, Object> scriptCfg = (Map<String, Object>) responseMapping.get("script");
|
||||
try {
|
||||
Map<String, Object> stepBody = ScriptHelper.execute(scriptCfg, ctxNode, stepContext, Map.class);
|
||||
if(stepBody != null) {
|
||||
stepResponse.setResult(stepBody);
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stepResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当validateResponse不为空表示验参失败,使用该配置响应数据
|
||||
*/
|
||||
private AggregateResult doInputDataMapping(Input input, Map<String, Object> validateResponse) {
|
||||
AggregateResult aggResult = new AggregateResult();
|
||||
Map<String, Map<String,Object>> group = (Map<String, Map<String, Object>>) stepContext.get("input");
|
||||
if(group == null) {
|
||||
group = new HashMap<String, Map<String,Object>>();
|
||||
stepContext.put("input", group);
|
||||
}
|
||||
Map<String,Object> response = null;
|
||||
if(group.get("response") == null) {
|
||||
response = new HashMap<>();
|
||||
group.put("response", response);
|
||||
}
|
||||
response = group.get("response");
|
||||
if (input != null && input.getConfig() != null && input.getConfig().getDataMapping() != null) {
|
||||
Map<String, Object> responseMapping = (Map<String, Object>) input.getConfig().getDataMapping()
|
||||
.get("response");
|
||||
if (validateResponse != null) {
|
||||
responseMapping = validateResponse;
|
||||
}
|
||||
if (responseMapping != null && !StringUtils.isEmpty(responseMapping)) {
|
||||
ONode ctxNode = PathMapping.toONode(stepContext);
|
||||
|
||||
// headers
|
||||
response.put("headers",
|
||||
PathMapping.transform(ctxNode, stepContext,
|
||||
(Map<String, Object>) responseMapping.get("fixedHeaders"),
|
||||
(Map<String, Object>) responseMapping.get("headers")));
|
||||
|
||||
// body
|
||||
Map<String,Object> body = PathMapping.transform(ctxNode, stepContext,
|
||||
(Map<String, Object>) responseMapping.get("fixedBody"),
|
||||
(Map<String, Object>) responseMapping.get("body"));
|
||||
|
||||
// script
|
||||
if (responseMapping.get("script") != null) {
|
||||
Map<String, Object> scriptCfg = (Map<String, Object>) responseMapping.get("script");
|
||||
try {
|
||||
Object respBody = ScriptHelper.execute(scriptCfg, ctxNode, stepContext);
|
||||
if(respBody != null) {
|
||||
body.putAll((Map<String, Object>) respBody);
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
}
|
||||
}
|
||||
response.put("body", body);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> respBody = (Map<String, Object>) response.get("body");
|
||||
// 测试模式返回StepContext
|
||||
if(stepContext.returnContext()) {
|
||||
respBody.put("_context", stepContext);
|
||||
}
|
||||
|
||||
aggResult.setBody((Map<String, Object>) response.get("body"));
|
||||
aggResult.setHeaders(MapUtil.toMultiValueMap((Map<String, Object>) response.get("headers")));
|
||||
return aggResult;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<String> inputValidate(Input input, Map<String, Object> clientInput) {
|
||||
try {
|
||||
InputConfig config = input.getConfig();
|
||||
if (config instanceof ClientInputConfig) {
|
||||
Map<String, Object> langDef = ((ClientInputConfig) config).getLangDef();
|
||||
this.handleLangDef(langDef);
|
||||
|
||||
Map<String, Object> headersDef = ((ClientInputConfig) config).getHeadersDef();
|
||||
if (!CollectionUtils.isEmpty(headersDef)) {
|
||||
// 验证headers入参是否符合要求
|
||||
List<String> errorList = JsonSchemaUtils.validateAllowValueStr(JSON.toJSONString(headersDef), JSON.toJSONString(clientInput.get("headers")));
|
||||
if (!CollectionUtils.isEmpty(errorList)) {
|
||||
return errorList;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> paramsDef = ((ClientInputConfig) config).getParamsDef();
|
||||
if (!CollectionUtils.isEmpty(paramsDef)) {
|
||||
// 验证params入参是否符合要求
|
||||
List<String> errorList = JsonSchemaUtils.validateAllowValueStr(JSON.toJSONString(paramsDef), JSON.toJSONString(clientInput.get("params")));
|
||||
if (!CollectionUtils.isEmpty(errorList)) {
|
||||
return errorList;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> bodyDef = ((ClientInputConfig) config).getBodyDef();
|
||||
if (!CollectionUtils.isEmpty(bodyDef)) {
|
||||
// 验证body入参是否符合要求
|
||||
List<String> errorList = JsonSchemaUtils.validate(JSON.toJSONString(bodyDef), JSON.toJSONString(clientInput.get("body")));
|
||||
if (!CollectionUtils.isEmpty(errorList)) {
|
||||
return errorList;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> scriptValidate = ((ClientInputConfig) config).getScriptValidate();
|
||||
if (!CollectionUtils.isEmpty(scriptValidate)) {
|
||||
ONode ctxNode = PathMapping.toONode(stepContext);
|
||||
// 验证入参是否符合脚本要求
|
||||
try {
|
||||
List<String> errorList = (List<String>) ScriptHelper.execute(scriptValidate, ctxNode, stepContext, List.class);
|
||||
if (!CollectionUtils.isEmpty(errorList)) {
|
||||
return errorList;
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
I18nUtils.removeContextLocale();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleLangDef(Map<String, Object> langDef) {
|
||||
if (!CollectionUtils.isEmpty(langDef)) {
|
||||
// 存在提示语言定义配置
|
||||
Object langParamObj = langDef.get("langParam");
|
||||
String langParam = null;
|
||||
if (langParamObj instanceof String) {
|
||||
langParam = (String) langParamObj;
|
||||
}
|
||||
Object langMappingObj = langDef.get("langMapping");
|
||||
Map<String, Object> langMapping = null;
|
||||
if (langMappingObj instanceof Map) {
|
||||
langMapping = (Map<String, Object>) langMappingObj;
|
||||
}
|
||||
if (langParam != null && !CollectionUtils.isEmpty(langMapping)) {
|
||||
ONode ctxNode = PathMapping.toONode(stepContext);
|
||||
Map<String, Object> langParamMap = new HashMap<>(2);
|
||||
langParamMap.put("langParam", langParam);
|
||||
Map<String, Object> transformMap = PathMapping.transform(ctxNode, stepContext, null, langParamMap);
|
||||
Object langParamValue = transformMap.get("langParam");
|
||||
if (langParamValue != null) {
|
||||
// 判断使用哪种语言
|
||||
Object zh = langMapping.get("zh");
|
||||
if (zh != null && zh.toString().equals(langParamValue.toString())) {
|
||||
I18nUtils.setContextLocale(new Locale("zh"));
|
||||
}
|
||||
Object en = langMapping.get("en");
|
||||
if (en != null && en.toString().equals(langParamValue.toString())) {
|
||||
I18nUtils.setContextLocale(new Locale("en"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
148
src/main/java/com/wehotel/fizz/Step.java
Normal file
148
src/main/java/com/wehotel/fizz/Step.java
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.web.reactive.function.BodyInserter;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.wehotel.fizz.input.Input;
|
||||
import com.wehotel.fizz.input.InputConfig;
|
||||
import com.wehotel.fizz.input.InputContext;
|
||||
import com.wehotel.fizz.input.InputFactory;
|
||||
import com.wehotel.fizz.input.InputType;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
public class Step {
|
||||
|
||||
private String name;
|
||||
|
||||
// 是否在执行完当前step就返回
|
||||
private boolean stop;
|
||||
|
||||
private Map<String, Object> dataMapping;
|
||||
|
||||
private Map<String, InputConfig> requestConfigs = new HashMap<String, InputConfig>();
|
||||
|
||||
public static class Builder {
|
||||
public Step read(Map<String, Object> config) {
|
||||
Step step = new Step();
|
||||
List<Map> requests= (List<Map>) config.get("requests");
|
||||
for(Map requestConfig: requests) {
|
||||
InputConfig inputConfig = InputFactory.createInputConfig(requestConfig);
|
||||
step.addRequestConfig((String)requestConfig.get("name"), inputConfig);
|
||||
}
|
||||
return step;
|
||||
}
|
||||
}
|
||||
|
||||
private StepContext<String, Object> stepContext;
|
||||
private StepResponse lastStepResponse = null;
|
||||
private Map<String, Input> inputs = new HashMap<String, Input>();
|
||||
public void beforeRun(StepContext<String, Object> stepContext2, StepResponse response ) {
|
||||
stepContext = stepContext2;
|
||||
lastStepResponse = response;
|
||||
StepResponse stepResponse = new StepResponse(this, null, new HashMap<String, Map<String, Object>>());
|
||||
stepContext.put(name, stepResponse);
|
||||
Map<String, InputConfig> configs = this.getRequestConfigs();
|
||||
for(String configName :configs.keySet()) {
|
||||
InputConfig inputConfig = configs.get(configName);
|
||||
InputType type = inputConfig.getType();
|
||||
Input input = InputFactory.createInput(type.toString());
|
||||
input.setConfig(inputConfig);
|
||||
input.setName(configName);
|
||||
input.setStepResponse(stepResponse);
|
||||
InputContext context = new InputContext(stepContext, lastStepResponse);
|
||||
input.beforeRun(context);
|
||||
inputs.put(input.getName(), input);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Mono> run() {
|
||||
List<Mono> monos = new ArrayList<Mono>();
|
||||
for(String name :inputs.keySet()) {
|
||||
Input input = inputs.get(name);
|
||||
if (input.needRun(stepContext)) {
|
||||
Mono<Map> singleMono = input.run();
|
||||
monos.add(singleMono);
|
||||
}
|
||||
}
|
||||
return monos;
|
||||
}
|
||||
|
||||
public void afeterRun() {
|
||||
|
||||
}
|
||||
|
||||
public InputConfig addRequestConfig(String name, InputConfig requestConfig) {
|
||||
return requestConfigs.put(name, requestConfig);
|
||||
}
|
||||
|
||||
|
||||
public Map<String, InputConfig> getRequestConfigs() {
|
||||
return requestConfigs;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
return name = "step" + (int)(Math.random()*100);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isStop() {
|
||||
return stop;
|
||||
}
|
||||
|
||||
public void setStop(boolean stop) {
|
||||
this.stop = stop;
|
||||
}
|
||||
|
||||
public Map<String, Object> getDataMapping() {
|
||||
return dataMapping;
|
||||
}
|
||||
|
||||
public void setDataMapping(Map<String, Object> dataMapping) {
|
||||
this.dataMapping = dataMapping;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
549
src/main/java/com/wehotel/fizz/StepContext.java
Normal file
549
src/main/java/com/wehotel/fizz/StepContext.java
Normal file
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.wehotel.constants.CommonConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
* @author francis
|
||||
*
|
||||
* @param <K>
|
||||
* @param <V>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class StepContext<K, V> extends ConcurrentHashMap<K, V> {
|
||||
|
||||
public static final String ELAPSED_TIMES = "elapsedTimes";
|
||||
public static final String DEBUG = "debug";
|
||||
public static final String RETURN_CONTEXT = "returnContext";
|
||||
|
||||
public void setDebug(Boolean debug) {
|
||||
this.put((K)DEBUG, (V)debug);
|
||||
}
|
||||
|
||||
public String getTraceId() {
|
||||
return (String) this.get(CommonConstants.TRACE_ID);
|
||||
}
|
||||
|
||||
public void setTraceId(String traceId) {
|
||||
this.put((K)CommonConstants.TRACE_ID, (V)traceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否调试模式
|
||||
* @return
|
||||
*/
|
||||
public Boolean isDebug() {
|
||||
return this.get(DEBUG) == null ? false : (Boolean) this.get(DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在响应体里返回上下文
|
||||
* @return
|
||||
*/
|
||||
public boolean returnContext() {
|
||||
return Boolean.valueOf((String)getInputReqHeader(RETURN_CONTEXT));
|
||||
}
|
||||
|
||||
public synchronized void addElapsedTime(String actionName, Long milliSeconds) {
|
||||
List<Map<String, Long>> elapsedTimes = (List<Map<String, Long>>) this.get(ELAPSED_TIMES);
|
||||
if (elapsedTimes == null) {
|
||||
elapsedTimes = new ArrayList<Map<String, Long>>();
|
||||
this.put((K) ELAPSED_TIMES, (V) elapsedTimes);
|
||||
}
|
||||
Map<String, Long> record = new HashMap<>();
|
||||
record.put(actionName, milliSeconds);
|
||||
elapsedTimes.add(record);
|
||||
}
|
||||
|
||||
public V getElapsedTimes() {
|
||||
return this.get(ELAPSED_TIMES);
|
||||
}
|
||||
|
||||
private Map<String, Object> getStepRequest(String stepName, String requestName) {
|
||||
StepResponse stepResponse = (StepResponse) this.get(stepName);
|
||||
if (stepResponse == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Map<String, Object>> requests = (Map<String, Map<String, Object>>) stepResponse.getRequests();
|
||||
if (requests == null) {
|
||||
requests = new HashMap<>();
|
||||
stepResponse.setRequests(requests);
|
||||
requests.put(requestName, new HashMap<String, Object>());
|
||||
}
|
||||
return (Map<String, Object>) requests.get(requestName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Step里调用接口的请求头
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param headerName
|
||||
* @param headerValue
|
||||
*/
|
||||
public void setStepReqHeader(String stepName, String requestName, String headerName, Object headerValue) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> req = (Map<String, Object>) request.get("request");
|
||||
if (req == null) {
|
||||
req = new HashMap<>();
|
||||
request.put("request", req);
|
||||
}
|
||||
Map<String, Object> headers = (Map<String, Object>) req.get("headers");
|
||||
if (headers == null) {
|
||||
headers = new HashMap<>();
|
||||
req.put("headers", headers);
|
||||
}
|
||||
headers.put(headerName, headerValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Step里调用接口的请求头
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param headerName
|
||||
*/
|
||||
public Object getStepReqHeader(String stepName, String requestName, String headerName) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> req = (Map<String, Object>) request.get("request");
|
||||
if (req == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> headers = (Map<String, Object>) req.get("headers");
|
||||
if (headers == null) {
|
||||
return null;
|
||||
}
|
||||
return headers.get(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Step里调用接口的请求body
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public void setStepReqBody(String stepName, String requestName, String key, Object value) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> req = (Map<String, Object>) request.get("request");
|
||||
if (req == null) {
|
||||
req = new HashMap<>();
|
||||
request.put("request", req);
|
||||
}
|
||||
Map<String, Object> body = (Map<String, Object>) req.get("body");
|
||||
if (body == null) {
|
||||
body = new HashMap<>();
|
||||
req.put("body", body);
|
||||
}
|
||||
body.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Step里调用接口的请求body
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param key
|
||||
*/
|
||||
public Object getStepReqBody(String stepName, String requestName, String key) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> req = (Map<String, Object>) request.get("request");
|
||||
if (req == null) {
|
||||
req = new HashMap<>();
|
||||
request.put("request", req);
|
||||
}
|
||||
Map<String, Object> body = (Map<String, Object>) req.get("body");
|
||||
if (body == null) {
|
||||
return null;
|
||||
}
|
||||
return body.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Step里调用接口的请求body
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
*/
|
||||
public Object getStepReqBody(String stepName, String requestName) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> req = (Map<String, Object>) request.get("request");
|
||||
if (req == null) {
|
||||
req = new HashMap<>();
|
||||
request.put("request", req);
|
||||
}
|
||||
return req.get("body");
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Step里调用接口响应头
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param headerName
|
||||
* @param headerValue
|
||||
*/
|
||||
public void setStepRespHeader(String stepName, String requestName, String headerName, Object headerValue) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) request.get("response");
|
||||
if (response == null) {
|
||||
response = new HashMap<>();
|
||||
request.put("response", response);
|
||||
}
|
||||
Map<String, Object> headers = (Map<String, Object>) response.get("headers");
|
||||
if (headers == null) {
|
||||
headers = new HashMap<>();
|
||||
response.put("headers", headers);
|
||||
}
|
||||
headers.put(headerName, headerValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Step里调用接口响应头
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param headerName
|
||||
*/
|
||||
public Object getStepRespHeader(String stepName, String requestName, String headerName) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) request.get("response");
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> headers = (Map<String, Object>) response.get("headers");
|
||||
if (headers == null) {
|
||||
return null;
|
||||
}
|
||||
return headers.get(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Step里调用接口的响应body
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public void setStepRespBody(String stepName, String requestName, String key, Object value) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) request.get("response");
|
||||
if (response == null) {
|
||||
response = new HashMap<>();
|
||||
request.put("response", response);
|
||||
}
|
||||
Map<String, Object> body = (Map<String, Object>) response.get("body");
|
||||
if (body == null) {
|
||||
body = new HashMap<>();
|
||||
response.put("body", body);
|
||||
}
|
||||
body.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Step里调用接口的响应body
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
* @param key
|
||||
*/
|
||||
public Object getStepRespBody(String stepName, String requestName, String key) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) request.get("response");
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> body = (Map<String, Object>) response.get("body");
|
||||
if (body == null) {
|
||||
return null;
|
||||
}
|
||||
return body.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Step里调用接口的响应body
|
||||
*
|
||||
* @param stepName
|
||||
* @param requestName
|
||||
*/
|
||||
public Object getStepRespBody(String stepName, String requestName) {
|
||||
Map<String, Object> request = getStepRequest(stepName, requestName);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) request.get("response");
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
return response.get("body");
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Step的结果
|
||||
*
|
||||
* @param stepName
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public void setStepResult(String stepName, String key, Object value) {
|
||||
StepResponse stepResponse = (StepResponse) this.get(stepName);
|
||||
if (stepResponse == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> result = (Map<String, Object>) stepResponse.getResult();
|
||||
if (result == null) {
|
||||
result = new HashMap<>();
|
||||
stepResponse.setResult(result);
|
||||
}
|
||||
result.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Step的结果
|
||||
*
|
||||
* @param stepName
|
||||
* @param key
|
||||
*/
|
||||
public Object getStepResult(String stepName, String key) {
|
||||
StepResponse stepResponse = (StepResponse) this.get(stepName);
|
||||
if (stepResponse == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> result = (Map<String, Object>) stepResponse.getResult();
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
return result.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Step的结果
|
||||
*
|
||||
* @param stepName
|
||||
*/
|
||||
public Object getStepResult(String stepName) {
|
||||
StepResponse stepResponse = (StepResponse) this.get(stepName);
|
||||
if (stepResponse == null) {
|
||||
return null;
|
||||
}
|
||||
return stepResponse.getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置聚合接口的响应头
|
||||
*
|
||||
* @param headerName
|
||||
* @param headerValue
|
||||
*/
|
||||
public void setInputRespHeader(String headerName, Object headerValue) {
|
||||
Map<String, Object> input = (Map<String, Object>) this.get("input");
|
||||
if (input == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) input.get("response");
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> headers = (Map<String, Object>) response.get("headers");
|
||||
if (headers == null) {
|
||||
headers = new HashMap<>();
|
||||
response.put("headers", headers);
|
||||
}
|
||||
headers.put(headerName, headerValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聚合接口的响应头
|
||||
*
|
||||
* @param headerName
|
||||
*/
|
||||
public Object getInputRespHeader(String headerName) {
|
||||
Map<String, Object> input = (Map<String, Object>) this.get("input");
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) input.get("response");
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> headers = (Map<String, Object>) response.get("headers");
|
||||
if (headers == null) {
|
||||
return null;
|
||||
}
|
||||
return headers.get(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聚合接口的请求头
|
||||
*
|
||||
* @param headerName
|
||||
*/
|
||||
public Object getInputReqHeader(String headerName) {
|
||||
Map<String, Object> input = (Map<String, Object>) this.get("input");
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> request = (Map<String, Object>) input.get("request");
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> headers = (Map<String, Object>) request.get("headers");
|
||||
if (headers == null) {
|
||||
return null;
|
||||
}
|
||||
return headers.get(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置聚合接口的响应body
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public void setInputRespBody(String key, Object value) {
|
||||
Map<String, Object> input = (Map<String, Object>) this.get("input");
|
||||
if (input == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) input.get("response");
|
||||
if (response == null) {
|
||||
response = new HashMap<>();
|
||||
input.put("response", response);
|
||||
}
|
||||
Map<String, Object> body = (Map<String, Object>) response.get("body");
|
||||
if (body == null) {
|
||||
body = new HashMap<>();
|
||||
response.put("body", body);
|
||||
}
|
||||
body.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聚合接口的响应body
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public Object getInputRespBody(String key) {
|
||||
Map<String, Object> input = (Map<String, Object>) this.get("input");
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) input.get("response");
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> body = (Map<String, Object>) response.get("body");
|
||||
if (body == null) {
|
||||
return null;
|
||||
}
|
||||
return body.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聚合接口的响应body
|
||||
*
|
||||
*/
|
||||
public Object getInputRespBody() {
|
||||
Map<String, Object> input = (Map<String, Object>) this.get("input");
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> response = (Map<String, Object>) input.get("response");
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
return response.get("body");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聚合接口的请求body
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public Object getInputReqBody(String key) {
|
||||
Map<String, Object> body = (Map<String, Object>) getInputReqAttr("body");
|
||||
if (body == null) {
|
||||
return null;
|
||||
}
|
||||
return body.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聚合接口的请求body
|
||||
*
|
||||
*/
|
||||
public Object getInputReqBody() {
|
||||
return getInputReqAttr("body");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聚合接口请求属性<br/>
|
||||
* 可选属性:path,method,headers,params,body
|
||||
*
|
||||
*/
|
||||
public Object getInputReqAttr(String key) {
|
||||
Map<String, Object> input = (Map<String, Object>) this.get("input");
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> request = (Map<String, Object>) input.get("request");
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
return request.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
67
src/main/java/com/wehotel/fizz/StepResponse.java
Normal file
67
src/main/java/com/wehotel/fizz/StepResponse.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author linwaiwai
|
||||
*/
|
||||
public class StepResponse {
|
||||
private String stepName;
|
||||
private Map<String, Map<String, Object>> requests;
|
||||
private Map result;
|
||||
private boolean stop;
|
||||
|
||||
public StepResponse(Step aStep, HashMap item, Map<String, Map<String, Object>> requests) {
|
||||
setStepName(aStep.getName());
|
||||
setResult(item);
|
||||
setRequests(requests);
|
||||
}
|
||||
public StepResponse(Step aStep, HashMap item) {
|
||||
setStepName(aStep.getName());
|
||||
setResult(item);
|
||||
}
|
||||
|
||||
public boolean isStop() {
|
||||
return stop;
|
||||
}
|
||||
public void setStop(boolean stop) {
|
||||
this.stop = stop;
|
||||
}
|
||||
public String getStepName() {
|
||||
return stepName;
|
||||
}
|
||||
public void setStepName(String stepName) {
|
||||
this.stepName = stepName;
|
||||
}
|
||||
public Map<String, Map<String, Object>> getRequests() {
|
||||
return requests;
|
||||
}
|
||||
public void setRequests(Map<String, Map<String, Object>> requests) {
|
||||
this.requests = requests;
|
||||
}
|
||||
public Map getResult() {
|
||||
return result;
|
||||
}
|
||||
public void setResult(Map result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
}
|
||||
160
src/main/java/com/wehotel/fizz/input/ClientInputConfig.java
Normal file
160
src/main/java/com/wehotel/fizz/input/ClientInputConfig.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
public class ClientInputConfig extends InputConfig {
|
||||
|
||||
private boolean debug;
|
||||
private String path;
|
||||
private String method;
|
||||
private Map<String, Object> headers = new HashMap<String, Object>();
|
||||
private Map<String, Object> langDef;
|
||||
private Map<String, Object> bodyDef;
|
||||
private Map<String, Object> headersDef;
|
||||
private Map<String, Object> paramsDef;
|
||||
private Map<String, Object> scriptValidate;
|
||||
private Map<String, Object> validateResponse;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ClientInputConfig(Map configBody) {
|
||||
if(configBody.get("debug") != null) {
|
||||
this.debug = (boolean) configBody.get("debug");
|
||||
}
|
||||
this.path = (String) configBody.get("path");
|
||||
if (configBody.get("headers") != null) {
|
||||
setHeaders((Map) configBody.get("headers"));
|
||||
}
|
||||
if (configBody.get("method") != null) {
|
||||
setMethod((String) configBody.get("method"));
|
||||
} else {
|
||||
setMethod("GET");
|
||||
}
|
||||
|
||||
if (configBody.get("langDef") != null) {
|
||||
langDef = ((Map) configBody.get("langDef"));
|
||||
}
|
||||
if (configBody.get("bodyDef") != null) {
|
||||
bodyDef = ((Map) configBody.get("bodyDef"));
|
||||
}
|
||||
if (configBody.get("paramsDef") != null) {
|
||||
paramsDef = ((Map) configBody.get("paramsDef"));
|
||||
}
|
||||
if (configBody.get("headersDef") != null) {
|
||||
headersDef = ((Map) configBody.get("headersDef"));
|
||||
}
|
||||
if (configBody.get("scriptValidate") != null) {
|
||||
scriptValidate = ((Map) configBody.get("scriptValidate"));
|
||||
}
|
||||
if (configBody.get("validateResponse") != null) {
|
||||
validateResponse = ((Map) configBody.get("validateResponse"));
|
||||
}
|
||||
}
|
||||
|
||||
public ClientInputConfig() {
|
||||
|
||||
}
|
||||
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Map<String, Object> getLangDef() {
|
||||
return langDef;
|
||||
}
|
||||
|
||||
public void setLangDef(Map<String, Object> langDef) {
|
||||
this.langDef = langDef;
|
||||
}
|
||||
|
||||
public Map<String, Object> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, Object> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public Map<String, Object> getBodyDef() {
|
||||
return bodyDef;
|
||||
}
|
||||
|
||||
public void setBodyDef(Map<String, Object> bodyDef) {
|
||||
this.bodyDef = bodyDef;
|
||||
}
|
||||
|
||||
public Map<String, Object> getHeadersDef() {
|
||||
return headersDef;
|
||||
}
|
||||
|
||||
public void setHeadersDef(Map<String, Object> headersDef) {
|
||||
this.headersDef = headersDef;
|
||||
}
|
||||
|
||||
public Map<String, Object> getParamsDef() {
|
||||
return paramsDef;
|
||||
}
|
||||
|
||||
public void setParamsDef(Map<String, Object> paramsDef) {
|
||||
this.paramsDef = paramsDef;
|
||||
}
|
||||
|
||||
public Map<String, Object> getScriptValidate() {
|
||||
return scriptValidate;
|
||||
}
|
||||
|
||||
public void setScriptValidate(Map<String, Object> scriptValidate) {
|
||||
this.scriptValidate = scriptValidate;
|
||||
}
|
||||
|
||||
public Map<String, Object> getValidateResponse() {
|
||||
return validateResponse;
|
||||
}
|
||||
|
||||
public void setValidateResponse(Map<String, Object> validateResponse) {
|
||||
this.validateResponse = validateResponse;
|
||||
}
|
||||
}
|
||||
83
src/main/java/com/wehotel/fizz/input/Input.java
Normal file
83
src/main/java/com/wehotel/fizz/input/Input.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.wehotel.fizz.StepContext;
|
||||
import com.wehotel.fizz.StepResponse;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
*
|
||||
*/
|
||||
public class Input {
|
||||
protected String name;
|
||||
protected InputConfig config;
|
||||
protected InputContext inputContext;
|
||||
protected StepResponse lastStepResponse = null;
|
||||
protected StepResponse stepResponse;
|
||||
|
||||
public void setConfig(InputConfig inputConfig) {
|
||||
config = inputConfig;
|
||||
}
|
||||
public InputConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void beforeRun(InputContext context) {
|
||||
this.inputContext = context;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
return name = "input" + (int)(Math.random()*100);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查该Input是否需要运行,默认都运行
|
||||
* @stepContext Step上下文
|
||||
* @return TRUE:运行
|
||||
*/
|
||||
public boolean needRun(StepContext<String, Object> stepContext) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
public Mono<Map> run() {
|
||||
return null;
|
||||
}
|
||||
public void setName(String configName) {
|
||||
this.name = configName;
|
||||
|
||||
}
|
||||
|
||||
public StepResponse getStepResponse() {
|
||||
return stepResponse;
|
||||
}
|
||||
public void setStepResponse(StepResponse stepResponse) {
|
||||
this.stepResponse = stepResponse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
48
src/main/java/com/wehotel/fizz/input/InputConfig.java
Normal file
48
src/main/java/com/wehotel/fizz/input/InputConfig.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
*
|
||||
*/
|
||||
public class InputConfig {
|
||||
|
||||
private InputType type;
|
||||
protected Map<String, Object> dataMapping;
|
||||
|
||||
public InputType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(InputType typeEnum) {
|
||||
this.type = typeEnum;
|
||||
}
|
||||
|
||||
public Map<String, Object> getDataMapping() {
|
||||
return dataMapping;
|
||||
}
|
||||
|
||||
public void setDataMapping(Map<String, Object> dataMapping) {
|
||||
this.dataMapping = dataMapping;
|
||||
}
|
||||
|
||||
}
|
||||
68
src/main/java/com/wehotel/fizz/input/InputContext.java
Normal file
68
src/main/java/com/wehotel/fizz/input/InputContext.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.wehotel.fizz.StepContext;
|
||||
import com.wehotel.fizz.StepResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
*
|
||||
*/
|
||||
public class InputContext {
|
||||
private StepContext<String, Object> stepContext;
|
||||
private StepResponse lastStepResponse = null;
|
||||
public InputContext(StepContext<String, Object> stepContext2, StepResponse lastStepResponse2) {
|
||||
this.stepContext = stepContext2;
|
||||
this.lastStepResponse = lastStepResponse2;
|
||||
}
|
||||
public StepContext<String, Object> getStepContext() {
|
||||
return stepContext;
|
||||
}
|
||||
public void setStepContext(StepContext<String, Object> stepContext) {
|
||||
this.stepContext = stepContext;
|
||||
}
|
||||
public StepResponse getLastStepResponse() {
|
||||
return lastStepResponse;
|
||||
}
|
||||
public void setLastStepResponse(StepResponse lastStepResponse) {
|
||||
this.lastStepResponse = lastStepResponse;
|
||||
}
|
||||
// public Map<String, Object> getResponses() {
|
||||
// //TODO:
|
||||
// if (stepContext != null) {
|
||||
// Map<String, Object> responses = new HashMap<String, Object>();
|
||||
// for( String key :stepContext.keySet()) {
|
||||
// StepResponse stepResponse = (StepResponse)stepContext.get(key);
|
||||
// responses.put(key, stepResponse.getResponse());
|
||||
// }
|
||||
// return responses;
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
62
src/main/java/com/wehotel/fizz/input/InputFactory.java
Normal file
62
src/main/java/com/wehotel/fizz/input/InputFactory.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
*
|
||||
*/
|
||||
public class InputFactory {
|
||||
public static InputConfig createInputConfig(Map config) {
|
||||
String type = (String) config.get("type");
|
||||
InputType typeEnum = InputType.valueOf(type.toUpperCase());
|
||||
InputConfig inputConfig = null;
|
||||
switch(typeEnum) {
|
||||
case REQUEST:
|
||||
inputConfig = new RequestInputConfig(config);
|
||||
|
||||
break;
|
||||
case MYSQL:
|
||||
inputConfig = new MySQLInputConfig(config);
|
||||
break;
|
||||
}
|
||||
inputConfig.setType(typeEnum);
|
||||
inputConfig.setDataMapping((Map<String, Object>) config.get("dataMapping"));
|
||||
|
||||
return inputConfig;
|
||||
}
|
||||
|
||||
public static Input createInput(String type) {
|
||||
InputType typeEnum = InputType.valueOf(type.toUpperCase());
|
||||
Input input = null;
|
||||
switch(typeEnum) {
|
||||
case REQUEST:
|
||||
input = new RequestInput();
|
||||
break;
|
||||
case MYSQL:
|
||||
input = new MySQLInput();
|
||||
break;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
||||
32
src/main/java/com/wehotel/fizz/input/InputType.java
Normal file
32
src/main/java/com/wehotel/fizz/input/InputType.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
*
|
||||
*/
|
||||
public enum InputType {
|
||||
REQUEST("REQUEST"),
|
||||
MYSQL("MYSQL");
|
||||
private final String type;
|
||||
private InputType(String aType) {
|
||||
this.type = aType;
|
||||
}
|
||||
}
|
||||
27
src/main/java/com/wehotel/fizz/input/MySQLInput.java
Normal file
27
src/main/java/com/wehotel/fizz/input/MySQLInput.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
*
|
||||
*/
|
||||
public class MySQLInput extends Input {
|
||||
|
||||
}
|
||||
33
src/main/java/com/wehotel/fizz/input/MySQLInputConfig.java
Normal file
33
src/main/java/com/wehotel/fizz/input/MySQLInputConfig.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
*
|
||||
*/
|
||||
public class MySQLInputConfig extends InputConfig {
|
||||
|
||||
public MySQLInputConfig(Map configBody) {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
||||
315
src/main/java/com/wehotel/fizz/input/PathMapping.java
Normal file
315
src/main/java/com/wehotel/fizz/input/PathMapping.java
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.noear.snack.ONode;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.wehotel.constants.CommonConstants;
|
||||
import com.wehotel.fizz.StepContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
public class PathMapping {
|
||||
|
||||
public static ONode toONode(Object obj) {
|
||||
ONode o = null;
|
||||
synchronized (obj) {
|
||||
o = ONode.loadObj(obj);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public static void setByPath(ONode target, String path, Object obj) {
|
||||
if (CommonConstants.WILDCARD_STAR.equals(path)) {
|
||||
if (obj instanceof ONode) {
|
||||
ONode node = (ONode) obj;
|
||||
if(node.isObject()) {
|
||||
target.setAll(node);
|
||||
}
|
||||
} else if (obj instanceof Map) {
|
||||
target.setAll((Map) obj);
|
||||
}
|
||||
} else {
|
||||
String[] keys = path.split("\\.");
|
||||
ONode cur = target;
|
||||
for (int i = 0; i < keys.length - 1; i++) {
|
||||
cur = cur.get(keys[i]);
|
||||
}
|
||||
|
||||
if ((obj instanceof ONode && ((ONode) obj).isArray()) || obj instanceof Collection ||
|
||||
(obj instanceof ONode && ((ONode) obj).isObject()) || obj instanceof Map) {
|
||||
if (cur == null) {
|
||||
target.get(keys[keys.length - 1]).fill(obj);
|
||||
} else {
|
||||
cur.get(keys[keys.length - 1]).fill(obj);
|
||||
}
|
||||
} else {
|
||||
if (cur == null) {
|
||||
target.set(keys[keys.length - 1], obj);
|
||||
} else {
|
||||
cur.set(keys[keys.length - 1], obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, Object> transformToMap(ONode ctxNode, Map<String, Object> rules) {
|
||||
ONode target = transform(ctxNode, rules);
|
||||
return target.toObject(Map.class);
|
||||
}
|
||||
|
||||
public static ONode transform(ONode ctxNode, Map<String, Object> rules) {
|
||||
ONode target = ONode.load(new HashMap());
|
||||
if (rules.isEmpty()) {
|
||||
return target;
|
||||
}
|
||||
|
||||
Map<String, String> rs = new HashMap<>();
|
||||
Map<String, String> types = new HashMap<>();
|
||||
for (Entry<String, Object> entry : rules.entrySet()) {
|
||||
if (entry.getValue() instanceof String) {
|
||||
String val = (String) entry.getValue();
|
||||
String[] vals = val.split(" ");
|
||||
if (vals.length > 1) {
|
||||
rs.put(entry.getKey(), vals[1]);
|
||||
types.put(entry.getKey(), vals[0]);
|
||||
} else {
|
||||
rs.put(entry.getKey(), val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rs.isEmpty()) {
|
||||
return target;
|
||||
}
|
||||
|
||||
// wildcard star entry
|
||||
Object starValObj = null;
|
||||
String starEntryKey = null;
|
||||
|
||||
for (Entry<String, String> entry : rs.entrySet()) {
|
||||
ONode val = ctxNode.select("$." + handlePath(entry.getValue()));
|
||||
|
||||
Object obj = val;
|
||||
if (val != null && types.containsKey(entry.getKey())) {
|
||||
switch (types.get(entry.getKey())) {
|
||||
case "Integer":
|
||||
case "int": {
|
||||
obj = val.val().isNull() ? null : val.val().getInt();
|
||||
break;
|
||||
}
|
||||
case "Boolean":
|
||||
case "boolean": {
|
||||
obj = val.val().isNull() ? null : val.val().getBoolean();
|
||||
break;
|
||||
}
|
||||
case "Float":
|
||||
case "float": {
|
||||
obj = val.val().isNull() ? null : val.val().getFloat();
|
||||
break;
|
||||
}
|
||||
case "Double":
|
||||
case "double": {
|
||||
obj = val.val().isNull() ? null : val.val().getDouble();
|
||||
break;
|
||||
}
|
||||
case "String": {
|
||||
obj = val.val().isNull() ? null : val.val().getString();
|
||||
break;
|
||||
}
|
||||
case "Long":
|
||||
case "long": {
|
||||
obj = val.val().isNull() ? null : val.val().getLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CommonConstants.WILDCARD_STAR.equals(entry.getKey())) {
|
||||
starValObj = obj;
|
||||
starEntryKey = entry.getKey();
|
||||
}else {
|
||||
setByPath(target, entry.getKey(), obj);
|
||||
}
|
||||
}
|
||||
|
||||
if(starEntryKey != null) {
|
||||
setByPath(target, starEntryKey, starValObj);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public static Map<String, Object> getScriptRules(Map<String, Object> rules) {
|
||||
if (rules.isEmpty()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
Map<String, Object> rs = new HashMap<>();
|
||||
for (Entry<String, Object> entry : rules.entrySet()) {
|
||||
if (!(entry.getValue() instanceof String)) {
|
||||
rs.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把Path转为context里的实际路径<br/>
|
||||
* 步骤兼容以下几种写法,把后几种转换为第一种标准路径<br/>
|
||||
*
|
||||
* 例子1:<br/>
|
||||
* step1.requests.request1.request.headers<br/>
|
||||
* step1.request1.request.headers<br/>
|
||||
* step1.request1.requestHeaders<br/>
|
||||
* step1.requests.request1.requestHeaders<br/>
|
||||
*
|
||||
* 例子2:<br/>
|
||||
* step1.requests.request1.response.body<br/>
|
||||
* step1.request1.response.body<br/>
|
||||
* step1.request1.responseBody<br/>
|
||||
* step1.requests.request1.responseBody<br/>
|
||||
*
|
||||
* input兼容以下写法,把第二种转换为第一种标准路径<br/>
|
||||
*
|
||||
* 例子1:<br/>
|
||||
* input.request.headers<br/>
|
||||
* input.requestHeaders<br/>
|
||||
*
|
||||
* 例子2:<br/>
|
||||
* input.response.body<br/>
|
||||
* input.responseBody<br/>
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static String handlePath(String path) {
|
||||
if(path.startsWith("step")) {
|
||||
String[] arr = path.split("\\.");
|
||||
|
||||
List<String> list = Arrays.stream(arr).collect(Collectors.toList());
|
||||
// 补齐 requests
|
||||
if(list.size() >= 2 && !"requests".equals(list.get(1))) {
|
||||
list.add(1,"requests");
|
||||
}
|
||||
|
||||
// 拆分一级为两级,如:requestBody -> request.body
|
||||
if(list.size() >= 4) {
|
||||
String s = list.get(3);
|
||||
switch (s) {
|
||||
case "requestHeaders":
|
||||
list.set(3, "headers");
|
||||
list.add(3, "request");
|
||||
break;
|
||||
case "requestParams":
|
||||
list.set(3, "params");
|
||||
list.add(3, "request");
|
||||
break;
|
||||
case "requestBody":
|
||||
list.set(3, "body");
|
||||
list.add(3, "request");
|
||||
break;
|
||||
case "responseHeaders":
|
||||
list.set(3, "headers");
|
||||
list.add(3, "response");
|
||||
break;
|
||||
case "responseBody":
|
||||
list.set(3, "body");
|
||||
list.add(3, "response");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return String.join(".", list);
|
||||
}else if(path.startsWith("input")) {
|
||||
String[] arr = path.split("\\.");
|
||||
|
||||
List<String> list = Arrays.stream(arr).collect(Collectors.toList());
|
||||
|
||||
// 拆分一级为两级,如:requestBody -> request.body
|
||||
if(list.size() >= 2) {
|
||||
String s = list.get(1);
|
||||
switch (s) {
|
||||
case "requestHeaders":
|
||||
list.set(1, "headers");
|
||||
list.add(1, "request");
|
||||
break;
|
||||
case "requestParams":
|
||||
list.set(1, "params");
|
||||
list.add(1, "request");
|
||||
break;
|
||||
case "requestBody":
|
||||
list.set(1, "body");
|
||||
list.add(1, "request");
|
||||
break;
|
||||
case "responseHeaders":
|
||||
list.set(1, "headers");
|
||||
list.add(1, "response");
|
||||
break;
|
||||
case "responseBody":
|
||||
list.set(1, "body");
|
||||
list.add(1, "response");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return String.join(".", list);
|
||||
|
||||
}else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据转换
|
||||
*
|
||||
* @param ctxNode
|
||||
* @param stepContext
|
||||
* @param fixed optional
|
||||
* @param mappingRules optional
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Object> transform(ONode ctxNode, StepContext<String, Object> stepContext,
|
||||
Map<String, Object> fixed, Map<String, Object> mappingRules) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if (fixed != null) {
|
||||
result.putAll((Map<String, Object>) fixed);
|
||||
}
|
||||
if (mappingRules != null) {
|
||||
// 路径映射
|
||||
ONode target = PathMapping.transform(ctxNode, mappingRules);
|
||||
// 脚本转换
|
||||
Map<String, Object> scriptRules = PathMapping.getScriptRules(mappingRules);
|
||||
Map<String, Object> scriptResult = ScriptHelper.executeScripts(target, scriptRules, ctxNode, stepContext);
|
||||
if (scriptResult != null && !scriptResult.isEmpty()) {
|
||||
result.putAll(scriptResult);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
334
src/main/java/com/wehotel/fizz/input/RequestInput.java
Normal file
334
src/main/java/com/wehotel/fizz/input/RequestInput.java
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.noear.snack.ONode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.wehotel.flume.clients.log4j2appender.LogService;
|
||||
import com.wehotel.FizzGatewayApplication;
|
||||
import com.wehotel.constants.CommonConstants;
|
||||
import com.wehotel.fizz.StepContext;
|
||||
import com.wehotel.fizz.StepResponse;
|
||||
import com.wehotel.proxy.FizzWebClient;
|
||||
import com.wehotel.util.MapUtil;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class RequestInput extends Input {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RequestInput.class);
|
||||
private InputType type;
|
||||
protected Map<String, Object> dataMapping;
|
||||
protected Map<String, Object> request = new HashMap<>();
|
||||
protected Map<String, Object> response = new HashMap<>();
|
||||
|
||||
private static final String FALLBACK_MODE_STOP = "stop";
|
||||
private static final String FALLBACK_MODE_CONTINUE = "continue";
|
||||
|
||||
public InputType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(InputType typeEnum) {
|
||||
this.type = typeEnum;
|
||||
}
|
||||
|
||||
public Map<String, Object> getDataMapping() {
|
||||
return dataMapping;
|
||||
}
|
||||
|
||||
public void setDataMapping(Map<String, Object> dataMapping) {
|
||||
this.dataMapping = dataMapping;
|
||||
}
|
||||
|
||||
private void doRequestMapping(InputConfig aConfig, InputContext inputContext) {
|
||||
RequestInputConfig config = (RequestInputConfig) aConfig;
|
||||
|
||||
// 把请求信息放入stepContext
|
||||
Map<String, Object> group = new HashMap<>();
|
||||
group.put("request", request);
|
||||
group.put("response", response);
|
||||
this.stepResponse.getRequests().put(name, group);
|
||||
|
||||
HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase());
|
||||
request.put("method", method);
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.putAll(MapUtil.toHashMap(config.getQueryParams()));
|
||||
request.put("params", params);
|
||||
|
||||
// 数据转换
|
||||
if (inputContext != null && inputContext.getStepContext() != null) {
|
||||
StepContext<String, Object> stepContext = inputContext.getStepContext();
|
||||
Map<String, Object> dataMapping = this.getConfig().getDataMapping();
|
||||
if (dataMapping != null) {
|
||||
Map<String, Object> requestMapping = (Map<String, Object>) dataMapping.get("request");
|
||||
if (requestMapping != null && !StringUtils.isEmpty(requestMapping)) {
|
||||
ONode ctxNode = PathMapping.toONode(stepContext);
|
||||
|
||||
// headers
|
||||
request.put("headers",
|
||||
PathMapping.transform(ctxNode, stepContext,
|
||||
(Map<String, Object>) requestMapping.get("fixedHeaders"),
|
||||
(Map<String, Object>) requestMapping.get("headers")));
|
||||
|
||||
// params
|
||||
params.putAll(PathMapping.transform(ctxNode, stepContext,
|
||||
(Map<String, Object>) requestMapping.get("fixedParams"),
|
||||
(Map<String, Object>) requestMapping.get("params")));
|
||||
request.put("params", params);
|
||||
|
||||
// body
|
||||
Map<String,Object> body = PathMapping.transform(ctxNode, stepContext,
|
||||
(Map<String, Object>) requestMapping.get("fixedBody"),
|
||||
(Map<String, Object>) requestMapping.get("body"));
|
||||
|
||||
|
||||
// script
|
||||
if (requestMapping.get("script") != null) {
|
||||
Map<String, Object> scriptCfg = (Map<String, Object>) requestMapping.get("script");
|
||||
try {
|
||||
Object reqBody = ScriptHelper.execute(scriptCfg, ctxNode, stepContext);
|
||||
if (reqBody != null) {
|
||||
body.putAll((Map<String, Object>) reqBody);
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
}
|
||||
}
|
||||
request.put("body", body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(config.getBaseUrl() + config.getPath())
|
||||
.queryParams(MapUtil.toMultiValueMap(params)).build();
|
||||
request.put("url", uriComponents.toUriString());
|
||||
}
|
||||
|
||||
private void doResponseMapping(InputConfig aConfig, InputContext inputContext, String responseBody) {
|
||||
RequestInputConfig config = (RequestInputConfig) aConfig;
|
||||
response.put("body", JSON.parse(responseBody));
|
||||
// 数据转换
|
||||
if (inputContext != null && inputContext.getStepContext() != null) {
|
||||
StepContext<String, Object> stepContext = inputContext.getStepContext();
|
||||
Map<String, Object> dataMapping = this.getConfig().getDataMapping();
|
||||
if (dataMapping != null) {
|
||||
Map<String, Object> responseMapping = (Map<String, Object>) dataMapping.get("response");
|
||||
if (responseMapping != null && !StringUtils.isEmpty(responseMapping)) {
|
||||
ONode ctxNode = PathMapping.toONode(stepContext);
|
||||
|
||||
// headers
|
||||
Map<String, Object> fixedHeaders = (Map<String, Object>) responseMapping.get("fixedHeaders");
|
||||
Map<String, Object> headerMapping = (Map<String, Object>) responseMapping.get("headers");
|
||||
if ((fixedHeaders != null && !fixedHeaders.isEmpty())
|
||||
|| (headerMapping != null && !headerMapping.isEmpty())) {
|
||||
Map<String, Object> headers = new HashMap<>();
|
||||
headers.putAll(PathMapping.transform(ctxNode, stepContext, fixedHeaders, headerMapping));
|
||||
response.put("headers", headers);
|
||||
}
|
||||
|
||||
// body
|
||||
Map<String, Object> fixedBody = (Map<String, Object>) responseMapping.get("fixedBody");
|
||||
Map<String, Object> bodyMapping = (Map<String, Object>) responseMapping.get("body");
|
||||
Map<String, Object> scriptCfg = (Map<String, Object>) responseMapping.get("script");
|
||||
if ((fixedBody != null && !fixedBody.isEmpty()) || (bodyMapping != null && !bodyMapping.isEmpty())
|
||||
|| (scriptCfg != null && scriptCfg.get("type") != null
|
||||
&& scriptCfg.get("source") != null)) {
|
||||
// body
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.putAll(PathMapping.transform(ctxNode, stepContext, fixedBody, bodyMapping));
|
||||
|
||||
// script
|
||||
if (scriptCfg != null && scriptCfg.get("type") != null && scriptCfg.get("source") != null) {
|
||||
try {
|
||||
Object respBody = ScriptHelper.execute(scriptCfg, ctxNode, stepContext);
|
||||
if (respBody != null) {
|
||||
body.putAll((Map<String, Object>) respBody);
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
}
|
||||
}
|
||||
response.put("body", body);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
response.put("body", JSON.parse(responseBody));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<ClientResponse> getClientSpecFromContext(InputConfig aConfig, InputContext inputContext) {
|
||||
RequestInputConfig config = (RequestInputConfig) aConfig;
|
||||
|
||||
int timeout = config.getTimeout() < 1 ? 3000 : config.getTimeout() > 10000 ? 10000 : config.getTimeout();
|
||||
|
||||
HttpMethod method = HttpMethod.valueOf(config.getMethod());
|
||||
String url = (String) request.get("url");
|
||||
|
||||
Map<String, Object> headers = (Map<String, Object>) request.get("headers");
|
||||
if (headers == null) {
|
||||
headers = new HashMap<>();
|
||||
}
|
||||
if (!headers.containsKey("Content-Type")) {
|
||||
// defalut content-type
|
||||
headers.put("Content-Type", "application/json; charset=UTF-8");
|
||||
}
|
||||
headers.put(CommonConstants.HEADER_TRACE_ID, inputContext.getStepContext().getTraceId());
|
||||
|
||||
HttpMethod aggrMethod = HttpMethod.valueOf(inputContext.getStepContext().getInputReqAttr("method").toString());
|
||||
String aggrPath = (String)inputContext.getStepContext().getInputReqAttr("path");
|
||||
String aggrService = aggrPath.split("\\/")[2];
|
||||
|
||||
FizzWebClient client = FizzGatewayApplication.appContext.getBean(FizzWebClient.class);
|
||||
return client.aggrSend(aggrService, aggrMethod, aggrPath, null, method, url,
|
||||
MapUtil.toHttpHeaders(headers), request.get("body"), (long)timeout);
|
||||
}
|
||||
|
||||
private Map<String, Object> getResponses(Map<String, StepResponse> stepContext2) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean needRun(StepContext<String, Object> stepContext) {
|
||||
Map<String, Object> condition = ((RequestInputConfig) config).getCondition();
|
||||
if (CollectionUtils.isEmpty(condition)) {
|
||||
// 没有配置condition,直接运行
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
ONode ctxNode = PathMapping.toONode(stepContext);
|
||||
try {
|
||||
Boolean needRun = ScriptHelper.execute(condition, ctxNode, stepContext, Boolean.class);
|
||||
return needRun != null ? needRun : Boolean.TRUE;
|
||||
} catch (ScriptException e) {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.warn("execute script failed", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Map> run() {
|
||||
long t1 = System.currentTimeMillis();
|
||||
this.doRequestMapping(config, inputContext);
|
||||
inputContext.getStepContext().addElapsedTime(stepResponse.getStepName() + "-" + this.name + "-RequestMapping",
|
||||
System.currentTimeMillis() - t1);
|
||||
|
||||
String prefix = stepResponse.getStepName() + "-" + "调用接口";
|
||||
long start = System.currentTimeMillis();
|
||||
Mono<ClientResponse> clientResponse = this.getClientSpecFromContext(config, inputContext);
|
||||
Mono<String> body = clientResponse.flatMap(cr->{
|
||||
return Mono.just(cr).doOnError(throwable -> cleanup(cr));
|
||||
}).doOnSuccess(cr -> {
|
||||
long elapsedMillis = System.currentTimeMillis() - start;
|
||||
HttpHeaders httpHeaders = cr.headers().asHttpHeaders();
|
||||
Map<String, Object> headers = new HashMap<>();
|
||||
httpHeaders.forEach((key, value) -> {
|
||||
if (value.size() > 1) {
|
||||
headers.put(key, value);
|
||||
} else {
|
||||
headers.put(key, httpHeaders.getFirst(key));
|
||||
}
|
||||
});
|
||||
headers.put("elapsedTime", elapsedMillis + "ms");
|
||||
this.response.put("headers", headers);
|
||||
inputContext.getStepContext().addElapsedTime(prefix + request.get("url"),
|
||||
elapsedMillis);
|
||||
}).flatMap(cr -> cr.bodyToMono(String.class)).doOnSuccess(resp -> {
|
||||
long elapsedMillis = System.currentTimeMillis() - start;
|
||||
if(inputContext.getStepContext().isDebug()) {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.info("{} 耗时:{}ms URL={}, reqHeader={} req={} resp={}", prefix, elapsedMillis, request.get("url"),
|
||||
JSON.toJSONString(this.request.get("headers")),
|
||||
JSON.toJSONString(this.request.get("body")), resp);
|
||||
}
|
||||
}).doOnError(ex -> {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.warn("failed to call {}", request.get("url"), ex);
|
||||
long elapsedMillis = System.currentTimeMillis() - start;
|
||||
inputContext.getStepContext().addElapsedTime(
|
||||
stepResponse.getStepName() + "-" + "调用接口 failed " + request.get("url"), elapsedMillis);
|
||||
});
|
||||
|
||||
// fallback handler
|
||||
RequestInputConfig reqConfig = (RequestInputConfig) config;
|
||||
if (reqConfig.getFallback() != null) {
|
||||
Map<String, String> fallback = reqConfig.getFallback();
|
||||
String mode = fallback.get("mode");
|
||||
if (FALLBACK_MODE_STOP.equals(mode)) {
|
||||
body = body.onErrorStop();
|
||||
} else if (FALLBACK_MODE_CONTINUE.equals(mode)) {
|
||||
body = body.onErrorResume(ex -> {
|
||||
return Mono.just(fallback.get("defaultResult"));
|
||||
});
|
||||
} else {
|
||||
body = body.onErrorStop();
|
||||
}
|
||||
}
|
||||
|
||||
return body.flatMap(item -> {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("data", item);
|
||||
result.put("request", this);
|
||||
|
||||
long t3 = System.currentTimeMillis();
|
||||
this.doResponseMapping(config, inputContext, item);
|
||||
inputContext.getStepContext().addElapsedTime(
|
||||
stepResponse.getStepName() + "-" + this.name + "-ResponseMapping", System.currentTimeMillis() - t3);
|
||||
|
||||
return Mono.just(result);
|
||||
});
|
||||
}
|
||||
|
||||
private void cleanup(ClientResponse clientResponse) {
|
||||
if (clientResponse != null) {
|
||||
clientResponse.bodyToMono(Void.class).subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
129
src/main/java/com/wehotel/fizz/input/RequestInputConfig.java
Normal file
129
src/main/java/com/wehotel/fizz/input/RequestInputConfig.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author linwaiwai
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
public class RequestInputConfig extends InputConfig{
|
||||
private URL url ;
|
||||
private String method ;
|
||||
private int timeout = 3;
|
||||
private Map<String,String> fallback = new HashMap<String, String>();
|
||||
private Map<String, Object> condition;
|
||||
|
||||
public RequestInputConfig(Map configBody) {
|
||||
String url = (String) configBody.get("url");
|
||||
if(StringUtils.isEmpty(url)) {
|
||||
throw new RuntimeException("Request URL can not be blank");
|
||||
}
|
||||
setUrl(url);
|
||||
if (configBody.get("method") != null) {
|
||||
setMethod(((String)configBody.get("method")).toUpperCase());
|
||||
} else {
|
||||
setMethod("GET");
|
||||
}
|
||||
if (configBody.get("timeout") != null) {
|
||||
timeout = Integer.valueOf(configBody.get("timeout").toString());
|
||||
}
|
||||
if (configBody.get("fallback") != null) {
|
||||
fallback = (Map<String,String>)configBody.get("fallback");
|
||||
}
|
||||
if (configBody.get("condition") != null) {
|
||||
setCondition((Map)configBody.get("condition"));
|
||||
}
|
||||
}
|
||||
|
||||
public String getQueryStr(){
|
||||
return url.getQuery();
|
||||
}
|
||||
|
||||
public MultiValueMap<String, String> getQueryParams(){
|
||||
MultiValueMap<String, String> parameters =
|
||||
UriComponentsBuilder.fromUriString(url.toString()).build().getQueryParams();
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
||||
public String getBaseUrl() {
|
||||
return url.getProtocol()+ "://"+ url.getHost() + (url.getPort() == -1 ? "" : ":" + url.getPort());
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return url.getPath();
|
||||
}
|
||||
|
||||
public void setUrl(String string) {
|
||||
try {
|
||||
url = new URL(string);
|
||||
} catch (MalformedURLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public Map<String, String> getFallback() {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public void setFallback(Map<String, String> fallback) {
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
public Map<String, Object> getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void setCondition(Map<String, Object> condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
}
|
||||
151
src/main/java/com/wehotel/fizz/input/ScriptHelper.java
Normal file
151
src/main/java/com/wehotel/fizz/input/ScriptHelper.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.wehotel.fizz.input;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.noear.snack.ONode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ctrip.framework.apollo.core.utils.StringUtils;
|
||||
import com.wehotel.constants.CommonConstants;
|
||||
import com.wehotel.exception.StopAndResponseException;
|
||||
import com.wehotel.fizz.StepContext;
|
||||
import com.wehotel.util.Script;
|
||||
import com.wehotel.util.ScriptUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author francis
|
||||
*
|
||||
*/
|
||||
public class ScriptHelper {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ScriptHelper.class);
|
||||
|
||||
public static Object execute(Map<String, Object> scriptCfg, ONode ctxNode, StepContext<String, Object> stepContext)
|
||||
throws ScriptException {
|
||||
return execute(scriptCfg, ctxNode, stepContext, Object.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T execute(Map<String, Object> scriptCfg, ONode ctxNode, StepContext<String, Object> stepContext, Class<T> clazz)
|
||||
throws ScriptException {
|
||||
Script script = new Script();
|
||||
script.setType((String) scriptCfg.get("type"));
|
||||
script.setSource((String) scriptCfg.get("source"));
|
||||
if (StringUtils.isBlank(script.getType()) || StringUtils.isBlank(script.getSource())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, Object> ctx = new HashMap<>();
|
||||
ctx.put("context", stepContext);
|
||||
|
||||
Object rs = ScriptUtils.execute(script, ctx);
|
||||
if (ScriptUtils.GROOVY.equals(script.getType())) {
|
||||
return (T) handleStopResponse(stepContext, rs);
|
||||
} else if (ScriptUtils.JAVA_SCRIPT.equals(script.getType())) {
|
||||
if(rs != null) {
|
||||
if(rs instanceof Collection || rs instanceof Map) {
|
||||
return (T) rs;
|
||||
}else {
|
||||
String json = rs.toString();
|
||||
if(json.startsWith("[") && json.endsWith("]")) {
|
||||
return JSON.parseArray(json).toJavaObject(clazz);
|
||||
}else if(json.startsWith("{") && json.endsWith("}")) {
|
||||
if(clazz.isAssignableFrom(Map.class)) {
|
||||
return (T)handleStopResponse(stepContext, JSON.parseObject(json).toJavaObject(clazz));
|
||||
}else {
|
||||
handleStopResponse(stepContext, JSON.parseObject(json).toJavaObject(Map.class));
|
||||
return JSON.parseObject(json).toJavaObject(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (T) rs;
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return (T) rs;
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, Object> executeScripts(ONode target, Map<String, Object> scriptRules, ONode ctxNode,
|
||||
StepContext<String, Object> stepContext) {
|
||||
return executeScripts(target, scriptRules, ctxNode, stepContext, Object.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Map<String, T> executeScripts(ONode target, Map<String, Object> scriptRules, ONode ctxNode,
|
||||
StepContext<String, Object> stepContext, Class<T> clazz) {
|
||||
if(target == null) {
|
||||
target = ONode.load(new HashMap());
|
||||
}
|
||||
if (scriptRules != null && !scriptRules.isEmpty()) {
|
||||
// wildcard star entry
|
||||
Object starValObj = null;
|
||||
String starEntryKey = null;
|
||||
for (Entry<String, Object> entry : scriptRules.entrySet()) {
|
||||
Map<String, Object> scriptCfg = (Map<String, Object>) entry.getValue();
|
||||
try {
|
||||
if (CommonConstants.WILDCARD_STAR.equals(entry.getKey())) {
|
||||
starValObj = execute(scriptCfg, ctxNode, stepContext, clazz);
|
||||
starEntryKey = entry.getKey();
|
||||
}else {
|
||||
PathMapping.setByPath(target, entry.getKey(), execute(scriptCfg, ctxNode, stepContext, clazz));
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
}
|
||||
}
|
||||
if(starEntryKey != null) {
|
||||
PathMapping.setByPath(target, starEntryKey, starValObj);
|
||||
}
|
||||
}
|
||||
return target.toObject(Map.class);
|
||||
}
|
||||
|
||||
public static Object handleStopResponse(StepContext<String, Object> stepContext, Object result) {
|
||||
if(result instanceof Map) {
|
||||
Map<String, Object> rs = (Map<String, Object>) result;
|
||||
if (rs.containsKey(CommonConstants.STOP_AND_RESPONSE_KEY)) {
|
||||
if (rs.get(CommonConstants.STOP_AND_RESPONSE_KEY) != null
|
||||
&& rs.get(CommonConstants.STOP_AND_RESPONSE_KEY) instanceof Boolean
|
||||
&& (Boolean) rs.get(CommonConstants.STOP_AND_RESPONSE_KEY)) {
|
||||
rs.remove(CommonConstants.STOP_AND_RESPONSE_KEY);
|
||||
// 测试模式返回StepContext
|
||||
if (stepContext.returnContext()) {
|
||||
rs.put("_context", stepContext);
|
||||
}
|
||||
throw new StopAndResponseException("stop and response", JSON.toJSONString(rs));
|
||||
} else {
|
||||
rs.remove(CommonConstants.STOP_AND_RESPONSE_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user