Browse Source

Pull request #9095: feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件)

Merge in DESIGN/design from ~HARRISON/design:feature/x to feature/x

* commit '3276b22b864b20afdb1db8225540ae108f9f60db':
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 遗留问题处理
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 1-修改退出时的逻辑展示 2-添加 fatalError 的检测 3-工具栏效果 4-优化一下 MessageWithLink 的使用方式 5-补充超链接
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 调整一下环境检测相关的内容 1-国际化效果\通过 html 封装 text 实现替换逻辑 2-补充注释 3-添加 EnvPrepare 注入到环境中,用来帮助环境启动时的一些相关钩子的启动
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 1-梳理需要进行检测的逻辑 2-添加单元测试
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 1-优化 UI 部分的代码质量 2-抽象部分公共类
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 1-补充设定,针对某一项的某一个异常进行检测 2-所有的日志,在检测后,统一输出,避免遗忘 3-优化一下代码质量 4-补充 UI 部分 - 异常展示 5-补充 UI 部分 - 检测 model
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) UI面板+部分资源 1-提供部分 Utils, 帮助调试 UI 2-抽象 notification 3-抽象 table 4-完成 envDetect -> notification 的联系
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 修改核心逻辑。 遇到不明确的异常, 则将异常添加进来后,进行匹配检测 遇到明确的异常,通过 DetectorType 进行匹配处理 统一检测时,直接调用
  feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件) 基本完成所有的业务逻辑。准备处理 UI 逻辑
feature/x
Harrison 2 years ago
parent
commit
c83ccfe2b3
  1. 24
      designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java
  2. 20
      designer-base/src/main/java/com/fr/design/DesignerEnvManager.java
  3. 21
      designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java
  4. 348
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java
  5. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java
  6. 88
      designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java
  7. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java
  8. 16
      designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java
  9. 78
      designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java
  10. 150
      designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java
  11. 184
      designer-base/src/main/java/com/fr/design/components/table/TablePanel.java
  12. 24
      designer-base/src/main/java/com/fr/design/constants/DesignerColor.java
  13. 80
      designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java
  14. 5
      designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
  15. 29
      designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java
  16. 30
      designer-base/src/main/java/com/fr/design/utils/ColorUtils.java
  17. 12
      designer-base/src/main/java/com/fr/design/utils/DevDebugUtils.java
  18. 60
      designer-base/src/main/java/com/fr/design/utils/DevUtils.java
  19. 55
      designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java
  20. 182
      designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java
  21. 26
      designer-base/src/main/java/com/fr/env/detect/EnvPrepare.java
  22. 8
      designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java
  23. 19
      designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java
  24. 87
      designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java
  25. 11
      designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java
  26. 21
      designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java
  27. 127
      designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java
  28. 59
      designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java
  29. 2
      designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java
  30. 21
      designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetectorConfig.java
  31. 71
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java
  32. 13
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java
  33. 91
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java
  34. 30
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java
  35. 12
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java
  36. 5
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java
  37. 15
      designer-base/src/main/java/com/fr/env/detect/bean/Message.java
  38. 26
      designer-base/src/main/java/com/fr/env/detect/exception/DetectorException.java
  39. 10
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java
  40. 16
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java
  41. 15
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java
  42. 15
      designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java
  43. 132
      designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java
  44. 131
      designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java
  45. 191
      designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java
  46. 53
      designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassThrowableConvertor.java
  47. 85
      designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbDirtyConverter.java
  48. 32
      designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java
  49. 26
      designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java
  50. 17
      designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java
  51. 135
      designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java
  52. 28
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java
  53. 494
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java
  54. 40
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java
  55. 70
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java
  56. 61
      designer-base/src/main/java/com/fr/exit/DesignerExiter.java
  57. 3
      designer-base/src/main/java/com/fr/start/BaseDesigner.java
  58. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg
  59. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg
  60. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg
  61. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg
  62. BIN
      designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif
  63. BIN
      designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif
  64. 4
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg
  65. 3
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg
  66. 5
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg
  67. 3
      designer-base/src/main/resources/com/fr/env/detect/detect.svg
  68. 3
      designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg
  69. 43
      designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java
  70. 23
      designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java
  71. 33
      designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java
  72. 37
      designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java
  73. 22
      designer-realize/src/main/java/com/fr/start/Designer.java
  74. 70
      designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java

24
designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java

@ -0,0 +1,24 @@
package com.fr.base.function;
import com.fr.log.FineLoggerFactory;
/**
* 可抛出异常的 Runnable
*
* created by Harrison on 2022/05/24
**/
public interface ThrowableRunnable<T extends Exception> {
void run() throws T;
static <T extends Exception> Runnable toRunnable(ThrowableRunnable<T> runnable) {
return () -> {
try {
runnable.run();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
};
}
}

20
designer-base/src/main/java/com/fr/design/DesignerEnvManager.java

@ -29,6 +29,7 @@ import com.fr.design.style.color.ColorSelectConfigManager;
import com.fr.design.update.push.DesignerPushUpdateConfigManager;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.DesignerPort;
import com.fr.env.detect.base.EnvDetectorConfig;
import com.fr.exit.DesignerExiter;
import com.fr.file.FILEFactory;
import com.fr.general.ComparatorUtils;
@ -168,6 +169,12 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private boolean embedServerLazyStartup = false;
//最近使用的颜色
private ColorSelectConfigManager configManager = new ColorSelectConfigManager();
/**
* 环境检测配置
*/
private EnvDetectorConfig envDetectorConfig = EnvDetectorConfig.getInstance();
/**
* alphafine
*/
@ -1820,6 +1827,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
readActiveStatus(reader);
} else if (ComparatorUtils.equals(CAS_PARAS, name)) {
readHttpsParas(reader);
} else if (name.equals(EnvDetectorConfig.XML_TAG)) {
readEnvDetectorConfig(reader);
} else if (name.equals("AlphaFineConfigManager")) {
readAlphaFineAttr(reader);
} else if (name.equals("RecentColors")) {
@ -1856,6 +1865,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private void readAlphaFineAttr(XMLableReader reader) {
reader.readXMLObject(this.alphaFineConfigManager = AlphaFineConfigManager.getInstance());
}
private void readEnvDetectorConfig(XMLableReader reader) {
reader.readXMLObject(this.envDetectorConfig);
}
private void readHttpsParas(XMLableReader reader) {
String tempVal;
@ -2070,6 +2083,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writeActiveStatus(writer);
writeHttpsParas(writer);
writeAlphaFineAttr(writer);
writeEnvDetectorConfig(writer);
writeRecentColor(writer);
writeOpenDebug(writer);
writeDesignerPushUpdateAttr(writer);
@ -2113,6 +2127,12 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writer.end();
}
}
private void writeEnvDetectorConfig(XMLPrintWriter writer) {
if (this.envDetectorConfig != null) {
this.envDetectorConfig.writeXML(writer);
}
}
//写入uuid
private void writeUUID(XMLPrintWriter writer) {

21
designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java

@ -0,0 +1,21 @@
package com.fr.design.components.notification;
/**
* created by Harrison on 2022/05/24
**/
public interface NotificationAction {
/**
* 行为名
*
* @return 名称
*/
String name();
/**
* 行为动作
*
* @param args 参数
*/
void run(Object... args);
}

348
designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java

@ -0,0 +1,348 @@
package com.fr.design.components.notification;
import com.fr.base.function.ThrowableRunnable;
import com.fr.base.svg.IconUtils;
import com.fr.design.components.page.PageControlModel;
import com.fr.design.components.page.PageControlPanel;
import com.fr.design.dialog.link.MessageWithLink;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.utils.LinkStrUtils;
import com.fr.env.detect.base.EnvDetectorConfig;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* 右下角的提醒 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=388333688">异常提醒</a>
*
* created by Harrison on 2022/05/24
**/
public class NotificationDialog extends JDialog {
private Dimension contentSize = new Dimension(300, 100);
private Dimension buttonDimension = new Dimension(68, 20);
private NotificationDialogProperties properties;
/* 数据 model */
private List<NotificationModel> notificationModels;
private PageControlModel pageControlModel;
private JPanel body;
private JPanel headerPanel;
private JPanel contentPanel;
private JPanel tailPanel;
public NotificationDialog(NotificationDialogProperties properties, List<NotificationModel> notificationModels) {
super(properties.getOwner());
setTitle(properties.getTitle());
this.properties = properties;
this.notificationModels = notificationModels;
this.pageControlModel = new PageControlModel(0, this.notificationModels.size());
initComponents();
}
public void initComponents() {
//UI 配置
configProperties();
this.body = FRGUIPaneFactory.createBorderLayout_L_Pane();
body.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
//首行
layoutHeaderPanel();
//消息内容
layoutContentPanel();
//查看详情
layoutTailPanel();
add(body);
Dimension dimension = body.getPreferredSize();
setSize(dimension.width, dimension.height);
Container parent = getParent();
setLocation((parent.getWidth() - dimension.width - 30 + parent.getX()),
parent.getY() + parent.getHeight() - dimension.height - 30);
}
public void open() {
setVisible(true);
}
private void configProperties() {
setModal(properties.isModal());
setFocusable(false);
setAutoRequestFocus(false);
setResizable(false);
}
protected JPanel createHeaderPanel() {
return null;
}
/**
* 内容
*
* @return 内容面板
*/
protected JPanel createContentPanel() {
JPanel contentPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
contentPanel.setBorder(BorderFactory.createEmptyBorder(8, 10, 8, 10));
contentPanel.setName("contentPanel");
NotificationModel model = getCurrentModel();
UILabel icon = new UILabel(getIconForType(model.getType()));
icon.setPreferredSize(new Dimension(16, 16));
JPanel iconPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 10, 8));
iconPanel.add(icon, BorderLayout.NORTH);
contentPanel.add(iconPanel, BorderLayout.WEST);
JPanel centerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 20));
NotificationMessage[] messages = model.getMessages();
List<? extends JComponent> messageComponents = Arrays.stream(messages)
.map((messageModel) -> {
if (messageModel.getType() == NotificationMessage.Type.LINK) {
NotificationMessage.LinkMessage linkMessage = (NotificationMessage.LinkMessage) messageModel;
return new MessageWithLink(linkMessage.format(), ThrowableRunnable.toRunnable(() -> {
Desktop.getDesktop().browse(URI.create(linkMessage.getLink()));
}));
}
return new UILabel(LinkStrUtils.generateHtmlTag(messageModel.format()));
})
.peek((component) -> {
Dimension preferredSize = component.getPreferredSize();
double componentWidth = preferredSize.getWidth();
double componentHeight = preferredSize.getHeight();
double widthFactor = Math.ceil(componentWidth / 300);
double heightFactor = Math.ceil(componentHeight / 15);
int realHeight = (int) (heightFactor + widthFactor - 1) * 15;
component.setPreferredSize(new Dimension(300, realHeight));
})
.collect(Collectors.toList());
// 竖向排列
JPanel messageSummaryPanel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 0);
messageComponents.forEach(messageSummaryPanel::add);
JScrollPane jScrollPane = new JScrollPane(messageSummaryPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane.setBorder(BorderFactory.createEmptyBorder());
centerPanel.add(jScrollPane, BorderLayout.CENTER);
centerPanel.setPreferredSize(contentSize);
contentPanel.add(centerPanel, BorderLayout.CENTER);
return contentPanel;
}
/**
* 行动
*
* UI布局
* /翻页/不再提醒/提醒行为/我知道了
*
* @return 行动面板
*/
protected JPanel createTailPanel() {
JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
tailPanel.setName("tailPanel");
// 翻页按钮效果
PageControlPanel pageControlPanel = new PageControlPanel(pageControlModel);
pageControlPanel.actions(new Runnable() {
@Override
public void run() {
pageControlModel = pageControlPanel.performPrevious();
refresh();
}
}, new Runnable() {
@Override
public void run() {
pageControlModel = pageControlPanel.performNext();
refresh();
}
});
tailPanel.add(pageControlPanel, BorderLayout.WEST);
// 行为效果
JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_M_Pane();
{
actionsPanel.setBorder(BorderFactory.createEmptyBorder());
actionsPanel.setName("actionsPanel");
UILabel notReminder = new UILabel();
notReminder.setText(Toolkit.i18nText("Fine-Design_Basic_Not_Reminder"));
notReminder.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 配置处理
EnvDetectorConfig.getInstance().setEnabled(false);
// 点击事件
destroy();
}
});
Color color = new Color(65, 155, 249);
notReminder.setForeground(color);
actionsPanel.add(notReminder, BorderLayout.WEST);
JPanel buttonPanel = FRGUIPaneFactory.createBorderLayout_M_Pane();
buttonPanel.setBorder(BorderFactory.createEmptyBorder());
// real-action
NotificationModel currentModel = getCurrentModel();
NotificationAction action = currentModel.getAction();
if (action != null) {
UIButton actionButton = new UIButton(action.name());
actionButton.setPreferredSize(buttonDimension);
actionButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
action.run();
}
});
buttonPanel.add(actionButton, BorderLayout.WEST);
}
UIButton knowButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Know"));
knowButton.setPreferredSize(buttonDimension);
knowButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (pageControlModel.isLast()) {
destroy();
return;
}
pageControlModel = pageControlPanel.performNext();
refresh();
}
});
buttonPanel.add(knowButton, BorderLayout.EAST);
actionsPanel.add(buttonPanel, BorderLayout.EAST);
}
tailPanel.add(actionsPanel, BorderLayout.EAST);
return tailPanel;
}
private void refresh() {
layoutContentPanel();
layoutTailPanel();
this.repaint();
}
private void layoutHeaderPanel() {
this.headerPanel = layoutPanel(this.headerPanel, this::createHeaderPanel, BorderLayout.NORTH);
}
private void layoutTailPanel() {
this.tailPanel = layoutPanel(this.tailPanel, this::createTailPanel, BorderLayout.SOUTH);
}
private void layoutContentPanel() {
this.contentPanel = layoutPanel(this.contentPanel, this::createContentPanel, BorderLayout.CENTER);
}
private JPanel layoutPanel(JPanel oldPanel, Supplier<JPanel> supplier, Object constraints){
if (oldPanel != null) {
this.body.remove(oldPanel);
}
JPanel newPanel = supplier.get();
if (newPanel != null) {
this.body.add(newPanel, constraints);
}
return newPanel;
}
private NotificationModel getCurrentModel() {
int index = pageControlModel.getIndex();
return notificationModels.get(index);
}
protected Icon getIconForType(NotificationType type) {
String iconPath;
switch (type) {
case ERROR:
iconPath = "/com/fr/design/standard/reminder/reminder_error.svg";
break;
case INFO:
iconPath = "/com/fr/design/standard/reminder/reminder_success.svg";
break;
case WARNING:
iconPath = "/com/fr/design/standard/reminder/reminder_warning.svg";
break;
default:
return null;
}
return IconUtils.readIcon(iconPath);
}
private void destroy() {
setVisible(false);
dispose();
}
@Override
public void dispose() {
super.dispose();
// todo
}
}

39
designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java

@ -0,0 +1,39 @@
package com.fr.design.components.notification;
import java.awt.Frame;
/**
* 通知会话的属性
*
* created by Harrison on 2022/05/24
**/
public class NotificationDialogProperties {
private Frame owner;
private String title;
private boolean modal;
public NotificationDialogProperties(Frame owner, String title) {
this.owner = owner;
this.title = title;
this.modal = false;
}
public void setModal(boolean modal) {
this.modal = modal;
}
public Frame getOwner() {
return owner;
}
public String getTitle() {
return title;
}
public boolean isModal() {
return modal;
}
}

88
designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java

@ -0,0 +1,88 @@
package com.fr.design.components.notification;
import com.fr.design.utils.LinkStrUtils;
/**
* created by Harrison on 2022/05/24
**/
public interface NotificationMessage {
/**
* 格式化
*
* @return 通知信息
*/
String format();
/**
* 类型
*
* @return 类型
*/
Type getType();
enum Type {
/**
* 简单型
*/
SIMPLE,
/**
* 链接
*/
LINK
}
class SimpleMessage implements NotificationMessage {
private String text;
public SimpleMessage(String text) {
this.text = text;
}
@Override
public String format() {
return text;
}
@Override
public Type getType() {
return Type.SIMPLE;
}
}
class LinkMessage implements NotificationMessage {
private String text;
private String link;
public LinkMessage(String text, String link) {
this.text = text;
this.link = link;
}
public String getText() {
return text;
}
public String getLink() {
return link;
}
@Override
public String format() {
return LinkStrUtils.generateHtmlTag(text);
}
@Override
public Type getType() {
return Type.LINK;
}
}
}

39
designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java

@ -0,0 +1,39 @@
package com.fr.design.components.notification;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class NotificationModel {
private final NotificationType type;
private final NotificationMessage[] messages;
@Nullable
private final NotificationAction action;
public NotificationModel(NotificationType type, @Nullable NotificationAction action, List<NotificationMessage> messages) {
this(type, action, messages.toArray(new NotificationMessage[0]));
}
public NotificationModel(NotificationType type, @Nullable NotificationAction action, NotificationMessage... messages) {
this.type = type;
this.messages = messages;
this.action = action;
}
public NotificationType getType() {
return type;
}
public NotificationMessage[] getMessages() {
return messages == null ? new NotificationMessage[0] : messages;
}
public @Nullable NotificationAction getAction() {
return action;
}
}

16
designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java

@ -0,0 +1,16 @@
package com.fr.design.components.notification;
/**
* 提醒类型
* 决定图标种类
*
* created by Harrison on 2022/05/27
**/
public enum NotificationType {
INFO,
ERROR,
WARNING
}

78
designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java

@ -0,0 +1,78 @@
package com.fr.design.components.page;
/**
* created by Harrison on 2022/05/26
**/
public class PageControlModel {
/**
* 当前索引
*
* = (页数-1)
*/
private int index;
/**
* 总页数
*/
private int summary;
public PageControlModel(int index, int summary) {
this.index = index;
this.summary = summary;
}
public PageControlModel() {
}
public PageControlModel previous() {
this.index--;
return this;
}
public PageControlModel next() {
this.index++;
return this;
}
/**
* 页数
* index+1
*
* @return 页数
*/
public int getNumber() {
return index + 1;
}
public boolean isFirst() {
return getNumber() == 1;
}
public boolean isLast() {
return getNumber() == getSummary();
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getSummary() {
return summary;
}
public void setSummary(int summary) {
this.summary = summary;
}
public String toContent() {
return getNumber() + "/" + this.summary;
}
}

150
designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java

@ -0,0 +1,150 @@
package com.fr.design.components.page;
import com.fr.base.svg.IconUtils;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.function.Function;
/**
* 翻页组件
*
* created by Harrison on 2022/05/26
**/
public class PageControlPanel extends JPanel {
private static final long serialVersionUID = 8140501834691131305L;
private static final Dimension PAGE_CONTROL_BUTTON_DIMENSION = new Dimension(20, 20);
private UIButton previous;
private Runnable previousAction;
private UILabel content;
private PageControlModel model;
private UIButton next;
private Runnable nextAction;
public PageControlPanel(PageControlModel model) {
this.model = model;
setBorder(BorderFactory.createEmptyBorder());
setLayout(new BorderLayout(6, 0));
this.previous = new UIButton();
previous.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION);
previous.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_left.svg"));
previous.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_left.svg"));
previous.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performAction(previousAction);
}
});
this.add(previous, BorderLayout.WEST);
this.content = new UILabel(model.toContent());
this.add(content, BorderLayout.CENTER);
next = new UIButton();
next.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION);
next.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_right.svg"));
next.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_right.svg"));
next.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performAction(nextAction);
}
});
this.add(next, BorderLayout.EAST);
refresh();
}
public PageControlModel performPrevious() {
update(PageControlModel::previous);
return this.model;
}
public PageControlModel performNext() {
update(PageControlModel::next);
return this.model;
}
public PageControlModel getModel() {
return this.model;
}
public void update(PageControlModel model) {
this.model.setIndex(model.getIndex());
this.model.setSummary(model.getSummary());
refresh();
}
public void update(Function<PageControlModel, PageControlModel> updateAction) {
PageControlModel newModel = updateAction.apply(this.model);
update(newModel);
refresh();
}
public void refresh() {
this.content.setText(this.model.toContent());
this.content.repaint();
this.previous.setEnabled(true);
this.next.setEnabled(true);
if (model.getNumber() == 1) {
// 禁用上一个
disableButton(this.previous);
// 禁用next
if (model.getNumber() == model.getSummary()) {
disableButton(this.next);
}
return;
}
// 禁用next
if (model.getNumber() == model.getSummary()) {
disableButton(this.next);
}
}
private void enable(UIButton button) {
button.setEnabled(true);
}
private void disableButton(UIButton button) {
button.setEnabled(false);
}
private void performAction(Runnable action) {
if (action != null) {
action.run();
refresh();
}
}
public void actions(Runnable previousAction, Runnable nextAction) {
this.previousAction = previousAction;
this.nextAction = nextAction;
}
}

184
designer-base/src/main/java/com/fr/design/components/table/TablePanel.java

@ -0,0 +1,184 @@
package com.fr.design.components.table;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.utils.ColorUtils;
import com.fr.third.org.apache.commons.lang3.ArrayUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
/**
* 表头
* 内容
*
* 适用于需要一个表格的 Panel
*
* created by Harrison on 2022/05/26
**/
public class TablePanel extends JPanel {
private static final Color DEFAULT_HEADER_COLOR = new Color(232, 232, 233);
private static final Color DEFAULT_ODD_ROW_COLOR = new Color(245, 245, 247);
private static final Color DEFAULT_EVEN_ROW_COLOR = Color.WHITE;
private JPanel headerPanel;
private JPanel[] headerItemPanels;
private JPanel contentPanel;
private JPanel[][] cellPanels;
public TablePanel(int row, int column) {
setLayout(FRGUIPaneFactory.createBorderLayout());
/* header 部分 */
this.headerPanel = new JPanel();
headerPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column));
headerPanel.setName("header-panel");
headerPanel.setPreferredSize(new Dimension(640, 24));
// border
headerPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221)));
syncHeaderColor(headerPanel);
headerItemPanels = new JPanel[column];
for (int i = 0; i < column; i++) {
JPanel headerItemWrapper = FRGUIPaneFactory.createBorderLayout_S_Pane();
syncHeaderColor(headerItemWrapper);
headerItemWrapper.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
JPanel headerItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
headerItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
headerItemPanels[i] = headerItemPanel;
UILabel label = new UILabel();
syncHeaderColor(label);
headerItemPanel.add(new UILabel(), BorderLayout.CENTER);
headerItemWrapper.add(headerItemPanel, BorderLayout.WEST);
if (i != column - 1) {
JSeparator separator = new JSeparator(JSeparator.VERTICAL);
separator.setBackground(new Color(218, 218, 221));
headerItemWrapper.add(separator, BorderLayout.EAST);
}
headerPanel.add(headerItemWrapper);
}
/* content 部分 */
contentPanel = new JPanel();
contentPanel.setLayout(new GridLayout(row, 1));
contentPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221)));
cellPanels = new JPanel[row][column];
for (int i = 0; i < row; i++) {
JPanel rowPanel = new JPanel();
// 获取行号
Color rowColor = getRowColorByRowNumber(i + 1);
rowPanel.setBackground(rowColor);
rowPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column));
rowPanel.setName("row-" + i);
rowPanel.setBorder(BorderFactory.createEmptyBorder());
rowPanel.setPreferredSize(new Dimension(640, 24));
for (int j = 0; j < column; j++) {
JPanel rowItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
rowItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
rowItemPanel.setName("rowItemPanel-"+ i + "-" + j);
final UILabel empty = new UILabel();
empty.setPreferredSize(new Dimension(210, 24));
rowItemPanel.setBackground(rowPanel.getBackground());
rowItemPanel.add(empty, BorderLayout.CENTER);
rowPanel.add(rowItemPanel);
cellPanels[i][j] = rowItemPanel;
}
contentPanel.add(rowPanel);
}
add(headerPanel, BorderLayout.NORTH);
add(contentPanel, BorderLayout.SOUTH);
}
/**
* 获取行的颜色
*
* @param row 行号
* @return 颜色
*/
private Color getRowColorByRowNumber(int row) {
Color rowColor;
if (row % 2 != 0) {
rowColor = DEFAULT_EVEN_ROW_COLOR;
} else {
rowColor = DEFAULT_ODD_ROW_COLOR;
}
return rowColor;
}
public void updateHeaders(String[] headers) {
for (int i = 0; i < headers.length; i++) {
String header = headers[i];
UILabel headerContent = new UILabel(header);
JPanel headerItemPanel = headerItemPanels[i];
if (ArrayUtils.getLength(headerItemPanel.getComponents()) == 1) {
headerItemPanel.remove(0);
}
headerItemPanel.add(headerContent);
syncHeaderColor(headerItemPanel);
}
}
public void updateCell(int row, int column, Component component) {
int x = row - 1;
int y = column - 1;
syncCellColor(row, component);
JPanel cellPanel = this.cellPanels[x][y];
if (ArrayUtils.getLength(cellPanel.getComponents()) == 1) {
cellPanel.remove(0);
}
cellPanel.add(component);
}
public void updateCell(int row, int column, String value) {
UILabel cellContent = new UILabel(value);
syncCellColor(row, cellContent);
this.updateCell(row, column, cellContent);
}
private void syncHeaderColor(Component component) {
ColorUtils.syncBackground(component, DEFAULT_HEADER_COLOR);
}
private void syncCellColor(int row, Component component) {
Color rowColor = getRowColorByRowNumber(row);
ColorUtils.syncBackground(component, rowColor);
component.setBackground(rowColor);
}
}

24
designer-base/src/main/java/com/fr/design/constants/DesignerColor.java

@ -0,0 +1,24 @@
package com.fr.design.constants;
import java.awt.Color;
/**
* <a href="https://www.figma.com/file/G2f40rv7cY8zpDDYbt6pY2/%E8%AE%BE%E8%AE%A1%E5%99%A811.0%E8%A7%84%E8%8C%83%E6%95%B4%E7%90%86">设计器规范</a>
* 将相关的逻辑抽象过来
* 如果后面更改的话 可以统一修改
* 如果换版本可以换成 v2 这种类推
*
* created by Harrison on 2022/05/26
**/
public interface DesignerColor {
interface Button {
interface Primary {
Color PRESSED = new Color(29, 122, 220);
Color HOVER = new Color(84, 165, 249);
Color NORMAL = new Color(65, 155, 249);
}
}
}

80
designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java

@ -1,16 +1,18 @@
package com.fr.design.dialog.link;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.utils.LinkStrUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import javax.swing.JEditorPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Font;
import java.net.URI;
import java.net.URL;
import static com.fr.design.utils.LinkStrUtils.LABEL;
/**
* 用来构建JOptionPane带超链的消息提示
@ -20,9 +22,28 @@ import java.net.URI;
* Created by hades on 2020/10/23
*/
public class MessageWithLink extends JEditorPane {
/**
* 直接放入 html 内容
* 如果有超链接标签 <a href=""></a> 的话将会自动点击匹配 url
*
* @param htmlText html内容
*/
public MessageWithLink(String htmlText) {
super("text/html", htmlText);
initListener();
setEditable(false);
setBorder(null);
}
private static final UILabel LABEL = new UILabel();
public MessageWithLink(String htmlText, Runnable action) {
super("text/html", htmlText);
initListener(action);
setEditable(false);
setBorder(null);
}
public MessageWithLink(String message, String linkName, String link) {
this(message, linkName, link, LABEL.getBackground(), LABEL.getFont());
@ -49,36 +70,45 @@ public class MessageWithLink extends JEditorPane {
}
public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) {
super("text/html", "<html><body style=\"" + generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
super("text/html", "<html><body style=\"" + LinkStrUtils.generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
initListener(link);
setEditable(false);
setBorder(null);
}
protected void initListener(String link) {
addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
try {
Desktop.getDesktop().browse(URI.create(link));
} catch (Exception exception) {
FineLoggerFactory.getLogger().error(exception.getMessage(), exception);
}
protected void initListener() {
addHyperlinkListener(hyperlinkEvent -> {
try {
if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
URL url = hyperlinkEvent.getURL();
Desktop.getDesktop().browse(url.toURI());
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
});
}
protected void initListener(Runnable runnable) {
addHyperlinkListener(e -> {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
runnable.run();
}
});
}
private static StringBuilder generateStyle(Color backgroundColor, Font font, Color fontColor) {
// 构建相同风格样式
StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";");
style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";");
style.append("font-size:").append(font.getSize()).append("pt;");
style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");");
style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");");
return style;
protected void initListener(String link) {
initListener(() -> {
try {
Desktop.getDesktop().browse(URI.create(link));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
});
}
}

5
designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java

@ -64,6 +64,7 @@ import com.fr.design.os.impl.SupportOSImpl;
import com.fr.design.remote.action.RemoteDesignAuthManagerAction;
import com.fr.design.update.actions.SoftwareUpdateAction;
import com.fr.design.utils.ThemeUtils;
import com.fr.env.detect.ui.EnvDetectorAction;
import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralContext;
import com.fr.general.locale.LocaleAction;
@ -572,7 +573,9 @@ public abstract class ToolBarMenuDock {
if (AlphaFineConfigManager.isALPHALicAvailable()) {
shortCuts.add(new AlphaFineAction());
}
shortCuts.add(new EnvDetectorAction());
shortCuts.add(SeparatorDef.DEFAULT);
if (DesignerEnvManager.getEnvManager().isOpenDebug()) {
OSSupportCenter.buildAction(objects -> shortCuts.add(new FineUIAction()), SupportOSImpl.FINEUI);

29
designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java

@ -1,9 +1,12 @@
package com.fr.design.ui.util;
import com.fr.log.FineLoggerFactory;
import com.fr.third.guava.base.Stopwatch;
import com.fr.third.guava.base.Supplier;
import org.jetbrains.annotations.NotNull;
import javax.swing.SwingUtilities;
import java.util.concurrent.TimeUnit;
/**
* 一些常用的 GUI 工具
@ -52,4 +55,30 @@ public class UIUtil {
}
}
}
/**
* 有些时候交互上需要有一些等待的效果
* 如果没有等待到 会让交互失去作用
*
* @param supplier 结果
* @param timeout 超时
* @param timeUnit 单位
* @return 结果
*/
public static <T> T waitUntil(Supplier<T> supplier, long timeout, TimeUnit timeUnit) {
Stopwatch st = Stopwatch.createStarted();
T result = supplier.get();
long elapsed = st.elapsed(timeUnit);
long minus = timeout - elapsed;
if (minus > 0) {
long value = timeUnit.toMillis(minus);
try {
Thread.sleep(value);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
return result;
}
}

30
designer-base/src/main/java/com/fr/design/utils/ColorUtils.java

@ -0,0 +1,30 @@
package com.fr.design.utils;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.util.Arrays;
/**
* created by Harrison on 2022/05/29
**/
public class ColorUtils {
/**
* 递归的同步颜色
*
* @param color 颜色
*/
public static void syncBackground(Component component, Color color) {
component.setBackground(color);
if (component instanceof Container) {
Container container = (Container) component;
Component[] components = container.getComponents();
if (components != null) {
Arrays.stream(components).forEach((e) -> syncBackground(e, color));
}
}
}
}

12
designer-base/src/main/java/com/fr/design/utils/DevDebugUtils.java

@ -0,0 +1,12 @@
package com.fr.design.utils;
/**
* created by Harrison on 2022/05/26
**/
public class DevDebugUtils {
public static void main(String[] args) {
org.swingexplorer.Launcher.main(new String[]{"com.fr.design.utils.DevUtils"});
}
}

60
designer-base/src/main/java/com/fr/design/utils/DevUtils.java

@ -0,0 +1,60 @@
package com.fr.design.utils;
import com.fr.config.dao.DaoContext;
import com.fr.config.dao.impl.LocalClassHelperDao;
import com.fr.config.dao.impl.LocalEntityDao;
import com.fr.config.dao.impl.LocalXmlEntityDao;
import com.fr.design.ui.util.UIUtil;
import com.fr.transaction.Configurations;
import com.fr.transaction.LocalConfigurationHelper;
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.util.function.Consumer;
/**
* 设计器的开发时工具
* 帮助进行 UI 页面的调试
* <p>
* created by Harrison on 2022/05/23
**/
public class DevUtils {
private static void prepare() {
DaoContext.setEntityDao(new LocalEntityDao());
DaoContext.setClassHelperDao(new LocalClassHelperDao());
DaoContext.setXmlEntityDao(new LocalXmlEntityDao());
Configurations.setHelper(new LocalConfigurationHelper());
}
public static void show(Consumer<Frame> consumer) {
DesignUtils.initLookAndFeel();
UIUtil.invokeLaterIfNeeded(() -> {
JFrame frame = new JFrame("dev-util");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
frame.setSize(dimension);
consumer.accept(frame);
frame.setVisible(true);
});
}
public static void main(String[] args) {
DevUtils.prepare();
DevUtils.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
}
});
}
}

55
designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java

@ -0,0 +1,55 @@
package com.fr.design.utils;
import com.fr.design.gui.ilable.UILabel;
import com.fr.stable.StringUtils;
import java.awt.Color;
import java.awt.Font;
/**
* created by Harrison on 2022/05/24
**/
public class LinkStrUtils {
public static final UILabel LABEL = new UILabel();
public static String generateHtmlTag(String html) {
String defaultStyle = generateDefaultStyle();
return generateHtmlTag(defaultStyle, html);
}
public static String generateHtmlTag(String style, String html) {
if (StringUtils.isEmpty(style)) {
throw new NullPointerException("style");
}
if (StringUtils.isEmpty(html)) {
throw new NullPointerException("html");
}
return "<html><body style=\"" + style + "\">" + html + "</body></html>";
}
public static String generateLinkTag(String link, String text) {
return "<a href=\"" + link + "\">" + text + "</a>";
}
public static String generateStyle(Color backgroundColor, Font font, Color fontColor) {
// 构建相同风格样式
StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";");
style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";");
style.append("font-size:").append(font.getSize()).append("pt;");
style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");");
style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");");
return style.toString();
}
public static String generateDefaultStyle() {
return generateStyle(LABEL.getBackground(), LABEL.getFont(), LABEL.getForeground());
}
}

