From 28c2cdaf5bc940272b51598be554bd96989cfa77 Mon Sep 17 00:00:00 2001 From: catbref Date: Wed, 5 Dec 2018 11:32:55 +0000 Subject: [PATCH] FATJAR packaging + block explorer changes Switched from maven-assembly-plugin to maven-shade-plugin for building FATJAR. When running from FATJAR, class-path is ". .." to help find log4j2.properties file. Swagger-UI can now be served direct from inside FATJAR instead of requiring resources in filesystem. Default package Start now controller/Controller block-explorer.html now served via Jetty and modified to use relative URLs instead of absolute http://localhost:9085/... style Improved shutdown code in controller /admin/stop API call disabled for now Highly permissive settings.json added --- block-explorer.html | 14 ++--- pom.xml | 88 ++++++++++++++++++++---------- settings.json | 6 ++ src/Start.java | 25 --------- src/api/AdminResource.java | 16 ++---- src/api/ApiService.java | 24 ++++---- src/api/BlockExplorerResource.java | 35 ++++++++++++ src/controller/Controller.java | 59 ++++++++++++++++++++ 8 files changed, 182 insertions(+), 85 deletions(-) create mode 100644 settings.json delete mode 100644 src/Start.java create mode 100644 src/api/BlockExplorerResource.java create mode 100644 src/controller/Controller.java diff --git a/block-explorer.html b/block-explorer.html index 4e724fb4..6048e391 100644 --- a/block-explorer.html +++ b/block-explorer.html @@ -88,7 +88,7 @@ document.body.innerHTML = html; XHR({ - url: "http://localhost:9085/transactions/address/" + address, + url: "/transactions/address/" + address, onload: renderAddressTransactions, responseType: "json" }); @@ -96,7 +96,7 @@ function fetchAddressInfo(address) { XHR({ - url: "http://localhost:9085/addresses/assets/" + address, + url: "/addresses/assets/" + address, onload: renderAddressInfo, responseType: "json" }); @@ -181,7 +181,7 @@ // Fetch block's transactions XHR({ - url: "http://localhost:9085/transactions/block/" + blockData.signature, + url: "/transactions/block/" + blockData.signature, onload: renderBlockTransactions, responseType: "json" }); @@ -189,7 +189,7 @@ function fetchBlockInfo(height) { XHR({ - url: "http://localhost:9085/blocks/byheight/" + height, + url: "/blocks/byheight/" + height, onload: renderBlockInfo, responseType: "json" }); @@ -227,7 +227,7 @@ function shutdownAPI() { XHR({ - url: "http://localhost:9085/admin/stop", + url: "/admin/stop", onload: showShutdown, responseType: "json" }); @@ -247,7 +247,7 @@ for (var h = height; h > 0 && h >= height - 20; --h) XHR({ - url: "http://localhost:9085/blocks/byheight/" + h, + url: "/blocks/byheight/" + h, onload: listBlock, responseType: "json" }); @@ -264,7 +264,7 @@ function windowOnLoad() { XHR({ - url: "http://localhost:9085/blocks/height", + url: "/blocks/height", onload: initialBlocks, responseType: "json" }); diff --git a/pom.xml b/pom.xml index 4ce392db..7a781439 100644 --- a/pom.xml +++ b/pom.xml @@ -4,6 +4,7 @@ org.qora qora-core 2.0.0-SNAPSHOT + jar UTF-8 3.19.0 @@ -20,36 +21,6 @@ 1.8 - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - - - - Start - - true - - - . .. - - - - jar-with-dependencies - - Qora - false - - - - maven-dependency-plugin @@ -118,6 +89,63 @@ + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + true + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + false + + + + org.webjars:swagger-ui + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + package + + shade + + + + + + controller.Controller + + . .. + + + + + + + diff --git a/settings.json b/settings.json new file mode 100644 index 00000000..e60b3697 --- /dev/null +++ b/settings.json @@ -0,0 +1,6 @@ +{ + "rpcallowed": [ + "::/0", + "0.0.0.0/0" + ] +} diff --git a/src/Start.java b/src/Start.java deleted file mode 100644 index 637899a6..00000000 --- a/src/Start.java +++ /dev/null @@ -1,25 +0,0 @@ - -import api.ApiService; -import repository.DataException; -import repository.RepositoryFactory; -import repository.RepositoryManager; -import repository.hsqldb.HSQLDBRepositoryFactory; - -public class Start { - - private static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true"; - - public static void main(String args[]) throws DataException { - RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl); - RepositoryManager.setRepositoryFactory(repositoryFactory); - - ApiService apiService = ApiService.getInstance(); - apiService.start(); - - //// testing the API client - //ApiClient client = ApiClient.getInstance(); - //String test = client.executeCommand("GET blocks/first"); - //System.out.println(test); - } - -} diff --git a/src/api/AdminResource.java b/src/api/AdminResource.java index 6b904ff5..0f8a006d 100644 --- a/src/api/AdminResource.java +++ b/src/api/AdminResource.java @@ -15,8 +15,8 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; -import repository.DataException; -import repository.RepositoryManager; + +import controller.Controller; @Path("admin") @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) @@ -95,20 +95,14 @@ public class AdminResource { public String shutdown() { Security.checkApiCallAllowed("GET admin/stop", request); - try { - RepositoryManager.closeRepositoryFactory(); - } catch (DataException e) { - e.printStackTrace(); - } - new Thread(new Runnable() { @Override public void run() { - ApiService.getInstance().stop(); + Controller.shutdown(); } - }).start(); + }); // disabled for now: .start(); - return "true"; + return "false"; } } diff --git a/src/api/ApiService.java b/src/api/ApiService.java index c9e521b6..f68453e0 100644 --- a/src/api/ApiService.java +++ b/src/api/ApiService.java @@ -2,7 +2,6 @@ package api; import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource; -import java.io.File; import java.util.HashSet; import java.util.Set; import org.eclipse.jetty.rewrite.handler.RedirectPatternRule; @@ -26,32 +25,33 @@ public class ApiService { private final Set> resources; public ApiService() { - // resources to register + // Resources to register this.resources = new HashSet>(); this.resources.add(AddressesResource.class); this.resources.add(AdminResource.class); this.resources.add(BlocksResource.class); this.resources.add(TransactionsResource.class); + this.resources.add(BlockExplorerResource.class); this.resources.add(OpenApiResource.class); // swagger this.resources.add(ApiDefinition.class); // for API definition this.resources.add(AnnotationPostProcessor.class); // for API resource annotations ResourceConfig config = new ResourceConfig(this.resources); - // create RPC server + // Create RPC server this.server = new Server(Settings.getInstance().getRpcPort()); - // whitelist + // IP address based access control InetAccessHandler accessHandler = new InetAccessHandler(); for (String pattern : Settings.getInstance().getRpcAllowed()) { accessHandler.include(pattern); } this.server.setHandler(accessHandler); - // url rewriting + // URL rewriting RewriteHandler rewriteHandler = new RewriteHandler(); accessHandler.setHandler(rewriteHandler); - // context + // Context ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); context.setContextPath("/"); rewriteHandler.setHandler(context); @@ -69,9 +69,8 @@ public class ApiService { // Swagger-UI static content ClassLoader loader = this.getClass().getClassLoader(); - File swaggerUIResourceLocation = new File(loader.getResource("resources/swagger-ui/").getFile()); ServletHolder swaggerUIServlet = new ServletHolder("static-swagger-ui", DefaultServlet.class); - swaggerUIServlet.setInitParameter("resourceBase", swaggerUIResourceLocation.getAbsolutePath()); + swaggerUIServlet.setInitParameter("resourceBase", loader.getResource("resources/swagger-ui/").toString()); swaggerUIServlet.setInitParameter("dirAllowed", "true"); swaggerUIServlet.setInitParameter("pathInfoOnly", "true"); context.addServlet(swaggerUIServlet, "/api-documentation/*"); @@ -96,19 +95,20 @@ public class ApiService { public void start() { try { - // START RPC + // Start server server.start(); } catch (Exception e) { - // FAILED TO START RPC + // Failed to start + throw new RuntimeException("Failed to start API", e); } } public void stop() { try { - // STOP RPC + // Stop server server.stop(); } catch (Exception e) { - // FAILED TO STOP RPC + // Failed to stop } } } diff --git a/src/api/BlockExplorerResource.java b/src/api/BlockExplorerResource.java new file mode 100644 index 00000000..e8720c11 --- /dev/null +++ b/src/api/BlockExplorerResource.java @@ -0,0 +1,35 @@ +package api; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +@Path("/") +@Produces({ MediaType.TEXT_HTML }) +public class BlockExplorerResource { + + @Context + HttpServletRequest request; + + public BlockExplorerResource() { + } + + @GET + @Path("/block-explorer.html") + public String getBlockExplorer() { + try { + byte[] htmlBytes = Files.readAllBytes(FileSystems.getDefault().getPath("block-explorer.html")); + return new String(htmlBytes, "UTF-8"); + } catch (IOException e) { + return "block-explorer.html not found"; + } + } + +} diff --git a/src/controller/Controller.java b/src/controller/Controller.java new file mode 100644 index 00000000..37c01250 --- /dev/null +++ b/src/controller/Controller.java @@ -0,0 +1,59 @@ +package controller; + +import api.ApiService; +import repository.DataException; +import repository.RepositoryFactory; +import repository.RepositoryManager; +import repository.hsqldb.HSQLDBRepositoryFactory; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class Controller { + + private static final Logger LOGGER = LogManager.getLogger(Controller.class); + + private static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true"; + private static final Object shutdownLock = new Object(); + private static boolean isStopping = false; + + public static void main(String args[]) throws DataException { + LOGGER.info("Starting up..."); + + LOGGER.info("Starting repository"); + RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl); + RepositoryManager.setRepositoryFactory(repositoryFactory); + + LOGGER.info("Starting API"); + ApiService apiService = ApiService.getInstance(); + apiService.start(); + + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + Controller.shutdown(); + } + }); + } + + public static void shutdown() { + synchronized (shutdownLock) { + if (!isStopping) { + isStopping = true; + + LOGGER.info("Shutting down API"); + ApiService.getInstance().stop(); + + try { + LOGGER.info("Shutting down repository"); + RepositoryManager.closeRepositoryFactory(); + } catch (DataException e) { + e.printStackTrace(); + } + + LOGGER.info("Shutdown complete!"); + } + } + } + +}