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

7198: Add websocket server that pushes data on selection updates #306

Closed
wants to merge 22 commits into from

Conversation

cimi
Copy link
Contributor

@cimi cimi commented Sep 9, 2021

This PR adds a websocket server that pushes event data as JSON to all connected clients whenever the user updates their current selection in JMC. The server is disabled by default and can be enabled and disabled from JMC preferences. This is a rework of the proof-of-concept code in #225 and uses the JSON serialiser introduced in #279.

Screenshot 2021-11-27 at 21 13 54

The three endpoints available on the server are:

  • /events/ - raw serialised events
  • /tree/ - StacktraceTreeModel, data used in the flame graph view
  • /graph/ - StacktraceGraphModel, data used in the graph view

Please see this Observable collection for examples on how to connect.

This PR adds several new dependencies:

  • org.eclipse.jetty.websocket:websocket-jetty-server:10.0.5
  • org.eclipse.jetty.websocket:websocket-javax-server:10.0.5
  • org.eclipse.jetty.websocket:websocket-jetty-api:10.0.5
  • org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.34

After adding the new dependencies, I had issues with resolving transitive dependency conflicts (when I was trying to use Jetty 9.x) then with fixing the eclipse launcher - please see the comments for details.


Progress

  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

  • JMC-7198: Add websocket server that pushes data on selection updates

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jmc pull/306/head:pull/306
$ git checkout pull/306

Update a local copy of the PR:
$ git checkout pull/306
$ git pull https://git.openjdk.java.net/jmc pull/306/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 306

View PR using the GUI difftool:
$ git pr show -t 306

Using diff file

Download this PR as a diff file:
https://git.openjdk.java.net/jmc/pull/306.diff

@bridgekeeper
Copy link

bridgekeeper bot commented Sep 9, 2021

👋 Welcome back cimi! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Sep 10, 2021

@cimi this pull request can not be integrated into master due to one or more merge conflicts. To resolve these merge conflicts and update this pull request you can run the following commands in the local repository for your personal fork:

git checkout cimi/websocket-server
git fetch https://git.openjdk.java.net/jmc master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push

@cimi cimi force-pushed the cimi/websocket-server branch from d023281 to a098a18 Compare September 10, 2021 13:31
@openjdk openjdk bot removed the merge-conflict label Sep 10, 2021
@cimi cimi force-pushed the cimi/websocket-server branch from a098a18 to 4e2a004 Compare September 10, 2021 17:34
@cimi cimi force-pushed the cimi/websocket-server branch from 4e2a004 to 6ac7278 Compare September 10, 2021 17:45
@cimi cimi marked this pull request as ready for review September 13, 2021 10:28
@openjdk openjdk bot added the rfr label Sep 13, 2021
@mlbridge
Copy link

mlbridge bot commented Sep 13, 2021

Copy link
Collaborator

@bric3 bric3 left a comment

Choose a reason for hiding this comment

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

