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; } /** * 由云端运维,触发切换埋点 * 内部空实现 * 见 实现 */ 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()); 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 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 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 getNoExistServiceSet(WorkspaceConnectionInfo info) { Set noExistServiceSet = new HashSet(); Set remoteServiceSet = new HashSet(); Set 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 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(); } }