From 5b2bd7f928bbf9d3233ff029ed5c09ac46daf0de Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Mon, 28 Nov 2016 14:37:02 +0300 Subject: all components using jackson now, org.json serializer moved to compatibility tests package --- build.gradle | 1 + juick-api/src/main/java/com/juick/api/TGBot.java | 9 +- juick-core/build.gradle | 1 - .../main/java/com/juick/json/JSONSerializer.java | 73 ----------- .../java/com/juick/json/MessageSerializer.java | 145 --------------------- .../main/java/com/juick/json/PlaceSerializer.java | 73 ----------- .../main/java/com/juick/json/UserSerializer.java | 66 ---------- .../java/com/juick/components/Notifications.java | 28 ++-- .../java/com/juick/components/mpns/MPNSError.java | 29 +++++ .../java/com/juick/components/mpns/MPNSToken.java | 29 +++++ juick-server/build.gradle | 1 - .../com/juick/server/protocol/JuickProtocol.java | 38 +++--- juick-ws/build.gradle | 1 + .../src/main/java/com/juick/ws/XMPPConnection.java | 54 ++++---- .../src/main/java/com/juick/www/FacebookLogin.java | 27 ++-- .../src/main/java/com/juick/www/TwitterAuth.java | 10 +- .../main/java/com/juick/www/VKontakteLogin.java | 24 ++-- .../main/java/com/juick/www/facebook/Graph.java | 43 ++++++ .../src/main/java/com/juick/www/twitter/User.java | 19 +++ .../main/java/com/juick/www/vk/GraphResponse.java | 19 +++ .../src/main/java/com/juick/www/vk/Token.java | 29 +++++ juick-www/src/main/java/com/juick/www/vk/User.java | 39 ++++++ .../main/java/com/juick/components/XMPPBot.java | 7 +- src/test/java/com/juick/json/JSONSerializer.java | 73 +++++++++++ .../java/com/juick/json/MessageSerializer.java | 145 +++++++++++++++++++++ src/test/java/com/juick/json/PlaceSerializer.java | 73 +++++++++++ src/test/java/com/juick/json/UserSerializer.java | 66 ++++++++++ src/test/java/com/juick/tests/ApiTests.java | 3 +- 28 files changed, 668 insertions(+), 457 deletions(-) delete mode 100644 juick-core/src/main/java/com/juick/json/JSONSerializer.java delete mode 100644 juick-core/src/main/java/com/juick/json/MessageSerializer.java delete mode 100644 juick-core/src/main/java/com/juick/json/PlaceSerializer.java delete mode 100644 juick-core/src/main/java/com/juick/json/UserSerializer.java create mode 100644 juick-notifications/src/main/java/com/juick/components/mpns/MPNSError.java create mode 100644 juick-notifications/src/main/java/com/juick/components/mpns/MPNSToken.java create mode 100644 juick-www/src/main/java/com/juick/www/facebook/Graph.java create mode 100644 juick-www/src/main/java/com/juick/www/twitter/User.java create mode 100644 juick-www/src/main/java/com/juick/www/vk/GraphResponse.java create mode 100644 juick-www/src/main/java/com/juick/www/vk/Token.java create mode 100644 juick-www/src/main/java/com/juick/www/vk/User.java create mode 100644 src/test/java/com/juick/json/JSONSerializer.java create mode 100644 src/test/java/com/juick/json/MessageSerializer.java create mode 100644 src/test/java/com/juick/json/PlaceSerializer.java create mode 100644 src/test/java/com/juick/json/UserSerializer.java diff --git a/build.gradle b/build.gradle index f0e83b9b..3af0fdae 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,7 @@ dependencies { testCompile project(':juick-core') testCompile project(':juick-www') testCompile project(':juick-xmpp') + testCompile 'org.json:json:20160810' testCompile 'com.fasterxml.jackson.core:jackson-core:2.8.1' testCompile 'com.fasterxml.jackson.core:jackson-databind:2.8.1' testCompile 'org.springframework:spring-jdbc:4.3.4.RELEASE' diff --git a/juick-api/src/main/java/com/juick/api/TGBot.java b/juick-api/src/main/java/com/juick/api/TGBot.java index ae3c6b74..882dc821 100644 --- a/juick-api/src/main/java/com/juick/api/TGBot.java +++ b/juick-api/src/main/java/com/juick/api/TGBot.java @@ -1,6 +1,6 @@ package com.juick.api; -import com.juick.json.MessageSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; import com.juick.service.MessagesService; import com.juick.service.TelegramService; import com.neovisionaries.ws.client.WebSocket; @@ -16,7 +16,6 @@ import com.pengrad.telegrambot.request.SendMessage; import com.pengrad.telegrambot.request.SetWebhook; import com.pengrad.telegrambot.response.SendResponse; import org.apache.commons.lang3.StringUtils; -import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,7 +35,7 @@ public class TGBot implements AutoCloseable { TelegramBot bot; WebSocket ws; - MessageSerializer ms = new MessageSerializer(); + ObjectMapper ms = new ObjectMapper(); @Inject TelegramService telegramService; @@ -71,8 +70,8 @@ public class TGBot implements AutoCloseable { @Override public void onTextMessage(WebSocket websocket, String text) throws Exception { super.onTextMessage(websocket, text); - com.juick.Message jmsg = ms.deserialize(new JSONObject(text)); - logger.info("got jmsg: " + ms.serialize(jmsg).toString()); + com.juick.Message jmsg = ms.readValue(text, com.juick.Message.class); + logger.info("got jmsg: " + ms.writeValueAsString(jmsg)); String msgUrl = formatUrl(jmsg); if (jmsg.getRid() == 0) { String msg = formatPost(jmsg); diff --git a/juick-core/build.gradle b/juick-core/build.gradle index 134156b2..295a22d3 100644 --- a/juick-core/build.gradle +++ b/juick-core/build.gradle @@ -11,7 +11,6 @@ dependencies { compile 'org.apache.commons:commons-lang3:3.5' compile 'org.apache.commons:commons-collections4:4.1' compile 'commons-io:commons-io:2.5' - compile 'org.json:json:20160810' } compileJava.options.encoding = 'UTF-8' diff --git a/juick-core/src/main/java/com/juick/json/JSONSerializer.java b/juick-core/src/main/java/com/juick/json/JSONSerializer.java deleted file mode 100644 index 3dc9e04e..00000000 --- a/juick-core/src/main/java/com/juick/json/JSONSerializer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.juick.json; - -import java.text.ParseException; -import java.util.Iterator; -import java.util.List; -import org.json.JSONObject; - -/** - * - * @author vt - * @param - */ -public abstract class JSONSerializer { - - public enum URIScheme { - Plain, - Secure - } - - private URIScheme uriScheme; - - public URIScheme getUriScheme() { - return uriScheme; - } - - public void setUriScheme(URIScheme uriScheme) { - this.uriScheme = uriScheme; - } - - public JSONSerializer() { - this.uriScheme = URIScheme.Plain; - } - - /** - * - * @param json - * @return - */ - public abstract T deserialize(JSONObject json) throws ParseException; - - /** - * - * @param obj - * @return - */ - public abstract JSONObject serialize(T obj); - - /** - * - * @param objs - * @return - */ - public String serializeList(List objs) { - String json = "["; - - Iterator i = objs.iterator(); - while (i.hasNext()) { - T m = i.next(); - if (json.length() > 1) { - json += ","; - } - json += serialize(m).toString(); - } - - json += "]"; - return json; - } -} diff --git a/juick-core/src/main/java/com/juick/json/MessageSerializer.java b/juick-core/src/main/java/com/juick/json/MessageSerializer.java deleted file mode 100644 index ebc3b0b0..00000000 --- a/juick-core/src/main/java/com/juick/json/MessageSerializer.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Juick - * Copyright (C) 2008-2011, Ugnich Anton - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.juick.json; - -import com.juick.Message; -import com.juick.Tag; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -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 - public Message deserialize(JSONObject json) throws JSONException, ParseException { - com.juick.Message jmsg = new com.juick.Message(); - jmsg.setMid(json.getInt("mid")); - if (json.has("rid")) { - jmsg.setRid(json.getInt("rid")); - } - if (json.has("replyto")) { - jmsg.setReplyto(json.getInt("replyto")); - } - - jmsg.FriendsOnly = json.has("friendsonly"); - jmsg.ReadOnly = json.has("readonly"); - - jmsg.setText(json.getString("body").replace(""", "\"")); - jmsg.setUser(userSerializer.deserialize(json.getJSONObject("user"))); - - jmsg.setDate(df.parse(json.getString("timestamp"))); - - if (json.has("tags")) { - JSONArray tags = json.getJSONArray("tags"); - for (int n = 0; n < tags.length(); n++) { - jmsg.getTags().add(new Tag(tags.getString(n).replace(""", "\""))); - } - } - - if (json.has("replies")) { - jmsg.Replies = json.getInt("replies"); - } - - if (json.has("photo")) { - jmsg.Photo = json.getJSONObject("photo").getString("small"); - } - - return jmsg; - } - - @Override - public JSONObject serialize(Message msg) { - JSONObject json = new JSONObject(); - - try { - if (msg.getMid() > 0) { - json.put("mid", msg.getMid()); - } - if (msg.getRid() > 0) { - json.put("rid", msg.getRid()); - } - if (msg.getReplyto() > 0) { - json.put("replyto", msg.getReplyto()); - } - if (msg.FriendsOnly) { - json.put("friendsonly", 1); - } - if (msg.ReadOnly) { - json.put("readonly", 1); - } - if (msg.getText() != null) { - json.put("body", msg.getText()); - } - if (msg.getDate() != null) { - json.put("timestamp", df.format(msg.getDate())); - } - if (msg.getUser() != null) { - json.put("user", userSerializer.serialize(msg.getUser())); - } - if (msg.getTags() != null && msg.getTags().size() > 0) { - json.put("tags", new JSONArray(msg.getTags().stream().map(Tag::getName).collect(Collectors.toList()))); - } - if (msg.Replies > 0) { - json.put("replies", msg.Replies); - } - if (msg.Place != null) { - json.put("place", placeSerializer.serialize(msg.Place)); - } - if (msg.AttachmentType != null) { - String fname = msg.getMid() + (msg.getRid() > 0 ? "-" + msg.getRid() : "") + "." + msg.AttachmentType; - JSONObject photo = new JSONObject(); - String protocol = getUriScheme() == URIScheme.Plain ? "http:" : "https:"; - photo.put("thumbnail", protocol + "//i.juick.com/ps/" + fname); - photo.put("small", protocol + "//i.juick.com/photos-512/" + fname); - photo.put("medium", protocol + "//i.juick.com/photos-1024/" + fname); - json.put("photo", photo); - } - } catch (JSONException e) { - LOGGER.error("JSON Exception", e); - } - - return json; - } - - public SimpleDateFormat getDf() { - return df; - } -} diff --git a/juick-core/src/main/java/com/juick/json/PlaceSerializer.java b/juick-core/src/main/java/com/juick/json/PlaceSerializer.java deleted file mode 100644 index f433f7f0..00000000 --- a/juick-core/src/main/java/com/juick/json/PlaceSerializer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Juick - * Copyright (C) 2008-2011, Ugnich Anton - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.juick.json; - -import com.juick.Place; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * - * @author Ugnich Anton - */ -public class PlaceSerializer extends JSONSerializer { - - @Override - public Place deserialize(JSONObject json) throws JSONException { - Place jplace = new Place(); - - jplace.pid = json.getInt("pid"); - jplace.lat = json.getDouble("lat"); - jplace.lon = json.getDouble("lon"); - jplace.name = json.getString("name").replace(""", "\""); - if (json.has("users")) { - jplace.users = json.getInt("users"); - } - if (json.has("messages")) { - jplace.messages = json.getInt("messages"); - } - if (json.has("distance")) { - jplace.distance = json.getInt("distance"); - } - - return jplace; - } - - @Override - public JSONObject serialize(Place place) { - JSONObject json = new JSONObject(); - - try { - if (place.pid > 0) { - json.put("pid", place.pid); - } - if (place.lat >= -90 && place.lat <= 90) { - json.put("lat", place.lat); - } - if (place.lon >= -180 && place.lon <= 180) { - json.put("lon", place.lon); - } - if (place.name != null) { - json.put("name", place.name); - } - } catch (JSONException e) { - } - - return json; - } -} diff --git a/juick-core/src/main/java/com/juick/json/UserSerializer.java b/juick-core/src/main/java/com/juick/json/UserSerializer.java deleted file mode 100644 index 120645a6..00000000 --- a/juick-core/src/main/java/com/juick/json/UserSerializer.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Juick - * Copyright (C) 2008-2011, Ugnich Anton - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.juick.json; - -import com.juick.User; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * - * @author Ugnich Anton - */ -public class UserSerializer extends JSONSerializer { - - @Override - public User deserialize(JSONObject json) throws JSONException { - User juser = new User(); - juser.setUid(json.getInt("uid")); - juser.setName(json.getString("uname")); - if (json.has("fullname")) { - juser.setFullName(json.getString("fullname")); - } - return juser; - } - - @Override - public JSONObject serialize(User user) { - JSONObject json = new JSONObject(); - - try { - if (user.getUid() > 0) { - json.put("uid", user.getUid()); - } - if (user.getName() != null) { - json.put("uname", user.getName()); - } - if (user.getFullName() != null) { - json.put("fullname", user.getFullName()); - } - if (user.getJid() != null) { - json.put("jid", user.getJid()); - } - if (user.getUnreadCount() > 0) { - json.put("unreadCount", user.getUnreadCount()); - } - } catch (JSONException e) { - } - - return json; - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/Notifications.java b/juick-notifications/src/main/java/com/juick/components/Notifications.java index cb120ce9..e0155a0a 100644 --- a/juick-notifications/src/main/java/com/juick/components/Notifications.java +++ b/juick-notifications/src/main/java/com/juick/components/Notifications.java @@ -17,8 +17,10 @@ */ package com.juick.components; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.android.gcm.server.*; -import com.juick.json.MessageSerializer; +import com.juick.components.mpns.MPNSError; +import com.juick.components.mpns.MPNSToken; import com.notnoop.apns.APNS; import com.notnoop.apns.ApnsService; import org.apache.commons.lang3.StringEscapeUtils; @@ -35,7 +37,6 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.apache.http.util.TextUtils; -import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.ParameterizedTypeReference; @@ -71,6 +72,8 @@ public class Notifications implements AutoCloseable { private final int xmppPort; private final String xmppPushPassword; + private final ObjectMapper mapper; + @Inject private ApnsService apns; @@ -84,6 +87,7 @@ public class Notifications implements AutoCloseable { xmppHost = env.getProperty("xmpp_host", "localhost"); xmppPort = NumberUtils.toInt(env.getProperty("xmpp_port"), 5347); xmppPushPassword = env.getProperty("push_xmpp_password", ""); + mapper = new ObjectMapper(); } @PostConstruct @@ -114,11 +118,11 @@ public class Notifications implements AutoCloseable { } if (!regids.isEmpty()) { - MessageSerializer messageSerializer = new MessageSerializer(); - String json = messageSerializer.serialize(jmsg).toString(); - logger.info(json); - Message message = new Message.Builder().addData("message", json).build(); try { + ObjectMapper messageSerializer = new ObjectMapper(); + String json = messageSerializer.writeValueAsString(jmsg); + logger.info(json); + Message message = new Message.Builder().addData("message", json).build(); MulticastResult result = GCMSender.send(message, regids, 3); List results = result.getResults(); for (int i = 0; i < results.size(); i++) { @@ -238,15 +242,15 @@ public class Notifications implements AutoCloseable { HttpResponse response = client.execute(httppost); int statusCode = response.getStatusLine().getStatusCode(); String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8); - JSONObject json = new JSONObject(responseContent); if (statusCode != 200) { - throw new IOException(json.opt("error") + ": " + json.opt("error_description")); + MPNSError error = mapper.readValue(responseContent, MPNSError.class); + throw new IOException(error.getError() + ": " + error.getErrorDescription()); } - String tokenType = (String) json.get("token_type"); - if (tokenType.length() >= 1) { - tokenType = Character.toUpperCase(tokenType.charAt(0)) + tokenType.substring(1); + MPNSToken token = mapper.readValue(responseContent, MPNSToken.class); + if (token.getTokenType().length() >= 1) { + token.setTokenType(Character.toUpperCase(token.getTokenType().charAt(0)) + token.getTokenType().substring(1)); } - return tokenType + " " + json.get("access_token"); + return token.getTokenType() + " " + token.getAccessToken(); } void sendWNS(final String wnsToken, final String url, final String xml) throws IOException { diff --git a/juick-notifications/src/main/java/com/juick/components/mpns/MPNSError.java b/juick-notifications/src/main/java/com/juick/components/mpns/MPNSError.java new file mode 100644 index 00000000..de27641e --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/mpns/MPNSError.java @@ -0,0 +1,29 @@ +package com.juick.components.mpns; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Created by vitalyster on 28.11.2016. + */ +public class MPNSError { + private String error; + private String errorDescription; + + @JsonProperty("error") + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + @JsonProperty("error_description") + public String getErrorDescription() { + return errorDescription; + } + + public void setErrorDescription(String errorDescription) { + this.errorDescription = errorDescription; + } +} diff --git a/juick-notifications/src/main/java/com/juick/components/mpns/MPNSToken.java b/juick-notifications/src/main/java/com/juick/components/mpns/MPNSToken.java new file mode 100644 index 00000000..68baf9cd --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/mpns/MPNSToken.java @@ -0,0 +1,29 @@ +package com.juick.components.mpns; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Created by vitalyster on 28.11.2016. + */ +public class MPNSToken { + private String tokenType; + private String accessToken; + + @JsonProperty("token_type") + public String getTokenType() { + return tokenType; + } + + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + @JsonProperty("access_token") + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } +} diff --git a/juick-server/build.gradle b/juick-server/build.gradle index 17c292bb..23387506 100644 --- a/juick-server/build.gradle +++ b/juick-server/build.gradle @@ -41,7 +41,6 @@ dependencies { compile 'org.apache.commons:commons-dbcp2:2.1.1' compile 'com.googlecode.log4jdbc:log4jdbc:1.2' - compile 'org.json:json:20160810' compile 'javax.inject:javax.inject:1' compile 'org.bitbucket.sco0ter.babbler:xmpp-core-client:0ba6c0e2f9' diff --git a/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java b/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java index eb579712..6bd8e11f 100644 --- a/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java +++ b/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java @@ -1,10 +1,11 @@ package com.juick.server.protocol; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.juick.Message; import com.juick.Tag; import com.juick.User; import com.juick.formatters.PlainTextFormatter; -import com.juick.json.MessageSerializer; import com.juick.server.*; import com.juick.server.protocol.annotation.UserCommand; import com.juick.util.TagUtils; @@ -22,7 +23,7 @@ import java.util.stream.Collectors; */ public class JuickProtocol { - MessageSerializer json = new MessageSerializer(); + ObjectMapper json = new ObjectMapper(); JdbcTemplate sql; String baseUri; @@ -41,7 +42,7 @@ public class JuickProtocol { * @throws NoSuchMethodException */ public ProtocolReply getReply(User user, String userInput) throws InvocationTargetException, - IllegalAccessException, NoSuchMethodException { + IllegalAccessException, NoSuchMethodException, JsonProcessingException { Optional cmd = Arrays.stream(getClass().getDeclaredMethods()) .filter(m -> m.isAnnotationPresent(UserCommand.class)) .filter(m -> Pattern.compile(m.getAnnotation(UserCommand.class).pattern(), @@ -64,24 +65,24 @@ public class JuickProtocol { } } - public ProtocolReply postMessage(User user, String input) { + public ProtocolReply postMessage(User user, String input) throws JsonProcessingException { List tags = TagQueries.fromString(sql, input, false); String body = input.substring(TagUtils.toString(tags).length()); int mid = MessagesQueries.createMessage(sql, user.getUid(), body, null, tags); SubscriptionsQueries.subscribeMessage(sql, mid, user.getUid()); //app.events().publishEvent(new JuickMessageEvent(app.messages().getMessage(mid))); return new ProtocolReply("New message posted.\n#" + mid + " " + baseUri + mid, - Optional.of(json.serializeList(Collections.singletonList(MessagesQueries.getMessage(sql, mid))))); + Optional.of(json.writeValueAsString(Collections.singletonList(MessagesQueries.getMessage(sql, mid))))); } @UserCommand(pattern = "^#(\\++)$", help = "#+ - Show last Juick messages (#++ - second page, ...)") - public ProtocolReply commandLast(User user, String... arguments) { + public ProtocolReply commandLast(User user, String... arguments) throws JsonProcessingException { // number of + is the page count int page = arguments[0].length() - 1; List mids = MessagesQueries.getAll(sql, user.getUid(), page); List messages = MessagesQueries.getMessages(sql, mids); return new ProtocolReply("Last messages: \n" + String.join("\n", messages.stream().map(PlainTextFormatter::formatPost) - .collect(Collectors.toList())), Optional.of(json.serializeList(messages))); + .collect(Collectors.toList())), Optional.of(json.writeValueAsString(messages))); } @UserCommand(pattern = "^\\s*bl\\s*$", patternFlags = Pattern.CASE_INSENSITIVE, @@ -182,19 +183,19 @@ public class JuickProtocol { } @UserCommand(pattern = "!", help = "! - Show your favorite messages") - public ProtocolReply commandFavorites(User currentUser, String... args) { + public ProtocolReply commandFavorites(User currentUser, String... args) throws JsonProcessingException { List mids = MessagesQueries.getUserRecommendations(sql, currentUser.getUid(), 0); if (mids.size() > 0) { List messages = MessagesQueries.getMessages(sql, mids); return new ProtocolReply("Favorite messages: \n" + String.join("\n", messages.stream().map(PlainTextFormatter::formatPost) - .collect(Collectors.toList())), Optional.of(json.serializeList(messages))); + .collect(Collectors.toList())), Optional.of(json.writeValueAsString(messages))); } return new ProtocolReply("No favorite messages, try to \"like\" something ;)", Optional.empty()); } @UserCommand(pattern = "^\\@([^\\s\\n\\+]+)(\\+?)$", help = "@username+ - Show user's info and last 10 messages (@username++ - second page, ..)") - public ProtocolReply commandUser(User user, String... arguments) { + public ProtocolReply commandUser(User user, String... arguments) throws JsonProcessingException { User blogUser = UserQueries.getUserByName(sql, arguments[0]); int page = arguments[1].length(); if (blogUser != null) { @@ -203,7 +204,7 @@ public class JuickProtocol { return new ProtocolReply(String.format("Last messages from @%s:\n%s", arguments[0], String.join("\n", messages.stream() .map(Object::toString).collect(Collectors.toList()))), - Optional.of(json.serializeList(messages))); + Optional.of(json.writeValueAsString(messages))); } return new ProtocolReply("User not found", Optional.empty()); } @@ -230,7 +231,7 @@ public class JuickProtocol { } @UserCommand(pattern = "^(#+)$", help = "# - Show last messages from your feed (## - second page, ...)") - public ProtocolReply commandMyFeed(User user, String... arguments) { + public ProtocolReply commandMyFeed(User user, String... arguments) throws JsonProcessingException { // number of # is the page count int page = arguments[0].length() - 1; List mids = MessagesQueries.getMyFeed(sql, user.getUid(), page); @@ -238,7 +239,7 @@ public class JuickProtocol { // TODO: add instructions for empty feed return new ProtocolReply("Your feed: \n" + String.join("\n", messages.stream().map(PlainTextFormatter::formatPost).collect(Collectors.toList())), - Optional.of(json.serializeList(messages))); + Optional.of(json.writeValueAsString(messages))); } @UserCommand(pattern = "^\\s*(on|off)\\s*$", patternFlags = Pattern.CASE_INSENSITIVE, @@ -333,7 +334,7 @@ public class JuickProtocol { } @UserCommand(pattern = "^#(\\d+)(\\+?)$", help = "#1234 - Show message (#1234+ - message with replies)") - public ProtocolReply commandShow(User user, String... arguments) { + public ProtocolReply commandShow(User user, String... arguments) throws JsonProcessingException { boolean showReplies = arguments[1].length() > 0; int mid; try { @@ -348,15 +349,16 @@ public class JuickProtocol { replies.add(0, msg); return new ProtocolReply(String.join("\n", replies.stream().map(PlainTextFormatter::formatPost).collect(Collectors.toList())), - Optional.of(json.serializeList(replies))); + Optional.of(json.writeValueAsString(replies))); } - return new ProtocolReply(PlainTextFormatter.formatPost(msg), Optional.of(json.serializeList(Collections.singletonList(msg)))); + return new ProtocolReply(PlainTextFormatter.formatPost(msg), + Optional.of(json.writeValueAsString(Collections.singletonList(msg)))); } return new ProtocolReply("Message not found", Optional.empty()); } @UserCommand(pattern = "^(#|\\.)(\\d+)((\\.|\\-|\\/)(\\d+))?\\s([\\s\\S]+)", help = "#1234 *tag *tag2 - edit tags\n#1234 text - reply to message") - public ProtocolReply EditOrReply(User user, String... args) { + public ProtocolReply EditOrReply(User user, String... args) throws JsonProcessingException { int mid; try { mid = Integer.parseInt(args[1]); @@ -381,7 +383,7 @@ public class JuickProtocol { int newrid = MessagesQueries.createReply(sql, mid, rid, user.getUid(), txt, null); return new ProtocolReply("Reply posted.\n#" + mid + "/" + newrid + " " + baseUri + mid + "/" + newrid, - Optional.of(json.serializeList(Collections.singletonList(MessagesQueries.getReply(sql, mid, newrid))))); + Optional.of(json.writeValueAsString(Collections.singletonList(MessagesQueries.getReply(sql, mid, newrid))))); } } diff --git a/juick-ws/build.gradle b/juick-ws/build.gradle index b235a2c1..2326a13b 100644 --- a/juick-ws/build.gradle +++ b/juick-ws/build.gradle @@ -15,6 +15,7 @@ def springFrameworkVersion = '4.3.4.RELEASE' dependencies { compile project(':juick-server') + compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.6.3' compile "org.springframework:spring-webmvc:${springFrameworkVersion}" compile "org.springframework:spring-websocket:${springFrameworkVersion}" compile 'com.mitchellbosecke:pebble-spring4:2.3.0' diff --git a/juick-ws/src/main/java/com/juick/ws/XMPPConnection.java b/juick-ws/src/main/java/com/juick/ws/XMPPConnection.java index 30dad3f3..2019ec0a 100644 --- a/juick-ws/src/main/java/com/juick/ws/XMPPConnection.java +++ b/juick-ws/src/main/java/com/juick/ws/XMPPConnection.java @@ -1,7 +1,9 @@ package com.juick.ws; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.juick.User; -import com.juick.json.MessageSerializer; import com.juick.server.MessagesQueries; import com.juick.server.SubscriptionsQueries; import org.apache.commons.lang3.math.NumberUtils; @@ -31,7 +33,7 @@ public class XMPPConnection implements AutoCloseable { private final JdbcTemplate jdbc; private final WebsocketComponent wsHandler; private final String xmppPassword; - private final MessageSerializer ms; + private final ObjectMapper ms; private final int xmppPort; private final String wsJid; @@ -51,29 +53,33 @@ public class XMPPConnection implements AutoCloseable { xmppPort = NumberUtils.toInt(env.getProperty("xmpp_port"), 5347); wsJid = env.getProperty("ws_jid", "ws.juick.local"); - ms = new MessageSerializer(); + ms = new XmlMapper(); XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() .extensions(Extension.of(com.juick.Message.class)) .build(); xmpp = ExternalComponent.create(wsJid, xmppPassword, configuration, "localhost", xmppPort); xmpp.addInboundMessageListener(e -> { - Message msg = e.getMessage(); - com.juick.Message jmsg = msg.getExtension(com.juick.Message.class); - if (jmsg != null) { - logger.info("got msg: " + ms.serialize(jmsg).toString()); - if (jmsg.getMid() == 0) { - int uid_to = NumberUtils.toInt(msg.getTo().getLocal(), 0); - if (uid_to > 0) { - onJuickPM(uid_to, jmsg); + try { + Message msg = e.getMessage(); + com.juick.Message jmsg = msg.getExtension(com.juick.Message.class); + if (jmsg != null) { + logger.info("got msg: " + ms.writeValueAsString(jmsg)); + if (jmsg.getMid() == 0) { + int uid_to = NumberUtils.toInt(msg.getTo().getLocal(), 0); + if (uid_to > 0) { + onJuickPM(uid_to, jmsg); + } + } else if (jmsg.getRid() == 0) { + onJuickMessagePost(jmsg); + } else { + // to get quote + com.juick.Message reply = MessagesQueries.getReply(jdbc, jmsg.getMid(), jmsg.getRid()); + onJuickMessageReply(reply); } - } else if (jmsg.getRid() == 0) { - onJuickMessagePost(jmsg); - } else { - // to get quote - com.juick.Message reply = MessagesQueries.getReply(jdbc, jmsg.getMid(), jmsg.getRid()); - onJuickMessageReply(reply); } + } catch (JsonProcessingException ex) { + logger.error("mapper exception", ex); } }); try { @@ -91,10 +97,8 @@ public class XMPPConnection implements AutoCloseable { logger.info("XmppSession on WS destroyed"); } - MessageSerializer messageSerializer = new MessageSerializer(); - - private void onJuickPM(final int uid_to, final com.juick.Message jmsg) { - String json = messageSerializer.serialize(jmsg).toString(); + private void onJuickPM(final int uid_to, final com.juick.Message jmsg) throws JsonProcessingException { + String json = ms.writeValueAsString(jmsg); synchronized (wsHandler.getClients()) { wsHandler.getClients().stream().filter(c -> !c.legacy && c.visitor.getUid() == uid_to).forEach(c -> { try { @@ -107,8 +111,8 @@ public class XMPPConnection implements AutoCloseable { } } - private void onJuickMessagePost(final com.juick.Message jmsg) { - String json = messageSerializer.serialize(jmsg).toString(); + private void onJuickMessagePost(final com.juick.Message jmsg) throws JsonProcessingException { + String json = ms.writeValueAsString(jmsg); List uids = SubscriptionsQueries.getSubscribedUsers(jdbc, jmsg.getUser().getUid(), jmsg.getMid()) .stream().map(User::getUid).collect(Collectors.toList()); synchronized (wsHandler.getClients()) { @@ -136,8 +140,8 @@ public class XMPPConnection implements AutoCloseable { } } - private void onJuickMessageReply(final com.juick.Message jmsg) { - String json = messageSerializer.serialize(jmsg).toString(); + private void onJuickMessageReply(final com.juick.Message jmsg) throws JsonProcessingException { + String json = ms.writeValueAsString(jmsg); List threadUsers = SubscriptionsQueries.getUsersSubscribedToComments(jdbc, jmsg.getMid(), jmsg.getUser().getUid()) .stream().map(User::getUid).collect(Collectors.toList()); diff --git a/juick-www/src/main/java/com/juick/www/FacebookLogin.java b/juick-www/src/main/java/com/juick/www/FacebookLogin.java index 2b67dd5c..b42bb23b 100644 --- a/juick-www/src/main/java/com/juick/www/FacebookLogin.java +++ b/juick-www/src/main/java/com/juick/www/FacebookLogin.java @@ -17,8 +17,11 @@ */ package com.juick.www; +import com.fasterxml.jackson.databind.ObjectMapper; import com.juick.server.UserQueries; -import org.json.JSONObject; +import com.juick.www.facebook.Graph; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; @@ -43,10 +46,12 @@ public class FacebookLogin { private final String FACEBOOK_APPID; private final String FACEBOOK_SECRET; private final String FACEBOOK_REDIRECT = "http://juick.com/_fblogin"; + private final ObjectMapper mapper; public FacebookLogin(String ApplicationID, String secret) { this.FACEBOOK_APPID = ApplicationID; this.FACEBOOK_SECRET = secret; + mapper = new ObjectMapper(); } protected void doGet(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -94,24 +99,16 @@ public class FacebookLogin { } try { - JSONObject json = new JSONObject(graph); - String fbIDStr = json.getString("id"); - String fbName = json.getString("name"); - String fbLink = json.getString("link"); - boolean fbVerified = json.getBoolean("verified"); - - long fbID = 0; - if (fbIDStr != null && !fbIDStr.isEmpty()) { - fbID = Long.parseLong(fbIDStr); - } + Graph fb = mapper.readValue(graph, Graph.class); - if (fbID == 0 || fbName == null || fbLink == null || fbName.isEmpty() || fbLink.isEmpty()) { + long fbID = NumberUtils.toLong(fb.getId(), 0); + if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) { throw new Exception(); } int uid = getUIDbyFBID(sql, fbID); if (uid > 0) { - if (!updateDB(sql, fbID, token, fbName, fbLink)) { + if (!updateDB(sql, fbID, token, fb.getName(), fb.getLink())) { throw new Exception(); } Cookie c = new Cookie("hash", UserQueries.getHashByUID(sql, uid)); @@ -119,9 +116,9 @@ public class FacebookLogin { response.addCookie(c); response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location", "/"); - } else if (fbVerified) { + } else if (fb.getVerified()) { String loginhash = UUID.randomUUID().toString(); - if (!insertDB(sql, fbID, loginhash, token, fbName, fbLink)) { + if (!insertDB(sql, fbID, loginhash, token, fb.getName(), fb.getLink())) { throw new Exception(); } response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); diff --git a/juick-www/src/main/java/com/juick/www/TwitterAuth.java b/juick-www/src/main/java/com/juick/www/TwitterAuth.java index 5ea58eb3..c6aaf9a1 100644 --- a/juick-www/src/main/java/com/juick/www/TwitterAuth.java +++ b/juick-www/src/main/java/com/juick/www/TwitterAuth.java @@ -1,5 +1,6 @@ package com.juick.www; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.scribejava.apis.TwitterApi; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.model.OAuth1AccessToken; @@ -8,7 +9,6 @@ import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Verb; import com.github.scribejava.core.oauth.OAuth10aService; import com.juick.server.UserQueries; -import org.json.JSONObject; import org.springframework.jdbc.core.JdbcTemplate; import javax.servlet.ServletException; @@ -26,9 +26,12 @@ public class TwitterAuth { private String consumerKey, consumerSecret; + private final ObjectMapper mapper; + public TwitterAuth(String consumerKey, String consumerSecret) { this.consumerKey = consumerKey; this.consumerSecret = consumerSecret; + mapper = new ObjectMapper(); } protected void doGet(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response) @@ -72,10 +75,9 @@ public class TwitterAuth { OAuth1AccessToken accessToken = oAuthService.getAccessToken(requestToken, verifier); OAuthRequest oAuthRequest = new OAuthRequest(Verb.GET, VERIFY_URL, oAuthService); oAuthService.signRequest(accessToken, oAuthRequest); - JSONObject jsonResponse = new JSONObject(oAuthRequest.send().getBody()); - String screenName = jsonResponse.getString("screen_name"); + com.juick.www.twitter.User twitterUser = mapper.readValue(oAuthRequest.send().getBody(), com.juick.www.twitter.User.class); if (UserQueries.linkTwitterAccount(sql, user, accessToken.getToken(), accessToken.getTokenSecret(), - screenName)) { + twitterUser.getScreenName())) { response.setStatus(HttpServletResponse.SC_FOUND); response.setHeader("Location", "http://juick.com/settings"); } else { diff --git a/juick-www/src/main/java/com/juick/www/VKontakteLogin.java b/juick-www/src/main/java/com/juick/www/VKontakteLogin.java index f0010ac8..83619b2a 100644 --- a/juick-www/src/main/java/com/juick/www/VKontakteLogin.java +++ b/juick-www/src/main/java/com/juick/www/VKontakteLogin.java @@ -17,9 +17,9 @@ */ package com.juick.www; +import com.fasterxml.jackson.databind.ObjectMapper; import com.juick.server.UserQueries; -import org.json.JSONException; -import org.json.JSONObject; +import com.juick.www.vk.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; @@ -43,6 +43,8 @@ public class VKontakteLogin { private static final String VK_SECRET = "z2afNI8jA5lIpZ2jsTm1"; private static final String VK_REDIRECT = "http://juick.com/_vklogin"; + private final ObjectMapper mapper = new ObjectMapper(); + protected void doGet(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String code = request.getParameter("code"); if (code == null || code.equals("")) { @@ -60,15 +62,9 @@ public class VKontakteLogin { } String token = null; long vkID = 0; - try { - JSONObject json = new JSONObject(tokenjson); - token = json.getString("access_token"); - vkID = json.getLong("user_id"); - } catch (JSONException e) { - logger.error("VK TOKEN EXCEPTION: ", e); - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - return; - } + Token json = mapper.readValue(tokenjson, Token.class); + token = json.getAccessToken(); + vkID = json.getUserId(); if (token == null || vkID == 0) { logger.error("VK TOKEN EMPTY: " + tokenjson); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); @@ -85,9 +81,9 @@ public class VKontakteLogin { } try { - JSONObject json = new JSONObject(graph).getJSONArray("response").getJSONObject(0); - String vkName = json.getString("first_name") + " " + json.getString("last_name"); - String vkLink = json.getString("screen_name"); + com.juick.www.vk.User jsonUser = mapper.readValue(graph, GraphResponse.class).getUser(); + String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName(); + String vkLink = jsonUser.getScreenName(); if (vkName == null || vkLink == null || vkName.isEmpty() || vkName.length() == 1 || vkLink.isEmpty()) { throw new Exception(); diff --git a/juick-www/src/main/java/com/juick/www/facebook/Graph.java b/juick-www/src/main/java/com/juick/www/facebook/Graph.java new file mode 100644 index 00000000..b5827751 --- /dev/null +++ b/juick-www/src/main/java/com/juick/www/facebook/Graph.java @@ -0,0 +1,43 @@ +package com.juick.www.facebook; + +/** + * Created by vitalyster on 28.11.2016. + */ +public class Graph { + private String id; + private String name; + private String link; + private boolean verified; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public boolean getVerified() { + return verified; + } + + public void setVerified(boolean verified) { + this.verified = verified; + } +} diff --git a/juick-www/src/main/java/com/juick/www/twitter/User.java b/juick-www/src/main/java/com/juick/www/twitter/User.java new file mode 100644 index 00000000..47b90f9a --- /dev/null +++ b/juick-www/src/main/java/com/juick/www/twitter/User.java @@ -0,0 +1,19 @@ +package com.juick.www.twitter; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Created by vitalyster on 28.11.2016. + */ +public class User { + private String screenName; + + @JsonProperty("screen_name") + public String getScreenName() { + return screenName; + } + + public void setScreenName(String screenName) { + this.screenName = screenName; + } +} diff --git a/juick-www/src/main/java/com/juick/www/vk/GraphResponse.java b/juick-www/src/main/java/com/juick/www/vk/GraphResponse.java new file mode 100644 index 00000000..f1985a91 --- /dev/null +++ b/juick-www/src/main/java/com/juick/www/vk/GraphResponse.java @@ -0,0 +1,19 @@ +package com.juick.www.vk; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Created by vitalyster on 28.11.2016. + */ +public class GraphResponse { + private User user; + + @JsonValue + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } +} diff --git a/juick-www/src/main/java/com/juick/www/vk/Token.java b/juick-www/src/main/java/com/juick/www/vk/Token.java new file mode 100644 index 00000000..abeb7c96 --- /dev/null +++ b/juick-www/src/main/java/com/juick/www/vk/Token.java @@ -0,0 +1,29 @@ +package com.juick.www.vk; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Created by vitalyster on 28.11.2016. + */ +public class Token { + private Long userId; + private String accessToken; + + @JsonProperty("user_id") + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + @JsonProperty("access_token") + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } +} diff --git a/juick-www/src/main/java/com/juick/www/vk/User.java b/juick-www/src/main/java/com/juick/www/vk/User.java new file mode 100644 index 00000000..c197da2e --- /dev/null +++ b/juick-www/src/main/java/com/juick/www/vk/User.java @@ -0,0 +1,39 @@ +package com.juick.www.vk; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Created by vitalyster on 28.11.2016. + */ +public class User { + private String firstName; + private String lastName; + private String screenName; + + @JsonProperty("first_name") + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + @JsonProperty("last_name") + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @JsonProperty("screen_name") + public String getScreenName() { + return screenName; + } + + public void setScreenName(String screenName) { + this.screenName = screenName; + } +} diff --git a/juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java b/juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java index 43ed3dde..15ba073e 100644 --- a/juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java +++ b/juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java @@ -1,5 +1,6 @@ package com.juick.components; +import com.fasterxml.jackson.core.JsonProcessingException; import com.juick.User; import com.juick.server.UserQueries; import com.juick.server.helpers.UserInfo; @@ -78,16 +79,14 @@ public class XMPPBot implements AutoCloseable { replyMessage.setBody(reply.getDescription()); replyMessage.setFrom(juickJid); component.send(replyMessage); - } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException ex) { + } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException | JsonProcessingException ex) { logger.warn("unhandled error", ex); } } }); component.connect(); - } catch (XmppException e) { + } catch (XmppException | IOException e) { logger.error("bot connection error", e); - } catch (IOException e) { - logger.error("bot initialization error", e); } } diff --git a/src/test/java/com/juick/json/JSONSerializer.java b/src/test/java/com/juick/json/JSONSerializer.java new file mode 100644 index 00000000..3dc9e04e --- /dev/null +++ b/src/test/java/com/juick/json/JSONSerializer.java @@ -0,0 +1,73 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.juick.json; + +import java.text.ParseException; +import java.util.Iterator; +import java.util.List; +import org.json.JSONObject; + +/** + * + * @author vt + * @param + */ +public abstract class JSONSerializer { + + public enum URIScheme { + Plain, + Secure + } + + private URIScheme uriScheme; + + public URIScheme getUriScheme() { + return uriScheme; + } + + public void setUriScheme(URIScheme uriScheme) { + this.uriScheme = uriScheme; + } + + public JSONSerializer() { + this.uriScheme = URIScheme.Plain; + } + + /** + * + * @param json + * @return + */ + public abstract T deserialize(JSONObject json) throws ParseException; + + /** + * + * @param obj + * @return + */ + public abstract JSONObject serialize(T obj); + + /** + * + * @param objs + * @return + */ + public String serializeList(List objs) { + String json = "["; + + Iterator i = objs.iterator(); + while (i.hasNext()) { + T m = i.next(); + if (json.length() > 1) { + json += ","; + } + json += serialize(m).toString(); + } + + json += "]"; + return json; + } +} diff --git a/src/test/java/com/juick/json/MessageSerializer.java b/src/test/java/com/juick/json/MessageSerializer.java new file mode 100644 index 00000000..ebc3b0b0 --- /dev/null +++ b/src/test/java/com/juick/json/MessageSerializer.java @@ -0,0 +1,145 @@ +/* + * Juick + * Copyright (C) 2008-2011, Ugnich Anton + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.juick.json; + +import com.juick.Message; +import com.juick.Tag; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +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 + public Message deserialize(JSONObject json) throws JSONException, ParseException { + com.juick.Message jmsg = new com.juick.Message(); + jmsg.setMid(json.getInt("mid")); + if (json.has("rid")) { + jmsg.setRid(json.getInt("rid")); + } + if (json.has("replyto")) { + jmsg.setReplyto(json.getInt("replyto")); + } + + jmsg.FriendsOnly = json.has("friendsonly"); + jmsg.ReadOnly = json.has("readonly"); + + jmsg.setText(json.getString("body").replace(""", "\"")); + jmsg.setUser(userSerializer.deserialize(json.getJSONObject("user"))); + + jmsg.setDate(df.parse(json.getString("timestamp"))); + + if (json.has("tags")) { + JSONArray tags = json.getJSONArray("tags"); + for (int n = 0; n < tags.length(); n++) { + jmsg.getTags().add(new Tag(tags.getString(n).replace(""", "\""))); + } + } + + if (json.has("replies")) { + jmsg.Replies = json.getInt("replies"); + } + + if (json.has("photo")) { + jmsg.Photo = json.getJSONObject("photo").getString("small"); + } + + return jmsg; + } + + @Override + public JSONObject serialize(Message msg) { + JSONObject json = new JSONObject(); + + try { + if (msg.getMid() > 0) { + json.put("mid", msg.getMid()); + } + if (msg.getRid() > 0) { + json.put("rid", msg.getRid()); + } + if (msg.getReplyto() > 0) { + json.put("replyto", msg.getReplyto()); + } + if (msg.FriendsOnly) { + json.put("friendsonly", 1); + } + if (msg.ReadOnly) { + json.put("readonly", 1); + } + if (msg.getText() != null) { + json.put("body", msg.getText()); + } + if (msg.getDate() != null) { + json.put("timestamp", df.format(msg.getDate())); + } + if (msg.getUser() != null) { + json.put("user", userSerializer.serialize(msg.getUser())); + } + if (msg.getTags() != null && msg.getTags().size() > 0) { + json.put("tags", new JSONArray(msg.getTags().stream().map(Tag::getName).collect(Collectors.toList()))); + } + if (msg.Replies > 0) { + json.put("replies", msg.Replies); + } + if (msg.Place != null) { + json.put("place", placeSerializer.serialize(msg.Place)); + } + if (msg.AttachmentType != null) { + String fname = msg.getMid() + (msg.getRid() > 0 ? "-" + msg.getRid() : "") + "." + msg.AttachmentType; + JSONObject photo = new JSONObject(); + String protocol = getUriScheme() == URIScheme.Plain ? "http:" : "https:"; + photo.put("thumbnail", protocol + "//i.juick.com/ps/" + fname); + photo.put("small", protocol + "//i.juick.com/photos-512/" + fname); + photo.put("medium", protocol + "//i.juick.com/photos-1024/" + fname); + json.put("photo", photo); + } + } catch (JSONException e) { + LOGGER.error("JSON Exception", e); + } + + return json; + } + + public SimpleDateFormat getDf() { + return df; + } +} diff --git a/src/test/java/com/juick/json/PlaceSerializer.java b/src/test/java/com/juick/json/PlaceSerializer.java new file mode 100644 index 00000000..f433f7f0 --- /dev/null +++ b/src/test/java/com/juick/json/PlaceSerializer.java @@ -0,0 +1,73 @@ +/* + * Juick + * Copyright (C) 2008-2011, Ugnich Anton + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.juick.json; + +import com.juick.Place; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * + * @author Ugnich Anton + */ +public class PlaceSerializer extends JSONSerializer { + + @Override + public Place deserialize(JSONObject json) throws JSONException { + Place jplace = new Place(); + + jplace.pid = json.getInt("pid"); + jplace.lat = json.getDouble("lat"); + jplace.lon = json.getDouble("lon"); + jplace.name = json.getString("name").replace(""", "\""); + if (json.has("users")) { + jplace.users = json.getInt("users"); + } + if (json.has("messages")) { + jplace.messages = json.getInt("messages"); + } + if (json.has("distance")) { + jplace.distance = json.getInt("distance"); + } + + return jplace; + } + + @Override + public JSONObject serialize(Place place) { + JSONObject json = new JSONObject(); + + try { + if (place.pid > 0) { + json.put("pid", place.pid); + } + if (place.lat >= -90 && place.lat <= 90) { + json.put("lat", place.lat); + } + if (place.lon >= -180 && place.lon <= 180) { + json.put("lon", place.lon); + } + if (place.name != null) { + json.put("name", place.name); + } + } catch (JSONException e) { + } + + return json; + } +} diff --git a/src/test/java/com/juick/json/UserSerializer.java b/src/test/java/com/juick/json/UserSerializer.java new file mode 100644 index 00000000..120645a6 --- /dev/null +++ b/src/test/java/com/juick/json/UserSerializer.java @@ -0,0 +1,66 @@ +/* + * Juick + * Copyright (C) 2008-2011, Ugnich Anton + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.juick.json; + +import com.juick.User; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * + * @author Ugnich Anton + */ +public class UserSerializer extends JSONSerializer { + + @Override + public User deserialize(JSONObject json) throws JSONException { + User juser = new User(); + juser.setUid(json.getInt("uid")); + juser.setName(json.getString("uname")); + if (json.has("fullname")) { + juser.setFullName(json.getString("fullname")); + } + return juser; + } + + @Override + public JSONObject serialize(User user) { + JSONObject json = new JSONObject(); + + try { + if (user.getUid() > 0) { + json.put("uid", user.getUid()); + } + if (user.getName() != null) { + json.put("uname", user.getName()); + } + if (user.getFullName() != null) { + json.put("fullname", user.getFullName()); + } + if (user.getJid() != null) { + json.put("jid", user.getJid()); + } + if (user.getUnreadCount() > 0) { + json.put("unreadCount", user.getUnreadCount()); + } + } catch (JSONException e) { + } + + return json; + } +} diff --git a/src/test/java/com/juick/tests/ApiTests.java b/src/test/java/com/juick/tests/ApiTests.java index b80b9eb9..727447e0 100644 --- a/src/test/java/com/juick/tests/ApiTests.java +++ b/src/test/java/com/juick/tests/ApiTests.java @@ -2,6 +2,7 @@ package com.juick.tests; import ch.vorburger.exec.ManagedProcessException; import ch.vorburger.mariadb4j.DB; +import com.fasterxml.jackson.core.JsonProcessingException; import com.juick.Message; import com.juick.Tag; import com.juick.User; @@ -100,7 +101,7 @@ public class ApiTests { } @Test - public void protocolTests() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, ParseException { + public void protocolTests() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, ParseException, JsonProcessingException { String baseUri = "http://localhost/"; JuickProtocol protocol = new JuickProtocol(jdbc, baseUri); MessageSerializer json = new MessageSerializer(); -- cgit v1.2.3