|
|
|
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<String> 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<Boolean, Void>() {
|
|
|
|
@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<String> getNoExistServiceDescription(String envName) {
|
|
|
|
DesignerEnvManager envManager = DesignerEnvManager.getEnvManager();
|
|
|
|
DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName);
|
|
|
|
WorkspaceConnectionInfo connectionInfo = selectedEnv.getConnection();
|
|
|
|
List<String> noExistServiceDescription = new ArrayList<>();
|
|
|
|
Set<Class> 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<String>() {
|
|
|
|
@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<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 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<String, PluginContext> localPluginsMap = new HashMap<>();
|
|
|
|
List<PluginContext> localPlugins = PluginManager.getContexts();
|
|
|
|
for (PluginContext pluginContext : localPlugins) {
|
|
|
|
localPluginsMap.put(pluginContext.getID(), pluginContext);
|
|
|
|
}
|
|
|
|
JSONObject remotePlugin;
|
|
|
|
Map<String, String> 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<String> uninstallFailed = uninstallPlugins(differentPlugins);
|
|
|
|
List<PluginMarker> plugins = getSyncPlugins(differentPlugins, uninstallFailed);
|
|
|
|
installPlugins(plugins);
|
|
|
|
return getPluginsSyncFailed(differentPlugins);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static List<PluginMarker> getSyncPlugins(JSONArray differentPlugins, Set<String> uninstallFailed) {
|
|
|
|
JSONObject differentPlugin;
|
|
|
|
String id;
|
|
|
|
String version;
|
|
|
|
List<PluginMarker> 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<String> uninstallPlugins(JSONArray differentPlugins) {
|
|
|
|
Set<PluginMarker> pluginsNeedUninstall = new HashSet<>();
|
|
|
|
Map<String, PluginContext> localPluginsMap = new HashMap<>();
|
|
|
|
List<PluginContext> 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<String> 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<PluginContext> localPlugins = PluginManager.getContexts();
|
|
|
|
Map<String, String> 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<PluginMarker> 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|