From b4ebee8a81688e223213b9e34ca6182e54efc572 Mon Sep 17 00:00:00 2001 From: sowhat Date: Fri, 7 Jul 2017 19:49:12 +0300 Subject: [PATCH 01/13] Play-2.6.x_2.11 migration according to [Manual](https://www.playframework.com/documentation/2.6.x/Migration26). --- build.sbt | 8 +++++--- project/build.properties | 2 +- project/plugins.sbt | 2 +- sample/java/build.sbt | 4 ++-- sample/java/conf/application.conf | 2 +- sample/java/project/build.properties | 2 +- sample/java/project/plugins.sbt | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index 366802c..29b1c5a 100644 --- a/build.sbt +++ b/build.sbt @@ -1,15 +1,17 @@ name := "geolocation" -version := "2.1.0" +version := "2.2.0" -scalaVersion := "2.11.7" +scalaVersion := "2.11.11" lazy val root = (project in file(".")).enablePlugins(PlayJava) libraryDependencies ++= Seq( javaCore, javaWs, - cache, + ehcache, + guice, + "com.typesafe.play" %% "play-json" % "2.6.0", "org.mockito" % "mockito-core" % "2.0.43-beta" % Test, "com.jayway.awaitility" % "awaitility" % "1.7.0" % Test ) diff --git a/project/build.properties b/project/build.properties index 43b8278..64317fd 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.11 +sbt.version=0.13.15 diff --git a/project/plugins.sbt b/project/plugins.sbt index 67531ab..c5e46de 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,6 +2,6 @@ logLevel := Level.Warn // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.5.9")) +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.1")) addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3") diff --git a/sample/java/build.sbt b/sample/java/build.sbt index b6dac72..1760f2f 100644 --- a/sample/java/build.sbt +++ b/sample/java/build.sbt @@ -4,14 +4,14 @@ version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayJava) -scalaVersion := "2.11.7" +scalaVersion := "2.11.11" routesGenerator := InjectedRoutesGenerator libraryDependencies ++= Seq( // Add your project dependencies here, javaCore, - "com.edulify" %% "geolocation" % "2.1.0" + "com.edulify" %% "geolocation" % "2.2.0" ) resolvers ++= Seq( diff --git a/sample/java/conf/application.conf b/sample/java/conf/application.conf index 1640f63..e48326a 100644 --- a/sample/java/conf/application.conf +++ b/sample/java/conf/application.conf @@ -5,7 +5,7 @@ # ~~~~~ # The secret key is used to secure cryptographics functions. # If you deploy your application to several instances be sure to use the same key! -play.crypto.secret="i[7Ve:r2mSr`PKm1x@kVYm0XfqW[vLarVbjGuP/Q8I8p@iZ8RLVPSiq@6ZElMyEr" +play.http.secret.key="i[7Ve:r2mSr`PKm1x@kVYm0XfqW[vLarVbjGuP/Q8I8p@iZ8RLVPSiq@6ZElMyEr" # The application languages # ~~~~~ diff --git a/sample/java/project/build.properties b/sample/java/project/build.properties index 817bc38..64317fd 100644 --- a/sample/java/project/build.properties +++ b/sample/java/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.9 +sbt.version=0.13.15 diff --git a/sample/java/project/plugins.sbt b/sample/java/project/plugins.sbt index fbb149e..f604d1e 100644 --- a/sample/java/project/plugins.sbt +++ b/sample/java/project/plugins.sbt @@ -5,5 +5,5 @@ logLevel := Level.Warn resolvers += Resolver.typesafeRepo("releases") // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.5.9")) +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.1")) From 44864e6556b2a51f25d69a8ec8f064adc9dd8f9c Mon Sep 17 00:00:00 2001 From: sowhat Date: Mon, 23 Oct 2017 19:49:40 +0300 Subject: [PATCH 02/13] Play-2.6.x_2.12 migration according to [Manual](https://www.playframework.com/documentation/2.6.x/Migration26). --- build.sbt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index 29b1c5a..9b1f98f 100644 --- a/build.sbt +++ b/build.sbt @@ -2,15 +2,13 @@ name := "geolocation" version := "2.2.0" -scalaVersion := "2.11.11" +scalaVersion := "2.12.4" -lazy val root = (project in file(".")).enablePlugins(PlayJava) +lazy val root = (project in file(".")).enablePlugins(PlayMinimalJava) libraryDependencies ++= Seq( - javaCore, javaWs, - ehcache, - guice, + cacheApi, "com.typesafe.play" %% "play-json" % "2.6.0", "org.mockito" % "mockito-core" % "2.0.43-beta" % Test, "com.jayway.awaitility" % "awaitility" % "1.7.0" % Test From d64620aa975439a8e8aafb7b79894adf0919b0df Mon Sep 17 00:00:00 2001 From: sowhat Date: Wed, 25 Oct 2017 05:06:24 +0300 Subject: [PATCH 03/13] Bump sbt-plugin version and remove unnecessary dependencies. --- .gitignore | 1 - build.sbt | 2 +- project/build.properties | 2 +- project/plugins.sbt | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index ee869bc..a13372d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ target logs project/project project/target -target tmp .history dist diff --git a/build.sbt b/build.sbt index 9b1f98f..c68eac6 100644 --- a/build.sbt +++ b/build.sbt @@ -9,7 +9,7 @@ lazy val root = (project in file(".")).enablePlugins(PlayMinimalJava) libraryDependencies ++= Seq( javaWs, cacheApi, - "com.typesafe.play" %% "play-json" % "2.6.0", + guice, "org.mockito" % "mockito-core" % "2.0.43-beta" % Test, "com.jayway.awaitility" % "awaitility" % "1.7.0" % Test ) diff --git a/project/build.properties b/project/build.properties index 64317fd..c091b86 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.15 +sbt.version=0.13.16 diff --git a/project/plugins.sbt b/project/plugins.sbt index c5e46de..ed6f4a5 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,6 +2,6 @@ logLevel := Level.Warn // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.1")) +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.6")) addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3") From c40d471f349bd44bc5164237af6e3245856a07c1 Mon Sep 17 00:00:00 2001 From: sowhat Date: Wed, 25 Oct 2017 05:08:42 +0300 Subject: [PATCH 04/13] MaxmindProvider up to date with new API. Also covered by test. --- .../geolocation/providers/MaxmindModule.java | 12 ++- .../providers/MaxmindProvider.java | 37 ++++----- .../providers/MaxmindProviderTest.java | 75 +++++++++++++++++++ 3 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 test/com/edulify/modules/geolocation/providers/MaxmindProviderTest.java diff --git a/app/com/edulify/modules/geolocation/providers/MaxmindModule.java b/app/com/edulify/modules/geolocation/providers/MaxmindModule.java index a640eb1..0ac38ee 100644 --- a/app/com/edulify/modules/geolocation/providers/MaxmindModule.java +++ b/app/com/edulify/modules/geolocation/providers/MaxmindModule.java @@ -2,11 +2,19 @@ import com.edulify.modules.geolocation.GeolocationProvider; import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.typesafe.config.Config; +import play.libs.ws.WSClient; + +import java.util.concurrent.Executor; public class MaxmindModule extends AbstractModule { @Override - protected void configure() { - bind(GeolocationProvider.class).to(MaxmindProvider.class); + protected void configure() { } + + @Provides + public GeolocationProvider geolocationProvider(WSClient wsClient, Config config, Executor wsExecutor) { + return new MaxmindProvider(wsClient, config.getString("geolocation.maxmind.license"), wsExecutor); } } diff --git a/app/com/edulify/modules/geolocation/providers/MaxmindProvider.java b/app/com/edulify/modules/geolocation/providers/MaxmindProvider.java index 179d718..ac74bd4 100644 --- a/app/com/edulify/modules/geolocation/providers/MaxmindProvider.java +++ b/app/com/edulify/modules/geolocation/providers/MaxmindProvider.java @@ -2,34 +2,37 @@ import com.edulify.modules.geolocation.Geolocation; import com.edulify.modules.geolocation.GeolocationProvider; -import play.Configuration; -import play.libs.F; -import play.libs.concurrent.HttpExecution; import play.libs.ws.WSClient; -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executor; -@Singleton public class MaxmindProvider implements GeolocationProvider { - private String license; + private final Executor threadToRunOn; - private WSClient ws; - private Configuration configuration; + private final WSClient ws; - @Inject - public MaxmindProvider(WSClient ws, Configuration configuration) { + private final String license; + + private final String baseUrl; + + MaxmindProvider(WSClient ws, String license, Executor threadToRunOn, String urlFormat) { this.ws = ws; - this.configuration = configuration; - this.license = this.configuration.getString("geolocation.maxmind.license"); + this.license = license; + this.threadToRunOn = threadToRunOn; + this.baseUrl = urlFormat; + } + + public MaxmindProvider(WSClient ws, String license, Executor threadToRunOn) { + this(ws, license, threadToRunOn, "https://geoip.maxmind.com/a?l=%s"); } @Override public CompletionStage get(final String ip) { - String url = String.format("https://geoip.maxmind.com/a?l=%s&i=%s", license, ip); - return ws.url(url) + return ws.url(baseUrl) // WSRequest is not a value-object. Adding query parameters will modify it's state instead of + .addQueryParameter("l", license) // creating a new instance. That is why we FORCED to store all request + .addQueryParameter("i", ip) // parameters and re-creating request each time rather re-using same instance. .get() .thenApplyAsync(response -> { if (response.getStatus() != 200) return null; @@ -37,10 +40,10 @@ public CompletionStage get(final String ip) { String body = response.getBody(); if ("(null),IP_NOT_FOUND".equals(body)) return null; return body; - }, HttpExecution.defaultContext()) + }, threadToRunOn) .thenApplyAsync(body -> { if (body == null) return Geolocation.empty(); return new Geolocation(ip, body); - }, HttpExecution.defaultContext()); + }, threadToRunOn); } } diff --git a/test/com/edulify/modules/geolocation/providers/MaxmindProviderTest.java b/test/com/edulify/modules/geolocation/providers/MaxmindProviderTest.java new file mode 100644 index 0000000..cd24405 --- /dev/null +++ b/test/com/edulify/modules/geolocation/providers/MaxmindProviderTest.java @@ -0,0 +1,75 @@ +package com.edulify.modules.geolocation.providers; + +import com.edulify.modules.geolocation.Geolocation; +import com.edulify.modules.geolocation.GeolocationProvider; +import com.google.common.collect.ImmutableMap; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import play.libs.ws.WSClient; +import play.mvc.Http; +import play.routing.RoutingDsl; +import play.server.Server; + +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static play.mvc.Results.ok; + +public class MaxmindProviderTest { + + private Server server; + + private WSClient ws; + + private GeolocationProvider maxmindProvider; + private ExecutorService executor; + + @Before + public void setUp() throws Exception { + server = Server.forRouter((components) -> RoutingDsl.fromComponents(components) + .GET("/ip").routeTo(() -> { + final Http.Context context = Http.Context.current.get();// Deprecated hack because Java can't do string interpolation. + + final String countryCode = ImmutableMap.of("ip1", "country1", "ip2", "country2").entrySet().stream() + .filter(entry -> entry.getKey().equals(context.request().getQueryString("i"))) + .map(Map.Entry::getValue) + .findAny().orElse("(null),IP_NOT_FOUND"); + + return ok(countryCode); + }) + .build()); + + ws = play.test.WSTestClient.newClient(server.httpPort()); + + executor = Executors.newSingleThreadExecutor(); + maxmindProvider = new MaxmindProvider(ws, "any test string", executor, "/ip?l=%s"); + } + + @After + public void tearDown() throws Exception { + try { + ws.close(); + } + finally { + executor.shutdown(); + server.stop(); + } + } + + @Test + public void get() throws Exception { + Geolocation geolocation = maxmindProvider.get("ip1").toCompletableFuture().get(10, TimeUnit.SECONDS); + assertEquals("country1", geolocation.getCountryCode()); + + geolocation = maxmindProvider.get("ip2").toCompletableFuture().get(10, TimeUnit.SECONDS); + assertEquals("country2", geolocation.getCountryCode()); + + geolocation = maxmindProvider.get("not at list").toCompletableFuture().get(10, TimeUnit.SECONDS); + assertEquals("", geolocation.getCountryCode()); + } + +} \ No newline at end of file From ee1eeb683f3563a09d275487ee63fdfd1f12d43e Mon Sep 17 00:00:00 2001 From: sowhat Date: Wed, 25 Oct 2017 05:33:37 +0300 Subject: [PATCH 05/13] FreegeoipProvider up to date with new API. Also covered by test. --- .../providers/FreegeoipModule.java | 11 ++- .../providers/FreegeoipProvider.java | 24 +++--- .../providers/FreegeoipProviderTest.java | 75 +++++++++++++++++++ 3 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 test/com/edulify/modules/geolocation/providers/FreegeoipProviderTest.java diff --git a/app/com/edulify/modules/geolocation/providers/FreegeoipModule.java b/app/com/edulify/modules/geolocation/providers/FreegeoipModule.java index 247b13f..e479a9f 100644 --- a/app/com/edulify/modules/geolocation/providers/FreegeoipModule.java +++ b/app/com/edulify/modules/geolocation/providers/FreegeoipModule.java @@ -2,11 +2,18 @@ import com.edulify.modules.geolocation.GeolocationProvider; import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import play.libs.ws.WSClient; + +import java.util.concurrent.Executor; public class FreegeoipModule extends AbstractModule { @Override - protected void configure() { - bind(GeolocationProvider.class).to(FreegeoipProvider.class); + protected void configure() { } + + @Provides + public GeolocationProvider geolocationProvider(WSClient wsClient, Executor wsExecutor) { + return new FreegeoipProvider(wsClient, wsExecutor); } } diff --git a/app/com/edulify/modules/geolocation/providers/FreegeoipProvider.java b/app/com/edulify/modules/geolocation/providers/FreegeoipProvider.java index 7c9502d..fc94aed 100644 --- a/app/com/edulify/modules/geolocation/providers/FreegeoipProvider.java +++ b/app/com/edulify/modules/geolocation/providers/FreegeoipProvider.java @@ -3,37 +3,43 @@ import com.edulify.modules.geolocation.Geolocation; import com.edulify.modules.geolocation.GeolocationProvider; import com.fasterxml.jackson.databind.JsonNode; -import play.libs.concurrent.HttpExecution; import play.libs.ws.WSClient; -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executor; -@Singleton public class FreegeoipProvider implements GeolocationProvider { private WSClient ws; - @Inject - public FreegeoipProvider(WSClient ws) { + private final String urlFormat; + + private final Executor threadToRunOn; + + public FreegeoipProvider(WSClient ws, Executor threadToRunOn, String urlFormat) { this.ws = ws; + this.urlFormat = urlFormat; + this.threadToRunOn = threadToRunOn; + } + + FreegeoipProvider(WSClient ws, Executor threadToRunOn) { + this(ws, threadToRunOn, "http://freegeoip.net/json/%s"); } @Override public CompletionStage get(String ip) { - String url = String.format("http://freegeoip.net/json/%s", ip); + String url = String.format(urlFormat, ip); return ws.url(url) .get() .thenApplyAsync(response -> { if (response.getStatus() != 200) return null; if (response.getBody().contains("not found")) return null; return response.asJson(); - }, HttpExecution.defaultContext()) + }, threadToRunOn) .thenApplyAsync(json -> { if (json == null) return Geolocation.empty(); return asGeolocation(json); - }, HttpExecution.defaultContext()); + }, threadToRunOn); } private Geolocation asGeolocation(JsonNode json) { diff --git a/test/com/edulify/modules/geolocation/providers/FreegeoipProviderTest.java b/test/com/edulify/modules/geolocation/providers/FreegeoipProviderTest.java new file mode 100644 index 0000000..e4e1c77 --- /dev/null +++ b/test/com/edulify/modules/geolocation/providers/FreegeoipProviderTest.java @@ -0,0 +1,75 @@ +package com.edulify.modules.geolocation.providers; + +import com.edulify.modules.geolocation.Geolocation; +import com.edulify.modules.geolocation.GeolocationProvider; +import com.google.common.collect.ImmutableMap; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import play.libs.ws.WSClient; +import play.routing.RoutingDsl; +import play.server.Server; + +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static play.mvc.Results.ok; + +public class FreegeoipProviderTest { + + private Server server; + + private WSClient ws; + + private GeolocationProvider freeGeoIpProvider; + private ExecutorService executor; + + @Before + public void setUp() throws Exception { + server = Server.forRouter((components) -> RoutingDsl.fromComponents(components) + .GET("/ip/:ipAddress").routeTo((String ipAddress) -> { + + final String countryCode = ImmutableMap.of( + "185.129.62.62", "{\"ip\":\"185.129.62.62\",\"country_code\":\"DK\",\"country_name\":\"Denmark\",\"region_code\":\"\",\"region_name\":\"\",\"city\":\"\",\"zip_code\":\"\",\"time_zone\":\"Europe/Copenhagen\",\"latitude\":55.7123,\"longitude\":12.0564,\"metro_code\":0}", + "88.85.80.69", "{\"ip\":\"88.85.80.69\",\"country_code\":\"NL\",\"country_name\":\"Netherlands\",\"region_code\":\"\",\"region_name\":\"\",\"city\":\"\",\"zip_code\":\"\",\"time_zone\":\"Europe/Amsterdam\",\"latitude\":52.3824,\"longitude\":4.8995,\"metro_code\":0}") + .entrySet().stream() + .filter(entry -> entry.getKey().equals(ipAddress)) + .map(Map.Entry::getValue) + .findAny().orElse("{\"ip\":\""+ipAddress+"\",\"country_code\":\"\",\"country_name\":\"\",\"region_code\":\"\",\"region_name\":\"\",\"city\":\"\",\"zip_code\":\"\",\"time_zone\":\"\",\"latitude\":0,\"longitude\":0,\"metro_code\":0}"); + + return ok(countryCode); + }) + .build()); + + ws = play.test.WSTestClient.newClient(server.httpPort()); + + executor = Executors.newSingleThreadExecutor(); + freeGeoIpProvider = new FreegeoipProvider(ws, executor, "/ip/%s"); + } + + @After + public void tearDown() throws Exception { + try { + ws.close(); + } + finally { + executor.shutdown(); + server.stop(); + } + } + + @Test + public void get() throws Exception { + Geolocation geolocation = freeGeoIpProvider.get("185.129.62.62").toCompletableFuture().get(10, TimeUnit.SECONDS); + assertEquals("DK", geolocation.getCountryCode()); + + geolocation = freeGeoIpProvider.get("88.85.80.69").toCompletableFuture().get(10, TimeUnit.SECONDS); + assertEquals("NL", geolocation.getCountryCode()); + + geolocation = freeGeoIpProvider.get("172.16.1.5").toCompletableFuture().get(10, TimeUnit.SECONDS); + assertEquals("", geolocation.getCountryCode()); + } +} From 25c1acbc2ceaf35f6ed31ef434bf6e3647713c91 Mon Sep 17 00:00:00 2001 From: sowhat Date: Wed, 25 Oct 2017 08:08:32 +0300 Subject: [PATCH 06/13] Deprecated `GeolocationService` and `GeolocationCache`, introduced `CachedProvider` decorator instead. --- .../modules/geolocation/CachedProvider.java | 25 ++++++ .../modules/geolocation/GeolocationCache.java | 7 ++ .../geolocation/GeolocationModule.java | 31 +++++++ .../geolocation/GeolocationService.java | 15 ++-- build.sbt | 3 +- conf/{application.conf => reference.conf} | 4 +- .../geolocation/CachedProviderTest.java | 87 +++++++++++++++++++ .../geolocation/GeolocationCacheTest.java | 4 + .../geolocation/GeolocationServiceTest.java | 17 ++-- 9 files changed, 179 insertions(+), 14 deletions(-) create mode 100644 app/com/edulify/modules/geolocation/CachedProvider.java create mode 100644 app/com/edulify/modules/geolocation/GeolocationModule.java rename conf/{application.conf => reference.conf} (53%) create mode 100644 test/com/edulify/modules/geolocation/CachedProviderTest.java diff --git a/app/com/edulify/modules/geolocation/CachedProvider.java b/app/com/edulify/modules/geolocation/CachedProvider.java new file mode 100644 index 0000000..ca7ef4c --- /dev/null +++ b/app/com/edulify/modules/geolocation/CachedProvider.java @@ -0,0 +1,25 @@ +package com.edulify.modules.geolocation; + +import play.cache.AsyncCacheApi; + +import java.util.concurrent.CompletionStage; + +public class CachedProvider implements GeolocationProvider +{ + private final AsyncCacheApi cache; + + private final int timeToLive; + + private final GeolocationProvider provider; + + public CachedProvider(AsyncCacheApi cache, int timeToLive, GeolocationProvider provider) { + this.cache = cache; + this.timeToLive = timeToLive; + this.provider = provider; + } + + @Override + public CompletionStage get(String ip) { + return cache.getOrElseUpdate(ip, () -> provider.get(ip), timeToLive); + } +} diff --git a/app/com/edulify/modules/geolocation/GeolocationCache.java b/app/com/edulify/modules/geolocation/GeolocationCache.java index b25bd21..693e1fe 100644 --- a/app/com/edulify/modules/geolocation/GeolocationCache.java +++ b/app/com/edulify/modules/geolocation/GeolocationCache.java @@ -6,6 +6,13 @@ import javax.inject.Inject; import javax.inject.Singleton; + +/** + * The GeolocationCache API. + * + * @deprecated Deprecated as of 2.2.0. Use {@link CachedProvider}. + */ +@Deprecated @Singleton public class GeolocationCache { diff --git a/app/com/edulify/modules/geolocation/GeolocationModule.java b/app/com/edulify/modules/geolocation/GeolocationModule.java new file mode 100644 index 0000000..612e8a8 --- /dev/null +++ b/app/com/edulify/modules/geolocation/GeolocationModule.java @@ -0,0 +1,31 @@ +package com.edulify.modules.geolocation; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.typesafe.config.Config; +import play.Environment; +import play.cache.AsyncCacheApi; + +import javax.inject.Named; + +public class GeolocationModule extends AbstractModule { + + private final Environment environment; + private final Config config; + + public GeolocationModule(Environment environment, Config config) + { + this.environment = environment; + this.config = config; + } + + @Override + protected void configure() { } + + @Named("CachedGeolocationProvider") + @Provides + public GeolocationProvider cachedGeolocationProvider(GeolocationProvider provider, AsyncCacheApi cacheApi) + { + return new CachedProvider(cacheApi, config.getInt("geolocation.cache.ttl"), provider); + } +} diff --git a/app/com/edulify/modules/geolocation/GeolocationService.java b/app/com/edulify/modules/geolocation/GeolocationService.java index b3ba9ca..6e6bb65 100644 --- a/app/com/edulify/modules/geolocation/GeolocationService.java +++ b/app/com/edulify/modules/geolocation/GeolocationService.java @@ -3,9 +3,14 @@ import play.libs.concurrent.HttpExecution; import javax.inject.Inject; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +/** + * Wrapper for {@link GeolocationProvider} to cache results. + * + * @deprecated Deprecated as of 2.2.0. Use {@link CachedProvider}. + */ +@Deprecated public final class GeolocationService { private GeolocationProvider provider; @@ -18,11 +23,9 @@ public GeolocationService(GeolocationProvider provider, GeolocationCache cache) } public CompletionStage getGeolocation(String ip) { - Geolocation geolocation = cache.get(ip); - if (geolocation != null) return CompletableFuture.completedFuture(geolocation); + final CompletionStage stage = provider.get(ip); + stage.thenAcceptAsync(cache::set, HttpExecution.defaultContext()); - CompletionStage promise = provider.get(ip); - promise.thenAcceptAsync(cache::set, HttpExecution.defaultContext()); - return promise; + return stage; } } diff --git a/build.sbt b/build.sbt index c68eac6..30daaef 100644 --- a/build.sbt +++ b/build.sbt @@ -10,7 +10,8 @@ libraryDependencies ++= Seq( javaWs, cacheApi, guice, - "org.mockito" % "mockito-core" % "2.0.43-beta" % Test, + ehcache % Test, // Should be removed with deprecated GeolocationService and GeolocationCache + "org.mockito" % "mockito-core" % "2.11.0" % Test, "com.jayway.awaitility" % "awaitility" % "1.7.0" % Test ) diff --git a/conf/application.conf b/conf/reference.conf similarity index 53% rename from conf/application.conf rename to conf/reference.conf index 85eb438..5217f6a 100644 --- a/conf/application.conf +++ b/conf/reference.conf @@ -1,5 +1,7 @@ + +play.modules.enabled += com.edulify.modules.geolocation.GeolocationModule + geolocation { - provider = "com.edulify.modules.geolocation.providers.FreegeoipProvider" cache { on = true ttl = 100 diff --git a/test/com/edulify/modules/geolocation/CachedProviderTest.java b/test/com/edulify/modules/geolocation/CachedProviderTest.java new file mode 100644 index 0000000..f6d9f43 --- /dev/null +++ b/test/com/edulify/modules/geolocation/CachedProviderTest.java @@ -0,0 +1,87 @@ +package com.edulify.modules.geolocation; + +import akka.Done; +import org.junit.Test; +import play.cache.AsyncCacheApi; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.*; + +public class CachedProviderTest { + @Test + public void get() throws Exception { + + GeolocationProvider provider = mock(GeolocationProvider.class); + when(provider.get("any address")).thenReturn(CompletableFuture.completedFuture(Geolocation.empty())); + + AsyncCacheApi cacheApi = new StubCacheApi(); + + GeolocationProvider target = new CachedProvider(cacheApi, 100, provider); + + target.get("any address").toCompletableFuture().get(1, TimeUnit.SECONDS); + target.get("any address").toCompletableFuture().get(1, TimeUnit.SECONDS); + verify(provider, times(1)).get("any address"); + } + + private class StubCacheApi implements AsyncCacheApi { + + private Map cache = new HashMap<>(1); + + @SuppressWarnings("unchecked") + @Override + public CompletionStage getOrElseUpdate(String key, Callable> block, int expiration) { + if (cache.containsKey(key)) { + return CompletableFuture.completedFuture((T) Geolocation.empty()); // We test only method invocations, not method call results so we don't need any value here. + } + cache.put(key, key); + // See Scala.asScalaWithFuture(block) + try { + return block.call(); + } catch (RuntimeException | Error e) { + throw e; + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // ---- Rest are stubs. Just to implement interface. ISP violation. + + @Override + public CompletionStage get(String key) { + return null; // Testing white box. No need to implement all methods. + } + + @Override + public CompletionStage getOrElseUpdate( + String key, Callable> block + ) { + return null; // Testing white box. No need to implement all methods. + } + + @Override + public CompletionStage set(String key, Object value, int expiration) { + return null; // Testing white box. No need to implement all methods. + } + + @Override + public CompletionStage set(String key, Object value) { + return null; // Testing white box. No need to implement all methods. + } + + @Override + public CompletionStage remove(String key) { + return null; // Testing white box. No need to implement all methods. + } + + @Override + public CompletionStage removeAll() { + return null; // Testing white box. No need to implement all methods. + } + } +} diff --git a/test/com/edulify/modules/geolocation/GeolocationCacheTest.java b/test/com/edulify/modules/geolocation/GeolocationCacheTest.java index d7fd3ff..4572126 100644 --- a/test/com/edulify/modules/geolocation/GeolocationCacheTest.java +++ b/test/com/edulify/modules/geolocation/GeolocationCacheTest.java @@ -9,6 +9,10 @@ import java.util.HashMap; import java.util.Map; +/** + * @deprecated Deprecated as of 2.2.0. Source should be removed. + */ +@Deprecated public class GeolocationCacheTest { private final String ipAddress = "192.30.252.129"; diff --git a/test/com/edulify/modules/geolocation/GeolocationServiceTest.java b/test/com/edulify/modules/geolocation/GeolocationServiceTest.java index 1f999c3..3ce96f4 100644 --- a/test/com/edulify/modules/geolocation/GeolocationServiceTest.java +++ b/test/com/edulify/modules/geolocation/GeolocationServiceTest.java @@ -1,21 +1,26 @@ package com.edulify.modules.geolocation; -import org.junit.*; -import org.hamcrest.*; +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Test; import org.mockito.Mockito; - -import play.*; -import play.test.WithApplication; +import play.Application; +import play.Mode; import play.inject.guice.GuiceApplicationBuilder; +import play.test.WithApplication; import java.io.File; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; -import static com.jayway.awaitility.Awaitility.*; +import static com.jayway.awaitility.Awaitility.await; import static play.inject.Bindings.bind; +/** + * @deprecated Deprecated as of 2.2.0. Source should be removed. + */ +@Deprecated public class GeolocationServiceTest extends WithApplication { private final String ipAddress = "192.30.252.129"; From 9c05fa5b19bda1d82331adcebfdd589a2b725175 Mon Sep 17 00:00:00 2001 From: sowhat Date: Wed, 25 Oct 2017 08:12:21 +0300 Subject: [PATCH 07/13] Bump sample application code. --- sample/java/app/controllers/Application.java | 24 ++++++++++---------- sample/java/build.sbt | 7 +++--- sample/java/conf/application.conf | 10 +------- sample/java/conf/reference.conf | 5 ---- sample/java/project/build.properties | 2 +- sample/java/project/plugins.sbt | 2 +- 6 files changed, 18 insertions(+), 32 deletions(-) delete mode 100644 sample/java/conf/reference.conf diff --git a/sample/java/app/controllers/Application.java b/sample/java/app/controllers/Application.java index dd976fc..188f3d7 100644 --- a/sample/java/app/controllers/Application.java +++ b/sample/java/app/controllers/Application.java @@ -1,14 +1,14 @@ package controllers; import com.edulify.modules.geolocation.Geolocation; -import play.mvc.*; - -import views.html.*; +import com.edulify.modules.geolocation.GeolocationProvider; +import play.mvc.Controller; +import play.mvc.Result; +import views.html.geoData; +import views.html.index; import javax.inject.Inject; - -import com.edulify.modules.geolocation.GeolocationService; - +import javax.inject.Named; import java.util.concurrent.CompletionStage; import java.util.function.Function; @@ -17,11 +17,11 @@ public class Application extends Controller { - private GeolocationService geolocationService; + private GeolocationProvider geolocationService; @Inject - public Application(GeolocationService geolocationService) { - this.geolocationService = geolocationService; + public Application(@Named("CachedGeolocationProvider") GeolocationProvider geolocationProvider) { + this.geolocationService = geolocationProvider; } public Result index() { @@ -29,17 +29,17 @@ public Result index() { } public CompletionStage getCountry(final String addr) { - return geolocationService.getGeolocation(addr) + return geolocationService.get(addr) .thenApplyAsync(geolocation -> ok(index.render(formHeader(geolocation, addr, Geolocation::getCountryName)))); } public CompletionStage getCountryCode(final String addr) { - return geolocationService.getGeolocation(addr) + return geolocationService.get(addr) .thenApplyAsync(geolocation -> ok(index.render(formHeader(geolocation, addr)))); } public CompletionStage getGeolocation(final String addr) { - return geolocationService.getGeolocation(addr) + return geolocationService.get(addr) .thenApplyAsync(geolocation -> ok(geoData.render(geolocation, formHeader(geolocation, addr)))); } diff --git a/sample/java/build.sbt b/sample/java/build.sbt index 1760f2f..47bff21 100644 --- a/sample/java/build.sbt +++ b/sample/java/build.sbt @@ -2,15 +2,14 @@ name := "geolocation-java-sample" version := "1.0-SNAPSHOT" -lazy val root = (project in file(".")).enablePlugins(PlayJava) +lazy val root = (project in file(".")).enablePlugins(PlayMinimalJava) -scalaVersion := "2.11.11" +scalaVersion := "2.12.4" routesGenerator := InjectedRoutesGenerator libraryDependencies ++= Seq( - // Add your project dependencies here, - javaCore, + ehcache, "com.edulify" %% "geolocation" % "2.2.0" ) diff --git a/sample/java/conf/application.conf b/sample/java/conf/application.conf index e48326a..6ceca73 100644 --- a/sample/java/conf/application.conf +++ b/sample/java/conf/application.conf @@ -9,14 +9,6 @@ play.http.secret.key="i[7Ve:r2mSr`PKm1x@kVYm0XfqW[vLarVbjGuP/Q8I8p@iZ8RLVPSiq@6Z # The application languages # ~~~~~ -application.langs="en" +play.i18n.langs=["en"] play.modules.enabled += "com.edulify.modules.geolocation.providers.FreegeoipModule" - -geolocation { - timeout = 1s - cache { - on = true - ttl = 10s - } -} \ No newline at end of file diff --git a/sample/java/conf/reference.conf b/sample/java/conf/reference.conf deleted file mode 100644 index 77aaa62..0000000 --- a/sample/java/conf/reference.conf +++ /dev/null @@ -1,5 +0,0 @@ -play { - modules { - enabled += "com.edulify.modules.geolocation.providers.FreegeoipModule" - } -} diff --git a/sample/java/project/build.properties b/sample/java/project/build.properties index 64317fd..c091b86 100644 --- a/sample/java/project/build.properties +++ b/sample/java/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.15 +sbt.version=0.13.16 diff --git a/sample/java/project/plugins.sbt b/sample/java/project/plugins.sbt index f604d1e..0de67c6 100644 --- a/sample/java/project/plugins.sbt +++ b/sample/java/project/plugins.sbt @@ -5,5 +5,5 @@ logLevel := Level.Warn resolvers += Resolver.typesafeRepo("releases") // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.1")) +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.6")) From 914ec9d2bd30d9fc5a01f30ae935bc79445967e5 Mon Sep 17 00:00:00 2001 From: sowhat Date: Wed, 25 Oct 2017 08:27:27 +0300 Subject: [PATCH 08/13] Fix deprecated GeolocationCacheTest --- .../com/edulify/modules/geolocation/GeolocationCacheTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/com/edulify/modules/geolocation/GeolocationCacheTest.java b/test/com/edulify/modules/geolocation/GeolocationCacheTest.java index 4572126..b5ed53d 100644 --- a/test/com/edulify/modules/geolocation/GeolocationCacheTest.java +++ b/test/com/edulify/modules/geolocation/GeolocationCacheTest.java @@ -1,9 +1,11 @@ package com.edulify.modules.geolocation; +import com.edulify.modules.geolocation.providers.FreegeoipModule; import org.hamcrest.CoreMatchers; import org.junit.Assert; import org.junit.Test; import play.Application; +import play.inject.guice.GuiceApplicationBuilder; import play.test.Helpers; import java.util.HashMap; @@ -47,6 +49,6 @@ public void shouldNotAddGeolocationToCacheWhenCacheIsOff() { private Application getApplication(boolean cacheOn) { Map config = new HashMap<>(); config.put("geolocation.cache.on", cacheOn); - return Helpers.fakeApplication(config); + return new GuiceApplicationBuilder().bindings(new FreegeoipModule()).configure(config).build(); } } From cbd52a9dae0d519d22ebf347e1484cdce22f372a Mon Sep 17 00:00:00 2001 From: sowaalexandr Date: Mon, 13 Nov 2017 19:52:01 +0200 Subject: [PATCH 09/13] Modular sub-project based repository structure to be able to add Freegeoip and MaxMind dependencies one at a time. --- .gitignore | 5 +- .travis.yml | 1 - README.md | 9 +- .../providers/FreegeoipModule.java | 19 -- .../geolocation/providers/MaxmindModule.java | 20 -- build.sbt | 194 ++++++++++++------ conf/reference.conf | 10 - .../modules/geolocation/FreegeoipModule.java | 31 +++ .../geolocation}/FreegeoipProviderTest.java | 31 ++- .../geolocation}/FreegeoipProvider.java | 15 +- .../geolocation/GeolocationModule.java | 0 .../geolocation/GeolocationCacheTest.java | 52 +++++ .../geolocation/GeolocationServiceTest.java | 35 ++++ .../modules/geolocation/CachedProvider.java | 0 .../modules/geolocation/Geolocation.java | 0 .../modules/geolocation/GeolocationCache.java | 0 .../geolocation/GeolocationProvider.java | 0 .../geolocation/GeolocationService.java | 0 geolocation/src/main/resources/reference.conf | 4 + .../geolocation/CachedProviderTest.java | 0 .../modules/geolocation/MaxmindModule.java | 31 +++ .../src/main/resources/reference.conf | 1 + .../geolocation}/MaxmindProviderTest.java | 33 ++- .../modules/geolocation}/MaxmindProvider.java | 12 +- project/build.properties | 2 +- project/plugins.sbt | 4 +- sample/java/.gitignore | 15 -- .../ws/standalone/StandaloneAhcWSModule.java | 46 +++++ sample/java/build.sbt | 18 -- sample/java/conf/application.conf | 5 +- sample/java/project/build.properties | 1 - sample/java/project/plugins.sbt | 9 - .../geolocation/GeolocationCacheTest.java | 54 ----- .../geolocation/GeolocationServiceTest.java | 67 ------ version.sbt | 1 + 35 files changed, 409 insertions(+), 316 deletions(-) delete mode 100644 app/com/edulify/modules/geolocation/providers/FreegeoipModule.java delete mode 100644 app/com/edulify/modules/geolocation/providers/MaxmindModule.java delete mode 100644 conf/reference.conf create mode 100644 freegeoip-guice/src/main/java/com/edulify/modules/geolocation/FreegeoipModule.java rename {test/com/edulify/modules/geolocation/providers => freegeoip-guice/src/test/java/com/edulify/modules/geolocation}/FreegeoipProviderTest.java (80%) rename {app/com/edulify/modules/geolocation/providers => freegeoip/src/main/java/com/edulify/modules/geolocation}/FreegeoipProvider.java (84%) rename {app => geolocation-guice/src/main/java}/com/edulify/modules/geolocation/GeolocationModule.java (100%) create mode 100644 geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationCacheTest.java create mode 100644 geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java rename {app => geolocation/src/main/java}/com/edulify/modules/geolocation/CachedProvider.java (100%) rename {app => geolocation/src/main/java}/com/edulify/modules/geolocation/Geolocation.java (100%) rename {app => geolocation/src/main/java}/com/edulify/modules/geolocation/GeolocationCache.java (100%) rename {app => geolocation/src/main/java}/com/edulify/modules/geolocation/GeolocationProvider.java (100%) rename {app => geolocation/src/main/java}/com/edulify/modules/geolocation/GeolocationService.java (100%) create mode 100644 geolocation/src/main/resources/reference.conf rename {test => geolocation/src/test/java}/com/edulify/modules/geolocation/CachedProviderTest.java (100%) create mode 100644 maxmind-geoip2web-guice/src/main/java/com/edulify/modules/geolocation/MaxmindModule.java create mode 100644 maxmind-geoip2web-guice/src/main/resources/reference.conf rename {test/com/edulify/modules/geolocation/providers => maxmind-geoip2web-guice/src/test/java/com/edulify/modules/geolocation}/MaxmindProviderTest.java (76%) rename {app/com/edulify/modules/geolocation/providers => maxmind-geoip2web/src/main/java/com/edulify/modules/geolocation}/MaxmindProvider.java (76%) delete mode 100644 sample/java/.gitignore create mode 100644 sample/java/app/com/edulify/modules/ws/standalone/StandaloneAhcWSModule.java delete mode 100644 sample/java/build.sbt delete mode 100644 sample/java/project/build.properties delete mode 100644 sample/java/project/plugins.sbt delete mode 100644 test/com/edulify/modules/geolocation/GeolocationCacheTest.java delete mode 100644 test/com/edulify/modules/geolocation/GeolocationServiceTest.java create mode 100644 version.sbt diff --git a/.gitignore b/.gitignore index a13372d..f44dcb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ .idea -project target -logs -project/project -project/target +logs/ tmp .history dist diff --git a/.travis.yml b/.travis.yml index c01440a..a2fa2bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: scala script: - sbt clean compile test publishLocal - - cd sample/java && sbt clean compile test jdk: - oraclejdk8 diff --git a/README.md b/README.md index 602d25c..1b8e800 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,6 @@ object ApplicationBuild extends Build { val appDependencies = Seq( // Add your project dependencies here, - javaCore, - javaJdbc, "com.edulify" %% "geolocation" % "2.1.0" ) @@ -84,13 +82,13 @@ object ApplicationBuild extends Build { Since there is support to Freegeoip and Maxmind, there is also two modules that you enable, depending on which one you want to use. To eanble the module, just add the following line to you `conf/application.conf` file: ``` -play.modules.enabled += "com.edulify.modules.geolocation.providers.FreegeoipModule" +play.modules.enabled += "com.edulify.modules.geolocation.FreegeoipModule" ``` Or, in case you want to use Maxmind instead: ``` -play.modules.enabled += "com.edulify.modules.geolocation.providers.MaxmindModule" +play.modules.enabled += "com.edulify.modules.geolocation.MaxmindModule" ``` ## Configurations @@ -112,14 +110,13 @@ geolocation { on = true ttl = 10s } - maxmind.license = "your-maxmind-license" } ``` Also, notice that the cache uses the cache support offered by Playframework. A complete configuration can be found below: ``` -play.modules.enabled += "com.edulify.modules.geolocation.providers.FreegeoipModule" +play.modules.enabled += "com.edulify.modules.geolocation.FreegeoipModule" geolocation { cache { diff --git a/app/com/edulify/modules/geolocation/providers/FreegeoipModule.java b/app/com/edulify/modules/geolocation/providers/FreegeoipModule.java deleted file mode 100644 index e479a9f..0000000 --- a/app/com/edulify/modules/geolocation/providers/FreegeoipModule.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.edulify.modules.geolocation.providers; - -import com.edulify.modules.geolocation.GeolocationProvider; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import play.libs.ws.WSClient; - -import java.util.concurrent.Executor; - -public class FreegeoipModule extends AbstractModule { - - @Override - protected void configure() { } - - @Provides - public GeolocationProvider geolocationProvider(WSClient wsClient, Executor wsExecutor) { - return new FreegeoipProvider(wsClient, wsExecutor); - } -} diff --git a/app/com/edulify/modules/geolocation/providers/MaxmindModule.java b/app/com/edulify/modules/geolocation/providers/MaxmindModule.java deleted file mode 100644 index 0ac38ee..0000000 --- a/app/com/edulify/modules/geolocation/providers/MaxmindModule.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.edulify.modules.geolocation.providers; - -import com.edulify.modules.geolocation.GeolocationProvider; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.typesafe.config.Config; -import play.libs.ws.WSClient; - -import java.util.concurrent.Executor; - -public class MaxmindModule extends AbstractModule { - - @Override - protected void configure() { } - - @Provides - public GeolocationProvider geolocationProvider(WSClient wsClient, Config config, Executor wsExecutor) { - return new MaxmindProvider(wsClient, config.getString("geolocation.maxmind.license"), wsExecutor); - } -} diff --git a/build.sbt b/build.sbt index 30daaef..b998d90 100644 --- a/build.sbt +++ b/build.sbt @@ -1,68 +1,138 @@ -name := "geolocation" -version := "2.2.0" - -scalaVersion := "2.12.4" - -lazy val root = (project in file(".")).enablePlugins(PlayMinimalJava) - -libraryDependencies ++= Seq( - javaWs, - cacheApi, - guice, - ehcache % Test, // Should be removed with deprecated GeolocationService and GeolocationCache - "org.mockito" % "mockito-core" % "2.11.0" % Test, - "com.jayway.awaitility" % "awaitility" % "1.7.0" % Test +val javacSettings = Seq( + "-source", "1.8", + "-target", "1.8", + "-Xlint:deprecation", + "-Xlint:unchecked" ) -testOptions += Tests.Argument(TestFrameworks.JUnit, "-v", "-q") - -organization := "com.edulify" - -organizationName := "Edulify.com" - -organizationHomepage := Some(new URL("https://edulify.com")) - -publishMavenStyle := true - -publishArtifact in Test := false - -pomIncludeRepository := { _ => false } - -publishTo := { - if (version.value.trim.endsWith("SNAPSHOT")) - Some(Resolver.sonatypeRepo("snapshots")) - else - Some("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") -} - -startYear := Some(2013) - -description := "This is a geolocation module for Playframework." - -licenses := Seq("The Apache Software License, Version 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")) +lazy val commonSettings = Seq( + scalaVersion := "2.12.4", + organization := "com.edulify", + organizationName := "Edulify.com", + organizationHomepage := Some(new URL("https://edulify.com")), + startYear := Some(2013), + licenses := Seq("The Apache Software License, Version 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")), + homepage := Some(url("http://edulify.github.io/play-geolocation-module.edulify.com/")), + pomExtra := + + https://github.com/edulify/play-geolocation-module.edulify.com + scm:git:git@github.com:edulify/play-geolocation-module.edulify.com.git + scm:git:https://github.com/edulify/play-geolocation-module.edulify.com.git + + + + megazord + Megazord + contact [at] edulify.com + https://github.com/megazord + + + ranierivalenca + Ranieri Valença + ranierivalenca [at] edulify.com + https://github.com/ranierivalenca + +, + publishMavenStyle := true, + pomIncludeRepository := { _ => false }, + publishTo := { Some(if (isSnapshot.value) Resolver.sonatypeRepo("snapshots") else "releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") }, + scalacOptions := Seq("-feature", "-deprecation"), + javacOptions in (Compile, doc) ++= javacSettings, + javacOptions in Test ++= javacSettings, + javacOptions in IntegrationTest ++= javacSettings, + testOptions += Tests.Argument(TestFrameworks.JUnit, "-v", "-q", "-a"), +) -homepage := Some(url("http://edulify.github.io/play-geolocation-module.edulify.com/")) +val disableDocs = Seq[Setting[_]]( + sources in (Compile, doc) := Seq.empty, + publishArtifact in (Compile, packageDoc) := false +) -pomExtra := - - https://github.com/edulify/play-geolocation-module.edulify.com - scm:git:git@github.com:edulify/play-geolocation-module.edulify.com.git - scm:git:https://github.com/edulify/play-geolocation-module.edulify.com.git - - - - megazord - Megazord - contact [at] edulify.com - https://github.com/megazord - - - ranierivalenca - Ranieri Valença - ranierivalenca [at] edulify.com - https://github.com/ranierivalenca - - +val disablePublishing = Seq[Setting[_]]( + publishArtifact := false, + // The above is enough for Maven repos but it doesn't prevent publishing of ivy.xml files + publish := {}, + publishLocal := {} +) -scalacOptions := Seq("-feature", "-deprecation") +val playWsStandalone = "com.typesafe.play" %% "play-ahc-ws-standalone" % "1.1.3" +val junit = "junit" % "junit" % "4.12" % Test +val junitInterface = "com.novocode" % "junit-interface" % "0.11" % Test +val mockito = "org.mockito" % "mockito-core" % "2.11.0" % Test +val hamcrest = "org.hamcrest" % "hamcrest-core" % "1.3" % Test + +lazy val root = (project in file(".")) + .enablePlugins(PlayMinimalJava) + .aggregate(geolocation, `geolocation-guice`, freegeoip, `freegeoip-guice`, `maxmind-geoip2web`, `maxmind-geoip2web-guice`, `javaSample`) + .settings(commonSettings, disablePublishing, disableDocs, name := "edulify-geolocation") + +lazy val geolocation = (project in file("geolocation")) + .settings( + name := "geolocation", + description := "This is a geolocation module for Playframework.", + commonSettings + ) + .settings(libraryDependencies ++= Seq( + component("play-cache"), + ehcache % Test, // Should be removed with deprecated GeolocationService and GeolocationCache + junit, + junitInterface, + mockito + )) + +lazy val `geolocation-guice` = (project in file("geolocation-guice")) + .settings(commonSettings) + .settings(libraryDependencies ++= Seq( + guice, + hamcrest + )) + .dependsOn(geolocation % "test->test;compile->compile") + +lazy val freegeoip = (project in file("freegeoip")) + .settings(commonSettings) + .settings(libraryDependencies ++= Seq( + playWsStandalone + )) + .dependsOn(geolocation) + +lazy val `freegeoip-guice` = (project in file("freegeoip-guice")) + .settings(commonSettings) + .settings(libraryDependencies ++= Seq( + component("play-server") % Test, + javaCore % Test, + component("play-test") % Test, + component("play-ahc-ws") % Test, + component("play-akka-http-server") % Test + )) + .dependsOn(freegeoip, `geolocation-guice` % "test->test;compile->compile") + +lazy val `maxmind-geoip2web` = (project in file("maxmind-geoip2web")) + .settings(commonSettings) + .settings(libraryDependencies ++= Seq( + playWsStandalone + )) + .dependsOn(geolocation) + +lazy val `maxmind-geoip2web-guice` = (project in file("maxmind-geoip2web-guice")) + .settings(commonSettings) + .settings(libraryDependencies ++= Seq( + component("play-server") % Test, + javaCore % Test, + component("play-ahc-ws") % Test, + component("play-akka-http-server") % Test + )) + .dependsOn(`maxmind-geoip2web`, `geolocation-guice` % "test->test;compile->compile") + +lazy val `javaSample` = (project in file("sample/java")) + .enablePlugins(PlayMinimalJava) + .settings(routesGenerator := InjectedRoutesGenerator) + .settings( + commonSettings, + disableDocs, + disablePublishing + ) + .settings(libraryDependencies ++= Seq( + ehcache, ws + )) + .dependsOn(`freegeoip-guice`) diff --git a/conf/reference.conf b/conf/reference.conf deleted file mode 100644 index 5217f6a..0000000 --- a/conf/reference.conf +++ /dev/null @@ -1,10 +0,0 @@ - -play.modules.enabled += com.edulify.modules.geolocation.GeolocationModule - -geolocation { - cache { - on = true - ttl = 100 - } - maxmind.license = "abc123" -} \ No newline at end of file diff --git a/freegeoip-guice/src/main/java/com/edulify/modules/geolocation/FreegeoipModule.java b/freegeoip-guice/src/main/java/com/edulify/modules/geolocation/FreegeoipModule.java new file mode 100644 index 0000000..d63decb --- /dev/null +++ b/freegeoip-guice/src/main/java/com/edulify/modules/geolocation/FreegeoipModule.java @@ -0,0 +1,31 @@ +package com.edulify.modules.geolocation; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.typesafe.config.Config; +import play.Environment; +import play.libs.ws.StandaloneWSClient; + +import java.util.concurrent.Executor; + +public class FreegeoipModule extends AbstractModule { + + private final Environment environment; + private final Config config; + + public FreegeoipModule(Environment environment, Config config) + { + this.environment = environment; + this.config = config; + } + + @Override + protected void configure() { + install(new GeolocationModule(environment, config)); + } + + @Provides + public GeolocationProvider geolocationProvider(StandaloneWSClient wsClient, Executor wsExecutor) { + return new FreegeoipProvider(wsClient, wsExecutor); + } +} diff --git a/test/com/edulify/modules/geolocation/providers/FreegeoipProviderTest.java b/freegeoip-guice/src/test/java/com/edulify/modules/geolocation/FreegeoipProviderTest.java similarity index 80% rename from test/com/edulify/modules/geolocation/providers/FreegeoipProviderTest.java rename to freegeoip-guice/src/test/java/com/edulify/modules/geolocation/FreegeoipProviderTest.java index e4e1c77..c4895fe 100644 --- a/test/com/edulify/modules/geolocation/providers/FreegeoipProviderTest.java +++ b/freegeoip-guice/src/test/java/com/edulify/modules/geolocation/FreegeoipProviderTest.java @@ -1,15 +1,16 @@ -package com.edulify.modules.geolocation.providers; +package com.edulify.modules.geolocation; -import com.edulify.modules.geolocation.Geolocation; -import com.edulify.modules.geolocation.GeolocationProvider; import com.google.common.collect.ImmutableMap; import org.junit.After; import org.junit.Before; import org.junit.Test; +import play.libs.ws.StandaloneWSClient; +import play.libs.ws.StandaloneWSRequest; import play.libs.ws.WSClient; import play.routing.RoutingDsl; import play.server.Server; +import java.io.IOException; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -22,7 +23,7 @@ public class FreegeoipProviderTest { private Server server; - private WSClient ws; + private StandaloneWSClient ws; private GeolocationProvider freeGeoIpProvider; private ExecutorService executor; @@ -44,7 +45,27 @@ public void setUp() throws Exception { }) .build()); - ws = play.test.WSTestClient.newClient(server.httpPort()); + WSClient wsClient = play.test.WSTestClient.newClient(server.httpPort()); + ws = new StandaloneWSClient() + { + @Override + public Object getUnderlying() + { + return wsClient.getUnderlying(); + } + + @Override + public StandaloneWSRequest url(String url) + { + return wsClient.url(url); + } + + @Override + public void close() throws IOException + { + wsClient.close(); + } + }; executor = Executors.newSingleThreadExecutor(); freeGeoIpProvider = new FreegeoipProvider(ws, executor, "/ip/%s"); diff --git a/app/com/edulify/modules/geolocation/providers/FreegeoipProvider.java b/freegeoip/src/main/java/com/edulify/modules/geolocation/FreegeoipProvider.java similarity index 84% rename from app/com/edulify/modules/geolocation/providers/FreegeoipProvider.java rename to freegeoip/src/main/java/com/edulify/modules/geolocation/FreegeoipProvider.java index fc94aed..d21dc11 100644 --- a/app/com/edulify/modules/geolocation/providers/FreegeoipProvider.java +++ b/freegeoip/src/main/java/com/edulify/modules/geolocation/FreegeoipProvider.java @@ -1,28 +1,27 @@ -package com.edulify.modules.geolocation.providers; +package com.edulify.modules.geolocation; -import com.edulify.modules.geolocation.Geolocation; -import com.edulify.modules.geolocation.GeolocationProvider; import com.fasterxml.jackson.databind.JsonNode; -import play.libs.ws.WSClient; +import play.libs.Json; +import play.libs.ws.StandaloneWSClient; import java.util.concurrent.CompletionStage; import java.util.concurrent.Executor; public class FreegeoipProvider implements GeolocationProvider { - private WSClient ws; + private StandaloneWSClient ws; private final String urlFormat; private final Executor threadToRunOn; - public FreegeoipProvider(WSClient ws, Executor threadToRunOn, String urlFormat) { + public FreegeoipProvider(StandaloneWSClient ws, Executor threadToRunOn, String urlFormat) { this.ws = ws; this.urlFormat = urlFormat; this.threadToRunOn = threadToRunOn; } - FreegeoipProvider(WSClient ws, Executor threadToRunOn) { + FreegeoipProvider(StandaloneWSClient ws, Executor threadToRunOn) { this(ws, threadToRunOn, "http://freegeoip.net/json/%s"); } @@ -34,7 +33,7 @@ public CompletionStage get(String ip) { .thenApplyAsync(response -> { if (response.getStatus() != 200) return null; if (response.getBody().contains("not found")) return null; - return response.asJson(); + return Json.parse(response.getBodyAsBytes().toArray()); }, threadToRunOn) .thenApplyAsync(json -> { if (json == null) return Geolocation.empty(); diff --git a/app/com/edulify/modules/geolocation/GeolocationModule.java b/geolocation-guice/src/main/java/com/edulify/modules/geolocation/GeolocationModule.java similarity index 100% rename from app/com/edulify/modules/geolocation/GeolocationModule.java rename to geolocation-guice/src/main/java/com/edulify/modules/geolocation/GeolocationModule.java diff --git a/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationCacheTest.java b/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationCacheTest.java new file mode 100644 index 0000000..23b8174 --- /dev/null +++ b/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationCacheTest.java @@ -0,0 +1,52 @@ +package com.edulify.modules.geolocation; + +import com.google.common.collect.ImmutableMap; +import org.junit.Test; +import play.Configuration; +import play.cache.CacheApi; + +import static org.mockito.Mockito.*; + +/** + * @deprecated Deprecated as of 2.2.0. Source should be removed. + */ +@Deprecated +public class GeolocationCacheTest { + + private final String ipAddress = "192.30.252.129"; + private final String countryCode = "BR"; + + @Test + public void shouldAddGeolocationToCacheWhenCacheIsOn() { + final CacheApi cacheApi = mock(CacheApi.class); + final GeolocationCache geolocationCache = new GeolocationCache( + new Configuration(ImmutableMap.of( + "geolocation.cache.on", true, + "geolocation.cache.ttl", 5000L + )), + cacheApi + ); + + final Geolocation geolocation = new Geolocation(ipAddress, countryCode); + geolocationCache.set(geolocation); + + verify(cacheApi).set(anyString(), eq(geolocation), eq(5000)); + } + + @Test + public void shouldNotAddGeolocationToCacheWhenCacheIsOff() { + final CacheApi cacheApi = mock(CacheApi.class); + final GeolocationCache geolocationCache = new GeolocationCache( + new Configuration(ImmutableMap.of( + "geolocation.cache.on", false, + "geolocation.cache.ttl", 5000L + )), + cacheApi + ); + + final Geolocation geolocation = new Geolocation(ipAddress, countryCode); + geolocationCache.set(geolocation); + + verify(cacheApi, never()).set(anyString(), eq(geolocation), eq(5000)); + } +} diff --git a/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java b/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java new file mode 100644 index 0000000..8ce9e89 --- /dev/null +++ b/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java @@ -0,0 +1,35 @@ +package com.edulify.modules.geolocation; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.*; + +/** + * @deprecated Deprecated as of 2.2.0. Source should be removed. + */ +@Deprecated +public class GeolocationServiceTest { + + @Test + public void shouldGetAGeolocationForAGivenIp() throws Exception { + + final GeolocationProvider provider = mock(GeolocationProvider.class); + + String ipAddress = "192.30.252.129"; + String countryCode = "BR"; + final Geolocation geolocation = new Geolocation(ipAddress, countryCode); + when(provider.get(ipAddress)).thenReturn(CompletableFuture.completedFuture(geolocation)); + final GeolocationCache cache = mock(GeolocationCache.class); + + GeolocationService service = new GeolocationService(provider, cache); + Geolocation target = service.getGeolocation(ipAddress).toCompletableFuture().get(1, TimeUnit.SECONDS); + + verify(cache).set(geolocation); + + Assert.assertSame(target, geolocation); + } +} diff --git a/app/com/edulify/modules/geolocation/CachedProvider.java b/geolocation/src/main/java/com/edulify/modules/geolocation/CachedProvider.java similarity index 100% rename from app/com/edulify/modules/geolocation/CachedProvider.java rename to geolocation/src/main/java/com/edulify/modules/geolocation/CachedProvider.java diff --git a/app/com/edulify/modules/geolocation/Geolocation.java b/geolocation/src/main/java/com/edulify/modules/geolocation/Geolocation.java similarity index 100% rename from app/com/edulify/modules/geolocation/Geolocation.java rename to geolocation/src/main/java/com/edulify/modules/geolocation/Geolocation.java diff --git a/app/com/edulify/modules/geolocation/GeolocationCache.java b/geolocation/src/main/java/com/edulify/modules/geolocation/GeolocationCache.java similarity index 100% rename from app/com/edulify/modules/geolocation/GeolocationCache.java rename to geolocation/src/main/java/com/edulify/modules/geolocation/GeolocationCache.java diff --git a/app/com/edulify/modules/geolocation/GeolocationProvider.java b/geolocation/src/main/java/com/edulify/modules/geolocation/GeolocationProvider.java similarity index 100% rename from app/com/edulify/modules/geolocation/GeolocationProvider.java rename to geolocation/src/main/java/com/edulify/modules/geolocation/GeolocationProvider.java diff --git a/app/com/edulify/modules/geolocation/GeolocationService.java b/geolocation/src/main/java/com/edulify/modules/geolocation/GeolocationService.java similarity index 100% rename from app/com/edulify/modules/geolocation/GeolocationService.java rename to geolocation/src/main/java/com/edulify/modules/geolocation/GeolocationService.java diff --git a/geolocation/src/main/resources/reference.conf b/geolocation/src/main/resources/reference.conf new file mode 100644 index 0000000..8ec375f --- /dev/null +++ b/geolocation/src/main/resources/reference.conf @@ -0,0 +1,4 @@ +geolocation.cache { + on = true + ttl = 100 +} diff --git a/test/com/edulify/modules/geolocation/CachedProviderTest.java b/geolocation/src/test/java/com/edulify/modules/geolocation/CachedProviderTest.java similarity index 100% rename from test/com/edulify/modules/geolocation/CachedProviderTest.java rename to geolocation/src/test/java/com/edulify/modules/geolocation/CachedProviderTest.java diff --git a/maxmind-geoip2web-guice/src/main/java/com/edulify/modules/geolocation/MaxmindModule.java b/maxmind-geoip2web-guice/src/main/java/com/edulify/modules/geolocation/MaxmindModule.java new file mode 100644 index 0000000..29894e6 --- /dev/null +++ b/maxmind-geoip2web-guice/src/main/java/com/edulify/modules/geolocation/MaxmindModule.java @@ -0,0 +1,31 @@ +package com.edulify.modules.geolocation; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.typesafe.config.Config; +import play.Environment; +import play.libs.ws.StandaloneWSClient; + +import java.util.concurrent.Executor; + +public class MaxmindModule extends AbstractModule { + + private final Environment environment; + private final Config config; + + public MaxmindModule(Environment environment, Config config) + { + this.environment = environment; + this.config = config; + } + + @Override + protected void configure() { + install(new GeolocationModule(environment, config)); + } + + @Provides + public GeolocationProvider geolocationProvider(StandaloneWSClient wsClient, Executor wsExecutor) { + return new MaxmindProvider(wsClient, config.getString("geolocation.maxmind.license"), wsExecutor); + } +} diff --git a/maxmind-geoip2web-guice/src/main/resources/reference.conf b/maxmind-geoip2web-guice/src/main/resources/reference.conf new file mode 100644 index 0000000..536e6a6 --- /dev/null +++ b/maxmind-geoip2web-guice/src/main/resources/reference.conf @@ -0,0 +1 @@ +geolocation.maxmind.license = ~ diff --git a/test/com/edulify/modules/geolocation/providers/MaxmindProviderTest.java b/maxmind-geoip2web-guice/src/test/java/com/edulify/modules/geolocation/MaxmindProviderTest.java similarity index 76% rename from test/com/edulify/modules/geolocation/providers/MaxmindProviderTest.java rename to maxmind-geoip2web-guice/src/test/java/com/edulify/modules/geolocation/MaxmindProviderTest.java index cd24405..1eb74cb 100644 --- a/test/com/edulify/modules/geolocation/providers/MaxmindProviderTest.java +++ b/maxmind-geoip2web-guice/src/test/java/com/edulify/modules/geolocation/MaxmindProviderTest.java @@ -1,16 +1,17 @@ -package com.edulify.modules.geolocation.providers; +package com.edulify.modules.geolocation; -import com.edulify.modules.geolocation.Geolocation; -import com.edulify.modules.geolocation.GeolocationProvider; import com.google.common.collect.ImmutableMap; import org.junit.After; import org.junit.Before; import org.junit.Test; +import play.libs.ws.StandaloneWSClient; +import play.libs.ws.StandaloneWSRequest; import play.libs.ws.WSClient; import play.mvc.Http; import play.routing.RoutingDsl; import play.server.Server; +import java.io.IOException; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -23,7 +24,7 @@ public class MaxmindProviderTest { private Server server; - private WSClient ws; + private StandaloneWSClient ws; private GeolocationProvider maxmindProvider; private ExecutorService executor; @@ -43,7 +44,27 @@ public void setUp() throws Exception { }) .build()); - ws = play.test.WSTestClient.newClient(server.httpPort()); + WSClient wsClient = play.test.WSTestClient.newClient(server.httpPort()); + ws = new StandaloneWSClient() + { + @Override + public Object getUnderlying() + { + return wsClient.getUnderlying(); + } + + @Override + public StandaloneWSRequest url(String url) + { + return wsClient.url(url); + } + + @Override + public void close() throws IOException + { + wsClient.close(); + } + }; executor = Executors.newSingleThreadExecutor(); maxmindProvider = new MaxmindProvider(ws, "any test string", executor, "/ip?l=%s"); @@ -72,4 +93,4 @@ public void get() throws Exception { assertEquals("", geolocation.getCountryCode()); } -} \ No newline at end of file +} diff --git a/app/com/edulify/modules/geolocation/providers/MaxmindProvider.java b/maxmind-geoip2web/src/main/java/com/edulify/modules/geolocation/MaxmindProvider.java similarity index 76% rename from app/com/edulify/modules/geolocation/providers/MaxmindProvider.java rename to maxmind-geoip2web/src/main/java/com/edulify/modules/geolocation/MaxmindProvider.java index ac74bd4..dcfa183 100644 --- a/app/com/edulify/modules/geolocation/providers/MaxmindProvider.java +++ b/maxmind-geoip2web/src/main/java/com/edulify/modules/geolocation/MaxmindProvider.java @@ -1,8 +1,6 @@ -package com.edulify.modules.geolocation.providers; +package com.edulify.modules.geolocation; -import com.edulify.modules.geolocation.Geolocation; -import com.edulify.modules.geolocation.GeolocationProvider; -import play.libs.ws.WSClient; +import play.libs.ws.StandaloneWSClient; import java.util.concurrent.CompletionStage; import java.util.concurrent.Executor; @@ -11,20 +9,20 @@ public class MaxmindProvider implements GeolocationProvider { private final Executor threadToRunOn; - private final WSClient ws; + private final StandaloneWSClient ws; private final String license; private final String baseUrl; - MaxmindProvider(WSClient ws, String license, Executor threadToRunOn, String urlFormat) { + MaxmindProvider(StandaloneWSClient ws, String license, Executor threadToRunOn, String urlFormat) { this.ws = ws; this.license = license; this.threadToRunOn = threadToRunOn; this.baseUrl = urlFormat; } - public MaxmindProvider(WSClient ws, String license, Executor threadToRunOn) { + public MaxmindProvider(StandaloneWSClient ws, String license, Executor threadToRunOn) { this(ws, license, threadToRunOn, "https://geoip.maxmind.com/a?l=%s"); } diff --git a/project/build.properties b/project/build.properties index c091b86..9abea12 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.16 +sbt.version=1.0.3 diff --git a/project/plugins.sbt b/project/plugins.sbt index ed6f4a5..697c787 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,6 +2,6 @@ logLevel := Level.Warn // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.6")) +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.7")) -addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3") +addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0") diff --git a/sample/java/.gitignore b/sample/java/.gitignore deleted file mode 100644 index 8570daf..0000000 --- a/sample/java/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -logs -project/project -project/target -target -tmp -.history -dist -/.idea -/*.iml -/out -/.idea_modules -/.classpath -/.project -/RUNNING_PID -/.settings diff --git a/sample/java/app/com/edulify/modules/ws/standalone/StandaloneAhcWSModule.java b/sample/java/app/com/edulify/modules/ws/standalone/StandaloneAhcWSModule.java new file mode 100644 index 0000000..5d14a1d --- /dev/null +++ b/sample/java/app/com/edulify/modules/ws/standalone/StandaloneAhcWSModule.java @@ -0,0 +1,46 @@ +package com.edulify.modules.ws.standalone; + +import akka.stream.Materializer; +import play.api.Configuration; +import play.api.Environment; +import play.api.inject.Binding; +import play.api.inject.Module; +import play.libs.ws.StandaloneWSClient; +import play.libs.ws.ahc.StandaloneAhcWSClient; +import play.shaded.ahc.org.asynchttpclient.AsyncHttpClient; +import scala.collection.Seq; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; + +/** + * Play not supplies such a module by default. + */ +public class StandaloneAhcWSModule extends Module +{ + + @Override + public Seq> bindings(Environment environment, Configuration configuration) { + return seq( + // AsyncHttpClientProvider is added by the Scala API + bind(StandaloneWSClient.class).toProvider(StandaloneAhcWSModule.AhcWSClientProvider.class) + ); + } + + @Singleton + public static class AhcWSClientProvider implements Provider + { + private final StandaloneWSClient client; + + @Inject + public AhcWSClientProvider(AsyncHttpClient asyncHttpClient, Materializer materializer) { + client = new StandaloneAhcWSClient(asyncHttpClient, materializer); + } + + @Override + public StandaloneWSClient get() { + return client; + } + } +} diff --git a/sample/java/build.sbt b/sample/java/build.sbt deleted file mode 100644 index 47bff21..0000000 --- a/sample/java/build.sbt +++ /dev/null @@ -1,18 +0,0 @@ -name := "geolocation-java-sample" - -version := "1.0-SNAPSHOT" - -lazy val root = (project in file(".")).enablePlugins(PlayMinimalJava) - -scalaVersion := "2.12.4" - -routesGenerator := InjectedRoutesGenerator - -libraryDependencies ++= Seq( - ehcache, - "com.edulify" %% "geolocation" % "2.2.0" -) - -resolvers ++= Seq( - Resolver.url("Edulify Repository", url("https://edulify.github.io/modules/releases/"))(Resolver.ivyStylePatterns) -) diff --git a/sample/java/conf/application.conf b/sample/java/conf/application.conf index 6ceca73..ac941b0 100644 --- a/sample/java/conf/application.conf +++ b/sample/java/conf/application.conf @@ -11,4 +11,7 @@ play.http.secret.key="i[7Ve:r2mSr`PKm1x@kVYm0XfqW[vLarVbjGuP/Q8I8p@iZ8RLVPSiq@6Z # ~~~~~ play.i18n.langs=["en"] -play.modules.enabled += "com.edulify.modules.geolocation.providers.FreegeoipModule" +play.modules { + enabled += "com.edulify.modules.geolocation.FreegeoipModule" + enabled += "com.edulify.modules.ws.standalone.StandaloneAhcWSModule" +} diff --git a/sample/java/project/build.properties b/sample/java/project/build.properties deleted file mode 100644 index c091b86..0000000 --- a/sample/java/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=0.13.16 diff --git a/sample/java/project/plugins.sbt b/sample/java/project/plugins.sbt deleted file mode 100644 index 0de67c6..0000000 --- a/sample/java/project/plugins.sbt +++ /dev/null @@ -1,9 +0,0 @@ -// Comment to get more information during initialization -logLevel := Level.Warn - -// The Typesafe repository -resolvers += Resolver.typesafeRepo("releases") - -// Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.6.6")) - diff --git a/test/com/edulify/modules/geolocation/GeolocationCacheTest.java b/test/com/edulify/modules/geolocation/GeolocationCacheTest.java deleted file mode 100644 index b5ed53d..0000000 --- a/test/com/edulify/modules/geolocation/GeolocationCacheTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.edulify.modules.geolocation; - -import com.edulify.modules.geolocation.providers.FreegeoipModule; -import org.hamcrest.CoreMatchers; -import org.junit.Assert; -import org.junit.Test; -import play.Application; -import play.inject.guice.GuiceApplicationBuilder; -import play.test.Helpers; - -import java.util.HashMap; -import java.util.Map; - -/** - * @deprecated Deprecated as of 2.2.0. Source should be removed. - */ -@Deprecated -public class GeolocationCacheTest { - - private final String ipAddress = "192.30.252.129"; - private final String countryCode = "BR"; - - @Test - public void shouldAddGeolocationToCacheWhenCacheIsOn() { - Application application = getApplication(true); - - Helpers.running(application, () -> { - Geolocation geolocation = new Geolocation(ipAddress, countryCode); - GeolocationCache cache = application.injector().instanceOf(GeolocationCache.class); - - cache.set(geolocation); - Assert.assertThat(cache.get(ipAddress), CoreMatchers.notNullValue()); - }); - } - - @Test - public void shouldNotAddGeolocationToCacheWhenCacheIsOff() { - Application application = getApplication(false); - - Helpers.running(application, () -> { - Geolocation geolocation = new Geolocation(ipAddress, countryCode); - GeolocationCache cache = application.injector().instanceOf(GeolocationCache.class); - - cache.set(geolocation); - Assert.assertThat(cache.get(ipAddress), CoreMatchers.nullValue()); - }); - } - - private Application getApplication(boolean cacheOn) { - Map config = new HashMap<>(); - config.put("geolocation.cache.on", cacheOn); - return new GuiceApplicationBuilder().bindings(new FreegeoipModule()).configure(config).build(); - } -} diff --git a/test/com/edulify/modules/geolocation/GeolocationServiceTest.java b/test/com/edulify/modules/geolocation/GeolocationServiceTest.java deleted file mode 100644 index 3ce96f4..0000000 --- a/test/com/edulify/modules/geolocation/GeolocationServiceTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.edulify.modules.geolocation; - -import org.hamcrest.CoreMatchers; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; -import play.Application; -import play.Mode; -import play.inject.guice.GuiceApplicationBuilder; -import play.test.WithApplication; - -import java.io.File; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeUnit; - -import static com.jayway.awaitility.Awaitility.await; -import static play.inject.Bindings.bind; - -/** - * @deprecated Deprecated as of 2.2.0. Source should be removed. - */ -@Deprecated -public class GeolocationServiceTest extends WithApplication { - - private final String ipAddress = "192.30.252.129"; - private final String countryCode = "BR"; - - @Override - public Application provideApplication() { - Geolocation geolocation = new Geolocation(ipAddress, countryCode); - - GeolocationProvider provider = Mockito.mock(GeolocationProvider.class); - Mockito.when(provider.get(ipAddress)).thenReturn(CompletableFuture.completedFuture(geolocation)); - - return new GuiceApplicationBuilder() - .in(new File(".")) - .in(Mode.TEST) - .configure("geolocation.cache.on", true) - .bindings(bind(GeolocationProvider.class).toInstance(provider)) - .build(); - } - - @Test - public void shouldGetAGeolocationForAGivenIp() throws Exception { - GeolocationService service = app.injector().instanceOf(GeolocationService.class); - Geolocation geolocation = service.getGeolocation(ipAddress).toCompletableFuture().get(1, TimeUnit.SECONDS); - - Assert.assertThat(geolocation.getIp(), CoreMatchers.equalTo(ipAddress)); - Assert.assertThat(geolocation.getCountryCode(), CoreMatchers.equalTo(countryCode)); - } - - @Test - public void shouldSetAGeolocationCache() throws InterruptedException { - GeolocationService service = app.injector().instanceOf(GeolocationService.class); - GeolocationCache cache = app.injector().instanceOf(GeolocationCache.class); - - CompletionStage promise = service.getGeolocation(ipAddress); - - await().atMost(5, TimeUnit.SECONDS).until(() -> { - return promise.toCompletableFuture().isDone(); - }); - - Geolocation geolocation = cache.get(ipAddress); - Assert.assertThat(geolocation, CoreMatchers.notNullValue()); - } -} diff --git a/version.sbt b/version.sbt new file mode 100644 index 0000000..0192e94 --- /dev/null +++ b/version.sbt @@ -0,0 +1 @@ +version in ThisBuild := "2.1.0" \ No newline at end of file From e07c6f7209b37ca758e72469f29751a2d37dac96 Mon Sep 17 00:00:00 2001 From: sovaalexandr Date: Tue, 14 Nov 2017 13:28:46 +0200 Subject: [PATCH 10/13] no need to publishLocal --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a2fa2bf..67c18ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: scala script: - - sbt clean compile test publishLocal + - sbt clean compile test jdk: - oraclejdk8 From 01c14cb85bdf4de7e06b65e6ad1147d6e522166e Mon Sep 17 00:00:00 2001 From: sovaalexandr Date: Tue, 14 Nov 2017 13:42:54 +0200 Subject: [PATCH 11/13] Adjust test for concurrent environment --- .../com/edulify/modules/geolocation/GeolocationServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java b/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java index 8ce9e89..ecef81c 100644 --- a/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java +++ b/geolocation-guice/src/test/java/com/edulify/modules/geolocation/GeolocationServiceTest.java @@ -28,7 +28,7 @@ public void shouldGetAGeolocationForAGivenIp() throws Exception { GeolocationService service = new GeolocationService(provider, cache); Geolocation target = service.getGeolocation(ipAddress).toCompletableFuture().get(1, TimeUnit.SECONDS); - verify(cache).set(geolocation); + verify(cache, timeout(100).times(1)).set(geolocation); Assert.assertSame(target, geolocation); } From 8eda6356462c6521b7cdc8ac13b5d1d2ebf0cb76 Mon Sep 17 00:00:00 2001 From: sovaalexandr Date: Tue, 14 Nov 2017 14:11:19 +0200 Subject: [PATCH 12/13] Add Scala version to build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 67c18ca..5d1c8ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,3 +4,5 @@ script: jdk: - oraclejdk8 +scala: + - 2.12.4 \ No newline at end of file From e3d9387d684271071f32805170216ace66d151ea Mon Sep 17 00:00:00 2001 From: sovaalexandr Date: Fri, 17 Nov 2017 18:02:38 +0200 Subject: [PATCH 13/13] Module autoloading --- freegeoip-guice/src/main/resources/reference.conf | 1 + maxmind-geoip2web-guice/src/main/resources/reference.conf | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 freegeoip-guice/src/main/resources/reference.conf diff --git a/freegeoip-guice/src/main/resources/reference.conf b/freegeoip-guice/src/main/resources/reference.conf new file mode 100644 index 0000000..af0d301 --- /dev/null +++ b/freegeoip-guice/src/main/resources/reference.conf @@ -0,0 +1 @@ +play.modules.enabled += "com.edulify.modules.geolocation.FreegeoipModule" diff --git a/maxmind-geoip2web-guice/src/main/resources/reference.conf b/maxmind-geoip2web-guice/src/main/resources/reference.conf index 536e6a6..5d1d34c 100644 --- a/maxmind-geoip2web-guice/src/main/resources/reference.conf +++ b/maxmind-geoip2web-guice/src/main/resources/reference.conf @@ -1 +1,3 @@ +play.modules.enabled += "com.edulify.modules.geolocation.MaxmindModule" + geolocation.maxmind.license = ~