From 194a9a763c6b11d207e682b2f93de94475c473b4 Mon Sep 17 00:00:00 2001 From: Alexander Alexeev Date: Sat, 12 Nov 2016 01:34:07 +0700 Subject: extracted application configuration from Mvc configuration with application specific beans; extracted bean initialization from constructor; force using properties; --- .../java/com/juick/components/Notifications.java | 111 +++++++++++-------- .../NotificationsAppConfiguration.java | 40 +++++++ .../configuration/NotificationsConfiguration.java | 122 --------------------- .../configuration/NotificationsInitializer.java | 10 +- .../NotificationsMvcConfiguration.java | 41 +++++++ 5 files changed, 153 insertions(+), 171 deletions(-) create mode 100644 juick-notifications/src/main/java/com/juick/components/configuration/NotificationsAppConfiguration.java delete mode 100644 juick-notifications/src/main/java/com/juick/components/configuration/NotificationsConfiguration.java create mode 100644 juick-notifications/src/main/java/com/juick/components/configuration/NotificationsMvcConfiguration.java (limited to 'juick-notifications/src/main/java/com/juick/components') 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 12993418..b7e6b2b8 100644 --- a/juick-notifications/src/main/java/com/juick/components/Notifications.java +++ b/juick-notifications/src/main/java/com/juick/components/Notifications.java @@ -19,6 +19,7 @@ package com.juick.components; import com.google.android.gcm.server.*; import com.juick.json.MessageSerializer; +import com.juick.util.ThreadHelper; import com.juick.xmpp.JID; import com.juick.xmpp.Message.MessageListener; import com.juick.xmpp.Stream; @@ -44,13 +45,12 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.env.Environment; import org.springframework.http.HttpMethod; -import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; -import javax.inject.Inject; import java.io.IOException; import java.net.Socket; import java.util.ArrayList; @@ -59,63 +59,75 @@ import java.util.List; import java.util.concurrent.ExecutorService; /** - * * @author Ugnich Anton */ -public class Notifications implements DisposableBean, Stream.StreamListener, MessageListener { - +public class Notifications implements InitializingBean, DisposableBean, Stream.StreamListener, MessageListener { private static Logger logger = LoggerFactory.getLogger(Notifications.class); - String wns_application_sip; - String wns_client_secret; - @Inject - RestTemplate rest; - Socket socket; - Stream xmpp; - Sender GCMSender; - ExecutorService service; + private final RestTemplate rest; + private final ExecutorService service; + private Socket socket; + private Stream xmpp; + private final Sender GCMSender; + + private final String wns_application_sip; + private final String wns_client_secret; + private final String pushJid; + private final String xmppHost; + private final int xmppPort; + private final String xmppPushPassword; - @Inject - public Notifications(Environment env, ExecutorService service) { + + public Notifications(final Environment env, final ExecutorService service, final RestTemplate rest) { this.service = service; - logger.info("component initialized"); + this.rest = rest; + wns_application_sip = env.getProperty("wns_application_sip", ""); wns_client_secret = env.getProperty("wns_client_secret", ""); GCMSender = new Sender(env.getProperty("gcm_key", ""), Endpoint.GCM); - - setupXmppComponent(new JID("", env.getProperty("push_jid"), ""), env.getProperty("xmpp_host", "localhost"), - NumberUtils.toInt(env.getProperty("xmpp_port", ""), 5347), env.getProperty("push_xmpp_password", "")); - service.submit(() -> xmpp.startParsing()); + pushJid = env.getProperty("push_jid"); + xmppHost = env.getProperty("xmpp_host", "localhost"); + xmppPort = NumberUtils.toInt(env.getProperty("xmpp_port"), 5347); + xmppPushPassword = env.getProperty("push_xmpp_password", ""); } @Override - public void destroy() { - logger.info("component destroyed"); - } - - public void setupXmppComponent(JID jid, String host, int port, String password) { + public void afterPropertiesSet() throws Exception { try { - socket = new Socket(host, port); - xmpp = new StreamComponent(jid, socket.getInputStream(), socket.getOutputStream(), password); + socket = new Socket(xmppHost, xmppPort); + xmpp = new StreamComponent(new JID("", pushJid, ""), socket.getInputStream(), socket.getOutputStream(), xmppPushPassword); xmpp.addChildParser(new JuickMessage()); xmpp.addListener((Stream.StreamListener) this); xmpp.addListener((MessageListener) this); - } catch (IOException e) { - logger.error(e.getMessage(), e); + + service.submit(() -> xmpp.startParsing()); + + logger.info("Notifications initialized"); + } catch (Exception e) { + logger.error("Notifications initialization error", e); } } + @Override + public void destroy() { + ThreadHelper.shutdownAndAwaitTermination(service); + + logger.info("component destroyed"); + } + @Override public void onStreamReady() { logger.info("XMPP STREAM READY"); } @Override - public void onStreamFail(Exception e) {logger.error("XMPP STREAM FAIL", e);} + public void onStreamFail(final Exception e) { + logger.error("XMPP STREAM FAIL", e); + } @Override - public void onMessage(com.juick.xmpp.Message msg) { - JuickMessage jmsg = (JuickMessage)msg.getChild(JuickMessage.XMLNS); + public void onMessage(final com.juick.xmpp.Message msg) { + JuickMessage jmsg = (JuickMessage) msg.getChild(JuickMessage.XMLNS); boolean isPM = jmsg.getMID() == 0; boolean isReply = jmsg.getRID() > 0; int pmTo = 0; @@ -125,11 +137,13 @@ public class Notifications implements DisposableBean, Stream.StreamListener, Mes if (isPM) { regids.addAll(rest.exchange(String.format("http://api.juick.com/notifications?type=gcm&uid=%s", jmsg.getUser().getUID()), - HttpMethod.GET, null, new ParameterizedTypeReference>() {}).getBody()); + HttpMethod.GET, null, new ParameterizedTypeReference>() { + }).getBody()); } else { regids.addAll(rest.exchange(String.format("http://api.juick.com/notifications?type=gcm&uid=%s&mid=%s", jmsg.getUser().getUID(), jmsg.getMID()), - HttpMethod.GET, null, new ParameterizedTypeReference>() {}).getBody()); + HttpMethod.GET, null, new ParameterizedTypeReference>() { + }).getBody()); } if (!regids.isEmpty()) { @@ -157,14 +171,15 @@ public class Notifications implements DisposableBean, Stream.StreamListener, Mes if (isPM) { urls.addAll(rest.exchange(String.format("http://api.juick.com/notifications?type=mpns&uid=%s", jmsg.getUser().getUID()), - HttpMethod.GET, null, new ParameterizedTypeReference>() {}).getBody()); + HttpMethod.GET, null, new ParameterizedTypeReference>() { + }).getBody()); } else { urls.addAll(rest.exchange(String.format("http://api.juick.com/notifications?type=mpns&uid=%s&mid=%s", jmsg.getUser().getUID(), jmsg.getMID()), - HttpMethod.GET, null, new ParameterizedTypeReference>() {}).getBody()); + HttpMethod.GET, null, new ParameterizedTypeReference>() { + }).getBody()); } - if (urls.isEmpty()) { logger.info("WNS: no recipients"); } else { @@ -203,11 +218,13 @@ public class Notifications implements DisposableBean, Stream.StreamListener, Mes if (isPM) { tokens.addAll(rest.exchange(String.format("http://api.juick.com/notifications?type=apns&uid=%s", jmsg.getUser().getUID()), - HttpMethod.GET, null, new ParameterizedTypeReference>() {}).getBody()); + HttpMethod.GET, null, new ParameterizedTypeReference>() { + }).getBody()); } else { tokens.addAll(rest.exchange(String.format("http://api.juick.com/notifications?type=apns&uid=%s&mid=%s", jmsg.getUser().getUID(), jmsg.getMID()), - HttpMethod.GET, null, new ParameterizedTypeReference>() {}).getBody()); + HttpMethod.GET, null, new ParameterizedTypeReference>() { + }).getBody()); } if (!tokens.isEmpty()) { ApnsService service = APNS.newService().withCert("/etc/juick/ios.p12", "juick") @@ -223,10 +240,10 @@ public class Notifications implements DisposableBean, Stream.StreamListener, Mes } String getWnsAccessToken() throws IOException, IllegalStateException { - if(TextUtils.isEmpty(wns_application_sip)) { + if (TextUtils.isEmpty(wns_application_sip)) { throw new IllegalStateException("'wns_application_sip' is not initialized"); } - if(TextUtils.isEmpty(wns_client_secret)) { + if (TextUtils.isEmpty(wns_client_secret)) { throw new IllegalStateException("'wns_client_secret' is not initialized"); } HttpClient client = HttpClientBuilder.create().build(); @@ -243,17 +260,17 @@ public class Notifications implements DisposableBean, Stream.StreamListener, Mes int statusCode = response.getStatusLine().getStatusCode(); String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8); JSONObject json = new JSONObject(responseContent); - if(statusCode != 200) { + if (statusCode != 200) { throw new IOException(json.opt("error") + ": " + json.opt("error_description")); } - String tokenType = (String)json.get("token_type"); - if(tokenType.length() >= 1) { + String tokenType = (String) json.get("token_type"); + if (tokenType.length() >= 1) { tokenType = Character.toUpperCase(tokenType.charAt(0)) + tokenType.substring(1); } return tokenType + " " + json.get("access_token"); } - void sendWNS(String wnsToken, String url, String xml) throws IOException { + void sendWNS(final String wnsToken, final String url, final String xml) throws IOException { HttpClient client = HttpClientBuilder.create().build(); StringEntity entity = new StringEntity(xml, Consts.UTF_8); HttpPost httpPost = new HttpPost(url); @@ -263,13 +280,13 @@ public class Notifications implements DisposableBean, Stream.StreamListener, Mes httpPost.setEntity(entity); HttpResponse response = client.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); - if(statusCode != 200) { + if (statusCode != 200) { String headersContent = stringifyWnsHttpHeaders(response.getAllHeaders()); throw new IOException(headersContent); } } - static String stringifyWnsHttpHeaders(Header[] allHeaders) { + static String stringifyWnsHttpHeaders(final Header[] allHeaders) { String[] wnsHeaders = Arrays.stream(allHeaders) .filter(x -> x.getName().startsWith("X-WNS-") || x.getName().startsWith("WWW-")) .map(x -> x.getName() + ": " + x.getValue()) 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 new file mode 100644 index 00000000..1974830a --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsAppConfiguration.java @@ -0,0 +1,40 @@ +package com.juick.components.configuration; + +import com.juick.components.Notifications; +import com.juick.configuration.DataConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.web.client.RestTemplate; + +import javax.inject.Inject; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by aalexeev on 11/12/16. + */ +@Configuration +@PropertySource("classpath:juick.conf") +@Import(DataConfiguration.class) +public class NotificationsAppConfiguration { + @Inject + private Environment env; + + @Bean + public RestTemplate rest() { + return new RestTemplate(); + } + + @Bean + public Notifications push() { + return new Notifications(env, service(), rest()); + } + + @Bean + public ExecutorService service() { + return Executors.newCachedThreadPool(); + } +} diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsConfiguration.java deleted file mode 100644 index 7410648a..00000000 --- a/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsConfiguration.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.juick.components.configuration; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.juick.components.Notifications; -import com.mitchellbosecke.pebble.PebbleEngine; -import com.mitchellbosecke.pebble.loader.Loader; -import com.mitchellbosecke.pebble.loader.ServletLoader; -import com.mitchellbosecke.pebble.spring4.PebbleViewResolver; -import com.mitchellbosecke.pebble.spring4.extension.SpringExtension; -import org.springframework.beans.factory.config.PlaceholderConfigurerSupport; -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.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.core.env.Environment; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; - -import javax.inject.Inject; -import javax.servlet.ServletContext; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Created by vitalyster on 28.06.2016. - */ -@Configuration -@ComponentScan(basePackages = {"com.juick"}) -@PropertySource(value = {"classpath:juick.conf", "file:${user.home}/juick.conf"}) -public class NotificationsConfiguration extends WebMvcConfigurationSupport { - @Inject - Environment env; - @Inject - private ServletContext servletContext; - - @Bean - public static PlaceholderConfigurerSupport propertySourcesPlaceholderConfigurer() { - PlaceholderConfigurerSupport configurer = new PropertySourcesPlaceholderConfigurer(); - - configurer.setFileEncoding("utf-8"); - configurer.setOrder(1); - return configurer; - } - - @Bean - RestTemplate rest() { - return new RestTemplate(); - } - - @Bean - public Loader templateLoader() { - return new ServletLoader(servletContext); - } - - @Bean - public SpringExtension springExtension() { - return new SpringExtension(); - } - - @Bean - public PebbleEngine pebbleEngine() { - return new PebbleEngine.Builder() - .loader(this.templateLoader()) - .extension(springExtension()) - .build(); - } - - @Bean - public ViewResolver viewResolver() { - PebbleViewResolver viewResolver = new PebbleViewResolver(); - viewResolver.setPrefix("/WEB-INF/templates/"); - viewResolver.setSuffix(".html"); - viewResolver.setPebbleEngine(pebbleEngine()); - return viewResolver; - } - - @Bean - public Notifications push() { - return new Notifications(env, service()); - } - - @Bean - public ExecutorService service() { - return Executors.newCachedThreadPool(); - } - - @Override - public RequestMappingHandlerMapping requestMappingHandlerMapping() { - RequestMappingHandlerMapping mapping = super.requestMappingHandlerMapping(); - mapping.setUseSuffixPatternMatch(false); - return mapping; - } - - @Override - protected void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.setOrder(0); - registry.addResourceHandler("/scripts.js").addResourceLocations("/"); - registry.addResourceHandler("/style.css").addResourceLocations("/"); - } - - @Override - protected void configureMessageConverters(List> converters) { - Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() - .serializationInclusion(JsonInclude.Include.NON_DEFAULT) - .serializationInclusion(JsonInclude.Include.NON_NULL) - .serializationInclusion(JsonInclude.Include.NON_ABSENT) - .serializationInclusion(JsonInclude.Include.NON_EMPTY); - MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build()); - converter.getObjectMapper().registerModule(new Jdk8Module()); - converters.add(converter); - super.configureMessageConverters(converters); - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsInitializer.java b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsInitializer.java index 417cc7fa..48ff52c2 100644 --- a/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsInitializer.java +++ b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsInitializer.java @@ -10,14 +10,15 @@ import javax.servlet.Filter; * Created by vt on 09/02/16. */ public class NotificationsInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override protected Class[] getRootConfigClasses() { - return new Class[]{DataConfiguration.class}; + return new Class[]{NotificationsAppConfiguration.class, DataConfiguration.class}; } @Override protected Class[] getServletConfigClasses() { - return new Class[]{NotificationsConfiguration.class}; + return new Class[]{NotificationsMvcConfiguration.class}; } @Override @@ -31,4 +32,9 @@ public class NotificationsInitializer extends AbstractAnnotationConfigDispatcher characterEncodingFilter.setEncoding("UTF-8"); return new Filter[]{characterEncodingFilter}; } + + @Override + protected String getServletName() { + return "Notifications dispatcher servlet"; + } } diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsMvcConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsMvcConfiguration.java new file mode 100644 index 00000000..a0f0ad06 --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/configuration/NotificationsMvcConfiguration.java @@ -0,0 +1,41 @@ +package com.juick.components.configuration; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import java.util.List; + +/** + * Created by vitalyster on 28.06.2016. + */ +@Configuration +@ComponentScan(basePackages = {"com.juick.components.controllers"}) +public class NotificationsMvcConfiguration extends WebMvcConfigurationSupport { + + @Override + public RequestMappingHandlerMapping requestMappingHandlerMapping() { + RequestMappingHandlerMapping mapping = super.requestMappingHandlerMapping(); + mapping.setUseSuffixPatternMatch(false); + return mapping; + } + + @Override + protected void configureMessageConverters(List> converters) { + Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() + .serializationInclusion(JsonInclude.Include.NON_DEFAULT) + .serializationInclusion(JsonInclude.Include.NON_NULL) + .serializationInclusion(JsonInclude.Include.NON_ABSENT) + .serializationInclusion(JsonInclude.Include.NON_EMPTY); + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build()); + converter.getObjectMapper().registerModule(new Jdk8Module()); + converters.add(converter); + super.configureMessageConverters(converters); + } +} -- cgit v1.2.3