From bad2718b1b85d806221fce52c76fa1d388993396 Mon Sep 17 00:00:00 2001 From: Alexander Alexeev Date: Wed, 7 Dec 2016 18:53:37 +0700 Subject: singleton java 8 date formatters --- .../main/java/com/juick/util/DateFormatter.java | 38 ++++++ .../java/com/juick/util/DateFormattersHolder.java | 43 +++++++ .../src/main/java/com/juick/util/MessageUtils.java | 2 + .../com/juick/xml/adapters/SimpleDateAdapter.java | 23 +--- .../src/test/java/com/juick/FormatterTest.java | 45 +++++++ juick-rss/src/main/java/com/juick/rss/Main.java | 16 +-- juick-www/src/main/java/com/juick/www/RSS.java | 6 +- .../com/juick/xmpp/extensions/JuickMessage.java | 132 ++++++++++----------- .../java/com/juick/json/MessageSerializer.java | 19 +-- src/test/java/com/juick/tests/MessageTests.java | 5 +- 10 files changed, 210 insertions(+), 119 deletions(-) create mode 100644 juick-core/src/main/java/com/juick/util/DateFormatter.java create mode 100644 juick-core/src/main/java/com/juick/util/DateFormattersHolder.java create mode 100644 juick-core/src/test/java/com/juick/FormatterTest.java diff --git a/juick-core/src/main/java/com/juick/util/DateFormatter.java b/juick-core/src/main/java/com/juick/util/DateFormatter.java new file mode 100644 index 00000000..34585c63 --- /dev/null +++ b/juick-core/src/main/java/com/juick/util/DateFormatter.java @@ -0,0 +1,38 @@ +package com.juick.util; + +import org.apache.commons.lang3.StringUtils; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +/** + * Created by aalexeev on 12/7/16. + */ +public class DateFormatter { + private final DateTimeFormatter formatter; + + DateFormatter(String pattern) { + formatter = DateTimeFormatter.ofPattern(pattern); + } + + public String format(final Date date) { + if (date == null) + return null; + + LocalDateTime ldt = LocalDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC); + + return ldt.format(formatter); + } + + + public Date parse(final String v) { + if (StringUtils.isBlank(v)) + return null; + + LocalDateTime ldt = LocalDateTime.parse(v, formatter); + + return Date.from(ldt.toInstant(ZoneOffset.UTC)); + } +} diff --git a/juick-core/src/main/java/com/juick/util/DateFormattersHolder.java b/juick-core/src/main/java/com/juick/util/DateFormattersHolder.java new file mode 100644 index 00000000..79414808 --- /dev/null +++ b/juick-core/src/main/java/com/juick/util/DateFormattersHolder.java @@ -0,0 +1,43 @@ +package com.juick.util; + +/** + * Created by aalexeev on 12/7/16. + */ +public class DateFormattersHolder { + + private DateFormattersHolder() { + throw new IllegalStateException(); + } + + private static volatile DateFormatter messageFormatter; + + public static DateFormatter getMessageFormatterInstance() { + DateFormatter localInstance = messageFormatter; + + if (localInstance == null) { + synchronized (DateFormatter.class) { + localInstance = messageFormatter; + + if (localInstance == null) + messageFormatter = localInstance = new DateFormatter("yyyy-MM-dd HH:mm:ss"); + } + } + return localInstance; + } + + private static volatile DateFormatter rssFormatter; + + public static DateFormatter getRssFormatterInstance() { + DateFormatter localInstance = rssFormatter; + + if (localInstance == null) { + synchronized (DateFormatter.class) { + localInstance = rssFormatter; + + if (localInstance == null) + rssFormatter = localInstance = new DateFormatter("EEE, d MMM yyyy HH:mm:ss"); + } + } + return localInstance; + } +} diff --git a/juick-core/src/main/java/com/juick/util/MessageUtils.java b/juick-core/src/main/java/com/juick/util/MessageUtils.java index 12ae71c1..96d650a8 100644 --- a/juick-core/src/main/java/com/juick/util/MessageUtils.java +++ b/juick-core/src/main/java/com/juick/util/MessageUtils.java @@ -24,6 +24,7 @@ public class MessageUtils { return result; } + private static Pattern regexLinks2 = Pattern.compile("((?<=\\s)|(?<=\\A))([\\[\\{]|<)((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\\"\\)\\!]+)/?(?:[^\\]\\}](?" + msg + ""; } + public static String formatMessage(String msg) { msg = msg.replaceAll("&", "&"); msg = msg.replaceAll("<", "<"); diff --git a/juick-core/src/main/java/com/juick/xml/adapters/SimpleDateAdapter.java b/juick-core/src/main/java/com/juick/xml/adapters/SimpleDateAdapter.java index 1093e47a..382db45a 100644 --- a/juick-core/src/main/java/com/juick/xml/adapters/SimpleDateAdapter.java +++ b/juick-core/src/main/java/com/juick/xml/adapters/SimpleDateAdapter.java @@ -1,10 +1,9 @@ package com.juick.xml.adapters; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; +import com.juick.util.DateFormattersHolder; import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.util.Date; /** * Created by vitalyster on 15.11.2016. @@ -12,27 +11,13 @@ import javax.xml.bind.annotation.adapters.XmlAdapter; public class SimpleDateAdapter extends XmlAdapter { - private final SimpleDateFormat dateFormat; - public SimpleDateAdapter() { - dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } - @Override public String marshal(Date v) throws Exception { - if (v == null) { - return null; - } - synchronized (dateFormat) { - return dateFormat.format(v); - } + return DateFormattersHolder.getMessageFormatterInstance().format(v); } @Override public Date unmarshal(String v) throws Exception { - synchronized (dateFormat) { - return dateFormat.parse(v); - } + return DateFormattersHolder.getMessageFormatterInstance().parse(v); } - } diff --git a/juick-core/src/test/java/com/juick/FormatterTest.java b/juick-core/src/test/java/com/juick/FormatterTest.java new file mode 100644 index 00000000..d246c369 --- /dev/null +++ b/juick-core/src/test/java/com/juick/FormatterTest.java @@ -0,0 +1,45 @@ +package com.juick; + +import com.juick.util.DateFormattersHolder; +import org.apache.commons.lang3.RandomUtils; +import org.junit.Test; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +/** + * Created by aalexeev on 12/7/16. + */ +public class FormatterTest { + + @Test + public void forAnyDateFormatterShouldReturnNotEmptyString() throws Exception { + Date date = new Date(); + + assertThat(DateFormattersHolder.getMessageFormatterInstance().format(date), not(isEmptyOrNullString())); + assertThat(DateFormattersHolder.getRssFormatterInstance().format(date), not(isEmptyOrNullString())); + + date = new Date(RandomUtils.nextLong(1, Long.MAX_VALUE / 10000)); + + assertThat(DateFormattersHolder.getMessageFormatterInstance().format(date), not(isEmptyOrNullString())); + assertThat(DateFormattersHolder.getRssFormatterInstance().format(date), not(isEmptyOrNullString())); + } + + @Test + public void forConcreteDateShouldReturnCorrectString() throws Exception { + Calendar calendar = GregorianCalendar.getInstance(); + + calendar.set(2012, 0, 1, 0, 0, 0); + calendar.setTimeZone(TimeZone.getTimeZone("UTC")); + + Date date = calendar.getTime(); + + assertThat(DateFormattersHolder.getMessageFormatterInstance().format(date), equalTo("2012-01-01 00:00:00")); + assertThat(DateFormattersHolder.getRssFormatterInstance().format(date), equalTo("Sun, 1 Jan 2012 00:00:00")); + } +} diff --git a/juick-rss/src/main/java/com/juick/rss/Main.java b/juick-rss/src/main/java/com/juick/rss/Main.java index adb20a0d..8d247465 100644 --- a/juick-rss/src/main/java/com/juick/rss/Main.java +++ b/juick-rss/src/main/java/com/juick/rss/Main.java @@ -18,8 +18,10 @@ package com.juick.rss; import com.juick.Message; +import com.juick.Tag; import com.juick.server.MessagesQueries; import com.juick.server.UserQueries; +import com.juick.util.DateFormattersHolder; import com.juick.util.MessageUtils; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.lang3.StringEscapeUtils; @@ -33,7 +35,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; -import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Properties; @@ -44,7 +45,6 @@ import java.util.Properties; @WebServlet(name = "Main", urlPatterns = {"/"}) public class Main extends HttpServlet { - private static final SimpleDateFormat sdfRSS = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); JdbcTemplate sql; @Override @@ -131,19 +131,19 @@ public class Main extends HttpServlet { out.print("<![CDATA[@" + msg.getUser().getName() + ":"); if (!msg.getTags().isEmpty()) { - for (int n = 0; n < msg.getTags().size(); n++) { - out.print(" *" + msg.getTags().get(n)); + for (Tag tag : msg.getTags()) { + out.print(" *" + tag); } } out.println("]]>"); out.println(""); - out.println("" + sdfRSS.format(msg.getDate()) + ""); + out.println("" + DateFormattersHolder.getRssFormatterInstance().format(msg.getDate()) + ""); out.println("http://juick.com/" + msg.getUser().getName() + "/" + msg.getMid() + ""); if (!msg.getTags().isEmpty()) { - for (int n = 0; n < msg.getTags().size(); n++) { - out.println("" + StringEscapeUtils.escapeHtml4(msg.getTags().get(n).getName()) + ""); + for (Tag tag : msg.getTags()) { + out.println("" + StringEscapeUtils.escapeHtml4(tag.getName()) + ""); } } if (msg.getAttachmentType() != null) { @@ -209,7 +209,7 @@ public class Main extends HttpServlet { out.println("http://juick.com/" + r.uname + "/"); out.println("@" + r.uname + ":"); out.println(""); - out.println("" + sdfRSS.format(r.pubDate) + ""); + out.println("" + DateFormattersHolder.getRssFormatterInstance().format(r.pubDate) + ""); String attachment = r.attachmentType; if (attachment != null && !attachment.isEmpty()) { if (attachment.equals("jpg")) { diff --git a/juick-www/src/main/java/com/juick/www/RSS.java b/juick-www/src/main/java/com/juick/www/RSS.java index a343d13b..91ba9380 100644 --- a/juick-www/src/main/java/com/juick/www/RSS.java +++ b/juick-www/src/main/java/com/juick/www/RSS.java @@ -19,6 +19,7 @@ package com.juick.www; import com.juick.Message; import com.juick.server.MessagesQueries; +import com.juick.util.DateFormattersHolder; import com.juick.util.MessageUtils; import com.mitchellbosecke.pebble.error.PebbleException; import com.mitchellbosecke.pebble.template.PebbleTemplate; @@ -28,7 +29,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; -import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -39,8 +39,6 @@ import java.util.Map; */ public class RSS { - private static final SimpleDateFormat sdfRSS = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); - protected void doGet(JdbcTemplate sql, HttpServletResponse response, int uid) throws ServletException, IOException, PebbleException { List mids = MessagesQueries.getUserBlog(sql, uid, 0, 0); if (mids.isEmpty()) { @@ -58,7 +56,7 @@ public class RSS { Map context = new HashMap<>(); context.put("user", msgs.stream().findFirst().get().getUser()); context.put("msgs", msgs); - context.put("sdfRSS", sdfRSS); + context.put("sdfRSS", DateFormattersHolder.getRssFormatterInstance()); template.evaluate(out, context); } } diff --git a/juick-xmpp/src/main/java/com/juick/xmpp/extensions/JuickMessage.java b/juick-xmpp/src/main/java/com/juick/xmpp/extensions/JuickMessage.java index 18477b2a..b8a329db 100644 --- a/juick-xmpp/src/main/java/com/juick/xmpp/extensions/JuickMessage.java +++ b/juick-xmpp/src/main/java/com/juick/xmpp/extensions/JuickMessage.java @@ -18,35 +18,27 @@ package com.juick.xmpp.extensions; import com.juick.Tag; +import com.juick.util.DateFormattersHolder; +import com.juick.xmpp.StanzaChild; import com.juick.xmpp.utils.XmlUtils; -import com.juick.xmpp.*; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.TimeZone; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.io.IOException; +import java.text.ParseException; + /** - * * @author Ugnich Anton */ public class JuickMessage extends com.juick.Message implements StanzaChild { - public final static String XMLNS = "http://juick.com/message"; public final static String TagName = "juick"; - private SimpleDateFormat df; public JuickMessage() { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); } public JuickMessage(com.juick.Message msg) { super(msg); - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); } @Override @@ -84,7 +76,7 @@ public class JuickMessage extends com.juick.Message implements StanzaChild { } String ts = parser.getAttributeValue(null, "ts"); if (ts != null) { - jmsg.setDate(df.parse(ts)); + jmsg.setDate(DateFormattersHolder.getMessageFormatterInstance().parse(ts)); } jmsg.setAttachmentType(parser.getAttributeValue(null, "attach")); @@ -106,78 +98,76 @@ public class JuickMessage extends com.juick.Message implements StanzaChild { @Override public String toString() { - String ret = ""; + StringBuilder builder = new StringBuilder(); - ret = "<" + TagName + " xmlns=\"" + XMLNS + "\""; - if (getMid() > 0) { - ret += " mid=\"" + getMid() + "\""; - } - if (getRid() > 0) { - ret += " rid=\"" + getRid() + "\""; - } - if (getReplyto() > 0) { - ret += " replyto=\"" + getReplyto() + "\""; - } - ret += " privacy=\"" + getPrivacy() + "\""; - if (FriendsOnly) { - ret += " friendsonly=\"1\""; - } - if (ReadOnly) { - ret += " readonly=\"1\""; - } - if (getDate() != null) { - ret += " ts=\"" + df.format(getDate()) + "\""; - } - if (getAttachmentType() != null) { - ret += " attach=\"" + getAttachmentType() + "\""; - } - ret += ">"; - if (getUser() != null) { - ret += JuickUser.toString(getUser()); - } - if (getText() != null) { - ret += "" + XmlUtils.escape(getText()) + ""; - } - for (com.juick.Tag Tag : getTags()) { - ret += "" + XmlUtils.escape(Tag.getName()) + ""; - } - ret += ""; + builder.append("<").append(TagName).append(" xmlns=\"").append(XMLNS).append("\""); + + if (getMid() > 0) + builder.append(" mid=\"").append(getMid()).append("\""); + + if (getRid() > 0) + builder.append(" rid=\"").append(getRid()).append("\""); + + if (getReplyto() > 0) + builder.append(" replyto=\"").append(getReplyto()).append("\""); + + builder.append(" privacy=\"").append(getPrivacy()).append("\""); + + if (FriendsOnly) + builder.append(" friendsonly=\"1\""); - return ret; + if (ReadOnly) + builder.append(" readonly=\"1\""); + + if (getDate() != null) + builder.append(" ts=\"") + .append(DateFormattersHolder.getMessageFormatterInstance().format(getDate())) + .append("\""); + + if (getAttachmentType() != null) + builder.append(" attach=\"").append(getAttachmentType()).append("\""); + + builder.append(">"); + + if (getUser() != null) + builder.append(JuickUser.toString(getUser())); + + if (getText() != null) + builder.append("").append(XmlUtils.escape(getText())).append(""); + + for (com.juick.Tag Tag : getTags()) + builder.append("").append(XmlUtils.escape(Tag.getName())).append(""); + + builder.append(""); + + return builder.toString(); } @Override public boolean equals(Object obj) { - if (!(obj instanceof JuickMessage)) { + if (obj == this) + return true; + + if (!(obj instanceof JuickMessage)) return false; - } + JuickMessage jmsg = (JuickMessage) obj; return (this.getMid() == jmsg.getMid() && this.getRid() == jmsg.getRid()); } @Override public int compareTo(Object obj) throws ClassCastException { - if (!(obj instanceof JuickMessage)) { - throw new ClassCastException(); - } - JuickMessage jmsg = (JuickMessage) obj; + if (obj == this) + return 0; - if (this.getMid() != jmsg.getMid()) { - if (this.getMid() > jmsg.getMid()) { - return -1; - } else { - return 1; - } - } + if (!(obj instanceof JuickMessage)) + throw new ClassCastException(); - if (this.getRid() != jmsg.getRid()) { - if (this.getRid() < jmsg.getRid()) { - return -1; - } else { - return 1; - } - } + JuickMessage jmsg = (JuickMessage) obj; + int cmp = Integer.compare(jmsg.getMid(), getMid()); + if (cmp == 0) + cmp = Integer.compare(getRid(), jmsg.getRid()); - return 0; + return cmp; } } diff --git a/src/test/java/com/juick/json/MessageSerializer.java b/src/test/java/com/juick/json/MessageSerializer.java index b49c991a..7ed060dd 100644 --- a/src/test/java/com/juick/json/MessageSerializer.java +++ b/src/test/java/com/juick/json/MessageSerializer.java @@ -20,6 +20,7 @@ package com.juick.json; import com.juick.Message; import com.juick.Photo; import com.juick.Tag; +import com.juick.util.DateFormattersHolder; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -27,26 +28,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.TimeZone; import java.util.stream.Collectors; /** - * * @author Ugnich Anton */ public class MessageSerializer extends JSONSerializer { - private final static Logger LOGGER = LoggerFactory.getLogger(MessageSerializer.class); - + UserSerializer userSerializer = new UserSerializer(); PlaceSerializer placeSerializer = new PlaceSerializer(); - private final SimpleDateFormat df; - public MessageSerializer() { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); } @Override @@ -66,7 +59,7 @@ public class MessageSerializer extends JSONSerializer { jmsg.setText(json.getString("body").replace(""", "\"")); jmsg.setUser(userSerializer.deserialize(json.getJSONObject("user"))); - jmsg.setDate(df.parse(json.getString("timestamp"))); + jmsg.setDate(DateFormattersHolder.getMessageFormatterInstance().parse(json.getString("timestamp"))); if (json.has("tags")) { JSONArray tags = json.getJSONArray("tags"); @@ -115,7 +108,7 @@ public class MessageSerializer extends JSONSerializer { json.put("body", msg.getText()); } if (msg.getDate() != null) { - json.put("timestamp", df.format(msg.getDate())); + json.put("timestamp", DateFormattersHolder.getMessageFormatterInstance().format(msg.getDate())); } if (msg.getUser() != null) { json.put("user", userSerializer.serialize(msg.getUser())); @@ -145,8 +138,4 @@ public class MessageSerializer extends JSONSerializer { return json; } - - public SimpleDateFormat getDf() { - return df; - } } diff --git a/src/test/java/com/juick/tests/MessageTests.java b/src/test/java/com/juick/tests/MessageTests.java index 45575ded..a0cfd444 100644 --- a/src/test/java/com/juick/tests/MessageTests.java +++ b/src/test/java/com/juick/tests/MessageTests.java @@ -3,6 +3,7 @@ package com.juick.tests; import static org.junit.Assert.assertEquals; import com.juick.json.MessageSerializer; +import com.juick.util.DateFormattersHolder; import com.juick.xmpp.extensions.JuickMessage; import org.json.JSONObject; import org.junit.Test; @@ -33,7 +34,7 @@ public class MessageTests { msg.setDate(currentDate); MessageSerializer serializer = new MessageSerializer(); JSONObject jsonMessage = serializer.serialize(msg); - assertEquals("date should be in timestamp field", serializer.getDf().format(currentDate), + assertEquals("date should be in timestamp field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), jsonMessage.getString("timestamp")); JuickMessage xmppMessage = new JuickMessage(msg); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -42,7 +43,7 @@ public class MessageTests { Document doc = db.parse(new ByteArrayInputStream(xmppMessage.toString().getBytes("UTF-8"))); Node juickNode = doc.getElementsByTagName("juick").item(0); NamedNodeMap attrs = juickNode.getAttributes(); - assertEquals("date should be in ts field", serializer.getDf().format(currentDate), + assertEquals("date should be in ts field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), attrs.getNamedItem("ts").getNodeValue()); } } \ No newline at end of file -- cgit v1.2.3