Skip to content

Conversation

@matejvasek
Copy link
Contributor

@matejvasek matejvasek commented Sep 1, 2020

resolves #212

@matejvasek
Copy link
Contributor Author

relates to #212

Copy link
Member

@slinkydeveloper slinkydeveloper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw you did some refactoring of restful-ws impl inside this PR, can you push it in a separate PR?

@slinkydeveloper slinkydeveloper added the enhancement New feature or request label Sep 1, 2020
@slinkydeveloper slinkydeveloper added this to the 2.0.0-milestone3 milestone Sep 1, 2020
@matejvasek
Copy link
Contributor Author

matejvasek commented Sep 1, 2020

@slinkydeveloper Sorry for mixing up things:
Re: restful-ws changes -- commit just an example of usage it there only to demonstrate usage, it is not supposed to be merged.
BTW it also shows that generic interface is not most efficient since I had to convert Multi Map to ordinary map iterator.

);
}

public static MessageWriter createWriter(BiConsumer<String, String> putHeader, Consumer<byte[]> putBody) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a cool idea!

@slinkydeveloper
Copy link
Member

@slinkydeveloper Sorry for mixing up things:
Re: restful-ws changes -- commit just an example of usage it there only to demonstrate usage, it is not supposed to be merged.
BTW it also shows that generic interface is not most efficient since I had to convert Multi Map to ordinary map iterator.

For demonstration purpose, can you add a snippet to the module readme? (also with the tests, the usage should be pretty clear)

Copy link

@eamonnmcmanus eamonnmcmanus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together! It's very close to what I was imagining.

@matejvasek
Copy link
Contributor Author

I added examples using java.net.HttpURLConnection and com.sun.net.httpserver.HttpServer.

@matejvasek
Copy link
Contributor Author

Speaking of header: I must not forget about their case-insensitivity.

@slinkydeveloper
Copy link
Member

Speaking of header: I must not forget about their case-insensitivity.

On the write side, i guess you should just take a convention and use it... Then the internal representation is up to the single http libraries

}
}

public static Stream<Arguments> binaryTestArguments() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is already copypasted with little changes at multiple places. We should refactor that latter (not in this PR) if possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a todo to the code itself?

@matejvasek
Copy link
Contributor Author

I added README and some examples HttpURLConnection, Servlet API, com.sun.net.httpserver.HttpServer.

@matejvasek
Copy link
Contributor Author

TODO: add Javadocs

@matejvasek
Copy link
Contributor Author

Should I call it basic http or generic http?

@slinkydeveloper
Copy link
Member

For me the name of the module should be cloudevents-http-basic

@matejvasek matejvasek changed the title Http basic Generic HTTP bindings Sep 4, 2020
@matejvasek matejvasek marked this pull request as ready for review September 4, 2020 15:52
@matejvasek
Copy link
Contributor Author

@eamonnmcmanus pleas give it another look.

Copy link

@eamonnmcmanus eamonnmcmanus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good. Thanks for putting in all that work!

* Example of usage with <a href="https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html">HttpServletRequest</a>:
* {@code
* Consumer<BiConsumer<String,String>> forEachHeader = processHeader -> {
* Enumeration<String> headerNames = httpServletRequest.getHeaderNames();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (String name : Collections.list(httpServletRequest.getHeaderNames())) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely would work, but why allocate new List just to iterate over it?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collections.list was introduced specifically to get the legacy type Enumeration out of the way as quickly as possible. For me this is the idiomatic way to iterate over the Enumeration<String> type that the ancient Servlet API imposes. It's also a lot more readable for the example code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found out that there is asIterator() then I could call forEachRemaining unfortunately the asIterator() method is available since Java 9+ 😞

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that

for (String name : Collections.list(httpServletRequest.getHeaderNames())) {}

is probably more readable.

But I find ArrayList allocation (and possible internal reallocation on its growth) unnecessary.
I specifically chosen that obsolete type to show that it works well with Consumer<BiConsumer<String,String>> forEachHeader. @slinkydeveloper wdyt?

* @return a message reader implementation with potentially an unknown encoding
* @throws IllegalArgumentException If, in case of binary mode, the spec version is invalid
*/
public static MessageReader createReaderFromMultiMap(Map<String, List<String>> headers, byte[] body) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the spelling Multimap rather than MultiMap is more usual.

Copy link
Member

@slinkydeveloper slinkydeveloper Sep 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer MultiMap because to me it's a reasoning like TreeMap (first part of the name tells you the impl detail, the second one the interface it implements), but it's a matter of taste

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A TreeMap is just a kind of Map, but a Multimap is a different sort of thing. As words we would write "tree map" but "multimap". https://en.wikipedia.org/wiki/Multimap

Copy link
Member

@slinkydeveloper slinkydeveloper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a first pass, on monday i'll do another one 😄

import java.io.IOException;
import java.io.InputStream;

// based on apache commons io
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a link to the source code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better now?

Copy link
Member

@slinkydeveloper slinkydeveloper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the basic http example contains examples with sun http server, http url connection and jetty server, maybe you should add a basic readme that explains the three different samples here?

httpExchange.sendResponseHeaders(200, body.length);
httpExchange.getResponseBody().write(body);
} catch (IOException t) {
throw new UncheckedIOException(t);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waaaaat, i didn't knew it 😍

* }
* };
* byte[] body;
* int contentLength = httpServletRequest.getContentLength();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

@matejvasek
Copy link
Contributor Author

@eamonnmcmanus please give it another look.

// V03
Arguments.of(
V03_MIN,
new HashMap<String,String>() {{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every time you use double-brace initialization, God kills a kitten

Probably OK in a test, but you could also write a helper function that takes a String[] or a String[][] and makes a Map out of it. Better still would be to use Map.of(...), but that requires Java 9+.

Copy link
Contributor Author

@matejvasek matejvasek Sep 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eamonnmcmanus Originally I used something different: c09ef8c#diff-da38f4f0dad4b560cd509239f96a762eL241 was it better?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize it uses anon classes. Gee couldn't they just already add proper literals to the language.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course this is only a test, so the kittens God is killing are only test kittens. Still, I think I preferred the way you had it before, which was at least as readable without triggering the kitten-killing fear in seasoned Java developers.

For literals, I think List.of(...) and Set.of(...), added in Java 9, are good enough for those types without needing a special syntax. There's also Map.of(...), which you could have used here except for the desire to work on Java 8. But that one is a bit dicey anyway since there's no obvious syntactic difference between keys and values, and it arbitrarily stops at 10 key-value pairs.

@slinkydeveloper
Copy link
Member

@matejvasek can you fix the dco?

Copy link
Member

@slinkydeveloper slinkydeveloper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last change and we're ready to go

<artifactId>cloudevents-json-jackson</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need that, because it's brought in by cloudevents-json-jackson

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also should be in cloudevents-http-basic

Signed-off-by: Matej Vasek <mvasek@redhat.com>
@slinkydeveloper slinkydeveloper merged commit 6eecf29 into cloudevents:master Sep 9, 2020
@slinkydeveloper
Copy link
Member

slinkydeveloper commented Sep 9, 2020

Thanks @matejvasek for the great work with this PR and thanks to @eamonnmcmanus for the fantastic job with the reviews!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Much harder with V2 than V1 to send binary CloudEvents

3 participants