package com.fr.design.versioncheck; import com.fr.base.FRContext; import com.fr.design.DesignerEnvManager; import com.fr.design.dialog.NotificationDialog; import com.fr.design.dialog.NotificationDialogAction; import com.fr.design.env.DesignerWorkspaceInfo; import com.fr.design.env.DesignerWorkspaceType; import com.fr.design.env.RemoteWorkspace; import com.fr.design.i18n.DesignSizeI18nManager; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.env.CheckServiceDialog; import com.fr.general.ComparatorUtils; import com.fr.general.GeneralUtils; import com.fr.invoke.Reflect; import com.fr.json.JSONArray; import com.fr.json.JSONObject; import com.fr.locale.InterProviderFactory; import com.fr.log.FineLoggerFactory; import com.fr.plugin.context.PluginContext; import com.fr.plugin.context.PluginMarker; import com.fr.plugin.manage.PluginManager; import com.fr.plugin.manage.control.PluginControllerHelper; import com.fr.plugin.manage.control.PluginExtraInfo; import com.fr.plugin.manage.control.PluginTaskCallback; import com.fr.plugin.manage.control.PluginTaskResult; import com.fr.plugin.manage.control.ProgressCallback; import com.fr.report.ReportHelper; import com.fr.rpc.ExceptionHandler; import com.fr.rpc.RPCInvokerExceptionInfo; import com.fr.rpc.Result; import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; 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 com.fr.workspace.server.check.VersionInfoOperator; import java.lang.reflect.Method; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.swing.SwingWorker; /** * @author pengda * @version 10.0 * Created on 2021-06-02 */ public class VersionCheckUtils { public static final String INCONSISTENCY = "inconsistency"; public static final String MISSING = "missing"; private static final String ID = "id"; private static final String VERSION = "version"; private static final String NAME = "name"; private static final String RUNNING = "running"; private static final String SYNC = "sync"; private static final String GROUP = "group"; private static final String BI = "bi"; private static final String BIPREFIX = "com.finebi"; private static final Set pluginsNeedIgnore = new HashSet<>(); static { pluginsNeedIgnore.addAll(Arrays.asList( "com.fr.plugin.performance.newexecutetool", "com.fr.plugin.performance.newline", "com.fr.plugin.performance.pdfstream", "com.fr.plugin.performance.dzstartemptyfile", "com.fr.plugin.performance.treenode.button.optimization", "com.fr.plugin.performance.druid", "com.fr.plugin.performance.reducecalculation", "com.fr.plugin.performance.fasttree", "com.fr.plugin.performance.paralleldsloader", "com.fr.plugin.cloud.analytics.v10" )); } public static boolean versionCheck(String envName) { return checkLocalAndRemoteJartime(envName) && checkLocalAndRemotePlugin().size() == 0; } public static boolean versionCheck(DesignerWorkspaceInfo selectedEnv) { return checkLocalAndRemoteJartime(selectedEnv) && checkLocalAndRemotePlugin().size() == 0; } public static void showVersionCheckDialog(String envName) { new SwingWorker() { @Override protected Boolean doInBackground() { return !VersionCheckUtils.versionCheck(envName); } @Override protected void done() { try { if (get()) { showNotificationDialog(envName); } } catch (Exception e) { FineLoggerFactory.getLogger().warn(e.getMessage(), e); } } }.execute(); } private static void showNotificationDialog(String envName) { NotificationDialog notificationDialog = new NotificationDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Sync_Prompt"), false, NotificationDialog.WARNING_MESSAGE, Toolkit.i18nText("Fine-Design_Basic_Sync_Check_Brief_Info"), new NotificationDialogAction() { @Override public String name() { return "VERSION_CHECK"; } @Override public void doClick() { CheckServiceDialog checkServiceDialog = new CheckServiceDialog(DesignerContext.getDesignerFrame(), GeneralUtils.readFullBuildNO(), getRemoteBranch(envName), getNoExistServiceDescription(envName)); checkServiceDialog.setVisible(true); } },DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.version.check.dialog")); notificationDialog.setVisible(true); } public static boolean checkLocalAndRemoteJartime(String envName) { DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName); return checkLocalAndRemoteJartime(selectedEnv); } public static boolean checkLocalAndRemoteJartime(DesignerWorkspaceInfo selectedEnv) { //是否需要做服务校验 if (needCheckBranch(selectedEnv)) { String localBranch; String remoteBranch = getRemoteBranch(selectedEnv); localBranch = GeneralUtils.readFullBuildNO(); //通过是否包含#来避免当前版本为非安装版本(主要是内部开发版本) if (localBranch.contains("#") && ComparatorUtils.equals(localBranch, remoteBranch)) { //说明版本一致,仅做日志记录 FineLoggerFactory.getLogger().info("Remote Designer version consistency"); return true; } else { return false; } } return true; } public static List getNoExistServiceDescription(String envName) { DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName); WorkspaceConnectionInfo connectionInfo = selectedEnv.getConnection(); List noExistServiceDescription = new ArrayList<>(); Set noExistServiceSet = getNoExistServiceSet(connectionInfo); 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()); noExistServiceDescription.add(descriptionOfCN); } return noExistServiceDescription; } public static String getRemoteBranch(String envName) { DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName); return getRemoteBranch(selectedEnv); } public static String getRemoteBranch(DesignerWorkspaceInfo selectedEnv) { String remoteBranch; remoteBranch = WorkContext.getCurrent().get(VersionInfoOperator.class, new ExceptionHandler() { @Override public String callHandler(RPCInvokerExceptionInfo exceptionInfo) { WorkspaceConnectionInfo connectionInfo = selectedEnv.getConnection(); String remoteBranch = StringUtils.EMPTY; try { remoteBranch = new FunctionalHttpRequest(connectionInfo).getServerBranch(); } catch (WorkspaceConnectionException e) { remoteBranch = Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Branch_Is_Old") + formatBranch(GeneralUtils.readFullBuildNO()); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } return remoteBranch; } }).getFullBuildNO(); return remoteBranch; } /** * 获取不存在的服务列表 * * @param info 环境连接信息 * @return 以Set形式返回不存在的服务 */ public static 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 buildNO 初始的分支版本号 * @return 格式化后的版本号 */ private static String formatBranch(String buildNO) { Date jarDate = (new SimpleDateFormat("yyyy.MM.dd")).parse(buildNO, new ParsePosition(buildNO.indexOf("-") + 1)); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); return df.format(jarDate); } private static boolean needCheckBranch(DesignerWorkspaceInfo selectedEnv) { return selectedEnv.getType() == DesignerWorkspaceType.Remote; } public static JSONArray checkLocalAndRemotePlugin() { JSONArray differentPlugins = new JSONArray(); JSONArray remotePlugins = FRContext.getCommonOperator().getPluginStatus(); Map localPluginsMap = new HashMap<>(); List localPlugins = PluginManager.getContexts(); for (PluginContext pluginContext : localPlugins) { localPluginsMap.put(pluginContext.getID(), pluginContext); } JSONObject remotePlugin; Map pluginsNameMap = ReportHelper.getPluginNameMap(); for (int i = 0; i < remotePlugins.size(); i++) { remotePlugin = remotePlugins.getJSONObject(i); if (isPluginNeedIgnore(remotePlugin)) { continue; } String remotePluginID = remotePlugin.getString(ID); if (localPluginsMap.containsKey(remotePluginID)) { if (ComparatorUtils.equals(localPluginsMap.get(remotePluginID).getVersion(), remotePlugin.getString(VERSION))) { continue; } else { if (remotePlugin.getString(NAME) == null) { remotePlugin.put(NAME, localPluginsMap.get(remotePluginID).getName()); } remotePlugin.put("type", INCONSISTENCY); } } else { remotePlugin.put("type", MISSING); if (remotePlugin.getString(NAME) == null) { remotePlugin.put(NAME, pluginsNameMap.getOrDefault(remotePluginID, remotePluginID)); } } differentPlugins.put(remotePlugin); } return differentPlugins; } private static boolean isPluginNeedIgnore(JSONObject remotePlugin) { return ComparatorUtils.equals(remotePlugin.getString(RUNNING), "false") || (remotePlugin.containsKey(SYNC) && !remotePlugin.getBoolean(SYNC)) || (remotePlugin.containsKey(GROUP) && ComparatorUtils.equals(remotePlugin.getString(GROUP), BI) || remotePlugin.getString(ID).startsWith(BIPREFIX) || pluginsNeedIgnore.contains(remotePlugin.getString(ID))); } public static JSONArray syncPlugins(JSONArray differentPlugins) { Set uninstallFailed = uninstallPlugins(differentPlugins); List plugins = getSyncPlugins(differentPlugins, uninstallFailed); installPlugins(plugins); return getPluginsSyncFailed(differentPlugins); } private static List getSyncPlugins(JSONArray differentPlugins, Set uninstallFailed) { JSONObject differentPlugin; String id; String version; List plugins = new ArrayList<>(); if (differentPlugins != null) { for (int i = 0; i < differentPlugins.size(); i++) { differentPlugin = differentPlugins.getJSONObject(i); id = differentPlugin.getString(ID); if (uninstallFailed.contains(id)) { continue; } version = differentPlugin.getString(VERSION); plugins.add(PluginMarker.create(id, version)); } } return plugins; } private static Set uninstallPlugins(JSONArray differentPlugins) { Set pluginsNeedUninstall = new HashSet<>(); Map localPluginsMap = new HashMap<>(); List localPlugins = PluginManager.getContexts(); for (PluginContext pluginContext : localPlugins) { localPluginsMap.put(pluginContext.getID(), pluginContext); } for (int i = 0; i < differentPlugins.size(); i++) { String id = differentPlugins.getJSONObject(i).getString(ID); if (localPluginsMap.containsKey(id)) { pluginsNeedUninstall.add(localPluginsMap.get(id).getMarker()); } } Set uninstallFailedID = new HashSet<>(); CountDownLatch latch = new CountDownLatch(pluginsNeedUninstall.size()); for (PluginMarker pluginMarker : pluginsNeedUninstall) { PluginManager.getController().uninstall(pluginMarker, true, new PluginTaskCallback() { @Override public void done(PluginTaskResult result) { latch.countDown(); if (!result.isSuccess()) { uninstallFailedID.add(pluginMarker.getPluginID()); } } }); } try { latch.await(5000, TimeUnit.MILLISECONDS); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } return uninstallFailedID; } private static JSONArray getPluginsSyncFailed(JSONArray differentPlugins) { JSONArray pluginsNeedSync = JSONArray.create(); List localPlugins = PluginManager.getContexts(); Map localPluginsInfo = new HashMap<>(); for (int i = 0; i < localPlugins.size(); i++) { localPluginsInfo.put(localPlugins.get(i).getID(), localPlugins.get(i).getVersion()); } for (int i = 0; i < differentPlugins.size(); i++) { JSONObject plugin = differentPlugins.getJSONObject(i); String id = plugin.getString(ID); if (localPluginsInfo.containsKey(id) && ComparatorUtils.equals(plugin.getString(VERSION), localPluginsInfo.get(id))) { continue; } pluginsNeedSync.add(plugin); } return pluginsNeedSync; } private static void installPlugins(List plugins) { CountDownLatch latch = new CountDownLatch(plugins.size()); for (int i = 0; i < plugins.size(); i++) { PluginControllerHelper.installOnline(plugins.get(i), new ProgressCallback() { @Override public void updateProgress(String description, double progress) { } @Override public void done(PluginTaskResult result) { latch.countDown(); if(result.isSuccess()) { FineLoggerFactory.getLogger().info("installPlugin: " + result.getCurrentTask().getMarker().getPluginID()); } } }, PluginExtraInfo.newBuilder().username(DesignerEnvManager.getEnvManager().getDesignerLoginUsername()).build()); } try { latch.await(); } catch (InterruptedException e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } } }