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