You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

150 lines
6.5 KiB

package com.fr.plugin.pack.http;
import com.finebi.activate.foundation.StableManager;
import com.finebi.base.concurrent.DefaultThreadFactory;
import com.finebi.common.api.vo.table.parameter.Parameters;
import com.finebi.dashboard.api.bean.widget.WidgetBean;
import com.finebi.dashboard.api.service.FineDashBoardService;
import com.finebi.dashboard.api.service.FineWidgetExecutorService;
import com.finebi.dashboard.api.structure.result.preview.BIPreViewResult;
import com.finebi.dashboard.impl.helper.FineDashBoardUtils;
import com.finebi.foundation.api.reponse.FineRespond;
import com.finebi.foundation.api.service.FineService;
import com.finebi.selector.api.DirectSourceEngineFactory;
import com.finebi.utils.CollectionUtils;
import com.finebi.utils.StringUtils;
import com.finebi.web.action.v5.BaseAction;
import com.fr.decision.authority.data.User;
import com.fr.decision.fun.impl.BaseHttpHandler;
import com.fr.general.IOUtils;
import com.fr.invoke.Reflect;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.pack.bean.WidgetsBean;
import com.fr.plugin.pack.conf.PackPluginConfig;
import com.fr.plugin.pack.exception.ReportExceedException;
import com.fr.plugin.pack.exception.WidgetExceedException;
import com.fr.plugin.pack.source.PackDBSourceEngine;
import com.fr.plugin.pack.traffic.PackTraffic;
import com.fr.plugin.pack.traffic.PackTrafficFactory;
import com.fr.third.fasterxml.jackson.databind.ObjectMapper;
import com.fr.third.springframework.web.bind.annotation.RequestMethod;
import com.fr.web.utils.WebUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
/**
* @author Jonas
* @version 5.1.3
* Created by Jonas on 2020-10-19
*/
public class PackHttpHandler extends BaseHttpHandler {
private PackTraffic reportTraffic = PackTrafficFactory.getReportTraffic();
public static String PATH = "/widgets/data";
private ExecutorService executorService = Executors.newCachedThreadPool(new DefaultThreadFactory("pack-widget-execute"));
{
DirectSourceEngineFactory.INSTANCE.register(new PackDBSourceEngine());
}
@Override
public RequestMethod getMethod() {
return RequestMethod.POST;
}
@Override
public String getPath() {
return PATH;
}
@Override
public boolean isPublic() {
return false;
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String reportId = null;
try {
String body = IOUtils.inputStream2String(request.getInputStream());
WidgetsBean widgetsBean = mapper.readValue(body, WidgetsBean.class);
Map<String, Object> result = new HashMap<>();
Set<String> reportIds = widgetsBean.getWidgets().values().stream().map(WidgetBean::getReportId).collect(Collectors.toSet());
if (CollectionUtils.isEmpty(reportIds)) {
throw new UnsupportedOperationException();
} else {
reportId = reportIds.iterator().next();
if (StringUtils.isEmpty(reportId)) {
throw new UnsupportedOperationException("reportId must be not emtpy");
}
}
if (!reportTraffic.offer(reportId)) {
throw new ReportExceedException();
}
try {
List<Future<?>> futures = new ArrayList<>();
for (Map.Entry<String, WidgetBean> entry : widgetsBean.getWidgets().entrySet()) {
WidgetBean widgetBean = entry.getValue();
User user = FineDashBoardUtils.getUserFromReq(request, widgetBean.getReportId());
boolean mobile = FineDashBoardUtils.isMobile(request);
Parameters parameterFromRequest = FineDashBoardUtils.getParameterFromRequest(request);
String widgetId = entry.getKey();
Future<?> future = executorService.submit(() -> {
try {
BIPreViewResult widgetData = Reflect.on(FineDashBoardUtils.class)
.call("getWidgetData", widgetBean, user, mobile, parameterFromRequest,
getBean(FineDashBoardService.class), getBean(FineWidgetExecutorService.class))
.get();
result.put(widgetId, FineRespond.success(widgetData));
} catch (Exception e) {
FineLoggerFactory.getLogger().debug(e.getMessage(), e);
result.put(widgetId, handleException(e));
}
});
futures.add(future);
}
for (Future<?> future : futures) {
try {
// 设置超时时间,不能一直在等着
future.get(PackPluginConfig.getInstance().getWidgetQueryTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
future.cancel(true);
}
}
WebUtils.printAsString(response, mapper.writeValueAsString(FineRespond.success(result)));
} finally {
reportTraffic.release(reportId);
}
} catch (Exception e) {
e.printStackTrace();
WebUtils.printAsString(response, mapper.writeValueAsString(FineRespond.fail("500", mapper.writeValueAsString(handleException(e)))));
}
}
private static FineRespond handleException(Exception e) {
if (e instanceof ReportExceedException) {
return FineRespond.fail(((ReportExceedException) e).errorCode(), e.getMessage());
}
if (e instanceof WidgetExceedException) {
return FineRespond.fail(((WidgetExceedException) e).errorCode(), e.getMessage());
}
return Reflect.on(BaseAction.class).call("getExceptionRespond", e).get();
}
private static <T extends FineService> T getBean(Class<T> annotatedClass) {
return StableManager.getContext().getServiceBean(annotatedClass);
}
}