Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This replaces org.json with a more license friendly variety from the Android community. #1067

Closed
wants to merge 5 commits into from

Conversation

rdifrango
Copy link
Contributor

This replaces org.json with a more license friendly variety from the Android community.

I choose this as it was the closest direct port and was used already in the jsonassert.

Resolves #1016
Resolves #1064

Signed-off-by: Ronald DiFrango ronald.difrango@capitalone.com

…Android community.

I choose this as it was the closest direct port and was used already in the jsonassert.

Resolves fabric8io#1016
Resolves fabric8io#1064

Signed-off-by: Ronald DiFrango ronald.difrango@capitalone.com
@codecov
Copy link

codecov bot commented Aug 15, 2018

Codecov Report

Merging #1067 into master will decrease coverage by 0.16%.
The diff coverage is 54.23%.

@@             Coverage Diff             @@
##             master   #1067      +/-   ##
===========================================
- Coverage     51.66%   51.5%   -0.17%     
- Complexity     1392    1396       +4     
===========================================
  Files           147     149       +2     
  Lines          7557    7598      +41     
  Branches       1146    1146              
===========================================
+ Hits           3904    3913       +9     
- Misses         3280    3312      +32     
  Partials        373     373
Impacted Files Coverage Δ Complexity Δ
...a/io/fabric8/maven/docker/access/BuildOptions.java 100% <ø> (ø) 14 <0> (ø) ⬇️
.../docker/config/handler/property/ValueProvider.java 89.24% <ø> (ø) 11 <0> (ø) ⬇️
...ava/io/fabric8/maven/docker/access/AuthConfig.java 94.11% <ø> (-0.48%) 9 <0> (-2)
...ven/docker/access/hc/DockerAccessWithHcClient.java 13.39% <0%> (-0.23%) 12 <0> (ø)
...bric8/maven/docker/model/JsonParsingException.java 0% <0%> (ø) 0 <0> (?)
...ava/io/fabric8/maven/docker/model/ExecDetails.java 0% <0%> (ø) 0 <0> (ø) ⬇️
...abric8/maven/docker/model/NetworksListElement.java 0% <0%> (ø) 0 <0> (ø) ⬇️
...en/docker/config/handler/compose/ComposeUtils.java 70% <0%> (ø) 4 <0> (ø) ⬇️
...ocker/access/chunked/BuildJsonResponseHandler.java 0% <0%> (ø) 0 <0> (ø) ⬇️
...ric8/maven/docker/util/CredentialHelperClient.java 24.44% <0%> (ø) 3 <0> (ø) ⬇️
... and 21 more

DiFrango, Ronald (CONT) added 4 commits August 15, 2018 14:39
Signed-off-by: Ronald DiFrango ronald.difrango@capitalone.com
Signed-off-by: Ronald DiFrango ronald.difrango@capitalone.com
Signed-off-by: Ronald DiFrango ronald.difrango@capitalone.com
Signed-off-by: Ronald DiFrango ronald.difrango@capitalone.com
Copy link
Collaborator

@rhuss rhuss left a comment

Choose a reason for hiding this comment

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

Thanks a lot for taking care. However, this PR doesn't solve the problem with parsing of a stream of tokens (see comment inline).

Also I would prefer a more straight forward change like keeping using JSONObject.put but deal with the checked exception at an higher level.

But this is more a syntactic thing, the streaming part is much more important.

Do you think this could be solved with the vaadin json library ?

I wouldn't even mind to change to e.g json-simple with which I made good experiences in other projects (i.e. Jolokia)

handler.start();
try {
JSONTokener tokener = new JSONTokener(stream);
JSONTokener tokener = new JSONTokener(IOUtils.toString(stream, Charset.defaultCharset()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

I really want to keep the streaming as we want to process the objects as the come in. See below how each token in the stream is handled as it come in with the handler.process() method. This change here would first consume all the stream and only then tokenize it. It should be done while the stream comes in as it can take quite some time e.g. for an S2I build to be finished, and the stream contains progress messages, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In looking at it, I understand and see what you mean, I'll see what if anything can be done with vaadin.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rhuss Do you have any test cases around this that I can look at? The current set passed so I felt like I was good.

I'll say I've looked at both json-lib and json-simple and neither of them seem to have the feature to read the stream for just a single JSON block like the existing library so I wonder if you'd have to roll your own?

That said, I might have missed it so if you see one that does it in a manner similar to the current one

References:

Copy link
Collaborator

@rhuss rhuss Aug 20, 2018

Choose a reason for hiding this comment

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

Unfortunately, I don't have a test case for checking that a response is parsed in a streamed fashion. Tbh, I consider that this kind of testing should be done by the json library itself, as I'm only using it here.

You can easily see, whether the streaming processing is done properly when pulling an image from a registry with the plugin. The progress bar for the individual layers is served directly from the Docker daemon.

If it wouldn't be handled as a stream you just would see nothing for a long time and then the whole process flow all at once within a second. Haven't tried that but that should be the case with your PR.


I'm afraid that you are right, that json-simple doesn't have a streaming parser, too. I don't know json-lib, so can't comment on this lib.

Actually rolling one's own implementation shouldn't be that super hard:

  • Read the first chunk of the stream
  • Check for a "{" or a "[". Set a counter to 1.
  • Continue to read in chunks, increase the counter for each "{" (or "[" if this was the first char). Decrease the counter for each "}" (or "]")
  • If the counter is 0, take the bytes so far and create a JSON object/array for that, feed it into the handler.
  • Take the rest of the current chunk, strip whitespace from the beginning, look for a "{" or "[" again and start over.

I think its safe to assume that no literally JSON types (string, number, boolean) are included in isolation in the stream.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe that we can use https://github.com/fangyidong/json-simple/blob/a8b94b79b697df64b23428c27d65d6a187e9ebf9/src/main/java/org/json/simple/parser/JSONParser.java#L91 here.

This method will consume the next JSON token from the stream, and that is what we need here. We would then feed the object obtained from this method to the handler here and then read the next object from the stream until the stream is done.

Wdyt ?

I know, switching to json-simple would be a quite intrusive change, but as mentioned I made excellent experiences with it (I'm using it since 2008 in Jolokia without any issue. Also it's super small.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

@rdifrango good point haven't verified this but will do so. I thought it would really parse until the end of an object/array, not until the end of the stream. I'm pretty sure that the Docker daemon doesn't send EOF markers within the stream after each object/array.

Copy link
Collaborator

Choose a reason for hiding this comment

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

For me, from https://github.com/fangyidong/json-simple/blob/a8b94b79b697df64b23428c27d65d6a187e9ebf9/src/main/java/org/json/simple/parser/JSONParser.java#L270-L271 it looks like for me that TYPE_EOF is more like an internal marker, not directly related to the stream itself. But have to check this ..

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nope, doesn't seem to work ;-(

public class JsonStreamParsingTest {

    public static void main(String[] args) throws IOException, ParseException {
        Reader testReader = new StringReader("{ \"name\": \"first\", \"value\": 10 }\n\n" +
                                             "{ \"name\": \"second\", \"value\": 20 }");
        JSONParser parser = new JSONParser();
        int i = 0;
        while (testReader.ready()) {
            System.out.println(i++ + ": " + parser.parse(testReader));
        }
    }
}

leads to

Exception in thread "main" Unexpected token LEFT BRACE({) at position 34.
	at org.json.simple.parser.JSONParser.parse(JSONParser.java:146)
	at org.json.simple.parser.JSONParser.parse(JSONParser.java:92)
	at org.jolokia.util.JsonStreamParsingTest.main(JsonStreamParsingTest.java:22)

which means, that JSONParser also tries to slurp in everything to parse (and doesn't stop when it picked up the first object)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Wdyt about switching to gson ?

I tried this and it seems to work. gson might be a bit of an overkill as it's a full JSON mapping framework, but we might look into this if we don't find a better streaming parsing alternative

public class JsonStreamParsingTest {

    public static void main(String[] args) throws IOException {
        Reader testReader = new StringReader("{ \"name\": \"first\", \"value\": 10 }\n" +
                                             "{ \"name\": \"second\", \"value\": 20 }");
        JsonParser parser = new JsonParser();

        int i = 0;
        JsonReader json = new JsonReader(testReader);
        json.setLenient(true);
        while (json.peek() != JsonToken.END_DOCUMENT) {
            JsonElement element = parser.parse(json);
            System.out.println(i++ + ": " + element);
        }
    }
}

yields

0: {"name":"first","value":10}
1: {"name":"second","value":20}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rhuss Agreed, it might be a little bit of overkill, but I'll take a second stab switching this out to GSON as I think it more closely aligns to your goals on the streaming side.

@rdifrango
Copy link
Contributor Author

@rhuss That's good feedback and one of the reasons that I choose the vaadin library as it seemed like the less intrusive approach as its was a relatively straightforward port and the jsonassert library that's use for testing uses it, which interestingly enough the jsonassert team made the switch for the same reasons here.

I had made two prior attempts locally with Jackson and GSON and they were highly intrusive.

I can take a look at json-simple and see what that would look like along with trying to see if I could stream with vaadin.

@@ -30,23 +30,23 @@ public void process(JSONObject json) throws DockerAccessException {
private void logInfoMessage(JSONObject json) {
String value;
if (json.has("stream")) {
value = json.getString("stream").replaceFirst("\n$", "");
value = json.optString("stream").replaceFirst("\n$", "");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rhuss just as a note, I choose optString as it doesn't toss a checked exception, instead it returns a sensible/ aka default empty, value.

@rdifrango
Copy link
Contributor Author

Closing in favor of #1073

@rdifrango rdifrango closed this Sep 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants