帆软报表设计器源代码。
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.
 
 
 
 

644 lines
24 KiB

package com.fr.design;
import com.fr.common.report.ReportState;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.env.DesignerWorkspaceGenerator;
import com.fr.design.env.DesignerWorkspaceInfo;
import com.fr.design.env.DesignerWorkspaceInfoContext;
import com.fr.design.env.DesignerWorkspaceType;
import com.fr.design.env.RemoteDesignerWorkspaceInfo;
import com.fr.design.env.RemoteWorkspace;
import com.fr.design.env.processor.RemoteDesignerWorkspaceInfoProcessor;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.file.TemplateTreePane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard;
import com.fr.design.notification.NotificationCenter;
import com.fr.design.plugin.remind.PluginErrorDesignReminder;
import com.fr.design.utils.DesignUtils;
import com.fr.design.versioncheck.VersionCheckUtils;
import com.fr.env.EnvListPane;
import com.fr.env.handler.WorkspaceExceptionHandler;
import com.fr.exit.DesignerExiter;
import com.fr.general.GeneralUtils;
import com.fr.invoke.Reflect;
import com.fr.json.JSONArray;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory;
import com.fr.performance.profile.PerformancePoint;
import com.fr.process.ProcessEventPipe;
import com.fr.process.engine.core.CarryMessageEvent;
import com.fr.process.engine.core.FineProcessContext;
import com.fr.rpc.Result;
import com.fr.stable.AssistUtils;
import com.fr.stable.StringUtils;
import com.fr.start.server.ServerTray;
import com.fr.workspace.WorkContext;
import com.fr.workspace.WorkContextCallback;
import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceSwitchProcess;
import com.fr.workspace.base.WorkspaceAPI;
import com.fr.workspace.connect.WorkspaceConnectionInfo;
import com.fr.workspace.engine.base.FineObjectPool;
import com.fr.workspace.engine.channel.http.FunctionalHttpRequest;
import com.fr.workspace.engine.exception.WorkspaceConnectionException;
import com.fr.workspace.engine.rpc.WorkspaceProxyPool;
import static javax.swing.JOptionPane.QUESTION_MESSAGE;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class EnvChangeEntrance {
private static final String BRANCH_TAG = "#";
private static final String BRANCH_BEGIN = "-";
private static final int BRANCH_SUB_LENGTH = 13;
public static EnvChangeEntrance getInstance() {
return HOLDER.singleton;
}
private static class HOLDER {
private static EnvChangeEntrance singleton = new EnvChangeEntrance();
}
private BasicDialog dialog;
private EnvChangeEntrance() {
}
private boolean envListOkAction(EnvListPane envListPane, PopTipStrategy strategy) {
final String selectedName = envListPane.updateEnvManager();
return switch2Env(selectedName, strategy);
}
/**
* 切换到指定名称的工作目录
*
* @param envName 目标工作目录名称
*/
public void switch2Env(final String envName) {
if (switch2Env(envName, PopTipStrategy.LATER)) {
VersionCheckUtils.showVersionCheckDialog(envName);
}
}
/**
* 插件进行用户名转换
*
* @param workspaceInfo 环境信息
*/
private DesignerWorkspaceInfo customUserName(DesignerWorkspaceInfo workspaceInfo) {
//本地环境直接返回
if (workspaceInfo == null || workspaceInfo.getType() == DesignerWorkspaceType.Local) {
return workspaceInfo;
}
RemoteDesignerWorkspaceInfoProcessor processor = ExtraDesignClassManager.getInstance().getSingle(RemoteDesignerWorkspaceInfoProcessor.XML_TAG);
if (processor == null) {
return workspaceInfo;
}
try {
WorkspaceConnectionInfo workspaceConnectionInfo = processor.customUserName(workspaceInfo.getConnection());
return (RemoteDesignerWorkspaceInfo) ((RemoteDesignerWorkspaceInfo) workspaceInfo).cloneWithConnectionInfo(workspaceConnectionInfo);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
return workspaceInfo;
}
}
/**
* 切换到新环境
*
* @param envName 新工作环境名称
* @param strategy 提示策略
* @return 是否成功
*/
private boolean switch2Env(final String envName, PopTipStrategy strategy) {
WorkspaceSwitchProcess lastProcess = WorkContext.getSwitcher().getProcess();
PerformancePoint performancePoint = PerformancePoint.create();
boolean switchStatus = doSwitch2Env(envName, strategy);
WorkspaceSwitchProcess currentProcess = WorkContext.getSwitcher().getProcess();
// 如果相同,代表根本没切换 ==
if (lastProcess != currentProcess) {
// 记录切换耗时
recordSwitchInfos(performancePoint, switchStatus);
// 触发切换埋点
triggerSwitchMetric();
}
return switchStatus;
}
/**
* 由云端运维,触发切换埋点
* 内部空实现
* 见 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=945327503">实现</a>
*/
private void triggerSwitchMetric() {
}
/**
* 切换到新环境
* 1. 先获取选中的环境
* 2. 生成工作目录
* 3. 验证工作目录
* 4. 触发切换操作
* 5. 触发可能存在异常的切换后动作
* 6. 触发切换后动作
*
* @param envName 新工作环境名称
* @return 是否成功
*/
private boolean doSwitch2Env(final String envName, PopTipStrategy strategy) {
DesignerWorkspaceInfo selectedEnv = getSelectedEnv(envName);
try {
Workspace workspace = DesignerWorkspaceGenerator.generate(selectedEnv);
if (notValid(workspace, selectedEnv)) {
return false;
}
doSwitchAction(envName, workspace);
afterSwitchWithEx();
} catch (Exception exception) {
// 失败的处理
WorkspaceExceptionHandler.getInstance().handleInSwitch(exception, selectedEnv);
return false;
}
afterSwitch();
return true;
}
private DesignerWorkspaceInfo getSelectedEnv(String envName) {
DesignerEnvManager envManager = DesignerEnvManager.getEnvManager();
DesignerWorkspaceInfo selectedEnv = customUserName(envManager.getWorkspaceInfo(envName));
DesignerWorkspaceInfoContext.setWorkspaceInfo(selectedEnv);
return selectedEnv;
}
private static boolean notValid(Workspace workspace, DesignerWorkspaceInfo selectedEnv) throws Exception {
boolean checkValid = workspace != null && selectedEnv.checkValid();
return !checkValid;
}
private void doSwitchAction(String envName, Workspace workspace) {
//如果是相同环境
if (isSameEnv(workspace)) {
//目前切换到相同环境需要更新一下名字,后续如果有别的操作直接往里面加就行了
switch2SameEnv(envName);
} else {
//切换到新环境,做下封装
switch2OtherEnv(workspace, envName);
}
}
private static void afterSwitchWithEx() {
// REPORT-25688如果是war包部署的服务器,给与提示
if (WorkContext.getCurrent().isWarDeploy()) {
FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_War_Deploy_Tip"),
Toolkit.i18nText("Fine-Design_Basic_Message"), JOptionPane.INFORMATION_MESSAGE);
}
//REPORT-13810如果只是添加了工作目录,没有切换,这里ToolArea也是要显示新建的工作目录
JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (JTemplate.isValid(template)) {
template.refreshToolArea();
}
PluginErrorDesignReminder.getInstance().remindStartFailedPlugins();
}
private static void afterSwitch() {
TemplateTreePane.getInstance().refreshDockingView();
DesignModelAdapter<?, ?> model = DesignModelAdapter.getCurrentModelAdapter();
if (model != null) {
model.envChanged();
}
NotificationCenter.getInstance().clearAllNotifications();
//切换环境后,清空粘贴板里面的内容
TemplateTreeClipboard.getInstance().reset();
}
private static void recordSwitchInfos(PerformancePoint performancePoint, boolean switchSuccess) {
performancePoint.end(elapsed -> {
WorkspaceSwitchProcess process = WorkContext.getSwitcher().getProcess();
Optional.ofNullable(process)
.ifPresent((e) -> {
e.recordSwitchElapsed(elapsed);
e.setSwitchSuccess(switchSuccess);
});
});
}
/**
* 切换到其他环境
*
* @param workspace 要切换的环境
* @param envName 要切换的环境名称
*/
private void switch2OtherEnv(Workspace workspace, String envName) {
WorkContext.switchTo(workspace, new WorkContextCallback() {
@Override
public void done() {
DesignerEnvManager.getEnvManager().setCurEnvName(envName);
DesignUtils.refreshDesignerFrame();
DesignTableDataManager.fireDSChanged(new HashMap<String, String>());
if (WorkContext.getCurrent().isLocal()) {
//初始化一下serverTray
ServerTray.init();
}
}
});
}
/**
* 切换到相同环境要做的事情
*
* @param envName 当前的环境名
*/
private void switch2SameEnv(String envName) {
//当前环境名称可能重命名更改过,需要更新一下,防止启动失败
DesignerEnvManager.getEnvManager().setCurEnvName(envName);
}
/**
* 是否切换到相同环境
*
* @param workspace 要切换的环境
* @return 是则返回true
*/
private boolean isSameEnv(Workspace workspace) {
return AssistUtils.equals(WorkContext.getCurrent(), workspace);
}
/**
* 这个功能留着,可能会加回来,先做注释处理
* 切换远程环境之前,进行版本检测,当版本不一致的时候,提示。
* 当用户确认选择 ok 时,才继续。
*
* @param selectedEnv 选择的环境
* @return 是否一致
* 1. 非远程环境 , 返回 true
* 2. 远程环境
* 2.1 不匹配,
* 2.1.1 当选择 ok , 返回 true
* 2.1.2 当选择 no, 返回 false
* 2.2 匹配, 返回 true
* @throws Exception 异常
*/
private boolean versionCheckAndConfirm(DesignerWorkspaceInfo selectedEnv) throws Exception {
if (selectedEnv.getType() == DesignerWorkspaceType.Remote) {
WorkspaceConnectionInfo info = selectedEnv.getConnection();
String serverVersion = new FunctionalHttpRequest(info).getServerVersion();
if (AssistUtils.equals(serverVersion, WorkContext.getVersion())) {
return true;
}
final List<Integer> result = new ArrayList<>(1);
PopTipStrategy.NOW.showTip(new PopTip() {
@Override
public void show() {
String[] option = {Toolkit.i18nText("Fine-Design_Report_Yes"), Toolkit.i18nText("Fine-Design_Report_No")};
int choice = JOptionPane.showOptionDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Version_Inconsistency"),
UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.YES_NO_OPTION, QUESTION_MESSAGE, UIManager.getIcon("OptionPane.warningIcon"), option, 1);
result.add(choice);
}
});
// 只有选择 yes , 这里的值才为 0, 返回 true
// 否着返回 false, 将不进行下面的连接操作。
return result.size() != 0 && result.get(0) == 0;
}
return true;
}
/**
* 对选择的环境做服务检测
*
* @param selectedEnv 选择的工作环境
*/
public void showServiceDialog(DesignerWorkspaceInfo selectedEnv) throws Exception {
//是否需要做服务校验
if (needCheckBranch(selectedEnv)) {
String localBranch;
String remoteBranch;
WorkspaceConnectionInfo connectionInfo = selectedEnv.getConnection();
localBranch = GeneralUtils.readFullBuildNO();
try {
remoteBranch = new FunctionalHttpRequest(connectionInfo).getServerBranch();
} catch (WorkspaceConnectionException e) {
remoteBranch = Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Branch_Is_Old") + formatBranch(localBranch);
}
//通过是否包含#来避免当前版本为非安装版本(主要是内部开发版本)
if (localBranch.contains("#") && localBranch.equals(remoteBranch)) {
//说明版本一致,仅做日志记录
FineLoggerFactory.getLogger().info("Remote Designer version consistency");
} else {
localBranch = GeneralUtils.getVersion();
remoteBranch = formatBranch(remoteBranch);
Set<Class> noExistServiceSet = getNoExistServiceSet(connectionInfo);
StringBuilder textBuilder = new StringBuilder();
for (Class clazz : noExistServiceSet) {
WorkspaceAPI workspaceAPI = (WorkspaceAPI) clazz.getAnnotation(WorkspaceAPI.class);
if (workspaceAPI == null) {
FineLoggerFactory.getLogger().info("workspace service {} get annotation failed", clazz);
continue;
}
if (workspaceAPI.ignore()) {
continue;
}
String descriptionOfCN = InterProviderFactory.getProvider().getLocText(workspaceAPI.description());
textBuilder.append(descriptionOfCN).append("\n");
}
String areaText = textBuilder.toString();
if (StringUtils.isEmpty(areaText)) {
return;
}
}
}
}
/**
* 判断是否需要做版本验证,判断依据为
* 1、选择的环境为远程环境
* 2、一个月内不弹出是否勾选
*
* @param selectedEnv 选择的环境
* @return
*/
private boolean needCheckBranch(DesignerWorkspaceInfo selectedEnv) {
if (selectedEnv.getType() == DesignerWorkspaceType.Remote) {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar = Calendar.getInstance();
if (StringUtils.isEmpty(selectedEnv.getRemindTime())) {
return true;
}
//获取记录的时间
Date remindTime = format.parse(selectedEnv.getRemindTime());
calendar.setTime(remindTime);
//获取一个月后的时间
calendar.add(Calendar.MONTH, 1);
//与当前时间作对比,然后判断是否提示
if (new Date().after(calendar.getTime())) {
return true;
}
} catch (ParseException e) {
return true;
}
}
return false;
}
/**
* 获取不存在的服务列表
*
* @param info 环境连接信息
* @return 以Set形式返回不存在的服务
*/
public Set<Class> getNoExistServiceSet(WorkspaceConnectionInfo info) {
Set<Class> noExistServiceSet = new HashSet<Class>();
Set<Class> remoteServiceSet = new HashSet<Class>();
Set<Class> localServiceSet = FineObjectPool.getInstance().getServerPool().keySet();
try {
JSONArray serviceArray = new FunctionalHttpRequest(info).getServiceList(info);
for (int i = 0; i < serviceArray.size(); i++) {
try {
Class clazz = Class.forName((String) serviceArray.get(i));
remoteServiceSet.add(clazz);
} catch (Exception e) {
continue;
}
}
noExistServiceSet.addAll(localServiceSet);
noExistServiceSet.removeAll(remoteServiceSet);
return noExistServiceSet;
} catch (WorkspaceConnectionException e) {
FineLoggerFactory.getLogger().info(e.getMessage());
//根据本地的服务列表做逐一检测
for (Class clazz : localServiceSet) {
Method testMethod = Reflect.on(Method.class).create(clazz, "connectTest", new Class[0], String.class, new Class[0], 1025, 8, null, null, null, null).get();
WorkspaceProxyPool proxyPool = (WorkspaceProxyPool) (((RemoteWorkspace) WorkContext.getCurrent()).getClient()).getPool();
Result result = proxyPool.testInvoker(testMethod);
Exception invokeException = (Exception) result.getException();
if (invokeException != null) {
Exception cause = (Exception) invokeException.getCause();
//获取被包装最底层的异常
while (cause != null) {
invokeException = cause;
cause = (Exception) invokeException.getCause();
}
//该异常表示服务不存在
if (invokeException instanceof ClassNotFoundException) {
noExistServiceSet.add(clazz);
}
}
}
return noExistServiceSet;
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
return noExistServiceSet;
}
}
/**
* 格式化分支版本号
*
* @param branch 初始的分支版本号
* @return 格式化后的版本号
*/
private String formatBranch(String branch) {
if (branch.contains(BRANCH_TAG)) {
return branch.substring(branch.lastIndexOf(BRANCH_BEGIN) + 1, branch.length() - BRANCH_SUB_LENGTH);
}
return branch;
}
/**
* 编辑items
*
* @see EnvChangeEntrance#chooseEnv()
* @deprecated use {@link EnvChangeEntrance#chooseEnv()}
*/
@Deprecated
public void editItems() {
chooseEnv();
}
/**
* 出现对话框,选择使用的工作环境
*/
public void chooseEnv() {
chooseEnv(DesignerEnvManager.getEnvManager().getCurEnvName());
}
public void chooseEnv(final String envName) {
final EnvListPane envListPane = new EnvListPane();
final BasicDialog envListDialog = envListPane.showWindow(DesignerContext.getDesignerFrame());
dialog = envListDialog;
envListPane.populateEnvManager(envName);
envListDialog.addDialogActionListener(new DialogActionAdapter() {
@Override
public void doOk() {
SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(envListPane));
if (!saveSomeTemplatePane.showSavePane(true)) {
// 用户取消保存时,取消切换目录操作
return;
}
boolean changeResult = envListOkAction(envListPane, PopTipStrategy.LATER);
// 切换完成后清理密码
updateNotRememberPwdEnv();
if (changeResult) {
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName());
}
}
@Override
public void doCancel() {
envListDialog.dispose();
dialog = null;
// todo 断开了但是没选择新的环境,那么尝试重连旧环境,等接口
}
});
envListDialog.setVisible(true);
}
/**
* 处理异常
*/
public void dealEvnExceptionWhenStartDesigner(Throwable e, DesignerWorkspaceInfo workspaceInfo) {
ProcessEventPipe eventPipe = FineProcessContext.getParentPipe();
if (eventPipe != null) {
eventPipe.fire(new CarryMessageEvent(ReportState.STOP.getValue()));
}
final EnvListPane envListPane = new EnvListPane();
envListPane.populateEnvManager(DesignerEnvManager.getEnvManager().getCurEnvName());
BasicDialog envListDialog = envListPane.showWindow(SwingUtilities.getWindowAncestor(DesignerContext.getDesignerFrame()));
dialog = envListDialog;
envListDialog.addDialogActionListener(new DialogActionAdapter() {
@Override
public void doOk() {
FineProcessContext.getParentPipe().fire(new CarryMessageEvent(ReportState.ACTIVE.getValue()));
if (!envListOkAction(envListPane, PopTipStrategy.NOW)) {
DesignerExiter.getInstance().execute();
} else {
updateNotRememberPwdEnv();
if (DesignerContext.getDesignerFrame().isVisible()) {
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName());
}
}
}
@Override
public void doCancel() {
dialog = null;
DesignerExiter.getInstance().execute();
}
});
if (e != null) {
WorkspaceExceptionHandler.getInstance().handleInStart(e, workspaceInfo);
}
envListDialog.setVisible(true);
}
/**
* 切换环境后 刷新远程目录需要忘记密码的情况
*/
private void updateNotRememberPwdEnv() {
DesignerEnvManager mgr = DesignerEnvManager.getEnvManager();
Iterator<String> iterator = mgr.getEnvNameIterator();
while (iterator.hasNext()) {
String envName = iterator.next();
DesignerWorkspaceInfo info = mgr.getWorkspaceInfo(envName);
if (isNotRememberPwd(info)) {
WorkspaceConnectionInfo connection = info.getConnection();
DesignerWorkspaceInfo workspaceInfo = RemoteDesignerWorkspaceInfo.create(new WorkspaceConnectionInfo(
connection.getUrl(), connection.getUserName(), StringUtils.EMPTY, connection.getCertPath(), connection.getCertSecretKey(), false));
mgr.putEnv(envName, workspaceInfo);
}
}
}
private boolean isNotRememberPwd(DesignerWorkspaceInfo info) {
if (info != null && info.getType() == DesignerWorkspaceType.Remote) {
WorkspaceConnectionInfo connection = info.getConnection();
return connection != null && !connection.isRememberPwd();
}
return false;
}
public BasicDialog getDialog() {
return dialog;
}
/**
* 提示显示策略
*/
public enum PopTipStrategy {
/**
* 切换失败,就马上提示失败,不关闭选择列表对话框
*/
NOW {
@Override
void showTip(PopTip tip) {
tip.show();
}
},
/**
* 切换失败,自动关闭选择列表对话框,然后提示切换失败
*/
LATER {
@Override
void showTip(final PopTip tip) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
tip.show();
}
});
}
};
abstract void showTip(PopTip tip);
}
interface PopTip {
void show();
}
}