Hey Romain, you can now take a look at the current state. A builder pattern is implemented, and in the showcase you can see how the server is configured and injected. https://github.com/a-rekkusu/owb-centric-microserver
Please let me know what you think. Best regards, Alex On 08.07.2020 16:19, Romain Manni-Bucau wrote: > Le mer. 8 juil. 2020 à 14:42, Alexander Fischer <fische...@mailbox.org> a > écrit : > >> Hi Romain, >> >> thanks for the feedback. I made subtasks in Jira for the leftover server >> features and marked them for later. >> Regarding the configuration of our server, I took a look at how >> Meecrowave's Builder does it. Do you think it's a good idea to adopt >> this structure or should we build it another way? >> > Having a fluent API is good I think since it will often be created in a > producer, then you can use the flavor you like. > I tend to keep using fluent setters cause factories (xbean-finder, spring, > etc...) handle them more easily but not sure it is required there. > > >> And about the server as injectable bean: can you elaborate a bit about >> how you intend to use it and how it would be an advantage for you? What >> methods would you need available? Would it be like a container class >> that should contain all application scoped info (e.g. our HttpHandlers, >> the actual server)? >> > @Inject HttpServer server; > > String target = "http://localhost:" + server.getPort(); // ensure that if > the original port is 0 (random) then getPort returns the actual runtime port > > Host and if ssl is enabled are also useful info. > > >> Thanks and best regards, >> Alex >> >> On 06.07.2020 17:36, Romain Manni-Bucau wrote: >>> Hi Alex, >>> >>> A completionstage is just a promise so how it is wired is not that >>> important - it is not rare i don't use the fluent API for example but a >>> custom listener impl - but it is key to know in which thread context is >> it >>> executed. >>> Typically with your impl you inherit the caller threading - which can be >>> what you want or not. Concretely, while it is NOT netty NIOLoop threads >> it >>> is ok I think. >>> A small issue you can hit is the full http response is not chunking >>> compatible but it can be done in a second phase I guess. >>> In terms of global arch, you will also want to preresolve (see it as a >>> precompile phase) the execution (so no CDI.current().select(info.clazz). >>> get() at runtime but a resolve during the bootstrap or lazily but only >>> once). Same kind of side note for query params and form params, you >> likely >>> want to parse them lazily and call the decoder.destroy() in a finally >> block >>> ;). >>> That said, the showcase is already nice and this is pretty much details >>> since the structure is there and I guess it can be tackled after GSoC. >>> >>> Romain Manni-Bucau >>> @rmannibucau <https://twitter.com/rmannibucau> | Blog >>> <https://rmannibucau.metawerx.net/> | Old Blog >>> <http://rmannibucau.wordpress.com> | Github < >> https://github.com/rmannibucau> | >>> LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book >>> < >> https://www.packtpub.com/application-development/java-ee-8-high-performance >>> >>> >>> Le lun. 6 juil. 2020 à 17:03, Alexander Fischer <fische...@mailbox.org> >> a >>> écrit : >>> >>>> Hey Romain, >>>> >>>> the API, Netty and CDI are roughly working together now. >>>> How do you think we should handle the CompletionStage case in Netty? >>>> Should we handle it in Netty's ChannelFuture features or leave it out of >>>> there as CompletionStage does its work already? >>>> Right now I went with using ChannelFuture for CompletionStage. You can >>>> see the part here: >>>> >>>> >>>> >> https://github.com/a-rekkusu/owb-centric-microserver/blob/master/impl/src/main/java/org/apache/peeco/impl/HttpServerHandler.java#L69 >>>> Please let me know what you think overall. Next up would be the >>>> configuration tasks (e.g. server as CDI bean). >>>> Regarding the schedule, GSOC is running until August 31st, so Thomas and >>>> I try to get started with the native part from next week onwards, as we >>>> slowly hit the middle of the project time. >>>> >>>> Best regards, >>>> Alex >>>> >>>> On 19.06.2020 16:49, Romain Manni-Bucau wrote: >>>>> Except Response.setOutput which should use a plain InputStream (instead >>>> of >>>>> byte array flavor) it looks ok >>>>> >>>>> About parameters, one option is to do a "return >>>>> Stream.concat(body.entrySet().stream(), >>>>> form.entrySet().stream()).collect(toMap(Map.Entry::getKey, >>>>> Map.Entry::getValue, this::myMerger);" but impl is a detail for now ;). >>>>> Another - once again not blocking to impl - small note is you rarely >> use >>>>> body + param in the same request so it can be lazily instantiated >> (avoids >>>>> the parsing - netty has the needed classes to parse them) so a Supplier >>>> can >>>>> makes sense too, but this would be in the optim phase. >>>>> >>>>> In other words I think you can do a first impl with that API, then see >>>> how >>>>> to handle chunking and then only optimize the api internals, at least >> it >>>> is >>>>> how I would proceed. >>>>> >>>>> Romain Manni-Bucau >>>>> @rmannibucau <https://twitter.com/rmannibucau> | Blog >>>>> <https://rmannibucau.metawerx.net/> | Old Blog >>>>> <http://rmannibucau.wordpress.com> | Github < >>>> https://github.com/rmannibucau> | >>>>> LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book >>>>> < >> https://www.packtpub.com/application-development/java-ee-8-high-performance >>>>> >>>>> Le ven. 19 juin 2020 à 15:53, Alexander Fischer <fische...@mailbox.org >>>> a >>>>> écrit : >>>>> >>>>>> Hi Romain, >>>>>> >>>>>> you are right with your points and I've tried to apply them. The >>>>>> Request.parameters() method might be solvable more elegantly. Only >>>>>> streams were a bit unclear to me, but I did it as I understood it for >>>>>> now (correct me if I got it wrong): >>>>>> the user writes/casts his intended output to a ByteArrayInputStream, >>>>>> which is handed over to netty that transforms it to its actual output >>>>>> (maybe ChannelBufferOutputStream, but I have yet to figure it out). >>>>>> Let me know what you think of the current state, please. Once again >> the >>>>>> repo link, just for convenience. >>>>>> https://github.com/a-rekkusu/owb-centric-microserver >>>>>> >>>>>> Thanks and best regards, >>>>>> Alex >>>>>> >>>>>> On 18.06.2020 15:26, Romain Manni-Bucau wrote: >>>>>>> Should matching be an array? If so how would you impl it? (it is >>>>>> associated >>>>>>> with "url" or another parameter for its config, for instance EXACT + >>>> path >>>>>>> so i don't see how it would work to support EXACT and WILDCARD at the >>>>>> same >>>>>>> time for ex). >>>>>>> In Request ensure to return Map<String, List<String>> and not >>>>>>> HashMap<String, String> (it is not a hashmap cause headers are case >>>>>>> insensitive for ex, a TreeMap(String.CASE_INSENSITIVE) is better IMHO >>>> but >>>>>>> no need to expose the impl). >>>>>>> Parameters should likely be split in body parameters (form data) and >>>>>> query >>>>>>> parameters (so getParameter(String) would be a facade to 2 get in >> query >>>>>> and >>>>>>> form maps). >>>>>>> Kind of the same remark on the response (for HashMap) + payload is an >>>>>>> InputStream. This one requires some explanation: >>>>>>> >>>>>>> 1. Using a ByteArrayOutputStream is quite limiting since you drop all >>>>>>> decorations and oversized payload support >>>>>>> 2. An outputstream requires the server to know how to map this object >>>> to >>>>>>> something readable (input stream or the reactive equivalent) >>>>>>> 3. output stream will likely require the server to inject the >> instance >>>>>> once >>>>>>> 1 is fixed which is something we should try to avoid >>>>>>> >>>>>>> Now if you move to an Inputstream you can consumer it easily from the >>>>>>> server point of view, wrap it easily (in a filter for ex) and setting >>>> the >>>>>>> output is as easy: >>>>>>> >>>>>>> setOutput(new ByteArrayInputStream(...)); >>>>>>> + the user friendly flavor(s): setOutput(String) (which does the >>>>>>> setoutput(inputStream) + setHeader(content-length)) >>>>>>> >>>>>>> Romain Manni-Bucau >>>>>>> @rmannibucau <https://twitter.com/rmannibucau> | Blog >>>>>>> <https://rmannibucau.metawerx.net/> | Old Blog >>>>>>> <http://rmannibucau.wordpress.com> | Github < >>>>>> https://github.com/rmannibucau> | >>>>>>> LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book >>>>>>> < >> https://www.packtpub.com/application-development/java-ee-8-high-performance >>>>>>> Le jeu. 18 juin 2020 à 14:58, Alexander Fischer < >> fische...@mailbox.org >>>>>> a >>>>>>> écrit : >>>>>>> >>>>>>>> Hey Romain, >>>>>>>> >>>>>>>> thanks for the feedback! I have implemented the API feedback now, >>>> please >>>>>>>> take another look: >>>>>>>> https://github.com/a-rekkusu/owb-centric-microserver >>>>>>>> >>>>>>>> Are there functionalities that you miss? >>>>>>>> Else, the Netty implementation ist next. >>>>>>>> >>>>>>>> Best regards, >>>>>>>> Alex >>>>>>>> >>>>>>>> On 16.06.2020 14:04, Romain Manni-Bucau wrote: >>>>>>>>> Hi Alex, >>>>>>>>> >>>>>>>>> I don't think you need the HttpHandler annotation to be a qualifier >>>>>> (will >>>>>>>>> typically end up on a method not producing any bean at some point I >>>>>> think >>>>>>>>> as in the example at the end of this answer). >>>>>>>>> I guess Request/Response models are not yet done? Side note before >>>> you >>>>>>>> work >>>>>>>>> on them: maybe don't copy servlet API, content-type, content-length >>>> etc >>>>>>>> are >>>>>>>>> just headers, no need to make them specific, also prefer to set the >>>>>>>> payload >>>>>>>>> (as an inputstream or reactive stream) rather than encapsulating >>>>>>>> read/write >>>>>>>>> methods, it enables a better composition and decoration in general >>>> and >>>>>>>>> bypasses to go through a provider/factory to create >>>> requests/responses. >>>>>>>>> Last thing is you probably want to create a package for that work >> and >>>>>> not >>>>>>>>> use the default one ;). >>>>>>>>> >>>>>>>>> Typically it is a good start IMHO and once this works I'd do >> another >>>>>>>> small >>>>>>>>> iteration to end up on: >>>>>>>>> >>>>>>>>> public class HelloWorldHandlerFuture >>>>>>>>> { >>>>>>>>> @HttpHandler(method = {HttpMethod.GET, HttpMethod.POST}, url = >>>>>> "/hello", >>>>>>>>> matching = Matching.EXACT) >>>>>>>>> public CompletionStage<Response> apply(Request request) >>>>>>>>> { >>>>>>>>> return CompletableFuture.supplyAsync(() -> >>>>>>>>> { >>>>>>>>> Response response = new Response(); >>>>>>>>> response.setStatus(200); >>>>>>>>> response.write("Hello World from " + getClass().getName()); >>>>>>>>> return response; >>>>>>>>> }); >>>>>>>>> } >>>>>>>>> } >>>>>>>>> >>>>>>>>> Small side note (fully related to CompletionStage more than your >>>>>> current >>>>>>>>> work: if you want a synchronous impl of a CompletionStage you can >> use >>>>>>>>> CompletionFuture.completedFuture(response) - avoid the sypplyAsync >> - >>>>>> and >>>>>>>> if >>>>>>>>> you want to be async (sypplyAsync) ensure you pass an executor as >>>>>> second >>>>>>>>> parameter otherwise you end up being in default ForkJoinPool which >>>> has >>>>>> a >>>>>>>>> lot of side effects and limitations. >>>>>>>>> >>>>>>>>> Anyway, very good first iteration, it is pretty close to what I was >>>>>>>>> envisioning and it looks as smooth as I was thinking. >>>>>>>>> >>>>>>>>> Small tip for the impl phase (don't know if it is the next one or >>>> not): >>>>>>>> for >>>>>>>>> the handler registration, ensure to enable to do it >> programmatically: >>>>>>>>> register(Function<Request, CompletionStage<Response>>). It will >>>> enable >>>>>> to >>>>>>>>> use other models than the annotated one which is just a simplified >>>> API >>>>>> of >>>>>>>>> the actual one the server uses internally. >>>>>>>>> >>>>>>>>> Romain Manni-Bucau >>>>>>>>> @rmannibucau <https://twitter.com/rmannibucau> | Blog >>>>>>>>> <https://rmannibucau.metawerx.net/> | Old Blog >>>>>>>>> <http://rmannibucau.wordpress.com> | Github < >>>>>>>> https://github.com/rmannibucau> | >>>>>>>>> LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book >>>>>>>>> < >> https://www.packtpub.com/application-development/java-ee-8-high-performance >>>>>>>>> Le mar. 16 juin 2020 à 13:08, Alexander Fischer < >>>> fische...@mailbox.org >>>>>>>> a >>>>>>>>> écrit : >>>>>>>>> >>>>>>>>>> Hi Romain, >>>>>>>>>> >>>>>>>>>> I have made a first draft for the API and example showcase: >>>>>>>>>> https://github.com/a-rekkusu/owb-centric-microserver >>>>>>>>>> >>>>>>>>>> Please take a look and let me know what you think. >>>>>>>>>> CompletionStage is supported, but right now for all requests on a >>>>>>>>>> handler. If you would want a CompletableFuture only for POST for >>>>>>>>>> example, and not on GET, how do you think we should handle that? >>>>>>>>>> We could do it with a second HttpHandler on the same url but with >>>> the >>>>>>>>>> respective HttpMethod (e. g. HelloWorldHandlerGet / >>>>>>>> HelloWorldHandlerPost). >>>>>>>>>> Kind regards, >>>>>>>>>> Alex >>>>>>>>>> >>>>>>>>>> On 06.06.2020 15:44, Romain Manni-Bucau wrote: >>>>>>>>>>> Hi Alex, >>>>>>>>>>> >>>>>>>>>>> Nothing is written in the stone but here is how I would approach >>>>>> that: >>>>>>>>>>> 1. Write a HTTP server able to call a handler to answer a >> request - >>>>>> you >>>>>>>>>> can >>>>>>>>>>> start by giving a hardcoded handler but in terms of design, >> ensure >>>>>> you >>>>>>>>>> get >>>>>>>>>>> something taking a Request abstracting as input and a Response >>>>>>>>>> abstraction >>>>>>>>>>> as output. >>>>>>>>>>> Netty has these abstraction but we don't want to depend on netty >> so >>>>>> you >>>>>>>>>>> should duplicate it making it even more user friendly (netty >> stays >>>>>> low >>>>>>>>>>> level). >>>>>>>>>>> 2. Make this server CDI friendly, basically a CDI bean and nice >> to >>>>>>>> have, >>>>>>>>>>> configurable (port, ssl, ...) with MP-Config (or equivalent - if >>>> you >>>>>>>>>> take a >>>>>>>>>>> Map<String, String> as input you won here), >>>>>>>>>>> 3. Now you have to abstract the handler and make the default >>>> handler >>>>>> a >>>>>>>>>>> facade for user handlers. User handlers are CDI beans. I would >>>> start >>>>>> by >>>>>>>>>>> making them with something between servlet and jaxrs: >>>>>>>>>>> >>>>>>>>>>> @HttpHandler(method = {GET, POST}, url = "/foo", mathing = >>>>>>>>>> Matching.EXACT) >>>>>>>>>>> method being the http method handled, url the urlpattern matched >>>>>> thanks >>>>>>>>>> the >>>>>>>>>>> matching algo (i used an enum but it can be anything equivalent). >>>>>> EXACT >>>>>>>>>>> means request path == url, we can envision wildcard matching (as >> in >>>>>>>>>>> servlet), regex matching etc... >>>>>>>>>>> >>>>>>>>>>> The signature can start to be the exact expected one >>>>>>>>>>> (CompletionStage<Response> onRequest(Request)) while validated in >>>> the >>>>>>>> cdi >>>>>>>>>>> extension grabbing the handlers, then you can relax the >>>>>> CompletionStage >>>>>>>>>>> requirement (Response onReq(Request)) and finally you can go >> closer >>>>>> to >>>>>>>>>>> jaxrs adding @PathParam/@QueryParam/... like annotations but if >>>>>> Request >>>>>>>>>> API >>>>>>>>>>> is nice enough it is not required in this layer - it can be a >> layer >>>>>> on >>>>>>>>>> top >>>>>>>>>>> as jaxrs is on top of servlet. What's important here is to be >>>>>> reactive >>>>>>>>>>> friendly by design - I'll let you play with the threading >>>> strategies >>>>>> to >>>>>>>>>>> have an useful CompletionStage and how to link it - or not ;) - >> to >>>>>>>> netty >>>>>>>>>>> executors. >>>>>>>>>>> >>>>>>>>>>> Once handlers well done, it is easy to add filters on top of it, >>>> same >>>>>>>>>> kind >>>>>>>>>>> of API but it takes another optional parameter: >>>>>>>>>>> >>>>>>>>>>> CompletionStage<Response> onRequest(Request request, >>>>>>>>>>> Supplier<CompletionStage<Response>> proceed); >>>>>>>>>>> >>>>>>>>>>> with proceed the call to filter N+1 and finally the handler >> (check >>>>>> out >>>>>>>>>> OWB >>>>>>>>>>> interceptor impl, it is exactly the same. >>>>>>>>>>> >>>>>>>>>>> Last important point: ensure to handle @Priority (or add >> priority = >>>>>> int >>>>>>>>>>> in @HttpHandler) cause when you will implement the matching chain >>>> you >>>>>>>>>> will >>>>>>>>>>> need an order normally. >>>>>>>>>>> >>>>>>>>>>> Bonus: you can make the matching strategies pluggable if you want >>>> and >>>>>>>>>> just >>>>>>>>>>> provide some defaults OOTB. >>>>>>>>>>> >>>>>>>>>>> Hope it makes sense. >>>>>>>>>>> >>>>>>>>>>> Romain Manni-Bucau >>>>>>>>>>> @rmannibucau <https://twitter.com/rmannibucau> | Blog >>>>>>>>>>> <https://rmannibucau.metawerx.net/> | Old Blog >>>>>>>>>>> <http://rmannibucau.wordpress.com> | Github < >>>>>>>>>> https://github.com/rmannibucau> | >>>>>>>>>>> LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book >>>>>>>>>>> < >> https://www.packtpub.com/application-development/java-ee-8-high-performance >>>>>>>>>>> Le jeu. 4 juin 2020 à 15:35, Alexander Fischer < >>>>>> fische...@mailbox.org> >>>>>>>> a >>>>>>>>>>> écrit : >>>>>>>>>>> >>>>>>>>>>>> Hello everyone, >>>>>>>>>>>> >>>>>>>>>>>> in the last month I have spent most of my time getting to know >>>>>> coding >>>>>>>>>>>> basics of Maven, Netty, CDI/OWB and Servlets/Tomcat. I got to >> know >>>>>> CDI >>>>>>>>>>>> extensions which will be the technological foundation for the >>>>>> server. >>>>>>>>>>>> Next up will be defining and implementing the HTTP API, which >> will >>>>>>>> bring >>>>>>>>>>>> CDI and Netty together. Feel free to contribute your thoughts on >>>> the >>>>>>>>>>>> matter here on the mailing list or in the respective Jira issue: >>>>>>>>>>>> https://issues.apache.org/jira/projects/OWB/issues/OWB-1319 >>>>>>>>>>>> >>>>>>>>>>>> @Romain: can you share some ideas, annotations, interfaces for >> how >>>>>> you >>>>>>>>>>>> see the API roughly? Any kind of formal requirement-proposal >> would >>>>>> be >>>>>>>>>>>> helpful to start with. >>>>>>>>>>>> >>>>>>>>>>>> Thanks and best regards, >>>>>>>>>>>> Alexander >>>>>>>>>>>> >>>>>>>>>>>>