From d2838dc1d95b21be1665ea4beb1d6c55141f47e3 Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Mon, 3 Apr 2017 15:21:34 -0700 Subject: [PATCH] Generation and compilation functional. --- src/com/wurrly/BaseServer.java | 65 +- src/com/wurrly/controllers/Users.java | 16 +- src/com/wurrly/server/Extractors.java | 43 +- .../wurrly/server/GeneratedRouteHandler.java | 15 + src/com/wurrly/server/RestRoute.java | 156 ++++ src/com/wurrly/server/ServerRequest.java | 9 +- src/com/wurrly/tests/RestRouteGenerator.java | 781 ++++++++++++++++++ src/com/wurrly/tests/TestGenerator.java | 588 ------------- src/com/wurrly/utilities/HandleGenerator.java | 28 +- 9 files changed, 1056 insertions(+), 645 deletions(-) create mode 100644 src/com/wurrly/server/GeneratedRouteHandler.java create mode 100644 src/com/wurrly/server/RestRoute.java create mode 100644 src/com/wurrly/tests/RestRouteGenerator.java delete mode 100644 src/com/wurrly/tests/TestGenerator.java diff --git a/src/com/wurrly/BaseServer.java b/src/com/wurrly/BaseServer.java index a2a449c..601efc8 100644 --- a/src/com/wurrly/BaseServer.java +++ b/src/com/wurrly/BaseServer.java @@ -16,16 +16,14 @@ import com.google.inject.Injector; import com.jsoniter.DecodingMode; import com.jsoniter.JsonIterator; -import com.jsoniter.ReflectionDecoderFactory; import com.jsoniter.annotation.JsoniterAnnotationSupport; import com.jsoniter.output.EncodingMode; import com.jsoniter.output.JsonStream; -import com.jsoniter.spi.JsoniterSpi; -import com.wurrly.controllers.Users; import com.wurrly.models.User; import com.wurrly.modules.DIModule; +import com.wurrly.server.GeneratedRouteHandler; import com.wurrly.server.ServerRequest; -import com.wurrly.utilities.HandleGenerator; +import com.wurrly.tests.RestRouteGenerator; import io.undertow.Undertow; import io.undertow.UndertowOptions; @@ -33,7 +31,6 @@ 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; /** @@ -125,7 +122,7 @@ public static void main(String[] args) Injector injector = Guice.createInjector(new DIModule()); - Users usersController = injector.getInstance(Users.class); + // Users usersController = injector.getInstance(Users.class); // injector.injectMembers(usersController); @@ -136,32 +133,42 @@ public static void main(String[] args) RoutingHandler router = new RoutingHandler().setFallbackHandler(BaseHandlers::notFoundHandler); + RestRouteGenerator generator = new RestRouteGenerator("com.wurrly.controllers.handlers","RouteHandlers"); + generator.generateRoutes(); + + Class handlerClass = generator.compileRoutes(); + + Logger.debug("New class: " + handlerClass); + + GeneratedRouteHandler routeHandler = injector.getInstance(handlerClass); + + routeHandler.addRouteHandlers(router); + // 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 ); - - // router.addAll(Handlers.path().addPrefixPath(pathTemplate, handler)); - System.out.println("handler: " + handler); - - } +// 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 diff --git a/src/com/wurrly/controllers/Users.java b/src/com/wurrly/controllers/Users.java index ed7d7b2..8f9c863 100644 --- a/src/com/wurrly/controllers/Users.java +++ b/src/com/wurrly/controllers/Users.java @@ -4,21 +4,21 @@ package com.wurrly.controllers; import java.nio.ByteBuffer; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; +import java.util.UUID; +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; -import javax.ws.rs.FormParam; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,7 +27,6 @@ import com.google.inject.Singleton; import com.google.inject.name.Named; import com.jsoniter.any.Any; -import com.jsoniter.output.JsonStream; import com.typesafe.config.Config; import com.wurrly.models.User; import com.wurrly.server.ServerRequest; @@ -41,6 +40,7 @@ @Api(tags="users",produces="application/json", consumes="application/json") @Path("/api/users") @Produces(("application/json")) +@Consumes(("application/json")) @Singleton public class Users { @@ -64,10 +64,10 @@ public Users() @GET @Path("/{userId}/type") @ApiOperation(value = "Find users by id with type", nickname = "user", httpMethod = "GET", response = User.class) - public Any userType(final ServerRequest serverRequest, @PathParam("userId") final Long userId, @QueryParam("context") Optional context, @QueryParam("type") User.UserType type) + public Any userType(final ServerRequest serverRequest, @PathParam("userId") final Long userId, @QueryParam("context") Optional context, @QueryParam("type") User.UserType type, @QueryParam("uuid") UUID uuid) { // -// log.debug("esIndexName: " + esIndexName); + log.debug("uuid: " + uuid); // log.debug("configuration: " + configuration); // log.debug("context: " + context); diff --git a/src/com/wurrly/server/Extractors.java b/src/com/wurrly/server/Extractors.java index 41c7fcd..1f1bcbd 100644 --- a/src/com/wurrly/server/Extractors.java +++ b/src/com/wurrly/server/Extractors.java @@ -8,8 +8,10 @@ import java.nio.channels.FileChannel; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.Deque; -import java.util.Optional; +import java.text.SimpleDateFormat; +import java.time.ZonedDateTime; +import java.util.Date; +import java.util.Deque; import com.jsoniter.JsonIterator; import com.jsoniter.any.Any; @@ -44,6 +46,20 @@ public static final java.util.Optional typed(final HttpServerExchange exc } }); } + + public static final java.util.Optional typed(final HttpServerExchange exchange, final Class type ) + { + return jsonIterator(exchange).map(i -> { + try + { + return i.read(type); + } catch (Exception e) + { + return null; + } + }); + } + public static final java.util.Optional any(final HttpServerExchange exchange ) { @@ -89,17 +105,33 @@ public static final java.util.Optional string(final HttpServerExchange e { return java.util.Optional.ofNullable(exchange.getQueryParameters().get(name)).map(Deque::getFirst); } + + public static final java.util.Optional header(final HttpServerExchange exchange, final String name) + { + return java.util.Optional.ofNullable(exchange.getRequestHeaders().get(name)).map(Deque::getFirst); + } public static final java.util.Optional filePath(final HttpServerExchange exchange, final String name) { return java.util.Optional.ofNullable(exchange.getAttachment(FormDataParser.FORM_DATA).get(name)).map(Deque::getFirst).map(FormValue::getPath); } } + + public static Date date(final HttpServerExchange exchange,final String name) throws Throwable { + + return Date.from( ZonedDateTime.parse( string(exchange,name) ).toInstant() ); + + } public static final T typed(final HttpServerExchange exchange, final TypeLiteral type ) throws Exception { return jsonIterator(exchange).read(type); } + + public static final T typed(final HttpServerExchange exchange, final Class type ) throws Exception + { + return jsonIterator(exchange).read(type); + } public static final Any any(final HttpServerExchange exchange ) { @@ -153,6 +185,11 @@ public static final String string(final HttpServerExchange exchange, final Strin { return exchange.getQueryParameters().get(name).getFirst(); } + + public static final String header(final HttpServerExchange exchange, final String name) + { + return exchange.getRequestHeaders().get(name).getFirst(); + } public static final Long longValue(final HttpServerExchange exchange, final String name) { @@ -169,7 +206,7 @@ public static final Boolean booleanValue(final HttpServerExchange exchange, fina return Boolean.parseBoolean(string(exchange, name)); } - public static final > E enumValue(final HttpServerExchange exchange, final String name, Class clazz) + public static final > E enumValue(final HttpServerExchange exchange, Class clazz,final String name) { return Enum.valueOf(clazz, string(exchange, name)); } diff --git a/src/com/wurrly/server/GeneratedRouteHandler.java b/src/com/wurrly/server/GeneratedRouteHandler.java new file mode 100644 index 0000000..6a4603b --- /dev/null +++ b/src/com/wurrly/server/GeneratedRouteHandler.java @@ -0,0 +1,15 @@ +/** + * + */ +package com.wurrly.server; + +import io.undertow.server.RoutingHandler; + +/** + * @author jbauer + * + */ +public interface GeneratedRouteHandler +{ + public void addRouteHandlers(final RoutingHandler router); +} diff --git a/src/com/wurrly/server/RestRoute.java b/src/com/wurrly/server/RestRoute.java new file mode 100644 index 0000000..ad6585c --- /dev/null +++ b/src/com/wurrly/server/RestRoute.java @@ -0,0 +1,156 @@ +/** + * + */ +package com.wurrly.server; + +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import io.undertow.util.HttpString; + +/** + * @author jbauer + * + */ +public class RestRoute implements Comparable +{ + private HttpString method; + private String pathTemplate; + private String consumes; + private String produces; + private String controllerMethod; + private String controllerName; + + + public RestRoute() + { + + } + + /** + * @return the method + */ + public HttpString getMethod() + { + return method; + } + + /** + * @param method the method to set + */ + public void setMethod(HttpString method) + { + this.method = method; + } + + /** + * @return the pathTemplate + */ + public String getPathTemplate() + { + return pathTemplate; + } + + /** + * @param pathTemplate the pathTemplate to set + */ + public void setPathTemplate(String pathTemplate) + { + this.pathTemplate = pathTemplate; + } + + /** + * @return the consumes + */ + public String getConsumes() + { + return consumes; + } + + /** + * @param consumes the consumes to set + */ + public void setConsumes(String consumes) + { + this.consumes = consumes; + } + + /** + * @return the produces + */ + public String getProduces() + { + return produces; + } + + /** + * @param produces the produces to set + */ + public void setProduces(String produces) + { + this.produces = produces; + } + + /** + * @return the controllerMethod + */ + public String getControllerMethod() + { + return controllerMethod; + } + + /** + * @param controllerMethod the controllerMethod to set + */ + public void setControllerMethod(String controllerMethod) + { + this.controllerMethod = controllerMethod; + } + + /** + * @return the controllerName + */ + public String getControllerName() + { + return controllerName; + } + + /** + * @param controllerName the controllerName to set + */ + public void setControllerName(String controllerName) + { + this.controllerName = controllerName; + } + + + public int hashCode() + { + return new HashCodeBuilder(17, 37). + append(controllerName). + append(controllerMethod). + append(consumes). + append(produces). + append(method). + append(pathTemplate). + toHashCode(); + } + + public int compareTo(RestRoute o) { + RestRoute myClass = (RestRoute) o; + return new CompareToBuilder() + .append(this.controllerName, myClass.controllerName) + .append(this.method, myClass.method) + .append(this.controllerMethod, myClass.controllerMethod) + .toComparison(); + } + + @Override + public String toString() + { + return String.format("%-8s %-60s %-18s %-18s %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 5eb6a92..0245625 100644 --- a/src/com/wurrly/server/ServerRequest.java +++ b/src/com/wurrly/server/ServerRequest.java @@ -72,8 +72,8 @@ public ServerRequest(HttpServerExchange exchange) throws IOException this.exchange = exchange; this.contentType = exchange.getRequestHeaders().getFirst("Content-Type"); - //Logger.debug("content tyoe: " + contentType); - if (this.contentType != null) + + if (this.contentType != null ) { if (this.contentType.contains(FormEncodedDataDefinition.APPLICATION_X_WWW_FORM_URLENCODED) ) { @@ -149,10 +149,11 @@ public Map> getPathParameters() private void parseJson() throws IOException { - this.exchange.startBlocking(); if(this.exchange.getRequestContentLength() != -1) { + this.exchange.startBlocking(); + // ByteBuffer buffer = ByteBuffer.allocate((int) this.exchange.getRequestContentLength()); // this.exchange.getRequestChannel().read(buffer); // JsonIterator iterator = JsonIterator.parse(buffer.array()); @@ -228,6 +229,8 @@ private void parseJson() throws IOException } else { + this.exchange.startBlocking(); + InputStream is = exchange.getInputStream(); if (is != null) { diff --git a/src/com/wurrly/tests/RestRouteGenerator.java b/src/com/wurrly/tests/RestRouteGenerator.java new file mode 100644 index 0000000..d4eca60 --- /dev/null +++ b/src/com/wurrly/tests/RestRouteGenerator.java @@ -0,0 +1,781 @@ +/** + * + */ +package com.wurrly.tests; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.Headers; +import io.undertow.util.HttpString; +import io.undertow.util.MimeMappings; +import net.openhft.compiler.CompilerUtils; + +import java.io.File; +import java.io.PrintStream; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.lang.model.element.Modifier; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; +import javax.ws.rs.HeaderParam; + +import org.apache.commons.lang3.StringUtils; +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.AnnotationSpec; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.FieldSpec; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.TypeSpec; +import com.wurrly.server.Extractors; +import com.wurrly.server.GeneratedRouteHandler; +import com.wurrly.server.RestRoute; +import com.wurrly.server.ServerRequest; +import com.wurrly.utilities.HandleGenerator; + +/** + * @author jbauer + */ +public class RestRouteGenerator +{ + + + private static Logger log = LoggerFactory.getLogger(RestRouteGenerator.class.getCanonicalName()); + +// @Inject +// @Named("date.format") +// protected String dateFormat; + + private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("(java\\.util\\.[A-Za-z]+)<([^>]+)", Pattern.DOTALL | Pattern.UNIX_LINES); + + public static enum StatementParameterType + { + STRING, LITERAL, TYPE + } + + public static void generateTypeLiteral(MethodSpec.Builder builder, Type type, String name) + { + + builder.addCode(CodeBlock.of("\n\ncom.jsoniter.spi.TypeLiteral<$T> $L = new com.jsoniter.spi.TypeLiteral<$L>(){};\n\n", type, name, type)); + + } + + public static void generateParameterReference(MethodSpec.Builder builder, Class clazz) + { + + builder.addCode(CodeBlock.of("\n\nType $LType = $T.", clazz, clazz)); + + } + + public static enum TypeHandler + { + + LongType("Long $L = com.wurrly.server.Extractors.longValue(exchange,$S)", false, StatementParameterType.LITERAL, StatementParameterType.STRING), + IntegerType("Integer $L = com.wurrly.server.Extractors.integerValue(exchange,$S)", false, StatementParameterType.LITERAL, StatementParameterType.STRING), + StringType("String $L = com.wurrly.server.Extractors.string(exchange,$S)", false, StatementParameterType.LITERAL, StatementParameterType.STRING), + BooleanType("Boolean $L = com.wurrly.server.Extractors.booleanValue(exchange,$S)", false, StatementParameterType.LITERAL, StatementParameterType.STRING), + FilePathType("$T $L = com.wurrly.server.Extractors.filePath(exchange,$S)", true, java.nio.file.Path.class,StatementParameterType.LITERAL, StatementParameterType.STRING), + AnyType("$T $L = com.wurrly.server.Extractors.any(exchange)", true, com.jsoniter.any.Any.class, StatementParameterType.LITERAL), + JsonIteratorType("$T $L = com.wurrly.server.Extractors.jsonIterator(exchange)", true, com.jsoniter.JsonIterator.class,StatementParameterType.LITERAL), + ModelType("$T $L = com.wurrly.server.Extractors.typed(exchange,$L)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.LITERAL), + EnumType("$T $L = com.wurrly.server.Extractors.enumValue(exchange,$T.class,$S)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.TYPE, StatementParameterType.STRING), + ByteBufferType("$T $L = com.wurrly.server.Extractors.fileBytes(exchange,$S)", false, java.nio.ByteBuffer.class, StatementParameterType.LITERAL, StatementParameterType.STRING), + DateType("$T $L = com.wurrly.server.Extractors.date(exchange,$S)", false, java.util.Date.class, StatementParameterType.LITERAL, StatementParameterType.STRING), + + ValueOfType("$T $L = $T.valueOf(com.wurrly.server.Extractors.string(exchange,$S))",false, StatementParameterType.TYPE,StatementParameterType.LITERAL,StatementParameterType.TYPE, StatementParameterType.STRING), + FromStringType("$T $L = $T.fromString(com.wurrly.server.Extractors.string(exchange,$S))",false, StatementParameterType.TYPE,StatementParameterType.LITERAL,StatementParameterType.TYPE, StatementParameterType.STRING), + + HeaderValueOfType("$T $L = $T.valueOf(com.wurrly.server.Extractors.headerString(exchange,$S))",false, StatementParameterType.TYPE,StatementParameterType.LITERAL,StatementParameterType.TYPE, StatementParameterType.STRING), + HeaderFromStringType("$T $L = $T.fromString(com.wurrly.server.Extractors.headerString(exchange,$S))",false, StatementParameterType.TYPE,StatementParameterType.LITERAL,StatementParameterType.TYPE, StatementParameterType.STRING), + HeaderStringType("$T $L = com.wurrly.server.Extractors.headerString(exchange,$S)",false, java.lang.String.class,StatementParameterType.LITERAL,StatementParameterType.STRING), + + OptionalJsonIteratorType("$T<$T> $L = com.wurrly.server.Extractors.Optional.jsonIterator(exchange)", true, Optional.class, com.jsoniter.JsonIterator.class,StatementParameterType.LITERAL), + OptionalAnyType("$T<$T> $L = com.wurrly.server.Extractors.Optional.any(exchange)", true, Optional.class,com.jsoniter.any.Any.class,StatementParameterType.LITERAL), + OptionalStringType("$T $L = com.wurrly.server.Extractors.Optional.string(exchange,$S)", false, Optional.class,StatementParameterType.LITERAL, StatementParameterType.STRING), + OptionalLongType("$T $L = com.wurrly.server.Extractors.Optional.longValue(exchange,$S)", false,Optional.class, StatementParameterType.LITERAL, StatementParameterType.STRING), + OptionalIntegerType("$T $L = com.wurrly.server.Extractors.Optional.integerValue(exchange,$S)", false, Optional.class,StatementParameterType.LITERAL, StatementParameterType.STRING), + OptionalBooleanType("$T $L = com.wurrly.server.Extractors.Optional.booleanValue(exchange,$S)", false, Optional.class,StatementParameterType.LITERAL, StatementParameterType.STRING), + OptionalPathType("$T<$T> $L = com.wurrly.server.Extractors.Optional.filePath(exchange,$S)", true,Optional.class,java.nio.file.Path.class, StatementParameterType.LITERAL, StatementParameterType.STRING), + OptionalModelType("$T<$L> $L = com.wurrly.server.Extractors.Optional.typed(exchange,$L)", true, Optional.class,StatementParameterType.LITERAL,StatementParameterType.LITERAL, StatementParameterType.LITERAL), + + ; + + public boolean isBlocking() + { + return this.isBlocking; + } + + public String statement() + { + + return this.statement; + } + + final private String statement; + final private boolean isBlocking; + final private Object[] parameterTypes; + + private TypeHandler(String statement, boolean isBlocking, Object ... types) + { + this.statement = statement; + this.isBlocking = isBlocking; + this.parameterTypes = types; + } + + public static void addStatement(MethodSpec.Builder builder, Parameter parameter) throws Exception + { + TypeHandler handler = forType(parameter.getParameterizedType()); + + + + Object[] args = new Object[handler.parameterTypes.length]; + + for (int i = 0; i < handler.parameterTypes.length; i++) + { + if( handler.parameterTypes[i] instanceof StatementParameterType ) + { + StatementParameterType pType = (StatementParameterType)handler.parameterTypes[i]; + switch(pType) + { + case LITERAL: + args[i] = parameter.getName(); + break; + case STRING: + args[i] = parameter.getName(); + break; + case TYPE: + args[i] = parameter.getParameterizedType(); + break; + default: + break; + } + } + else if( handler.parameterTypes[i] instanceof Class ) + { + Class clazz = (Class)handler.parameterTypes[i]; + + args[i] = ClassName.get(clazz); + } + } + + builder.addStatement(handler.statement, args); + } + + public static TypeHandler forType(Type type) + { + boolean isEnum = false; + boolean hasValueOf = false; + boolean hasFromString = false; + + + try + { + Class clazz = Class.forName(type.getTypeName()); + + isEnum = clazz.isEnum(); + + try + { + clazz.getMethod("valueOf", java.lang.String.class); + hasValueOf = true; + + } catch (Exception e) + { + // TODO: handle exception + } + + try{ + clazz.getMethod("fromString", java.lang.String.class); + hasFromString = true; + + } catch (Exception e) + { + // TODO: handle exception + } + } catch (Exception e) + { + // TODO: handle exception + } + + // log.debug(type.getTypeName() + " " + type.toString() + " is enum " + isEnum); + + if (type.equals(Long.class)) + { + return LongType; + } + else if (type.equals(Integer.class)) + { + return IntegerType; + } + else if (type.equals(java.nio.ByteBuffer.class)) + { + return ByteBufferType; + } + else if (type.equals(Boolean.class)) + { + return BooleanType; + } + else if (type.equals(String.class)) + { + return StringType; + } + else if (type.equals(java.nio.file.Path.class)) + { + return FilePathType; + } + else if (type.equals(java.util.Date.class)) + { + return DateType; + } + else if (type.equals(com.jsoniter.any.Any.class)) + { + return AnyType; + } + else if (type.equals(com.jsoniter.JsonIterator.class)) + { + return JsonIteratorType; + } + else if (type.getTypeName().contains("java.util.Optional")) + { + if (type.getTypeName().contains("java.lang.Long")) + { + return OptionalLongType; + } + else if (type.getTypeName().contains("java.lang.String")) + { + return OptionalStringType; + } + else if (type.getTypeName().contains("java.lang.Boolean")) + { + return OptionalBooleanType; + } + else if (type.getTypeName().contains("java.lang.Integer")) + { + return OptionalIntegerType; + } + else if (type.getTypeName().contains("java.nio.file.Path")) + { + return OptionalPathType; + } + else + { + return StringType; + // throw new Exception("No type handler found!"); + } + } + else if (isEnum) + { + return EnumType; + } + else if( hasValueOf ) + { + return ValueOfType; + } + else if( hasFromString ) + { + return FromStringType; + } + else + { + return ModelType; + } + } + } + + + private List restRoutes = new ArrayList<>(); + private String packageName; + private String className; + private String sourceString; + + public static void main(String[] args) + { + RestRouteGenerator generator = new RestRouteGenerator("com.wurrly.controllers.handlers","RouteHandlers"); + + generator.generateRoutes(); + + StringBuilder sb = new StringBuilder(); + + generator.getRestRoutes().stream().forEachOrdered( r -> sb.append(r.toString() + "\n")); + + System.out.println(sb.toString()); + } + + public Class compileRoutes() + { + try + { + // JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + return CompilerUtils.CACHED_COMPILER.loadFromJava(packageName+"."+className, this.sourceString); + + + + } catch (Exception e) + { + log.error(e.getMessage(),e); + return null; + } + } + + public RestRouteGenerator(String packageName, String className) + { + this.packageName = packageName; + this.className = className; + + } + + public void generateRoutes() + { + try + { + + TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(className) + .addModifiers(Modifier.PUBLIC) + .addSuperinterface(ClassName.get(com.wurrly.server.GeneratedRouteHandler.class)); + + ClassName handleGeneratorClass = ClassName.get("com.wurrly.utilities", "HandleGenerator"); + + ClassName injectClass = ClassName.get("com.google.inject", "Inject"); + + String prefix = "com.wurrly.controllers"; + List classNames = getClassNamesFromPackage(prefix); + + MethodSpec.Builder constructor = MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addAnnotation(injectClass); + + + + for (String classNameSuffix : classNames) + { + String controllerClassName = prefix + "." + classNameSuffix; + + Class clazz = Class.forName(controllerClassName); + + String controllerName = clazz.getSimpleName().toLowerCase() + "Controller"; + + typeBuilder.addField(clazz, controllerName, Modifier.PROTECTED); + + constructor.addParameter(clazz,controllerName); + + constructor.addStatement("this.$N = $N", controllerName, controllerName); + + + addClassMethodHandlers(typeBuilder, clazz); + } + + typeBuilder.addMethod(constructor.build()); + + JavaFile javaFile = JavaFile.builder(packageName, typeBuilder.build()) + .addStaticImport(handleGeneratorClass, "*") + .build(); + + StringBuilder sb = new StringBuilder(); + + javaFile.writeTo(sb); + + this.sourceString = sb.toString(); + + + } catch (Exception e) + { + log.error(e.getMessage(),e); + } + } + + public void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class clazz) + { + ClassName httpHandlerClass = ClassName.get("io.undertow.server", "HttpHandler"); + + 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()); + + 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)); + + initBuilder.addCode("$L", "\n"); + + typeLiteralsMap.forEach((t, n) -> { + + initBuilder.addStatement("final $T<$L> $LType = new $T<$L>(){}",TypeLiteral.class, t, n, TypeLiteral.class, t); + + }); + + initBuilder.addCode("$L", "\n"); + + for (Method m : clazz.getDeclaredMethods()) + { + RestRoute route = new RestRoute(); + + route.setControllerName(clazz.getSimpleName()); + + String methodPath = HandleGenerator.extractPathTemplate.apply(m); + + log.debug("method path: " + methodPath); + + HttpString httpMethod = HandleGenerator.extractHttpMethod.apply(m); + + route.setMethod(httpMethod); + + route.setPathTemplate(methodPath); + + route.setControllerMethod( clazz.getSimpleName() + "." + m.getName() ); + + String methodName = String.format("%c%s%sHandler", Character.toLowerCase(clazz.getSimpleName().charAt(0)),clazz.getSimpleName().substring(1,clazz.getSimpleName().length()) , StringUtils.capitalize(m.getName())); + + TypeSpec.Builder handlerClassBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(httpHandlerClass); + + // handlerClassBuilder.addModifiers(Modifier.PUBLIC); + + MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("handleRequest").addModifiers(Modifier.PUBLIC).addException(ClassName.get("java.lang", "Exception")).addAnnotation(Override.class) + .addParameter(ParameterSpec.builder(HttpServerExchange.class, "exchange", Modifier.FINAL).build()); + + for (Parameter p : m.getParameters()) + { + + if (p.getParameterizedType().equals(ServerRequest.class)) + { + continue; + } + + try + { + TypeHandler t = TypeHandler.forType(p.getParameterizedType()); + + if (t.isBlocking()) + { + methodBuilder.addCode("$L", "\n"); + + methodBuilder.beginControlFlow("if(exchange.isInIoThread())"); + methodBuilder.addStatement("exchange.dispatch(this)"); + methodBuilder.addStatement("return"); + + methodBuilder.endControlFlow(); + + break; + } + + } catch (Exception e) + { + log.error(e.getMessage(), e); + } + } ; + + methodBuilder.addCode("$L", "\n"); + + Arrays.stream(m.getParameters()).forEachOrdered(p -> { + + Type type = p.getParameterizedType(); + + try + { + + if (p.getType().equals(ServerRequest.class)) + { + methodBuilder.addStatement("$T serverRequest = new $T(exchange)",ServerRequest.class,ServerRequest.class); + methodBuilder.addCode("$L", "\n"); + + } + else + { + if(p.isAnnotationPresent(HeaderParam.class)) + { + + Class t = p.getType(); + + TypeHandler handler = null; + + try + { + t.getMethod("valueOf", java.lang.String.class); + + handler = TypeHandler.HeaderValueOfType; + + methodBuilder.addStatement(handler.statement, t, p.getName(), t, p.getName()); + + } catch (Exception e) + { + } + + try + { + t.getMethod("fromString", java.lang.String.class); + + handler = TypeHandler.HeaderFromStringType; + + methodBuilder.addStatement(handler.statement, t, p.getName(), t, p.getName()); + + + } catch (Exception e) + { + + } + + if(handler == null) + { + handler = TypeHandler.HeaderStringType; + + methodBuilder.addStatement(handler.statement, p.getName(), p.getName()); + + } + + } + else + { + TypeHandler t = TypeHandler.forType(type); + + if (t.equals(TypeHandler.OptionalModelType) || t.equals(TypeHandler.ModelType)) + { + String interfaceType = typeLiteralsMap.get(type); + + String pType = interfaceType != null ? interfaceType + "Type" : type.getTypeName() + ".class"; + + methodBuilder.addStatement(t.statement, type, p.getName(), pType); + } + else + { + TypeHandler.addStatement(methodBuilder, p); + } + } + } + + } catch (Exception e) + { + log.error(e.getMessage(), e); + } + + }); + + methodBuilder.addCode("$L", "\n"); + + CodeBlock.Builder functionBlockBuilder = CodeBlock.builder(); + + String controllerMethodArgs = Arrays.stream(m.getParameters()).map(p -> p.getName()).collect(Collectors.joining(",")); + + if (!m.getReturnType().equals(Void.class)) + { + log.debug("return : " + m.getReturnType()); + functionBlockBuilder.add("$T $L = $L.$L($L);", m.getReturnType(), "response", controllerName, m.getName(), controllerMethodArgs); + + } + + methodBuilder.addCode(functionBlockBuilder.build()); + + methodBuilder.addCode("$L", "\n"); + + String producesContentType = "*/*"; + + Optional producesAnnotation = Optional.ofNullable(m.getAnnotation(javax.ws.rs.Produces.class)); + + if (!producesAnnotation.isPresent()) + { + producesAnnotation = Optional.ofNullable(clazz.getAnnotation(javax.ws.rs.Produces.class)); + + if (producesAnnotation.isPresent()) + { + producesContentType = producesAnnotation.get().value()[0]; + } + } + else + { + producesContentType = producesAnnotation.get().value()[0]; + } + + route.setProduces(producesContentType); + + String consumesContentType = "*/*"; + + Optional consumesAnnotation = Optional.ofNullable(m.getAnnotation(javax.ws.rs.Consumes.class)); + + if (!consumesAnnotation.isPresent()) + { + consumesAnnotation = Optional.ofNullable(clazz.getAnnotation(javax.ws.rs.Consumes.class)); + + if (consumesAnnotation.isPresent()) + { + consumesContentType = consumesAnnotation.get().value()[0]; + } + } + else + { + consumesContentType = consumesAnnotation.get().value()[0]; + } + + route.setConsumes(consumesContentType); + + methodBuilder.addCode("$L", "\n"); + + methodBuilder.addStatement("exchange.getResponseHeaders().put($T.CONTENT_TYPE, $S)",Headers.class, producesContentType); + + if (m.getReturnType().equals(String.class)) + { + methodBuilder.addStatement("exchange.getResponseHeaders().send($L)", "response"); + } + else + { + methodBuilder.addStatement("exchange.getResponseSender().send(com.jsoniter.output.JsonStream.serialize($L))", "response"); + } + + handlerClassBuilder.addMethod(methodBuilder.build()); + + FieldSpec handlerField = FieldSpec.builder(httpHandlerClass, methodName, Modifier.FINAL).initializer("$L", handlerClassBuilder.build()).build(); + + initBuilder.addCode("$L\n", handlerField.toString()); + + initBuilder.addStatement("$L.add(io.undertow.util.Methods.$L,$S,$L)", "router", httpMethod, methodPath, methodName); + + initBuilder.addCode("$L", "\n"); + + this.restRoutes.add(route); + } + + typeBuilder.addMethod(initBuilder.build()); + + } + + + /** + * @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 + */ + public String getPackageName() + { + return packageName; + } + + /** + * @param packageName the packageName to set + */ + public void setPackageName(String packageName) + { + this.packageName = packageName; + } + + /** + * @return the className + */ + public String getClassName() + { + return className; + } + + /** + * @param className the className to set + */ + public void setClassName(String className) + { + this.className = className; + } + + + public static ArrayList getClassNamesFromPackage(String packageName) throws Exception + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + URL packageURL; + ArrayList names = new ArrayList();; + + packageName = packageName.replace(".", "/"); + packageURL = classLoader.getResource(packageName); + + log.debug(packageURL + ""); + + URI uri = new URI(packageURL.toString()); + File folder = new File(uri.getPath()); + // won't work with path which contains blank (%20) + // File folder = new File(packageURL.getFile()); + File[] contenuti = folder.listFiles(); + String entryName; + for (File actual : contenuti) + { + if (actual.isDirectory()) + { + continue; + } + log.debug(actual + ""); + entryName = actual.getName(); + entryName = entryName.substring(0, entryName.lastIndexOf('.')); + names.add(entryName); + } + + return names; + } + + public static String typeLiteralNameForType(Type type) + { + String typeName = type.getTypeName(); + + Matcher matcher = TYPE_NAME_PATTERN.matcher(typeName); + + if (matcher.find()) + { + + int matches = matcher.groupCount(); + + if (matches == 2) + { + String genericInterface = matcher.group(1); + String erasedType = matcher.group(2).replaceAll("\\$", "."); + + String[] genericParts = genericInterface.split("\\."); + String[] erasedParts = erasedType.split("\\."); + + String genericTypeName = genericParts[genericParts.length - 1]; + String erasedTypeName = null; + + if (erasedParts.length > 1) + { + erasedTypeName = erasedParts[erasedParts.length - 2] + erasedParts[erasedParts.length - 1]; + } + else + { + erasedTypeName = erasedParts[0]; + } + + return String.format("%s%s%s", Character.toLowerCase(erasedTypeName.charAt(0)), erasedTypeName.substring(1, erasedTypeName.length()), genericTypeName); + } + + } + + return typeName; + } + +} diff --git a/src/com/wurrly/tests/TestGenerator.java b/src/com/wurrly/tests/TestGenerator.java deleted file mode 100644 index c1a34ab..0000000 --- a/src/com/wurrly/tests/TestGenerator.java +++ /dev/null @@ -1,588 +0,0 @@ -/** - * - */ -package com.wurrly.tests; - -import io.undertow.server.HttpServerExchange; -import io.undertow.util.HttpString; -import io.undertow.util.MimeMappings; - -import java.io.File; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.lang.reflect.Type; -import java.net.URI; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import javax.lang.model.element.Modifier; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.squareup.javapoet.AnnotationSpec; -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.CodeBlock; -import com.squareup.javapoet.FieldSpec; -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; -import com.squareup.javapoet.TypeSpec; -import com.wurrly.server.Extractors; -import com.wurrly.server.ServerRequest; -import com.wurrly.utilities.HandleGenerator; - -/** - * @author jbauer - * - */ -public class TestGenerator -{ - private static Logger log = LoggerFactory.getLogger(TestGenerator.class.getCanonicalName()); - - private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("(java\\.util\\.[A-Za-z]+)<([^>]+)",Pattern.DOTALL | Pattern.UNIX_LINES); - - public static enum StatementParameterType - { - STRING,LITERAL,TYPE - } - - public static void generateTypeLiteral( MethodSpec.Builder builder, Type type, String name) - { - - builder.addCode(CodeBlock.of("\n\ncom.jsoniter.spi.TypeLiteral<$T> $L = new com.jsoniter.spi.TypeLiteral<$L>(){};\n\n",type,name,type)); - - } - - - public static void generateParameterReference( MethodSpec.Builder builder, Class clazz ) - { - - builder.addCode(CodeBlock.of("\n\nType $LType = $T.",clazz,clazz)); - - } - - public static enum TypeHandler - { - - LongType("Long $L = Extractors.longValue(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - IntegerType("Integer $L = Extractors.integerValue(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - StringType("String $L = Extractors.string(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - BooleanType("Boolean $L = Extractors.booleanValue(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - FilePathType("Path $L = Extractors.filePath(exchange,$S)",true,StatementParameterType.LITERAL,StatementParameterType.STRING), - AnyType("Any $L = Extractors.any(exchange)",true,StatementParameterType.LITERAL), - JsonIteratorType("JsonIterator $L = Extractors.jsonIterator(exchange)",true,StatementParameterType.LITERAL), - ModelType("$T $L = Extractors.typed(exchange,$L)",true,StatementParameterType.TYPE,StatementParameterType.LITERAL,StatementParameterType.LITERAL), - EnumType("$T $L = Extractors.extractEnum(exchange,$L.class,$S)",true,StatementParameterType.TYPE,StatementParameterType.LITERAL,StatementParameterType.LITERAL,StatementParameterType.STRING), - ByteBufferType("ByteBuffer $L = Extractors.fileBytes(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - - OptionalJsonIteratorType("Optional $L = Extractors.Optional.jsonIterator(exchange)",true,StatementParameterType.LITERAL), - OptionalAnyType("Optional $L = Extractors.Optional.any(exchange)",true,StatementParameterType.LITERAL), - OptionalStringType("Optional $L = Extractors.Optional.string(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - OptionalLongType("Optional $L = Extractors.Optional.longValue(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - OptionalIntegerType("Optional $L = Extractors.Optional.integerValue(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - OptionalBooleanType("Optional $L = Extractors.Optional.booleanValue(exchange,$S)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), - OptionalPathType("Optional $L = Extractors.Optional.filePath(exchange,$S)",true,StatementParameterType.LITERAL,StatementParameterType.STRING), - OptionalModelType("Optional $L = Extractors.Optional.typed(exchange,$L)",true,StatementParameterType.LITERAL,StatementParameterType.LITERAL), - - ; - - public boolean isBlocking() - { - return this.isBlocking; - } - - public String statement() - { - - return this.statement; - } - - final private String statement; - final private boolean isBlocking; - final private StatementParameterType[] parameterTypes; - - - private TypeHandler(String statement, boolean isBlocking, StatementParameterType ... types) - { - this.statement = statement; - this.isBlocking = isBlocking; - this.parameterTypes = types; - } - - public static void addStatement(MethodSpec.Builder builder, Parameter parameter) throws Exception - { - TypeHandler handler = forType(parameter.getParameterizedType()); - - - - Object[] args = new Object[handler.parameterTypes.length]; - - for( int i = 0; i < handler.parameterTypes.length; i++ ) - { - switch(handler.parameterTypes[i]) - { - case LITERAL: - args[i] = parameter.getName(); - break; - case STRING: - args[i] = parameter.getName(); - break; - case TYPE: - args[i] = parameter.getParameterizedType(); - break; - default: - break; - - } - } - - builder.addStatement( handler.statement, args); - } - - public static TypeHandler forType( Type type ) - { - boolean isEnum = false; - - try - { - Class clazz = Class.forName(type.getTypeName()); - isEnum = clazz.isEnum(); - - } catch (Exception e) - { - // TODO: handle exception - } - - // log.debug(type.getTypeName() + " " + type.toString() + " is enum " + isEnum); - - if( type.equals( Long.class ) ) - { - return LongType; - } - else if( type.equals( Integer.class ) ) - { - return IntegerType; - } - else if( type.equals( java.nio.ByteBuffer.class ) ) - { - return ByteBufferType; - } - else if( type.equals( Boolean.class ) ) - { - return BooleanType; - } - else if( type.equals( String.class ) ) - { - return StringType; - } - else if( type.equals( java.nio.file.Path.class ) ) - { - return FilePathType; - } - else if( type.equals( com.jsoniter.any.Any.class ) ) - { - return AnyType; - } - else if( type.equals( com.jsoniter.JsonIterator.class ) ) - { - return JsonIteratorType; - } - else if( type.getTypeName().contains("java.util.Optional") ) - { - if( type.getTypeName().contains("java.lang.Long")) - { - return OptionalLongType; - } - else if( type.getTypeName().contains("java.lang.String")) - { - return OptionalStringType; - } - else if( type.getTypeName().contains("java.lang.Boolean")) - { - return OptionalBooleanType; - } - else if( type.getTypeName().contains("java.lang.Integer")) - { - return OptionalIntegerType; - } - else if( type.getTypeName().contains("java.nio.file.Path")) - { - return OptionalPathType; - } - else - { - return StringType; - //throw new Exception("No type handler found!"); - } - } - else if( isEnum ) - { - return EnumType; - } - else - { - return ModelType; - } - } - } - - public static String typeLiteralNameForType( Type type ) - { - String typeName = type.getTypeName(); - - Matcher matcher = TYPE_NAME_PATTERN.matcher(typeName); - - if (matcher.find()) { - - int matches = matcher.groupCount(); - - if( matches == 2 ) - { - String genericInterface = matcher.group(1); - String erasedType = matcher.group(2).replaceAll("\\$", "."); - - String[] genericParts = genericInterface.split("\\."); - String[] erasedParts = erasedType.split("\\."); - - String genericTypeName = genericParts[genericParts.length-1]; - String erasedTypeName = null; - - if(erasedParts.length > 1) - { - erasedTypeName = erasedParts[erasedParts.length-2] + erasedParts[erasedParts.length-1]; - } - else - { - erasedTypeName = erasedParts[0]; - } - - return String.format("%s%s%s",Character.toLowerCase(erasedTypeName.charAt(0)),erasedTypeName.substring(1,erasedTypeName.length()),genericTypeName); - } - - } - - return typeName; - } - - public static void main(String[] args) - { - - try - { - TypeSpec.Builder typeBuilder = TypeSpec.classBuilder("RouteHandlers"); - typeBuilder.addModifiers(Modifier.PUBLIC,Modifier.STATIC); - - ClassName controllersClass = ClassName.get("com.wurrly.controllers", "Users"); - - ClassName serverRequestClass = ClassName.get("com.wurrly.utilities", "ServerRequest"); - ClassName handleGeneratorClass = ClassName.get("com.wurrly.utilities", "HandleGenerator"); - ClassName filePathClass = ClassName.get("java.nio.file","Path"); - ClassName dequeClass = ClassName.get("java.util","Deque"); - ClassName optionalClass = ClassName.get("java.util","Optional"); - ClassName jsonIteratorClass = ClassName.get(com.jsoniter.JsonIterator.class); - ClassName jsonAnyClass = ClassName.get(com.jsoniter.any.Any.class); - ClassName jsonStreamClass = ClassName.get(com.jsoniter.output.JsonStream.class); - - ClassName formDataDefinitionClass = ClassName.get("io.undertow.server.form", "FormData" ); - ClassName formDataClass = ClassName.get("io.undertow.server.form","FormEncodedDataDefinition" ); - ClassName formParserDefinitionClass = ClassName.get("io.undertow.server.form", "MultiPartParserDefinition" ); - - ClassName.get("io.undertow","Undertow"); - ClassName extractors = ClassName.get("com.wurrly.server","Extractors"); - - ClassName.get("io.undertow","UndertowOptions"); - ClassName exchangeClass = ClassName.get("io.undertow.server","HttpServerExchange"); - ClassName.get("io.undertow.server","RoutingHandler"); - ClassName.get("io.undertow.util","Headers"); - - ClassName injectClass = ClassName.get("com.google.inject","Inject"); - ClassName namedClass = ClassName.get("com.google.inject.name","Named"); - - String prefix = "com.wurrly.controllers"; - List classNames = getClassNamesFromPackage(prefix); - - - - for( String classNameSuffix : classNames) - { - String className = prefix + "." + classNameSuffix; - - Class clazz = Class.forName(className); - - addClassMethodHandlers(typeBuilder, clazz); - } - - - JavaFile javaFile = JavaFile.builder("com.wurrly.controllers.handlers", typeBuilder.build()) - .addStaticImport(handleGeneratorClass, "*") - .build(); - - javaFile.writeTo(System.out); - - - } catch (Exception e) - { - e.printStackTrace(); - } - - } - - public static void addClassMethodHandlers( TypeSpec.Builder typeBuilder, Class clazz ) - { - ClassName httpHandlerClass = ClassName.get("io.undertow.server","HttpHandler"); - ClassName exchangeClass = ClassName.get("io.undertow.server","HttpServerExchange"); - - - String controllerName = clazz.getSimpleName().toLowerCase() + "Controller"; - - FieldSpec.Builder fieldBuilder = FieldSpec.builder(clazz, controllerName, Modifier.PROTECTED); - - ClassName injectClass = ClassName.get("com.google.inject","Inject"); - - fieldBuilder.addAnnotation(AnnotationSpec.builder(injectClass).build()); - - typeBuilder.addField(fieldBuilder.build()); - - - - MethodSpec.Builder initBuilder = MethodSpec.methodBuilder("addRouteHandlers").addModifiers(Modifier.PUBLIC) - .addParameter(ParameterSpec.builder( io.undertow.server.RoutingHandler.class, "router", Modifier.FINAL).build()); - - final Map allParameterTypeMap = 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(), TestGenerator::typeLiteralNameForType)); - - - initBuilder.addCode("$L","\n"); - - - allParameterTypeMap.forEach( (t,n) -> { - - initBuilder.addStatement("final TypeLiteral<$L> $LType = new TypeLiteral<$L>(){}",t,n,t); - - }); - - initBuilder.addCode("$L","\n"); - - - - for( Method m : com.wurrly.controllers.Users.class.getDeclaredMethods() ) - { - String methodPath = HandleGenerator.extractPathTemplate.apply(m); - - log.debug("method path: " + methodPath); - - HttpString httpMethod = HandleGenerator.extractHttpMethod.apply(m); - - String methodName = m.getName() + StringUtils.capitalize(httpMethod.toString().toLowerCase()) + "Handler"; - - - TypeSpec.Builder handlerClassBuilder = TypeSpec.anonymousClassBuilder("") - .addSuperinterface(httpHandlerClass); - - - - - //handlerClassBuilder.addModifiers(Modifier.PUBLIC); - - MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("handleRequest").addModifiers(Modifier.PUBLIC) - .addException(ClassName.get("java.lang","Exception")) - .addAnnotation(Override.class) - .addParameter(ParameterSpec.builder(HttpServerExchange.class, "exchange", Modifier.FINAL).build()); - - - - - - - for( Parameter p : m.getParameters() ) - { - - if(p.getParameterizedType().equals(ServerRequest.class)) - { - continue; - } - - try - { - TypeHandler t = TypeHandler.forType(p.getParameterizedType()); - - - if(t.isBlocking()) - { - methodBuilder.addCode("$L","\n"); - - methodBuilder.beginControlFlow("if(exchange.isInIoThread())"); - methodBuilder.addStatement("exchange.dispatch(this)"); - methodBuilder.endControlFlow(); - - break; - } - - } catch (Exception e) - { - log.error(e.getMessage(),e); - } - }; - - methodBuilder.addCode("$L","\n"); - - - Arrays.stream(m.getParameters()).forEachOrdered( p -> { - - Type type = p.getParameterizedType(); - - try - { - - - if(p.getType().equals(ServerRequest.class)) - { - methodBuilder.addCode(CodeBlock.of("ServerRequest serverRequest = new ServerRequest(exchange);\n")); - methodBuilder.addCode("$L","\n"); - - } - else - { - TypeHandler t = TypeHandler.forType(type); - - if(t.equals(TypeHandler.OptionalModelType) || t.equals(TypeHandler.ModelType)) - { - methodBuilder.addStatement(t.statement,type,allParameterTypeMap.get(type),type); - } - else - { - TypeHandler.addStatement(methodBuilder,p); - } - } - - } catch (Exception e) - { - log.error(e.getMessage(),e); - } - - }); - - methodBuilder.addCode("$L","\n"); - - CodeBlock.Builder functionBlockBuilder = CodeBlock.builder(); - - String controllerMethodArgs = Arrays.stream(m.getParameters()).map( p -> p.getName() ).collect(Collectors.joining(",")); - - if( !m.getReturnType().equals(Void.class)) - { - log.debug("return : " + m.getReturnType()); - functionBlockBuilder.add("$T $L = $L.$L($L);", m.getReturnType(), "response", controllerName, m.getName(), controllerMethodArgs ); - - } - - methodBuilder.addCode(functionBlockBuilder.build()); - - methodBuilder.addCode("$L","\n"); - - String returnContentType = MimeMappings.DEFAULT.getMimeType("json"); - - Optional producesAnnotation = Optional.ofNullable(m.getAnnotation(javax.ws.rs.Produces.class)); - - if( !producesAnnotation.isPresent() ) - { - producesAnnotation = Optional.ofNullable(clazz.getAnnotation(javax.ws.rs.Produces.class)); - - if( producesAnnotation.isPresent() ) - { - returnContentType = producesAnnotation.get().value()[0]; - } - } - else - { - returnContentType = producesAnnotation.get().value()[0]; - } - - methodBuilder.addCode("$L","\n"); - - methodBuilder.addStatement("exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, $S)",returnContentType); - - if( m.getReturnType().equals(String.class)) - { - methodBuilder.addStatement("exchange.getResponseHeaders().send($L)","response"); - } - else - { - methodBuilder.addStatement("exchange.getResponseSender().send(com.jsoniter.output.JsonStream.serialize($L))","response"); - } - - - handlerClassBuilder.addMethod(methodBuilder.build()); - - - FieldSpec handlerField = FieldSpec.builder(httpHandlerClass, methodName, Modifier.FINAL).initializer("$L",handlerClassBuilder.build() ).build(); - - - - - - - - initBuilder.addCode("$L\n",handlerField.toString()); - - initBuilder.addStatement("$L.add(io.undertow.util.Methods.$L,$S,$L)", "router", httpMethod,methodPath, methodName); - - initBuilder.addCode("$L","\n"); - } - - typeBuilder.addMethod(initBuilder.build()); - - - } - - public static ArrayList getClassNamesFromPackage(String packageName) throws Exception{ - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - URL packageURL; - ArrayList names = new ArrayList();; - - packageName = packageName.replace(".", "/"); - packageURL = classLoader.getResource(packageName); - - log.debug(packageURL+""); - - - URI uri = new URI(packageURL.toString()); - File folder = new File(uri.getPath()); - // won't work with path which contains blank (%20) - // File folder = new File(packageURL.getFile()); - File[] contenuti = folder.listFiles(); - String entryName; - for(File actual: contenuti){ - if(actual.isDirectory()) - { - continue; - } - log.debug(actual+""); - entryName = actual.getName(); - entryName = entryName.substring(0, entryName.lastIndexOf('.')); - names.add(entryName); - } - - return names; - } - -} diff --git a/src/com/wurrly/utilities/HandleGenerator.java b/src/com/wurrly/utilities/HandleGenerator.java index 1358b66..3878f24 100644 --- a/src/com/wurrly/utilities/HandleGenerator.java +++ b/src/com/wurrly/utilities/HandleGenerator.java @@ -226,17 +226,17 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception { try { - - if(exchange.isInIoThread()) - { - // Logger.debug("in io thread"); - exchange.dispatch(this); - return; - } - else - { - // Logger.debug("not in io thread"); - } +// +// if(exchange.isInIoThread()) +// { +// // Logger.debug("in io thread"); +// exchange.dispatch(this); +// return; +// } +// else +// { +// // Logger.debug("not in io thread"); +// } //Logger.debug("is dispatched: " + exchange.isDispatched()); //Logger.debug("exchange.getConnection().getWorker(): " + exchange.getConnection().getWorker()); @@ -244,7 +244,7 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception final ServerRequest request = new ServerRequest(exchange); - //final Long id = extractLong(exchange,"userId"); + final Long id = extractLong(exchange,"userId"); java.util.List t; @@ -256,9 +256,9 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception //final Any json = target.userForm(request, id, context, userType, Extractors.fileBytes(exchange, "testFile")); - TypeLiteral> typeLiteral = TypeLiteral.create(types[2]); + //TypeLiteral> typeLiteral = TypeLiteral.create(types[2]); - final Any json = target.createUser(request, context, Extractors.typed(exchange, typeLiteral)); + final Any json = target.user(request, id, context ); // json.whenComplete( ( u, e ) -> { //