package foundation.icall;
|
|
import java.io.File;
|
import java.io.OutputStream;
|
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.Method;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.Logger;
|
|
import foundation.dao.DataPackage;
|
import foundation.dao.DataReader;
|
import foundation.dao.DataSource;
|
import foundation.dao.DataWriter;
|
import foundation.dao.IDataLetter;
|
import foundation.dao.PackageItem;
|
import foundation.data.entity.Entity;
|
import foundation.data.entity.EntitySet;
|
import foundation.data.object.DataObject;
|
import foundation.handler.DataPool;
|
import foundation.handler.ResultPool;
|
import foundation.icall.callin.BodyReader;
|
import foundation.icall.callout.RemoteSourceBucket;
|
import foundation.icall.connector.HttpServerConn;
|
import foundation.icall.log.LogRecord;
|
import foundation.io.object.DownloadAction;
|
import foundation.io.object.DownloadWriter;
|
import foundation.json.JObjectReader;
|
import foundation.json.JType;
|
import foundation.route.Operation;
|
import foundation.util.Util;
|
import foundation.workflow.Event;
|
import foundation.workflow.EventType;
|
import foundation.workflow.Moment;
|
import foundation.workflow.SingletonActionProvider;
|
import foundation.workflow.WorkStep;
|
import foundation.workflow.WorkStepMeta;
|
import foundation.workflow.WorkflowDispatcher;
|
import foundation.workflow.reference.ICallSender;
|
|
|
public class ICallCenter extends SingletonActionProvider {
|
|
protected static Logger logger;
|
private static ICallCenter instance;
|
private static ICallBucket icallBucket;
|
|
static {
|
logger = LogManager.getLogger(ICallCenter.class);
|
}
|
|
private ICallCenter() {
|
icallBucket = ICallBucket.getInstance();
|
}
|
|
public static synchronized ICallCenter getInstance() {
|
if (instance == null) {
|
instance = new ICallCenter();
|
}
|
|
return instance;
|
}
|
|
@Override
|
protected void publishMethod() {
|
//0. 系统单点登录
|
addMethod("systemLogin");
|
|
//1. 执行接口
|
addMethod("callRemote");
|
addMethod("callRemoteServerBatch");
|
|
//2. inBound
|
addMethod("callIn");
|
|
//3. 执行 Echo 接口
|
addMethod("echo");
|
|
//4. 获取接口描述
|
addMethod("getMeta");
|
|
//5. 获取接口日志分类树
|
addMethod("getLogCategory");
|
|
//6. 获取某个具体接口的日志列表
|
addMethod("getLogList");
|
|
//7. 获取某个具体请求的Request日志
|
addMethod("getRequestFile");
|
|
//8. 获取某个具体请求的Response日志
|
addMethod("getResponseFile");
|
|
//9. 重新加载接口参数
|
addMethod("reloadInterfaceSource");
|
}
|
|
public Entity systemLogin(DataPool dataPool, String serverName) throws Exception {
|
HttpServerConn conn = (HttpServerConn) RemoteSourceBucket.getInstance().getOne(serverName);
|
conn.login(new WorkStep(), null);
|
Entity entity = conn.systemLogin(dataPool);
|
|
return entity;
|
}
|
|
public void callRemoteServerBatch(WorkStep step, ICall iCall) throws Exception {
|
EntitySet masterSet = null;
|
String dataName = iCall.getDataName();
|
if (step.getDataReader() != null) {
|
dataName = step.getDataName();
|
DataPackage dataPackage = step.getDataPackage();
|
dataPackage.loadBatchDataFromDB();
|
|
PackageItem masterItem = dataPackage.getMaster();
|
masterSet = masterItem.getEntitySet(DataSource.DB);
|
}
|
else {
|
DataObject dataObject = DataObject.getInstance(dataName);
|
masterSet = dataObject.getBrowseEntitySet();
|
}
|
|
for (Entity master : masterSet) {
|
DataPackage onePackage = DataPackage.getInstance(dataName);
|
onePackage.setMasterId(master.getId());
|
onePackage.loadOneDataFromDB();
|
step.setDataPackage(onePackage);
|
|
callRemote(step, iCall);
|
}
|
}
|
|
public void callRemote(WorkStep step, ICall iCall) throws Exception {
|
ICallDirection direction = iCall.getType();
|
|
//1. fire before event
|
ICallSender sender = new ICallSender(iCall.getName(), null);
|
Event event = new Event(EventType.ICall, iCall.getDataName(), step.getInstanceId(), Moment.Before, direction.name(), sender);
|
WorkflowDispatcher.onFireEvent(step, event);
|
|
//2. call remote
|
event = new Event(EventType.ICall, iCall.getDataName(), step.getInstanceId(), Moment.After, direction.name(), sender);
|
|
if (!sender.isSend()) {
|
return ;
|
}
|
|
if (ICallDirection.RemoteServer == direction) {
|
callRemoteServer(step, iCall, event);
|
}
|
else if (ICallDirection.RemoteDB == direction) {
|
callRemoteDB(step, iCall, event);
|
}
|
|
//3. fire after event
|
WorkflowDispatcher.onFireEvent(step, event);
|
}
|
|
public void callIn(WorkStep step, ICall iCall) throws Exception {
|
DataWriter dataWriter = step.getDataWriter();
|
InboundResult result = new InboundResult(iCall);
|
|
//1. get data package
|
String dataName = iCall.getDataName();
|
DataPackage dataPackage = DataPackage.getInstance(dataName);
|
|
if (dataPackage == null) {
|
throw new Exception("call in bound error, invalid data name: " + dataName);
|
}
|
|
//2. get request data
|
DataReader requestReader = step.getDataReader();
|
|
if (!requestReader.has(IDataLetter.Data)) {
|
dataWriter.reportOneError("DataNotExists", "data not exists in request");
|
logger.error("absent data interface call, skip");
|
return;
|
}
|
|
JObjectReader dataReader = requestReader.getReader(IDataLetter.Data, JType.Object);
|
|
//3. 加载DataPackage
|
BodyReader bodyReader = new BodyReader(dataReader, dataPackage, iCall.getMappings());
|
int received = bodyReader.parse();
|
result.setReceived(received);
|
|
//4. 保存数据到数据库
|
if (!dataPackage.isEmpty()) {
|
int saved = dataPackage.saveOneDataToPersist();
|
result.setSaved(saved);
|
}
|
|
//5. result
|
dataWriter.addValue(result);
|
}
|
|
public void echo(WorkStep step, ICall iCall) throws Exception {
|
DataReader requestReader = step.getDataReader();
|
DataWriter dataWriter = step.getDataWriter();
|
ResultPool resultPool = dataWriter.getResultPool();
|
|
DataPool dataPool = requestReader.getDataPool();
|
String serverName = requestReader.getString("server");
|
HttpServerConn conn = (HttpServerConn) RemoteSourceBucket.getInstance().getOne(serverName);
|
JObjectReader dataReader = conn.formatReader(requestReader);
|
|
String eventType = dataReader.getString("EventType");
|
|
if ("check_url".equals(eventType) || "suite_ticket".equals(eventType)) {
|
resultPool = conn.echoSignature(resultPool, dataPool);
|
}
|
|
//1. try get data package
|
// String dataName = iCall.getDataName();
|
// DataPackage dataPackage = DataPackage.getInstance(dataName);
|
|
//2. try get request data
|
// JObjectReader dataReader = requestReader.getReader(IDataLetter.Data, JType.Object);
|
|
//3. 加载DataPackage
|
// BodyReader bodyReader = new BodyReader(dataReader, dataPackage, iCall.getMappings());
|
// int received = bodyReader.parse();
|
// result.setReceived(received);
|
|
//4. 保存数据到数据库
|
// result.setResponseBody(requestReader.getBody());
|
|
//5. result
|
String resultStr = resultPool.toJSONString();
|
HttpServletResponse response = resultPool.getResponse();
|
OutputStream outputStream = response.getOutputStream();
|
outputStream.write(resultStr.getBytes());
|
outputStream.close();
|
response.setCharacterEncoding("UTF-8");
|
}
|
|
public void getMeta(WorkStep step, ICall iCall) throws Exception {
|
DataWriter dataWriter = step.getDataWriter();
|
ICallMeta meta = iCall.getMeta();
|
dataWriter.addValue(meta);
|
}
|
|
public void getRequestFile(WorkStep step, ICall iCall) throws Exception {
|
DataWriter dataWriter = step.getDataWriter();
|
DataReader dataReader = step.getDataReader();
|
|
//1. 从请求中得到日志ID
|
String id = dataReader.getString("id");
|
|
if (Util.isEmpty(id)) {
|
logger.error("request has no id");
|
return;
|
}
|
|
//2. 获取数据文件
|
DataObject dataObject = DataObject.getInstance("sys_interface_log");
|
Entity entity = dataObject.getTableEntity(id);
|
|
if (entity == null) {
|
logger.error("log record not exists");
|
return;
|
}
|
|
String path = entity.getString("request_content");
|
File file = new File(path);
|
|
if (!file.exists()) {
|
logger.error("file not exists: {}", file);
|
return;
|
}
|
|
//3. 返回文件流
|
DownloadWriter downloadWriter = new DownloadWriter(dataWriter);
|
downloadWriter.write(file, "requestbody", DownloadAction.ASTexT);
|
}
|
|
public void getResponseFile(WorkStep step, String method) throws Exception {
|
DataWriter dataWriter = step.getDataWriter();
|
DataReader dataReader = step.getDataReader();
|
|
//1. 从请求中得到日志ID
|
String id = dataReader.getString("id");
|
|
if (Util.isEmpty(id)) {
|
logger.error("request has no id");
|
return;
|
}
|
|
//2. 获取数据文件
|
DataObject dataObject = DataObject.getInstance("sys_interface_log");
|
Entity entity = dataObject.getTableEntity(id);
|
|
if (entity == null) {
|
logger.error("log record not exists");
|
return;
|
}
|
|
String path = entity.getString("return_content");
|
File file = new File(path);
|
|
if (!file.exists()) {
|
logger.error("file not exists: {}", file);
|
return;
|
}
|
|
//3. 返回文件流
|
DownloadWriter downloadWriter = new DownloadWriter(dataWriter);
|
downloadWriter.write(file, "responsebody", DownloadAction.ASTexT);
|
}
|
|
public void reloadInterfaceSource(WorkStep step, ICall iCall) throws Exception {
|
RemoteSourceBucket sourceBucket = RemoteSourceBucket.clean();
|
|
ICallLoader.loadRemoteDataBases(sourceBucket);
|
ICallLoader.loadHttpServers(sourceBucket);
|
}
|
|
private void callRemoteServer(WorkStep step, ICall iCall, Event event) throws Exception {
|
OutboundResult result = new OutboundResult(iCall, event);
|
|
//1. get data package
|
DataPackage dataPackage = step.getDataPackage();
|
|
if (dataPackage != null) {
|
DataPackage host = dataPackage.getHost();
|
|
if (host != null) {
|
host.setMasterId(dataPackage.getHostID());
|
host.loadOneDataFromDB();
|
|
dataPackage = host;
|
}
|
}
|
|
//2. 调用 远端接口
|
HttpServerConn source = iCall.remoteSource();
|
|
source.login(step, iCall);
|
try {
|
iCall.sendRemoteServerCall(step, result);
|
}
|
catch (Exception e) {
|
e.printStackTrace();
|
}
|
finally {
|
source.logout(step, iCall);
|
}
|
}
|
|
private void callRemoteDB(WorkStep step, ICall iCall, Event event) throws Exception {
|
DataWriter dataWriter = step.getDataWriter();
|
OutboundResult result = new OutboundResult(iCall, event);
|
LogRecord record = new LogRecord(iCall);
|
result.setRecord(record);
|
|
//1. 运行远程SQL
|
iCall.sendRemoteDBCall(step, result);
|
|
//2. result
|
if (dataWriter != null) {
|
dataWriter.addValue(result);
|
}
|
}
|
|
@Override
|
public void exec(WorkStep step, String methodName) throws Exception {
|
String iCallName = step.getStepParam();
|
|
if (Util.isEmpty(iCallName)) {
|
DataReader dataReader = step.getDataReader();
|
iCallName = dataReader.getString("icall");
|
}
|
iCallName = iCallName.toLowerCase();
|
ICall iCall = icallBucket.getOne(iCallName);
|
|
Method method = getMethod(methodName);
|
try {
|
method.invoke(this, step, iCall);
|
}
|
catch (InvocationTargetException e) {
|
e.printStackTrace();
|
Throwable throwable = e.getTargetException();
|
|
if (throwable == null) {
|
throw e;
|
}
|
else {
|
throw (Exception) throwable;
|
}
|
}
|
catch (Exception e) {
|
e.printStackTrace();
|
throw e;
|
}
|
}
|
|
@Override
|
protected void invokeMethod(Method method, DataPool dataPool, ResultPool resultPool) throws Exception {
|
//1. 创建 reader 和 writer
|
Operation operation = dataPool.getOperation();
|
DataReader dataReader = new DataReader(operation, dataPool);
|
|
DataWriter dataWriter = new DataWriter(resultPool, dataReader.getDomain());
|
resultPool.setLetterWriter(dataWriter);
|
|
//2. 创建 ICall, 请求样例-inbound:root/interface/call/md_org_data
|
//2. 每次请求系统都会根据 meta 创建一个新的 iCall 和 remote source
|
String iCallName = dataReader.getString("icall");
|
ICall iCall = icallBucket.getOne(iCallName);
|
|
//3. 创建 work step
|
String dataName = dataReader.getDomain().getDataName();
|
WorkStepMeta meta = new WorkStepMeta(dataName, operation.getOperator());
|
WorkStep step = new WorkStep(dataReader, dataWriter, meta);
|
|
//4. 调用方法
|
try {
|
method.invoke(this, step, iCall);
|
}
|
catch (InvocationTargetException e) {
|
e.printStackTrace();
|
Throwable throwable = e.getTargetException();
|
|
if (throwable == null) {
|
throw e;
|
}
|
else {
|
throw (Exception) throwable;
|
}
|
}
|
}
|
|
@Override
|
protected boolean validateMethodParameter(Class<?>[] parameters) {
|
if (parameters == null || parameters.length != 2) {
|
return false;
|
}
|
|
Class<?> type = parameters[0];
|
if (!type.isAssignableFrom(WorkStep.class)) {
|
return false;
|
};
|
|
type = parameters[1];
|
if (!type.isAssignableFrom(ICall.class)) {
|
return false;
|
};
|
|
return true;
|
}
|
}
|