From 2a41d88c29beda2f681c58f404040c6b449a6c2f Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 17 Feb 2019 10:05:39 -0500 Subject: [PATCH 1/3] http service: use spring datasource configuration --- http-service/pom.xml | 9 ++ .../service/SpringBootWebApplication.java | 88 +++++++++++++++---- .../src/main/resources/application.yaml | 7 ++ .../service/SpringBootWebApplicationTest.java | 48 ++-------- .../src/test/resources/application.properties | 10 --- .../src/test/resources/application.yaml | 35 ++++++++ http-service/src/test/resources/dev.yaml | 19 ++++ 7 files changed, 146 insertions(+), 70 deletions(-) create mode 100644 http-service/src/main/resources/application.yaml delete mode 100644 http-service/src/test/resources/application.properties create mode 100644 http-service/src/test/resources/application.yaml create mode 100644 http-service/src/test/resources/dev.yaml diff --git a/http-service/pom.xml b/http-service/pom.xml index 75e257d32d..32dc046a4c 100644 --- a/http-service/pom.xml +++ b/http-service/pom.xml @@ -55,6 +55,10 @@ spring-boot-devtools true + + org.springframework + spring-jdbc + org.mapstruct @@ -130,6 +134,11 @@ 3.7.0 test + + com.h2database + h2 + test + diff --git a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java index 562d93445a..bfdac0a254 100644 --- a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java +++ b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java @@ -25,13 +25,11 @@ package net.runelite.http.service; import ch.qos.logback.classic.LoggerContext; +import com.google.common.base.Strings; import java.io.IOException; import java.time.Instant; import java.util.HashMap; import java.util.Map; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; @@ -44,11 +42,17 @@ import okhttp3.Cache; import okhttp3.OkHttpClient; import org.slf4j.ILoggerFactory; import org.slf4j.impl.StaticLoggerBinder; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; +import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; import org.springframework.scheduling.annotation.EnableScheduling; import org.sql2o.Sql2o; import org.sql2o.converters.Converter; @@ -56,6 +60,7 @@ import org.sql2o.quirks.NoQuirks; @SpringBootApplication @EnableScheduling +@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) @Slf4j public class SpringBootWebApplication extends SpringBootServletInitializer { @@ -96,35 +101,80 @@ public class SpringBootWebApplication extends SpringBootServletInitializer }; } - private Context getContext() throws NamingException + @ConfigurationProperties(prefix = "datasource.runelite") + @Bean("dataSourceRuneLite") + public DataSourceProperties dataSourceProperties() { - Context initCtx = new InitialContext(); - return (Context) initCtx.lookup("java:comp/env"); + return new DataSourceProperties(); + } + + @ConfigurationProperties(prefix = "datasource.runelite-cache") + @Bean("dataSourceRuneLiteCache") + public DataSourceProperties dataSourcePropertiesCache() + { + return new DataSourceProperties(); + } + + @ConfigurationProperties(prefix = "datasource.runelite-tracker") + @Bean("dataSourceRuneLiteTracker") + public DataSourceProperties dataSourcePropertiesTracker() + { + return new DataSourceProperties(); + } + + @Bean(value = "runelite", destroyMethod = "") + public DataSource runeliteDataSource(@Qualifier("dataSourceRuneLite") DataSourceProperties dataSourceProperties) + { + return getDataSource(dataSourceProperties); + } + + @Bean(value = "runelite-cache", destroyMethod = "") + public DataSource runeliteCache2DataSource(@Qualifier("dataSourceRuneLiteCache") DataSourceProperties dataSourceProperties) + { + return getDataSource(dataSourceProperties); + } + + @Bean(value = "runelite-tracker", destroyMethod = "") + public DataSource runeliteTrackerDataSource(@Qualifier("dataSourceRuneLiteTracker") DataSourceProperties dataSourceProperties) + { + return getDataSource(dataSourceProperties); } @Bean("Runelite SQL2O") - Sql2o sql2o() throws NamingException + public Sql2o sql2o(@Qualifier("runelite") DataSource dataSource) { - DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite"); - Map converters = new HashMap<>(); - converters.put(Instant.class, new InstantConverter()); - return new Sql2o(dataSource, new NoQuirks(converters)); + return createSql2oFromDataSource(dataSource); } @Bean("Runelite Cache SQL2O") - Sql2o cacheSql2o() throws NamingException + public Sql2o cacheSql2o(@Qualifier("runelite-cache") DataSource dataSource) { - DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite-cache2"); - Map converters = new HashMap<>(); - converters.put(Instant.class, new InstantConverter()); - return new Sql2o(dataSource, new NoQuirks(converters)); + return createSql2oFromDataSource(dataSource); } @Bean("Runelite XP Tracker SQL2O") - Sql2o trackerSql2o() throws NamingException + public Sql2o trackerSql2o(@Qualifier("runelite-tracker") DataSource dataSource) { - DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite-tracker"); - Map converters = new HashMap<>(); + return createSql2oFromDataSource(dataSource); + } + + private static DataSource getDataSource(DataSourceProperties dataSourceProperties) + { + if (!Strings.isNullOrEmpty(dataSourceProperties.getJndiName())) + { + // Use JNDI provided datasource, which is already configured with pooling + JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); + return dataSourceLookup.getDataSource(dataSourceProperties.getJndiName()); + } + else + { + return dataSourceProperties.initializeDataSourceBuilder().build(); + } + } + + private static Sql2o createSql2oFromDataSource(final DataSource dataSource) + { + final Map converters = new HashMap<>(); converters.put(Instant.class, new InstantConverter()); return new Sql2o(dataSource, new NoQuirks(converters)); } diff --git a/http-service/src/main/resources/application.yaml b/http-service/src/main/resources/application.yaml new file mode 100644 index 0000000000..7b6785a325 --- /dev/null +++ b/http-service/src/main/resources/application.yaml @@ -0,0 +1,7 @@ +datasource: + runelite: + jndiName: java:comp/env/jdbc/runelite + runelite-cache: + jndiName: java:comp/env/jdbc/runelite-cache2 + runelite-tracker: + jndiName: java:comp/env/jdbc/runelite-tracker \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/SpringBootWebApplicationTest.java b/http-service/src/test/java/net/runelite/http/service/SpringBootWebApplicationTest.java index 0503c075d8..d2d488e1e6 100644 --- a/http-service/src/test/java/net/runelite/http/service/SpringBootWebApplicationTest.java +++ b/http-service/src/test/java/net/runelite/http/service/SpringBootWebApplicationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Adam + * Copyright (c) 2019, Adam * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,57 +24,23 @@ */ package net.runelite.http.service; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import javax.naming.NamingException; -import net.runelite.http.service.util.InstantConverter; import org.junit.Ignore; import org.junit.Test; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.sql2o.Sql2o; -import org.sql2o.converters.Converter; -import org.sql2o.quirks.NoQuirks; -@SpringBootApplication -@EnableScheduling public class SpringBootWebApplicationTest { - @Bean("Runelite SQL2O") - Sql2o sql2o() - { - Map converters = new HashMap<>(); - converters.put(Instant.class, new InstantConverter()); - return new Sql2o("jdbc:mysql://192.168.1.2/runelite", "runelite", "runelite", new NoQuirks(converters)); - } - - @Bean("Runelite Cache SQL2O") - Sql2o cacheSql2o() throws NamingException - { - Map converters = new HashMap<>(); - converters.put(Instant.class, new InstantConverter()); - return new Sql2o("jdbc:mysql://192.168.1.2/cache", "runelite", "runelite", new NoQuirks(converters)); - } - - @Bean("Runelite XP Tracker SQL2O") - Sql2o xpSql2o() throws NamingException - { - Map converters = new HashMap<>(); - converters.put(Instant.class, new InstantConverter()); - return new Sql2o("jdbc:mysql://192.168.1.2/xptracker", "runelite", "runelite", new NoQuirks(converters)); - } - @Test @Ignore - public void test() throws InterruptedException + public void run() throws InterruptedException { - SpringApplication.run(SpringBootWebApplicationTest.class, new String[0]); + String[] args = new String[]{ + "--spring.config.location=classpath:/application.yaml,classpath:/dev.yaml" + }; + SpringApplication.run(SpringBootWebApplication.class, args); for (;;) { Thread.sleep(100L); } } -} +} \ No newline at end of file diff --git a/http-service/src/test/resources/application.properties b/http-service/src/test/resources/application.properties deleted file mode 100644 index ded3472a5c..0000000000 --- a/http-service/src/test/resources/application.properties +++ /dev/null @@ -1,10 +0,0 @@ -oauth.client-id=moo -oauth.client-secret=cow -minio.endpoint=http://10.96.22.171:9000 -minio.accesskey=AM54M27O4WZK65N6F8IP -minio.secretkey=/PZCxzmsJzwCHYlogcymuprniGCaaLUOET2n6yMP -minio.bucket=runelite -runelite.twitter.consumerkey=moo -runelite.twitter.secretkey=cow -runelite.twitter.listid=968949795153948673 -logging.level.net.runelite=DEBUG \ No newline at end of file diff --git a/http-service/src/test/resources/application.yaml b/http-service/src/test/resources/application.yaml new file mode 100644 index 0000000000..128e64d8ef --- /dev/null +++ b/http-service/src/test/resources/application.yaml @@ -0,0 +1,35 @@ +oauth: + client-id: moo + client-secret: cow + +minio: + endpoint: http://10.96.22.171:9000 + accesskey: AM54M27O4WZK65N6F8IP + secretkey: /PZCxzmsJzwCHYlogcymuprniGCaaLUOET2n6yMP + bucket: runelite + +runelite: + twitter: + consumerkey: moo + secretkey: cow + listid: 968949795153948673 + +logging: + level: + net: + runelite: + DEBUG + +datasource: + runelite: + driverClassName: org.h2.Driver + type: org.h2.jdbcx.JdbcDataSource + url: jdbc:h2:mem:runelite + runelite-cache: + driverClassName: org.h2.Driver + type: org.h2.jdbcx.JdbcDataSource + url: jdbc:h2:mem:cache + runelite-tracker: + driverClassName: org.h2.Driver + type: org.h2.jdbcx.JdbcDataSource + url: jdbc:h2:mem:xptracker diff --git a/http-service/src/test/resources/dev.yaml b/http-service/src/test/resources/dev.yaml new file mode 100644 index 0000000000..e4967ccee4 --- /dev/null +++ b/http-service/src/test/resources/dev.yaml @@ -0,0 +1,19 @@ +datasource: + runelite: + driverClassName: com.mysql.jdbc.Driver + type: com.mysql.jdbc.jdbc2.optional.MysqlDataSource + url: jdbc:mysql://192.168.1.2/runelite + username: runelite + password: runelite + runelite-cache: + driverClassName: com.mysql.jdbc.Driver + type: com.mysql.jdbc.jdbc2.optional.MysqlDataSource + url: jdbc:mysql://192.168.1.2/cache + username: runelite + password: runelite + runelite-tracker: + driverClassName: com.mysql.jdbc.Driver + type: com.mysql.jdbc.jdbc2.optional.MysqlDataSource + url: jdbc:mysql://192.168.1.2/xptracker + username: runelite + password: runelite From c55491cc117a65c043213ee68163008424930972 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 17 Feb 2019 12:47:41 -0500 Subject: [PATCH 2/3] http service: add loottracker controller test --- .../LootTrackerControllerTest.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java diff --git a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java new file mode 100644 index 0000000000..e708de0c29 --- /dev/null +++ b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.http.service.loottracker; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.loottracker.GameItem; +import net.runelite.http.api.loottracker.LootRecord; +import net.runelite.http.api.loottracker.LootRecordType; +import net.runelite.http.service.account.AuthFilter; +import net.runelite.http.service.account.beans.SessionEntry; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@WebMvcTest(LootTrackerController.class) +@Slf4j +public class LootTrackerControllerTest +{ + @Autowired + private MockMvc mockMvc; + + @MockBean + private LootTrackerService lootTrackerService; + + @MockBean + private AuthFilter authFilter; + + @Before + public void before() throws IOException + { + when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class))) + .thenReturn(mock(SessionEntry.class)); + } + + @Test + public void storeLootRecord() throws Exception + { + LootRecord lootRecord = new LootRecord(); + lootRecord.setType(LootRecordType.NPC); + lootRecord.setTime(Instant.now()); + lootRecord.setDrops(Collections.singletonList(new GameItem(4151, 1))); + + String data = RuneLiteAPI.GSON.toJson(lootRecord); + mockMvc.perform(post("/loottracker").content(data).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + verify(lootTrackerService).store(eq(lootRecord), anyInt()); + } +} \ No newline at end of file From 38cdbfcb6b9dc24556c6db3cd5a68f132ba32369 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 17 Feb 2019 17:51:14 -0500 Subject: [PATCH 3/3] http service: use http-api gson instance --- .../net/runelite/http/service/SpringWebMvcConfigurer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java b/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java index 4402ea6e89..f0fd4ed99c 100644 --- a/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java +++ b/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java @@ -25,6 +25,7 @@ package net.runelite.http.service; import java.util.List; +import net.runelite.http.api.RuneLiteAPI; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; @@ -53,6 +54,8 @@ public class SpringWebMvcConfigurer extends WebMvcConfigurerAdapter @Override public void configureMessageConverters(List> converters) { - converters.add(new GsonHttpMessageConverter()); + GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); + gsonHttpMessageConverter.setGson(RuneLiteAPI.GSON); + converters.add(gsonHttpMessageConverter); } }