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 result = new HashMap<>(); Set 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> futures = new ArrayList<>(); for (Map.Entry 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 getBean(Class annotatedClass) { return StableManager.getContext().getServiceBean(annotatedClass); } }