aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--juick-notifications/src/main/java/com/juick/components/Notifications.java233
-rw-r--r--juick-notifications/src/main/java/com/juick/components/configuration/NotificationsAppConfiguration.java14
-rw-r--r--juick-notifications/src/main/java/com/juick/components/configuration/XMPPConfiguration.java33
3 files changed, 125 insertions, 155 deletions
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 69b64c0d..0402f36c 100644
--- a/juick-notifications/src/main/java/com/juick/components/Notifications.java
+++ b/juick-notifications/src/main/java/com/juick/components/Notifications.java
@@ -22,22 +22,22 @@ import com.google.android.gcm.server.*;
import com.juick.ExternalToken;
import com.juick.User;
import com.juick.formatters.PlainTextFormatter;
+import com.juick.server.component.MessageEvent;
import com.turo.pushy.apns.ApnsClient;
import com.turo.pushy.apns.PushNotificationResponse;
import com.turo.pushy.apns.util.ApnsPayloadBuilder;
import com.turo.pushy.apns.util.SimpleApnsPushNotification;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationListener;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
-import rocks.xmpp.core.XmppException;
-import rocks.xmpp.extensions.component.accept.ExternalComponent;
+import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.IOException;
@@ -49,14 +49,12 @@ import java.util.stream.Collectors;
/**
* @author Ugnich Anton
*/
-public class Notifications implements NotificationClientListener, AutoCloseable {
+public class Notifications implements NotificationClientListener, AutoCloseable, ApplicationListener<MessageEvent> {
private static Logger logger = LoggerFactory.getLogger(Notifications.class);
@Inject
private RestTemplate rest;
@Inject
- private ExternalComponent xmpp;
- @Inject
private Sender GCMSender;
@Inject
@@ -76,145 +74,138 @@ public class Notifications implements NotificationClientListener, AutoCloseable
@PostConstruct
public void init() throws IOException {
mpnsClient.setListener(this);
- xmpp.addInboundMessageListener(e -> {
- rocks.xmpp.core.stanza.model.Message msg = e.getMessage();
- com.juick.Message jmsg = msg.getExtension(com.juick.Message.class);
- boolean isPM = jmsg.getMid() == 0;
- boolean isReply = jmsg.getRid() > 0;
- int pmTo = NumberUtils.toInt(msg.getTo().getLocal(), 0);
+ }
+ @Override
+ public void onApplicationEvent(@Nonnull MessageEvent event) {
+ com.juick.Message jmsg = event.getMessage();
+ boolean isPM = jmsg.getMid() == 0;
+ boolean isReply = jmsg.getRid() > 0;
+ User pmTo = jmsg.getTo();
- final List<User> users = new ArrayList<>();
- if (isPM) {
- users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%d",
- pmTo),
+ final List<User> users = new ArrayList<>();
+ if (isPM) {
+ users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%d",
+ pmTo.getUid()),
+ HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() {
+ }).getBody());
+ } else {
+ if (isReply) {
+ users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%d&mid=%d&rid=%d",
+ jmsg.getUser().getUid(), jmsg.getMid(), jmsg.getRid()),
HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() {
}).getBody());
} else {
- if (isReply) {
- users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%d&mid=%d&rid=%d",
- jmsg.getUser().getUid(), jmsg.getMid(), jmsg.getRid()),
- HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() {
- }).getBody());
- } else {
- users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%s&mid=%s",
- jmsg.getUser().getUid(), jmsg.getMid()),
- HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() {
- }).getBody());
- }
+ users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%s&mid=%s",
+ jmsg.getUser().getUid(), jmsg.getMid()),
+ HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() {
+ }).getBody());
}
+ }
- // GCM
- List<String> regids = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("gcm"))
- .map(ExternalToken::getToken).collect(Collectors.toList());
- if (!regids.isEmpty()) {
- try {
- String json = jsonMapper.writeValueAsString(jmsg);
- logger.info(json);
- Message message = new Message.Builder().addData("message", json).build();
- MulticastResult result = GCMSender.send(message, regids, 3);
- List<Result> results = result.getResults();
- for (int i = 0; i < results.size(); i++) {
- Result currentResult = results.get(i);
- logger.info("RES {}: {}", i, currentResult);
- List<String> errorCodes = Arrays.asList(Constants.ERROR_MISMATCH_SENDER_ID, Constants.ERROR_NOT_REGISTERED);
- if (errorCodes.contains(currentResult.getErrorCodeName())) {
- // assuming results are in order of regids
- // http://stackoverflow.com/a/11594531/1097384
- String currentId = regids.get(i);
- logger.info("{} is scheduled to remove", currentId);
- addInvalidGCMToken(currentId);
- }
+ // GCM
+ List<String> regids = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("gcm"))
+ .map(ExternalToken::getToken).collect(Collectors.toList());
+ if (!regids.isEmpty()) {
+ try {
+ String json = jsonMapper.writeValueAsString(jmsg);
+ logger.info(json);
+ Message message = new Message.Builder().addData("message", json).build();
+ MulticastResult result = GCMSender.send(message, regids, 3);
+ List<Result> results = result.getResults();
+ for (int i = 0; i < results.size(); i++) {
+ Result currentResult = results.get(i);
+ logger.info("RES {}: {}", i, currentResult);
+ List<String> errorCodes = Arrays.asList(Constants.ERROR_MISMATCH_SENDER_ID, Constants.ERROR_NOT_REGISTERED);
+ if (errorCodes.contains(currentResult.getErrorCodeName())) {
+ // assuming results are in order of regids
+ // http://stackoverflow.com/a/11594531/1097384
+ String currentId = regids.get(i);
+ logger.info("{} is scheduled to remove", currentId);
+ addInvalidGCMToken(currentId);
}
- } catch (IOException ex) {
- logger.error(ex.getMessage(), ex);
- } catch (IllegalArgumentException err) {
- logger.warn("Android: Invalid API Key", err);
}
- } else {
- logger.info("GMS: no recipients");
+ } catch (IOException ex) {
+ logger.error(ex.getMessage(), ex);
+ } catch (IllegalArgumentException err) {
+ logger.warn("Android: Invalid API Key", err);
}
+ } else {
+ logger.info("GMS: no recipients");
+ }
- /*** WinPhone ***/
- List<String> urls = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("mpns"))
- .map(ExternalToken::getToken).collect(Collectors.toList());
+ /*** WinPhone ***/
+ List<String> urls = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("mpns"))
+ .map(ExternalToken::getToken).collect(Collectors.toList());
- if (urls.isEmpty()) {
- logger.info("WNS: no recipients");
- } else {
- try {
- String text1 = "@" + jmsg.getUser().getName();
- if (!jmsg.getTags().isEmpty()) {
- text1 += ":" + StringEscapeUtils.escapeXml11(jmsg.getTagsString());
- }
- String text2 = StringEscapeUtils.escapeXml11(StringUtils.defaultString(jmsg.getText()));
- String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
- + "<toast>"
- + "<visual>"
- + "<binding template=\"ToastImageAndText02\">"
- + "<image id=\"1\" src=\"http://i.juick.com/as/" + jmsg.getUser().getUid() + ".png\" />"
- + "<text id=\"1\">" + text1 + "</text>"
- + "<text id=\"2\">" + text2 + "</text>"
- + "</binding>"
- + "</visual>"
- + "<commands>"
- + "<command arguments=\"/ThreadView.xaml?mid=" + jmsg.getMid() + "\" />"
- + "</commands>"
- + "</toast>";
- logger.trace(xml);
- for (String url : urls) {
- logger.info("WNS: {}", url);
- mpnsClient.sendNotification(url, xml);
- }
- } catch (IOException | IllegalStateException ex) {
- logger.error("WNS: ", ex);
+ if (urls.isEmpty()) {
+ logger.info("WNS: no recipients");
+ } else {
+ try {
+ String text1 = "@" + jmsg.getUser().getName();
+ if (!jmsg.getTags().isEmpty()) {
+ text1 += ":" + StringEscapeUtils.escapeXml11(jmsg.getTagsString());
}
+ String text2 = StringEscapeUtils.escapeXml11(StringUtils.defaultString(jmsg.getText()));
+ String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ + "<toast>"
+ + "<visual>"
+ + "<binding template=\"ToastImageAndText02\">"
+ + "<image id=\"1\" src=\"http://i.juick.com/as/" + jmsg.getUser().getUid() + ".png\" />"
+ + "<text id=\"1\">" + text1 + "</text>"
+ + "<text id=\"2\">" + text2 + "</text>"
+ + "</binding>"
+ + "</visual>"
+ + "<commands>"
+ + "<command arguments=\"/ThreadView.xaml?mid=" + jmsg.getMid() + "\" />"
+ + "</commands>"
+ + "</toast>";
+ logger.trace(xml);
+ for (String url : urls) {
+ logger.info("WNS: {}", url);
+ mpnsClient.sendNotification(url, xml);
+ }
+ } catch (IOException | IllegalStateException ex) {
+ logger.error("WNS: ", ex);
}
+ }
- /*** iOS ***/
- List<String> tokens = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("apns"))
- .map(ExternalToken::getToken).collect(Collectors.toList());
- if (!tokens.isEmpty()) {
- ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder();
- apnsPayloadBuilder.addCustomProperty("mid", jmsg.getMid());
- String post = PlainTextFormatter.formatPost(jmsg);
- String[] parts = post.split("\n", 2);
- String payload = apnsPayloadBuilder.setAlertTitle(parts[0])
- .setAlertBody(parts[1]).buildWithDefaultMaximumLength();
- for (String token : tokens) {
- final Future<PushNotificationResponse<SimpleApnsPushNotification>> notification
- = apns.sendNotification(new SimpleApnsPushNotification(token, topic, payload));
- try {
- final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse
- = notification.get();
- if (pushNotificationResponse.isAccepted()) {
- logger.info("APNS accepted: {}", token);
- } else {
- String reason = pushNotificationResponse.getRejectionReason();
- logger.info("APNS rejected: {}", reason);
- if (reason.equals("BadDeviceToken")) {
- invalidAPNSTokens.add(token);
- }
+ /*** iOS ***/
+ List<String> tokens = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("apns"))
+ .map(ExternalToken::getToken).collect(Collectors.toList());
+ if (!tokens.isEmpty()) {
+ ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder();
+ apnsPayloadBuilder.addCustomProperty("mid", jmsg.getMid());
+ String post = PlainTextFormatter.formatPost(jmsg);
+ String[] parts = post.split("\n", 2);
+ String payload = apnsPayloadBuilder.setAlertTitle(parts[0])
+ .setAlertBody(parts[1]).buildWithDefaultMaximumLength();
+ for (String token : tokens) {
+ final Future<PushNotificationResponse<SimpleApnsPushNotification>> notification
+ = apns.sendNotification(new SimpleApnsPushNotification(token, topic, payload));
+ try {
+ final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse
+ = notification.get();
+ if (pushNotificationResponse.isAccepted()) {
+ logger.info("APNS accepted: {}", token);
+ } else {
+ String reason = pushNotificationResponse.getRejectionReason();
+ logger.info("APNS rejected: {}", reason);
+ if (reason.equals("BadDeviceToken")) {
+ invalidAPNSTokens.add(token);
}
- } catch (final ExecutionException | InterruptedException ex) {
- logger.info("APNS exception", ex);
}
+ } catch (final ExecutionException | InterruptedException ex) {
+ logger.info("APNS exception", ex);
}
- } else {
- logger.info("APNS: no recipients");
}
- });
- try {
- xmpp.connect();
- } catch (XmppException e) {
- logger.warn("xmpp extension", e);
+ } else {
+ logger.info("APNS: no recipients");
}
}
@Override
public void close() throws Exception {
apns.close();
- if (xmpp != null)
- xmpp.close();
logger.info("ExternalComponent on notifications destroyed");
}
diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsAppConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsAppConfiguration.java
index 19d56d59..5cd2b3cd 100644
--- a/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsAppConfiguration.java
+++ b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsAppConfiguration.java
@@ -2,7 +2,10 @@ package com.juick.components.configuration;
import com.juick.components.CleanUp;
import com.juick.components.Notifications;
+import com.juick.server.component.JuickServerComponent;
+import com.juick.server.component.JuickServerReconnectManager;
import com.juick.server.configuration.BaseWebConfiguration;
+import com.juick.server.configuration.JuickServerComponentConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.http.client.ClientHttpRequestInterceptor;
@@ -24,7 +27,7 @@ import java.util.List;
@PropertySource("classpath:juick.conf")
@ComponentScan(basePackages = "com.juick.components.service")
@Import({ APNSConfiguration.class, MPNSConfiguration.class,
- GCMConfiguration.class, XMPPConfiguration.class })
+ GCMConfiguration.class, JuickServerComponentConfiguration.class})
public class NotificationsAppConfiguration extends BaseWebConfiguration {
@Value("${api_user:juick}")
private String apiUser;
@@ -32,6 +35,15 @@ public class NotificationsAppConfiguration extends BaseWebConfiguration {
private String apiSecret;
@Bean
+ public JuickServerComponent juickServerComponent() {
+ return new JuickServerComponent();
+ }
+ @Bean
+ public JuickServerReconnectManager juickServerReconnectManager() {
+ return new JuickServerReconnectManager();
+ }
+
+ @Bean
public RestTemplate rest() {
RestTemplate rest = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = Collections.singletonList(
diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/XMPPConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/XMPPConfiguration.java
deleted file mode 100644
index 0073b502..00000000
--- a/juick-notifications/src/main/java/com/juick/components/configuration/XMPPConfiguration.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.juick.components.configuration;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import rocks.xmpp.core.session.Extension;
-import rocks.xmpp.core.session.XmppSessionConfiguration;
-import rocks.xmpp.core.session.debug.LogbackDebugger;
-import rocks.xmpp.extensions.component.accept.ExternalComponent;
-
-/**
- * Created by vital on 29.03.2017.
- */
-@Configuration
-public class XMPPConfiguration {
- @Value("${push_jid}")
- private String pushJid;
- @Value("${xmpp_host:localhost}")
- private String xmppHost;
- @Value("${xmpp_port:5347}")
- private int xmppPort;
- @Value("${push_xmpp_password:secret}")
- private String xmppPushPassword;
-
- @Bean
- public ExternalComponent xmpp() {
- XmppSessionConfiguration configuration = XmppSessionConfiguration.builder()
- .extensions(Extension.of(com.juick.Message.class))
- .debugger(LogbackDebugger.class)
- .build();
- return ExternalComponent.create(pushJid, xmppPushPassword, configuration, xmppHost, xmppPort);
- }
-}