182
designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java vendored

@ -0,0 +1,182 @@
package com.fr.env.detect;
import com.fr.common.util.Collections;
import com.fr.design.components.notification.NotificationDialog;
import com.fr.design.components.notification.NotificationDialogProperties;
import com.fr.design.components.notification.NotificationModel;
import com.fr.design.constants.DesignerLaunchStatus;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
import com.fr.env.detect.base.DetectorBridge;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorStatus;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.event.Null;
import com.fr.start.server.EmbedServerEvent;
import com.fr.update.delay.DelayHelper;
import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceEvent;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 环境检测中心
* 如果环境检测 ->
*
* created by Harrison on 2022/05/27
**/
public class EnvDetectorCenter {
public static EnvDetectorCenter getInstance() {
return EnvDetectorCenterHolder.INSTANCE;
}
private static class EnvDetectorCenterHolder {
private static final EnvDetectorCenter INSTANCE = new EnvDetectorCenter();
}
private final AtomicReference<DetectorProcess> PROCESS = new AtomicReference<>();
/**
* 初始化
*/
public void init() {
// 默认是启动
PROCESS.set(DetectorProcess.DESIGN_LAUNCH);
start();
// 添加启动完成监听
EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener<Null>() {
@Override
public void on(Event event, Null param) {
if (isSameProcess(DetectorProcess.DESIGN_LAUNCH)) {
stop();
}
}
});
// 切换完成后的监听
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener<Workspace>() {
@Override
public void on(Event event, Workspace param) {
if (isSameProcess(DetectorProcess.DESIGN_LAUNCH)) {
stop();
}
}
});
// 打开内置服务器
EventDispatcher.listen(EmbedServerEvent.BeforeStart, new Listener<Null>() {
@Override
public void on(Event event, Null param) {
PROCESS.set(DetectorProcess.SERVER_LAUNCH);
start();
}
});
EventDispatcher.listen(EmbedServerEvent.AfterStart, new Listener<Null>() {
@Override
public void on(Event event, Null param) {
if (isSameProcess(DetectorProcess.SERVER_LAUNCH)) {
stop();
}
}
});
}
/**
* 当前的流程符合预期
* 什么情况下不符合
* design.start -> server.start -> design.end -> server.end
* 这个时候 design.end 就不会触发等待服务器启动后才触发
*
* @param process 检测流程
* @return /
*/
private boolean isSameProcess(DetectorProcess process) {
return PROCESS.compareAndSet(process, null);
}
/**
* 启动
*/
public void start() {
DetectorBridge.getInstance().start();
}
/**
* 关闭
*/
public void stop() {
// 一分钟后执行
DelayHelper.delayCall(EnvDetectorCenter.class.getName(), () -> {
Stream<DetectorResult> resultStream = DetectorBridge.getInstance().detect();
// 结束
DetectorBridge.getInstance().stop();
// 展示效果
NotificationDialogProperties properties = new NotificationDialogProperties(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Detect_Notification_Title"));
List<NotificationModel> notificationModels = resultStream
.filter(Objects::nonNull)
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.map(DetectorUtil::convert2Notification)
.collect(Collectors.toList());
if (Collections.isEmpty(notificationModels)) {
return;
}
UIUtil.invokeLaterIfNeeded(() -> {
NotificationDialog dialog = new NotificationDialog(properties, notificationModels);
dialog.open();
});
}, 30, TimeUnit.SECONDS);
}
/**
* 使用预期外的错误进行展示
*
* @param throwable 异常
* @return
*/
public List<DetectorResult> terminate(Throwable throwable) {
Stream<DetectorResult> resultStream = DetectorBridge.getInstance().detect(throwable);
return resultStream
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.collect(Collectors.toList());
}
private enum DetectorProcess {
/**
* 设计器启动
*/
DESIGN_LAUNCH,
/**
* 服务器启动
*/
SERVER_LAUNCH,
/**
* 环境切换
*/
ENV_SWITCH
}
}

26
designer-base/src/main/java/com/fr/env/detect/EnvPrepare.java vendored

@ -0,0 +1,26 @@
package com.fr.env.detect;
import com.fr.module.Activator;
/**
* 设计器环境准备
* 更多的是一些钩子需要在环境启动切换时进行处理
* 使用监听 {@link com.fr.workspace.WorkspaceEvent} 只能满足
* before -> stop -> start -> after
* 现在支持 =>
* before -> stop -> prepare -> start -> after
*
* created by Harrison on 2022/05/29
**/
public class EnvPrepare extends Activator {
@Override
public void start() {
EnvDetectorCenter.getInstance().init();
}
@Override
public void stop() {
}
}

8
designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java vendored