Nice stepping stone toward flexible UIs.
There's still some println here and there ;)
Stopping the websocket server is not yet implemented.

}
websocketServerEnabledListener = e -> {
if (e.getProperty().equals(PreferenceKeys.PROPERTY_ENABLE_WEBSOCKET_SERVER)) {
if ((Boolean) e.getNewValue()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

For readability purpose maybe this code could benefit from an explicit equality check

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 is refactored, we don't use a boolean setting to see if we should enable the server.

import org.openjdk.jmc.flightrecorder.serializers.json.IItemCollectionJsonSerializer;

public class WebsocketServer {
private static int PORT = 8029;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the port should be configurable.

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 is done now - instead of a checkbox to enable the server, users need to pick a port number with 0 being the default value. When 0 is selected the webserver is disabled.

We had a discussion about this and @jpbempel pointed out that 0 is a valid port number that means the operating system should pick an open port. Since we don't display the port number in the UI anywhere, binding to a random port will be confusing for the user because they won't know what to connect to 😃 So I think it's ok to keep 0 as the disabled value, what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

In general I think it's ok to allow automatic port binding as long as this information is being sent back to the user. But for this use case it's not critical, so using zero to disable the server is OK for me. And if this prove to be too much misleading this can be changed without too much effort.

private void startServer() {
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(PORT);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not quite sure how this feature will be used, but can it make sense to only bind to locahost ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 Yup, definitely! This was in the plan 😉 it's done now.

@@ -45,8 +46,10 @@
<hdrhistogram.version>2.1.12</hdrhistogram.version>
<jakarta.activation.version>1.2.1</jakarta.activation.version>
<jakarta.mail.version>1.6.5</jakarta.mail.version>
<javax.websocket.version>1.1</javax.websocket.version>
<jetty.version>9.4.43.v20210629</jetty.version>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I have seen in the PR description this codes needs to stick with 9.4.43…. But I noticed the coordinate of the artefacts may have changed after version 9 (group:org.eclipse.jetty.websocket, artefact: wesocket-server -> websocket-jetty-server). I haven't yet checked the dependencies in the POM, maybe that helps.

By the way there's a more recent version of jetty 11.0.6.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting, thanks for pointing this out!

I picked 9.4.43 because it was the latest version I saw here https://mvnrepository.com/artifact/org.eclipse.jetty.websocket/websocket-server I didn't notice the rename for later versions. 😭

Maybe I can get rid of the dependency issues if I just use 10.0.5 which is already required by something (I don't know what) in the uitests.

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've just tried using 10.0.5 and I get this error:

Caused by: org.osgi.framework.BundleException: Bundle org.openjdk.jmc.console.agent cannot be resolved:org.openjdk.jmc.console.agent [130]
  Unresolved requirement: Require-Bundle: org.openjdk.jmc.flightrecorder.ui
    -> Bundle-SymbolicName: org.openjdk.jmc.flightrecorder.ui; bundle-version="8.2.0.qualifier"; singleton:="true"
       org.openjdk.jmc.flightrecorder.ui [132]
         Unresolved requirement: Require-Bundle: org.eclipse.jetty.websocket-api
           -> Bundle-SymbolicName: org.eclipse.jetty.websocket-api; bundle-version="1.1.2"
              org.eclipse.jetty.websocket-api [93]
                Unresolved requirement: Require-Capability: osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"

It seems this needs SPI Fly now...

Copy link
Collaborator

Choose a reason for hiding this comment

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

So it seems you finally go this working :)

@cimi cimi force-pushed the cimi/websocket-server branch from 2077969 to 16c3ca7 Compare September 14, 2021 18:37
@@ -46,6 +46,9 @@
<unit id="org.adoptopenjdk.jemmy-browser" version="2.0.0"/>
<unit id="org.adoptopenjdk.jemmy-core" version="2.0.0"/>
<unit id="org.adoptopenjdk.jemmy-swt" version="2.0.0"/>
<unit id="javax.servlet-api" version="3.1.0"/>
<unit id="javax.websocket-api" version="1.1.0"/>
<unit id="org.eclipse.jetty.websocket.server" version="9.4.43.v20210629"/>
Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems there's still references to jetty 9 in older platform definition.

I'm not familiar with eclipse based applications, but should those target be removed once the platform is upgraded to a more recent version ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🙈 Cleaned up now, I was just fiddling around with this config trying to get the dependencies to resolve properly and I was just updating the active one.

<unit id="org.eclipse.jetty.websocket.servlet" version="10.0.5"/>
<unit id="org.eclipse.jetty.websocket.javax.server" version="10.0.5"/>
<unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.4"/>
.servlet-api_4.0.6.jar
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this shouldn't be there ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops 😂 glad it didn't complain...

@cimi cimi force-pushed the cimi/websocket-server branch from 16c3ca7 to 15f9f81 Compare September 15, 2021 11:24
@cimi cimi force-pushed the cimi/websocket-server branch from 15f9f81 to eb04ded Compare September 15, 2021 11:49
@@ -123,7 +126,29 @@ public JfrEditor() {
}
}
};
if (FlightRecorderUI.getDefault().isWebsocketServerEnabled()) {
long websocketServerPort = FlightRecorderUI.getDefault().getWebsocketPort();
Copy link
Member

Choose a reason for hiding this comment

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

why long for the variable type? it forces you to cast to int when calling WebsocketServer constructor below while getWebsocketPort() returns int anyway

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 is a leftover after refactoring, I was initially using IQuantity for the port because other numeric configs were using that, then I changed to long and finally to int. Good spot, fixed now!

releng/third-party/pom.xml Outdated Show resolved Hide resolved
releng/third-party/pom.xml Outdated Show resolved Hide resolved
Comment on lines 39 to 41
private List<WebsocketConnectionHandler> handlers = new ArrayList<>();
private List<WebsocketConnectionHandler> treeHandlers = new ArrayList<>();
private List<WebsocketConnectionHandler> graphHandlers = new ArrayList<>();
Copy link
Member

Choose a reason for hiding this comment

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

Since there is more than one thread involved into accessing those handlers I would use CopyOnWriteArrayList to be safe on the access.

@aptmac
Copy link
Member

aptmac commented Nov 16, 2021

I've updated the Eclipse launchers to include the additional asm plugins and now I'm no longer seeing startup errors, everything seems to work fine. I've added a commit with these changes.

I think these look good, after fighting with my Eclipse for a bit I was able to verify that the additional plugins here get it working.

Having said that, I wonder if the JMC-Eclipse-JDK-8.launch should be removed.. the jetty dependencies are having a fit because they require jdk 11, and using certain target platforms it's not even possible to launch JMC with jdk 8 anyways.

@thegreystone thegreystone changed the title 7198: add websocket server that pushes data on selection updates 7198: Add websocket server that pushes data on selection updates Nov 25, 2021
@openjdk
Copy link

openjdk bot commented Nov 25, 2021

⚠️ @cimi the full name on your profile does not match the author name in this pull requests' HEAD commit. If this pull request gets integrated then the author name from this pull requests' HEAD commit will be used for the resulting commit. If you wish to push a new commit with a different author name, then please run the following commands in a local repository of your personal fork:

$ git checkout cimi/websocket-server
$ git commit -c user.name='Preferred Full Name' --allow-empty -m 'Update full name'
$ git push

@openjdk
Copy link

openjdk bot commented Nov 25, 2021

@cimi This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

7198: Add websocket server that pushes data on selection updates

Reviewed-by: hirt, aptmac

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been no new commits pushed to the master branch. If another commit should be pushed before you perform the /integrate command, your PR will be automatically rebased. If you prefer to avoid any potential automatic rebasing, please check the documentation for the /integrate command for further details.

As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@thegreystone, @aptmac) but any other Committer may sponsor as well.

➡️ To flag this PR as ready for integration with the above commit message, type /integrate in a new comment. (Afterwards, your sponsor types /sponsor in a new comment to perform the integration).

@openjdk openjdk bot added ready and removed merge-conflict labels Nov 25, 2021
@cimi
Copy link
Contributor Author

cimi commented Nov 26, 2021

/integrate

@openjdk openjdk bot added the sponsor label Nov 26, 2021
@openjdk
Copy link

openjdk bot commented Nov 26, 2021

@cimi
Your change (at version b120657) is now ready to be sponsored by a Committer.

@openjdk openjdk bot removed the sponsor label Nov 29, 2021
@cimi
Copy link
Contributor Author

cimi commented Nov 29, 2021

/integrate

@openjdk openjdk bot added the sponsor label Nov 29, 2021
@openjdk
Copy link

openjdk bot commented Nov 29, 2021

@cimi
Your change (at version 63817ca) is now ready to be sponsored by a Committer.

@thegreystone
Copy link
Member

/sponsor

@openjdk
Copy link

openjdk bot commented Nov 29, 2021

Going to push as commit ca20442.

@openjdk
Copy link

openjdk bot commented Nov 29, 2021

@thegreystone @cimi Pushed as commit ca20442.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@cimi cimi mentioned this pull request Jan 9, 2022
2 tasks
@cimi cimi deleted the cimi/websocket-server branch January 10, 2022 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

5 participants