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

Bug #130: Support for JSON-RPC-like Debug Server Protocol's RPC #131

Merged
merged 5 commits into from
Nov 29, 2017

Conversation

jonahgraham
Copy link
Contributor

This provides the supporting RPC implementation for VSCode's Debug Protocol
as defined https://github.com/Microsoft/vscode-debugadapter-node/blob/master/debugProtocol.json

See the class comment on DebugMessageTypeAdapterFactory for details on
mapping between Debug Server Protocol and JSON-RPC 2.0.

Signed-off-by: Jonah Graham jonah@kichwacoders.com

@eclipsewebmaster
Copy link

Issue tracker reference:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=130

@mickaelistria
Copy link
Contributor

@svenefftinge @spoenemann @akosyakov Is there anything I can do to help on this topic? I'm eager to see progress there and can allocate most of my time.

@svenefftinge
Copy link
Contributor

@jonahkichwacoders thanks for the PR.
Could we vote you in as a committer and maintainer of this part?

Copy link
Contributor

@spoenemann spoenemann left a comment

Choose a reason for hiding this comment

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

Thank you for this proposal! The code seems to me of very high quality. I would support your nomination as a committer :-)

Are you planning to also implement service interfaces with corresponding data structures in the style of org.eclipse.lsp4j.services.LanguageServer? Or have you already done that?

ide/build.gradle Outdated
@@ -30,6 +38,7 @@ oomphIde {
addProjectFolder('../org.eclipse.lsp4j')
addProjectFolder('../org.eclipse.lsp4j.generator')
addProjectFolder('../org.eclipse.lsp4j.jsonrpc')
addProjectFolder('../org.eclipse.dsp4j.jsonrpc')
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure about the namespace org.eclipse.dsp4j, since theoretically that could cause name clashes with other Eclipse projects. On the other hand, I like the symmetry with org.eclipse.lsp4j. What do others think about this?

An alternative project name could be org.eclipse.lsp4j.jsonrpc.debug

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, depending on decision here will affect name of the interfaces containing plug-in. I was originally planning on org.eclipse.dsp4j, but perhaps org.eclipse.lsp4j.debug makes more sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, IIRC there even is some rule at eclipse for java packages to use the project name as prefix.

return result;
}

protected Object parseParams(JsonReader in, String method) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should make MessageTypeAdapterFactory extensible in order to avoid duplicating code here. I'll prepare a PR for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, there is certainly some duplication between the two.

Copy link
Contributor

Choose a reason for hiding this comment

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

Merged #135.

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 updated the debug code to to use this new code. I also slightly refactored the MessageTypeAdapterFactory to access some of its logic from the subclass.

super(supportedMethods, configureGson);
}

public GsonBuilder getDefaultGsonBuilder() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This additional class could be avoided by passing a Consumer<GsonBuilder> to the default MessageJsonHandler. When multiple type adapter factories are configured for the same type, the last one should win.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, the advantage of your approach too is that the other type factories don't need to be duplicated. A lot of the tests instantiate DebugMessageJsonHandler directly, so I'll probably want a method somewhere that constructs a MessageJsonHandler correctly for the tests in the same way as it is constructed for by the DebugLauncher. Perhaps a method in the DebugLauncher itself.

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 am having trouble writing a sensible method in DebugLauncher, at the moment it looks like the sample below, which seems uglier than having the extra class, ideas welcome.

The reason for the complication is the circular dependency between the MessageJsonHandler and the DebugMessageTypeAdapterFactory.

My next update will have the DebugMessageJsonHandler still, but rather than repeating everything in getDefaultGsonBuilder I'll call super's one and then add on the DebugMessageTypeAdapterFactory.

If you have a thought on something I overlooked, I would be pleased for the feedback.

	static MessageJsonHandler createMessageHandler(Map<String, JsonRpcMethod> supportedMethods,
			Consumer<GsonBuilder> configureGson) {
		DebugMessageTypeAdapterFactory adapterFactory[] = new DebugMessageTypeAdapterFactory[] {null};
		Consumer<GsonBuilder> consumer = (builder) -> {
			builder.registerTypeAdapterFactory(adapterFactory[0]);
			configureGson.accept(builder);
		};
		MessageJsonHandler messageJsonHandler = new MessageJsonHandler(supportedMethods, consumer);
		adapterFactory[0] = new DebugMessageTypeAdapterFactory(messageJsonHandler);
		return messageJsonHandler;
	}

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmm, we could change the configureGson parameter in MessageJsonHandler to BiConsumer<GsonBuilder, MessageJsonHandler>, but that's a breaking change. @akosyakov, @svenefftinge do you think this is worth it? Would help for cases when someone wants to customize parsing / serialization of messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could also add an additional constructor and deprecate the existing one. That would prevent it being a breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, we don't even need to deprecate the old one.

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 have not made this change yet. The current version, and the new constructor we discussed suffers from a problem. It passes a reference to this from the constructor when the object is not fully created, so creating new API that required and actually enforced passing around an incompletely constructed object seems like a bad idea. If you would like me to pursue this further (e.g. add an initialize() method for example) I can raise and issue and work on that separately?

}

@Test
public void testParamsParsing_AllOrders() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This parsing test that tries all iterations would also be nice for the MessageJsonHandlerTest in org.eclipse.lsp4j.jsonrpc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I will contribute it back to both places. I also realised on revisiting that the idea was to remove the _02/_03/etc versions of the methods, so I will do that 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.

I have added the _AllOrders method to MessageJsonHandlerTest and extended it to do all the types of messages.

@spoenemann
Copy link
Contributor

@eclipsewebmaster

Issue tracker reference:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=130

That makes no sense. Has probably been triggered by Jonahs mention of Bug #130. So better use the term "issue" in this context :-D