@ -7,13 +7,13 @@ import com.fr.env.detect.bean.DetectorType;
**/
public abstract class AbstractExceptionDetector implements ExceptionDetector {
private DetectorType key;
private DetectorType type;
public AbstractExceptionDetector(DetectorType key) {
this.key = key;
public AbstractExceptionDetector(DetectorType type) {
this.type = type;
}
public DetectorType type() {
return key;
return type;
}
}

19
designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java vendored

@ -16,8 +16,14 @@ public abstract class CatchExceptionDetector extends AbstractExceptionDetector {
private ThrowableConverter throwableConverter;
public CatchExceptionDetector(DetectorType key, ThrowableStore throwableStore, ThrowableConverter throwableConverter) {
super(key);
public CatchExceptionDetector(DetectorType type, ThrowableConverter throwableConverter) {
super(type);
this.throwableStore = ThrowableStore.getInstance();
this.throwableConverter = throwableConverter;
}
public CatchExceptionDetector(DetectorType type, ThrowableStore throwableStore, ThrowableConverter throwableConverter) {
super(type);
this.throwableStore = throwableStore;
this.throwableConverter = throwableConverter;
}
@ -36,9 +42,14 @@ public abstract class CatchExceptionDetector extends AbstractExceptionDetector {
List<Throwable> throwableList = throwableStore.getAll();
for (Throwable throwable : throwableList) {
if (throwableConverter.accept(throwable)) {
return throwableConverter.convert(throwable);
DetectorResult result = throwableConverter.convert(throwable);
if (result == null) {
result = DetectorResult.normal(type());
}
return result;
}
}
return null;
return DetectorResult.normal(type());
}
}

87
designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java vendored

@ -2,15 +2,24 @@ package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.FineDbDirtyDetector;
import com.fr.env.detect.impl.FineDbLockedDetector;
import com.fr.env.detect.impl.FineDbPermissionDetector;
import com.fr.env.detect.impl.JarConflictDetector;
import com.fr.env.detect.impl.JarInconsistentDetector;
import com.fr.env.detect.impl.JarLackDetector;
import com.fr.env.detect.thowable.ThrowableLogAppender;
import com.fr.env.detect.thowable.ThrowableStore;
import com.fr.value.NotNullLazyValue;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
/**
* 检测器桥接逻辑
* [detect-core] - bridge - ui
*
* created by Harrison on 2022/05/13
**/
public class DetectorBridge {
@ -25,20 +34,21 @@ public class DetectorBridge {
private static final DetectorBridge INSTANCE = new DetectorBridge();
}
private final NotNullLazyValue<ThrowableBridge> throwableBridge = new NotNullLazyValue<ThrowableBridge>() {
@Override
protected @NotNull ThrowableBridge compute() {
return new ThrowableBridge();
}
};
private final NotNullLazyValue<DetectorManager> detectorManager = new NotNullLazyValue<DetectorManager>() {
@Override
protected @NotNull DetectorManager compute() {
DetectorManager manager = new DetectorManager();
manager.register(new FineDbDirtyDetector());
manager.register(new FineDbPermissionDetector());
manager.register(new FineDbLockedDetector());
return new DetectorManager();
manager.register(new JarInconsistentDetector());
manager.register(new JarLackDetector());
manager.register(new JarConflictDetector());
return manager;
}
};
@ -46,7 +56,7 @@ public class DetectorBridge {
public void start() {
if (ExceptionDetectorConfig.getInstance().isOpen()) {
if (!hasStarted.get() && EnvDetectorConfig.getInstance().isEnabled()) {
// 开始注册异常处理
ThrowableLogAppender.getInstance().enable();
hasStarted.set(true);
@ -62,34 +72,63 @@ public class DetectorBridge {
}
/**
* 执行-检测异常
* 针对某一项进行检测
* 主要用于手动检测时
*
* @return 能够检测出的异常情况
* @param type 检测类型
* @return 检测结果
*/
public Stream<DetectorResult> detect() {
@NotNull
public DetectorResult detect(DetectorType type) {
return detectorManager.getValue().detect(type);
}
return detectorManager.getValue().detect();
/**
* 针对某一项 \ 某一个异常进行检测
*
* @param type 类型
* @param throwable 异常
* @return 结果
*/
@NotNull
public DetectorResult detect(DetectorType type, Throwable throwable) {
ThrowableStore.getInstance().add(throwable);
DetectorResult result = detect(type);
ThrowableStore.getInstance().reset();
return result;
}
/**
* 针对某一项进行检测
* 异常检测
* 对异常统一检测
*
* @param type 检测类型
* @return 检测结果
* @return 能够检测出的异常情况
*/
public Optional<DetectorResult> detect(DetectorType type) {
public Stream<DetectorResult> detect() {
return detectorManager.getValue().detect(type);
return detectorManager.getValue().detect();
}
/**
* 执行-捕获异常
* 异常检测
* 当遇到异常时且异常难以处理直接导致服务器启动失败时调用
* 将异常添加进来统一检测
*
* @param throwable 异常
* @return 检测结果
*/
public Optional<DetectorResult> convert(Throwable throwable) {
return throwableBridge.getValue().convert(throwable);
public Stream<DetectorResult> detect(Throwable throwable) {
ThrowableStore.getInstance().add(throwable);
Stream<DetectorResult> result = detect();
ThrowableStore.getInstance().reset();
return result;
}
}

11
designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java vendored

@ -0,0 +1,11 @@
package com.fr.env.detect.base;
/**
* created by Harrison on 2022/05/25
**/
public class DetectorConstants {
public static final String JAR_HELP_LINK = "https://help.fanruan.com/finereport/doc-view-4700.html?source=3";
public static final String FINE_DB_HELP_LINK = "https://help.fanruan.com/finereport/doc-view-4701.html?source=3";
}

21
designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java vendored

@ -1,15 +1,18 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 检测器中心
*
* created by Harrison on 2022/05/24
**/
class DetectorManager {
@ -25,16 +28,26 @@ class DetectorManager {
public Stream<DetectorResult> detect() {
return detectors.stream()
Stream<DetectorResult> results = detectors.stream()
.map(ExceptionDetector::detect)
.filter(Objects::nonNull);
List<DetectorResult> resultList = results.collect(Collectors.toList());
resultList.forEach(DetectorResult::log);
return resultList.stream();
}
public Optional<DetectorResult> detect(DetectorType type) {
public DetectorResult detect(DetectorType type) {
return detectors.stream()
Optional<DetectorResult> result = detectors.stream()
.filter((detector -> type == detector.type()))
.findFirst()
.map(ExceptionDetector::detect);
// 记录日志
result.ifPresent(DetectorResult::log);
return result.orElse(DetectorResult.normal(type));
}
}

127
designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java vendored

@ -0,0 +1,127 @@
package com.fr.env.detect.base;
import com.fr.base.function.ThrowableRunnable;
import com.fr.design.components.notification.NotificationAction;
import com.fr.design.components.notification.NotificationMessage;
import com.fr.design.components.notification.NotificationModel;
import com.fr.design.components.notification.NotificationType;
import com.fr.design.dialog.link.MessageWithLink;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.utils.LinkStrUtils;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.env.detect.bean.SolutionAction;
import com.fr.general.build.BuildInfo;
import com.fr.stable.StringUtils;
import org.jetbrains.annotations.NotNull;
import javax.swing.JComponent;
import java.awt.Desktop;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
/**
* created by Harrison on 2022/05/25
**/
public class DetectorUtil {
/**
* 是否是设计器的 jar
*
* @param info 信息
* @return /
*/
public static boolean isDesignerJar(BuildInfo info) {
if (info == null) {
return false;
}
return StringUtils.contains(info.getJar(), "fine-report-designer");
}
/**
* 将结果转化为提醒的数据
*
* @param result 结果
* @return 数据
*/
public static NotificationModel convert2Notification(DetectorResult result) {
List<NotificationMessage> messages = new ArrayList<>();
Function<Message, Optional<NotificationMessage>> convert2NotificationMsg = message -> {
NotificationMessage notificationMessage = null;
if (message != null) {
Message.Type type = message.getType();
switch (type) {
case SIMPLE:
notificationMessage = (new NotificationMessage.SimpleMessage(message.get()));
break;
case LINK:
Message.Link linkMsg = (Message.Link) message;
notificationMessage = new NotificationMessage.LinkMessage(linkMsg.getText(), linkMsg.getLink());
break;
default:
break;
}
}
return Optional.ofNullable(notificationMessage);
};
ExceptionTips tips = result.getTips();
if (tips != null) {
convert2NotificationMsg
.apply(tips.getMessage())
.ifPresent(messages::add);
}
ExceptionSolution solution = result.getSolution();
if (solution != null) {
convert2NotificationMsg.apply(solution.getMessage())
.ifPresent(messages::add);
}
NotificationAction notificationAction = null;
if (solution != null) {
SolutionAction solutionAction = solution.getAction();
if (solutionAction != null) {
notificationAction = new NotificationAction() {
@Override
public String name() {
return solutionAction.name();
}
@Override
public void run(Object... args) {
solutionAction.run();
}
};
}
}
return new NotificationModel(NotificationType.WARNING, notificationAction, messages);
}
/**
* 将信息转化为展示的组件
*
* @param message 信息
* @return 组件
*/
public static JComponent convert2TextComponent(@NotNull Message message) {
if (message.getType() == Message.Type.LINK) {
Message.Link linkMsg = (Message.Link) message;
return new MessageWithLink(linkMsg.getText(), ThrowableRunnable.toRunnable(() -> {
Desktop.getDesktop().browse(URI.create(linkMsg.getLink()));
}));
}
return new UILabel(LinkStrUtils.generateHtmlTag(message.get()));
}
}

59
designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java vendored

@ -0,0 +1,59 @@
package com.fr.env.detect.base;
import com.fr.design.DesignerEnvManager;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLable;
import com.fr.stable.xml.XMLableReader;
/**
* created by Harrison on 2022/05/13
**/
public class EnvDetectorConfig implements XMLable {
public static final String XML_TAG = "EnvDetectorConfig";
private static final long serialVersionUID = -8170289826729582122L;
private static final EnvDetectorConfig INSTANCE = new EnvDetectorConfig();
public static EnvDetectorConfig getInstance() {
return INSTANCE;
}
private boolean enabled = true;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
save();
}
private void save() {
DesignerEnvManager.getEnvManager(false).saveXMLFile();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public void readXML(XMLableReader reader) {
if (reader.isAttr()) {
this.setEnabled(reader.getAttrAsBoolean("isEnabled", true));
}
}
@Override
public void writeXML(XMLPrintWriter writer) {
writer.startTAG(XML_TAG);
writer.attr("isEnabled", this.isEnabled());
writer.end();
}
}

2
designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java vendored

@ -1,7 +1,7 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
/**
* created by Harrison on 2022/05/13

21
designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetectorConfig.java vendored

@ -1,21 +0,0 @@
package com.fr.env.detect.base;
/**
* created by Harrison on 2022/05/13
**/
public class ExceptionDetectorConfig {
public static ExceptionDetectorConfig getInstance() {
return ExceptionDetectorConfigHolder.INSTANCE;
}
private static class ExceptionDetectorConfigHolder {
private static final ExceptionDetectorConfig INSTANCE = new ExceptionDetectorConfig();
}
public boolean isOpen() {
return true;
}
}

71
designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java vendored

@ -17,23 +17,42 @@ public class DetectorResult {
private ExceptionSolution solution;
private ExceptionLog exceptionLog;
private ExceptionLog log;
public DetectorResult(DetectorType type, ExceptionTips tips, ExceptionSolution solution, ExceptionLog exceptionLog) {
private DetectorResult(DetectorType type) {
this.type = type;
}
private DetectorResult(DetectorType type, ExceptionTips tips, ExceptionSolution solution, ExceptionLog log) {
this.type = type;
this.tips = tips;
this.solution = solution;
this.exceptionLog = exceptionLog;
this.log = log;
}
public DetectorType getType() {
return type;
public static DetectorResult normal(DetectorType type) {
DetectorResult result = new DetectorResult(type);
result.status = DetectorStatus.NORMAL;
return result;
}
public static DetectorResult exception(DetectorType type, ExceptionTips tips, ExceptionSolution solution, ExceptionLog log) {
DetectorResult result = new DetectorResult(type, tips, solution, log);
result.status = DetectorStatus.EXCEPTION;
return result;
}
public DetectorStatus getStatus() {
return status;
}
public DetectorType getType() {
return type;
}
@Nullable
public ExceptionTips getTips() {
return tips;
@ -44,25 +63,26 @@ public class DetectorResult {
return solution;
}
@Nullable
public ExceptionLog getExceptionLog() {
return exceptionLog;
public void log() {
if (log != null) {
log.log();
}
}
public static DetectorResultBuilder builder() {
return new DetectorResultBuilder();
return new DetectorResultBuilder()
.withStatus(DetectorStatus.EXCEPTION);
}
public static final class DetectorResultBuilder {
private DetectorType type;
private DetectorStatus status;
private ExceptionTips tips;
private ExceptionSolution solution;
private ExceptionLog exceptionLog;
private ExceptionLog log;
private DetectorResultBuilder() {
}
@ -82,19 +102,38 @@ public class DetectorResult {
return this;
}
public DetectorResultBuilder withTips(String message) {
Message.Simple simple = new Message.Simple(message);
this.tips = new ExceptionTips(simple);
return this;
}
public DetectorResultBuilder withSolution(ExceptionSolution solution) {
this.solution = solution;
return this;
}
public DetectorResultBuilder withSolution(String content, String link) {
Message.Link message = new Message.Link(content, link);
this.solution = new ExceptionSolution(message, null);
return this;
}
public DetectorResultBuilder withLog(String log, Object... args) {
this.log = ExceptionLog.create(log, args);
return this;
}
public DetectorResultBuilder withExceptionLog(ExceptionLog exceptionLog) {
this.exceptionLog = exceptionLog;
public DetectorResultBuilder withLog(ExceptionLog log) {
this.log = log;
return this;
}
public DetectorResult build() {
DetectorResult detectorResult = new DetectorResult(type, tips, solution, exceptionLog);
DetectorResult detectorResult = new DetectorResult(type, tips, solution, log);
detectorResult.status = this.status;
return detectorResult;
}

13
designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java vendored

@ -1,22 +1,17 @@
package com.fr.env.detect.bean;
/**
* created by Harrison on 2022/05/25
* created by Harrison on 2022/05/27
**/
public enum DetectorStatus {
/**
* 成功
* 正常
*/
SUCCESS,
/**
* 失败
*/
FAILED,
NORMAL,
/**
* 异常
*/
UNKNOWN
EXCEPTION,
}

91
designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java vendored

@ -1,7 +1,11 @@
package com.fr.env.detect.bean;
import com.fr.design.i18n.Toolkit;
/**
* 检测的原生数据
* 其实这里可以继续拆分到不同的逻辑下面的, 比如实际生成 DetectorResult 的地方 {@link com.fr.env.detect.base.ExceptionDetector}
* 不过目前没有必要先这样处理
*
* created by Harrison on 2022/05/13
**/
@ -10,43 +14,87 @@ public enum DetectorType {
/**
* 缺少 JAR
*/
LACK_OF_JAR(Kind.JAR, WorkType.LOCAL),
LACK_OF_JAR(Kind.JAR, WorkType.LOCAL,
"Fine_Design_Basic_Jar_Lacked_Desc",
"Fine_Design_Basic_Jar_Lack",
"Fine_Design_Basic_Jar_Solution",
"Fine_Design_Basic_Log_Jar_Lack"),
/**
* JAR 包版本不一致
*/
JAR_IN_CONSISTENCE(Kind.JAR, WorkType.SIMPLE),
JAR_IN_CONSISTENCE(Kind.JAR, WorkType.SIMPLE,
"Fine_Design_Basic_Jar_InConsistent_Desc",
"Fine_Design_Basic_Jar_InConsistent",
"Fine_Design_Basic_Jar_Solution",
"Fine_Design_Basic_Log_Jar_InConsistent"),
/**
* JAR 包冲突
*/
JAR_CONFLICT(Kind.JAR, WorkType.REMOTE),
JAR_CONFLICT(Kind.JAR, WorkType.REMOTE,
"Fine_Design_Basic_Jar_Problem_Desc",
"Fine_Design_Basic_Jar_Problem",
"Fine_Design_Basic_Jar_Solution",
"Fine_Design_Basic_Log_Jar_Problem"),
/**
* FineDB 权限问题
*/
FINE_DB_PERMISSION(Kind.FINE_DB, WorkType.LOCAL),
FINE_DB_PERMISSION(Kind.FINE_DB, WorkType.LOCAL,
"Fine_Design_Basic_FineDB_Permission_Occupied_Desc",
"Fine_Design_Basic_FineDB_Permission_Occupied",
"Fine_Design_Basic_FineDB_Solution",
"Fine_Design_Basic_Log_FineDB_Permission_Occupied"),
/**
* FineDB
*/
FINE_DB_LOCKED(Kind.FINE_DB, WorkType.LOCAL),
FINE_DB_LOCKED(Kind.FINE_DB, WorkType.LOCAL,
"Fine_Design_Basic_FineDB_Locked_Desc",
"Fine_Design_Basic_FineDB_Locked",
"Fine_Design_Basic_FineDB_Solution",
"Fine_Design_Basic_Log_FineDB_Locked"),
/**
* FineDB 脏数据
*/
FINE_DB_DIRTY(Kind.FINE_DB, WorkType.SIMPLE)
FINE_DB_DIRTY(Kind.FINE_DB, WorkType.SIMPLE,
"Fine_Design_Basic_FineDB_Dirty_Data_Desc",
"Fine_Design_Basic_FineDB_Dirty_Data",
"Fine_Design_Basic_FineDB_Dirty_Solution",
"Fine_Design_Basic_Log_FineDB_Dirty_Data")
;
private final Kind kind;
private final WorkType workType;
DetectorType(Kind kind, WorkType workType) {
private final String descLocale;
private final String tipsLocale;
private final String solutionLocale;
private final String logLocale;
DetectorType(Kind kind, WorkType workType, String descLocale, String tipsLocale, String solutionLocale, String logLocale) {
this.kind = kind;
this.workType = workType;
this.descLocale = descLocale;
this.tipsLocale = tipsLocale;
this.solutionLocale = solutionLocale;
this.logLocale = logLocale;
}
public String getDescription() {
return Toolkit.i18nText(descLocale);
}
public String getDescLocale() {
return descLocale;
}
public Kind getKind() {
@ -57,16 +105,39 @@ public enum DetectorType {
return workType;
}
public String getTipsLocale() {
return tipsLocale;
}
public String getSolutionLocale() {
return solutionLocale;
}
public String getLogLocale() {
return logLocale;
}
public enum Kind {
/**
* JAR 类型
*/
JAR,
JAR("Fine_Design_Basic_Jar_Kind_Desc"),
/**
* FineDB 类型
*/
FINE_DB
FINE_DB("Fine_Design_Basic_FineDB_Kind_Desc");
private final String locale;
Kind(String locale) {
this.locale = locale;
}
public String getDescription() {
return Toolkit.i18nText(this.locale);
}
}
public enum WorkType {

30
designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java vendored

@ -1,24 +1,36 @@
package com.fr.env.detect.bean;
import com.fr.log.FineLoggerFactory;
/**
* created by Harrison on 2022/05/13
**/
public class ExceptionLog {
private final String errorCode;
private final String template;
private final Object[] args;
private ExceptionLog(String template, Object... args) {
this.template = template;
this.args = args;
}
public static ExceptionLog create(String template, Object... args) {
return new ExceptionLog(template, args);
}
private final String locale;
public void log() {
public ExceptionLog(String errorCode, String locale) {
this.errorCode = errorCode;
this.locale = locale;
FineLoggerFactory.getLogger().error(template, args);
}
public String getErrorCode() {
return errorCode;
public String getTemplate() {
return template;
}
public String getLocale() {
return locale;
public Object[] getArgs() {
return args;
}
}

12
designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java vendored

@ -1,5 +1,7 @@
package com.fr.env.detect.bean;
import org.jetbrains.annotations.Nullable;
/**
* created by Harrison on 2022/05/13
**/
@ -7,9 +9,15 @@ public class ExceptionSolution {
private Message message;
@Nullable
private SolutionAction action;
public ExceptionSolution(Message message, SolutionAction action) {
public static ExceptionSolution create(String text, String link, SolutionAction action) {
return new ExceptionSolution(new Message.Link(text, link), action);
}
public ExceptionSolution(Message message, @Nullable SolutionAction action) {
this.message = message;
this.action = action;
}
@ -18,7 +26,7 @@ public class ExceptionSolution {
return message;
}
public SolutionAction getAction() {
public @Nullable SolutionAction getAction() {
return action;
}
}

5
designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java vendored

@ -9,6 +9,11 @@ public class ExceptionTips {
private Message message;
public static ExceptionTips create(String text) {
return new ExceptionTips(new Message.Simple(text));
}
public ExceptionTips(Message message) {
this.message = message;
}

15
designer-base/src/main/java/com/fr/env/detect/bean/Message.java vendored

@ -12,6 +12,13 @@ public interface Message {
*/
Type getType();
/**
* 返回内容
*
* @return 内容
*/
String get();
enum Type {
/**
@ -33,7 +40,8 @@ public interface Message {
this.message = message;
}
public String getMessage() {
@Override
public String get() {
return message;
}
@ -54,6 +62,11 @@ public interface Message {
this.link = link;
}
@Override
public String get() {
return getText();
}
public String getText() {
return text;
}

26
designer-base/src/main/java/com/fr/env/detect/exception/DetectorException.java vendored

@ -1,26 +0,0 @@
package com.fr.env.detect.exception;
/**
* created by Harrison on 2022/05/25
**/
public class DetectorException extends RuntimeException {
public DetectorException() {
}
public DetectorException(String message) {
super(message);
}
public DetectorException(String message, Throwable cause) {
super(message, cause);
}
public DetectorException(Throwable cause) {
super(cause);
}
public DetectorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

10
designer-base/src/main/java/com/fr/env/detect/impl/HsqlDirtyDetector.java → designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java vendored

@ -2,15 +2,19 @@ package com.fr.env.detect.impl;
import com.fr.env.detect.base.CatchExceptionDetector;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.thowable.ThrowableStore;
import com.fr.env.detect.impl.converter.FineDbDirtyConverter;
import com.fr.env.detect.thowable.ThrowableStore;
/**
* created by Harrison on 2022/05/25
**/
public class HsqlDirtyDetector extends CatchExceptionDetector {
public class FineDbDirtyDetector extends CatchExceptionDetector {
public FineDbDirtyDetector() {
this(ThrowableStore.getInstance());
}
public HsqlDirtyDetector(ThrowableStore throwableStore) {
public FineDbDirtyDetector(ThrowableStore throwableStore) {
super(DetectorType.FINE_DB_DIRTY, throwableStore, new FineDbDirtyConverter());
}

16
designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java vendored

@ -0,0 +1,16 @@
package com.fr.env.detect.impl;
import com.fr.env.detect.base.CatchExceptionDetector;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.converter.FineDbLockedConverter;
/**
* created by Harrison on 2022/05/26
**/
public class FineDbLockedDetector extends CatchExceptionDetector {
public FineDbLockedDetector() {
super(DetectorType.FINE_DB_LOCKED, new FineDbLockedConverter());
}
}

15
designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java vendored

@ -0,0 +1,15 @@
package com.fr.env.detect.impl;
import com.fr.env.detect.base.CatchExceptionDetector;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.converter.FineDbPermissionConverter;
/**
* created by Harrison on 2022/05/26
**/
public class FineDbPermissionDetector extends CatchExceptionDetector {
public FineDbPermissionDetector() {
super(DetectorType.FINE_DB_PERMISSION, new FineDbPermissionConverter());
}
}

15
designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java vendored

@ -0,0 +1,15 @@
package com.fr.env.detect.impl;
import com.fr.env.detect.base.CatchExceptionDetector;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.converter.ClassConflictConvertor;
/**
* created by Harrison on 2022/05/26
**/
public class JarConflictDetector extends CatchExceptionDetector {
public JarConflictDetector() {
super(DetectorType.JAR_CONFLICT, new ClassConflictConvertor());
}
}

132
designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java vendored

@ -1,20 +1,31 @@
package com.fr.env.detect.impl;
import com.fr.common.util.Collections;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.AbstractExceptionDetector;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.exception.DetectorException;
import com.fr.env.detect.bean.ExceptionLog;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.general.build.BuildInfo;
import com.fr.general.build.BuildInfoOperator;
import com.fr.general.build.BuildInfoManager;
import com.fr.stable.StringUtils;
import com.fr.general.build.BuildInfoOperator;
import com.fr.general.build.impl.BuildInfoOperatorImpl;
import com.fr.third.guava.collect.MapDifference;
import com.fr.third.guava.collect.Maps;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.workspace.WorkContext;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -22,53 +33,106 @@ import java.util.stream.Collectors;
**/
public class JarInconsistentDetector extends AbstractExceptionDetector {
public static final String SEPARATOR = ",";
public JarInconsistentDetector() {
super(DetectorType.JAR_IN_CONSISTENCE);
}
/**
* 本地
* 先获取 Designer, 然后对其他的 JAR 信息匹配
* <p>
* 远程
* 两边一一对应匹配
*
* @return 结果
*/
@Override
public DetectorResult detect() {
DetectorResult.DetectorResultBuilder builder = DetectorResult.builder();
// 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包
BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class);
List<BuildInfo> buildInfos = buildInfoOperator.getBuildInfos();
if (WorkContext.getCurrent().isLocal()) {
String designerBuild = buildInfos.stream()
.filter(this::isDesignerJar)
.map(BuildInfo::getGroupBuild)
.filter(StringUtils::isNotEmpty)
.findFirst()
.orElseThrow(DetectorException::new);
List<BuildInfo> inConsistentInfos = buildInfos.stream()
.filter((e) -> !StringUtils.equals(designerBuild, e.getGroupBuild()))
.collect(Collectors.toList());
return detectLocal();
} else {
// 远程情况
List<BuildInfo> localInfos = BuildInfoManager.getInstance().getInfos();
Map<String, String> localMap = groupBy(localInfos);
List<BuildInfo> remoteInfos = buildInfos;
Map<String, String> remoteMap = groupBy(remoteInfos);
MapDifference<String, String> difference = Maps.difference(localMap, remoteMap);
// 两边都有的 JAR 的不同之处
Map<String, String> diffInCommon = difference.entriesInCommon();
return detectLocalAndRemote();
}
}
return builder.build();
@NotNull
private DetectorResult detectLocalAndRemote() {
// 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包
BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class);
List<BuildInfo> buildInfos = buildInfoOperator.getBuildInfos();
// 远程情况
List<BuildInfo> localInfos = BuildInfoManager.getInstance().getInfos();
Map<String, String> localMap = groupBy(localInfos);
List<BuildInfo> remoteInfos = buildInfos;
Map<String, String> remoteMap = groupBy(remoteInfos);
MapDifference<String, String> difference = Maps.difference(localMap, remoteMap);
Map<String, String> diffInCommon = difference.entriesInCommon();
if (diffInCommon.isEmpty()) {
return DetectorResult.normal(type());
}
Set<String> inConsistentJars = diffInCommon.keySet();
String message = StringUtils.join(inConsistentJars, SEPARATOR);
Message.Simple tipsMessage = new Message.Simple(Toolkit.i18nText("Fine_Design_Basic_Detect_Server") + Toolkit.i18nText(type().getTipsLocale()) + message);
return DetectorResult.exception(type(),
new ExceptionTips(tipsMessage),
new ExceptionSolution(new Message.Link(Toolkit.i18nText(type().getSolutionLocale(),DetectorConstants.JAR_HELP_LINK)
, DetectorConstants.JAR_HELP_LINK), null),
ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message));
}
private boolean isDesignerJar(BuildInfo info) {
@NotNull
private DetectorResult detectLocal() {
// 本地的获取方式
BuildInfoOperator operator = new BuildInfoOperatorImpl();
List<BuildInfo> buildInfos = operator.getBuildInfos();
// 获取设计器的 build
Optional<String> designerBuild = buildInfos.stream()
.filter(DetectorUtil::isDesignerJar)
.map(BuildInfo::getGroupBuild)
.filter(StringUtils::isNotEmpty)
.findFirst();
// 如果 build
if (!designerBuild.isPresent()) {
return DetectorResult.normal(type());
}
// 获取所有的不一致的 build
List<BuildInfo> inConsistentInfos = buildInfos.stream()
.filter((e) -> !StringUtils.equals(designerBuild.get(), e.getGroupBuild()))
.collect(Collectors.toList());
// 没有直接返回
if (Collections.isEmpty(inConsistentInfos)) {
return DetectorResult.normal(type());
}
// 有的话
List<String> inConsistentJars = inConsistentInfos.stream()
.map(BuildInfo::getJar)
.collect(Collectors.toList());
String message = StringUtils.join(inConsistentJars, SEPARATOR);
String tipsMessage = Toolkit.i18nText("Fine_Design_Basic_Detect_Local") + Toolkit.i18nText(type().getTipsLocale()) + message;
return StringUtils.contains(info.getJar(), "fine-report-designer");
return DetectorResult.exception(type(),
new ExceptionTips(new Message.Simple(tipsMessage)),
new ExceptionSolution(new Message.Link(Toolkit.i18nText(type().getSolutionLocale()), DetectorConstants.JAR_HELP_LINK), null),
ExceptionLog.create(type().getLogLocale() + message));
}
private Map<String, String> groupBy(List<BuildInfo> localInfos) {

131
designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java vendored

@ -1,43 +1,150 @@
package com.fr.env.detect.impl;
import com.fr.common.util.Collections;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.AbstractExceptionDetector;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionLog;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.general.build.BuildInfo;
import com.fr.general.build.BuildInfoOperator;
import com.fr.stable.StringUtils;
import com.fr.general.build.impl.BuildInfoOperatorImpl;
import com.fr.third.guava.collect.Lists;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.workspace.WorkContext;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* created by Harrison on 2022/05/24
**/
public class JarLackDetector extends AbstractExceptionDetector {
public static final String SEPARATOR = "、";
public static final String BR_TAG = "<br/>";
public static final String WEB_LIB_PATH = "%FR_HOME%\\webapps\\webroot\\WEB-INF\\lib:";
public static final String FR_HOME_LIB = "%FR_HOME%\\lib:";
public JarLackDetector() {
super(DetectorType.LACK_OF_JAR);
}
@Override
public DetectorResult detect() {
DetectorResult.DetectorResultBuilder builder = DetectorResult.builder();
// 不支持远程
if (!WorkContext.getCurrent().isLocal()) {
return DetectorResult.normal(type());
}
// 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包
BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class);
BuildInfoOperator buildInfoOperator = new BuildInfoOperatorImpl();
List<BuildInfo> buildInfos = buildInfoOperator.getBuildInfos();
for (BuildInfo buildInfo : buildInfos) {
String jar = buildInfo.getJar();
String buildContent = buildInfo.getGroupBuild();
boolean isLack = StringUtils.isEmpty(buildContent);
if (isLack) {
// 处理信息
}
List<BuildInfo> lackInfos = buildInfos.stream()
.filter(this::isLackInfo)
.collect(Collectors.toList());
if (Collections.isEmpty(lackInfos)) {
return DetectorResult.normal(type());
}
return builder.build();
Message tipsMsg = tipsMessage(lackInfos);
ExceptionLog exceptionLog = exceptionLog(lackInfos);
return DetectorResult.exception(type(),
new ExceptionTips(tipsMsg),
new ExceptionSolution(
new Message.Link(Toolkit.i18nText(type().getSolutionLocale()), DetectorConstants.JAR_HELP_LINK),
null), exceptionLog);
}
private ExceptionLog exceptionLog(List<BuildInfo> lackInfos) {
List<String> jarInfos = lackInfos.stream()
.map(BuildInfo::getJar)
.collect(Collectors.toList());
String message = StringUtils.join(jarInfos, ",");
return ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message);
}
private boolean isLackInfo(BuildInfo e) {
return StringUtils.isNotEmpty(e.getGroupBuild());
}
private Message tipsMessage(List<BuildInfo> infos) {
String webLibPath = WEB_LIB_PATH;
String homeLibPath = FR_HOME_LIB;
Map<String, List<String>> libMap = groupByPath(infos, homeLibPath, webLibPath);
StringBuilder sb = new StringBuilder();
List<String> homeLibs = libMap.get(homeLibPath);
if (!Collections.isEmpty(homeLibs)) {
sb.append(homeLibPath);
sb.append(StringUtils.join(homeLibs, SEPARATOR));
}
List<String> webLibs = libMap.get(webLibPath);
if (!Collections.isEmpty(webLibs)) {
if (sb.length() != 0) {
sb.append(BR_TAG);
}
sb.append(webLibPath);
sb.append(StringUtils.join(webLibs, SEPARATOR));
}
String mainContent = sb.toString();
DetectorType type = this.type();
String header = Toolkit.i18nText(type.getTipsLocale());
return new Message.Simple(header + mainContent);
}
@NotNull
private Map<String, List<String>> groupByPath(List<BuildInfo> infos, String homeLibPath, String webLibPath) {
Map<String, List<String>> libMap = new HashMap<>();
for (BuildInfo info : infos) {
String key;
if (inHomeLib(info)) {
key = homeLibPath;
} else {
key = webLibPath;
}
libMap.compute(key, (keyA, value) -> {
if (Collections.isEmpty(value)) {
value = Lists.newArrayList(info.getJar());
} else {
value.add(info.getJar());
}
return value;
});
}
return libMap;
}
/**
* %FR_HOME%\lib
* 否则都是在 %FR_HOME%\webapps\webroot\WEB-INF\lib
*
* @param info JAR 信息
* @return 是否位于 HOME\LIB
*/
private boolean inHomeLib(BuildInfo info) {
return DetectorUtil.isDesignerJar(info);
}
}

191
designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java vendored

@ -0,0 +1,191 @@
package com.fr.env.detect.impl.converter;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionLog;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.stable.resource.ResourceLoader;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import javax.el.MethodNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 类抛出异常的转换
* 原则可以找不到但不要误报
*
* created by Harrison on 2022/05/24
**/
public class ClassConflictConvertor implements ThrowableConverter {
public static final String CLASSES = "classes";
public static final String SEPARATOR = "、";
/**
* 获取对应的 JAR 包名称
*/
private static final Pattern JAR_NAME_PATTERN = Pattern.compile("([\\w+-\\.]*\\.jar)");
private final Map<Class<?>, ClassNameConverter> throwableMap = new HashMap<>();
public ClassConflictConvertor() {
// 类异常
this.throwableMap.put(ClassNotFoundException.class, Converter.CLASS);
this.throwableMap.put(NoClassDefFoundError.class, Converter.CLASS);
this.throwableMap.put(ClassCastException.class, Converter.CLASS);
this.throwableMap.put(IncompatibleClassChangeError.class, Converter.CLASS);
// 方法异常
this.throwableMap.put(MethodNotFoundException.class, Converter.METHOD);
this.throwableMap.put(NoSuchMethodException.class, Converter.METHOD);
this.throwableMap.put(NoSuchMethodError.class, Converter.METHOD);
}
@Override
public boolean accept(Throwable throwable) {
Throwable sign = throwable;
while (sign != null) {
if (throwableMap.containsKey(sign.getClass())) {
return true;
}
sign = sign.getCause();
}
return false;
}
@Override
public DetectorResult convert(Throwable throwable) {
Iterable<String> classNames = Collections.emptyList();
Throwable sign = throwable;
while (sign != null) {
if (throwableMap.containsKey(sign.getClass())) {
classNames = throwableMap.get(sign.getClass())
.converter(throwable);
}
sign = sign.getCause();
}
Set<String> allPath = new HashSet<>();
for (String className : classNames) {
String classFile = convertClass2Path(className);
try {
Enumeration<URL> urls = ResourceLoader.getResources(classFile, this.getClass());
List<URL> urlList = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
urlList.add(url);
}
for (URL url : urlList) {
String file = url.getFile();
Matcher matcher = JAR_NAME_PATTERN.matcher(url.getFile());
if (matcher.find()) {
String jar = matcher.group();
allPath.add(jar);
} else {
boolean containsClasses = file.contains(CLASSES);
if (containsClasses) {
allPath.add(CLASSES);
}
}
}
} catch (IOException ignore) {
}
}
String msg = StringUtils.join(allPath, SEPARATOR);
DetectorType type = DetectorType.JAR_CONFLICT;
return DetectorResult.exception(type,
ExceptionTips.create(Toolkit.i18nText(type.getTipsLocale(), msg)),
ExceptionSolution.create(Toolkit.i18nText(type.getSolutionLocale()), DetectorConstants.JAR_HELP_LINK, null),
ExceptionLog.create(Toolkit.i18nText(type.getLogLocale()), msg));
}
@NotNull
private String convertClass2Path(String className) {
return "/" + className.replaceAll("\\.", "/") + ".class";
}
private interface ClassNameConverter {
/**
* 将异常解析为类名可能有多个
*
* @param throwable 异常
* @return 类名
*/
Iterable<String> converter(Throwable throwable);
}
public enum Converter implements ClassNameConverter {
/**
* 类匹配
*/
CLASS {
/**
* 匹配 111.222.333
* 至少有一个 111.
* 至少有一个 333
*/
private final Pattern CLASS_PATTERN = Pattern.compile("((\\w+\\.)+(\\w+))");
@Override
public Iterable<String> converter(Throwable throwable) {
String message = throwable.getMessage();
Matcher matcher = CLASS_PATTERN.matcher(message);
List<String> names = new ArrayList<>();
while (matcher.find()) {
String className = matcher.group();
names.add(className);
}
return names;
}
},
/**
* 方法匹配
*/
METHOD {
/**
* 后面有 .method()xxxx
*/
private final Pattern METHOD_PATTERN = Pattern.compile("((\\w+\\.)+(\\w+))(\\.\\w+\\(\\))");
@Override
public Iterable<String> converter(Throwable throwable) {
String message = throwable.getMessage();
Matcher matcher = METHOD_PATTERN.matcher(message);
List<String> names = new ArrayList<>();
while (matcher.find()) {
String className = matcher.group();
names.add(className);
}
return names;
}
}
}
}

53
designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassThrowableConvertor.java vendored

@ -1,53 +0,0 @@
package com.fr.env.detect.impl.converter;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.thowable.ThrowableConverter;
import javax.el.MethodNotFoundException;
import java.util.HashSet;
import java.util.Set;
/**
* 类抛出异常的转换
* created by Harrison on 2022/05/24
**/
public class ClassThrowableConvertor implements ThrowableConverter {
private Set<Class<?>> throwableClassSet = new HashSet<>();
private Set<Class<?>> throwableMethodSet = new HashSet<>();
public ClassThrowableConvertor() {
// 类异常
this.throwableClassSet.add(ClassNotFoundException.class);
this.throwableClassSet.add(NoClassDefFoundError.class);
this.throwableClassSet.add(ClassCastException.class);
this.throwableClassSet.add(IncompatibleClassChangeError.class);
// 方法异常
this.throwableMethodSet.add(MethodNotFoundException.class);
this.throwableMethodSet.add(NoSuchMethodException.class);
this.throwableMethodSet.add(NoSuchMethodError.class);
}
@Override
public boolean accept(Throwable throwable) {
Throwable sign = throwable;
while (sign != null) {
if (throwableClassSet.contains(sign.getClass()) || throwableMethodSet.contains(sign.getClass())) {
return true;
}
sign = sign.getCause();
}
return false;
}
@Override
public DetectorResult convert(Throwable throwable) {
// todo
return null;
}
}

85
designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbDirtyConverter.java vendored

@ -1,11 +1,29 @@
package com.fr.env.detect.impl.converter;
import com.fr.config.ConfigContext;
import com.fr.config.Configuration;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.Message;
import com.fr.env.detect.bean.SolutionAction;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.io.utils.ResourceIOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StableUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.third.org.hibernate.exception.GenericJDBCException;
import org.jetbrains.annotations.Nullable;
import javax.swing.JOptionPane;
import java.util.Iterator;
/**
* 脏数据检测
*
* created by Harrison on 2022/05/25
**/
public class FineDbDirtyConverter implements ThrowableConverter {
@ -15,7 +33,7 @@ public class FineDbDirtyConverter implements ThrowableConverter {
Throwable sign = throwable;
while (sign != null) {
if (sign instanceof GenericJDBCException) {
if (sign.getClass() == GenericJDBCException.class) {
return true;
}
sign = sign.getCause();
@ -23,11 +41,70 @@ public class FineDbDirtyConverter implements ThrowableConverter {
return false;
}
/**
* 根据堆栈确认是否是从配置中发出来的异常
* 如果是则找到对应的配置的表
* 输出信息
*
* @param throwable 异常
* @return 检测结果
*/
@Override
public @Nullable DetectorResult convert(Throwable throwable) {
Iterator<String> tableNames = ConfigContext.getConfigNames();
while (tableNames.hasNext()) {
String tableName = tableNames.next();
Class<? extends Configuration> configClass = ConfigContext.getConfigClass(tableName);
Configuration configuration = ConfigContext.getConfigInstance(configClass);
try {
// 尝试获取每一个值
configuration.mirror();
} catch (Throwable e) {
DetectorType detectorType = DetectorType.FINE_DB_DIRTY;
DetectorResult.DetectorResultBuilder builder = DetectorResult.builder()
.withType(detectorType);
String tipsLocale = Toolkit.i18nText(detectorType.getTipsLocale(), tableName);
String solutionLocale = detectorType.getSolutionLocale();
ExceptionSolution exceptionSolution = new ExceptionSolution(new Message.Link(Toolkit.i18nText(solutionLocale, DetectorConstants.FINE_DB_HELP_LINK), DetectorConstants.FINE_DB_HELP_LINK), new SolutionAction() {
@Override
public String name() {
return Toolkit.i18nText("Fine-Design_Basic_Reset_Immediately");
}
// 检测 Config
// todo
return null;
@Override
public void run() {
boolean success = false;
try {
ResourceIOUtils.copy(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME),
StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_BAK_NAME));
success = ResourceIOUtils.delete(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
// todo 最好的逻辑是,这里应该和 UI 隔离开的
if (!success) {
FineJOptionPane.showMessageDialog(null,
Toolkit.i18nText("Fine-Design_Error_Finedb_Backup_Reset_Result",
ResourceIOUtils.getRealPath(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME))),
Toolkit.i18nText("Fine-Design_Basic_Error"),
JOptionPane.ERROR_MESSAGE);
}
}
});
builder.withTips(tipsLocale)
.withSolution(exceptionSolution)
.withLog(Toolkit.i18nText(detectorType.getLogLocale(), tableName));
return builder.build();
}
}
return DetectorResult.normal(DetectorType.FINE_DB_DIRTY);
}
}

32
designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java vendored

@ -1,7 +1,11 @@
package com.fr.env.detect.impl.converter;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.third.org.hsqldb.HsqlException;
/**
@ -9,12 +13,14 @@ import com.fr.third.org.hsqldb.HsqlException;
**/
public class FineDbLockedConverter implements ThrowableConverter {
public static final String LOCK_FILE = "lockFile";
@Override
public boolean accept(Throwable throwable) {
Throwable sign = throwable;
while (sign != null) {
if (sign instanceof HsqlException) {
if (sign.getClass() == HsqlException.class) {
return true;
}
sign = sign.getCause();
@ -22,10 +28,32 @@ public class FineDbLockedConverter implements ThrowableConverter {
return false;
}
/**
* 检测 FineDB 是否锁住
*
* @param throwable 异常
* @return 结果
*/
@Override
public DetectorResult convert(Throwable throwable) {
// todo
Throwable sign = throwable;
while (sign.getClass() != HsqlException.class) {
sign = sign.getCause();
}
DetectorType type = DetectorType.FINE_DB_LOCKED;
String message = sign.getMessage();
if (StringUtils.containsIgnoreCase(message, LOCK_FILE)) {
return DetectorResult.builder()
.withType(type)
.withTips(Toolkit.i18nText(type.getTipsLocale()))
.withSolution(Toolkit.i18nText(type.getSolutionLocale(),DetectorConstants.FINE_DB_HELP_LINK), DetectorConstants.FINE_DB_HELP_LINK)
.withLog(Toolkit.i18nText(type.getLogLocale()))
.build();
}
return null;
}
}

26
designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java vendored

@ -1,7 +1,11 @@
package com.fr.env.detect.impl.converter;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.third.org.hsqldb.HsqlException;
/**
@ -11,12 +15,14 @@ import com.fr.third.org.hsqldb.HsqlException;
**/
public class FineDbPermissionConverter implements ThrowableConverter {
public static final String PERMISSION = "permission";
@Override
public boolean accept(Throwable throwable) {
Throwable sign = throwable;
while (sign != null) {
if (sign instanceof HsqlException) {
if (sign.getClass() == HsqlException.class) {
return true;
}
sign = sign.getCause();
@ -27,7 +33,23 @@ public class FineDbPermissionConverter implements ThrowableConverter {
@Override
public DetectorResult convert(Throwable throwable) {
// todo
Throwable sign = throwable;
while (sign.getClass() != HsqlException.class) {
sign = sign.getCause();
}
DetectorType type = DetectorType.FINE_DB_PERMISSION;
String message = sign.getMessage();
if (StringUtils.containsIgnoreCase(message, PERMISSION)) {
return DetectorResult.builder()
.withType(type)
.withTips(Toolkit.i18nText(type.getTipsLocale()))
.withSolution(Toolkit.i18nText(type.getSolutionLocale(), DetectorConstants.FINE_DB_HELP_LINK),
DetectorConstants.FINE_DB_HELP_LINK)
.withLog(type.getLogLocale())
.build();
}
return null;
}
}

17
designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java vendored

@ -25,24 +25,33 @@ public class ThrowableLogAppender extends AbstractAppender {
}
private static class ExceptionLogAppenderHolder {
private static final ThrowableLogAppender INSTANCE = new ThrowableLogAppender("exception-detect", null, null, false, null);
private static final ThrowableLogAppender INSTANCE = new ThrowableLogAppender("exception-detect-appender", null, null, false, null);
}
private LogHandler<ThrowableLogAppender> logHandler = toHandler();
private final LogHandler<ThrowableLogAppender> logHandler = toHandler();
@Override
public void append(LogEvent logEvent) {
if (logEvent.getLevel() == Level.ERROR) {
Throwable thrown = logEvent.getThrown();
ThrowableStore.getInstance().add(thrown);
if (thrown != null) {
ThrowableStore.getInstance().add(thrown);
}
}
}
private LogHandler<ThrowableLogAppender> toHandler() {
final ThrowableLogAppender appender = this;
return () -> appender;
appender.start();
LogHandler<ThrowableLogAppender> handler = new LogHandler<ThrowableLogAppender>() {
@Override
public ThrowableLogAppender getHandler() {
return appender;
}
};
return handler;
}

135
designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java vendored

@ -0,0 +1,135 @@
package com.fr.env.detect.ui;
import com.fr.design.RestartHelper;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.utils.ColorUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.exit.DesignerExiter;
import com.fr.general.FRFont;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* 未知错误框
* todo 其实这里可以将多个 error-dialog 抽象在一起的 时间不够 简单写写
* {@link com.fr.design.dialog.ErrorDialog}
*
* created by Harrison on 2022/05/29
**/
public class DetectorErrorDialog extends JDialog implements ActionListener {
private UIButton okButton;
private UIButton restartButton;
public DetectorErrorDialog(Frame parent, List<DetectorResult> results) {
super(parent, true);
JPanel northPane = FRGUIPaneFactory.createBorderLayout_L_Pane();
JPanel messagePane = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true);
UILabel boldHeader = new UILabel(Toolkit.i18nText("Fine-Design_Error_Start_Apology_Message"));
Font font = FRFont.getInstance(boldHeader.getFont().getFontName(), Font.BOLD, 20);
boldHeader.setFont(font);
messagePane.add(boldHeader);
UILabel description = new UILabel(Toolkit.i18nText("Fine-Design_Send_Report_To_Us"));
messagePane.add(description);
northPane.add(messagePane);
JPanel centerPane = FRGUIPaneFactory.createBorderLayout_L_Pane();
UILabel detailDesc = new UILabel(Toolkit.i18nText("Fine-Design_Problem_Detail_Message"));
centerPane.add(detailDesc, BorderLayout.NORTH);
JPanel detailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
detailPanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 10, 10));
for (DetectorResult result : results) {
ExceptionTips tips = result.getTips();
if (tips != null) {
Message tipsMsg = tips.getMessage();
detailPanel.add(DetectorUtil.convert2TextComponent(tipsMsg), BorderLayout.NORTH);
}
ExceptionSolution solution = result.getSolution();
if (solution != null) {
Message solutionMsg = solution.getMessage();
detailPanel.add(DetectorUtil.convert2TextComponent(solutionMsg), BorderLayout.CENTER);
}
}
JScrollPane detailPanelWrapper = new JScrollPane(detailPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
ColorUtils.syncBackground(detailPanelWrapper, Color.WHITE);
centerPane.add(detailPanelWrapper, BorderLayout.CENTER);
JPanel southPane = FRGUIPaneFactory.createBorderLayout_L_Pane();
JPanel controlPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
okButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Ok"));
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
okEvent();
}
});
buttonPane.add(okButton);
restartButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Restart"));
restartButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
restartEvent();
}
});
buttonPane.add(restartButton);
controlPane.add(buttonPane, BorderLayout.EAST);
southPane.add(controlPane);
this.setTitle(Toolkit.i18nText("Fine-Design_Error_Start_Report"));
this.setResizable(false);
this.add(northPane, BorderLayout.NORTH);
this.add(centerPane, BorderLayout.CENTER);
this.add(southPane, BorderLayout.SOUTH);
this.setSize(new Dimension(600, 500));
GUICoreUtils.centerWindow(this);
}
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
protected void okEvent() {
dispose();
DesignerExiter.getInstance().execute();
}
protected void restartEvent() {
dispose();
RestartHelper.restart();
}
}

28
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java vendored

@ -0,0 +1,28 @@
package com.fr.env.detect.ui;
import com.fr.design.actions.UpdateAction;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import java.awt.event.ActionEvent;
/**
* 工具栏里面的行为
*
* created by Harrison on 2022/05/29
**/
public class EnvDetectorAction extends UpdateAction {
public EnvDetectorAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Detect_Toolbar_Title"));
this.setSmallIcon("com/fr/env/detect/detect_normal.svg");
}
@Override
public void actionPerformed(ActionEvent e) {
EnvDetectorDialog dialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame());
dialog.setVisible(true);
}
}

494
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java vendored

@ -0,0 +1,494 @@
package com.fr.env.detect.ui;
import com.fr.base.svg.IconUtils;
import com.fr.design.components.notification.NotificationDialog;
import com.fr.design.components.notification.NotificationDialogProperties;
import com.fr.design.components.notification.NotificationModel;
import com.fr.design.components.table.TablePanel;
import com.fr.design.constants.DesignerColor;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ibutton.UIButtonUI;
import com.fr.design.gui.icheckbox.UICheckBox;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.utils.gui.GUIPaintUtils;
import com.fr.env.detect.base.DetectorBridge;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.base.EnvDetectorConfig;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorStatus;
import com.fr.env.detect.bean.DetectorType;
import org.jetbrains.annotations.NotNull;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.plaf.ButtonUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* created by Harrison on 2022/05/26
**/
public class EnvDetectorDialog extends JDialog {
private static final ImageIcon LOADING_ICON = getLoadingIcon();
public static final int TIMEOUT = 1000;
private JPanel body;
private final JPanel headerPanel;
private final TablePanel tablePanel;
private final JPanel tailPanel;
/* 数据 model */
private EnvDetectorModel model;
/* 流程 model */
/**
* 默认是第一个要检测
*/
private int currentDetectIndex = 0;
private EnvDetectorButtonStatus buttonStatus = EnvDetectorButtonStatus.START;
private SwingWorker<Void, Void> detectWorker = null;
/* config model */
private boolean detectOpen = EnvDetectorConfig.getInstance().isEnabled();
public EnvDetectorDialog(Frame owner) {
this(owner, null);
}
public EnvDetectorDialog(Frame owner, EnvDetectorModel model) {
super(owner);
configProperties();
if (model == null) {
this.model = new EnvDetectorModel();
} else {
this.model = model;
}
this.body = FRGUIPaneFactory.createBorderLayout_L_Pane();
Color backgroundColor = new Color(240, 240, 243, 1);
this.body.setBackground( backgroundColor);
this.headerPanel = createHeaderPanel();
body.add(headerPanel, BorderLayout.NORTH);
this.tablePanel = createTablePanel();
body.add(tablePanel, BorderLayout.CENTER);
/* tailPanel*/
this.tailPanel = createTailPanel();
body.add(tailPanel, BorderLayout.SOUTH);
add(body);
Dimension preferredSize = body.getPreferredSize();
setSize(preferredSize);
repaint();
pack();
GUICoreUtils.centerWindow(this);
}
/* header */
@NotNull
private JPanel createHeaderPanel() {
JPanel headerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
headerPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 12, 0));
UIButton detectButton = new UIButton(buttonStatus.getDesc()) {
@Override
public ButtonUI getUI() {
return new UIButtonUI() {
@Override
protected void doExtraPainting(UIButton b, Graphics2D g2d, int w, int h, String selectedRoles) {
if (isPressed(b) && b.isPressedPainted()) {
GUIPaintUtils.fillPressed(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles),
DesignerColor.Button.Primary.PRESSED);
} else if (isRollOver(b)) {
GUIPaintUtils.fillRollOver(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles), b.isPressedPainted(),
DesignerColor.Button.Primary.HOVER);
} else if (b.isNormalPainted()) {
GUIPaintUtils.fillNormal(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles), b.isPressedPainted(),
DesignerColor.Button.Primary.NORMAL);
}
}
};
}
};
detectButton.setForeground(Color.WHITE);
detectButton.addActionListener(event -> {
if (buttonStatus.isNotExecuting()) {
startDetecting(detectButton);
} else {
stopDetecting(detectButton);
}
});
detectButton.setPreferredSize(new Dimension(68, 20));
detectButton.setBorderPainted(false);
detectButton.setContentAreaFilled(false);
headerPanel.add(detectButton, BorderLayout.WEST);
return headerPanel;
}
private void startDetecting(UIButton detectButton) {
// 执行前
buttonStatus = buttonStatus.next();
UIUtil.invokeLaterIfNeeded(() -> detectButton.setText(buttonStatus.getDesc()));
detectWorker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
List<EnvDetectorItem> items = model.getItems();
// 执行刷新
for (int i = currentDetectIndex; i < items.size(); i++) {
// 看一下是否关闭了, 有可能已经关闭了。
if (buttonStatus.isNotExecuting()) {
return null;
}
// 刷新一下面板-开始执行啦
UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refresh);
EnvDetectorItem item = items.get(i);
DetectorType type = item.getType();
// 执行检测, UI-当前在检测中
DetectorResult result = UIUtil.waitUntil(
() -> DetectorBridge.getInstance().detect(type),
TIMEOUT, TimeUnit.MILLISECONDS);
// 获取结果
item.setResult(result);
// 更新UI
// 只有还在运行中,才会真正的刷新面板
if (buttonStatus.isExecuting()) {
// 在刷新一下面板
UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refresh);
currentDetectIndex++;
}
}
return null;
}
@Override
protected void done() {
if (buttonStatus.isExecuting()) {
// 执行结束
buttonStatus = EnvDetectorButtonStatus.A_NEW;
UIUtil.invokeLaterIfNeeded(() -> detectButton.setText(buttonStatus.getDesc()));
}
}
};
// 开始执行
detectWorker.execute();
}
private void stopDetecting(UIButton detectButton) {
buttonStatus = buttonStatus.next();
// 先停止
detectWorker.cancel(false);
// 更改-UI
// 执行中
UIUtil.invokeLaterIfNeeded(() -> {
// 刷新按钮
detectButton.setText(buttonStatus.getDesc());
// 刷新面板
refresh();
});
}
/* table */
@NotNull
private TablePanel createTablePanel() {
TablePanel tablePanel = new TablePanel(18, 3);
tablePanel.updateHeaders(new String[] {
Toolkit.i18nText("Fine-Design_Basic_Detect_Kind"),
Toolkit.i18nText("Fine-Design_Basic_Detect_Item"),
Toolkit.i18nText("Fine-Design_Basic_Detect_Result")});
updateTable(tablePanel);
return tablePanel;
}
private void updateTable(TablePanel tablePanel) {
Map<DetectorType.Kind, List<EnvDetectorItem>> itemMap = model.getItemMap();
// 行号, 这边更新是通过 行/列 。 不是索引
int row = 1;
for (Map.Entry<DetectorType.Kind, List<EnvDetectorItem>> entry : itemMap.entrySet()) {
DetectorType.Kind kind = entry.getKey();
List<EnvDetectorItem> items = entry.getValue();
for (int i = 0; i < items.size(); i++) {
if (i == 0) {
tablePanel.updateCell(row, 1, kind.getDescription());
}
EnvDetectorItem item = items.get(i);
tablePanel.updateCell(row, 2, new UILabel(item.getDescription()));
DetectorResult result = item.getResult();
int detectRow = currentDetectIndex + 1;
if (result == null) {
// 处于非正在检测状态 或者 索引不等于当前行号的时候
UILabel label;
if (buttonStatus.isExecuting() && detectRow == row) {
// 正在检测索引
label = new UILabel(LOADING_ICON, UILabel.LEADING);
} else {
label = new UILabel("-");
}
tablePanel.updateCell(row, 3, label);
} else {
Component resultComponent = createResultComponent(result);
tablePanel.updateCell(row, 3, resultComponent);
}
row++;
}
}
}
private Component createResultComponent(DetectorResult result) {
JPanel statusPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
if (result.getStatus() == DetectorStatus.NORMAL) {
statusPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_success.svg")), BorderLayout.WEST);
statusPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Normal")), BorderLayout.CENTER);
} else {
JPanel infoPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
{
infoPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_error.svg")), BorderLayout.WEST);
infoPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Exception")), BorderLayout.CENTER);
}
statusPanel.add(infoPanel, BorderLayout.WEST);
JPanel detailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
{
detailPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
UILabel detailLabel = new UILabel(Toolkit.i18nText("Fine_Designer_Look_Detail"));
detailLabel.setForeground(new Color(65, 155, 249));
detailLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
NotificationDialogProperties properties = new NotificationDialogProperties((Frame) EnvDetectorDialog.this.getOwner(), Toolkit.i18nText("Fine-Design_Basic_Detect_Notification_Title"));
Stream<DetectorResult> results = model.getResults();
List<NotificationModel> notificationModels = results
.filter(Objects::nonNull)
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.map(DetectorUtil::convert2Notification)
.collect(Collectors.toList());
NotificationDialog dialog = new NotificationDialog(properties, notificationModels);
dialog.open();
}
});
detailPanel.add(detailLabel, BorderLayout.CENTER);
}
statusPanel.add(detailPanel, BorderLayout.CENTER);
}
return statusPanel;
}
/* tail */
@NotNull
private JPanel createTailPanel() {
JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
tailPanel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0));
JPanel configPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
{
UICheckBox checkBox = new UICheckBox();
checkBox.setSelected(this.detectOpen);
checkBox.addChangeListener(e -> {
UICheckBox source = (UICheckBox) e.getSource();
EnvDetectorDialog.this.detectOpen = source.isSelected();
});
configPanel.add(checkBox, BorderLayout.WEST);
UILabel description = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Switch"));
configPanel.add(description, BorderLayout.EAST);
}
tailPanel.add(configPanel, BorderLayout.WEST);
JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout());
{
UIButton confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm"));
confirmButton.addActionListener((e) -> {
setVisible(false);
dispose();
// 配置处理
EnvDetectorConfig.getInstance().setEnabled(this.detectOpen);
});
actionsPanel.add(confirmButton, BorderLayout.WEST);
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.addActionListener((e) -> {
setVisible(false);
dispose();
});
actionsPanel.add(cancelButton, BorderLayout.EAST);
}
tailPanel.add(actionsPanel, BorderLayout.EAST);
return tailPanel;
}
private void refresh() {
updateTable(this.tablePanel);
pack();
repaint();
}
private static ImageIcon getLoadingIcon() {
URL resource = EnvDetectorDialog.class.getResource("/com/fr/design/standard/loading/loading-120.gif");
if (resource == null) {
return null;
}
ImageIcon loadingIcon = new ImageIcon(resource);
int width = 16;
int height = 16;
loadingIcon.setImage(loadingIcon.getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT));
return loadingIcon;
}
private void configProperties() {
setTitle(Toolkit.i18nText("Fine-Design_Basic_Detect_Title"));
setModal(false);
setFocusable(false);
setAutoRequestFocus(false);
setResizable(false);
}
/**
* 按钮的当前状态
*/
private enum EnvDetectorButtonStatus {
/**
* 开始 -> 停止
*/
START("Fine-Design_Basic_Detect_Start") {
@Override
public EnvDetectorButtonStatus next() {
return STOP;
}
},
/**
* 停止 -> 继续
*/
STOP("Fine-Design_Basic_Detect_Stop") {
@Override
public EnvDetectorButtonStatus next() {
return CONTINUE;
}
},
/**
* 继续 -> 停止
*/
CONTINUE("Fine-Design_Basic_Detect_Continue") {
@Override
public EnvDetectorButtonStatus next() {
return STOP;
}
},
/**
* 重新 -> 停止
*/
A_NEW("Fine-Design_Basic_Detect_A_New") {
@Override
public EnvDetectorButtonStatus next() {
return STOP;
}
}
;
private String descLocale;
EnvDetectorButtonStatus(String descLocale) {
this.descLocale = descLocale;
}
public String getDesc() {
return Toolkit.i18nText(descLocale);
}
/**
* 在执行中
*
* @return /
*/
public boolean isExecuting() {
return this == EnvDetectorButtonStatus.STOP;
};
/**
* 不在执行中
*
* @return /
*/
public boolean isNotExecuting() {
return !isExecuting();
}
public abstract EnvDetectorButtonStatus next();
}
}

40
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java vendored

@ -0,0 +1,40 @@
package com.fr.env.detect.ui;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
/**
* 环境检测条目
*
* created by Harrison on 2022/05/27
**/
public class EnvDetectorItem {
private DetectorType type;
private DetectorResult result;
public EnvDetectorItem(DetectorType detectorType) {
this.type = detectorType;
}
public DetectorType getType() {
return type;
}
public String getKind() {
return this.type.getKind().getDescription();
}
public String getDescription() {
return this.type.getDescription();
}
public DetectorResult getResult() {
return result;
}
public void setResult(DetectorResult result) {
this.result = result;
}
}

70
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java vendored

@ -0,0 +1,70 @@
package com.fr.env.detect.ui;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.third.guava.collect.Lists;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 环境检测数据格式
*
* created by Harrison on 2022/05/27
**/
public class EnvDetectorModel {
/**
* 类型 -> list [{type-result}]
*/
private final Map<DetectorType.Kind, List<EnvDetectorItem>> itemMap = new LinkedHashMap<>();
public EnvDetectorModel() {
itemMap.put(DetectorType.Kind.JAR, Lists.newArrayList(
new EnvDetectorItem(DetectorType.LACK_OF_JAR),
new EnvDetectorItem(DetectorType.JAR_IN_CONSISTENCE),
new EnvDetectorItem(DetectorType.JAR_CONFLICT)));
itemMap.put(DetectorType.Kind.FINE_DB, Lists.newArrayList(
new EnvDetectorItem(DetectorType.FINE_DB_LOCKED),
new EnvDetectorItem(DetectorType.FINE_DB_PERMISSION),
new EnvDetectorItem(DetectorType.FINE_DB_DIRTY)));
}
public void update(DetectorType type, DetectorResult result) {
List<EnvDetectorItem> items = itemMap.get(type.getKind());
items.stream()
.filter((e) -> e.getType() == type)
.findFirst()
.ifPresent((e) -> {
e.setResult(result);
});
}
public Stream<DetectorResult> getResults() {
return getItems().stream()
.map(EnvDetectorItem::getResult);
}
public List<EnvDetectorItem> getItems() {
return itemMap.values().stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
public Map<DetectorType.Kind, List<EnvDetectorItem>> getItemMap() {
return this.itemMap;
}
}

61
designer-base/src/main/java/com/fr/exit/DesignerExiter.java

@ -1,10 +1,24 @@
package com.fr.exit;
import com.fr.common.util.Collections;
import com.fr.design.RestartHelper;
import com.fr.design.dialog.ErrorDialog;
import com.fr.design.env.DesignerWorkspaceGenerator;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrame;
import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector;
import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage;
import com.fr.design.monitor.DesignerLifecycleMonitorContext;
import com.fr.env.detect.EnvDetectorCenter;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.ui.DetectorErrorDialog;
import com.fr.log.FineLoggerFactory;
import com.fr.process.engine.core.FineProcessContext;
import com.fr.process.engine.core.FineProcessEngineEvent;
import java.util.List;
/**
* @author hades
* @version 10.0
@ -17,7 +31,52 @@ public class DesignerExiter {
public static DesignerExiter getInstance() {
return INSTANCE;
}
public void exit(Throwable throwable) {
FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable);
StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(),
DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(),
throwable.getMessage());
// 尝试进行检测
List<DetectorResult> results = EnvDetectorCenter.getInstance().terminate(throwable);
if (Collections.isEmpty(results)) {
// 为空,则
showOldExitDialog(throwable);
} else {
showNewExitDialog(results);
}
}
private void showNewExitDialog(List<DetectorResult> results) {
DesignerFrame designerFrame = DesignerContext.getDesignerFrame();
DetectorErrorDialog errorDialog = new DetectorErrorDialog(designerFrame, results);
errorDialog.setVisible(true);
}
private void showOldExitDialog(Throwable throwable) {
ErrorDialog dialog = new ErrorDialog(null, Toolkit.i18nText("Fine-Design_Error_Start_Apology_Message"),
Toolkit.i18nText("Fine-Design_Error_Start_Report"),
throwable.getMessage()) {
@Override
protected void okEvent() {
dispose();
DesignerExiter.getInstance().execute();
}
@Override
protected void restartEvent() {
dispose();
RestartHelper.restart();
}
};
dialog.setVisible(true);
}
public void execute() {
DesignerLifecycleMonitorContext.getMonitor().beforeStop();
beforeExit();

3
designer-base/src/main/java/com/fr/start/BaseDesigner.java

@ -32,7 +32,6 @@ import com.fr.process.ProcessEventPipe;
import com.fr.process.engine.core.CarryMessageEvent;
import com.fr.process.engine.core.FineProcessContext;
import com.fr.stable.OperatingSystem;
import com.fr.start.event.LazyStartupEvent;
import com.fr.workspace.base.WorkspaceStatus;
@ -138,7 +137,7 @@ public abstract class BaseDesigner extends ToolBarMenuDock {
if (!isException) {
showDesignerFrame(true);
} else {
DesignerExiter.getInstance().execute();
DesignerExiter.getInstance().exit(e);
}
}
}

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.70711 8L10.3536 11.6464C10.5488 11.8417 10.5488 12.1583 10.3536 12.3536C10.1583 12.5488 9.84171 12.5488 9.64645 12.3536L5.64645 8.35355C5.45118 8.15829 5.45118 7.84171 5.64645 7.64645L9.64645 3.64645C9.84171 3.45118 10.1583 3.45118 10.3536 3.64645C10.5488 3.84171 10.5488 4.15829 10.3536 4.35355L6.70711 8Z" fill="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.29289 8L5.64645 11.6464C5.45118 11.8417 5.45118 12.1583 5.64645 12.3536C5.84171 12.5488 6.15829 12.5488 6.35355 12.3536L10.3536 8.35355C10.5488 8.15829 10.5488 7.84171 10.3536 7.64645L6.35355 3.64645C6.15829 3.45118 5.84171 3.45118 5.64645 3.64645C5.45118 3.84171 5.45118 4.15829 5.64645 4.35355L9.29289 8Z" fill="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.70711 8L10.3536 11.6464C10.5488 11.8417 10.5488 12.1583 10.3536 12.3536C10.1583 12.5488 9.84171 12.5488 9.64645 12.3536L5.64645 8.35355C5.45118 8.15829 5.45118 7.84171 5.64645 7.64645L9.64645 3.64645C9.84171 3.45118 10.1583 3.45118 10.3536 3.64645C10.5488 3.84171 10.5488 4.15829 10.3536 4.35355L6.70711 8Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.29289 8L5.64645 11.6464C5.45118 11.8417 5.45118 12.1583 5.64645 12.3536C5.84171 12.5488 6.15829 12.5488 6.35355 12.3536L10.3536 8.35355C10.5488 8.15829 10.5488 7.84171 10.3536 7.64645L6.35355 3.64645C6.15829 3.45118 5.84171 3.45118 5.64645 3.64645C5.45118 3.84171 5.45118 4.15829 5.64645 4.35355L9.29289 8Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

BIN
designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

4
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg

@ -0,0 +1,4 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.6886 8.16379C15.6886 12.0057 12.5493 15.1208 8.67764 15.1208C4.80595 15.1208 1.66669 12.0057 1.66669 8.16379C1.66669 4.32189 4.80595 1.20679 8.67764 1.20679C12.5493 1.20679 15.6886 4.32189 15.6886 8.16379Z" fill="#EB1D1F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5105 6.19599C11.7451 5.96312 11.7451 5.58555 11.5105 5.35268C11.2758 5.1198 10.8953 5.1198 10.6606 5.35268L8.67761 7.32041L6.69461 5.35268C6.45993 5.1198 6.07944 5.1198 5.84476 5.35268C5.61008 5.58555 5.61008 5.96312 5.84476 6.19599L7.82776 8.16373L5.84476 10.1315C5.61008 10.3643 5.61008 10.7419 5.84476 10.9748C6.07944 11.2077 6.45993 11.2077 6.69461 10.9748L8.67761 9.00705L10.6606 10.9748C10.8953 11.2077 11.2758 11.2077 11.5105 10.9748C11.7451 10.7419 11.7451 10.3643 11.5105 10.1315L9.52747 8.16373L11.5105 6.19599Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 971 B

3
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg

@ -0,0 +1,3 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.67764 15.4156C12.5493 15.4156 15.6886 12.3005 15.6886 8.45859C15.6886 4.61669 12.5493 1.50159 8.67764 1.50159C4.80595 1.50159 1.66669 4.61669 1.66669 8.45859C1.66669 12.3005 4.80595 15.4156 8.67764 15.4156ZM4.86229 8.12204C5.10492 7.89732 5.48519 7.91034 5.71164 8.1511L7.60931 10.1687L11.844 5.66646C12.0704 5.42569 12.4507 5.41268 12.6933 5.63739C12.9359 5.8621 12.9491 6.23945 12.7226 6.48021L8.04863 11.4495C7.81105 11.7021 7.40756 11.7021 7.16999 11.4495L4.833 8.96485C4.60655 8.72409 4.61966 8.34675 4.86229 8.12204Z" fill="#16C153"/>
</svg>

After

Width:  |  Height:  |  Size: 696 B

5
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 8C15 11.8656 11.8656 15 8 15C4.13435 15 1 11.8656 1 8C1 4.13435 4.13435 1 8 1C11.8656 1 15 4.13435 15 8Z" fill="#FAAA39"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.43333 10.292C7.27777 10.4476 7.2 10.6365 7.2 10.8587C7.2 11.0809 7.27777 11.2698 7.43333 11.4254C7.58889 11.5809 7.77777 11.6587 8 11.6587C8.22222 11.6587 8.41111 11.5809 8.56666 11.4254C8.72222 11.2698 8.8 11.0809 8.8 10.8587C8.8 10.6365 8.72222 10.4476 8.56666 10.292C8.41111 10.1365 8.22222 10.0587 8 10.0587C7.77777 10.0587 7.58889 10.1365 7.43333 10.292Z" fill="white"/>
<rect x="7.3" y="4.22132" width="1.4" height="5" rx="0.7" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 780 B

3
designer-base/src/main/resources/com/fr/env/detect/detect.svg vendored

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2H14.5V5H1.5V2ZM1.5 6L1.5 14H14.5V6H1.5ZM15.5 6V14C15.5 14.5523 15.0523 15 14.5 15H1.5C0.947715 15 0.5 14.5523 0.5 14V2C0.5 1.44772 0.947715 1 1.5 1H14.5C15.0523 1 15.5 1.44772 15.5 2V5V6ZM6.67926 6.87216L7.10381 7.79011L8.53859 10.8923L9.06189 9.94086L9.20436 9.68182H9.5H12.5H13V10.6818H12.5H9.79564L8.93811 12.241L8.46141 13.1077L8.04619 12.2099L6.62074 9.12784L5.94232 10.415L5.80166 10.6818H5.5H3.5H3V9.68182H3.5H5.19834L6.20768 7.76686L6.67926 6.87216ZM3.5 3H2.5V4H3.5V3ZM4 3H5V4H4V3ZM6.5 3H5.5V4H6.5V3Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 685 B

3
designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg vendored

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2H14.5V5H1.5V2ZM1.5 6L1.5 14H14.5V6H1.5ZM15.5 6V14C15.5 14.5523 15.0523 15 14.5 15H1.5C0.947715 15 0.5 14.5523 0.5 14V2C0.5 1.44772 0.947715 1 1.5 1H14.5C15.0523 1 15.5 1.44772 15.5 2V5V6ZM6.67926 6.87216L7.10381 7.79011L8.53859 10.8923L9.06189 9.94086L9.20436 9.68182H9.5H12.5H13V10.6818H12.5H9.79564L8.93811 12.241L8.46141 13.1077L8.04619 12.2099L6.62074 9.12784L5.94232 10.415L5.80166 10.6818H5.5H3.5H3V9.68182H3.5H5.19834L6.20768 7.76686L6.67926 6.87216ZM3.5 3H2.5V4H3.5V3ZM4 3H5V4H4V3ZM6.5 3H5.5V4H6.5V3Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 685 B

43
designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java

@ -0,0 +1,43 @@
package com.fr.design.components.notification;
import com.fr.design.utils.DevUtils;
import com.fr.third.guava.collect.Lists;
import java.awt.Frame;
import java.util.function.Consumer;
public class NotificationDialogTest {
public static void main(String[] args) {
testShow();
}
public static void testShow() {
DevUtils.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
NotificationModel model1 = new NotificationModel(NotificationType.WARNING, null, new NotificationMessage.LinkMessage("test", "abc"), new NotificationMessage.LinkMessage("abc", "aaa"));
NotificationModel model2 = new NotificationModel(NotificationType.INFO, new NotificationAction() {
@Override
public String name() {
return "action";
}
@Override
public void run(Object... args) {
System.out.println("1111");
}
}, new NotificationMessage.LinkMessage("1111 2222 33333333 4444 555 6666 66555 888 999 333 <br/> 3333", ""),new NotificationMessage.LinkMessage("display <a href='#'>model2</a> test", "abc"));
NotificationDialogProperties properties = new NotificationDialogProperties(frame, "test");
NotificationDialog dialog = new NotificationDialog(properties, Lists.newArrayList(model1, model2));
dialog.setVisible(true);
}
});
}
}

23
designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java vendored

@ -0,0 +1,23 @@
package com.fr.env.detect.impl.converter;
import org.junit.Test;
public class ClassConflictConvertorTest {
@Test
public void testInnerFinder() {
ClassNotFoundException ex1 = new ClassNotFoundException("Class 111.222.333 not found");
Iterable<String> names = ClassConflictConvertor.Converter.CLASS.converter(ex1);
System.out.println();
}
@Test
public void testConverter() {
ClassNotFoundException ex1 = new ClassNotFoundException("com.zaxxer.hikari.HikariConfig");
ClassConflictConvertor convertor = new ClassConflictConvertor();
convertor.convert(ex1);
}
}

33
designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java vendored

@ -0,0 +1,33 @@
package com.fr.env.detect.ui;
import com.fr.design.utils.DevUtils;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionLog;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.third.guava.collect.Lists;
import java.awt.Frame;
import java.util.function.Consumer;
import static org.junit.Assert.*;
public class DetectorErrorDialogTest {
public static void main(String[] args) {
DevUtils.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
DetectorErrorDialog dialog = new DetectorErrorDialog(frame, Lists.newArrayList(DetectorResult.exception(DetectorType.FINE_DB_PERMISSION,
ExceptionTips.create("test"),
ExceptionSolution.create("111<a href=\"\">test</a>222", "www.baidu.com", null),
ExceptionLog.create("log"))));
dialog.setVisible(true);
}
});
}
}

37
designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java vendored

@ -0,0 +1,37 @@
package com.fr.env.detect.ui;
import com.fr.design.utils.DevUtils;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorStatus;
import com.fr.env.detect.bean.DetectorType;
import java.awt.Frame;
import java.util.function.Consumer;
public class EnvDetectorDialogTest {
public static void main(String[] args) {
testShow();
}
private static void testShow() {
DevUtils.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
EnvDetectorModel envDetectorModel = new EnvDetectorModel();
envDetectorModel.update(DetectorType.JAR_CONFLICT, DetectorResult.builder()
.withTips("test")
.withSolution("test", "abc")
.withStatus(DetectorStatus.EXCEPTION)
.build());
EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(frame, envDetectorModel);
envDetectorDialog.setVisible(true);
}
});
}
}

22
designer-realize/src/main/java/com/fr/start/Designer.java

@ -1,6 +1,7 @@
package com.fr.start;
import com.fr.design.os.impl.SupportOSImpl;
import com.fr.exit.DesignerExiter;
import com.fr.log.FineLoggerFactory;
/**
@ -22,11 +23,26 @@ public class Designer {
// 创建进程
DesignerLauncher.getInstance().start(args);
}
} catch (Exception e) {
runNonGuardianDesigner(args);
FineLoggerFactory.getLogger().error(e.getMessage(), e);
} catch (Throwable ex1) {
try {
FineLoggerFactory.getLogger().error(ex1.getMessage(), ex1);
runNonGuardianDesigner(args);
} catch (Throwable ex2) {
// 异常退出
exitExceptionally(ex2);
}
}
}
/**
* 异常退出
*
* @param throwable 异常
*/
private static void exitExceptionally(Throwable throwable) {
DesignerExiter.getInstance().exit(throwable);
}
/**
* 启动非守护设计器

70
designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java

@ -2,11 +2,14 @@ package com.fr.start;
import com.fr.common.report.ReportState;
import com.fr.design.RestartHelper;
import com.fr.design.dialog.ErrorDialog;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector;
import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage;
import com.fr.env.detect.base.DetectorBridge;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorStatus;
import com.fr.env.detect.bean.DetectorType;
import com.fr.exit.DesignerExiter;
import com.fr.general.IOUtils;
import com.fr.io.utils.ResourceIOUtils;
@ -19,7 +22,7 @@ import com.fr.stable.lifecycle.ErrorTypeHelper;
import com.fr.stable.lifecycle.FineLifecycleFatalError;
import com.fr.stable.project.ProjectConstants;
import javax.swing.*;
import javax.swing.JOptionPane;
import java.util.HashMap;
import java.util.Map;
@ -60,16 +63,22 @@ public class LifecycleFatalErrorHandler {
* finedb处理
*/
enum FineDBHandler implements Handler {
/**
* 自检测
*/
SELF {
@Override
public void handle(FineLifecycleFatalError fatal) {
String showText = generateShowText(fatal);
StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.FINEDB_PROBLEM.getId(),
DesignerErrorMessage.FINEDB_PROBLEM.getMessage(),
fatal.getMessage());
FineLoggerFactory.getLogger().error(DesignerErrorMessage.FINEDB_PROBLEM.getId() + ": " + DesignerErrorMessage.FINEDB_PROBLEM.getMessage());
int result = FineJOptionPane.showOptionDialog(null,
Toolkit.i18nText("Fine-Design_Error_Finedb_Backup_Reset"),
showText,
Toolkit.i18nText("Fine-Design_Basic_Error_Tittle"),
JOptionPane.YES_NO_OPTION,
JOptionPane.ERROR_MESSAGE,
@ -95,8 +104,33 @@ public class LifecycleFatalErrorHandler {
DesignerExiter.getInstance().execute();
}
}
/**
* 生成展示信息
*
* @param fatal 异常
* @return 文本
*/
private String generateShowText(FineLifecycleFatalError fatal) {
// todo 其实这里的交互还是有问题, 为什么在锁住和没权限的场景下,要重置 FineDB 呢。
DetectorResult detectorResult = DetectorBridge.getInstance().detect(DetectorType.FINE_DB_LOCKED, fatal);
if (detectorResult.getStatus() == DetectorStatus.EXCEPTION) {
return Toolkit.i18nText("Fine-Design_Error_Finedb_Locked_Backup_Reset");
}
detectorResult = DetectorBridge.getInstance().detect(DetectorType.FINE_DB_PERMISSION, fatal);
if (detectorResult.getStatus() == DetectorStatus.EXCEPTION) {
return Toolkit.i18nText("Fine-Design_Error_Finedb_Permission_Backup_Reset");
}
detectorResult = DetectorBridge.getInstance().detect(DetectorType.FINE_DB_DIRTY, fatal);
if (detectorResult.getStatus() == DetectorStatus.EXCEPTION) {
return Toolkit.i18nText("Fine-Design_Error_Finedb_Dirty_Backup_Reset");
}
return Toolkit.i18nText("Fine-Design_Error_Finedb_Backup_Reset");
}
private void afterBackupFailed() {
FineJOptionPane.showMessageDialog(null,
Toolkit.i18nText("Fine-Design_Error_Finedb_Backup_Reset_Result",
ResourceIOUtils.getRealPath(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME))),
@ -111,29 +145,15 @@ public class LifecycleFatalErrorHandler {
* 默认处理
*/
enum DefaultHandler implements Handler {
/**
* 自处理
*/
SELF {
@Override
public void handle(FineLifecycleFatalError fatal) {
FineLoggerFactory.getLogger().error(fatal.getMessage(), fatal);
StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(),
DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(),
fatal.getMessage());
ErrorDialog dialog = new ErrorDialog(null, Toolkit.i18nText("Fine-Design_Error_Start_Apology_Message"),
Toolkit.i18nText("Fine-Design_Error_Start_Report"),
fatal.getMessage()) {
@Override
protected void okEvent() {
dispose();
DesignerExiter.getInstance().execute();
}
@Override
protected void restartEvent() {
dispose();
RestartHelper.restart();
}
};
dialog.setVisible(true);
DesignerExiter.getInstance().exit(fatal);
}
}
}

Loading…
Cancel
Save