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? 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)?
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 >>>>>>>>>> >>>>>>>>>>