@jonahgraham
Copy link
Contributor Author

jonahgraham commented Nov 17, 2017

Could we vote you in as a committer and maintainer of this part?

Yes.

@jonahgraham
Copy link
Contributor Author

Thank you for this proposal! The code seems to me of very high quality. I would support your nomination as a committer :-)

Thanks.

Are you planning to also implement service interfaces with corresponding data structures in the style of org.eclipse.lsp4j.services.LanguageServer? Or have you already done that?

I am planning to create a PR in the coming days with the equivalent for the debug protocol. It is generated from the debug protocol json schema. Originally I was going to put it in a plug-in called org.eclipse.dsp4j, but based on your other comments, perhaps org.eclipse.lsp4j.debug would make more sense.

@jonahgraham
Copy link
Contributor Author

So better use the term "issue" in this context :-D

OK.

@spoenemann
Copy link
Contributor

It seems like the word "bug" is not necessary for triggering the Bugzilla bot, see eclipse/kapua#131

…ng of JSON

The DSP implementation created some new tests for checking every order
of fields in a JSON message. This commit adapts the same test for LSP
messages.

Signed-off-by: Jonah Graham <jonah@kichwacoders.com>
@jonahgraham
Copy link
Contributor Author

@spoenemann I have updated the code with all your feedback and it is again ready for review.

This update has the next part too, the service protocol files. As the DSP has a Json Schema that defines it, the DebugProtocol.java, IDebugProtocolClient and IDebugProtocolServer are auto-generated using a generator derived from the typescript generator used by vscode. Please see the instructions for the generator in the root of the org.eclipse.lsp4j.debug plug-in. I don't know if the licensing of the generator allows it to live in the lsp4j code base. I also don't know if continuing to generate it automatically as the protocol evolves is the best plan either, so perhaps the generator is only useful to bootstrap the project?

Copy link
Contributor

@spoenemann spoenemann left a comment

Choose a reason for hiding this comment

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

Excellent!

As long as the main source for the DSP is a JSON schema, it totally makes sense to generate the Java code from it. Ideally, the generator would be in this project (org.eclipse.lsp4j.generator), but probably we cannot just copy the code from Microsoft/vscode-debugadapter-node or a derived version of it. We can leave that problem for later and first make this PR ready for merge.

```
$ git clone git@github.com:jonahkichwacoders/vscode-debugadapter-node.git
$ git checkout dsp
$ npm install -g typescript
Copy link
Contributor

Choose a reason for hiding this comment

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

typescript is already in the devDependencies of the package.json, so it's not necessary to install it globally. The line tsc -p ./src/ # convert typescript should be added as a script in the package.json

/**
* <p>
* Version of debugProtocol.json this class was derived from.
* </p>
Copy link
Contributor

Choose a reason for hiding this comment

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

All these <p>...</p> create quite a lot of noise. I would prefer to omit them.

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 can add some additional logic to the generator to only add the <p> between paragraphs and omit them on single paragraph comments.

* completed, by executing a debugger statement etc.
* </p>
*/
public static class StoppedEventArguments {
Copy link
Contributor

Choose a reason for hiding this comment

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

The class structure should not be nested, but flat, in order to be consistent with the LSP implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably it would be better to generate a DebugProtocol.xtend with @JsonRpcData tags and that gets us even closer. It would be a 2 stage generation process (first the typescript one then the o.e.lsp4j.generator one), but then the DebugProtocol.xtend would be much readable (and shorter). WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

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

Two-stage generation sounds a bit scary at first. But a nice side effect is that all the derived members (getters, setters, equals, hashCode) are consistent in both protocols. And I like the idea to have a more readable version of the Java data structures.

* Possible values include - but not limited to those defined in {@link Reason}
* </p>
*/
public String reason;
Copy link
Contributor

Choose a reason for hiding this comment

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

The fields should not be public, but accessible via getters, in order to be consistent with the LSP implementation.

* </ul>
*/
@JsonNotification
default void initialized() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why these default implementations? I'd remove them.

These are warnings always seen when running gradle build

Signed-off-by: Jonah Graham <jonah@kichwacoders.com>
This provides the supporting RPC implementation for VSCode's Debug Protocol
as defined https://github.com/Microsoft/vscode-debugadapter-node/blob/master/debugProtocol.json

See the class comment on DebugMessageTypeAdapter for details on
mapping between Debug Server Protocol and JSON-RPC 2.0.

See DebugProtocol/IDebugProtocolClient/IDebugProtocolServer for the Java
Service Interfaces and supporting types.

Signed-off-by: Jonah Graham <jonah@kichwacoders.com>
…dler

Signed-off-by: Jonah Graham <jonah@kichwacoders.com>
Signed-off-by: Jonah Graham <jonah@kichwacoders.com>
@jonahgraham
Copy link
Contributor Author

@spoenemann Its ready, I have hopefully addressed all your concerns adequately. With the generation of DebugProtocol.xtend and using the existing generator as the second-pass generator makes it much easier to read DebugProtocol.xtend and the generated javadoc still looks fine.

Copy link
Contributor

@spoenemann spoenemann left a comment

Choose a reason for hiding this comment

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

Looks good to me, thanks again!

A further improvement would be to generate @NonNull annotations from the required properties in the schema, but I'll create a separate issue for that.

* <p>
* Auto-generated from debugProtocol.json schema version 1.24.0. Do not edit manually.
*/
class DebugProtcol {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this class could be removed now.

@spoenemann spoenemann merged commit 0cacee9 into eclipse-lsp4j:master Nov 29, 2017
adietish pushed a commit to adietish/lsp4j that referenced this pull request Aug 20, 2024
is deprecated and going to be removed soon.

Fixes eclipse-lsp4j#131

Signed-off-by: azerr <azerr@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants