From 6c3b8d666e4085d089a6a756265707ece9f4e38a Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Wed, 5 Apr 2017 18:15:04 -0700 Subject: [PATCH] Cleanup application. --- pom.xml | 6 + src/com/wurrly/Application.java | 438 ++++++++++++++++++ src/com/wurrly/BaseServer.java | 334 ------------- src/com/wurrly/controllers/Users.java | 4 +- .../wurrly/modules/AbstractServerModule.java | 8 +- src/com/wurrly/modules/ConfigModule.java | 7 +- src/com/wurrly/modules/RoutingModule.java | 35 +- src/com/wurrly/modules/SwaggerModule.java | 134 ++++-- .../{RestRoute.java => RouteRecord.java} | 26 +- src/com/wurrly/server/ServerRequest.java | 2 +- ...outeGenerator.java => RouteGenerator.java} | 116 ++--- src/com/wurrly/utilities/SecurityOps.java | 67 +++ src/resources/swagger/swagger.html | 1 + 13 files changed, 716 insertions(+), 462 deletions(-) create mode 100644 src/com/wurrly/Application.java delete mode 100644 src/com/wurrly/BaseServer.java rename src/com/wurrly/server/{RestRoute.java => RouteRecord.java} (79%) rename src/com/wurrly/server/generate/{RestRouteGenerator.java => RouteGenerator.java} (93%) create mode 100644 src/com/wurrly/utilities/SecurityOps.java diff --git a/pom.xml b/pom.xml index 0b9ea72..6f9fe1e 100644 --- a/pom.xml +++ b/pom.xml @@ -175,5 +175,11 @@ swagger-ui 3.0.4 + + + com.auth0 + java-jwt + 3.1.0 + \ No newline at end of file diff --git a/src/com/wurrly/Application.java b/src/com/wurrly/Application.java new file mode 100644 index 0000000..f4c6a40 --- /dev/null +++ b/src/com/wurrly/Application.java @@ -0,0 +1,438 @@ +/** + * + */ +package com.wurrly; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.Deque; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.Service; +import com.google.common.util.concurrent.ServiceManager; +import com.google.common.util.concurrent.ServiceManager.Listener; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; +import com.jsoniter.DecodingMode; +import com.jsoniter.JsonIterator; +import com.jsoniter.annotation.JacksonAnnotationSupport; +import com.jsoniter.annotation.JsoniterAnnotationSupport; +import com.jsoniter.output.EncodingMode; +import com.jsoniter.output.JsonStream; +import com.typesafe.config.Config; +import com.wurrly.controllers.Users; +import com.wurrly.models.User; +import com.wurrly.modules.ConfigModule; +import com.wurrly.modules.RoutingModule; +import com.wurrly.modules.SwaggerModule; +import com.wurrly.server.GeneratedRouteHandler; +import com.wurrly.server.RouteRecord; +import com.wurrly.server.ServerRequest; +import com.wurrly.server.generate.RouteGenerator; + +import io.undertow.Undertow; +import io.undertow.UndertowOptions; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.RoutingHandler; +import io.undertow.util.Headers; +import io.undertow.util.HttpString; +import io.undertow.util.Methods; + +/** + * @author jbauer + */ +public class Application +{ + + + private static Logger log = LoggerFactory.getLogger(Application.class.getCanonicalName()); + + + static final String CHARSET = "UTF-8"; + + + + + public static class BaseHandlers + { + public static void notFoundHandler(HttpServerExchange exchange) { + exchange.setStatusCode(404); + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); + exchange.getResponseSender().send("Page Not Found!!"); + } + } + + + + protected Injector injector = null; + protected ServiceManager serviceManager = null; + protected Undertow webServer = null; + protected Set> registeredServices = new HashSet<>(); + protected Set> registeredControllers = new HashSet<>(); + + public Application() + { + injector = Guice.createInjector(new ConfigModule(),new RoutingModule()); + + + + } + + public void start() + { + log.info("Starting services..."); + + Set services = registeredServices.stream().map( sc -> { + + return injector.getInstance(sc); + + }).collect(Collectors.toSet()); + + this.serviceManager = new ServiceManager(services); + + this.serviceManager.addListener(new Listener() { + public void stopped() {} + public void healthy() { + log.info("Services are healthy..."); + + + buildServer().start(); + } + public void failure(Service service) + { + System.exit(1); + } + }, + MoreExecutors.directExecutor()); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + + try { + serviceManager.stopAsync().awaitStopped(5, TimeUnit.SECONDS); + webServer.stop(); + } catch (TimeoutException timeout) { + // stopping timed out + }})); + + serviceManager.startAsync(); + } + + public Undertow buildServer() + { + Config rootConfig = injector.getInstance(Config.class); + RoutingHandler router = injector.getInstance(RoutingHandler.class); + + + log.debug(injector.getAllBindings()+""); + RouteGenerator generator = new RouteGenerator("com.wurrly.controllers.handlers","RouteHandlers"); + + injector.injectMembers(generator); + + generator.generateRoutes(this.registeredControllers); + + Class handlerClass = generator.compileRoutes(); + + log.debug("New class: " + handlerClass); + + GeneratedRouteHandler routeHandler = injector.getInstance(handlerClass); + + routeHandler.addRouteHandlers(router); + + addBenchmarkHandler(router); + + StringBuilder sb = new StringBuilder(); + + Set routeRecords = injector.getInstance(Key.get(new TypeLiteral>() {},Names.named("routeRecords"))); + + routeRecords.stream().forEachOrdered( r -> sb.append(r.toString() + "\n")); + + log.info("\n\nRegistered the following endpoints: \n\n" + sb.toString()); + + webServer = Undertow.builder() + .addHttpListener(rootConfig.getInt("application.port"), "localhost") + .setBufferSize(1024 * 16) + .setIoThreads(Runtime.getRuntime().availableProcessors()) + .setServerOption(UndertowOptions.ENABLE_HTTP2, true) + .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true) + .setSocketOption(org.xnio.Options.BACKLOG, 10000) + .setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false) + + .setWorkerThreads(Runtime.getRuntime().availableProcessors() * 8) + .setHandler(new HttpHandler() + { + @Override + public void handleRequest(final HttpServerExchange exchange) throws Exception + { + try + { +// if(exchange.isInIoThread()) +// { +// exchange.dispatch(this); +// return; +// } + +// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Origin"), "*"); +// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Methods"), "GET, POST, DELETE, PUT, PATCH, OPTIONS"); +// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Headers"), "Content-Type, api_key, Authorization"); + router.handleRequest(exchange); + + } catch (Exception e) + { + if (exchange.isResponseChannelAvailable()) + { + log.error(e.getMessage(),e); + } + } + } + }).build(); + + return webServer; + } + + public void useService(Class serviceClass) + { + this.registeredServices.add(serviceClass); + } + + public void useController(Class controllerClass) + { + this.registeredControllers.add(controllerClass); + } + + public static void main(String[] args) + { + + try + { + + // Injector injector = Guice.createInjector(new ConfigModule(),new RoutingModule()); + + Application app = new Application(); + + app.useService(SwaggerModule.class); + + app.useController(Users.class); + + app.start(); + + } catch (Exception e) + { + e.printStackTrace(); + } + // Users usersController = injector.getInstance(Users.class); + + // injector.injectMembers(usersController); + + + + + + //Set> classes = RouteGenerator.getApiClasses("com.wurrly.controllers",null); + +// RouteGenerator generator = new RouteGenerator("com.wurrly.controllers.handlers","RouteHandlers"); +// generator.generateRoutes(); +// +// + + + + // generator.getRestRoutes().stream().forEachOrdered( r -> sb.append(r.toString() + "\n")); + +// SwaggerModule swaggerModule = injector.getInstance(SwaggerModule.class); +// +// +// Set services = Collections.singleton(swaggerModule); +// +// ServiceManager manager = new ServiceManager(Collections.singleton(swaggerModule)); +// +// manager.addListener(new Listener() { +// public void stopped() {} +// public void healthy() { +// // Services have been initialized and are healthy, start accepting requests... +// Logger.info("Services are healthy..."); +// } +// public void failure(Service service) { +// // Something failed, at this point we could log it, notify a load balancer, or take +// // some other action. For now we will just exit. +// System.exit(1); +// } +// }, +// MoreExecutors.directExecutor()); +// +// Runtime.getRuntime().addShutdownHook(new Thread() { +// public void run() { +// // Give the services 5 seconds to stop to ensure that we are responsive to shutdown +// // requests. +// try { +// manager.stopAsync().awaitStopped(5, TimeUnit.SECONDS); +// } catch (TimeoutException timeout) { +// // stopping timed out +// } +// } +// }); +// manager.startAsync(); // start all the services asynchronously + +// swaggerModule.generateSwaggerSpec(classes); +// +// Logger.debug("swagger spec\n"); +// +// Swagger swagger = swaggerModule.getSwagger(); +// +// Logger.debug("swagger spec: " + JsonMapper.toPrettyJSON(swagger)); +// +// swaggerModule.addRouteHandlers(); + +// HttpHandler getUserHandler = null; +// GetUsersHandler getUserHandler = new GetUsersHandler(usersController); + +// for( Method m : Users.class.getDeclaredMethods() ) +// { +// System.out.println("method: " + m); +// +// if( m.isSynthetic() || !m.getDeclaringClass().equals(Users.class)) +// { +// System.out.println("m " + m + " is shady"); +// continue; +// } +// +// HttpString httpMethod = HandleGenerator.extractHttpMethod.apply(m); +// String pathTemplate = HandleGenerator.extractPathTemplate.apply(m); +// HttpHandler handler = HandleGenerator.generateHandler(usersController, m, httpMethod.equals(Methods.POST)); +// +// Logger.info("\nFUNCTION: " + m + "\n\tMETHOD: " + httpMethod + "\n\tPATH: " + pathTemplate); +// +// +// router.add(httpMethod, pathTemplate, handler ); +// +// System.out.println("handler: " + handler); +// +// } + +// final HttpHandler createUserPostHandler = new HttpHandler() { +// @Override +// public void handleRequest(final HttpServerExchange exchange) throws Exception { +// if(exchange.isInIoThread()) { +// exchange.dispatch(this); +// } +// ServerRequest serverRequest = new ServerRequest(exchange); +// Optional context = Optional.ofNullable(exchange.getQueryParameters().get("context")).map(Deque::getFirst); +// Any user = exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY).readAny(); +// Any response = usersController.createUser(serverRequest,context,user); +// exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); +// exchange.getResponseSender().send(com.jsoniter.output.JsonStream.serialize(response)); +// } +// }; + + + + +// Config rootConfig = injector.getInstance(Config.class); +// +// Undertow server = Undertow.builder() +// .addHttpListener(rootConfig.getInt("application.port"), "localhost") +// .setBufferSize(1024 * 16) +// .setIoThreads(Runtime.getRuntime().availableProcessors()) +// .setServerOption(UndertowOptions.ENABLE_HTTP2, true) +// .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true) +// .setSocketOption(org.xnio.Options.BACKLOG, 10000) +// .setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false) +// +// .setWorkerThreads(Runtime.getRuntime().availableProcessors() * 8) +// .setHandler(new HttpHandler() +// { +// @Override +// public void handleRequest(final HttpServerExchange exchange) throws Exception +// { +// try +// { +//// if(exchange.isInIoThread()) +//// { +//// exchange.dispatch(this); +//// return; +//// } +// +//// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Origin"), "*"); +//// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Methods"), "GET, POST, DELETE, PUT, PATCH, OPTIONS"); +//// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Headers"), "Content-Type, api_key, Authorization"); +// router.handleRequest(exchange); +// +// } catch (Exception e) +// { +// if (exchange.isResponseChannelAvailable()) +// { +// e.printStackTrace(); +// } +// } +// } +// }).build(); +// server.start(); + +// Runtime.getRuntime().addShutdownHook( new Thread(){ +// +// @Override +// public void run() +// { +// +// } +// }); +// +// +// } catch (Exception e) +// { +// e.printStackTrace(); +// } + + } + + private final static class BenchmarkMessage + { + public String message = "hello world"; + } + + public static void addBenchmarkHandler(RoutingHandler routeHandler) + { + final ByteBuffer msgBuffer = ByteBuffer.wrap("hello world".getBytes()); + + + + routeHandler.add(Methods.GET, "/string", new HttpHandler(){ + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception + { + // TODO Auto-generated method stub + + exchange.getResponseSender().send(msgBuffer); + + } + } ); + + routeHandler.add(Methods.GET, "/json", new HttpHandler(){ + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception + { + // TODO Auto-generated method stub + + exchange.getResponseSender().send(JsonStream.serialize(new BenchmarkMessage())); + + } + } ); + } + +} diff --git a/src/com/wurrly/BaseServer.java b/src/com/wurrly/BaseServer.java deleted file mode 100644 index 224106d..0000000 --- a/src/com/wurrly/BaseServer.java +++ /dev/null @@ -1,334 +0,0 @@ -/** - * - */ -package com.wurrly; - -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.nio.ByteBuffer; -import java.util.Deque; -import java.util.Optional; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.jsoniter.DecodingMode; -import com.jsoniter.JsonIterator; -import com.jsoniter.annotation.JacksonAnnotationSupport; -import com.jsoniter.annotation.JsoniterAnnotationSupport; -import com.jsoniter.any.Any; -import com.jsoniter.output.EncodingMode; -import com.jsoniter.output.JsonStream; -import com.typesafe.config.Config; -import com.wurrly.models.User; -import com.wurrly.modules.ConfigModule; -import com.wurrly.modules.RoutingModule; -import com.wurrly.modules.SwaggerModule; -import com.wurrly.server.GeneratedRouteHandler; -import com.wurrly.server.ServerRequest; -import com.wurrly.server.generate.RestRouteGenerator; -import com.wurrly.utilities.JsonMapper; - -import io.swagger.models.Swagger; -import io.undertow.Undertow; -import io.undertow.UndertowOptions; -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; -import io.undertow.server.RoutingHandler; -import io.undertow.util.Headers; -import io.undertow.util.HttpString; -import io.undertow.util.Methods; - -/** - * @author jbauer - */ -public class BaseServer -{ - - public interface RouteArgumentMapper - { - public void map(M method, E exchange); - } - - private static Logger Logger = LoggerFactory.getLogger(BaseServer.class.getCanonicalName()); - - private static final String URL_ENCODED_FORM_TYPE = "x-www-form-urlencoded"; - private static final String FORM_DATA_TYPE = "form-data"; - private static final String OCTET_STREAM_TYPE = "octet-stream"; - private static final String JSON_TYPE = "application/json"; - private static final String CONTENT_TYPE = "Content-Type"; - static final String CHARSET = "UTF-8"; - - - - public static class BaseHandlers - { - public static void notFoundHandler(HttpServerExchange exchange) { - exchange.setStatusCode(404); - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); - exchange.getResponseSender().send("Page Not Found!!"); - } - } - - public static RouteArgumentMapper mapMethodParameters = (Method method, HttpServerExchange exchange) -> - { - final Parameter[] parameters = method.getParameters(); - - for (final Parameter parameter : parameters) - { - Logger.debug("parameter: " + parameter.getParameterizedType() + " " + parameter.getName()); - - if( parameter.getAnnotatedType() instanceof ServerRequest) - { - - } - } - }; - - /* - * Undertow server = Undertow.builder() - .addHttpListener(8080, "0.0.0.0") - .setHandler(Handlers.pathTemplate() - .add("/item/{itemId}", new ItemHandler()) - ) - .build(); -server.start(); - */ - - static Optional queryParam(HttpServerExchange exchange, String name) { - - return Optional.ofNullable(exchange.getQueryParameters().get(name)) - .map(Deque::getFirst); - } - - - static Optional pathParam(HttpServerExchange exchange, String name) { - - return Optional.ofNullable(exchange.getQueryParameters().get(name)) - .map(Deque::getFirst); - } - - static Optional pathParamAsLong(HttpServerExchange exchange, String name) { - return pathParam(exchange, name).map(Long::parseLong); - } - - static Optional pathParamAsInteger(HttpServerExchange exchange, String name) { - return pathParam(exchange, name).map(Integer::parseInt); - } - - - final static ByteBuffer msgBuffer = ByteBuffer.wrap("hello world".getBytes()); - - public static void main(String[] args) - { - - try - { - - Injector injector = Guice.createInjector(new ConfigModule(),new RoutingModule()); - - - // Users usersController = injector.getInstance(Users.class); - - // injector.injectMembers(usersController); - - - JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH); - JsonStream.setMode(EncodingMode.DYNAMIC_MODE); - JacksonAnnotationSupport.enable(); - - - Set> classes = RestRouteGenerator.getApiClasses("com.wurrly.controllers",null); - - RestRouteGenerator generator = new RestRouteGenerator("com.wurrly.controllers.handlers","RouteHandlers"); - generator.generateRoutes(classes); - - StringBuilder sb = new StringBuilder(); - - generator.getRestRoutes().stream().forEachOrdered( r -> sb.append(r.toString() + "\n")); - - Logger.info("\n\nRegistered the following endpoints: \n\n" + sb.toString()); - - Class handlerClass = generator.compileRoutes(); - - RoutingHandler router = injector.getInstance(RoutingHandler.class); - - Logger.debug("New class: " + handlerClass); - - GeneratedRouteHandler routeHandler = injector.getInstance(handlerClass); - - routeHandler.addRouteHandlers(router); - - SwaggerModule swaggerModule = injector.getInstance(SwaggerModule.class); - - swaggerModule.generateSwaggerSpec(classes); - - Logger.debug("swagger spec\n"); - - Swagger swagger = swaggerModule.getSwagger(); - - Logger.debug("swagger spec: " + JsonMapper.toPrettyJSON(swagger)); - - swaggerModule.addRouteHandlers(); - -// HttpHandler getUserHandler = null; -// GetUsersHandler getUserHandler = new GetUsersHandler(usersController); - -// for( Method m : Users.class.getDeclaredMethods() ) -// { -// System.out.println("method: " + m); -// -// if( m.isSynthetic() || !m.getDeclaringClass().equals(Users.class)) -// { -// System.out.println("m " + m + " is shady"); -// continue; -// } -// -// HttpString httpMethod = HandleGenerator.extractHttpMethod.apply(m); -// String pathTemplate = HandleGenerator.extractPathTemplate.apply(m); -// HttpHandler handler = HandleGenerator.generateHandler(usersController, m, httpMethod.equals(Methods.POST)); -// -// Logger.info("\nFUNCTION: " + m + "\n\tMETHOD: " + httpMethod + "\n\tPATH: " + pathTemplate); -// -// -// router.add(httpMethod, pathTemplate, handler ); -// -// System.out.println("handler: " + handler); -// -// } - -// final HttpHandler createUserPostHandler = new HttpHandler() { -// @Override -// public void handleRequest(final HttpServerExchange exchange) throws Exception { -// if(exchange.isInIoThread()) { -// exchange.dispatch(this); -// } -// ServerRequest serverRequest = new ServerRequest(exchange); -// Optional context = Optional.ofNullable(exchange.getQueryParameters().get("context")).map(Deque::getFirst); -// Any user = exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY).readAny(); -// Any response = usersController.createUser(serverRequest,context,user); -// exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); -// exchange.getResponseSender().send(com.jsoniter.output.JsonStream.serialize(response)); -// } -// }; - - - router.add(Methods.GET, "/", new HttpHandler(){ - - /* (non-Javadoc) - * @see io.undertow.server.HttpHandler#handleRequest(io.undertow.server.HttpServerExchange) - */ - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception - { - // TODO Auto-generated method stub - - exchange.getResponseSender().send(msgBuffer); - - } - - - - } ); - - Config rootConfig = injector.getInstance(Config.class); - - Undertow server = Undertow.builder() - .addHttpListener(rootConfig.getInt("application.port"), "localhost") - .setBufferSize(1024 * 16) - .setIoThreads(Runtime.getRuntime().availableProcessors()) - .setServerOption(UndertowOptions.ENABLE_HTTP2, true) - .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true) - .setSocketOption(org.xnio.Options.BACKLOG, 10000) - .setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false) - - .setWorkerThreads(Runtime.getRuntime().availableProcessors() * 8) - .setHandler(new HttpHandler() - { - @Override - public void handleRequest(final HttpServerExchange exchange) throws Exception - { - try - { -// if(exchange.isInIoThread()) -// { -// exchange.dispatch(this); -// return; -// } - - exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Origin"), "*"); - exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Methods"), "GET, POST, DELETE, PUT, PATCH, OPTIONS"); - exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Headers"), "Content-Type, api_key, Authorization"); - router.handleRequest(exchange); - - } catch (Exception e) - { - if (exchange.isResponseChannelAvailable()) - { - e.printStackTrace(); - } - } - } - }).build(); - server.start(); - - Runtime.getRuntime().addShutdownHook( new Thread(){ - - @Override - public void run() - { - - } - }); - - - } catch (Exception e) - { - e.printStackTrace(); - } - - } - - - - public static class UserIdHandler implements HttpHandler { - - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception { - - -// // Method 1 -// PathTemplateMatch pathMatch = exchange.getAttachment(PathTemplateMatch.ATTACHMENT_KEY); -// -// System.out.println(pathMatch.getMatchedTemplate()); -// -// System.out.println(pathMatch.getParameters()); -// -// -// System.out.println(exchange.getQueryParameters()); - - - - Long userId = pathParam(exchange,"id").map(Long::parseLong).orElse(0l); - - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, JSON_TYPE); - - User user = new User(); - user.setId(userId); -// - String json = JsonStream.serialize(user); - - // JsonStream.serialize(user,exchange.getOutputStream()); - exchange.getResponseSender().send(json); - - // exchange.getResponseSender().send(ByteBuffer.wrap(JsonMapper.getInstance().writeValueAsBytes(user))); - - // exchange.getResponseSender().send(JsonStream.serialize(Collections.singletonMap("id", userId))); - - } - } - -} diff --git a/src/com/wurrly/controllers/Users.java b/src/com/wurrly/controllers/Users.java index 40996de..30d99a4 100644 --- a/src/com/wurrly/controllers/Users.java +++ b/src/com/wurrly/controllers/Users.java @@ -123,10 +123,10 @@ public Any user(@ApiParam(hidden=true)final ServerRequest serverRequest, @POST @Path("/") - @Consumes("multipart/form-data") + //@Consumes("multipart/form-data") // @ApiImplicitParams({ @ApiImplicitParam(dataType = "com.wurrly.models.User", name = "user", paramType = "body", required = false, allowMultiple = false) }) @ApiOperation(value = "Create a user", httpMethod = "POST", response = User.class) - public Any createUser(@ApiParam(hidden=true)final ServerRequest serverRequest, @QueryParam("context") Optional context, final java.nio.file.Path filePath ) + public Any createUser(@ApiParam(hidden=true)final ServerRequest serverRequest, @QueryParam("context") Optional context, final User user ) { // diff --git a/src/com/wurrly/modules/AbstractServerModule.java b/src/com/wurrly/modules/AbstractServerModule.java index 9ae1cbb..3623455 100644 --- a/src/com/wurrly/modules/AbstractServerModule.java +++ b/src/com/wurrly/modules/AbstractServerModule.java @@ -6,13 +6,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.util.concurrent.AbstractIdleService; import com.google.inject.Inject; /** * @author jbauer * */ -public class AbstractServerModule +public abstract class AbstractServerModule extends AbstractIdleService { private static Logger log = LoggerFactory.getLogger(AbstractServerModule.class.getCanonicalName()); @@ -20,7 +21,7 @@ public class AbstractServerModule * @see com.google.inject.AbstractModule#configure() */ - public String configFile; + protected String configFile; @Inject protected ConfigModule configModule; @@ -34,8 +35,7 @@ public AbstractServerModule() protected void configure() { log.debug("Configuring : " + this.getClass().getSimpleName()); - - + if( this.configFile != null ) { configModule.bindFileConfig(this.configFile); diff --git a/src/com/wurrly/modules/ConfigModule.java b/src/com/wurrly/modules/ConfigModule.java index baa2de9..3874515 100644 --- a/src/com/wurrly/modules/ConfigModule.java +++ b/src/com/wurrly/modules/ConfigModule.java @@ -71,10 +71,7 @@ public void bindFileConfig(String fileName) @SuppressWarnings("unchecked") public void bindConfig(final Config config) { - // root nodes - - - + traverse(this.binder(), "", config.root()); @@ -97,7 +94,7 @@ public void bindConfig(final Config config) } } // bind config - this.binder().bind(Config.class).toInstance( ConfigFactory.load(config)); + this.binder().bind(Config.class).toInstance( ConfigFactory.load(config) ); log.info("Config:\n" + config); diff --git a/src/com/wurrly/modules/RoutingModule.java b/src/com/wurrly/modules/RoutingModule.java index 350fca7..5b9e706 100644 --- a/src/com/wurrly/modules/RoutingModule.java +++ b/src/com/wurrly/modules/RoutingModule.java @@ -3,38 +3,45 @@ */ package com.wurrly.modules; +import java.util.Set; +import java.util.TreeSet; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.inject.AbstractModule; +import com.google.inject.Scope; import com.google.inject.Singleton; -import com.wurrly.BaseServer.BaseHandlers; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; +import com.wurrly.Application.BaseHandlers; +import com.wurrly.server.RouteRecord; -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; import io.undertow.server.RoutingHandler; -import io.undertow.util.Methods; /** * @author jbauer * */ @Singleton -public class RoutingModule extends AbstractModule +public class RoutingModule extends AbstractModule { + private static Logger log = LoggerFactory.getLogger(RoutingModule.class.getCanonicalName()); - - /* (non-Javadoc) - * @see com.google.inject.AbstractModule#configure() - */ + protected Set routeRecords = new TreeSet<>(); + @Override protected void configure() { RoutingHandler router = new RoutingHandler().setFallbackHandler(BaseHandlers::notFoundHandler); + + this.binder().bind(RoutingHandler.class).toInstance(router); + this.binder().bind(new TypeLiteral>() {}).annotatedWith(Names.named("routeRecords")).toInstance(routeRecords); - - - System.out.println("router: " + router.hashCode()); - - this.binder().bind(RoutingHandler.class).toInstance(router); } + + } diff --git a/src/com/wurrly/modules/SwaggerModule.java b/src/com/wurrly/modules/SwaggerModule.java index f1a9abe..2bdd97d 100644 --- a/src/com/wurrly/modules/SwaggerModule.java +++ b/src/com/wurrly/modules/SwaggerModule.java @@ -23,6 +23,8 @@ import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.template.PebbleTemplate; import com.typesafe.config.Config; +import com.wurrly.server.RouteRecord; +import com.wurrly.server.generate.RouteGenerator; import com.wurrly.server.swagger.ServerParameterExtension; import com.wurrly.utilities.JsonMapper; @@ -38,7 +40,9 @@ import io.undertow.server.handlers.resource.ResourceHandler; import io.undertow.util.CanonicalPathUtils; import io.undertow.util.Headers; +import io.undertow.util.Methods; +import static org.apache.http.entity.ContentType.*; /** * @author jbauer * @@ -53,12 +57,13 @@ public class SwaggerModule extends AbstractServerModule protected final String swaggerThemesPath = "resources/swagger/themes"; - protected Swagger swagger; + protected Swagger swagger = null; private String swaggerSpec = null; private String swaggerIndexHTML = null; + @Inject @Named("swagger.basePath") protected String swaggerBasePath; @@ -67,6 +72,15 @@ public class SwaggerModule extends AbstractServerModule @Named("swagger.theme") protected String swaggerTheme; + @Inject + @Named("swagger.specFilename") + protected String specFilename; + + @Inject + @Named("swagger.info") + protected Config swaggerInfo; + + @Inject @Named("application.host") protected String host; @@ -80,27 +94,25 @@ public class SwaggerModule extends AbstractServerModule protected Integer port; @Inject - @Named("swagger.specFilename") - protected String specFilename; + @Named("application.path") + protected String applicationPath; @Inject - @Named("swagger.info") - protected Config swaggerInfo; + @Named("routeRecords") + private Set routeRecords; @Inject RoutingHandler routingHandler; + public SwaggerModule() { - + this.configFile = "swagger.conf"; } public void generateSwaggerSpec(Set> classes) { - log.debug("ConfigModule: " + this.configModule + " handler: " + routingHandler + " info: " + swaggerInfo); - - List extensions = new ArrayList<>(); extensions.add(new ServerParameterExtension()); @@ -112,6 +124,8 @@ public void generateSwaggerSpec(Set> classes) Swagger swagger = new Swagger(); + swagger.setBasePath(applicationPath); + swagger.setHost(host+((port != 80 && port != 443) ? ":" + port : "")); Info info = new Info(); @@ -179,8 +193,7 @@ public void setSwagger(Swagger swagger) public void generateSwaggerHTML() { try - { - + { PebbleEngine engine = new PebbleEngine.Builder().build(); PebbleTemplate compiledTemplate = engine.getTemplate("resources/swagger/swagger.html"); @@ -227,7 +240,7 @@ public void addRouteHandlers() @Override public void handleRequest(HttpServerExchange exchange) throws Exception { - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, org.apache.http.entity.ContentType.APPLICATION_JSON.getMimeType()); + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, APPLICATION_JSON.getMimeType()); exchange.getResponseSender().send(swaggerSpec); @@ -236,26 +249,45 @@ public void handleRequest(HttpServerExchange exchange) throws Exception }); - + RouteRecord record = new RouteRecord(); + record.setConsumes("*/*"); + record.setProduces(APPLICATION_JSON.getMimeType()); + record.setPathTemplate(pathTemplate); + record.setMethod(Methods.GET); + record.setControllerName("Swagger"); + + routeRecords.add(record); + + pathTemplate = this.swaggerBasePath; - this.routingHandler.add(HttpMethod.GET, this.swaggerBasePath , new HttpHandler(){ + this.routingHandler.add(HttpMethod.GET, pathTemplate , new HttpHandler(){ @Override public void handleRequest(HttpServerExchange exchange) throws Exception { - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, org.apache.http.entity.ContentType.TEXT_HTML.getMimeType()); + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, TEXT_HTML.getMimeType()); exchange.getResponseSender().send(swaggerIndexHTML); } }); + record = new RouteRecord(); + record.setConsumes("*/*"); + record.setProduces("text/html"); + record.setPathTemplate(pathTemplate); + record.setMethod(Methods.GET); + record.setControllerName("Swagger"); + + routeRecords.add(record); + ClassPathResourceManager resourceManager = new ClassPathResourceManager(this.getClass().getClassLoader()); + pathTemplate = this.swaggerBasePath + "/themes/*"; - this.routingHandler.add(HttpMethod.GET, this.swaggerBasePath + "/themes/*", new ResourceHandler(resourceManager){ + this.routingHandler.add(HttpMethod.GET, pathTemplate, new ResourceHandler(resourceManager){ @Override public void handleRequest(HttpServerExchange exchange) throws Exception @@ -272,25 +304,22 @@ public void handleRequest(HttpServerExchange exchange) throws Exception }); + record = new RouteRecord(); + record.setConsumes("*/*"); + record.setProduces("text/css"); + record.setPathTemplate(pathTemplate); + record.setMethod(Methods.GET); + record.setControllerName("Swagger"); + routeRecords.add(record); + try { - Resource swaggerUIResource = resourceManager.getResource(webJarPath); + //Resource swaggerUIResource = resourceManager.getResource(webJarPath); - log.debug("swaggerUIResource: " + swaggerUIResource.getPath()); - log.debug("swaggerUIResource: " + swaggerUIResource.list()); - - Path swaggerParentPath = swaggerUIResource.getFilePath(); - - log.debug("swaggerParentPath: " + swaggerParentPath); - - - //if(subDirectories.length > 0) - { - -// webJarPath = webJarPath + "/" + subDirectories[0].getName() + "/dist"; - - this.routingHandler.add(HttpMethod.GET, this.swaggerBasePath + "/*", new ResourceHandler(resourceManager){ + pathTemplate = this.swaggerBasePath + "/*"; + + this.routingHandler.add(HttpMethod.GET, pathTemplate, new ResourceHandler(resourceManager){ @Override public void handleRequest(HttpServerExchange exchange) throws Exception @@ -306,9 +335,17 @@ public void handleRequest(HttpServerExchange exchange) throws Exception } }); - } + record = new RouteRecord(); + record.setConsumes("*/*"); + record.setProduces("*/*"); + record.setPathTemplate(pathTemplate); + record.setMethod(Methods.GET); + record.setControllerName("Swagger"); + + routeRecords.add(record); + } catch (Exception e) { log.error(e.getMessage(),e); @@ -321,6 +358,39 @@ public void handleRequest(HttpServerExchange exchange) throws Exception + } + + + + /* (non-Javadoc) + * @see com.google.common.util.concurrent.AbstractIdleService#startUp() + */ + @Override + protected void startUp() throws Exception + { + // TODO Auto-generated method stub + + Set> classes = RouteGenerator.getApiClasses("com.wurrly.controllers",null); + + this.generateSwaggerSpec(classes); + + + Swagger swagger = this.getSwagger(); + + log.info("swagger spec: " + JsonMapper.toPrettyJSON(swagger)); + + this.addRouteHandlers(); + + } + + /* (non-Javadoc) + * @see com.google.common.util.concurrent.AbstractIdleService#shutDown() + */ + @Override + protected void shutDown() throws Exception + { + // TODO Auto-generated method stub + } } diff --git a/src/com/wurrly/server/RestRoute.java b/src/com/wurrly/server/RouteRecord.java similarity index 79% rename from src/com/wurrly/server/RestRoute.java rename to src/com/wurrly/server/RouteRecord.java index ad6585c..e670846 100644 --- a/src/com/wurrly/server/RestRoute.java +++ b/src/com/wurrly/server/RouteRecord.java @@ -12,17 +12,17 @@ * @author jbauer * */ -public class RestRoute implements Comparable +public class RouteRecord implements Comparable { private HttpString method; private String pathTemplate; - private String consumes; - private String produces; - private String controllerMethod; - private String controllerName; + private String consumes = "*/*"; + private String produces = "*/*"; + private String controllerMethod = "*"; + private String controllerName = "anonymous"; - public RestRoute() + public RouteRecord() { } @@ -136,19 +136,21 @@ public int hashCode() toHashCode(); } - public int compareTo(RestRoute o) { - RestRoute myClass = (RestRoute) o; + public int compareTo(RouteRecord o) { + RouteRecord other = (RouteRecord) o; return new CompareToBuilder() - .append(this.controllerName, myClass.controllerName) - .append(this.method, myClass.method) - .append(this.controllerMethod, myClass.controllerMethod) + .append(this.controllerName, other.controllerName) + .append(this.method, other.method) + .append(this.controllerMethod, other.controllerMethod) + .append(this.pathTemplate, other.pathTemplate) + .toComparison(); } @Override public String toString() { - return String.format("%-8s %-60s %-18s %-18s %s", this.method, this.pathTemplate, "[" + this.consumes + "]", "[" + this.produces+ "]", "("+this.controllerMethod+ ")"); + return String.format("%-8s %-30s %-26s %-26s %s", this.method, this.pathTemplate, "[" + this.consumes + "]", "[" + this.produces+ "]", "("+this.controllerMethod+ ")"); } diff --git a/src/com/wurrly/server/ServerRequest.java b/src/com/wurrly/server/ServerRequest.java index c02c2cb..f47f128 100644 --- a/src/com/wurrly/server/ServerRequest.java +++ b/src/com/wurrly/server/ServerRequest.java @@ -83,7 +83,7 @@ else if (this.contentType.contains(MultiPartParserDefinition.MULTIPART_FORM_DATA { this.parseMultipartForm(); } - else if (this.contentType.contains(APPLICATION_JSON)) + else if (this.contentType.contains(APPLICATION_JSON) && this.exchange.getRequestContentLength() != -1) { this.parseJson(); } diff --git a/src/com/wurrly/server/generate/RestRouteGenerator.java b/src/com/wurrly/server/generate/RouteGenerator.java similarity index 93% rename from src/com/wurrly/server/generate/RestRouteGenerator.java rename to src/com/wurrly/server/generate/RouteGenerator.java index 9ae4475..e11015a 100644 --- a/src/com/wurrly/server/generate/RestRouteGenerator.java +++ b/src/com/wurrly/server/generate/RouteGenerator.java @@ -11,7 +11,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -30,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.jsoniter.spi.TypeLiteral; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; @@ -39,7 +41,7 @@ import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; import com.wurrly.server.GeneratedRouteHandler; -import com.wurrly.server.RestRoute; +import com.wurrly.server.RouteRecord; import com.wurrly.server.ServerRequest; import com.wurrly.utilities.HandleGenerator; @@ -52,11 +54,11 @@ /** * @author jbauer */ -public class RestRouteGenerator +public class RouteGenerator { - private static Logger log = LoggerFactory.getLogger(RestRouteGenerator.class.getCanonicalName()); + private static Logger log = LoggerFactory.getLogger(RouteGenerator.class.getCanonicalName()); // @Inject // @Named("date.format") @@ -338,36 +340,42 @@ else if( hasFromString ) } } + @Inject + @Named("routeRecords") + protected Set routeRecords; - private List restRoutes = new ArrayList<>(); - private String packageName; - private String className; - private String sourceString; - - public static void main(String[] args) - { - try - { - RestRouteGenerator generator = new RestRouteGenerator("com.wurrly.controllers.handlers","RouteHandlers"); - - Set> classes = getApiClasses("com.wurrly.controllers",null); - - generator.generateRoutes(classes); - - StringBuilder sb = new StringBuilder(); - - generator.getRestRoutes().stream().forEachOrdered( r -> sb.append(r.toString() + "\n")); - - System.out.println(sb.toString()); - - System.out.println("\n" + generator.sourceString); - - } catch (Exception e) - { - log.error(e.getMessage(),e); - } - - } + @Inject + @Named("application.path") + protected String applicationPath; + + protected String packageName; + protected String className; + protected String sourceString; + +// public static void main(String[] args) +// { +// try +// { +// RouteGenerator generator = new RouteGenerator("com.wurrly.controllers.handlers","RouteHandlers"); +// +// Set> classes = getApiClasses("com.wurrly.controllers",null); +// +// generator.generateRoutes(); +// +// StringBuilder sb = new StringBuilder(); +// +// //generator.getRestRoutes().stream().forEachOrdered( r -> sb.append(r.toString() + "\n")); +// +// System.out.println(sb.toString()); +// +// System.out.println("\n" + generator.sourceString); +// +// } catch (Exception e) +// { +// log.error(e.getMessage(),e); +// } +// +// } public Class compileRoutes() { @@ -385,7 +393,7 @@ public Class compileRoutes() } } - public RestRouteGenerator(String packageName, String className) + public RouteGenerator(String packageName, String className) { this.packageName = packageName; this.className = className; @@ -396,9 +404,10 @@ public void generateRoutes(Set> classes) { try { - String prefix = "com.wurrly.controllers"; -// List classNames = getClassNamesFromPackage(prefix); +// Set> classes = getApiClasses("com.wurrly.controllers",null); + + TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(className) .addModifiers(Modifier.PUBLIC) .addSuperinterface(ClassName.get(com.wurrly.server.GeneratedRouteHandler.class)); @@ -406,9 +415,7 @@ public void generateRoutes(Set> classes) ClassName handleGeneratorClass = ClassName.get("com.wurrly.utilities", "HandleGenerator"); ClassName injectClass = ClassName.get("com.google.inject", "Inject"); - - - + MethodSpec.Builder constructor = MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) .addAnnotation(injectClass); @@ -456,14 +463,17 @@ public void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class clazz) String controllerName = clazz.getSimpleName().toLowerCase() + "Controller"; - MethodSpec.Builder initBuilder = MethodSpec.methodBuilder("addRouteHandlers").addModifiers(Modifier.PUBLIC).addParameter(ParameterSpec.builder(io.undertow.server.RoutingHandler.class, "router", Modifier.FINAL).build()); + MethodSpec.Builder initBuilder = MethodSpec.methodBuilder("addRouteHandlers") + .addModifiers(Modifier.PUBLIC) + .addParameter(ParameterSpec.builder(io.undertow.server.RoutingHandler.class, "router", Modifier.FINAL) + .build()); final Map typeLiteralsMap = Arrays.stream(clazz.getDeclaredMethods()).flatMap(m -> { return Arrays.stream(m.getParameters()).map(Parameter::getParameterizedType).filter(t -> t.getTypeName().contains("<")); }).distinct().filter(t -> { TypeHandler handler = TypeHandler.forType(t); return (handler.equals(TypeHandler.ModelType) || handler.equals(TypeHandler.OptionalModelType)); - }).collect(Collectors.toMap(java.util.function.Function.identity(), RestRouteGenerator::typeLiteralNameForType)); + }).collect(Collectors.toMap(java.util.function.Function.identity(), RouteGenerator::typeLiteralNameForType)); initBuilder.addCode("$L", "\n"); @@ -477,11 +487,13 @@ public void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class clazz) for (Method m : clazz.getDeclaredMethods()) { - RestRoute route = new RestRoute(); + RouteRecord route = new RouteRecord(); route.setControllerName(clazz.getSimpleName()); - String methodPath = HandleGenerator.extractPathTemplate.apply(m); + String methodPath = HandleGenerator.extractPathTemplate.apply(m).replaceAll("\\/\\/", "\\/"); + + methodPath = applicationPath + methodPath; log.debug("method path: " + methodPath); @@ -704,7 +716,7 @@ else if (t.equals(TypeHandler.OptionalFromStringType) || t.equals(TypeHandler.Op initBuilder.addCode("$L", "\n"); - this.restRoutes.add(route); + this.routeRecords.add(route); } typeBuilder.addMethod(initBuilder.build()); @@ -712,21 +724,9 @@ else if (t.equals(TypeHandler.OptionalFromStringType) || t.equals(TypeHandler.Op } - /** - * @return the restRoutes - */ - public List getRestRoutes() - { - return restRoutes; - } - /** - * @param restRoutes the restRoutes to set - */ - public void setRestRoutes(List restRoutes) - { - this.restRoutes = restRoutes; - } + + /** * @return the packageName diff --git a/src/com/wurrly/utilities/SecurityOps.java b/src/com/wurrly/utilities/SecurityOps.java new file mode 100644 index 0000000..a60c4fe --- /dev/null +++ b/src/com/wurrly/utilities/SecurityOps.java @@ -0,0 +1,67 @@ +/** + * + */ +package com.wurrly.utilities; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.util.function.Function; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +/** + * @author jbauer + * + */ +public class SecurityOps +{ + public static SSLContext createSSLContext(final KeyStore keyStore, final KeyStore trustStore, final String password) throws Exception { + KeyManager[] keyManagers; + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, password.toCharArray()); + keyManagers = keyManagerFactory.getKeyManagers(); + + TrustManager[] trustManagers; + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(trustStore); + trustManagers = trustManagerFactory.getTrustManagers(); + + SSLContext sslContext; + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, trustManagers, null); + + return sslContext; + } + + public static KeyStore loadKeyStore(String storePath, String password) throws Exception + { + + try( final InputStream stream = Files.newInputStream(Paths.get(storePath)) ) + { + if(stream == null) { + throw new RuntimeException("Could not load keystore"); + } + + try(InputStream is = stream) + { + + KeyStore loadedKeystore = KeyStore.getInstance("JKS"); + loadedKeystore.load(is, password.toCharArray()); + return loadedKeystore; + + } catch(Exception e) + { + throw new RuntimeException("Could not load keystore: " + e.getMessage()); + } + } + + + + } +} diff --git a/src/resources/swagger/swagger.html b/src/resources/swagger/swagger.html index 288af4c..b5e9d7c 100644 --- a/src/resources/swagger/swagger.html +++ b/src/resources/swagger/swagger.html @@ -93,6 +93,7 @@ plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], + showRequestHeaders: true, layout: "StandaloneLayout", validatorUrl: null })