diff options
author | 2022-11-22 19:16:47 +0100 | |
---|---|---|
committer | 2022-11-22 19:21:42 +0100 | |
commit | a8ffe38e6e5401011352cda5bc92a0a7a88ef40e (patch) | |
tree | 97f14cfb809f365aebfdbfaed43c8733aec930e6 | |
parent | fix(frontend): mobx 6.7.0 typing (diff) | |
download | refinery-a8ffe38e6e5401011352cda5bc92a0a7a88ef40e.tar.gz refinery-a8ffe38e6e5401011352cda5bc92a0a7a88ef40e.tar.zst refinery-a8ffe38e6e5401011352cda5bc92a0a7a88ef40e.zip |
chore: upgrade to Java 19
Use Java 19 and Jetty 12 to take advantage of Project Loom preview
features to reduce CPU usage due to XtextWebDocumentAccess thread pools.
15 files changed, 148 insertions, 102 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 80d6b4f3..62f74f13 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml | |||
@@ -21,10 +21,11 @@ jobs: | |||
21 | uses: actions/checkout@v2 | 21 | uses: actions/checkout@v2 |
22 | with: | 22 | with: |
23 | fetch-depth: ${{ !steps.check-secret.outputs.is_SONAR_TOKEN_set && 1 || 0 }} # Shallow clones should be disabled for a better relevancy of SonarCloud analysis | 23 | fetch-depth: ${{ !steps.check-secret.outputs.is_SONAR_TOKEN_set && 1 || 0 }} # Shallow clones should be disabled for a better relevancy of SonarCloud analysis |
24 | - name: Set up JDK 17 | 24 | - name: Set up JDK 19 |
25 | uses: actions/setup-java@v1 | 25 | uses: actions/setup-java@v2 |
26 | with: | 26 | with: |
27 | java-version: 17 | 27 | java-version: 19 |
28 | distribution: temurin | ||
28 | - name: Cache Gradle packages | 29 | - name: Cache Gradle packages |
29 | uses: actions/cache@v2 | 30 | uses: actions/cache@v2 |
30 | with: | 31 | with: |
@@ -6,27 +6,28 @@ | |||
6 | 6 | ||
7 | ### With Eclipse IDE | 7 | ### With Eclipse IDE |
8 | 8 | ||
9 | 1. Download and install a _Java 17_ compatible JDK. For Windows, prefer OpenJDK builds from [Adoptium](https://adoptium.net/). | 9 | 1. Download and install a _Java 19_ compatible JDK. For Windows, prefer OpenJDK builds from [Adoptium](https://adoptium.net/). |
10 | 10 | ||
11 | 2. Download and extract the [Eclipse IDE for Java and DSL Developers 2021-12](https://www.eclipse.org/downloads/packages/release/2021-12/r/eclipse-ide-java-and-dsl-developers) package. | 11 | 2. Download and extract the [Eclipse IDE for Java and DSL Developers 2022-09](https://www.eclipse.org/downloads/packages/release/2022-09/r/eclipse-ide-java-and-dsl-developers) package. |
12 | 12 | ||
13 | 3. Launch Eclipse and create a new workspace. | 13 | 3. Launch Eclipse and create a new workspace. |
14 | 14 | ||
15 | 4. Open _Help > Install New Software..._ and install the following software from the _2021-12_ update site: | 15 | 4. Open _Help > Install New Software..._ and install the following software from the _2022-09_ update site: |
16 | * _Modeling > Ecore Diagram Editor (SDK)_ | 16 | * _Modeling > Ecore Diagram Editor (SDK)_ |
17 | 17 | ||
18 | 5. Open _Help > Eclipse Marketplace_ and install the following software: | 18 | 5. Open _Help > Eclipse Marketplace_ and install the following software: |
19 | * _EclEmma Java Code Coverage_ | 19 | * _EclEmma Java Code Coverage_ |
20 | * _Java 19 Support for Eclipse 2022-09 (4.25)_ | ||
20 | * _SonarLint_ | 21 | * _SonarLint_ |
21 | 22 | ||
22 | 6. Open _Window > Preferences_ and set the following preferences: | 23 | 6. Open _Window > Preferences_ and set the following preferences: |
23 | * _General > Workspace > Text file encoding_ should be _UTF-8_. | 24 | * _General > Workspace > Text file encoding_ should be _UTF-8_. |
24 | * _General > Workspace > New text file line delimiter_ should be _Unix_. | 25 | * _General > Workspace > New text file line delimiter_ should be _Unix_. |
25 | * Add the JDK 17 to _Java > Installed JREs_. | 26 | * Add the JDK 19 to _Java > Installed JREs_. |
26 | * Make sure JDK 17 is selected for _JavaSE-17_ at _Java > Installed JREs > Execution Environments_. | 27 | * Make sure JDK 19 is selected for _JavaSE-19_ at _Java > Installed JREs > Execution Environments_. |
27 | * Set _Gradle > Java home_ to the `JAVA_HOME` directory (the directory which contains the `bin` directory) of JDK 17. Here, Buildship will show a yellow warning sign, which can be safely ignored. | 28 | * Set _Gradle > Java home_ to the `JAVA_HOME` directory (the directory which contains the `bin` directory) of JDK 17. Here, Buildship will show a yellow warning sign, which can be safely ignored. |
28 | * Set _Java > Compiler > JDK Compliance > Compiler compliance level_ to _17_. The warning about using Java 16 system libraries during compilation should disappear. | 29 | * Set _Java > Compiler > JDK Compliance > Compiler compliance level_ to _19_. The warning about using Java 16 system libraries during compilation should disappear. |
29 | 30 | ||
30 | 7. Clone the project Git repository but do not import it into Eclipse yet. | 31 | 7. Clone the project Git repository but do not import it into Eclipse yet. |
31 | 32 | ||
32 | 8. Open a new terminal an run `./gradlew prepareEclipse` (`.\gradlew prepareEclipse` on Windows) in the cloned repository. | 33 | 8. Open a new terminal an run `./gradlew prepareEclipse` (`.\gradlew prepareEclipse` on Windows) in the cloned repository. |
@@ -36,11 +37,11 @@ | |||
36 | 37 | ||
37 | 9. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse. | 38 | 9. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse. |
38 | * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_. | 39 | * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_. |
39 | * If you have previously imported the project into Eclipse, this step will likely fail. In that case, you should remove the projects from Eclipse, run `git clean -fxd` in the repository, and start over from step 8. | 40 | * If you have previously imported the project into Eclipse, this step will likely fail. In that case, you should remove the projects from Eclipse, run `git clean -fxd` in the repository, and start over from step 8. |
40 | 41 | ||
41 | ### With IntelliJ IDEA | 42 | ### With IntelliJ IDEA |
42 | 43 | ||
43 | It is possible to import the project into IntelliJ IDEA, but it gives no editing help for Xtext (`*.xtext`), MWE2 (`*.mwe2`), and Xtend (`*.xtend`) and Ecore class diagrams (`*.aird`, `*.ecore`, `*.genmodel`). | 44 | It is possible to import the project into IntelliJ IDEA, but it gives no editing help for Xtext (`*.xtext`), MWE2 (`*.mwe2`), and Xtend (`*.xtend`) and Ecore class diagrams (`*.aird`, `*.ecore`, `*.genmodel`). |
44 | 45 | ||
45 | ## License | 46 | ## License |
46 | 47 | ||
diff --git a/buildSrc/src/main/groovy/refinery-java-application.gradle b/buildSrc/src/main/groovy/refinery-java-application.gradle index c38ccdb3..9abfc2b3 100644 --- a/buildSrc/src/main/groovy/refinery-java-application.gradle +++ b/buildSrc/src/main/groovy/refinery-java-application.gradle | |||
@@ -4,6 +4,10 @@ plugins { | |||
4 | id 'refinery-java-conventions' | 4 | id 'refinery-java-conventions' |
5 | } | 5 | } |
6 | 6 | ||
7 | application { | ||
8 | applicationDefaultJvmArgs += '--enable-preview' | ||
9 | } | ||
10 | |||
7 | for (taskName in ['distTar', 'distZip', 'shadowDistTar', 'shadowDistZip']) { | 11 | for (taskName in ['distTar', 'distZip', 'shadowDistTar', 'shadowDistZip']) { |
8 | tasks.named(taskName) { | 12 | tasks.named(taskName) { |
9 | enabled = false | 13 | enabled = false |
diff --git a/buildSrc/src/main/groovy/refinery-java-conventions.gradle b/buildSrc/src/main/groovy/refinery-java-conventions.gradle index b95153ce..eedefdf8 100644 --- a/buildSrc/src/main/groovy/refinery-java-conventions.gradle +++ b/buildSrc/src/main/groovy/refinery-java-conventions.gradle | |||
@@ -21,7 +21,7 @@ dependencies { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | java.toolchain { | 23 | java.toolchain { |
24 | languageVersion = JavaLanguageVersion.of(17) | 24 | languageVersion = JavaLanguageVersion.of(19) |
25 | } | 25 | } |
26 | 26 | ||
27 | def jacocoTestReport = tasks.named('jacocoTestReport') | 27 | def jacocoTestReport = tasks.named('jacocoTestReport') |
@@ -53,6 +53,18 @@ tasks.named('jar') { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | tasks.withType(JavaCompile) { | ||
57 | options.compilerArgs += '--enable-preview' | ||
58 | } | ||
59 | |||
60 | tasks.withType(Test) { | ||
61 | jvmArgs += '--enable-preview' | ||
62 | } | ||
63 | |||
64 | tasks.withType(JavaExec) { | ||
65 | jvmArgs += '--enable-preview' | ||
66 | } | ||
67 | |||
56 | def generateEclipseSourceFolders = tasks.register('generateEclipseSourceFolders') | 68 | def generateEclipseSourceFolders = tasks.register('generateEclipseSourceFolders') |
57 | 69 | ||
58 | tasks.register('prepareEclipse') { | 70 | tasks.register('prepareEclipse') { |
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d8b3d4d8..e8b7f5dd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml | |||
@@ -1,6 +1,6 @@ | |||
1 | [versions] | 1 | [versions] |
2 | eclipseCollections = "11.1.0" | 2 | eclipseCollections = "11.1.0" |
3 | jetty = "11.0.12" | 3 | jetty = "12.0.0.alpha2" |
4 | jmh = "1.36" | 4 | jmh = "1.36" |
5 | junit = "5.9.1" | 5 | junit = "5.9.1" |
6 | mockito = "4.9.0" | 6 | mockito = "4.9.0" |
@@ -19,9 +19,9 @@ gradlePlugin-shadow = { group = "gradle.plugin.com.github.johnrengelman", name = | |||
19 | gradlePlugin-sonarqube = { group = "org.sonarsource.scanner.gradle", name = "sonarqube-gradle-plugin", version = "3.3" } | 19 | gradlePlugin-sonarqube = { group = "org.sonarsource.scanner.gradle", name = "sonarqube-gradle-plugin", version = "3.3" } |
20 | hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "2.2" } | 20 | hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "2.2" } |
21 | jetty-server = { group = "org.eclipse.jetty", name = "jetty-server", version.ref = "jetty" } | 21 | jetty-server = { group = "org.eclipse.jetty", name = "jetty-server", version.ref = "jetty" } |
22 | jetty-servlet = { group = "org.eclipse.jetty", name = "jetty-servlet", version.ref = "jetty" } | 22 | jetty-servlet = { group = "org.eclipse.jetty.ee10", name = "jetty-ee10-servlet", version.ref = "jetty" } |
23 | jetty-websocket-client = { group = "org.eclipse.jetty.websocket", name = "websocket-jetty-client", version.ref = "jetty" } | 23 | jetty-websocket-client = { group = "org.eclipse.jetty.ee10.websocket", name = "jetty-ee10-websocket-jetty-client", version.ref = "jetty" } |
24 | jetty-websocket-server = { group = "org.eclipse.jetty.websocket", name = "websocket-jetty-server", version.ref = "jetty" } | 24 | jetty-websocket-server = { group = "org.eclipse.jetty.ee10.websocket", name = "jetty-ee10-websocket-jetty-server", version.ref = "jetty" } |
25 | jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } | 25 | jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } |
26 | jmh-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } | 26 | jmh-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } |
27 | junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" } | 27 | junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" } |
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661e..f88321a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties | |||
@@ -1,5 +1,5 @@ | |||
1 | distributionBase=GRADLE_USER_HOME | 1 | distributionBase=GRADLE_USER_HOME |
2 | distributionPath=wrapper/dists | 2 | distributionPath=wrapper/dists |
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip | 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-rc-4-bin.zip |
4 | zipStoreBase=GRADLE_USER_HOME | 4 | zipStoreBase=GRADLE_USER_HOME |
5 | zipStorePath=wrapper/dists | 5 | zipStorePath=wrapper/dists |
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java index ec55036f..706413a9 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java | |||
@@ -3,12 +3,13 @@ | |||
3 | */ | 3 | */ |
4 | package tools.refinery.language.web; | 4 | package tools.refinery.language.web; |
5 | 5 | ||
6 | import org.eclipse.xtext.ide.ExecutorServiceProvider; | ||
6 | import org.eclipse.xtext.web.server.XtextServiceDispatcher; | 7 | import org.eclipse.xtext.web.server.XtextServiceDispatcher; |
7 | import org.eclipse.xtext.web.server.model.IWebDocumentProvider; | 8 | import org.eclipse.xtext.web.server.model.IWebDocumentProvider; |
8 | import org.eclipse.xtext.web.server.model.XtextWebDocumentAccess; | 9 | import org.eclipse.xtext.web.server.model.XtextWebDocumentAccess; |
9 | import org.eclipse.xtext.web.server.occurrences.OccurrencesService; | 10 | import org.eclipse.xtext.web.server.occurrences.OccurrencesService; |
10 | |||
11 | import tools.refinery.language.web.occurrences.ProblemOccurrencesService; | 11 | import tools.refinery.language.web.occurrences.ProblemOccurrencesService; |
12 | import tools.refinery.language.web.xtext.VirtualThreadExecutorServiceProvider; | ||
12 | import tools.refinery.language.web.xtext.server.push.PushServiceDispatcher; | 13 | import tools.refinery.language.web.xtext.server.push.PushServiceDispatcher; |
13 | import tools.refinery.language.web.xtext.server.push.PushWebDocumentAccess; | 14 | import tools.refinery.language.web.xtext.server.push.PushWebDocumentAccess; |
14 | import tools.refinery.language.web.xtext.server.push.PushWebDocumentProvider; | 15 | import tools.refinery.language.web.xtext.server.push.PushWebDocumentProvider; |
@@ -20,16 +21,20 @@ public class ProblemWebModule extends AbstractProblemWebModule { | |||
20 | public Class<? extends IWebDocumentProvider> bindIWebDocumentProvider() { | 21 | public Class<? extends IWebDocumentProvider> bindIWebDocumentProvider() { |
21 | return PushWebDocumentProvider.class; | 22 | return PushWebDocumentProvider.class; |
22 | } | 23 | } |
23 | 24 | ||
24 | public Class<? extends XtextWebDocumentAccess> bindXtextWebDocumentAccess() { | 25 | public Class<? extends XtextWebDocumentAccess> bindXtextWebDocumentAccess() { |
25 | return PushWebDocumentAccess.class; | 26 | return PushWebDocumentAccess.class; |
26 | } | 27 | } |
27 | 28 | ||
28 | public Class<? extends XtextServiceDispatcher> bindXtextServiceDispatcher() { | 29 | public Class<? extends XtextServiceDispatcher> bindXtextServiceDispatcher() { |
29 | return PushServiceDispatcher.class; | 30 | return PushServiceDispatcher.class; |
30 | } | 31 | } |
31 | 32 | ||
32 | public Class<? extends OccurrencesService> bindOccurrencesService() { | 33 | public Class<? extends OccurrencesService> bindOccurrencesService() { |
33 | return ProblemOccurrencesService.class; | 34 | return ProblemOccurrencesService.class; |
34 | } | 35 | } |
36 | |||
37 | public Class<? extends ExecutorServiceProvider> bindExecutorServiceProvider() { | ||
38 | return VirtualThreadExecutorServiceProvider.class; | ||
39 | } | ||
35 | } | 40 | } |
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java index 58c8ea4e..5da16850 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java | |||
@@ -5,20 +5,21 @@ package tools.refinery.language.web; | |||
5 | 5 | ||
6 | import jakarta.servlet.DispatcherType; | 6 | import jakarta.servlet.DispatcherType; |
7 | import jakarta.servlet.SessionTrackingMode; | 7 | import jakarta.servlet.SessionTrackingMode; |
8 | import org.eclipse.jetty.ee10.servlet.DefaultServlet; | ||
9 | import org.eclipse.jetty.ee10.servlet.ServletContextHandler; | ||
10 | import org.eclipse.jetty.ee10.servlet.ServletHolder; | ||
11 | import org.eclipse.jetty.ee10.servlet.SessionHandler; | ||
12 | import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; | ||
8 | import org.eclipse.jetty.server.Server; | 13 | import org.eclipse.jetty.server.Server; |
9 | import org.eclipse.jetty.server.session.SessionHandler; | 14 | import org.eclipse.jetty.util.VirtualThreads; |
10 | import org.eclipse.jetty.servlet.DefaultServlet; | ||
11 | import org.eclipse.jetty.servlet.ServletContextHandler; | ||
12 | import org.eclipse.jetty.servlet.ServletHolder; | ||
13 | import org.eclipse.jetty.util.resource.Resource; | 15 | import org.eclipse.jetty.util.resource.Resource; |
14 | import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; | 16 | import org.eclipse.jetty.util.resource.ResourceFactory; |
15 | import org.slf4j.Logger; | 17 | import org.slf4j.Logger; |
16 | import org.slf4j.LoggerFactory; | 18 | import org.slf4j.LoggerFactory; |
17 | import tools.refinery.language.web.config.BackendConfigServlet; | 19 | import tools.refinery.language.web.config.BackendConfigServlet; |
18 | import tools.refinery.language.web.xtext.servlet.XtextWebSocketServlet; | 20 | import tools.refinery.language.web.xtext.servlet.XtextWebSocketServlet; |
19 | 21 | ||
20 | import java.io.File; | 22 | import java.io.File; |
21 | import java.io.IOException; | ||
22 | import java.net.InetSocketAddress; | 23 | import java.net.InetSocketAddress; |
23 | import java.net.URI; | 24 | import java.net.URI; |
24 | import java.net.URISyntaxException; | 25 | import java.net.URISyntaxException; |
@@ -42,13 +43,18 @@ public class ServerLauncher { | |||
42 | 43 | ||
43 | private final Server server; | 44 | private final Server server; |
44 | 45 | ||
45 | public ServerLauncher(InetSocketAddress bindAddress, Resource baseResource, String[] allowedOrigins, | 46 | public ServerLauncher(InetSocketAddress bindAddress, String[] allowedOrigins, String webSocketUrl) { |
46 | String webSocketUrl) { | ||
47 | server = new Server(bindAddress); | 47 | server = new Server(bindAddress); |
48 | if (server.getThreadPool() instanceof VirtualThreads.Configurable virtualThreadsConfigurable) { | ||
49 | // Change this to setVirtualThreadsExecutor once | ||
50 | // https://github.com/eclipse/jetty.project/commit/83154b4ffe4767ef44981598d6c26e6a5d32e57c gets released. | ||
51 | virtualThreadsConfigurable.setUseVirtualThreads(VirtualThreads.areSupported()); | ||
52 | } | ||
48 | var handler = new ServletContextHandler(); | 53 | var handler = new ServletContextHandler(); |
49 | addSessionHandler(handler); | 54 | addSessionHandler(handler); |
50 | addProblemServlet(handler, allowedOrigins); | 55 | addProblemServlet(handler, allowedOrigins); |
51 | addBackendConfigServlet(handler, webSocketUrl); | 56 | addBackendConfigServlet(handler, webSocketUrl); |
57 | var baseResource = getBaseResource(); | ||
52 | if (baseResource != null) { | 58 | if (baseResource != null) { |
53 | handler.setBaseResource(baseResource); | 59 | handler.setBaseResource(baseResource); |
54 | handler.setWelcomeFiles(new String[]{"index.html"}); | 60 | handler.setWelcomeFiles(new String[]{"index.html"}); |
@@ -95,6 +101,35 @@ public class ServerLauncher { | |||
95 | handler.addServlet(defaultServletHolder, "/"); | 101 | handler.addServlet(defaultServletHolder, "/"); |
96 | } | 102 | } |
97 | 103 | ||
104 | private Resource getBaseResource() { | ||
105 | var factory = ResourceFactory.of(server); | ||
106 | var baseResourceOverride = System.getenv("BASE_RESOURCE"); | ||
107 | if (baseResourceOverride != null) { | ||
108 | // If a user override is provided, use it. | ||
109 | return factory.newResource(baseResourceOverride); | ||
110 | } | ||
111 | var indexUrlInJar = ServerLauncher.class.getResource("/webapp/index.html"); | ||
112 | if (indexUrlInJar != null) { | ||
113 | // If the app is packaged in the jar, serve it. | ||
114 | URI webRootUri = null; | ||
115 | try { | ||
116 | webRootUri = URI.create(indexUrlInJar.toURI().toASCIIString().replaceFirst("/index.html$", "/")); | ||
117 | } catch (URISyntaxException e) { | ||
118 | throw new IllegalStateException("Jar has invalid base resource URI", e); | ||
119 | } | ||
120 | return factory.newResource(webRootUri); | ||
121 | } | ||
122 | // Look for unpacked production artifacts (convenience for running from IDE). | ||
123 | var unpackedResourcePathComponents = new String[]{System.getProperty("user.dir"), "build", "webpack", | ||
124 | "production"}; | ||
125 | var unpackedResourceDir = new File(String.join(File.separator, unpackedResourcePathComponents)); | ||
126 | if (unpackedResourceDir.isDirectory()) { | ||
127 | return factory.newResource(unpackedResourceDir.toPath()); | ||
128 | } | ||
129 | // Fall back to just serving a 404. | ||
130 | return null; | ||
131 | } | ||
132 | |||
98 | public void start() throws Exception { | 133 | public void start() throws Exception { |
99 | server.start(); | 134 | server.start(); |
100 | LOG.info("Server started on {}", server.getURI()); | 135 | LOG.info("Server started on {}", server.getURI()); |
@@ -104,10 +139,9 @@ public class ServerLauncher { | |||
104 | public static void main(String[] args) { | 139 | public static void main(String[] args) { |
105 | try { | 140 | try { |
106 | var bindAddress = getBindAddress(); | 141 | var bindAddress = getBindAddress(); |
107 | var baseResource = getBaseResource(); | ||
108 | var allowedOrigins = getAllowedOrigins(); | 142 | var allowedOrigins = getAllowedOrigins(); |
109 | var webSocketUrl = getWebSocketUrl(); | 143 | var webSocketUrl = getWebSocketUrl(); |
110 | var serverLauncher = new ServerLauncher(bindAddress, baseResource, allowedOrigins, webSocketUrl); | 144 | var serverLauncher = new ServerLauncher(bindAddress, allowedOrigins, webSocketUrl); |
111 | serverLauncher.start(); | 145 | serverLauncher.start(); |
112 | } catch (Exception exception) { | 146 | } catch (Exception exception) { |
113 | LOG.error("Fatal server error", exception); | 147 | LOG.error("Fatal server error", exception); |
@@ -137,29 +171,6 @@ public class ServerLauncher { | |||
137 | return new InetSocketAddress(listenAddress, listenPort); | 171 | return new InetSocketAddress(listenAddress, listenPort); |
138 | } | 172 | } |
139 | 173 | ||
140 | private static Resource getBaseResource() throws IOException, URISyntaxException { | ||
141 | var baseResourceOverride = System.getenv("BASE_RESOURCE"); | ||
142 | if (baseResourceOverride != null) { | ||
143 | // If a user override is provided, use it. | ||
144 | return Resource.newResource(baseResourceOverride); | ||
145 | } | ||
146 | var indexUrlInJar = ServerLauncher.class.getResource("/webapp/index.html"); | ||
147 | if (indexUrlInJar != null) { | ||
148 | // If the app is packaged in the jar, serve it. | ||
149 | var webRootUri = URI.create(indexUrlInJar.toURI().toASCIIString().replaceFirst("/index.html$", "/")); | ||
150 | return Resource.newResource(webRootUri); | ||
151 | } | ||
152 | // Look for unpacked production artifacts (convenience for running from IDE). | ||
153 | var unpackedResourcePathComponents = new String[]{System.getProperty("user.dir"), "build", "webpack", | ||
154 | "production"}; | ||
155 | var unpackedResourceDir = new File(String.join(File.separator, unpackedResourcePathComponents)); | ||
156 | if (unpackedResourceDir.isDirectory()) { | ||
157 | return Resource.newResource(unpackedResourceDir); | ||
158 | } | ||
159 | // Fall back to just serving a 404. | ||
160 | return null; | ||
161 | } | ||
162 | |||
163 | private static String getPublicHost() { | 174 | private static String getPublicHost() { |
164 | var publicHost = System.getenv("PUBLIC_HOST"); | 175 | var publicHost = System.getenv("PUBLIC_HOST"); |
165 | if (publicHost != null) { | 176 | if (publicHost != null) { |
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java new file mode 100644 index 00000000..ead98927 --- /dev/null +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java | |||
@@ -0,0 +1,20 @@ | |||
1 | package tools.refinery.language.web.xtext; | ||
2 | |||
3 | import org.eclipse.xtext.ide.ExecutorServiceProvider; | ||
4 | |||
5 | import java.util.concurrent.ExecutorService; | ||
6 | import java.util.concurrent.Executors; | ||
7 | |||
8 | public class VirtualThreadExecutorServiceProvider extends ExecutorServiceProvider { | ||
9 | private static final String THREAD_POOL_NAME = "xtextWeb"; | ||
10 | |||
11 | @Override | ||
12 | protected ExecutorService createInstance(String key) { | ||
13 | var name = key == null ? THREAD_POOL_NAME : THREAD_POOL_NAME + "-" + key; | ||
14 | return Executors.newThreadPerTaskExecutor(Thread.ofVirtual() | ||
15 | .allowSetThreadLocals(true) | ||
16 | .inheritInheritableThreadLocals(false) | ||
17 | .name(name + "-", 0) | ||
18 | .factory()); | ||
19 | } | ||
20 | } | ||
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java index 82391d8b..1d9e0463 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java | |||
@@ -3,10 +3,10 @@ package tools.refinery.language.web.xtext.servlet; | |||
3 | import com.google.gson.Gson; | 3 | import com.google.gson.Gson; |
4 | import com.google.gson.JsonIOException; | 4 | import com.google.gson.JsonIOException; |
5 | import com.google.gson.JsonParseException; | 5 | import com.google.gson.JsonParseException; |
6 | import org.eclipse.jetty.websocket.api.Session; | 6 | import org.eclipse.jetty.ee10.websocket.api.Session; |
7 | import org.eclipse.jetty.websocket.api.StatusCode; | 7 | import org.eclipse.jetty.ee10.websocket.api.StatusCode; |
8 | import org.eclipse.jetty.websocket.api.WriteCallback; | 8 | import org.eclipse.jetty.ee10.websocket.api.WriteCallback; |
9 | import org.eclipse.jetty.websocket.api.annotations.*; | 9 | import org.eclipse.jetty.ee10.websocket.api.annotations.*; |
10 | import org.eclipse.xtext.resource.IResourceServiceProvider; | 10 | import org.eclipse.xtext.resource.IResourceServiceProvider; |
11 | import org.eclipse.xtext.web.server.ISession; | 11 | import org.eclipse.xtext.web.server.ISession; |
12 | import org.slf4j.Logger; | 12 | import org.slf4j.Logger; |
@@ -17,7 +17,6 @@ import tools.refinery.language.web.xtext.server.TransactionExecutor; | |||
17 | import tools.refinery.language.web.xtext.server.message.XtextWebRequest; | 17 | import tools.refinery.language.web.xtext.server.message.XtextWebRequest; |
18 | import tools.refinery.language.web.xtext.server.message.XtextWebResponse; | 18 | import tools.refinery.language.web.xtext.server.message.XtextWebResponse; |
19 | 19 | ||
20 | import java.io.IOException; | ||
21 | import java.io.Reader; | 20 | import java.io.Reader; |
22 | 21 | ||
23 | @WebSocket | 22 | @WebSocket |
@@ -108,12 +107,7 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler { | |||
108 | throw new ResponseHandlerException("Trying to send message when websocket is disconnected"); | 107 | throw new ResponseHandlerException("Trying to send message when websocket is disconnected"); |
109 | } | 108 | } |
110 | var responseString = gson.toJson(response); | 109 | var responseString = gson.toJson(response); |
111 | try { | 110 | webSocketSession.getRemote().sendPartialString(responseString, true, this); |
112 | webSocketSession.getRemote().sendPartialString(responseString, true, this); | ||
113 | } catch (IOException e) { | ||
114 | throw new ResponseHandlerException( | ||
115 | "Cannot initiate async write to websocket " + webSocketSession.getRemoteAddress(), e); | ||
116 | } | ||
117 | } | 111 | } |
118 | 112 | ||
119 | @Override | 113 | @Override |
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java index a2ad2943..9a32b937 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java | |||
@@ -2,7 +2,7 @@ package tools.refinery.language.web.xtext.servlet; | |||
2 | 2 | ||
3 | import jakarta.servlet.ServletConfig; | 3 | import jakarta.servlet.ServletConfig; |
4 | import jakarta.servlet.ServletException; | 4 | import jakarta.servlet.ServletException; |
5 | import org.eclipse.jetty.websocket.server.*; | 5 | import org.eclipse.jetty.ee10.websocket.server.*; |
6 | import org.eclipse.xtext.resource.IResourceServiceProvider; | 6 | import org.eclipse.xtext.resource.IResourceServiceProvider; |
7 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
8 | import org.slf4j.LoggerFactory; | 8 | import org.slf4j.LoggerFactory; |
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java index 652fc13b..6dfce780 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java | |||
@@ -1,17 +1,17 @@ | |||
1 | package tools.refinery.language.web; | 1 | package tools.refinery.language.web; |
2 | 2 | ||
3 | import org.eclipse.jetty.ee10.servlet.ServletContextHandler; | ||
4 | import org.eclipse.jetty.ee10.servlet.ServletHolder; | ||
5 | import org.eclipse.jetty.ee10.websocket.api.Session; | ||
6 | import org.eclipse.jetty.ee10.websocket.api.StatusCode; | ||
7 | import org.eclipse.jetty.ee10.websocket.api.annotations.WebSocket; | ||
8 | import org.eclipse.jetty.ee10.websocket.api.exceptions.UpgradeException; | ||
9 | import org.eclipse.jetty.ee10.websocket.client.ClientUpgradeRequest; | ||
10 | import org.eclipse.jetty.ee10.websocket.client.WebSocketClient; | ||
11 | import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; | ||
3 | import org.eclipse.jetty.http.HttpHeader; | 12 | import org.eclipse.jetty.http.HttpHeader; |
4 | import org.eclipse.jetty.http.HttpStatus; | 13 | import org.eclipse.jetty.http.HttpStatus; |
5 | import org.eclipse.jetty.server.Server; | 14 | import org.eclipse.jetty.server.Server; |
6 | import org.eclipse.jetty.servlet.ServletContextHandler; | ||
7 | import org.eclipse.jetty.servlet.ServletHolder; | ||
8 | import org.eclipse.jetty.websocket.api.Session; | ||
9 | import org.eclipse.jetty.websocket.api.StatusCode; | ||
10 | import org.eclipse.jetty.websocket.api.annotations.WebSocket; | ||
11 | import org.eclipse.jetty.websocket.api.exceptions.UpgradeException; | ||
12 | import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; | ||
13 | import org.eclipse.jetty.websocket.client.WebSocketClient; | ||
14 | import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; | ||
15 | import org.eclipse.xtext.testing.GlobalRegistries; | 15 | import org.eclipse.xtext.testing.GlobalRegistries; |
16 | import org.eclipse.xtext.testing.GlobalRegistries.GlobalStateMemento; | 16 | import org.eclipse.xtext.testing.GlobalRegistries.GlobalStateMemento; |
17 | import org.junit.jupiter.api.AfterEach; | 17 | import org.junit.jupiter.api.AfterEach; |
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java index b70d0ed5..ebf36f13 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java | |||
@@ -1,16 +1,15 @@ | |||
1 | package tools.refinery.language.web.tests; | 1 | package tools.refinery.language.web.tests; |
2 | 2 | ||
3 | import com.google.inject.Singleton; | ||
4 | import org.eclipse.xtext.ide.ExecutorServiceProvider; | ||
5 | |||
3 | import java.util.ArrayList; | 6 | import java.util.ArrayList; |
4 | import java.util.List; | 7 | import java.util.List; |
5 | import java.util.concurrent.ExecutorService; | 8 | import java.util.concurrent.ExecutorService; |
6 | 9 | ||
7 | import org.eclipse.xtext.ide.ExecutorServiceProvider; | ||
8 | |||
9 | import com.google.inject.Singleton; | ||
10 | |||
11 | @Singleton | 10 | @Singleton |
12 | public class AwaitTerminationExecutorServiceProvider extends ExecutorServiceProvider { | 11 | public class AwaitTerminationExecutorServiceProvider extends ExecutorServiceProvider { |
13 | private List<RestartableCachedThreadPool> servicesToShutDown = new ArrayList<>(); | 12 | private final List<RestartableCachedThreadPool> servicesToShutDown = new ArrayList<>(); |
14 | 13 | ||
15 | @Override | 14 | @Override |
16 | protected ExecutorService createInstance(String key) { | 15 | protected ExecutorService createInstance(String key) { |
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java index 1468273d..8e5038ae 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java | |||
@@ -1,45 +1,44 @@ | |||
1 | package tools.refinery.language.web.tests; | 1 | package tools.refinery.language.web.tests; |
2 | 2 | ||
3 | import java.util.Collection; | ||
4 | import java.util.List; | ||
5 | import java.util.concurrent.Callable; | ||
6 | import java.util.concurrent.ExecutionException; | ||
7 | import java.util.concurrent.ExecutorService; | ||
8 | import java.util.concurrent.Executors; | ||
9 | import java.util.concurrent.Future; | ||
10 | import java.util.concurrent.TimeUnit; | ||
11 | import java.util.concurrent.TimeoutException; | ||
12 | |||
13 | import org.slf4j.Logger; | 3 | import org.slf4j.Logger; |
14 | import org.slf4j.LoggerFactory; | 4 | import org.slf4j.LoggerFactory; |
15 | 5 | ||
6 | import java.util.Collection; | ||
7 | import java.util.List; | ||
8 | import java.util.concurrent.*; | ||
9 | |||
10 | @SuppressWarnings("NullableProblems") | ||
16 | public class RestartableCachedThreadPool implements ExecutorService { | 11 | public class RestartableCachedThreadPool implements ExecutorService { |
17 | private static final Logger LOG = LoggerFactory.getLogger(RestartableCachedThreadPool.class); | 12 | private static final Logger LOG = LoggerFactory.getLogger(RestartableCachedThreadPool.class); |
18 | 13 | ||
19 | private ExecutorService delegate; | 14 | private ExecutorService delegate; |
20 | 15 | ||
21 | public RestartableCachedThreadPool() { | 16 | public RestartableCachedThreadPool() { |
22 | delegate = createExecutorService(); | 17 | delegate = createExecutorService(); |
23 | } | 18 | } |
24 | 19 | ||
25 | public void waitForAllTasksToFinish() { | 20 | public void waitForAllTasksToFinish() { |
26 | delegate.shutdown(); | 21 | delegate.shutdown(); |
27 | waitForTermination(); | 22 | waitForTermination(); |
28 | delegate = createExecutorService(); | 23 | delegate = createExecutorService(); |
29 | } | 24 | } |
30 | 25 | ||
31 | public void waitForTermination() { | 26 | public void waitForTermination() { |
27 | boolean result = false; | ||
32 | try { | 28 | try { |
33 | delegate.awaitTermination(1, TimeUnit.SECONDS); | 29 | result = delegate.awaitTermination(1, TimeUnit.SECONDS); |
34 | } catch (InterruptedException e) { | 30 | } catch (InterruptedException e) { |
35 | LOG.warn("Interrupted while waiting for delegate executor to stop", e); | 31 | LOG.warn("Interrupted while waiting for delegate executor to stop", e); |
36 | } | 32 | } |
33 | if (!result) { | ||
34 | throw new IllegalStateException("Failed to shut down Xtext thread pool"); | ||
35 | } | ||
37 | } | 36 | } |
38 | 37 | ||
39 | protected ExecutorService createExecutorService() { | 38 | protected ExecutorService createExecutorService() { |
40 | return Executors.newCachedThreadPool(); | 39 | return Executors.newCachedThreadPool(); |
41 | } | 40 | } |
42 | 41 | ||
43 | @Override | 42 | @Override |
44 | public boolean awaitTermination(long arg0, TimeUnit arg1) throws InterruptedException { | 43 | public boolean awaitTermination(long arg0, TimeUnit arg1) throws InterruptedException { |
45 | return delegate.awaitTermination(arg0, arg1); | 44 | return delegate.awaitTermination(arg0, arg1); |
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java index 74695c9a..f19c10ca 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java | |||
@@ -1,10 +1,10 @@ | |||
1 | package tools.refinery.language.web.tests; | 1 | package tools.refinery.language.web.tests; |
2 | 2 | ||
3 | import org.eclipse.jetty.websocket.api.Session; | 3 | import org.eclipse.jetty.ee10.websocket.api.Session; |
4 | import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; | 4 | import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketClose; |
5 | import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; | 5 | import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketConnect; |
6 | import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError; | 6 | import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketError; |
7 | import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; | 7 | import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketMessage; |
8 | 8 | ||
9 | import java.io.IOException; | 9 | import java.io.IOException; |
10 | import java.time.Duration; | 10 | import java.time.Duration; |