diff --git a/designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java b/designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java new file mode 100644 index 0000000000..c89ad2115a --- /dev/null +++ b/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 { + + void run() throws T; + + static Runnable toRunnable(ThrowableRunnable runnable) { + + return () -> { + try { + runnable.run(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + }; + } +} diff --git a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java index 3694c6f83d..958d1fa652 100644 --- a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java +++ b/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) { diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java new file mode 100644 index 0000000000..d2f56976e8 --- /dev/null +++ b/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); +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java new file mode 100644 index 0000000000..9c83ff1e23 --- /dev/null +++ b/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; + +/** + * 右下角的提醒 异常提醒 + * + * 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 notificationModels; + private PageControlModel pageControlModel; + + private JPanel body; + private JPanel headerPanel; + private JPanel contentPanel; + private JPanel tailPanel; + + public NotificationDialog(NotificationDialogProperties properties, List 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 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 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 + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java new file mode 100644 index 0000000000..5bcff67150 --- /dev/null +++ b/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; + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java new file mode 100644 index 0000000000..c107a0fb88 --- /dev/null +++ b/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; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java new file mode 100644 index 0000000000..86d5a9edfd --- /dev/null +++ b/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 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; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java new file mode 100644 index 0000000000..0f5ab7b340 --- /dev/null +++ b/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 +} diff --git a/designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java b/designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java new file mode 100644 index 0000000000..3d024fb052 --- /dev/null +++ b/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; + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java b/designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java new file mode 100644 index 0000000000..0059f91259 --- /dev/null +++ b/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 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; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java b/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java new file mode 100644 index 0000000000..317a171954 --- /dev/null +++ b/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); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/constants/DesignerColor.java b/designer-base/src/main/java/com/fr/design/constants/DesignerColor.java new file mode 100644 index 0000000000..0ece84cca9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/constants/DesignerColor.java @@ -0,0 +1,24 @@ +package com.fr.design.constants; + +import java.awt.Color; + +/** + * 见 设计器规范 + * 将相关的逻辑抽象过来 + * 如果后面更改的话, 可以统一修改 + * 如果换版本,可以换成 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); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java b/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java index 2e839d27c2..d412fb682d 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java +++ b/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 内容 + * 如果有超链接标签, 如 的话,将会自动点击匹配 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", "" + frontMessage + "" + linkName + "" + backMessage + ""); + + super("text/html", "" + frontMessage + "" + linkName + "" + backMessage + ""); 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); + } + }); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java index ba9aadcc5e..2299337366 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java +++ b/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); diff --git a/designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java b/designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java index b7583d0dd9..86093a6d82 100644 --- a/designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java +++ b/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 waitUntil(Supplier 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; + } } diff --git a/designer-base/src/main/java/com/fr/design/utils/ColorUtils.java b/designer-base/src/main/java/com/fr/design/utils/ColorUtils.java new file mode 100644 index 0000000000..739d394720 --- /dev/null +++ b/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)); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/utils/DevDebugUtils.java b/designer-base/src/main/java/com/fr/design/utils/DevDebugUtils.java new file mode 100644 index 0000000000..af1d984ea4 --- /dev/null +++ b/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"}); + } +} diff --git a/designer-base/src/main/java/com/fr/design/utils/DevUtils.java b/designer-base/src/main/java/com/fr/design/utils/DevUtils.java new file mode 100644 index 0000000000..2d88277555 --- /dev/null +++ b/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 页面的调试 + *

+ * 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 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() { + @Override + public void accept(Frame frame) { + } + }); + } +} diff --git a/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java b/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java new file mode 100644 index 0000000000..d02c9abff2 --- /dev/null +++ b/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 + ""; + } + + public static String generateLinkTag(String link, String text) { + + return "" + text + ""; + } + + 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()); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java b/designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java new file mode 100644 index 0000000000..98938a4f8e --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java @@ -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 PROCESS = new AtomicReference<>(); + + /** + * 初始化 + */ + public void init() { + + // 默认是启动 + PROCESS.set(DetectorProcess.DESIGN_LAUNCH); + start(); + + // 添加启动完成监听 + EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener() { + @Override + public void on(Event event, Null param) { + if (isSameProcess(DetectorProcess.DESIGN_LAUNCH)) { + stop(); + } + } + }); + + // 切换完成后的监听 + EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener() { + @Override + public void on(Event event, Workspace param) { + if (isSameProcess(DetectorProcess.DESIGN_LAUNCH)) { + stop(); + } + } + }); + + // 打开内置服务器 + EventDispatcher.listen(EmbedServerEvent.BeforeStart, new Listener() { + @Override + public void on(Event event, Null param) { + PROCESS.set(DetectorProcess.SERVER_LAUNCH); + start(); + } + }); + EventDispatcher.listen(EmbedServerEvent.AfterStart, new Listener() { + @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 resultStream = DetectorBridge.getInstance().detect(); + + // 结束 + DetectorBridge.getInstance().stop(); + + // 展示效果 + NotificationDialogProperties properties = new NotificationDialogProperties(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Detect_Notification_Title")); + List 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 terminate(Throwable throwable) { + + Stream 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 + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/EnvPrepare.java b/designer-base/src/main/java/com/fr/env/detect/EnvPrepare.java new file mode 100644 index 0000000000..258d579aaa --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/EnvPrepare.java @@ -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() { + + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java b/designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java index 32d54a1d75..5414ba6489 100644 --- a/designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java +++ b/designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java @@ -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; } } diff --git a/designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java b/designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java index b2e60d42c7..0dbce9c003 100644 --- a/designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java +++ b/designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java @@ -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 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()); } } diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java index 78b5017844..0d5b60bc09 100644 --- a/designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java @@ -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 = new NotNullLazyValue() { - @Override - protected @NotNull ThrowableBridge compute() { - - return new ThrowableBridge(); - } - }; - private final NotNullLazyValue detectorManager = new NotNullLazyValue() { @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 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 detect(DetectorType type) { + public Stream detect() { - return detectorManager.getValue().detect(type); + return detectorManager.getValue().detect(); } /** - * 执行-捕获异常 + * 异常检测 + * 当遇到异常时,且异常难以处理,直接导致服务器启动失败时,调用 + * 将异常添加进来,统一检测 * * @param throwable 异常 * @return 检测结果 */ - public Optional convert(Throwable throwable) { - - return throwableBridge.getValue().convert(throwable); + public Stream detect(Throwable throwable) { + + ThrowableStore.getInstance().add(throwable); + Stream result = detect(); + ThrowableStore.getInstance().reset(); + + return result; } } diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java new file mode 100644 index 0000000000..be1036f0d8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java @@ -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"; +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java index 9d3ae2daa9..bc65870da7 100644 --- a/designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java @@ -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 detect() { - return detectors.stream() + Stream results = detectors.stream() .map(ExceptionDetector::detect) .filter(Objects::nonNull); + + List resultList = results.collect(Collectors.toList()); + resultList.forEach(DetectorResult::log); + + return resultList.stream(); } - public Optional detect(DetectorType type) { + public DetectorResult detect(DetectorType type) { - return detectors.stream() + Optional result = detectors.stream() .filter((detector -> type == detector.type())) .findFirst() .map(ExceptionDetector::detect); + + // 记录日志 + result.ifPresent(DetectorResult::log); + + return result.orElse(DetectorResult.normal(type)); } } diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java new file mode 100644 index 0000000000..fdfccf216f --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java @@ -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 messages = new ArrayList<>(); + + Function> 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())); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java b/designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java new file mode 100644 index 0000000000..caafdbe464 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java @@ -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(); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java b/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java index 3d6d8bc4eb..7713ef739e 100644 --- a/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java +++ b/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java @@ -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 diff --git a/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetectorConfig.java b/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetectorConfig.java deleted file mode 100644 index 489d5e3113..0000000000 --- a/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetectorConfig.java +++ /dev/null @@ -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; - } -} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java index 09850055d4..2b45ecbc1e 100644 --- a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java +++ b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java @@ -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; } diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java index d75a82e56e..6a12015e91 100644 --- a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java +++ b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java @@ -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, } diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java index 2bc71e58a5..1dc8e4d62a 100644 --- a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java +++ b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java @@ -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 { diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java index 90cdb58fdb..521e903452 100644 --- a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java +++ b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java @@ -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; } } diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java index a6748e26cb..b4f549f679 100644 --- a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java +++ b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java @@ -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; } } diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java index 970bca989d..b7ab6c63fa 100644 --- a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java +++ b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java @@ -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; } diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/Message.java b/designer-base/src/main/java/com/fr/env/detect/bean/Message.java index e1d6dcd62c..2acdec8b84 100644 --- a/designer-base/src/main/java/com/fr/env/detect/bean/Message.java +++ b/designer-base/src/main/java/com/fr/env/detect/bean/Message.java @@ -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; } diff --git a/designer-base/src/main/java/com/fr/env/detect/exception/DetectorException.java b/designer-base/src/main/java/com/fr/env/detect/exception/DetectorException.java deleted file mode 100644 index 14adcab292..0000000000 --- a/designer-base/src/main/java/com/fr/env/detect/exception/DetectorException.java +++ /dev/null @@ -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); - } -} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/HsqlDirtyDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java similarity index 64% rename from designer-base/src/main/java/com/fr/env/detect/impl/HsqlDirtyDetector.java rename to designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java index 6afc41a669..1b34597866 100644 --- a/designer-base/src/main/java/com/fr/env/detect/impl/HsqlDirtyDetector.java +++ b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java @@ -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()); } diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java new file mode 100644 index 0000000000..c312ce3288 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java @@ -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()); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java new file mode 100644 index 0000000000..4e3a18cedd --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java @@ -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()); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java new file mode 100644 index 0000000000..2eb38d94ef --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java @@ -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()); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java index 0967697f67..679671997b 100644 --- a/designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java +++ b/designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java @@ -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 信息匹配 + *

+ * 远程 + * 两边一一对应匹配 + * + * @return 结果 + */ @Override public DetectorResult detect() { - DetectorResult.DetectorResultBuilder builder = DetectorResult.builder(); - // 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包 - BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class); - List 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 inConsistentInfos = buildInfos.stream() - .filter((e) -> !StringUtils.equals(designerBuild, e.getGroupBuild())) - .collect(Collectors.toList()); + return detectLocal(); } else { - - // 远程情况 - List localInfos = BuildInfoManager.getInstance().getInfos(); - Map localMap = groupBy(localInfos); - - List remoteInfos = buildInfos; - Map remoteMap = groupBy(remoteInfos); - - MapDifference difference = Maps.difference(localMap, remoteMap); - // 两边都有的 JAR 的不同之处 - Map diffInCommon = difference.entriesInCommon(); - + return detectLocalAndRemote(); } + } - return builder.build(); + @NotNull + private DetectorResult detectLocalAndRemote() { + + // 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包 + BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class); + List buildInfos = buildInfoOperator.getBuildInfos(); + + // 远程情况 + List localInfos = BuildInfoManager.getInstance().getInfos(); + Map localMap = groupBy(localInfos); + + List remoteInfos = buildInfos; + Map remoteMap = groupBy(remoteInfos); + + MapDifference difference = Maps.difference(localMap, remoteMap); + Map diffInCommon = difference.entriesInCommon(); + + if (diffInCommon.isEmpty()) { + return DetectorResult.normal(type()); + } + + Set 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 buildInfos = operator.getBuildInfos(); + + // 获取设计器的 build + Optional designerBuild = buildInfos.stream() + .filter(DetectorUtil::isDesignerJar) + .map(BuildInfo::getGroupBuild) + .filter(StringUtils::isNotEmpty) + .findFirst(); + + // 如果 build + if (!designerBuild.isPresent()) { + return DetectorResult.normal(type()); + } + + // 获取所有的不一致的 build + List inConsistentInfos = buildInfos.stream() + .filter((e) -> !StringUtils.equals(designerBuild.get(), e.getGroupBuild())) + .collect(Collectors.toList()); + + // 没有直接返回 + if (Collections.isEmpty(inConsistentInfos)) { + return DetectorResult.normal(type()); + } + + // 有的话 + List 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 groupBy(List localInfos) { diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java index 86f589f303..74c908000a 100644 --- a/designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java +++ b/designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java @@ -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 = "
"; + 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 buildInfos = buildInfoOperator.getBuildInfos(); - for (BuildInfo buildInfo : buildInfos) { - String jar = buildInfo.getJar(); - String buildContent = buildInfo.getGroupBuild(); - boolean isLack = StringUtils.isEmpty(buildContent); - if (isLack) { - // 处理信息 - - } + List 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 lackInfos) { + + List 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 infos) { + + String webLibPath = WEB_LIB_PATH; + String homeLibPath = FR_HOME_LIB; + + Map> libMap = groupByPath(infos, homeLibPath, webLibPath); + + StringBuilder sb = new StringBuilder(); + + List homeLibs = libMap.get(homeLibPath); + if (!Collections.isEmpty(homeLibs)) { + sb.append(homeLibPath); + sb.append(StringUtils.join(homeLibs, SEPARATOR)); + } + + List 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> groupByPath(List infos, String homeLibPath, String webLibPath) { + Map> 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); + } + } diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java new file mode 100644 index 0000000000..3432d976d7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java @@ -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, 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 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 allPath = new HashSet<>(); + for (String className : classNames) { + String classFile = convertClass2Path(className); + try { + Enumeration urls = ResourceLoader.getResources(classFile, this.getClass()); + List 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 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 converter(Throwable throwable) { + + String message = throwable.getMessage(); + Matcher matcher = CLASS_PATTERN.matcher(message); + List 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 converter(Throwable throwable) { + + String message = throwable.getMessage(); + Matcher matcher = METHOD_PATTERN.matcher(message); + List names = new ArrayList<>(); + while (matcher.find()) { + String className = matcher.group(); + names.add(className); + } + return names; + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassThrowableConvertor.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassThrowableConvertor.java deleted file mode 100644 index 7fdd8bbe33..0000000000 --- a/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassThrowableConvertor.java +++ /dev/null @@ -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> throwableClassSet = new HashSet<>(); - - private Set> 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; - } -} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbDirtyConverter.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbDirtyConverter.java index d23aa9915c..4550cde4a2 100644 --- a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbDirtyConverter.java +++ b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbDirtyConverter.java @@ -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 tableNames = ConfigContext.getConfigNames(); + while (tableNames.hasNext()) { + String tableName = tableNames.next(); + Class 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); } + } diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java index 8924d688a2..8a5e74f0b5 100644 --- a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java +++ b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java @@ -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; } } diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java index 21722ebb4e..dd350abdf4 100644 --- a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java +++ b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java @@ -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; } } diff --git a/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java index 64cd3ce7b7..14210b8fb2 100644 --- a/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java +++ b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java @@ -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 logHandler = toHandler(); + private final LogHandler 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 toHandler() { final ThrowableLogAppender appender = this; - return () -> appender; + appender.start(); + LogHandler handler = new LogHandler() { + @Override + public ThrowableLogAppender getHandler() { + return appender; + } + }; + return handler; } diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java b/designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java new file mode 100644 index 0000000000..9b85c61af2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java @@ -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 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(); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java new file mode 100644 index 0000000000..7992648f01 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java @@ -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); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java new file mode 100644 index 0000000000..64d6f41682 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java @@ -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 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() { + + @Override + protected Void doInBackground() throws Exception { + List 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> itemMap = model.getItemMap(); + + // 行号, 这边更新是通过 行/列 。 不是索引 + int row = 1; + for (Map.Entry> entry : itemMap.entrySet()) { + + DetectorType.Kind kind = entry.getKey(); + List 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 results = model.getResults(); + List 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(); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java new file mode 100644 index 0000000000..0f9075313d --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java @@ -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; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java new file mode 100644 index 0000000000..457734d0bd --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java @@ -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> 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 items = itemMap.get(type.getKind()); + items.stream() + .filter((e) -> e.getType() == type) + .findFirst() + .ifPresent((e) -> { + e.setResult(result); + }); + } + + public Stream getResults() { + + return getItems().stream() + .map(EnvDetectorItem::getResult); + } + + public List getItems() { + + return itemMap.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + public Map> getItemMap() { + + return this.itemMap; + } + +} + + diff --git a/designer-base/src/main/java/com/fr/exit/DesignerExiter.java b/designer-base/src/main/java/com/fr/exit/DesignerExiter.java index cda2e015b0..3acb3cf8a9 100644 --- a/designer-base/src/main/java/com/fr/exit/DesignerExiter.java +++ b/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 results = EnvDetectorCenter.getInstance().terminate(throwable); + + if (Collections.isEmpty(results)) { + // 为空,则 + showOldExitDialog(throwable); + } else { + showNewExitDialog(results); + } + } + + private void showNewExitDialog(List 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(); diff --git a/designer-base/src/main/java/com/fr/start/BaseDesigner.java b/designer-base/src/main/java/com/fr/start/BaseDesigner.java index 360e9cdfa6..95f27442d4 100644 --- a/designer-base/src/main/java/com/fr/start/BaseDesigner.java +++ b/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); } } } diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg new file mode 100755 index 0000000000..0a20cf97a8 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg new file mode 100755 index 0000000000..9d111eff91 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg new file mode 100755 index 0000000000..4ab4c796e2 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg new file mode 100755 index 0000000000..040db18bd0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif new file mode 100644 index 0000000000..99f95a0fa8 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif new file mode 100644 index 0000000000..9db4c738fb Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg new file mode 100755 index 0000000000..6ef70206f1 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg new file mode 100755 index 0000000000..c26d221b58 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg new file mode 100755 index 0000000000..5b0eabe822 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/env/detect/detect.svg b/designer-base/src/main/resources/com/fr/env/detect/detect.svg new file mode 100644 index 0000000000..b279a649fd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/env/detect/detect.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg b/designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg new file mode 100644 index 0000000000..b279a649fd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java b/designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java new file mode 100644 index 0000000000..1536dd2622 --- /dev/null +++ b/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() { + @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
3333", ""),new NotificationMessage.LinkMessage("display model2 test", "abc")); + + NotificationDialogProperties properties = new NotificationDialogProperties(frame, "test"); + NotificationDialog dialog = new NotificationDialog(properties, Lists.newArrayList(model1, model2)); + dialog.setVisible(true); + } + }); + } + +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java b/designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java new file mode 100644 index 0000000000..cdc789b015 --- /dev/null +++ b/designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java @@ -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 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); + } +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java b/designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java new file mode 100644 index 0000000000..b54288ea54 --- /dev/null +++ b/designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java @@ -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() { + @Override + public void accept(Frame frame) { + + DetectorErrorDialog dialog = new DetectorErrorDialog(frame, Lists.newArrayList(DetectorResult.exception(DetectorType.FINE_DB_PERMISSION, + ExceptionTips.create("test"), + ExceptionSolution.create("111test222", "www.baidu.com", null), + ExceptionLog.create("log")))); + dialog.setVisible(true); + } + }); + } + +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java b/designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java new file mode 100644 index 0000000000..fd63b1714f --- /dev/null +++ b/designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java @@ -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() { + @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); + } + }); + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/start/Designer.java b/designer-realize/src/main/java/com/fr/start/Designer.java index 1f8d181ce3..c2ec299ea2 100644 --- a/designer-realize/src/main/java/com/fr/start/Designer.java +++ b/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); + } /** * 启动非守护设计器 diff --git a/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java b/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java index 446253e906..37f608ee16 100644 --- a/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java +++ b/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); } } }