From c83e39441243b7db8293f1c161ee203faaf360ef Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 15 Dec 2016 10:34:18 +0300 Subject: juick-notifications: RestService and GCM cleanup --- .../main/java/com/juick/components/CleanUp.java | 25 +++++--------- .../java/com/juick/components/Notifications.java | 30 ++++++++++++++++- .../NotificationsAppConfiguration.java | 9 +++++ .../juick/components/service/BaseRestService.java | 18 ++++++++++ .../service/NotificationsTokenService.java | 39 ++++++++++++++++++++++ .../com/juick/components/service/TokenService.java | 10 ++++++ 6 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 juick-notifications/src/main/java/com/juick/components/service/BaseRestService.java create mode 100644 juick-notifications/src/main/java/com/juick/components/service/NotificationsTokenService.java create mode 100644 juick-notifications/src/main/java/com/juick/components/service/TokenService.java diff --git a/juick-notifications/src/main/java/com/juick/components/CleanUp.java b/juick-notifications/src/main/java/com/juick/components/CleanUp.java index c78b3f77..7b800fec 100644 --- a/juick-notifications/src/main/java/com/juick/components/CleanUp.java +++ b/juick-notifications/src/main/java/com/juick/components/CleanUp.java @@ -1,17 +1,11 @@ package com.juick.components; -import com.juick.TokensList; +import com.juick.components.service.TokenService; import com.notnoop.apns.ApnsService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; import javax.inject.Inject; import java.util.ArrayList; @@ -28,7 +22,10 @@ public class CleanUp { @Inject ApnsService apns; @Inject - RestTemplate rest; + TokenService tokenService; + + @Inject + Notifications push; @Scheduled(fixedRate = 600000) public void cleanupTokens() { @@ -37,16 +34,12 @@ public class CleanUp { int count = devices.size(); if (count > 0) { logger.info("{} tokens to delete", count); - TokensList list = new TokensList(); - list.setType("apns"); - list.setTokens(new ArrayList<>(devices)); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON_UTF8); - rest.exchange("http://api.juick.com/notifications", - HttpMethod.DELETE, new HttpEntity<>(list, headers), new ParameterizedTypeReference() { - }); + tokenService.deleteTokens("apns", new ArrayList<>(devices)); } else { logger.info("No APNS tokens to delete"); } + logger.debug("initializing GCM tokens cleanup: {} tokens", push.getInvalidGCMTokens().size()); + tokenService.deleteTokens("gcm", push.getInvalidGCMTokens()); + push.cleanupGCMTokens(); } } 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 b06e0abf..6de648cf 100644 --- a/juick-notifications/src/main/java/com/juick/components/Notifications.java +++ b/juick-notifications/src/main/java/com/juick/components/Notifications.java @@ -54,6 +54,7 @@ import javax.inject.Inject; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -76,6 +77,8 @@ public class Notifications implements AutoCloseable { private final ObjectMapper mapper; + private final List invalidGCMTokens; + @Inject private ApnsService apns; @@ -93,6 +96,7 @@ public class Notifications implements AutoCloseable { mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT); + invalidGCMTokens = Collections.synchronizedList(new ArrayList<>()); } @PostConstruct @@ -134,7 +138,16 @@ public class Notifications implements AutoCloseable { MulticastResult result = GCMSender.send(message, regids, 3); List results = result.getResults(); for (int i = 0; i < results.size(); i++) { - logger.info("RES {}: {}", i, results.get(i)); + Result currentResult = results.get(i); + logger.info("RES {}: {}", i, currentResult); + List 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); @@ -283,4 +296,19 @@ public class Notifications implements AutoCloseable { .map(x -> x.getName() + ": " + x.getValue()) .collect(Collectors.joining("\n")); } + + public void addInvalidGCMToken(String token) { + synchronized (invalidGCMTokens) { + invalidGCMTokens.add(token); + } + } + public List getInvalidGCMTokens() { + return invalidGCMTokens; + } + public void cleanupGCMTokens() { + logger.info("removed {} tokens", invalidGCMTokens.size()); + synchronized (invalidGCMTokens) { + invalidGCMTokens.clear(); + } + } } 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 67a551c4..452cf61c 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 @@ -1,15 +1,18 @@ package com.juick.components.configuration; +import com.juick.components.CleanUp; import com.juick.components.Notifications; import com.notnoop.apns.APNS; import com.notnoop.apns.ApnsService; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.InterceptingClientHttpRequestFactory; import org.springframework.http.client.support.BasicAuthorizationInterceptor; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.client.RestTemplate; import javax.inject.Inject; @@ -20,7 +23,9 @@ import java.util.List; * Created by aalexeev on 11/12/16. */ @Configuration +@EnableScheduling @PropertySource("classpath:juick.conf") +@ComponentScan(basePackages = {"com.juick.components.service"}) public class NotificationsAppConfiguration { @Inject private Environment env; @@ -47,4 +52,8 @@ public class NotificationsAppConfiguration { return APNS.newService().withCert(env.getProperty("ios_pkcs12_file"), env.getProperty("ios_pkcs12_password")) .withSandboxDestination().build(); } + @Bean + public CleanUp cleanUp() { + return new CleanUp(); + } } diff --git a/juick-notifications/src/main/java/com/juick/components/service/BaseRestService.java b/juick-notifications/src/main/java/com/juick/components/service/BaseRestService.java new file mode 100644 index 00000000..d4bc369c --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/service/BaseRestService.java @@ -0,0 +1,18 @@ +package com.juick.components.service; + +import org.springframework.web.client.RestTemplate; + +/** + * Created by vitalyster on 15.12.2016. + */ +public abstract class BaseRestService { + private RestTemplate rest; + + public BaseRestService(RestTemplate rest) { + this.rest = rest; + } + + public RestTemplate getRest() { + return rest; + } +} diff --git a/juick-notifications/src/main/java/com/juick/components/service/NotificationsTokenService.java b/juick-notifications/src/main/java/com/juick/components/service/NotificationsTokenService.java new file mode 100644 index 00000000..c34f322b --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/service/NotificationsTokenService.java @@ -0,0 +1,39 @@ +package com.juick.components.service; + +import com.juick.TokensList; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Repository; +import org.springframework.web.client.RestTemplate; + +import javax.inject.Inject; +import java.util.List; + +/** + * Created by vitalyster on 15.12.2016. + */ +@Repository +public class NotificationsTokenService extends BaseRestService implements TokenService { + + @Inject + public NotificationsTokenService(RestTemplate rest) { + super(rest); + } + + @Override + public void deleteTokens(String type, List devices) { + if (devices.size() > 0) { + TokensList list = new TokensList(); + list.setType(type); + list.setTokens(devices); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON_UTF8); + getRest().exchange("http://api.juick.com/notifications", + HttpMethod.DELETE, new HttpEntity<>(list, headers), new ParameterizedTypeReference() { + }); + } + } +} diff --git a/juick-notifications/src/main/java/com/juick/components/service/TokenService.java b/juick-notifications/src/main/java/com/juick/components/service/TokenService.java new file mode 100644 index 00000000..2a578386 --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/service/TokenService.java @@ -0,0 +1,10 @@ +package com.juick.components.service; + +import java.util.List; + +/** + * Created by vitalyster on 15.12.2016. + */ +public interface TokenService { + void deleteTokens(String type, List list); +} -- cgit v1.2.3