diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cc788b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.cache* +.settings/* +.project +.settings +.cache +.target +*.class +target +project/target +project/project +log +*log +logs +logs/* +tmp +logFile* +.DS_STORE +.DS_STORE? +error.log +admin.log +bin +.classpath +.settings/org.scala-ide.sdt.core.prefs +.cache-tests \ No newline at end of file diff --git a/conf/application.conf b/conf/application.conf new file mode 100644 index 0000000..420cf6e --- /dev/null +++ b/conf/application.conf @@ -0,0 +1,190 @@ + +# images +image.size.min=120 +image.size.max=3200 +image.quality.max=80 + +# cassandra + + +cassandra.keyspace="wurrly" +cassandra.queryLimit=100 +cassandra.connections.max=100 +cassandra.connections.min=5 + +#redis + +redis.port=6379 +redis.password=null +redis.maxTotal=1024 +redis.maxIdle=10 +redis.minIdle=5 + +#elasticsearch + +es.index.name="wurrly" + + + +#graph + +graph.enabled = true + +# analytics + +events.batch.size=10 + +# okhttp + +okhttp.timeout=10 + +# azure + +azure.accountName="wurrly" +azure.accessKey.primary="lQyT2OeOYeNoYh/NX58LKCMFue6YYp7gjWLvH+2c5oq1s/jE0ur6kkN25oWn5vGDYdQgREmaZZHI6qpjs/FlnA==" +azure.accessKey.secondary="qYB2MkSrgsEAiXfFCVfG0xK7DDkmRCI8Y1KH0iWaQz+k+OdbLyOO8jax+ZqStWg0XIQL1SA099eUEcWGtCjRIA==" + +#ebean models + +ebean.default=[ "models.MediaContent", "models.VideoOverlay", "models.Mask", "models.ContentResource", "models.Content", "models.Hero", "models.Battle", "models.Tip", "models.PlaylistCategory", "models.Collaboration", "models.Review", "models.Collaborator", "models.CollaboratorComment", "models.MediaPurchase","models.AdminActivity","models.Playlist","models.SongTrack","models.Feature","models.Publisher","models.Label","models.Credentials","models.WurrlyModel","models.ArtistFact","models.ArtistQuestion","models.Property","models.Artist","models.Wurrly","models.Song","models.Report","models.Competition","models.Event","models.Comment", "models.User","models.adapter.UserEntityListener","models.adapter.SongEntityListener","models.adapter.WurrlyEntityListener"] + +# akka + +subsystem.worker.count=12 +subsystem.worker.timeout=60000 + +# netty + +play.http.parser.maxMemoryBuffer=256000K +play.http.parser.maxDiskBuffer=256000K + +# location + +location.country.db.path="support/geo/Country.mmdb" +location.city.db.path="support/geo/City.mmdb" +location.iso.codes.path="support/geo/territories.json" +location.default.region="GB" + +# hashids + +hashids.salt="3C0B0AEF-794F-4D89-9EEE-476CE9A89DFB" + +# newrelic + +newrelic.license.key="a9bfbe086c5964de4617fa0280077dd2273d3a6b" + +# users + +user.feed.item.limit=1500 +user.default.avatarPath="4c/50/b8/36/e7e2bf69ca.png" +user.default.bannerPath="57/60/9b/8f/61341a91f0.png" +user.password.backdoor="happyasaclamindecember" + + +# google cloud messaging + +gcm.senderId=1095155988888 +gcm.apiKey="AIzaSyDbHS8u7LEZQcr3_WooM5Ib-DUEU8HTCfU" + + +# twilio + +twilio.number="+16467987759" +twilio.sid="AC8a33a9fc51927ccd980ac919cdadcba5" +twilio.token="de44558f9a980b337512eb60b812f31a" + + + +#api + +api.authentication.header="X-Wurrly-Auth" +api.authentication.key="213fe69502445ed67ae8b99d22838802" + +# hfa +hfa.royaltyId.length=10 + +# shopify +shopify.api.key=769375b638f4a6132df62f3c10fdab21 +shopify.api.password=7f950bbb21cf43c0afe8c050907993b3 +shopify.api.secret=a9c0ebee8d529e05ded128c1738afbcb +shopify.login="josh@wurrly.com" +shopify.password="wuRR1y" +shopify.authorization="Basic NzY5Mzc1YjYzOGY0YTYxMzJkZjYyZjNjMTBmZGFiMjE6N2Y5NTBiYmIyMWNmNDNjMGFmZThjMDUwOTA3OTkzYjM=" +shopify.shop.url="https://wurrly.myshopify.com/admin" +shopify.expiration.days=6 +shopify.product.image.prefix="http://cdn1.wurrly.co/images/w550/" +shopify.domain="wurrly.myshopify.com" +shopify.channel.mobile="23087876" +shopify.product.price="1.99" + +#migration +migration.baseUrl="http://imaging.wurrly.co:4444/wurrlies?" + +#itms +itms.secret="a1f89c67d6e34599b1056b3f42f1c735" +itms.verification.production.url="https://buy.itunes.apple.com/verifyReceipt" +itms.verification.sandbox.url="https://sandbox.itunes.apple.com/verifyReceipt" + +#subscriptions + +user.max.wurrlies=20 + +#notifications + +notifications.enabled=1 + +#collaborations + +collaborations.maxUsers=4 + +#mailchimp + + +mailchimp.base.url="https://us9.api.mailchimp.com/3.0/" + +#password + +user.default.password="$2a$10$6T5QVxo16r7qoSdwm9Hx/.rJzWuMQEFoJ6X/VL0DKY0uxaO.XSjBa" + +#battles + +battle.voting.duration=48 + +#sift + +sift.api.key="GT4cFVEZegH4N5jxq5rj" +sift.api.url="https://wur28vu8.pottymouthfilter.com/v1/" + + +# The application languages +# ~~~~~ + + +# Router +# ~~~~~ +# Define the Router object to use for this application. +# This router will be looked up first when the application is starting up, +# so make sure this is the entry point. +# Furthermore, it's assumed your route file is named properly. +# So for an application router like `my.application.Router`, +# you may need to define a router file `conf/my.application.routes`. +# Default to Routes in the root package (and conf/routes) +# play.http.router = my.application.Routes + +# Database configuration +# ~~~~~ +# You can declare as many datasources as you want. +# By convention, the default datasource is named `default` +# +# db.default.driver=org.h2.Driver +# db.default.url="jdbc:h2:mem:play" +# db.default.username=sa +# db.default.password="" + +# Evolutions +# ~~~~~ +# You can disable evolutions if needed +# play.evolutions.enabled=false + +# You can disable evolutions for a specific datasource if necessary +# play.evolutions.db.default.enabled=false diff --git a/conf/logback.xml b/conf/logback.xml new file mode 100644 index 0000000..39aa07f --- /dev/null +++ b/conf/logback.xml @@ -0,0 +1,115 @@ + + + + + true + + + + [%d{ISO8601}]-[%thread] %highlight(%-5level) [%boldCyan(%logger)] - %boldWhite(%message) %n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..7e5698d --- /dev/null +++ b/pom.xml @@ -0,0 +1,149 @@ + + 4.0.0 + wurrly-undertow + wurrly-undertow + 0.0.1-SNAPSHOT + + src + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + + + com.google.guava + guava + 21.0 + + + com.typesafe + config + 1.3.1 + + + com.fasterxml.jackson.core + jackson-annotations + 2.8.7 + + + + com.fasterxml.jackson.core + jackson-core + 2.8.7 + + + + com.fasterxml.jackson.core + jackson-databind + 2.8.7 + + + io.swagger + swagger-annotations + 1.5.12 + + + io.swagger + swagger-core + 1.5.12 + + + ch.qos.logback + logback-classic + 1.2.1 + + + + org.hashids + hashids + 1.0.1 + + + com.squareup.okhttp3 + okhttp + 3.6.0 + + + com.squareup.okhttp3 + okhttp-urlconnection + 3.6.0 + + + com.squareup.okhttp3 + okcurl + 3.6.0 + + + com.squareup.retrofit2 + retrofit + 2.2.0 + + + com.squareup.retrofit2 + adapter-java8 + 2.2.0 + + + com.squareup.retrofit2 + converter-jackson + 2.2.0 + + + com.squareup.okhttp3 + logging-interceptor + 3.6.0 + + + org.javassist + javassist + 3.22.0-CR1 + + + com.jsoniter + jsoniter + 0.9.8 + + + io.undertow + undertow-core + 1.4.11.Final + + + org.msgpack + jackson-dataformat-msgpack + 0.8.12 + + + com.fasterxml.jackson.module + jackson-module-afterburner + 2.8.7 + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + 2.8.7 + + + org.glassfish.jersey + jax-rs-ri + 2.0-rc1 + + + com.squareup + javapoet + 1.8.0 + + + com.google.inject + guice + 4.1.0 + + + \ No newline at end of file diff --git a/src/com/wurrly/BaseServer.java b/src/com/wurrly/BaseServer.java new file mode 100644 index 0000000..787b782 --- /dev/null +++ b/src/com/wurrly/BaseServer.java @@ -0,0 +1,293 @@ +/** + * + */ +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 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.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.utilities.HandleGenerator; +import com.wurrly.utilities.ServerRequest; + +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 DIModule()); + + + Users usersController = injector.getInstance(Users.class); + + // injector.injectMembers(usersController); + + + JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH); + JsonStream.setMode(EncodingMode.DYNAMIC_MODE); + JsoniterAnnotationSupport.enable(); + + RoutingHandler router = new RoutingHandler().setFallbackHandler(BaseHandlers::notFoundHandler); + +// 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); + + } + +// 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); + + } + + + + } ); + + + Undertow server = Undertow.builder() + .addHttpListener(8090, "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() * 2) + .setHandler(new HttpHandler() + { + @Override + public void handleRequest(final HttpServerExchange exchange) throws Exception + { + try + { +// if(exchange.isInIoThread()) +// { +// exchange.dispatch(this); +// return; +// } + + + 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 new file mode 100644 index 0000000..30400e5 --- /dev/null +++ b/src/com/wurrly/controllers/Users.java @@ -0,0 +1,116 @@ +/** + * + */ +package com.wurrly.controllers; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import javax.ws.rs.GET; +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.inject.Inject; +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.utilities.ServerRequest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * User API + */ +@Api(tags="users",produces="application/json", consumes="application/json") +@Path("/api/users") +@Produces(("application/json")) +@Singleton +public class Users +{ + + @Inject + @Named("es.index.name") + protected String esIndexName; + + @Inject + protected Config configuration; + + private static Logger log = LoggerFactory.getLogger(Users.class.getCanonicalName()); + + + public Users() + { + + } + + + @GET + @Path("/{userId}") + @ApiOperation(value = "Find users by id", nickname = "user", httpMethod = "GET", response = JsonNode.class) + public Any user(final ServerRequest serverRequest, @PathParam("userId") final Long userId, @QueryParam("context") Optional context) + { +// +// log.debug("esIndexName: " + esIndexName); +// log.debug("configuration: " + configuration); + +// log.debug("context: " + context); +// +// + return Any.wrap(new User(userId)); + + } + + + @POST + @Path("/") +// @ApiImplicitParams({ @ApiImplicitParam(dataType = "com.wurrly.models.User", name = "user", paramType = "body", required = false, allowMultiple = false) }) + @ApiOperation(value = "Find users by id", nickname = "user", httpMethod = "POST", response = JsonNode.class) + public User createUser(final ServerRequest serverRequest, @QueryParam("context") Optional context, final User user ) + { +// + +// log.debug("context: " + context); +// log.debug("request: " + serverRequest); +// log.debug("file: " + user); + + return user; + + + + } + + @PUT + @Path("/{userId}/username") +// @ApiImplicitParams({ @ApiImplicitParam(dataType = "com.wurrly.models.User", name = "user", paramType = "body", required = false, allowMultiple = false) }) + @ApiOperation(value = "Update a user's name", nickname = "updateUsername", httpMethod = "PUT", response = JsonNode.class) + public Any updateUsername(final ServerRequest serverRequest, @QueryParam("context") Optional context, final User user ) + { +// + log.debug("esIndexName: " + esIndexName); + log.debug("context: " + context); + log.debug("request: " + serverRequest); + log.debug("file: " + user); + + + return Any.wrap(user); + + } + + + +} diff --git a/src/com/wurrly/models/User.java b/src/com/wurrly/models/User.java new file mode 100644 index 0000000..1423b25 --- /dev/null +++ b/src/com/wurrly/models/User.java @@ -0,0 +1,38 @@ +/** + * + */ +package com.wurrly.models; + +public class User +{ + private Long id = 0l; + + public User() + { + + } + + public User(Long id) + { + this.id = id; + } + + /** + * @return the id + */ + public Long getId() + { + return id; + } + + /** + * @param id the id to set + */ + public void setId(Long id) + { + this.id = id; + } + + + +} \ No newline at end of file diff --git a/src/com/wurrly/modules/DIModule.java b/src/com/wurrly/modules/DIModule.java new file mode 100644 index 0000000..a0f056f --- /dev/null +++ b/src/com/wurrly/modules/DIModule.java @@ -0,0 +1,112 @@ +/** + * + */ +package com.wurrly.modules; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map.Entry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.AbstractModule; +import com.google.inject.Binder; +import com.google.inject.Key; +import com.google.inject.name.Named; +import com.google.inject.name.Names; +import com.google.inject.util.Types; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigObject; +import com.typesafe.config.ConfigValue; + +/** + * @author jbauer + */ +public class DIModule extends AbstractModule +{ + private static Logger log = LoggerFactory.getLogger(DIModule.class.getCanonicalName()); + + + /* + * (non-Javadoc) + * @see com.google.inject.AbstractModule#configure() + */ + @Override + protected void configure() + { + + log.debug("configuring..."); + + this.bindConfig(this.binder(), fileConfig("application.conf")); + + } + + @SuppressWarnings("unchecked") + private void bindConfig(final Binder binder, final Config config) + { + // root nodes + traverse(binder, "", config.root()); + + + // terminal nodes + for (Entry entry : config.entrySet()) + { + String name = entry.getKey(); + Named named = Names.named(name); + Object value = entry.getValue().unwrapped(); + if (value instanceof List) + { + List values = (List) value; + Type listType = values.size() == 0 ? String.class : Types.listOf(values.iterator().next().getClass()); + Key key = (Key) Key.get(listType, Names.named(name)); + binder.bind(key).toInstance(values); + } + else + { + binder.bindConstant().annotatedWith(named).to(value.toString()); + } + } + // bind config + binder.bind(Config.class).toInstance(config); + } + + + private static void traverse(final Binder binder, final String p, final ConfigObject root) + { + root.forEach((n, v) -> { + if (v instanceof ConfigObject) + { + ConfigObject child = (ConfigObject) v; + String path = p + n; + Named named = Names.named(path); + binder.bind(Config.class).annotatedWith(named).toInstance(child.toConfig()); + traverse(binder, path + ".", child); + } + }); + } + + + static Config fileConfig(final String fname) + { + File dir = new File(System.getProperty("user.dir")); + File froot = new File(dir, fname); + if (froot.exists()) + { + return ConfigFactory.parseFile(froot); + } + else + { + File fconfig = new File(new File(dir, "conf"), fname); + if (fconfig.exists()) + { + return ConfigFactory.parseFile(fconfig); + } + } + return ConfigFactory.empty(); + } + + +} diff --git a/src/com/wurrly/tests/TestGenerator.java b/src/com/wurrly/tests/TestGenerator.java new file mode 100644 index 0000000..3bb9cd9 --- /dev/null +++ b/src/com/wurrly/tests/TestGenerator.java @@ -0,0 +1,461 @@ +/** + * + */ +package com.wurrly.tests; + +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.List; +import java.util.Optional; +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.controllers.Users; +import com.wurrly.utilities.HandleGenerator; +import com.wurrly.utilities.ServerRequest; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import io.undertow.util.MimeMappings; + +/** + * @author jbauer + * + */ +public class TestGenerator +{ + private static Logger log = LoggerFactory.getLogger(TestGenerator.class.getCanonicalName()); + + public static enum StatementParameterType + { + STRING,LITERAL,TYPE + } + + public static enum TypeHandler + { + + LongType("Long $L = Long.parseInt(request.exchange.getQueryParameters().get($S).getFirst())",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + IntegerType("Integer $L = Integer.parseInt(request.exchange.getQueryParameters().get($S).getFirst())",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + StringType("String $L = exchange.getQueryParameters().get($S).getFirst()",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + BooleanType("Boolean $L = Boolean.parseBoolean(exchange.getQueryParameters().get($S).getFirst())",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + FilePathType("Path $L = request.files($S).getFirst().getPath()",true,StatementParameterType.LITERAL,StatementParameterType.STRING), + AnyType("Any $L = exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY).readAny()",true,StatementParameterType.LITERAL), + JsonIteratorType("JsonIterator $L = exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY)",true,StatementParameterType.LITERAL), + ModelType("$T $L = exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY).read($T.class)",true,StatementParameterType.TYPE,StatementParameterType.LITERAL,StatementParameterType.TYPE), + + OptionalJsonIteratorType("Optional $L = Optional.ofNullable(exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY))",true,StatementParameterType.LITERAL), + OptionalAnyType("Optional $L = Optional.ofNullable(exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY)).map(JsonIterator::readAny())",true,StatementParameterType.LITERAL), + OptionalStringType("Optional $L = Optional.ofNullable(exchange.getQueryParameters().get($S)).map(Deque::getFirst)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + OptionalLongType("Optional $L = Optional.ofNullable(exchange.getQueryParameters().get($S)).map(Deque::getFirst).map(Long::parseLong)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + OptionalIntegerType("Optional $L = Optional.ofNullable(exchange.getQueryParameters().get($S)).map(Deque::getFirst).map(Integer::parseInt)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + OptionalBooleanType("Optional $L = Optional.ofNullable(exchange.getQueryParameters().get($S)).map(Deque::getFirst).map(Boolean::parseBoolean)",false,StatementParameterType.LITERAL,StatementParameterType.STRING), + OptionalPathType("Optional $L = Optional.ofNullable(serverRequest.files($S)).map(Deque::getFirst).map(io.undertow.server.form.FormData.FormValue::getPath)",true,StatementParameterType.LITERAL,StatementParameterType.STRING), + + ; + + 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 ) throws Exception + { + log.debug(type.getTypeName() + " " + type.toString()); + + if( type.equals( Long.class ) ) + { + return LongType; + } + else if( type.equals( Integer.class ) ) + { + return IntegerType; + } + 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 + { + throw new Exception("No type handler found!"); + } + } + else + { + return ModelType; + } + } + } + + 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.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()); + + for( Method m : 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()); + + log.debug("t handler: " + t.name()); + if(t.isBlocking()) + { + methodBuilder.beginControlFlow("if(exchange.isInIoThread())"); + methodBuilder.addStatement("exchange.dispatch(this)"); + methodBuilder.endControlFlow(); + + break; + } + + } catch (Exception e) + { + log.error(e.getMessage(),e); + } + }; + + + + Arrays.stream(m.getParameters()).forEachOrdered( p -> { + + try + { + + + + + if(p.getType().equals(ServerRequest.class)) + { + methodBuilder.addCode(CodeBlock.of("ServerRequest serverRequest = new ServerRequest(exchange);\n")); + } + else + { + TypeHandler.addStatement(methodBuilder,p); + } +// else if(p.getType().equals(Long.class)) +// { +// methodBuilder.addStatement("\nLong $L = extractLong.apply(exchange, $S)", p.getName(), p.getName()); +// } +// else if(p.getType().equals(File.class)) +// { +// methodBuilder.addStatement("\nFile $L = extractFile.apply(exchange, $S)", p.getName(), p.getName()); +// } +// else if(p.getParameterizedType().equals(Optional.class)) +// { +// +// methodBuilder.addStatement("\n$T $L = extractOptionalString.apply(exchange, $S)",p.getParameterizedType(), p.getName(), p.getName()); +// } + + } catch (Exception e) + { + log.error(e.getMessage(),e); + } + + }); + + 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);\n", m.getReturnType(), "response", controllerName, m.getName(), controllerMethodArgs ); + + } + + methodBuilder.addCode(functionBlockBuilder.build()); + + + 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.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); + } + + 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/tests/TestInvoker.java b/src/com/wurrly/tests/TestInvoker.java new file mode 100644 index 0000000..396f9e7 --- /dev/null +++ b/src/com/wurrly/tests/TestInvoker.java @@ -0,0 +1,191 @@ +/** + * + */ +package com.wurrly.tests; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Throwables; +import com.wurrly.controllers.Users; +import com.wurrly.utilities.ServerRequest; +import static java.lang.invoke.MethodHandles.lookup; + +import java.lang.invoke.CallSite; +import java.lang.invoke.LambdaMetafactory; + +/** + * @author jbauer + * + */ +public class TestInvoker +{ + private final static Method biConsumerAccept; + private final static Method consumerAccept; + private final static Method quadConsumerAccept; + + private final static Method functionApply; + private final static Method biFunctionApply; + +private static Logger Logger = LoggerFactory.getLogger(TestInvoker.class.getCanonicalName()); + + interface QuadConsumer { + void accept(R r,T t, U u, V v); + } + +// public QuadConsumer> handleLambda = +// (Users users, ServerRequest req, Long userId, Optional context) -> { +// +// users.user(req, userId, context); +// +// }; +// + static { + try { + biConsumerAccept = BiConsumer.class.getMethod("accept", Object.class, Object.class); + consumerAccept = Consumer.class.getMethod("accept", Object.class); + functionApply = Function.class.getMethod("apply", Object.class); + biFunctionApply = BiFunction.class.getMethod("apply", Object.class, Object.class); + quadConsumerAccept = QuadConsumer.class.getMethod("accept", Object.class, Object.class, Object.class, Object.class); + + } catch (NoSuchMethodException e) { + throw Throwables.propagate(e); + } + } + + + +public static void main(String[] args) +{ + + try + { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + + Users users = new Users(); + + Method[] methods = Users.class.getDeclaredMethods(); + + for( Method m : methods ) + { + Logger.debug("method: " + m); + +// MethodHandle mh = lookup.unreflect(m); +// +// MethodType mt = MethodType.fromMethodDescriptorString(m.toString(),ClassLoader.getSystemClassLoader()); +// +// Logger.debug("method type: " + mt); + + final MethodHandles.Lookup caller = lookup.in(m.getDeclaringClass()); + final MethodHandle implementationMethod; + + try { + implementationMethod = caller.unreflect(m); + } catch (IllegalAccessException e) { + throw Throwables.propagate(e); + } + + final MethodType factoryMethodType = MethodType.methodType(consumerAccept.getDeclaringClass()); + + final Class methodReturn = m.getReturnType(); + + final Class[] methodParams = m.getParameterTypes(); + + for( Class c : methodParams ) + { + System.out.println("method param: " + c); + + } + + final MethodType functionMethodType = MethodType.methodType(methodReturn, methodParams); + + System.out.println("functionMethodType: " + functionMethodType); + + QuadConsumer.class.getMethod("accept", Object.class, Object.class, Object.class, Object.class); + + //invokeMethodHandler(users,mh); + + QuadConsumer> consumer = produceLambda(m,quadConsumerAccept); + + System.out.println("consumer: " + consumer); + + consumer.accept( users, new ServerRequest(), 2501l, Optional.of("default")); + + } + + + + + + } catch (Exception e) + { + e.printStackTrace(); + } +} + +public static T produceLambda(final Method sourceMethod, final Method targetMethod) { + MethodHandles.Lookup lookup = lookup(); + sourceMethod.setAccessible(true); + final MethodHandles.Lookup caller = lookup.in(sourceMethod.getDeclaringClass()); + final MethodHandle implementationMethod; + + try { + implementationMethod = caller.unreflect(sourceMethod); + } catch (IllegalAccessException e) { + throw Throwables.propagate(e); + } + + final MethodType factoryMethodType = MethodType.methodType(targetMethod.getDeclaringClass()); + + final Class methodReturn = targetMethod.getReturnType(); + final Class[] methodParams = targetMethod.getParameterTypes(); + + final MethodType functionMethodType = MethodType.methodType(methodReturn, methodParams); + + final CallSite lambdaFactory; + try { + lambdaFactory = LambdaMetafactory.metafactory( + lookup, + targetMethod.getName(), + factoryMethodType, + functionMethodType, + implementationMethod, + implementationMethod.type() + ); + + final MethodHandle factoryInvoker = lambdaFactory.getTarget(); + + return (T) factoryInvoker.invoke(); + + } catch (Throwable e) { + // TODO: fallback to classic reflection method if lambda generation fails. + throw new InternalError(String.format("Unable to generate lambda for method %s. %s", + sourceMethod.getDeclaringClass().getName() + "." + sourceMethod.getName(), + e.getMessage())); + } +} + + public static void invokeMethodHandler(Object source,MethodHandle handle) + { + try + { + handle.bindTo(source).invokeWithArguments(new ServerRequest(), 2501l, Optional.of("default")); + + } catch ( Throwable e) + { + + } + + } + +} diff --git a/src/com/wurrly/utilities/ChunkedStream.java b/src/com/wurrly/utilities/ChunkedStream.java new file mode 100644 index 0000000..0340112 --- /dev/null +++ b/src/com/wurrly/utilities/ChunkedStream.java @@ -0,0 +1,139 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.wurrly.utilities; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; + +import org.xnio.IoUtils; + +import io.undertow.connector.PooledByteBuffer; +import io.undertow.io.IoCallback; +import io.undertow.io.Sender; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.ServerConnection; +import io.undertow.util.HeaderMap; +import io.undertow.util.Headers; + +public class ChunkedStream implements IoCallback, Runnable { + + private ReadableByteChannel source; + + private HttpServerExchange exchange; + + private Sender sender; + + private PooledByteBuffer pooled; + + private IoCallback callback; + + private int bufferSize; + + private int chunk; + + private long len; + + private long total; + + public ChunkedStream(final long len) { + this.len = len; + } + + public ChunkedStream() { + this(-1); + } + + public void send(final ReadableByteChannel source, final HttpServerExchange exchange, + final IoCallback callback) { + this.source = source; + this.exchange = exchange; + this.callback = callback; + this.sender = exchange.getResponseSender(); + ServerConnection connection = exchange.getConnection(); + this.pooled = connection.getByteBufferPool().allocate(); + this.bufferSize = connection.getBufferSize(); + + onComplete(exchange, sender); + } + + @Override + public void run() { + ByteBuffer buffer = pooled.getBuffer(); + chunk += 1; + try { + buffer.clear(); + int count = source.read(buffer); + if (count == -1 || (len != -1 && total >= len)) { + done(); + callback.onComplete(exchange, sender); + } else { + total += count; + if (chunk == 1) { + if (count < bufferSize) { + HeaderMap headers = exchange.getResponseHeaders(); + if (!headers.contains(Headers.CONTENT_LENGTH)) { + headers.put(Headers.CONTENT_LENGTH, count); + headers.remove(Headers.TRANSFER_ENCODING); + } + } else { + HeaderMap headers = exchange.getResponseHeaders(); + // just check if + if (!headers.contains(Headers.CONTENT_LENGTH)) { + headers.put(Headers.TRANSFER_ENCODING, "chunked"); + } + } + } + buffer.flip(); + if (len > 0) { + if (total > len) { + long limit = count - (total - len); + buffer.limit((int) limit); + } + } + sender.send(buffer, this); + } + } catch (IOException ex) { + onException(exchange, sender, ex); + } + } + + @Override + public void onComplete(final HttpServerExchange exchange, final Sender sender) { + if (exchange.isInIoThread()) { + exchange.dispatch(this); + } else { + run(); + } + } + + @Override + public void onException(final HttpServerExchange exchange, final Sender sender, + final IOException ex) { + done(); + callback.onException(exchange, sender, ex); + } + + private void done() { + pooled.close(); + pooled = null; + IoUtils.safeClose(source); + } + +} diff --git a/src/com/wurrly/utilities/HandleGenerator.java b/src/com/wurrly/utilities/HandleGenerator.java new file mode 100644 index 0000000..f7d6ac1 --- /dev/null +++ b/src/com/wurrly/utilities/HandleGenerator.java @@ -0,0 +1,401 @@ +/** + * + */ +package com.wurrly.utilities; + +import static java.lang.invoke.MethodHandles.lookup; + +import java.io.File; +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.net.URI; +import java.net.URL; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Throwables; +import com.jsoniter.any.Any; +import com.jsoniter.output.JsonStream; +import com.wurrly.controllers.Users; +import com.wurrly.models.User; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.Headers; +import io.undertow.util.HttpString; +import io.undertow.util.Methods; + +/** + * @author jbauer + * + */ +public class HandleGenerator +{ + private static Logger Logger = LoggerFactory.getLogger(HandleGenerator.class.getCanonicalName()); + + public static void main(String[] args) + { + + try + { + String prefix = "com.wurrly.controllers"; + List classNames = getClassNamesFromPackage(prefix); + + for( String s : classNames) + { + String className = prefix + "." + s; + + Class clazz = Class.forName(className); + + System.out.println(clazz); + + Users users = new Users(); + + for( Method m : clazz.getDeclaredMethods() ) + { + System.out.println("method: " + m); + HttpHandler handler = generateHandler(users, m,false); + + System.out.println("handler: " + handler); + + } + } + + System.out.println(classNames); + + } catch (Exception e) + { + e.printStackTrace(); + } + + } + + + public final static Function extractHttpMethod = (m) -> + { + return Arrays.stream(m.getDeclaredAnnotations()).map( a -> { + + System.out.println("annotation: " + a); + + if( a instanceof javax.ws.rs.POST) + { + return Methods.POST; + } + else if( a instanceof javax.ws.rs.GET) + { + return Methods.GET; + } + else if( a instanceof javax.ws.rs.PUT) + { + return Methods.PUT; + } + else if( a instanceof javax.ws.rs.DELETE) + { + return Methods.DELETE; + } + else if( a instanceof javax.ws.rs.OPTIONS) + { + return Methods.OPTIONS; + } + + else + { + return null; + } + + }).filter( hm -> hm != null ).findFirst().get(); + + }; + + + public final static Function extractPathTemplate = (m) -> + { + javax.ws.rs.Path childPath = m.getDeclaredAnnotation(javax.ws.rs.Path.class); + + javax.ws.rs.Path parentPath = m.getDeclaringClass().getDeclaredAnnotation(javax.ws.rs.Path.class); + + if(!childPath.value().equals("/")) + { + return (parentPath.value() + '/' + childPath.value()).replaceAll("\\/\\/", "\\/") ; + } + + return (parentPath.value() ) ; + + }; + + + + public static HttpHandler generateHandler(final Users target, final Method targetMethod, final boolean blocking) + { + try + { + final MethodType factoryMethodType = MethodType.methodType(targetMethod.getDeclaringClass()); + + final Class methodReturn = targetMethod.getReturnType(); + final Class[] methodParams = targetMethod.getParameterTypes(); + + final MethodType functionMethodType = MethodType.methodType(methodReturn, methodParams); + + MethodHandles.Lookup lookup = lookup(); + targetMethod.setAccessible(true); + final MethodHandles.Lookup caller = lookup.in(targetMethod.getDeclaringClass()); + final MethodHandle implementationMethod; + + try { + implementationMethod = caller.unreflect(targetMethod); + } catch (IllegalAccessException e) { + throw Throwables.propagate(e); + } + + final String[] parameterNames = new String[targetMethod.getParameterCount()]; + final Type[] types = new Type[targetMethod.getParameterCount()]; + final BiFunction[] biFunctions = new BiFunction[targetMethod.getParameterCount()]; + + + + for( int i = 1; i < targetMethod.getParameterCount(); i++ ) + { + final Parameter p = targetMethod.getParameters()[i]; + parameterNames[i] = p.getName(); + types[i] = p.getParameterizedType(); + + Logger.debug("Type: " + types[i]); + + if( types[i].equals(Long.class) ) + { + Logger.debug("Long type"); + + biFunctions[i] = extractLong; + } + else if( types[i].equals(String.class) ) + { + Logger.debug("String type"); + + biFunctions[i] = extractString; + } + else if( types[i].equals(java.nio.file.Path.class) ) + { + Logger.debug("Path type"); + biFunctions[i] = extractFilePath; + } + else if( types[i].equals(Any.class) ) + { + Logger.debug("Any type"); + biFunctions[i] = extractAny; + } + else if( types[i].getTypeName().startsWith("java.util.Optional") ) + { + Type rawType = ((ParameterizedType) types[i] ); + + Logger.debug("Raw type: " + rawType); + + if( types[i].getTypeName().contains("java.lang.String") ) + { + biFunctions[i] = extractOptionalString; + } + + } + + } + +// final Object[] args = new Object[targetMethod.getParameterCount()]; + + final HttpHandler mapper = new HttpHandler() + { + @Override + 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"); + } + + //Logger.debug("is dispatched: " + exchange.isDispatched()); + //Logger.debug("exchange.getConnection().getWorker(): " + exchange.getConnection().getWorker()); + + + final ServerRequest request = new ServerRequest(exchange); + +// final Long any = Long.parseLong(request.exchange.getQueryParameters().get("userId").getFirst()); + + final Optional context = Optional.ofNullable(request.exchange.getQueryParameters().get("context")).map(Deque::getFirst); + + final User json = target.createUser(request,context,request.exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY).read(User.class)); + +// json.whenComplete( ( u, e ) -> { +// +// if(e != null) +// { +// e.printStackTrace(); +// exchange.setStatusCode(500); +// exchange.getResponseSender().send(e.getMessage()); +// } +// else +// { + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); + exchange.getResponseSender().send(JsonStream.serialize(json)); +// } +// +// +// }); + + + } catch (Throwable e) + { + e.printStackTrace(); + } + } + }; + + return mapper; + + } catch (Exception e) + { + e.printStackTrace(); + return null; + } + } + + public final static BiFunction extractLong = (request,name) -> { + + return Long.parseLong(request.exchange.getQueryParameters().get(name).getFirst()); + + }; + + public final static BiFunction extractAny = (request,name) -> { + + try + { + return request.exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY).readAny(); + } catch (IOException e) + { + // TODO Auto-generated catch block + return Any.wrap(false); + } + + }; + + public final static BiFunction extractFilePath = (request,name) -> { + + return request.files(name).getFirst().getPath(); + + }; + + public final static BiFunction> extractOptionalString = (request,name) -> { + + return Optional.ofNullable(request.exchange.getQueryParameters().get(name)).map(Deque::getFirst); + + }; + + public final static BiFunction extractString = (request,name) -> { + + return request.exchange.getQueryParameters().get(name).getFirst(); + + }; + + static Optional pathParamAsLong(HttpServerExchange exchange, String name) { + return baseParameter(exchange, name).map(Long::parseLong); + } + + static Optional pathParamAsInteger(HttpServerExchange exchange, String name) { + return baseParameter(exchange, name).map(Integer::parseInt); + } + + + static Optional baseParameter(HttpServerExchange exchange, String name) { + + return Optional.ofNullable(exchange.getQueryParameters().get(name)) + .map(Deque::getFirst); + } + + private static interface RequestMapper extends Function + { + T apply(HttpServerExchange exchange,String name); + } + + public static BiFunction stringParameterMapper = (HttpServerExchange exchange, String name) -> + { + return baseParameter(exchange,name).get(); + }; + + public static BiFunction> longParameterMapper = (HttpServerExchange exchange, String name) -> + { + return baseParameter(exchange,name).map(Long::parseLong); + }; + + public static BiFunction> optionalStringParameterMapper = (HttpServerExchange exchange, String name) -> + { + return baseParameter(exchange,name); + }; + +// public static RequestMapper generateLongParameterMapper(String name) +// { +// return (HttpServerExchange exchange) -> { +// return baseParameter(exchange,name).map(Long::parseLong).get(); +// }; +// } +// +// public static RequestMapper generateIntegerParameterMapper(String name) +// { +// return (HttpServerExchange exchange) -> { +// return baseParameter(exchange,name).map(Integer::parseInt).get(); +// }; +// } + + 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); + + System.out.println(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; + } + System.out.println(actual); + entryName = actual.getName(); + entryName = entryName.substring(0, entryName.lastIndexOf('.')); + names.add(entryName); + } + + return names; + } + +} diff --git a/src/com/wurrly/utilities/JsonMapper.java b/src/com/wurrly/utilities/JsonMapper.java new file mode 100644 index 0000000..287c0cc --- /dev/null +++ b/src/com/wurrly/utilities/JsonMapper.java @@ -0,0 +1,499 @@ +/** + * + */ +package com.wurrly.utilities; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.msgpack.jackson.dataformat.MessagePackFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.module.afterburner.AfterburnerModule; + + +/** + * @author jbauer + * + */ +public class JsonMapper +{ + + private static ObjectMapper DEFAULT_MAPPER = null; + + public static ObjectMapper MSGPACK_MAPPER = null; + + private final static ConcurrentHashMap WRITER_CACHE = new ConcurrentHashMap<>(); + + public final static String EMPTY_JSON_ARRAY_STRING = JsonMapper.getInstance().createArrayNode().toString(); + + private static Logger Logger = LoggerFactory.getLogger(JsonMapper.class.getCanonicalName()); + + public static String toJSONString(Object object) + { + try + { + return getInstance().writeValueAsString(object); + } catch (Exception e) + { + Logger.error(e.getMessage(),e); + return ""; + } + + + } + + public static JsonNode toJSON(Object object) + { + try + { + return getInstance().valueToTree(object); + } catch (Exception e) + { + Logger.error(e.getMessage(),e); + return null; + } + + + } + + public static String toPrettyJSON(Object object) + { + try + { + + return getPrettyWriter().writeValueAsString(object); + } catch (Exception e) + { + Logger.error(e.getMessage(),e); + return ""; + } + + + } + + public static ObjectMapper getInstance() + { + if( DEFAULT_MAPPER == null ) + { + DEFAULT_MAPPER = new ObjectMapper(); + DEFAULT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + DEFAULT_MAPPER.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true); + DEFAULT_MAPPER.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true); + DEFAULT_MAPPER.configure(DeserializationFeature.EAGER_DESERIALIZER_FETCH,true); + DEFAULT_MAPPER.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + + DEFAULT_MAPPER.registerModule(new AfterburnerModule()); + DEFAULT_MAPPER.registerModule(new Jdk8Module()); + + + //DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm a z"); + //defaultInstance.setDateFormat(format); + + } + return DEFAULT_MAPPER; + } + + + public static ObjectWriter getPrettyWriter() + { + ObjectWriter writer = WRITER_CACHE.get("pretty"); + if( writer == null ) + { + writer = getInstance().writerWithDefaultPrettyPrinter(); + WRITER_CACHE.put("pretty", writer); + } + return writer; + } + + public static ObjectMapper getMsgPackInstance() + { + if( MSGPACK_MAPPER == null ) + { + MSGPACK_MAPPER = new ObjectMapper(new MessagePackFactory()); + MSGPACK_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + MSGPACK_MAPPER.configure(DeserializationFeature.EAGER_DESERIALIZER_FETCH,true); + MSGPACK_MAPPER.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + MSGPACK_MAPPER.registerModule(new AfterburnerModule()); + + //DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm a z"); + //defaultInstance.setDateFormat(format); + + } + return MSGPACK_MAPPER; + } + + + public static JsonNode toJSON(Class view, Object object) + { + ObjectWriter writer = WRITER_CACHE.get(view ); + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view , writer); + } + + final String jsonString = writer.writeValueAsString(object); + + final JsonNode node = getInstance().readTree(jsonString); + + return node; + } catch(Exception e) + { + Logger.error("\n" + e.getMessage() + "\nobject: " + object.getClass().getSimpleName(),e); + return null; + } + + } + + public static String toString(Class view, Object object) + { + ObjectWriter writer = WRITER_CACHE.get(view ); + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view , writer); + } + + return writer.writeValueAsString(object); + + } catch(Exception e) + { + Logger.error(e.getMessage() + "\nobject: " + object.getClass().getSimpleName(),e); + return null; + } + + } + + + public static ObjectNode wrap(String name, Class view, Object object) + { + ObjectWriter writer = WRITER_CACHE.get(view); + ObjectNode resultNode = getInstance().createObjectNode(); + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view, writer); + } + + JsonNode objectNode = null; + + + if (object instanceof List) { + List list = (List) object; + if( list.size() < 1) + { + objectNode = getInstance().createArrayNode(); + } + else + { + objectNode = getInstance().readTree(writer.writeValueAsString(object)); + } + } else if (object instanceof Collection) { + Collection col = (Collection) object; + if( col.size() < 1) + { + objectNode = getInstance().createArrayNode(); + } + else + { + objectNode = getInstance().readTree(writer.writeValueAsString(object)); + } + } + else + { + objectNode = getInstance().readTree(writer.writeValueAsString(object)); + } + + + + if( objectNode == null ) + { + objectNode = getInstance().createObjectNode(); + } + + + + resultNode.set(name, objectNode); + + return resultNode; + + } catch(Exception e) + { + Logger.error(e.getMessage(),e); + return null; + } + + } + + + public static ObjectNode wrapNode(String name, JsonNode node) + { + ObjectNode resultNode = getInstance().createObjectNode(); + resultNode.set(name, node); + return resultNode; + } + + + public static JsonNode withJSONView(Class view, Object object) + { + ObjectWriter writer = WRITER_CACHE.get(view); + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view, writer); + } + + + final String jsonString = writer.writeValueAsString(object); + + + final JsonNode node = getInstance().readTree(jsonString); + + + return node; + } catch(Exception e) + { + Logger.error(e.getMessage() + "\nobject: " + object.getClass().getSimpleName(),e); + return null; + } + + } + + public static ObjectNode wrapObjectNode(Class view, Object object) + { + + ObjectWriter writer = WRITER_CACHE.get(view); + final ObjectNode resultNode = getInstance().createObjectNode(); + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view, writer); + } + + final JsonNode objectNode = getInstance().readTree(writer.writeValueAsString(object)); + + + + resultNode.set(object.getClass().getSimpleName().toLowerCase(), objectNode); + + return resultNode; + + } catch(Exception e) + { + Logger.error(e.getMessage(),e); + return null; + } + + } + + /** + * Return an ObjectNode created from this object with the given view JSON rendition as + * a property with the given name. + * + * @param name the name of the property + * @param view the view class + * @return the objectNode + */ + + public static ObjectNode wrapObjectNode(String name, Class view, Object object) + { + ObjectWriter writer = WRITER_CACHE.get(view); + ObjectNode resultNode = getInstance().createObjectNode(); + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view, writer); + } + + JsonNode objectNode = getInstance().readTree(writer.writeValueAsString(object)); + + if( objectNode == null ) + { + objectNode = getInstance().createObjectNode(); + } + + resultNode.set(name, objectNode); + + return resultNode; + + } catch(Exception e) + { + Logger.error(e.getMessage(),e); + return null; + } + + } + + public static ObjectNode wrapJSONView(String name, Class view, Object object) + { + ObjectWriter writer = WRITER_CACHE.get(view); + ObjectNode resultNode = getInstance().createObjectNode(); + JsonNode objectNode = null; + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view, writer); + } + + if (object instanceof List) { + List list = (List) object; + if( list.size() < 1) + { + objectNode = getInstance().createArrayNode(); + } + else + { + objectNode = getInstance().readTree(writer.writeValueAsString(object)); + } + } else if (object instanceof Collection) { + Collection col = (Collection) object; + if( col.size() < 1) + { + objectNode = getInstance().createArrayNode(); + } + else + { + objectNode = getInstance().readTree(writer.writeValueAsString(object)); + } + } + else + { + objectNode = getInstance().readTree(writer.writeValueAsString(object)); + } + + + + if( objectNode == null ) + { + objectNode = getInstance().createObjectNode(); + } + + resultNode.set(name, objectNode); + + return resultNode; + + } catch(Exception e) + { + Logger.error(e.getMessage(),e); + return null; + } + + } + + public static JsonNode stringCollectionToJSONArray(Collection elements) + { + + final ArrayNode array = JsonMapper.getInstance().createArrayNode(); + elements.stream().forEach( element -> { + try{ + array.add( JsonMapper.getInstance().readTree(element) ); + } + catch(Exception e) + { + } + }); + + return array; + + } + + public static Set toStringSet(Collection elements) + { + + final Set stringSet = new HashSet<>(); + + elements.stream().forEach( element -> { + try + { + stringSet.add( JsonMapper.toJSONString(element) ); + } + catch(Exception e) + { + } + }); + + return stringSet; + + } + + public static String toJSONString(Class view, Object object) + { + ObjectWriter writer = WRITER_CACHE.get(view); + + try + { + if( writer == null) + { + writer = getInstance().writerWithView(view); + WRITER_CACHE.put(view, writer); + } + + return writer.writeValueAsString(object); + + } catch(Exception e) + { + Logger.error(e.getMessage(),e); + return null; + } + + } + + @SuppressWarnings("unchecked") + public static JsonNode nodeWithSerializer(Class view, T object, JsonSerializer serializer ) + { + ObjectMapper mapper = new ObjectMapper(); + + mapper.setConfig(mapper.getSerializationConfig().withView(view)); + + SimpleModule module = new SimpleModule(); + module.addSerializer((Class)object.getClass(),serializer); + + mapper.registerModule(module); + + try + { + return mapper.valueToTree(object); + + } catch(Exception e) + { + Logger.error(e.getMessage(),e); + return null; + } + + } +} diff --git a/src/com/wurrly/utilities/ServerRequest.java b/src/com/wurrly/utilities/ServerRequest.java new file mode 100644 index 0000000..791c805 --- /dev/null +++ b/src/com/wurrly/utilities/ServerRequest.java @@ -0,0 +1,274 @@ +/** + * + */ +package com.wurrly.utilities; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.net.URLDecoder; +import java.nio.ByteBuffer; +import java.util.Deque; +import java.util.Map; +import java.util.Scanner; +import java.util.concurrent.Executor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.channels.StreamSourceChannel; + +import com.jsoniter.JsonIterator; + +import io.undertow.connector.PooledByteBuffer; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.form.FormData; +import io.undertow.server.handlers.form.FormEncodedDataDefinition; +import io.undertow.server.handlers.form.MultiPartParserDefinition; +import io.undertow.util.AttachmentKey; +import io.undertow.util.Headers; +import io.undertow.websockets.core.UTF8Output; + +public class ServerRequest +{ + private static Logger Logger = LoggerFactory.getLogger(ServerRequest.class.getCanonicalName()); + + public static final AttachmentKey REQUEST_JSON_BODY = AttachmentKey.create(JsonIterator.class); + + 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 CHARSET = "UTF-8"; + + public final HttpServerExchange exchange; + + private final String path; + private FormData form; + private JsonIterator json; + private final String contentType; + private final String method; + + private static final String TMP_DIR = System.getProperty("java.io.tmpdir"); + + public ServerRequest() + { + this.method = null; + this.path = null; + this.exchange = null; + this.contentType = null; + + } + + public ServerRequest(HttpServerExchange exchange) throws IOException + { + this.method = exchange.getRequestMethod().toString(); + this.path = URLDecoder.decode(exchange.getRequestPath(), CHARSET); + this.exchange = exchange; + this.contentType = exchange.getRequestHeaders().getFirst("Content-Type"); + + //Logger.debug("content tyoe: " + contentType); + if (this.contentType != null) + { + if (this.contentType.contains(URL_ENCODED_FORM_TYPE) || this.contentType.contains(OCTET_STREAM_TYPE)) + { + this.parseEncodedForm(); + } + else if (this.contentType.contains(FORM_DATA_TYPE)) + { + this.parseMultipartForm(); + } + else if (this.contentType.contains(JSON_TYPE)) + { + this.parseJson(); + } + } + + this.exchange.getResponseHeaders().put(Headers.SERVER, "Bowser"); + + + } + + public Deque files(final String name) + { + + + if (this.form != null) + { + return form.get(name); + } + + return null; + } + + /** + * @param key + * @return + * @see io.undertow.util.AbstractAttachable#getAttachment(io.undertow.util.AttachmentKey) + */ + public T getAttachment(AttachmentKey key) + { + return exchange.getAttachment(key); + } + + /** + * @return + * @see io.undertow.server.HttpServerExchange#getDestinationAddress() + */ + public InetSocketAddress getDestinationAddress() + { + return exchange.getDestinationAddress(); + } + + // ChainedHandlerWrapper + + /** + * @return + * @see io.undertow.server.HttpServerExchange#getQueryParameters() + */ + public Map> getQueryParameters() + { + return exchange.getQueryParameters(); + } + + /** + * @return + * @see io.undertow.server.HttpServerExchange#getPathParameters() + */ + public Map> getPathParameters() + { + return exchange.getPathParameters(); + } + + private void parseEncodedForm() throws IOException + { + this.exchange.startBlocking(); + this.form = new FormEncodedDataDefinition().setDefaultEncoding(CHARSET).create(exchange).parseBlocking(); + + Logger.debug("Form " + form); + } + + private void parseJson() throws IOException + { + // Logger.debug("parsing json"); + + this.exchange.startBlocking(); + + if(this.exchange.getRequestContentLength() != -1) + { + +// try(PooledByteBuffer resource = this.exchange.getConnection().getByteBufferPool().allocate()) +// { +// final ByteBuffer buffer = resource.getBuffer(); +ByteBuffer buffer = ByteBuffer.allocate((int) this.exchange.getRequestContentLength()); +// final UTF8Output string = new UTF8Output(); +// +// final StreamSourceChannel channel = this.exchange.getRequestChannel(); +// +// try { +// int r = 0; +// do { +// r = channel.read(buffer); +// if (r == 0) { +// //channel.getReadSetter().set(this); +// channel.resumeReads(); +// } else if (r == -1) { +// JsonIterator iterator = JsonIterator.parse(string.extract()); +// this.exchange.putAttachment(REQUEST_JSON_BODY, iterator); +// IoUtils.safeClose(channel); +// } else { +// buffer.flip(); +// string.write(buffer); +// } +// } while (r > 0); + + + this.exchange.getRequestChannel().read(buffer); + + JsonIterator iterator = JsonIterator.parse(buffer.array()); + this.exchange.putAttachment(REQUEST_JSON_BODY, iterator); + +// } catch (IOException e) { +// throw e; +// } +// } +// Logger.debug("iterator " + iterator); + + } + else + { + InputStream is = exchange.getInputStream(); + if (is != null) { + + try + { + if (is.available() != -1) { + + try(Scanner scanner = new Scanner(is, "UTF-8")) + { + String s = scanner.useDelimiter("\\A").next(); + s = s.trim(); + JsonIterator iterator = JsonIterator.parse(s); + Logger.debug("iterator " + iterator); + + this.exchange.putAttachment(REQUEST_JSON_BODY, iterator); + } + + } + else + { + //Logger.debug("inputstream is not available "); + + } + + } catch (IOException e) { + Logger.error("IOException: ", e); + } + + } + else + { + //Logger.debug("inputstream is null "); + + } + } + + } + + private void parseMultipartForm() throws IOException + { + + this.exchange.startBlocking(); + this.form = new MultiPartParserDefinition().setTempFileLocation(new File(TMP_DIR).toPath()).setDefaultEncoding(CHARSET).create(exchange).parseBlocking(); + + Logger.debug("Form " + form); + + + } + + public String queryString() + { + return exchange.getQueryString(); + } + + public String method() + { + return this.method; + } + + public String path() + { + return path; + } + + public String rawPath() + { + return exchange.getRequestURI(); + } + + public void startAsync(final Executor executor, final Runnable runnable) + { + exchange.dispatch(executor, runnable); + } +} \ No newline at end of file diff --git a/src/resources/logging.properties b/src/resources/logging.properties new file mode 100644 index 0000000..8037cb8 --- /dev/null +++ b/src/resources/logging.properties @@ -0,0 +1,46 @@ + +# +# JBoss, Home of Professional Open Source. +# Copyright 2012 Red Hat, Inc., and individual contributors +# as indicated by the @author tags. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Additional logger names to configure (root logger is always configured) +loggers=org.xnio.listener,org.xnio.ssl,org.apache,io.undertow.util.TestHttpClient + +# Root logger configuration +logger.level=${test.level:ERROR} +logger.handlers=CONSOLE + +# Console handler configuration +handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler +handler.CONSOLE.properties=autoFlush,target +handler.CONSOLE.target=SYSTEM_ERR +handler.CONSOLE.level=ALL +handler.CONSOLE.autoFlush=true +handler.CONSOLE.formatter=PATTERN + +# The log format pattern +formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter +formatter.PATTERN.properties=pattern +formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p (%t) [%c] <%F:%L> %m%n + +logger.org.xnio.listener.level=ERROR + +logger.org.xnio.ssl.level=ERROR + +logger.org.apache.level=WARN +logger.org.apache.useParentHandlers=false +logger.io.undertow.util.TestHttpClient.level=WARN \ No newline at end of file