From 58dc6d403194ecd245fa8ffaab414729b16f34a2 Mon Sep 17 00:00:00 2001 From: Harrison Date: Mon, 30 May 2022 14:42:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20REPORT-70565=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8=E7=8E=AF=E5=A2=83=E7=9B=91=E6=B5=8B=EF=BC=88jar?= =?UTF-8?q?=E5=8C=85=E5=BC=82=E5=B8=B8=E3=80=81finedb=E3=80=81=E6=9D=80?= =?UTF-8?q?=E6=AF=92=E8=BD=AF=E4=BB=B6=EF=BC=89=201-=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E9=80=80=E5=87=BA=E6=97=B6=E7=9A=84=E9=80=BB=E8=BE=91=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=202-=E6=B7=BB=E5=8A=A0=20fatalError=20=E7=9A=84?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=203-=E5=B7=A5=E5=85=B7=E6=A0=8F=E6=95=88?= =?UTF-8?q?=E6=9E=9C=204-=E4=BC=98=E5=8C=96=E4=B8=80=E4=B8=8B=20MessageWit?= =?UTF-8?q?hLink=20=E7=9A=84=E4=BD=BF=E7=94=A8=E6=96=B9=E5=BC=8F=205-?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E8=B6=85=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fr/design/DesignerEnvManager.java | 20 +++++++ .../notification/NotificationDialog.java | 27 ++++++--- .../design/dialog/link/MessageWithLink.java | 12 +++- .../mainframe/toolbar/ToolBarMenuDock.java | 5 +- .../{DevDebugUtil.java => DevDebugUtils.java} | 4 +- .../java/com/fr/design/utils/DevUtils.java | 13 ----- .../java/com/fr/env/detect/EnvPrepare.java | 5 ++ .../fr/env/detect/base/DetectorConstants.java | 4 +- .../main/java/com/fr/exit/DesignerExiter.java | 58 +++++++++++-------- .../notification/NotificationDialogTest.java | 2 +- .../detect/ui/DetectorErrorDialogTest.java | 27 ++++++++- .../fr/start/LifecycleFatalErrorHandler.java | 30 +++------- .../main/java/com/fr/start/MainDesigner.java | 2 - 13 files changed, 131 insertions(+), 78 deletions(-) rename designer-base/src/main/java/com/fr/design/utils/{DevDebugUtil.java => DevDebugUtils.java} (79%) 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/NotificationDialog.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java index 42dac12c9f..9c83ff1e23 100644 --- 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 @@ -10,7 +10,8 @@ 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.env.detect.base.ExceptionDetectorConfig; +import com.fr.design.utils.LinkStrUtils; +import com.fr.env.detect.base.EnvDetectorConfig; import javax.swing.BorderFactory; import javax.swing.Icon; @@ -134,7 +135,9 @@ public class NotificationDialog extends JDialog { 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) @@ -145,19 +148,27 @@ public class NotificationDialog extends JDialog { Desktop.getDesktop().browse(URI.create(linkMessage.getLink())); })); } - return new UILabel(messageModel.format()); + 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); - - JPanel centerPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); - centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 20)); - + 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); @@ -211,7 +222,7 @@ public class NotificationDialog extends JDialog { @Override public void mouseClicked(MouseEvent e) { // 配置处理 - ExceptionDetectorConfig.getInstance().setOpen(false); + EnvDetectorConfig.getInstance().setEnabled(false); // 点击事件 destroy(); } 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 0d6bd23488..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 @@ -23,10 +23,16 @@ import static com.fr.design.utils.LinkStrUtils.LABEL; */ public class MessageWithLink extends JEditorPane { + /** + * 直接放入 html 内容 + * 如果有超链接标签, 如 的话,将会自动点击匹配 url + * + * @param htmlText html内容 + */ public MessageWithLink(String htmlText) { super("text/html", htmlText); - + initListener(); setEditable(false); setBorder(null); } @@ -71,7 +77,7 @@ public class MessageWithLink extends JEditorPane { setBorder(null); } - public void initListener() { + protected void initListener() { addHyperlinkListener(hyperlinkEvent -> { try { @@ -85,7 +91,7 @@ public class MessageWithLink extends JEditorPane { }); } - public void initListener(Runnable runnable) { + protected void initListener(Runnable runnable) { addHyperlinkListener(e -> { if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { 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/utils/DevDebugUtil.java b/designer-base/src/main/java/com/fr/design/utils/DevDebugUtils.java similarity index 79% rename from designer-base/src/main/java/com/fr/design/utils/DevDebugUtil.java rename to designer-base/src/main/java/com/fr/design/utils/DevDebugUtils.java index 2125455d38..af1d984ea4 100644 --- a/designer-base/src/main/java/com/fr/design/utils/DevDebugUtil.java +++ b/designer-base/src/main/java/com/fr/design/utils/DevDebugUtils.java @@ -3,10 +3,10 @@ package com.fr.design.utils; /** * created by Harrison on 2022/05/26 **/ -public class DevDebugUtil { +public class DevDebugUtils { public static void main(String[] args) { - org.swingexplorer.Launcher.main(new String[]{"com.fr.design.utils.DevUtil"}); + 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 index 85918f84be..2d88277555 100644 --- a/designer-base/src/main/java/com/fr/design/utils/DevUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/DevUtils.java @@ -5,13 +5,6 @@ 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.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.ui.DetectorErrorDialog; -import com.fr.third.guava.collect.Lists; import com.fr.transaction.Configurations; import com.fr.transaction.LocalConfigurationHelper; @@ -61,12 +54,6 @@ public class DevUtils { 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); } }); } 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 index eedc591db2..258d579aaa 100644 --- a/designer-base/src/main/java/com/fr/env/detect/EnvPrepare.java +++ b/designer-base/src/main/java/com/fr/env/detect/EnvPrepare.java @@ -4,6 +4,11 @@ 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 **/ 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 index fce9d5a889..be1036f0d8 100644 --- 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 @@ -5,7 +5,7 @@ package com.fr.env.detect.base; **/ public class DetectorConstants { - public static final String JAR_HELP_LINK = ""; + 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 = ""; + 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/exit/DesignerExiter.java b/designer-base/src/main/java/com/fr/exit/DesignerExiter.java index e1a93a46cf..7337ff7c74 100644 --- a/designer-base/src/main/java/com/fr/exit/DesignerExiter.java +++ b/designer-base/src/main/java/com/fr/exit/DesignerExiter.java @@ -33,37 +33,47 @@ public class DesignerExiter { } public void exit(Throwable throwable) { + + FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable); List results = EnvDetectorCenter.getInstance().terminate(throwable); if (Collections.isEmpty(results)) { - DesignerFrame designerFrame = DesignerContext.getDesignerFrame(); - DetectorErrorDialog errorDialog = new DetectorErrorDialog(designerFrame, results); - errorDialog.setVisible(true); + // 为空,则 + showOldExitDialog(throwable); } else { - FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable); - StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(), - DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(), - throwable.getMessage()); - 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); + 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) { + StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(), + DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(), + throwable.getMessage()); + 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/test/java/com/fr/design/components/notification/NotificationDialogTest.java b/designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java index 1ba115c785..1536dd2622 100644 --- 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 @@ -31,7 +31,7 @@ public class NotificationDialogTest { public void run(Object... args) { System.out.println("1111"); } - }, new NotificationMessage.LinkMessage("display model2 test", "abc")); + }, 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)); 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 index 42d7923b8d..b54288ea54 100644 --- 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 @@ -1,8 +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-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java b/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java index 2a9103f4ad..e4c5d73f91 100644 --- a/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java +++ b/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java @@ -116,30 +116,18 @@ public class LifecycleFatalErrorHandler { // todo 其实这里的交互还是有问题, 为什么在锁住和没权限的场景下,要重置 FineDB 呢。 DetectorResult detectorResult = DetectorBridge.getInstance().detect(DetectorType.FINE_DB_LOCKED, fatal); - if (detectorResult.getStatus() == DetectorStatus.NORMAL) { - detectorResult = DetectorBridge.getInstance().detect(DetectorType.FINE_DB_PERMISSION, fatal); + if (detectorResult.getStatus() == DetectorStatus.EXCEPTION) { + return Toolkit.i18nText("Fine-Design_Error_Finedb_Locked_Backup_Reset"); } - if (detectorResult.getStatus() == DetectorStatus.NORMAL) { - detectorResult = DetectorBridge.getInstance().detect(DetectorType.FINE_DB_DIRTY, fatal); + detectorResult = DetectorBridge.getInstance().detect(DetectorType.FINE_DB_PERMISSION, fatal); + if (detectorResult.getStatus() == DetectorStatus.EXCEPTION) { + return Toolkit.i18nText("Fine-Design_Error_Finedb_Permission_Backup_Reset"); } - - String message; - - DetectorType type = detectorResult.getType(); - switch (type) { - case FINE_DB_LOCKED: - message = Toolkit.i18nText("Fine-Design_Error_Finedb_Locked_Backup_Reset"); - break; - case FINE_DB_PERMISSION: - message = Toolkit.i18nText("Fine-Design_Error_Finedb_Permission_Backup_Reset"); - break; - case FINE_DB_DIRTY: - message = Toolkit.i18nText("Fine-Design_Error_Finedb_Dirty_Backup_Reset"); - break; - default: - message = Toolkit.i18nText("Fine-Design_Error_Finedb_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 message; + return Toolkit.i18nText("Fine-Design_Error_Finedb_Backup_Reset"); } private void afterBackupFailed() { diff --git a/designer-realize/src/main/java/com/fr/start/MainDesigner.java b/designer-realize/src/main/java/com/fr/start/MainDesigner.java index 09d7406834..f60003c9a1 100644 --- a/designer-realize/src/main/java/com/fr/start/MainDesigner.java +++ b/designer-realize/src/main/java/com/fr/start/MainDesigner.java @@ -46,7 +46,6 @@ import com.fr.design.share.SharableManager; import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.concurrent.ThreadFactoryBuilder; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.env.detect.EnvDetectorCenter; import com.fr.env.utils.DesignerInteractionHistory; import com.fr.event.Event; import com.fr.event.EventDispatcher; @@ -111,7 +110,6 @@ public class MainDesigner extends BaseDesigner { */ public static void main(String[] args) { - EnvDetectorCenter.getInstance().init(); showSplash(); DeepLinkManager.getInstance().start(args); StopWatch watch = new StopWatch();