From 05b5dfb592a0c3696753772f0b22ebf0f68c2d06 Mon Sep 17 00:00:00 2001 From: plough Date: Sun, 21 Apr 2019 11:15:25 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-15314=20103=E6=A8=A1=E6=9D=BF=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=94=B6=E9=9B=86=3D>=E8=80=83=E8=99=91=E6=94=BE?= =?UTF-8?q?=E5=81=87=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/info/DesignerOpenHistory.java | 117 ++++++++++++++++++ .../mainframe/template/info/TemplateInfo.java | 10 +- .../template/info/TemplateInfoCollector.java | 56 +++------ .../template/info/TimeConsumeTimer.java | 3 - .../info/DesignerOpenHistoryTest.java | 108 ++++++++++++++++ .../info/TemplateInfoCollectorTest.java | 16 +++ 6 files changed, 269 insertions(+), 41 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/template/info/DesignerOpenHistory.java create mode 100644 designer-base/src/test/java/com/fr/design/mainframe/template/info/DesignerOpenHistoryTest.java diff --git a/designer-base/src/main/java/com/fr/design/mainframe/template/info/DesignerOpenHistory.java b/designer-base/src/main/java/com/fr/design/mainframe/template/info/DesignerOpenHistory.java new file mode 100644 index 000000000..096b6d16a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/template/info/DesignerOpenHistory.java @@ -0,0 +1,117 @@ +package com.fr.design.mainframe.template.info; + +import com.fr.general.ComparatorUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLReadable; +import com.fr.stable.xml.XMLWriter; +import com.fr.stable.xml.XMLableReader; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * 管理打开设计器的日期记录 + * Created by plough on 2019/4/19. + */ +class DesignerOpenHistory implements XMLReadable, XMLWriter { + static final String XML_TAG = "DesignerOpenHistory"; + private static DesignerOpenHistory singleton; + private static final String SPLITTER = ","; + private static final int LENGTH = 3; // 保留最近 3 次的记录 + // 最近的日期是 history[0],最早的日期是 history[LENGTH-1] + private String[] history = new String[LENGTH]; + + private DesignerOpenHistory() { + for (int i = 0; i < LENGTH; i++) { + history[i] = StringUtils.EMPTY; + } + } + + static DesignerOpenHistory getInstance() { + if (singleton == null) { + singleton = new DesignerOpenHistory(); + } + return singleton; + } + + void update() { + String today = getToday(); + if (ComparatorUtils.equals(history[0], today)) { + return; + } + shiftByOne(); + history[0] = today; + } + + /** + * 获取历史记录中囊括的日子数。即最早的历史记录 history[LENGTH - 1],到最晚的记录 history[0] 之间的时间跨度 + */ + int getHistorySpanDayCount() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + try { + Date earliestDate = sdf.parse(getEarliestDate()); + Date latestDate = sdf.parse(history[0]); + long diffInMillies = latestDate.getTime() - earliestDate.getTime(); + return (int)TimeUnit.DAYS.convert(diffInMillies,TimeUnit.MILLISECONDS) + 1; + } catch (ParseException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return 1; + } + + /** + * 今天是否已经打开过设计器 + */ + boolean hasOpenedToday() { + String today = getToday(); + return ComparatorUtils.equals(today, history[0]); + } + + private String getEarliestDate() { + for (int i = LENGTH - 1; i >= 0; i--) { + if (StringUtils.isNotEmpty(history[i])) { + return history[i]; + } + } + throw new AssertionError("Designer open history is empty!"); + } + + private void shiftByOne() { + for (int i = LENGTH - 1; i > 0; i--) { + history[i] = history[i-1]; + } + } + + private String getToday() { + return new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); + } + + @Override + public String toString() { + return StringUtils.join(SPLITTER, history); + } + + private void parseString(String s) { + String[] arr = s.split(SPLITTER); + System.arraycopy(arr, 0, history, 0, arr.length); + } + + @Override + public void readXML(XMLableReader reader) { + if (XML_TAG.equals(reader.getTagName())) { + parseString(reader.getElementValue()); + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(XML_TAG); + writer.textNode(toString()); + writer.end(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java index af644a1e8..4c45ce823 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java @@ -203,7 +203,11 @@ class TemplateInfo implements XMLReadable, XMLWriter { } boolean isComplete() { - return idleDayCount > COMPLETE_DAY_COUNT; + // 条件 1. 超过15天未编辑 + // 条件 2. 设计器在这段未编辑的时间内启动超过 X 次(目前定的 X = 3)。即"设计器最近 X 次启动的时间跨度" < "未编辑时间"; + + return idleDayCount > COMPLETE_DAY_COUNT + && DesignerOpenHistory.getInstance().getHistorySpanDayCount() < idleDayCount; } String getConsumingMapJsonString() { @@ -245,4 +249,8 @@ class TemplateInfo implements XMLReadable, XMLWriter { void addIdleDayCountByOne() { this.idleDayCount += 1; } + + int getIdleDayCount() { + return this.idleDayCount; + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java index 5d5e5dd5b..30bfb5e1d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java @@ -2,7 +2,6 @@ package com.fr.design.mainframe.template.info; import com.fr.base.FRContext; import com.fr.design.DesignerEnvManager; -import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.ProductConstants; import com.fr.stable.StableUtils; @@ -19,9 +18,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Calendar; import java.util.HashMap; import java.util.Map; @@ -31,17 +28,23 @@ import java.util.Map; */ public class TemplateInfoCollector implements XMLReadable, XMLWriter { private static final String XML_TAG = "TplInfo"; - private static final String XML_DESIGNER_OPEN_DATE = "DesignerOpenDate"; private static final String XML_TEMPLATE_INFO_LIST = "TemplateInfoList"; private static final String XML_FILE_NAME = "tpl.info"; private static TemplateInfoCollector instance; private Map templateInfoMap; - private String designerOpenDate; //设计器最近一次打开日期 + private DesignerOpenHistory designerOpenHistory; private TemplateInfoCollector() { init(); } + private void init() { + templateInfoMap = new HashMap<>(); + designerOpenHistory = DesignerOpenHistory.getInstance(); + + loadFromFile(); + } + public static TemplateInfoCollector getInstance() { if (instance == null) { instance = new TemplateInfoCollector(); @@ -96,6 +99,7 @@ public class TemplateInfoCollector implements XMLReadable, XMLWriter { * 发送本地模板信息到服务器,并清空已发送模版的本地记录 */ public void sendTemplateInfo() { + // 每次启动设计器后,都会执行这个函数(被 InformationCollector 的 collectStartTime 调用) addIdleDayCount(); removeTestTemplates(); @@ -120,13 +124,6 @@ public class TemplateInfoCollector implements XMLReadable, XMLWriter { return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), XML_FILE_NAME)); } - private void init() { - templateInfoMap = new HashMap<>(); - setDesignerOpenDate(); - - loadFromFile(); - } - void loadFromFile() { if (!getInfoFile().exists()) { return; @@ -150,21 +147,6 @@ public class TemplateInfoCollector implements XMLReadable, XMLWriter { return templateInfo; } - /** - * 把设计器最近打开日期设定为当前日期 - */ - private void setDesignerOpenDate() { - designerOpenDate = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); - } - - /** - * 判断今天是否第一次打开设计器,为了防止同一天内,多次 addIdleDayCount - */ - private boolean designerOpenFirstTime() { - String today = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); - return !ComparatorUtils.equals(today, designerOpenDate); - } - private boolean shouldCollectInfo() { //只收集本地环境的 if (!WorkContext.getCurrent().isLocal()) { @@ -189,12 +171,14 @@ public class TemplateInfoCollector implements XMLReadable, XMLWriter { * 更新 day_count:打开设计器却未编辑模板的连续日子 */ private void addIdleDayCount() { - if (designerOpenFirstTime()) { - for (TemplateInfo templateInfo : templateInfoMap.values()) { - templateInfo.addIdleDayCountByOne(); - } - setDesignerOpenDate(); + // 判断今天是否第一次打开设计器,为了防止同一天内,多次 addIdleDayCount + if (designerOpenHistory.hasOpenedToday()) { + return; } + for (TemplateInfo templateInfo : templateInfoMap.values()) { + templateInfo.addIdleDayCountByOne(); + } + designerOpenHistory.update(); } // 删除所有已完成的测试模版 @@ -220,8 +204,8 @@ public class TemplateInfoCollector implements XMLReadable, XMLWriter { if (reader.isChildNode()) { try { String name = reader.getTagName(); - if (XML_DESIGNER_OPEN_DATE.equals(name)) { - this.designerOpenDate = reader.getElementValue(); + if (DesignerOpenHistory.XML_TAG.equals(name)) { + reader.readXMLObject(designerOpenHistory); } else if (TemplateInfo.XML_TAG.equals(name)) { TemplateInfo templateInfo = TemplateInfo.newInstanceByRead(reader); templateInfoMap.put(templateInfo.getTemplateID(), templateInfo); @@ -236,9 +220,7 @@ public class TemplateInfoCollector implements XMLReadable, XMLWriter { public void writeXML(XMLPrintWriter writer) { writer.startTAG(XML_TAG); - writer.startTAG(XML_DESIGNER_OPEN_DATE); - writer.textNode(designerOpenDate); - writer.end(); + designerOpenHistory.writeXML(writer); writer.startTAG(XML_TEMPLATE_INFO_LIST); for (TemplateInfo templateInfo : templateInfoMap.values()) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TimeConsumeTimer.java b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TimeConsumeTimer.java index ace07be0d..527341411 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TimeConsumeTimer.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TimeConsumeTimer.java @@ -44,9 +44,6 @@ public class TimeConsumeTimer { startMS = 0; stopMS = 0; state = State.STOPPED; - - - System.out.println("timeConsume now: " + timeConsume); } public int popTime() { diff --git a/designer-base/src/test/java/com/fr/design/mainframe/template/info/DesignerOpenHistoryTest.java b/designer-base/src/test/java/com/fr/design/mainframe/template/info/DesignerOpenHistoryTest.java new file mode 100644 index 000000000..e3f63ddc3 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/mainframe/template/info/DesignerOpenHistoryTest.java @@ -0,0 +1,108 @@ +package com.fr.design.mainframe.template.info; + +import com.fr.invoke.Reflect; +import com.fr.stable.StringUtils; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLableReader; +import com.fr.third.javax.xml.stream.XMLStreamException; +import org.junit.Before; +import org.junit.Test; + +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Created by plough on 2019/4/21. + */ +public class DesignerOpenHistoryTest { + private DesignerOpenHistory openHistory; + private String[] mockHistory = new String[] { + "2019-04-08", "2019-04-03", "2019-03-29" + }; + + @Before + public void setUp() { + openHistory = DesignerOpenHistory.getInstance(); + Reflect.on(openHistory).set("history", mockHistory); + } + + @Test + public void testReadAndWrite() throws XMLStreamException { + // 写入 xml + StringWriter sw = new StringWriter(); + XMLPrintWriter writer = XMLPrintWriter.create(new PrintWriter(sw)); + openHistory.writeXML(writer); + writer.flush(); + writer.close(); + + String xmlText = sw.getBuffer().toString(); + + // 临时修改配置 + Reflect.on(openHistory).set("history", new String[] {"", "", ""}); + + // 从 xml 中读取 + StringReader sr = new StringReader(xmlText); + XMLableReader xmlReader = XMLableReader.createXMLableReader(sr); + xmlReader.readXMLObject(openHistory); + + // 验证:与写入时的配置一致 + assertArrayEquals(mockHistory, (String[])Reflect.on(openHistory).field("history").get()); + } + + @Test + public void testToString() { + assertEquals("2019-04-08,2019-04-03,2019-03-29", openHistory.toString()); + } + + @Test + public void testParseString() { + String[] mockDates = {"2020-04-08", "2019-04-03", "2016-03-29"}; + Reflect.on(openHistory).call("parseString", StringUtils.join(",", mockDates)); + assertArrayEquals(mockDates, (String[])Reflect.on(openHistory).field("history").get()); + } + + @Test + public void testGetHistorySpanDayCount() { + assertEquals(11, openHistory.getHistorySpanDayCount()); + + Reflect.on(openHistory).set("history", new String[] {"2019-05-03", "2019-05-02", ""}); + assertEquals(2, openHistory.getHistorySpanDayCount()); + + Reflect.on(openHistory).set("history", new String[] {"2019-05-03", "", ""}); + assertEquals(1, openHistory.getHistorySpanDayCount()); + + try { + Reflect.on(openHistory).set("history", new String[] {"", "", ""}); + fail("should not be here"); + } catch (AssertionError ignore) { + } + } + + @Test + public void testHasOpenedToday() { + assertFalse(openHistory.hasOpenedToday()); + + Reflect.on(openHistory).set("history", new String[] {getToday(), "2019-02-02", ""}); + assertTrue(openHistory.hasOpenedToday()); + } + + @Test + public void testUpdate() { + openHistory.update(); + String[] arr = { getToday(), "2019-04-08", "2019-04-03" }; + assertArrayEquals(arr, (String[])Reflect.on(openHistory).field("history").get()); + } + + private String getToday() { + return new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); + } +} diff --git a/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java b/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java index eb9aa2346..1b8fa7f6e 100644 --- a/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java +++ b/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java @@ -150,4 +150,20 @@ public class TemplateInfoCollectorTest { assertEquals(329, consumingMap.get("time_consume")); assertEquals(129, consumingMap.get("originTime")); } + + @Test + public void addIdleDateCount() { + String templateID = "16a988ce-8529-42f5-b17c-2ee849355071"; + TemplateInfoCollector collecter = TemplateInfoCollector.getInstance(); + TemplateInfo templateInfo = collecter.getOrCreateTemplateInfoByID(templateID); + + assertEquals(9, templateInfo.getIdleDayCount()); + + Reflect.on(collecter).call("addIdleDayCount"); + assertEquals(10, templateInfo.getIdleDayCount()); + + // 同一天内多次调用无效 + Reflect.on(collecter).call("addIdleDayCount"); + assertEquals(10, templateInfo.getIdleDayCount()); + } }