From aef2b083a2f1731463f0372b1abd4e8d7dad99d1 Mon Sep 17 00:00:00 2001 From: kwakeroni Date: Fri, 16 Nov 2018 09:13:20 +0100 Subject: [PATCH] Factored out Server support --- .../parameters-adapter-direct/pom.xml | 4 + ...irectBusinessParametersServiceFactory.java | 13 +- .../parameters-app-support/pom.xml | 107 +++++++++ .../app/support/SimpleRestServer.java | 105 +++++++++ .../parameters/app/support/StaticContent.java | 11 + .../app/support/StaticContentFactory.java | 66 ++++++ .../app/support/StaticContentResource.java} | 12 +- .../support/StaticContentResourceTest.java} | 15 +- .../parameters-standalone-app/pom.xml | 31 +-- .../kwakeroni/parameters/app/Application.java | 2 +- .../be/kwakeroni/parameters/app/Server.java | 143 ++++------- parameters-application/pom.xml | 1 + .../factory/BusinessParametersFactory.java | 6 +- .../parameters-client-rest/pom.xml | 7 +- .../rest/RestBusinessParametersClient.java | 3 + .../client/rest/factory/Config.java | 11 + .../RestBusinessParametersFactory.java | 52 ++++ ...ient.api.factory.BusinessParametersFactory | 1 + .../RestBusinessParametersClientTest.java | 7 + .../RestBusinessParametersFactoryTest.java | 135 +++++++++++ parameters-client/pom.xml | 5 + .../test/extension/ExtensionSupport.java | 1 + petshop/petshop-application/pom.xml | 151 ++++++++---- .../petshop/OldPetshopApplication.java | 165 +++++++++++++ .../petshop/PetshopApplication.java | 223 ++++++++---------- .../resources/business-parameters.properties | 1 - .../src/main/resources/petshop.properties | 2 + .../be/kwakeroni/scratch/env/Environment.java | 3 +- 28 files changed, 976 insertions(+), 307 deletions(-) create mode 100644 parameters-application/parameters-app-support/pom.xml create mode 100644 parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/SimpleRestServer.java create mode 100644 parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContent.java create mode 100644 parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentFactory.java rename parameters-application/{parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/StaticContent.java => parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentResource.java} (87%) rename parameters-application/{parameters-standalone-app/src/test/java/be/kwakeroni/parameters/app/StaticContentTest.java => parameters-app-support/src/test/java/be/kwakeroni/parameters/app/support/StaticContentResourceTest.java} (91%) create mode 100644 parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/Config.java create mode 100644 parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactory.java create mode 100644 parameters-client/parameters-client-rest/src/main/resources/META-INF/services/be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory create mode 100644 parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactoryTest.java create mode 100644 petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/OldPetshopApplication.java delete mode 100644 petshop/petshop-application/src/main/resources/business-parameters.properties create mode 100644 petshop/petshop-application/src/main/resources/petshop.properties diff --git a/parameters-adapter/parameters-adapter-direct/pom.xml b/parameters-adapter/parameters-adapter-direct/pom.xml index b66a7c3..dfdb987 100644 --- a/parameters-adapter/parameters-adapter-direct/pom.xml +++ b/parameters-adapter/parameters-adapter-direct/pom.xml @@ -58,6 +58,10 @@ be.kwakeroni.parameters.core parameters-core-support + + be.kwakeroni.parameters.core + parameters-core-support + org.slf4j slf4j-api diff --git a/parameters-adapter/parameters-adapter-direct/src/main/java/be/kwakeroni/parameters/adapter/direct/factory/DirectBusinessParametersServiceFactory.java b/parameters-adapter/parameters-adapter-direct/src/main/java/be/kwakeroni/parameters/adapter/direct/factory/DirectBusinessParametersServiceFactory.java index 3e65075..9176576 100644 --- a/parameters-adapter/parameters-adapter-direct/src/main/java/be/kwakeroni/parameters/adapter/direct/factory/DirectBusinessParametersServiceFactory.java +++ b/parameters-adapter/parameters-adapter-direct/src/main/java/be/kwakeroni/parameters/adapter/direct/factory/DirectBusinessParametersServiceFactory.java @@ -13,7 +13,12 @@ import be.kwakeroni.parameters.core.support.backend.DefaultBackendWireFormatterContext; import be.kwakeroni.parameters.core.support.client.DefaultClientWireFormatterContext; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; import java.util.function.Predicate; import static be.kwakeroni.parameters.core.support.service.BusinessParameterServices.loadServices; @@ -33,12 +38,12 @@ public void setBackendType(Predicate b } @Override - public BusinessParameters getInstance() { - return getWritableInstance(); + public BusinessParameters getInstance(Map properties) { + return getWritableInstance(properties); } @Override - public WritableBusinessParameters getWritableInstance() { + public WritableBusinessParameters getWritableInstance(Map properties) { DefaultClientWireFormatterContext clientRegistry = new DefaultClientWireFormatterContext(); loadServices(ClientWireFormatterFactory.class) diff --git a/parameters-application/parameters-app-support/pom.xml b/parameters-application/parameters-app-support/pom.xml new file mode 100644 index 0000000..64a2716 --- /dev/null +++ b/parameters-application/parameters-app-support/pom.xml @@ -0,0 +1,107 @@ + + + + parameters-application + be.kwakeroni.parameters.application + 0.1.0-SNAPSHOT + + 4.0.0 + + parameters-app-support + + + + + be.kwakeroni.parameters + parameters-deps + ${project.version} + pom + import + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + be.kwakeroni.parameters.core + parameters-core + ${project.version} + pom + import + + + + + + + org.slf4j + slf4j-api + + + + + + + + + + + + + + + + + + + + + com.sun.jersey + jersey-server + 1.19.1 + compile + + + be.kwakeroni.parameters.core + parameters-test-support + test + + + org.junit.jupiter + junit-jupiter-api + + + \ No newline at end of file diff --git a/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/SimpleRestServer.java b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/SimpleRestServer.java new file mode 100644 index 0000000..55984ef --- /dev/null +++ b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/SimpleRestServer.java @@ -0,0 +1,105 @@ +package be.kwakeroni.parameters.app.support; + +import com.sun.jersey.api.container.ContainerFactory; +import com.sun.jersey.api.container.httpserver.HttpServerFactory; +import com.sun.jersey.api.core.ApplicationAdapter; +import com.sun.jersey.api.core.ResourceConfig; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Application; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + + +public abstract class SimpleRestServer implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleRestServer.class); + + private HttpServer httpServer; + + protected abstract int getPort(); + + protected abstract String getContextPath(); + + protected abstract Collection getResources(); + + protected abstract String getHelloMessage(); + + protected synchronized void start() throws IOException { + if (this.httpServer != null) return; + + + String uri = String.format("http://127.0.0.1:%s/%s", + getPort(), + getContextPath()); + + LOG.info("Starting server at {}", uri); + + this.httpServer = HttpServerFactory.create(uri, + ContainerFactory.createContainer(HttpHandler.class, getResourceConfig(), null)); + + + this.httpServer.start(); + + LOG.info("Server ready at " + uri); + } + + protected synchronized void stop() { + if (this.httpServer != null) { + this.httpServer.stop(0); + this.httpServer = null; + } + } + + + @Override + public void close() { + this.stop(); + } + + + protected ResourceConfig getResourceConfig() { + Set resources = new HashSet<>(); + resources.add(getRootResource()); + resources.addAll(getResources()); + + Application application = new Application() { + @Override + public Set getSingletons() { + return resources; + } + }; + + ResourceConfig config = new ApplicationAdapter(application); + config.setPropertiesAndFeatures(Collections.singletonMap("com.sun.jersey.api.json.POJOMappingFeature", true)); + return config; + + } + + protected Object getRootResource() { + + + return new Root(); + } + + @Path("/") + public final class Root { + private Root() { + + } + + @GET + public String hello() { + return getHelloMessage(); + } + } + +} diff --git a/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContent.java b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContent.java new file mode 100644 index 0000000..f7b5cba --- /dev/null +++ b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContent.java @@ -0,0 +1,11 @@ +package be.kwakeroni.parameters.app.support; + +import java.nio.file.Path; + +public interface StaticContent { + + public Path getContentDirectory(); + + public String getIndexPage(); + +} diff --git a/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentFactory.java b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentFactory.java new file mode 100644 index 0000000..58a5ac1 --- /dev/null +++ b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentFactory.java @@ -0,0 +1,66 @@ +package be.kwakeroni.parameters.app.support; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Objects; +import java.util.function.Supplier; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class StaticContentFactory { + + private static final Logger LOG = LoggerFactory.getLogger(StaticContentFactory.class); + + private StaticContentFactory() { + + } + + public static StaticContent fromZip(Supplier zipFile, String indexFile, Path workDir) { + LOG.info("Buffering web application into {}", workDir); + + try { + Files.createDirectories(workDir); + unzip(zipFile, workDir); + } catch (IOException exc) { + throw new UncheckedIOException(exc); + } + + return new StaticContent() { + @Override + public Path getContentDirectory() { + return workDir; + } + + @Override + public String getIndexPage() { + return indexFile; + } + }; + } + + + private static void unzip(Supplier stream, java.nio.file.Path location) throws IOException { + + InputStream input = Objects.requireNonNull(stream.get(), "Could not obtain zip file"); + + try (ZipInputStream zipStream = new ZipInputStream(input)) { + for (ZipEntry entry = zipStream.getNextEntry(); entry != null; entry = zipStream.getNextEntry()) { + java.nio.file.Path dest = location.resolve(entry.getName()); + if (entry.isDirectory()) { + Files.createDirectories(dest); + } else { + Files.copy(zipStream, dest, StandardCopyOption.REPLACE_EXISTING); + } + } + zipStream.closeEntry(); + } + } + +} diff --git a/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/StaticContent.java b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentResource.java similarity index 87% rename from parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/StaticContent.java rename to parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentResource.java index cb2572a..8759f49 100644 --- a/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/StaticContent.java +++ b/parameters-application/parameters-app-support/src/main/java/be/kwakeroni/parameters/app/support/StaticContentResource.java @@ -1,4 +1,4 @@ -package be.kwakeroni.parameters.app; +package be.kwakeroni.parameters.app.support; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,14 +13,18 @@ import java.nio.file.Files; import java.util.Optional; -public abstract class StaticContent { +public abstract class StaticContentResource { - private static final Logger LOG = LoggerFactory.getLogger(StaticContent.class); + private static final Logger LOG = LoggerFactory.getLogger(StaticContentResource.class); private final java.nio.file.Path contentDirectory; private final String indexPage; - StaticContent(java.nio.file.Path contentDirectory, String indexPage) { + protected StaticContentResource(StaticContent content) { + this(content.getContentDirectory(), content.getIndexPage()); + } + + protected StaticContentResource(java.nio.file.Path contentDirectory, String indexPage) { this.contentDirectory = contentDirectory.toAbsolutePath().normalize(); this.indexPage = indexPage; } diff --git a/parameters-application/parameters-standalone-app/src/test/java/be/kwakeroni/parameters/app/StaticContentTest.java b/parameters-application/parameters-app-support/src/test/java/be/kwakeroni/parameters/app/support/StaticContentResourceTest.java similarity index 91% rename from parameters-application/parameters-standalone-app/src/test/java/be/kwakeroni/parameters/app/StaticContentTest.java rename to parameters-application/parameters-app-support/src/test/java/be/kwakeroni/parameters/app/support/StaticContentResourceTest.java index 3d9c848..f914be0 100644 --- a/parameters-application/parameters-standalone-app/src/test/java/be/kwakeroni/parameters/app/StaticContentTest.java +++ b/parameters-application/parameters-app-support/src/test/java/be/kwakeroni/parameters/app/support/StaticContentResourceTest.java @@ -1,5 +1,6 @@ -package be.kwakeroni.parameters.app; +package be.kwakeroni.parameters.app.support; +import be.kwakeroni.test.extension.TemporaryFolderExtension; import com.sun.jersey.api.container.ContainerFactory; import com.sun.jersey.api.container.httpserver.HttpServerFactory; import com.sun.jersey.api.core.ApplicationAdapter; @@ -11,6 +12,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.junit.rules.TemporaryFolder; import javax.ws.rs.Path; @@ -29,7 +31,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -public class StaticContentTest { +@ExtendWith(TemporaryFolderExtension.class) +public class StaticContentResourceTest { private static final String CONTEXT_PATH = "/content"; private static final String INDEX_PAGE = "index.test"; @@ -50,8 +53,8 @@ public class StaticContentTest { private static Function getFileContents = mock(Function.class); @Path(CONTEXT_PATH) - public static class TestStaticContent extends StaticContent { - private TestStaticContent(java.nio.file.Path contentDirectory) { + public static class TestStaticContentResource extends StaticContentResource { + private TestStaticContentResource(java.nio.file.Path contentDirectory) { super(contentDirectory, INDEX_PAGE); } @@ -83,7 +86,7 @@ static void setUpRestService() throws Exception { ResourceConfig config = new ApplicationAdapter(new Application() { @Override public Set getSingletons() { - return Collections.singleton(new TestStaticContent(contentDirectory.getRoot().toPath())); + return Collections.singleton(new TestStaticContentResource(contentDirectory.getRoot().toPath())); } }); config.setPropertiesAndFeatures(Collections.singletonMap("com.sun.jersey.api.json.POJOMappingFeature", true)); @@ -169,6 +172,6 @@ void testServerError() { } private static InputStream getImage() { - return StaticContentTest.class.getResourceAsStream("test.jpg"); + return StaticContentResourceTest.class.getResourceAsStream("test.jpg"); } } diff --git a/parameters-application/parameters-standalone-app/pom.xml b/parameters-application/parameters-standalone-app/pom.xml index 1969ed5..824ca55 100644 --- a/parameters-application/parameters-standalone-app/pom.xml +++ b/parameters-application/parameters-standalone-app/pom.xml @@ -66,6 +66,11 @@ + + be.kwakeroni.parameters.application + parameters-app-support + ${project.version} + be.kwakeroni.parameters.core parameters-core-support @@ -122,24 +127,6 @@ 20160810 runtime - - com.sun.jersey - jersey-client - 1.19.1 - runtime - - - com.sun.jersey - jersey-json - 1.19.1 - runtime - - - com.sun.jersey - jersey-servlet - 1.19.1 - compile - commons-cli commons-cli @@ -183,7 +170,9 @@ copy-webapp - copy + + copy + process-resources @@ -198,7 +187,9 @@ unpack-test-webapp - unpack + + unpack + process-test-resources diff --git a/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Application.java b/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Application.java index 2a0d42d..5ef0ac1 100644 --- a/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Application.java +++ b/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Application.java @@ -39,7 +39,7 @@ public static void main(String[] args) throws Exception { private static void initLogging() { System.out.println("log4j.configuration=" + System.getProperty("log4j.configuration")); if (System.getProperty("log4j.configuration") == null) { - if (Thread.currentThread().getContextClassLoader().getResource("log4j.properties") == null){ + if (Thread.currentThread().getContextClassLoader().getResource("log4j.properties") == null) { System.setProperty("log4j.configuration", "log4j.fallback.properties"); } } diff --git a/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Server.java b/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Server.java index 8ac0dc8..fa7c24e 100644 --- a/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Server.java +++ b/parameters-application/parameters-standalone-app/src/main/java/be/kwakeroni/parameters/app/Server.java @@ -2,51 +2,34 @@ import be.kwakeroni.parameters.adapter.rest.RestBackendAdapter; import be.kwakeroni.parameters.adapter.rest.factory.RestBackendAdapterFactory; +import be.kwakeroni.parameters.app.support.SimpleRestServer; +import be.kwakeroni.parameters.app.support.StaticContent; +import be.kwakeroni.parameters.app.support.StaticContentFactory; +import be.kwakeroni.parameters.app.support.StaticContentResource; import be.kwakeroni.parameters.backend.api.Configuration; import be.kwakeroni.parameters.backend.api.ConfigurationProvider; import be.kwakeroni.parameters.management.rest.RestParameterManagement; import be.kwakeroni.parameters.management.rest.factory.RestParameterManagementFactory; -import com.sun.jersey.api.container.ContainerFactory; -import com.sun.jersey.api.container.httpserver.HttpServerFactory; -import com.sun.jersey.api.core.ApplicationAdapter; -import com.sun.jersey.api.core.ResourceConfig; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.GET; + import javax.ws.rs.Path; -import javax.ws.rs.core.Application; import java.io.IOException; import java.io.InputStream; -import java.nio.file.Files; import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; +import java.util.Collection; import java.util.Iterator; import java.util.ServiceLoader; -import java.util.Set; -import java.util.function.Supplier; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; import static be.kwakeroni.parameters.app.Config.*; -class Server implements AutoCloseable { +class Server extends SimpleRestServer { @SuppressWarnings("WeakerAccess") public static final int DEFAULT_PORT = 8080; @SuppressWarnings("WeakerAccess") public static final String DEFAULT_CONTEXT_PATH = "parameters"; - private static final Logger LOG = LoggerFactory.getLogger(Server.class); - private final Configuration configuration; - private java.nio.file.Path webappDir; - private HttpServer httpServer; Server() { this(loadConfiguration()); @@ -68,99 +51,65 @@ Configuration getConfiguration() { return configuration; } - synchronized void start() throws IOException { - if (this.httpServer != null) return; - - - String uri = String.format("http://127.0.0.1:%s/%s", - this.configuration.get(PORT).orElse(DEFAULT_PORT), - this.configuration.get(CONTEXT_PATH).orElse(DEFAULT_CONTEXT_PATH)); - - LOG.info("Starting server at {}", uri); - - this.webappDir = configuration.get(WORK_DIRECTORY) - .orElseGet(() -> Paths.get("./work")) - .resolve("webapp"); - - prepareWebApp(); - - - - this.httpServer = HttpServerFactory.create(uri, - ContainerFactory.createContainer(HttpHandler.class, getResourceConfig(), null)); - - - this.httpServer.start(); - - LOG.info("Server ready"); + @Override + protected int getPort() { + return this.configuration.get(PORT).orElse(DEFAULT_PORT); } - synchronized void stop() { - if (this.httpServer != null) { - this.httpServer.stop(0); - this.httpServer = null; - } + @Override + protected String getContextPath() { + return this.configuration.get(CONTEXT_PATH).orElse(DEFAULT_CONTEXT_PATH); } @Override - public void close() { - this.stop(); + protected String getHelloMessage() { + return "Business Parameters"; } - private void prepareWebApp() throws IOException { - LOG.info("Buffering web application into {}", this.webappDir); + @Override + protected Collection getResources() { + StaticContentResource webContent = getWebManagement(); + RestBackendAdapter restBackend = new RestBackendAdapterFactory().newInstance(); + RestParameterManagement restManagement = new RestParameterManagementFactory().newInstance(); - Files.createDirectories(this.webappDir); - unzip(() -> Server.class.getResourceAsStream("/parameters-management-web.jar"), this.webappDir); + return Arrays.asList(restBackend, restManagement, webContent); } - private static void unzip(Supplier stream, java.nio.file.Path location) throws IOException { - try (ZipInputStream zipStream = new ZipInputStream(stream.get())) { - for (ZipEntry entry = zipStream.getNextEntry(); entry != null; entry = zipStream.getNextEntry()) { - java.nio.file.Path dest = location.resolve(entry.getName()); - if (entry.isDirectory()) { - Files.createDirectories(dest); - } else { - Files.copy(zipStream, dest, StandardCopyOption.REPLACE_EXISTING); - } + private StaticContentResource getWebManagement() { + + @Path("/web") + class WebManagement extends StaticContentResource { + private WebManagement() { + super(getManagementWebContent()); } - zipStream.closeEntry(); } + + return new WebManagement(); + } - private ResourceConfig getResourceConfig() { + private StaticContent getManagementWebContent() { + return StaticContentFactory.fromZip(this::getManagementWebZip, "index.html", getWebappDir()); + } - Root root = new Root(); - RestBackendAdapter restBackend = new RestBackendAdapterFactory().newInstance(); - RestParameterManagement restManagement = new RestParameterManagementFactory().newInstance(); - @Path("/web") - class WebManagement extends StaticContent { - private WebManagement() { - super(webappDir, "index.html"); - } - } - StaticContent webManagement = new WebManagement(); + private java.nio.file.Path getWebappDir() { + return configuration.get(WORK_DIRECTORY) + .orElseGet(() -> Paths.get("./work")) + .resolve("webapp"); + } - ResourceConfig config = new ApplicationAdapter(ofSingletons(root, restBackend, restManagement, webManagement)); - config.setPropertiesAndFeatures(Collections.singletonMap("com.sun.jersey.api.json.POJOMappingFeature", true)); - return config; + private InputStream getManagementWebZip() { + return Server.class.getResourceAsStream("/parameters-management-web.jar"); } - @Path("/") - public static final class Root { - @GET - public String hello() { - return "Business Parameters"; - } + @Override + protected synchronized void start() throws IOException { + super.start(); } - private static Application ofSingletons(Object... singletons) { - return new Application() { - @Override - public Set getSingletons() { - return new HashSet<>(Arrays.asList(singletons)); - } - }; + @Override + protected synchronized void stop() { + super.stop(); } } diff --git a/parameters-application/pom.xml b/parameters-application/pom.xml index 3ddd629..dfd31eb 100644 --- a/parameters-application/pom.xml +++ b/parameters-application/pom.xml @@ -14,5 +14,6 @@ pom parameters-standalone-app + parameters-app-support \ No newline at end of file diff --git a/parameters-client/parameters-client-api/src/main/java/be/kwakeroni/parameters/client/api/factory/BusinessParametersFactory.java b/parameters-client/parameters-client-api/src/main/java/be/kwakeroni/parameters/client/api/factory/BusinessParametersFactory.java index f584332..72735d6 100644 --- a/parameters-client/parameters-client-api/src/main/java/be/kwakeroni/parameters/client/api/factory/BusinessParametersFactory.java +++ b/parameters-client/parameters-client-api/src/main/java/be/kwakeroni/parameters/client/api/factory/BusinessParametersFactory.java @@ -3,13 +3,15 @@ import be.kwakeroni.parameters.client.api.BusinessParameters; import be.kwakeroni.parameters.client.api.WritableBusinessParameters; +import java.util.Map; + /** * (C) 2016 Maarten Van Puymbroeck */ public interface BusinessParametersFactory { - public BusinessParameters getInstance(); + public BusinessParameters getInstance(Map properties); - public WritableBusinessParameters getWritableInstance(); + public WritableBusinessParameters getWritableInstance(Map properties); } diff --git a/parameters-client/parameters-client-rest/pom.xml b/parameters-client/parameters-client-rest/pom.xml index cddb254..8ac7c86 100644 --- a/parameters-client/parameters-client-rest/pom.xml +++ b/parameters-client/parameters-client-rest/pom.xml @@ -12,7 +12,8 @@ parameters-client-rest bundle - Provides the BusinessParameters API implemented by calling a BusinessParameters REST Adapter. + Provides the BusinessParameters API implemented by calling a BusinessParameters REST Adapter. + @@ -38,6 +39,10 @@ be.kwakeroni.parameters.client parameters-client-api + + be.kwakeroni.parameters.core + parameters-core-support + be.kwakeroni.parameters.core parameters-test-support diff --git a/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClient.java b/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClient.java index 67ee3e5..5717fba 100644 --- a/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClient.java +++ b/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClient.java @@ -85,6 +85,9 @@ private String externalize(Query query) { if (external == null) { throw new IllegalArgumentException("Wireformat produced null for " + query); } + if (external instanceof JSONObject) { + external = ((JSONObject) external).toString(); + } if (!(external instanceof String)) { throw new IllegalArgumentException("Wireformat produced " + external.getClass().getName() + " instead of String for " + query); } diff --git a/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/Config.java b/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/Config.java new file mode 100644 index 0000000..a04ea53 --- /dev/null +++ b/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/Config.java @@ -0,0 +1,11 @@ +package be.kwakeroni.parameters.client.rest.factory; + +@SuppressWarnings("WeakerAccess") +public final class Config { + + public static final String REST_URL = "parameters.rest.url"; + + private Config() { + } +} + diff --git a/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactory.java b/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactory.java new file mode 100644 index 0000000..2d2dfe7 --- /dev/null +++ b/parameters-client/parameters-client-rest/src/main/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactory.java @@ -0,0 +1,52 @@ +package be.kwakeroni.parameters.client.rest.factory; + +import be.kwakeroni.parameters.client.api.BusinessParameters; +import be.kwakeroni.parameters.client.api.WritableBusinessParameters; +import be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory; +import be.kwakeroni.parameters.client.api.factory.ClientWireFormatterFactory; +import be.kwakeroni.parameters.client.api.query.ClientWireFormatterContext; +import be.kwakeroni.parameters.client.rest.RestBusinessParametersClient; +import be.kwakeroni.parameters.core.support.client.DefaultClientWireFormatterContext; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static be.kwakeroni.parameters.core.support.service.BusinessParameterServices.loadServices; + +public class RestBusinessParametersFactory implements BusinessParametersFactory { + + public static final Set SUPPORTED_WIREFORMATS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("json"))); + + @Override + public BusinessParameters getInstance(Map properties) { + return getWritableInstance(properties); + } + + @Override + public WritableBusinessParameters getWritableInstance(Map properties) { + return createClient(getUrl(properties), createWireFormatterContext()); + } + + RestBusinessParametersClient createClient(String url, ClientWireFormatterContext context) { + return new RestBusinessParametersClient(url, context); + } + + private ClientWireFormatterContext createWireFormatterContext() { + DefaultClientWireFormatterContext clientRegistry = new DefaultClientWireFormatterContext(); + loadServices(ClientWireFormatterFactory.class) + .filter(factory -> SUPPORTED_WIREFORMATS.contains(factory.getWireFormat())) + .forEach(clientRegistry::register); + return clientRegistry; + } + + private String getUrl(Map properties) { + String url = properties.get(Config.REST_URL); + if (url == null) { + throw new IllegalStateException("Missing configuration property: " + Config.REST_URL); + } + return url; + } +} diff --git a/parameters-client/parameters-client-rest/src/main/resources/META-INF/services/be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory b/parameters-client/parameters-client-rest/src/main/resources/META-INF/services/be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory new file mode 100644 index 0000000..19fac53 --- /dev/null +++ b/parameters-client/parameters-client-rest/src/main/resources/META-INF/services/be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory @@ -0,0 +1 @@ +be.kwakeroni.parameters.client.rest.factory.RestBusinessParametersFactory \ No newline at end of file diff --git a/parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClientTest.java b/parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClientTest.java index aa6e528..093c2f9 100644 --- a/parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClientTest.java +++ b/parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/RestBusinessParametersClientTest.java @@ -5,6 +5,7 @@ import be.kwakeroni.parameters.client.api.model.ParameterGroup; import be.kwakeroni.parameters.client.api.query.ClientWireFormatterContext; import be.kwakeroni.parameters.client.api.query.Query; +import be.kwakeroni.test.extension.TemporaryFolderExtension; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import org.junit.jupiter.api.AfterAll; @@ -18,6 +19,7 @@ import org.junit.jupiter.extension.mockito.MockitoExtension; import org.mockito.Mock; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -30,6 +32,7 @@ import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) +@ExtendWith(TemporaryFolderExtension.class) class RestBusinessParametersClientTest { static Runnable resetWireMock; @@ -47,6 +50,8 @@ class RestBusinessParametersClientTest { ParameterGroup group; @Mock Query query; + @TemporaryFolderExtension.TemporaryFolder + Path path; @BeforeAll static void setupClass() { @@ -77,6 +82,8 @@ class GetTest { @Test @DisplayName("to a REST endpoint") void testSendQuery() { + System.out.println(path); + stubFor(post(urlMatching(".*")).willReturn(ok())); when(group.getName()).thenReturn("myGroup"); diff --git a/parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactoryTest.java b/parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactoryTest.java new file mode 100644 index 0000000..b5b927a --- /dev/null +++ b/parameters-client/parameters-client-rest/src/test/java/be/kwakeroni/parameters/client/rest/factory/RestBusinessParametersFactoryTest.java @@ -0,0 +1,135 @@ +package be.kwakeroni.parameters.client.rest.factory; + +import be.kwakeroni.parameters.client.api.BusinessParameters; +import be.kwakeroni.parameters.client.api.WritableBusinessParameters; +import be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory; +import be.kwakeroni.parameters.client.api.factory.ClientWireFormatterFactory; +import be.kwakeroni.parameters.client.api.query.ClientWireFormatter; +import be.kwakeroni.parameters.client.api.query.ClientWireFormatterContext; +import be.kwakeroni.parameters.client.rest.RestBusinessParametersClient; +import be.kwakeroni.test.extension.ContextClassLoaderExtension; +import be.kwakeroni.test.extension.ContextClassLoaderExtension.AddToClasspath; +import be.kwakeroni.test.extension.TemporaryFolderExtension; +import be.kwakeroni.test.extension.TemporaryFolderExtension.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.extension.mockito.MockitoExtension; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.function.BiConsumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@ExtendWith(TemporaryFolderExtension.class) +@ExtendWith(ContextClassLoaderExtension.class) +class RestBusinessParametersFactoryTest { + + private static final String URL = "testurl"; + private static final Map PROPERTIES = Collections.singletonMap("parameters.rest.url", URL); + + @Mock + BiConsumer clientConstructor; + @Captor + ArgumentCaptor url; + @Captor + ArgumentCaptor context; + @TemporaryFolder + @AddToClasspath + Path temporaryClasspath; + + RestBusinessParametersFactory factory = new RestBusinessParametersFactory() { + @Override + RestBusinessParametersClient createClient(String url, ClientWireFormatterContext context) { + clientConstructor.accept(url, context); + return super.createClient(url, context); + } + }; + + @Test + void isExposedAsAService() { + Iterator iterator = ServiceLoader.load(BusinessParametersFactory.class).iterator(); + + assertThat(iterator.hasNext()).isTrue(); + assertThat(iterator.next()).isInstanceOf(RestBusinessParametersFactory.class); + assertThat(iterator.hasNext()).isFalse(); + } + + @Test + void getInstance() { + BusinessParameters parameters = factory.getInstance(PROPERTIES); + assertThat(parameters) + .isNotNull() + .isInstanceOf(RestBusinessParametersClient.class); + } + + @Test + void getWritableInstance() { + WritableBusinessParameters parameters = factory.getWritableInstance(PROPERTIES); + assertThat(parameters) + .isNotNull() + .isInstanceOf(RestBusinessParametersClient.class); + } + + @Test + void getsUrlFromProperties() { + BusinessParameters parameters = factory.getInstance(PROPERTIES); + verify(clientConstructor).accept(url.capture(), any()); + + assertThat(url.getValue()).isEqualTo(URL); + } + + @Test + void loadsClientWireFormatters() { + registerService(ClientWireFormatterFactory.class, TestClientWireFormatterFactory.class); + + BusinessParameters parameters = factory.getInstance(PROPERTIES); + verify(clientConstructor).accept(any(), context.capture()); + + assertThat(context.getValue()).isNotNull(); + + TestClientWireFormatter formatter = context.getValue().getWireFormatter(TestClientWireFormatter.class); + assertThat(formatter).isSameAs(TestClientWireFormatterFactory.FORMATTER); + } + + public static interface TestClientWireFormatter extends ClientWireFormatter { + + } + + public static class TestClientWireFormatterFactory implements ClientWireFormatterFactory { + + static final TestClientWireFormatter FORMATTER = mock(TestClientWireFormatter.class); + + @Override + public String getWireFormat() { + return "json"; + } + + @Override + public void visitInstances(Visitor visitor) { + visitor.visit(TestClientWireFormatter.class, FORMATTER); + } + } + + private void registerService(Class serviceClass, Class implementationClass) { + Path servicesDir = temporaryClasspath.resolve("META-INF/services"); + try { + Files.createDirectories(servicesDir); + Files.write(servicesDir.resolve(serviceClass.getName()), Collections.singleton(implementationClass.getName())); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + +} \ No newline at end of file diff --git a/parameters-client/pom.xml b/parameters-client/pom.xml index 73fddc9..c8c3fff 100644 --- a/parameters-client/pom.xml +++ b/parameters-client/pom.xml @@ -28,6 +28,11 @@ ${project.groupId} ${project.version} + + parameters-client-rest + ${project.groupId} + ${project.version} + diff --git a/parameters-core/parameters-test-support/src/main/java/be/kwakeroni/test/extension/ExtensionSupport.java b/parameters-core/parameters-test-support/src/main/java/be/kwakeroni/test/extension/ExtensionSupport.java index 349bc62..cd420f8 100644 --- a/parameters-core/parameters-test-support/src/main/java/be/kwakeroni/test/extension/ExtensionSupport.java +++ b/parameters-core/parameters-test-support/src/main/java/be/kwakeroni/test/extension/ExtensionSupport.java @@ -83,6 +83,7 @@ private Stream concatWithParents(S seed, Function> stream protected static void setField(Field field, Object instance, Object value) { try { + field.setAccessible(true); field.set(instance, value); } catch (IllegalAccessException e) { throw new IllegalStateException(e); diff --git a/petshop/petshop-application/pom.xml b/petshop/petshop-application/pom.xml index 03bf4b3..e349f13 100644 --- a/petshop/petshop-application/pom.xml +++ b/petshop/petshop-application/pom.xml @@ -48,6 +48,13 @@ pom import + + be.kwakeroni.parameters.basic + parameters-basic-common + ${project.version} + pom + import + be.kwakeroni.parameters.client parameters-client @@ -55,49 +62,80 @@ pom import + + be.kwakeroni.parameters.definition + parameters-definition + ${project.version} + pom + import + + + be.kwakeroni.parameters.core + parameters-core + ${project.version} + pom + import + + + + + + + + + - be.kwakeroni.parameters.management - parameters-management-rest - - - be.kwakeroni.parameters.adapter - parameters-adapter-direct - - - be.kwakeroni.parameters.adapter - parameters-adapter-rest + be.kwakeroni.parameters.client + parameters-client-rest + + + + + + + + + + + + + + + + - be.kwakeroni.parameters.backend - parameters-backend-inmemory + be.kwakeroni.parameters.client + parameters-client-api be.kwakeroni.parameters.basic - parameters-basic-backend + parameters-basic-client - be.kwakeroni.parameters.basic - parameters-basic-common + be.kwakeroni.parameters.definition + parameters-definition-api be.kwakeroni.parameters.basic - parameters-basic-inmemory + parameters-basic-common - be.kwakeroni.parameters.client - parameters-client-api + be.kwakeroni.parameters.core + parameters-core-support be.kwakeroni.parameters.basic - parameters-basic-client + parameters-basic-wireformat-json - be.kwakeroni.parameters.basic - parameters-basic-wireformat-raw + be.kwakeroni.parameters.application + parameters-standalone-app + 0.1.0-SNAPSHOT javax.ws.rs @@ -167,7 +205,7 @@ - be.kwakeroni.parameters.petshop.PetshopApplication + be.kwakeroni.parameters.petshop.OldPetshopApplication @@ -200,42 +238,59 @@ maven-dependency-plugin 3.0.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - unpack-parameters-management-web - process-sources - - unpack - - - - - be.kwakeroni.parameters.management - parameters-management-web - ${project.version} - jar - false - - - ${project.build.outputDirectory}/parameters-webapp - - - - unpack-petshop-web - process-sources + copy-webapp - unpack + copy + process-resources be.kwakeroni.parameters.petshop petshop-web - ${project.version} - jar - false - ${project.build.outputDirectory}/petshop-webapp + ${project.build.outputDirectory} + true diff --git a/petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/OldPetshopApplication.java b/petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/OldPetshopApplication.java new file mode 100644 index 0000000..510c13c --- /dev/null +++ b/petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/OldPetshopApplication.java @@ -0,0 +1,165 @@ +package be.kwakeroni.parameters.petshop; + +import be.kwakeroni.parameters.client.api.BusinessParameters; +import be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory; +import be.kwakeroni.parameters.petshop.rest.PetshopRestService; +import be.kwakeroni.parameters.petshop.service.AnimalCatalog; +import be.kwakeroni.parameters.petshop.service.ContactService; +import be.kwakeroni.parameters.petshop.service.PriceCalculator; +import com.sun.jersey.api.container.ContainerFactory; +import com.sun.jersey.api.container.httpserver.HttpServerFactory; +import com.sun.jersey.api.core.ApplicationAdapter; +import com.sun.jersey.api.core.ResourceConfig; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Created by kwakeroni on 07/11/17. + */ +public class OldPetshopApplication { + + + private OldPetshopApplication() { + } + + private static PetshopRestService createPetshopRestService(Map properties) { + BusinessParameters parameters = createBusinessParameters(properties); + return new PetshopRestService( + new AnimalCatalog(parameters), + new PriceCalculator(parameters), + new ContactService(parameters)); + } + + public static void main(String[] args) throws Exception { + Properties properties = new Properties(); + properties.load(OldPetshopApplication.class.getResourceAsStream("/petshop.properties")); + Map propertyMap = properties.stringPropertyNames().stream().collect(Collectors.toMap(Function.identity(), properties::getProperty)); + + try ( + Server petshop = new Server(8081, "/", + createPetshopRestService(propertyMap), + new PetshopWebAppService() + ); + ) { + petshop.start(); + System.out.println("Enter 'q' to stop server."); + boolean running = true; + while (running) { + if ('q' == System.in.read()) { + running = false; + } + } + } + + } + + private static class Server implements AutoCloseable { + + private HttpServer server; + + public Server(int port, String root, Object... resources) throws IOException { + ResourceConfig config = new ApplicationAdapter(ofSingletons(resources)); + config.setPropertiesAndFeatures(Collections.singletonMap("com.sun.jersey.api.json.POJOMappingFeature", true)); + + this.server = HttpServerFactory.create("http://127.0.0.1:" + port + root, + ContainerFactory.createContainer(HttpHandler.class, config, null)); + } + + public void start() { + this.server.start(); + } + + @Override + public void close() throws Exception { + if (this.server != null) this.server.stop(0); + + } + } + + private static BusinessParameters createBusinessParameters(Map properties) { + return ServiceLoader.load(BusinessParametersFactory.class).iterator().next() + .getInstance(properties); + } + + private static Application ofSingletons(Object... singletons) { + return new Application() { + @Override + public Set getSingletons() { + return new HashSet<>(Arrays.asList(singletons)); + } + }; + } + + + public static abstract class AbstractWebAppService { + + private final String resourcePath; + private final String indexPage; + + public AbstractWebAppService(String resourcePath, String indexPage) { + this.resourcePath = resourcePath; + this.indexPage = indexPage; + } + + @GET + @Path("/") + public Response root() throws Exception { + return Response.seeOther(new URI(indexPage)).build(); + } + + @GET + @Path("{path:.*}") + public Response get(@PathParam("path") String path) throws Exception { + if (path == null || path.isEmpty() || "/".equals(path)) { + path = "index.html"; + } + + String webPath = resourcePath + "/" + path; + URL resource = OldPetshopApplication.class.getResource(webPath); + + if (resource != null) { + File file = new File(resource.toURI()); + + return Response.ok(file) + // .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional + .build(); + } else { + System.out.println("Resource not found: " + webPath); + return Response.status(404).build(); + } + } + } + + @Path("/petshop") + public static class PetshopWebAppService extends AbstractWebAppService { + public PetshopWebAppService() { + super("/petshop-webapp", "petshop/index.html"); + } + } + + @Path("/web") + public static class ParametersWebAppService extends AbstractWebAppService { + public ParametersWebAppService() { + super("/parameters-webapp", "web/index.html"); + } + } +} diff --git a/petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/PetshopApplication.java b/petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/PetshopApplication.java index 1b9270f..b8456d5 100644 --- a/petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/PetshopApplication.java +++ b/petshop/petshop-application/src/main/java/be/kwakeroni/parameters/petshop/PetshopApplication.java @@ -1,177 +1,156 @@ package be.kwakeroni.parameters.petshop; -import be.kwakeroni.parameters.adapter.rest.RestBackendAdapter; -import be.kwakeroni.parameters.adapter.rest.factory.RestBackendAdapterFactory; +import be.kwakeroni.parameters.app.support.SimpleRestServer; +import be.kwakeroni.parameters.app.support.StaticContent; +import be.kwakeroni.parameters.app.support.StaticContentFactory; +import be.kwakeroni.parameters.app.support.StaticContentResource; import be.kwakeroni.parameters.client.api.BusinessParameters; import be.kwakeroni.parameters.client.api.factory.BusinessParametersFactory; -import be.kwakeroni.parameters.management.rest.RestParameterManagement; -import be.kwakeroni.parameters.management.rest.factory.RestParameterManagementFactory; import be.kwakeroni.parameters.petshop.rest.PetshopRestService; import be.kwakeroni.parameters.petshop.service.AnimalCatalog; import be.kwakeroni.parameters.petshop.service.ContactService; import be.kwakeroni.parameters.petshop.service.PriceCalculator; -import com.sun.jersey.api.container.ContainerFactory; -import com.sun.jersey.api.container.httpserver.HttpServerFactory; -import com.sun.jersey.api.core.ApplicationAdapter; -import com.sun.jersey.api.core.ResourceConfig; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; - -import javax.ws.rs.GET; + import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Application; -import javax.ws.rs.core.Response; -import java.io.File; import java.io.IOException; -import java.net.URI; -import java.net.URL; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.file.Paths; import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; import java.util.ServiceLoader; -import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; -/** - * Created by kwakeroni on 07/11/17. - */ public class PetshopApplication { - public PetshopApplication() { + @SuppressWarnings("WeakerAccess") + public static final int DEFAULT_PORT = 8081; + @SuppressWarnings("WeakerAccess") + public static final String DEFAULT_CONTEXT_PATH = ""; + + public static void main(String[] args) throws Exception { + initLogging(); + + createServer(args) + .ifPresent(PetshopApplication::start); } - private static PetshopRestService createPetshopRestService() { - BusinessParameters parameters = createBusinessParameters(); - return new PetshopRestService( - new AnimalCatalog(parameters), - new PriceCalculator(parameters), - new ContactService(parameters)); + private static void initLogging() { + System.out.println("log4j.configuration=" + System.getProperty("log4j.configuration")); + if (System.getProperty("log4j.configuration") == null) { + if (Thread.currentThread().getContextClassLoader().getResource("log4j.properties") == null) { + System.setProperty("log4j.configuration", "log4j.fallback.properties"); + } + } } - public static void main(String[] args) throws Exception { - try ( - Server parameters = new Server(8080, "/parameters", - createAdapter(), - createManagement(), - new ParametersWebAppService() - ); - Server petshop = new Server(8081, "/", - createPetshopRestService(), - new PetshopWebAppService() - ); - ) { - parameters.start(); - petshop.start(); - System.out.println("Enter 'q' to stop server."); - boolean running = true; - while (running) { - if ('q' == System.in.read()) { - running = false; - } + private static void start(Server resource) { + try (Server server = resource) { + server.start(); + + while (true) { + // Thread.onSpinWait(); } + + } catch (IOException exc) { + throw new UncheckedIOException(exc); } + } + + + static Optional createServer(String[] args) throws IOException { + Properties properties = new Properties(); + properties.load(OldPetshopApplication.class.getResourceAsStream("/petshop.properties")); + Map propertyMap = properties.stringPropertyNames().stream().collect(Collectors.toMap(Function.identity(), properties::getProperty)); + return Optional.of(new Server(propertyMap)); } - private static class Server implements AutoCloseable { - private HttpServer server; + private static class Server extends SimpleRestServer { - public Server(int port, String root, Object... resources) throws IOException { - ResourceConfig config = new ApplicationAdapter(ofSingletons(resources)); - config.setPropertiesAndFeatures(Collections.singletonMap("com.sun.jersey.api.json.POJOMappingFeature", true)); + private final Map properties; - this.server = HttpServerFactory.create("http://127.0.0.1:" + port + root, - ContainerFactory.createContainer(HttpHandler.class, config, null)); + public Server(Map properties) { + this.properties = properties; } - public void start() { - this.server.start(); + @Override + protected int getPort() { + return DEFAULT_PORT; } @Override - public void close() throws Exception { - if (this.server != null) this.server.stop(0); + protected String getContextPath() { + return DEFAULT_CONTEXT_PATH; + } + @Override + protected String getHelloMessage() { + return "Business Parameters Petshop"; } - } + @Override + protected Collection getResources() { + StaticContentResource webApp = getWebApp(); + PetshopRestService restService = createPetshopRestService(properties); + return Arrays.asList(restService, webApp); + } - private static RestBackendAdapter createAdapter() { - RestBackendAdapterFactory factory = new RestBackendAdapterFactory(); - return factory.newInstance(); - } - private static RestParameterManagement createManagement() { - RestParameterManagementFactory factory = new RestParameterManagementFactory(); - return factory.newInstance(); - } + private PetshopRestService createPetshopRestService(Map properties) { + BusinessParameters parameters = createBusinessParameters(properties); + return new PetshopRestService( + new AnimalCatalog(parameters), + new PriceCalculator(parameters), + new ContactService(parameters)); + } - private static BusinessParameters createBusinessParameters() { - return ServiceLoader.load(BusinessParametersFactory.class).iterator().next().getInstance(); - } + private BusinessParameters createBusinessParameters(Map properties) { + return ServiceLoader.load(BusinessParametersFactory.class).iterator().next().getInstance(properties); + } - private static Application ofSingletons(Object... singletons) { - return new Application() { - @Override - public Set getSingletons() { - return new HashSet<>(Arrays.asList(singletons)); + private StaticContentResource getWebApp() { + @Path("/petshop") + class PetshopWebApp extends StaticContentResource { + public PetshopWebApp() { + super(getWebContent()); + } } - }; - } - - public static abstract class AbstractWebAppService { - private final String resourcePath; - private final String indexPage; - - public AbstractWebAppService(String resourcePath, String indexPage) { - this.resourcePath = resourcePath; - this.indexPage = indexPage; + return new PetshopWebApp(); } - @GET - @Path("/") - public Response root() throws Exception { - return Response.seeOther(new URI(indexPage)).build(); + private StaticContent getWebContent() { + return StaticContentFactory.fromZip(this::getManagementWebZip, "petshop/index.html", getWebappDir()); } - @GET - @Path("{path:.*}") - public Response get(@PathParam("path") String path) throws Exception { - if (path == null || path.isEmpty() || "/".equals(path)) { - path = "index.html"; - } - - String webPath = resourcePath + "/" + path; - URL resource = PetshopApplication.class.getResource(webPath); - - if (resource != null) { - File file = new File(resource.toURI()); + private java.nio.file.Path getWebappDir() { + return Optional.ofNullable(properties.get("server.workDir")) + .map(Paths::get) + .orElseGet(() -> Paths.get("./work")) + .resolve("petshop"); + } - return Response.ok(file) - // .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional - .build(); - } else { - System.out.println("Resource not found: " + webPath); - return Response.status(404).build(); - } + private InputStream getManagementWebZip() { + return PetshopApplication.class.getResourceAsStream("/petshop-web.jar"); } - } - @Path("/petshop") - public static class PetshopWebAppService extends AbstractWebAppService { - public PetshopWebAppService() { - super("/petshop-webapp", "petshop/index.html"); + @Override + protected synchronized void start() throws IOException { + super.start(); } - } - @Path("/web") - public static class ParametersWebAppService extends AbstractWebAppService { - public ParametersWebAppService() { - super("/parameters-webapp", "web/index.html"); + @Override + protected synchronized void stop() { + super.stop(); } } + } diff --git a/petshop/petshop-application/src/main/resources/business-parameters.properties b/petshop/petshop-application/src/main/resources/business-parameters.properties deleted file mode 100644 index 2f2cab7..0000000 --- a/petshop/petshop-application/src/main/resources/business-parameters.properties +++ /dev/null @@ -1 +0,0 @@ -inmemory.storage.folder=${project.basedir}/data \ No newline at end of file diff --git a/petshop/petshop-application/src/main/resources/petshop.properties b/petshop/petshop-application/src/main/resources/petshop.properties new file mode 100644 index 0000000..0942423 --- /dev/null +++ b/petshop/petshop-application/src/main/resources/petshop.properties @@ -0,0 +1,2 @@ +inmemory.storage.folder=${project.basedir}/data +parameters.rest.url=http://localhost:9988/failure \ No newline at end of file diff --git a/scratch/src/test/java/be/kwakeroni/scratch/env/Environment.java b/scratch/src/test/java/be/kwakeroni/scratch/env/Environment.java index e4f50bf..1d1e363 100644 --- a/scratch/src/test/java/be/kwakeroni/scratch/env/Environment.java +++ b/scratch/src/test/java/be/kwakeroni/scratch/env/Environment.java @@ -15,6 +15,7 @@ import org.junit.runners.model.Statement; import org.slf4j.Logger; +import java.util.Collections; import java.util.Optional; import java.util.function.Supplier; @@ -52,7 +53,7 @@ public Environment(Supplier testDataSupplier) { this.testData = testDataSupplier.get(); BusinessParametersFactory factory = Services.loadService(BusinessParametersFactory.class); ((DirectBusinessParametersServiceFactory) factory).setBackendType(this.testData::acceptBackend); - WritableBusinessParameters local = factory.getWritableInstance(); + WritableBusinessParameters local = factory.getWritableInstance(Collections.emptyMap()); this.parameters = new WritableBusinessParameters() { @Override public void set(ParameterGroup group, Query query, T value) {