diff --git a/src/main/java/io/sinistral/proteus/ProteusApplication.java b/src/main/java/io/sinistral/proteus/ProteusApplication.java index eff45d4..ff4e29f 100644 --- a/src/main/java/io/sinistral/proteus/ProteusApplication.java +++ b/src/main/java/io/sinistral/proteus/ProteusApplication.java @@ -16,8 +16,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.ImmutableMultimap; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.Service; +import com.google.common.util.concurrent.Service.State; import com.google.common.util.concurrent.ServiceManager; import com.google.common.util.concurrent.ServiceManager.Listener; import com.google.inject.Guice; @@ -104,7 +106,12 @@ public ProteusApplication(URL configURL) public void start() { - + if(this.isRunning()) + { + log.warn("Server has already started..."); + return; + } + injector = injector.createChildInjector(registeredModules); if( rootHandlerClass == null && rootHandler == null ) @@ -144,7 +151,7 @@ public void healthy() public void failure(Service service) { - log.error("Error on service: " + service); + log.error("Service failure: " + service); } }, MoreExecutors.directExecutor()); @@ -170,6 +177,13 @@ public void run() public void shutdown() throws TimeoutException { + if(!this.isRunning()) + { + log.warn("Server is not running..."); + + return; + } + log.info("Shutting down..."); serviceManager.stopAsync().awaitStopped(5, TimeUnit.SECONDS); @@ -199,7 +213,7 @@ public void buildServer() } catch (Exception e) { - log.error("Exception creating handlers for " + controllerClass.getName() + "!!!"); + log.error("Exception creating handlers for " + controllerClass.getName() + "!!!\n" + e.getMessage(), e); } } @@ -291,10 +305,30 @@ public void printStatus() StringBuilder sb = new StringBuilder(); - sb.append("\n\nUsing the following global headers: \n\n"); + sb.append("\n\nUsing global headers: \n\n"); sb.append(globalHeadersParameters.entrySet().stream().map( e -> "\t" + e.getKey() + " = " + e.getValue() ).collect(Collectors.joining("\n"))); - sb.append("\n\nRegistered the following endpoints: \n\n"); + sb.append("\n\nRegistered endpoints: \n\n"); sb.append(this.registeredEndpoints.stream().sorted().map(EndpointInfo::toString).collect(Collectors.joining("\n"))); + sb.append("\n\nRegistered services: \n\n"); + + ImmutableMultimap serviceStateMap = this.serviceManager.servicesByState(); + + String serviceStrings = serviceStateMap.asMap().entrySet().stream().sorted().flatMap( e -> { + + + return e.getValue().stream().map( s -> { + return "\t" + s.getClass().getSimpleName() + "\t" + e.getKey(); + }); + + + }).collect(Collectors.joining("\n")); + + sb.append(serviceStrings); + + sb.append("\n"); + + sb.append("\nListening on port " + config.getInt("application.port")); + sb.append("\n"); log.info(sb.toString()); diff --git a/src/main/java/io/sinistral/proteus/server/ServerResponse.java b/src/main/java/io/sinistral/proteus/server/ServerResponse.java index 9f6c218..cb9d2c3 100644 --- a/src/main/java/io/sinistral/proteus/server/ServerResponse.java +++ b/src/main/java/io/sinistral/proteus/server/ServerResponse.java @@ -6,6 +6,7 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; +import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; @@ -220,6 +221,7 @@ public ServerResponse textHtml() this.contentType = javax.ws.rs.core.MediaType.TEXT_HTML; return this; } + public ServerResponse applicationOctetStream() { diff --git a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java index 13cd0dd..15f9eec 100644 --- a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java +++ b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java @@ -55,6 +55,7 @@ import io.sinistral.proteus.server.ServerResponse; import io.sinistral.proteus.server.endpoints.EndpointInfo; import io.swagger.annotations.Api; +import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.server.RoutingHandler; import io.undertow.util.Headers; @@ -91,7 +92,7 @@ public enum TypeHandler FilePathType("$T $L = $T.filePath(exchange,$S)", true, java.nio.file.Path.class, StatementParameterType.LITERAL,io.sinistral.proteus.server.Extractors.class, StatementParameterType.STRING), AnyType("$T $L = $T.any(exchange)", true, com.jsoniter.any.Any.class, StatementParameterType.LITERAL,io.sinistral.proteus.server.Extractors.class), JsonIteratorType("$T $L = $T.jsonIterator(exchange)", true, com.jsoniter.JsonIterator.class, StatementParameterType.LITERAL,io.sinistral.proteus.server.Extractors.class), - ModelType("$T $L = $T.model(exchange,$L)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class, StatementParameterType.LITERAL), + ModelType("$T $L = io.sinistral.proteus.server.Extractors.model(exchange,$L)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.LITERAL), //EnumType("$T $L = $T.enumValue(exchange,$T.class,$S)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL,io.sinistral.proteus.server.Extractors.class, StatementParameterType.TYPE, StatementParameterType.STRING), ByteBufferType("$T $L = $T.byteBuffer(exchange,$S)", true, java.nio.ByteBuffer.class, StatementParameterType.LITERAL,io.sinistral.proteus.server.Extractors.class, StatementParameterType.STRING), @@ -793,7 +794,7 @@ else if(t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class)) for (Parameter p : m.getParameters()) { - if (p.getParameterizedType().equals(ServerRequest.class) || p.getParameterizedType().equals(HttpServerExchange.class)) + if (p.getParameterizedType().equals(ServerRequest.class) || p.getParameterizedType().equals(HttpServerExchange.class) || p.getParameterizedType().equals(HttpHandler.class)) { continue; } @@ -840,6 +841,11 @@ else if (p.getType().equals(HttpServerExchange.class)) { methodBuilder.addCode("$L", "\n"); } + else if (p.getType().equals(HttpHandler.class)) + { + methodBuilder.addStatement("$T $L = this", HttpHandler.class, p.getName()); + methodBuilder.addCode("$L", "\n"); + } else { if (p.isAnnotationPresent(HeaderParam.class)) @@ -907,8 +913,11 @@ else if( handler.equals(TypeHandler.FromStringType) ) String interfaceType = parameterizedLiteralsNameMap.get(type); String pType = interfaceType != null ? interfaceType + "TypeLiteral" : type.getTypeName() + ".class"; - - methodBuilder.addStatement(t.statement, type, p.getName(), pType); + + + methodBuilder.addStatement(t.statement, type, p.getName(), pType); + + } else if (t.equals(TypeHandler.OptionalFromStringType) || t.equals(TypeHandler.OptionalValueOfType)) { @@ -1029,11 +1038,22 @@ else if(producesContentType.contains(MediaType.TEXT_HTML)) } else { - functionBlockBuilder.add("$L.$L($L);", controllerName, m.getName(), "exchange"); + + functionBlockBuilder.add("$L.$L($L);", controllerName, m.getName(), controllerMethodArgs); + methodBuilder.addCode(functionBlockBuilder.build()); + methodBuilder.addCode("$L", "\n"); + + handlerClassBuilder.addMethod(methodBuilder.build()); + +// functionBlockBuilder.add("$L.$L($L);", controllerName, m.getName(), "exchange"); +// +// methodBuilder.addCode(functionBlockBuilder.build()); +// +// handlerClassBuilder.addMethod(methodBuilder.build()); } diff --git a/src/main/java/io/sinistral/proteus/services/BaseService.java b/src/main/java/io/sinistral/proteus/services/BaseService.java index 07e4796..939f563 100644 --- a/src/main/java/io/sinistral/proteus/services/BaseService.java +++ b/src/main/java/io/sinistral/proteus/services/BaseService.java @@ -7,7 +7,10 @@ import org.slf4j.LoggerFactory; import com.google.common.util.concurrent.AbstractIdleService; +import com.google.inject.Binder; import com.google.inject.Inject; +import com.google.inject.Module; +import com.google.inject.Singleton; import com.typesafe.config.Config; import io.sinistral.proteus.modules.ConfigModule; @@ -16,7 +19,8 @@ * @author jbauer * */ -public class BaseService extends AbstractIdleService +@Singleton +public abstract class BaseService extends AbstractIdleService implements Module { private static Logger log = LoggerFactory.getLogger(BaseService.class.getCanonicalName()); @@ -52,6 +56,16 @@ protected void shutDown() throws Exception { log.info("Stopping " + this.getClass().getSimpleName() ); } + + + /* (non-Javadoc) + * @see com.google.inject.Module#configure(com.google.inject.Binder) + */ + public void configure(Binder binder) + { + + + } } diff --git a/src/test/java/io/sinistral/proteus/controllers/Tests.java b/src/test/java/io/sinistral/proteus/controllers/Tests.java index fa38d8a..8bb824f 100644 --- a/src/test/java/io/sinistral/proteus/controllers/Tests.java +++ b/src/test/java/io/sinistral/proteus/controllers/Tests.java @@ -5,12 +5,8 @@ import static io.sinistral.proteus.server.ServerResponse.response; -import java.io.IOException; import java.nio.ByteBuffer; -import java.time.Instant; import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -33,7 +29,7 @@ import com.google.common.io.Files; import com.google.inject.Singleton; import com.jsoniter.output.JsonStream; - + import io.sinistral.proteus.models.User; import io.sinistral.proteus.server.ServerRequest; import io.sinistral.proteus.server.ServerResponse; @@ -41,7 +37,6 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.undertow.server.HttpServerExchange; -import io.undertow.util.HttpString; /** * @author jbauer diff --git a/src/test/java/io/sinistral/proteus/server/DefaultServer.java b/src/test/java/io/sinistral/proteus/server/DefaultServer.java index eb3296f..79fcaa7 100644 --- a/src/test/java/io/sinistral/proteus/server/DefaultServer.java +++ b/src/test/java/io/sinistral/proteus/server/DefaultServer.java @@ -47,8 +47,6 @@ public void run(final RunNotifier notifier) public void testStarted(Description description) throws Exception { - System.out.println("testStarted: " + description.getClassName() + "." + description.getMethodName()); - super.testStarted(description); } @@ -56,15 +54,11 @@ public void testStarted(Description description) throws Exception public void testFinished(Description description) throws Exception { - System.out.println("testFinished: " + description.getClassName() + "." + description.getMethodName()); - super.testFinished(description); } }); runInternal(notifier); - - super.run(notifier); } @@ -79,12 +73,10 @@ private static void runInternal(final RunNotifier notifier) app.addService(SwaggerService.class); app.addService(AssetsService.class); app.addController(Tests.class); - - app.start(); - - while(!app.isRunning()) + + while (!app.isRunning()) { try { diff --git a/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java index 244bc0f..79a0358 100644 --- a/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java +++ b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java @@ -4,267 +4,234 @@ package io.sinistral.proteus.server; import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; -import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.Arrays; -import java.util.Date; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.UUID; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; - import org.apache.commons.io.IOUtils; import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import static io.restassured.matcher.RestAssuredMatchers.*; import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.sinistral.proteus.models.User; -import io.swagger.annotations.ApiParam; - -import static io.restassured.RestAssured.*; -import static io.restassured.matcher.RestAssuredMatchers.*; -import static org.hamcrest.Matchers.*; /* -import static io.restassured.RestAssured.*; -import static io.restassured.matcher.RestAssuredMatchers.*; -import static org.hamcrest.Matchers.*; + * import static io.restassured.RestAssured.*; import static io.restassured.matcher.RestAssuredMatchers.*; import static org.hamcrest.Matchers.*; */ /** * @author jbauer - * */ @RunWith(DefaultServer.class) public class TestControllerEndpoints { - - private static String MESSAGE_JSON_RESPONSE = "{\r\n \"message\": \"Hello, World!\"\r\n}"; - private static String USER_JSON_RESPONSE = "{\r\n \"id\": 123,\r\n \"type\": \"GUEST\"\r\n}"; - private static String USER_XML_RESPONSE = "\r\n\r\n\t123\r\n\tGUEST\r\n"; - + private File file = null; - + @Before - public void setUp(){ - try + public void setUp() { - RestAssured.baseURI = "http://localhost:8090/v1"; - RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); - + try + { + RestAssured.baseURI = "http://localhost:8090/v1"; + RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); - file = new File(getClass().getClassLoader().getResource("data/video.mp4").toURI()); - - } catch (Exception e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } + file = new File(getClass().getClassLoader().getResource("data/video.mp4").toURI()); + + } catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } } - + @Test public void testSwaggerDocs() { - given().accept(ContentType.JSON).when().get("swagger.json").then().statusCode(200).and().body("basePath",is("/v1")); + given().accept(ContentType.JSON).log().uri().when().get("swagger.json").then().statusCode(200).and().body("basePath", is("/v1")); } - + @Test public void exchangeUserJson() { - User user = given().accept(ContentType.JSON).when().get("tests/exchange/user/json").as(User.class); - assertThat(user.getId(),CoreMatchers.is(123L)); + User user = given().accept(ContentType.JSON).log().uri().when().get("tests/exchange/user/json").as(User.class); + assertThat(user.getId(), CoreMatchers.is(123L)); } - + @Test public void exchangeUserXml() { - User user = given().accept(ContentType.XML).when().get("tests/exchange/user/xml").as(User.class); - assertThat(user.getId(),CoreMatchers.is(123L)); + User user = given().accept(ContentType.XML).log().uri().when().get("tests/exchange/user/xml").as(User.class); + assertThat(user.getId(), CoreMatchers.is(123L)); } - + @Test public void responseUserJson() { - User user = given().accept(ContentType.JSON).when().get("tests/response/user/json").as(User.class); - assertThat(user.getId(),CoreMatchers.is(123L)); + User user = given().accept(ContentType.JSON).log().uri().when().get("tests/response/user/json").as(User.class); + assertThat(user.getId(), CoreMatchers.is(123L)); } - + @Test public void responseUserXml() { - User user = given().accept(ContentType.XML).when().get("tests/response/user/xml").as(User.class); - assertThat(user.getId(),CoreMatchers.is(123L)); + User user = given().accept(ContentType.XML).log().uri().when().get("tests/response/user/xml").as(User.class); + assertThat(user.getId(), CoreMatchers.is(123L)); } - + @Test public void exchangePlaintext() { - given().accept(ContentType.TEXT).when().get("tests/exchange/plaintext").then().statusCode(200).and().body(containsString("Hello, World!")); - } - + given().accept(ContentType.TEXT).log().uri().when().get("tests/exchange/plaintext").then().statusCode(200).and().body(containsString("Hello, World!")); + } + @Test public void responsePlaintext() { - given().accept(ContentType.TEXT).when().get("tests/response/plaintext").then().statusCode(200).and().body(containsString("Hello, World!")); - } - + given().accept(ContentType.TEXT).log().uri().when().get("tests/response/plaintext").then().statusCode(200).and().body(containsString("Hello, World!")); + } + @Test public void responseFutureUser() { - given().log().all().accept(ContentType.JSON).when().get("tests/response/future/user").then().log().all().statusCode(200).and().body(containsString("123")); - - } - + given().accept(ContentType.JSON).log().uri().when().get("tests/response/future/user").then().statusCode(200).and().body(containsString("123")); + + } + @Test public void responseMap() { - given().log().all().accept(ContentType.JSON).when().get("tests/response/future/map").then().log().all().statusCode(200).and().body("message",is("success")); - } - + given().accept(ContentType.JSON).log().uri().when().get("tests/response/future/map").then().statusCode(200).and().body("message", is("success")); + } + @Test public void responseUploadFilePathParameter() { try { - - - final InputStream is = given().multiPart("file", file).log().uri().accept(ContentType.ANY).when().post("tests/response/file/path").asInputStream(); - + + final InputStream is = given().log().uri().multiPart("file", file).accept(ContentType.ANY).when().post("tests/response/file/path").asInputStream(); + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - IOUtils.copy(is, byteArrayOutputStream); - IOUtils.closeQuietly(byteArrayOutputStream); - IOUtils.closeQuietly(is); - - - assertThat(byteArrayOutputStream.size(), equalTo( Long.valueOf(file.length()).intValue() )); + IOUtils.copy(is, byteArrayOutputStream); + IOUtils.closeQuietly(byteArrayOutputStream); + IOUtils.closeQuietly(is); + assertThat(byteArrayOutputStream.size(), equalTo(Long.valueOf(file.length()).intValue())); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - - } - + + } + @Test public void responseUploadByteBufferParameter() { try - { + { final InputStream is = given().multiPart("file", file).log().uri().accept(ContentType.ANY).when().post("tests/response/file/bytebuffer").asInputStream(); - + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - IOUtils.copy(is, byteArrayOutputStream); - IOUtils.closeQuietly(byteArrayOutputStream); - IOUtils.closeQuietly(is); - - - assertThat(byteArrayOutputStream.size(), equalTo( Long.valueOf(file.length()).intValue() )); + IOUtils.copy(is, byteArrayOutputStream); + IOUtils.closeQuietly(byteArrayOutputStream); + IOUtils.closeQuietly(is); + + assertThat(byteArrayOutputStream.size(), equalTo(Long.valueOf(file.length()).intValue())); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - - } - + + } + @Test public void responseComplexParameters() { - /* - * @PathParam("pathLong") final Long pathLong, - @QueryParam("optionalQueryString") Optional optionalQueryString, - @QueryParam("optionalQueryDate") @ApiParam(format="date") Optional optionalQueryDate, - - - */ - + UUID randomUUID = UUID.randomUUID(); Long longValue = 123456789L; List integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); String stringValue = "TESTSTRING123!#$"; - - Map map = given().log().all() + + Map map = given() + + .log().uri() + .accept(ContentType.JSON) + .contentType("application/json") - - .queryParam("queryUUID",randomUUID) - - .queryParam("optionalQueryUUID",randomUUID) - .queryParam("queryLong",longValue) - - .queryParam("optionalQueryLong",longValue) + .queryParam("queryUUID", randomUUID) - .queryParam("optionalQueryDate","1970-01-01T00:00:00.000+00:00") + .queryParam("optionalQueryUUID", randomUUID) - .queryParam("queryEnum",User.UserType.ADMIN) - - .queryParam("optionalQueryEnum",User.UserType.ADMIN) + .queryParam("queryLong", longValue) - .queryParam("queryIntegerList",integerList) - - .queryParam("optionalQueryString",stringValue) + .queryParam("optionalQueryLong", longValue) + + .queryParam("optionalQueryDate", "1970-01-01T00:00:00.000+00:00") + + .queryParam("queryEnum", User.UserType.ADMIN) + + .queryParam("optionalQueryEnum", User.UserType.ADMIN) + + .queryParam("queryIntegerList", integerList) + + .queryParam("optionalQueryString", stringValue) .header("headerString", stringValue) - + .header("optionalHeaderString", stringValue) - + .header("optionalHeaderUUID", randomUUID) - .when().get("tests/response/parameters/complex/" + longValue.toString()).as(Map.class); - - System.out.println("map: " + map); - - assertThat( (map.get("queryUUID").toString()),CoreMatchers.is(randomUUID.toString())); - - assertThat( (map.get("optionalQueryUUID").toString()),CoreMatchers.is(randomUUID.toString())); + .when() - assertThat( (map.get("optionalHeaderUUID").toString()),CoreMatchers.is(randomUUID.toString())); + .get("tests/response/parameters/complex/" + longValue.toString()) - assertThat( (map.get("pathLong").toString()),CoreMatchers.is(longValue.toString())); + .as(Map.class); - assertThat( (map.get("optionalQueryLong").toString()),CoreMatchers.is(longValue.toString())); + assertThat((map.get("queryUUID").toString()), CoreMatchers.is(randomUUID.toString())); - assertThat( (map.get("optionalQueryEnum").toString()),CoreMatchers.is(User.UserType.ADMIN.name())); + assertThat((map.get("optionalQueryUUID").toString()), CoreMatchers.is(randomUUID.toString())); - assertThat( (map.get("queryEnum").toString()),CoreMatchers.is(User.UserType.ADMIN.name())); - - assertThat( (map.get("headerString").toString()),CoreMatchers.is(stringValue)); - - assertThat( (map.get("optionalHeaderString").toString()),CoreMatchers.is(stringValue)); - - assertThat( (map.get("optionalQueryString").toString()),CoreMatchers.is(stringValue)); + assertThat((map.get("optionalHeaderUUID").toString()), CoreMatchers.is(randomUUID.toString())); - assertThat( (map.get("optionalQueryDate").toString()),containsString("1970-01-01")); + assertThat((map.get("pathLong").toString()), CoreMatchers.is(longValue.toString())); - } - - + assertThat((map.get("optionalQueryLong").toString()), CoreMatchers.is(longValue.toString())); + + assertThat((map.get("optionalQueryEnum").toString()), CoreMatchers.is(User.UserType.ADMIN.name())); + + assertThat((map.get("queryEnum").toString()), CoreMatchers.is(User.UserType.ADMIN.name())); + + assertThat((map.get("headerString").toString()), CoreMatchers.is(stringValue)); + + assertThat((map.get("optionalHeaderString").toString()), CoreMatchers.is(stringValue)); + + assertThat((map.get("optionalQueryString").toString()), CoreMatchers.is(stringValue)); + + assertThat((map.get("optionalQueryDate").toString()), containsString("1970-01-01")); + + } } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index be93532..b70c441 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -9,7 +9,7 @@ - +