aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-web/src/main/java
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-11-10 14:35:24 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-11-10 14:35:24 +0100
commit4971c864a603e0c01f7ad84a23697905d096283b (patch)
treefc2ed2ced39aa50aa98602ad4bd2a9d877577dcd /subprojects/language-web/src/main/java
parentrefactor: rename CallKind to Polarity (diff)
downloadrefinery-4971c864a603e0c01f7ad84a23697905d096283b.tar.gz
refinery-4971c864a603e0c01f7ad84a23697905d096283b.tar.zst
refinery-4971c864a603e0c01f7ad84a23697905d096283b.zip
feat(web): backend URL configuration
To point the frontend to a backend server, update the config.json file in the website root. The config.json is generated automatically in debug mode and when running from a standalone jar.
Diffstat (limited to 'subprojects/language-web/src/main/java')
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java29
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java20
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java39
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java3
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java39
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java22
7 files changed, 114 insertions, 43 deletions
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java
index fbce62c1..fd2af1b2 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java
@@ -13,8 +13,9 @@ import java.util.regex.Pattern;
13public class CacheControlFilter implements Filter { 13public class CacheControlFilter implements Filter {
14 private static final Pattern CACHE_URI_PATTERN = Pattern.compile(".*\\.(css|gif|js|map|png|svg|woff2?)"); 14 private static final Pattern CACHE_URI_PATTERN = Pattern.compile(".*\\.(css|gif|js|map|png|svg|woff2?)");
15 15
16 private static final Set<String> CACHE_URI_DENYLIST = Set.of("apple-touch-icon.png", "favicon.png", "favicon.svg", 16 private static final Set<String> CACHE_URI_DENYLIST = Set.of("apple-touch-icon.png", "config.json", "favicon.png",
17 "favicon-96x96.png", "icon-any.svg", "icon-192x192.png", "icon-512x512.png", "mask-icon.svg", "sw.js"); 17 "favicon.svg", "favicon-96x96.png", "icon-any.svg", "icon-192x192.png", "icon-512x512.png", "mask-icon.svg",
18 "sw.js");
18 19
19 private static final Duration EXPIRY = Duration.ofDays(365); 20 private static final Duration EXPIRY = Duration.ofDays(365);
20 21
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 ffa61321..58c8ea4e 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
@@ -14,6 +14,7 @@ import org.eclipse.jetty.util.resource.Resource;
14import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; 14import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
15import org.slf4j.Logger; 15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory; 16import org.slf4j.LoggerFactory;
17import tools.refinery.language.web.config.BackendConfigServlet;
17import tools.refinery.language.web.xtext.servlet.XtextWebSocketServlet; 18import tools.refinery.language.web.xtext.servlet.XtextWebSocketServlet;
18 19
19import java.io.File; 20import java.io.File;
@@ -41,11 +42,13 @@ public class ServerLauncher {
41 42
42 private final Server server; 43 private final Server server;
43 44
44 public ServerLauncher(InetSocketAddress bindAddress, Resource baseResource, String[] allowedOrigins) { 45 public ServerLauncher(InetSocketAddress bindAddress, Resource baseResource, String[] allowedOrigins,
46 String webSocketUrl) {
45 server = new Server(bindAddress); 47 server = new Server(bindAddress);
46 var handler = new ServletContextHandler(); 48 var handler = new ServletContextHandler();
47 addSessionHandler(handler); 49 addSessionHandler(handler);
48 addProblemServlet(handler, allowedOrigins); 50 addProblemServlet(handler, allowedOrigins);
51 addBackendConfigServlet(handler, webSocketUrl);
49 if (baseResource != null) { 52 if (baseResource != null) {
50 handler.setBaseResource(baseResource); 53 handler.setBaseResource(baseResource);
51 handler.setWelcomeFiles(new String[]{"index.html"}); 54 handler.setWelcomeFiles(new String[]{"index.html"});
@@ -76,6 +79,12 @@ public class ServerLauncher {
76 JettyWebSocketServletContainerInitializer.configure(handler, null); 79 JettyWebSocketServletContainerInitializer.configure(handler, null);
77 } 80 }
78 81
82 private void addBackendConfigServlet(ServletContextHandler handler, String webSocketUrl) {
83 var backendConfigServletHolder = new ServletHolder(BackendConfigServlet.class);
84 backendConfigServletHolder.setInitParameter(BackendConfigServlet.WEBSOCKET_URL_INIT_PARAM, webSocketUrl);
85 handler.addServlet(backendConfigServletHolder, "/config.json");
86 }
87
79 private void addDefaultServlet(ServletContextHandler handler) { 88 private void addDefaultServlet(ServletContextHandler handler) {
80 var defaultServletHolder = new ServletHolder(DefaultServlet.class); 89 var defaultServletHolder = new ServletHolder(DefaultServlet.class);
81 var isWindows = System.getProperty("os.name").toLowerCase().contains("win"); 90 var isWindows = System.getProperty("os.name").toLowerCase().contains("win");
@@ -97,7 +106,8 @@ public class ServerLauncher {
97 var bindAddress = getBindAddress(); 106 var bindAddress = getBindAddress();
98 var baseResource = getBaseResource(); 107 var baseResource = getBaseResource();
99 var allowedOrigins = getAllowedOrigins(); 108 var allowedOrigins = getAllowedOrigins();
100 var serverLauncher = new ServerLauncher(bindAddress, baseResource, allowedOrigins); 109 var webSocketUrl = getWebSocketUrl();
110 var serverLauncher = new ServerLauncher(bindAddress, baseResource, allowedOrigins, webSocketUrl);
101 serverLauncher.start(); 111 serverLauncher.start();
102 } catch (Exception exception) { 112 } catch (Exception exception) {
103 LOG.error("Fatal server error", exception); 113 LOG.error("Fatal server error", exception);
@@ -190,4 +200,19 @@ public class ServerLauncher {
190 } 200 }
191 return new String[]{urlWithPort}; 201 return new String[]{urlWithPort};
192 } 202 }
203
204 private static String getWebSocketUrl() {
205 String host;
206 int port;
207 var publicHost = getPublicHost();
208 if (publicHost == null) {
209 host = getListenAddress();
210 port = getListenPort();
211 } else {
212 host = publicHost;
213 port = getPublicPort();
214 }
215 var scheme = port == HTTPS_DEFAULT_PORT ? "wss" : "ws";
216 return String.format("%s://%s:%d/xtext-service", scheme, host, port);
217 }
193} 218}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java
new file mode 100644
index 00000000..2e864998
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java
@@ -0,0 +1,20 @@
1package tools.refinery.language.web.config;
2
3import com.google.gson.annotations.SerializedName;
4
5public class BackendConfig {
6 @SerializedName("webSocketURL")
7 private String webSocketUrl;
8
9 public BackendConfig(String webSocketUrl) {
10 this.webSocketUrl = webSocketUrl;
11 }
12
13 public String getWebSocketUrl() {
14 return webSocketUrl;
15 }
16
17 public void setWebSocketUrl(String webSocketUrl) {
18 this.webSocketUrl = webSocketUrl;
19 }
20}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java
new file mode 100644
index 00000000..f314a9fa
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java
@@ -0,0 +1,39 @@
1package tools.refinery.language.web.config;
2
3import com.google.gson.Gson;
4import jakarta.servlet.ServletConfig;
5import jakarta.servlet.ServletException;
6import jakarta.servlet.http.HttpServlet;
7import jakarta.servlet.http.HttpServletRequest;
8import jakarta.servlet.http.HttpServletResponse;
9import org.eclipse.jetty.http.HttpStatus;
10
11import java.io.IOException;
12
13public class BackendConfigServlet extends HttpServlet {
14 public static final String WEBSOCKET_URL_INIT_PARAM = "tools.refinery.language.web.config.BackendConfigServlet" +
15 ".webSocketUrl";
16
17 private String serializedConfig;
18
19 @Override
20 public void init(ServletConfig config) throws ServletException {
21 super.init(config);
22 var webSocketUrl = config.getInitParameter(WEBSOCKET_URL_INIT_PARAM);
23 if (webSocketUrl == null) {
24 throw new IllegalArgumentException("Init parameter " + WEBSOCKET_URL_INIT_PARAM + " is mandatory");
25 }
26 var backendConfig = new BackendConfig(webSocketUrl);
27 var gson = new Gson();
28 serializedConfig = gson.toJson(backendConfig);
29 }
30
31 @Override
32 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
33 resp.setStatus(HttpStatus.OK_200);
34 resp.setContentType("application/json");
35 var writer = resp.getWriter();
36 writer.write(serializedConfig);
37 writer.flush();
38 }
39}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java
index 34fcb546..b686d33a 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java
@@ -1,7 +1,10 @@
1package tools.refinery.language.web.xtext.server; 1package tools.refinery.language.web.xtext.server;
2 2
3import java.io.Serial;
4
3public class ResponseHandlerException extends Exception { 5public class ResponseHandlerException extends Exception {
4 6
7 @Serial
5 private static final long serialVersionUID = 3589866922420268164L; 8 private static final long serialVersionUID = 3589866922420268164L;
6 9
7 public ResponseHandlerException(String message, Throwable cause) { 10 public ResponseHandlerException(String message, Throwable cause) {
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
index 0b417b06..7bb11d2e 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
@@ -1,35 +1,25 @@
1package tools.refinery.language.web.xtext.server; 1package tools.refinery.language.web.xtext.server;
2 2
3import java.lang.ref.WeakReference; 3import com.google.common.base.Strings;
4import java.util.ArrayList; 4import com.google.inject.Injector;
5import java.util.HashMap;
6import java.util.List;
7import java.util.Map;
8
9import org.eclipse.emf.common.util.URI; 5import org.eclipse.emf.common.util.URI;
10import org.eclipse.xtext.resource.IResourceServiceProvider; 6import org.eclipse.xtext.resource.IResourceServiceProvider;
11import org.eclipse.xtext.util.IDisposable; 7import org.eclipse.xtext.util.IDisposable;
12import org.eclipse.xtext.web.server.IServiceContext; 8import org.eclipse.xtext.web.server.*;
13import org.eclipse.xtext.web.server.IServiceResult;
14import org.eclipse.xtext.web.server.ISession;
15import org.eclipse.xtext.web.server.InvalidRequestException;
16import org.eclipse.xtext.web.server.InvalidRequestException.UnknownLanguageException; 9import org.eclipse.xtext.web.server.InvalidRequestException.UnknownLanguageException;
17import org.eclipse.xtext.web.server.XtextServiceDispatcher;
18import org.slf4j.Logger; 10import org.slf4j.Logger;
19import org.slf4j.LoggerFactory; 11import org.slf4j.LoggerFactory;
20 12import tools.refinery.language.web.xtext.server.message.*;
21import com.google.common.base.Strings;
22import com.google.inject.Injector;
23
24import tools.refinery.language.web.xtext.server.message.XtextWebErrorKind;
25import tools.refinery.language.web.xtext.server.message.XtextWebErrorResponse;
26import tools.refinery.language.web.xtext.server.message.XtextWebOkResponse;
27import tools.refinery.language.web.xtext.server.message.XtextWebPushMessage;
28import tools.refinery.language.web.xtext.server.message.XtextWebRequest;
29import tools.refinery.language.web.xtext.server.push.PrecomputationListener; 13import tools.refinery.language.web.xtext.server.push.PrecomputationListener;
30import tools.refinery.language.web.xtext.server.push.PushWebDocument; 14import tools.refinery.language.web.xtext.server.push.PushWebDocument;
31import tools.refinery.language.web.xtext.servlet.SimpleServiceContext; 15import tools.refinery.language.web.xtext.servlet.SimpleServiceContext;
32 16
17import java.lang.ref.WeakReference;
18import java.util.ArrayList;
19import java.util.HashMap;
20import java.util.List;
21import java.util.Map;
22
33public class TransactionExecutor implements IDisposable, PrecomputationListener { 23public class TransactionExecutor implements IDisposable, PrecomputationListener {
34 private static final Logger LOG = LoggerFactory.getLogger(TransactionExecutor.class); 24 private static final Logger LOG = LoggerFactory.getLogger(TransactionExecutor.class);
35 25
@@ -41,11 +31,11 @@ public class TransactionExecutor implements IDisposable, PrecomputationListener
41 31
42 private ResponseHandler responseHandler; 32 private ResponseHandler responseHandler;
43 33
44 private Object callPendingLock = new Object(); 34 private final Object callPendingLock = new Object();
45 35
46 private boolean callPending; 36 private boolean callPending;
47 37
48 private List<XtextWebPushMessage> pendingPushMessages = new ArrayList<>(); 38 private final List<XtextWebPushMessage> pendingPushMessages = new ArrayList<>();
49 39
50 public TransactionExecutor(ISession session, IResourceServiceProvider.Registry resourceServiceProviderRegistry) { 40 public TransactionExecutor(ISession session, IResourceServiceProvider.Registry resourceServiceProviderRegistry) {
51 this.session = session; 41 this.session = session;
@@ -132,10 +122,9 @@ public class TransactionExecutor implements IDisposable, PrecomputationListener
132 122
133 /** 123 /**
134 * Get the injector to satisfy the request in the {@code serviceContext}. 124 * Get the injector to satisfy the request in the {@code serviceContext}.
135 *
136 * Based on {@link org.eclipse.xtext.web.servlet.XtextServlet#getInjector}. 125 * Based on {@link org.eclipse.xtext.web.servlet.XtextServlet#getInjector}.
137 * 126 *
138 * @param serviceContext the Xtext service context of the request 127 * @param context the Xtext service context of the request
139 * @return the injector for the Xtext language in the request 128 * @return the injector for the Xtext language in the request
140 * @throws UnknownLanguageException if the Xtext language cannot be determined 129 * @throws UnknownLanguageException if the Xtext language cannot be determined
141 */ 130 */
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 fd41f213..82391d8b 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
@@ -1,31 +1,25 @@
1package tools.refinery.language.web.xtext.servlet; 1package tools.refinery.language.web.xtext.servlet;
2 2
3import java.io.IOException; 3import com.google.gson.Gson;
4import java.io.Reader; 4import com.google.gson.JsonIOException;
5 5import com.google.gson.JsonParseException;
6import org.eclipse.jetty.websocket.api.Session; 6import org.eclipse.jetty.websocket.api.Session;
7import org.eclipse.jetty.websocket.api.StatusCode; 7import org.eclipse.jetty.websocket.api.StatusCode;
8import org.eclipse.jetty.websocket.api.WriteCallback; 8import org.eclipse.jetty.websocket.api.WriteCallback;
9import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; 9import org.eclipse.jetty.websocket.api.annotations.*;
10import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
11import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
12import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
13import org.eclipse.jetty.websocket.api.annotations.WebSocket;
14import org.eclipse.xtext.resource.IResourceServiceProvider; 10import org.eclipse.xtext.resource.IResourceServiceProvider;
15import org.eclipse.xtext.web.server.ISession; 11import org.eclipse.xtext.web.server.ISession;
16import org.slf4j.Logger; 12import org.slf4j.Logger;
17import org.slf4j.LoggerFactory; 13import org.slf4j.LoggerFactory;
18
19import com.google.gson.Gson;
20import com.google.gson.JsonIOException;
21import com.google.gson.JsonParseException;
22
23import tools.refinery.language.web.xtext.server.ResponseHandler; 14import tools.refinery.language.web.xtext.server.ResponseHandler;
24import tools.refinery.language.web.xtext.server.ResponseHandlerException; 15import tools.refinery.language.web.xtext.server.ResponseHandlerException;
25import tools.refinery.language.web.xtext.server.TransactionExecutor; 16import tools.refinery.language.web.xtext.server.TransactionExecutor;
26import tools.refinery.language.web.xtext.server.message.XtextWebRequest; 17import tools.refinery.language.web.xtext.server.message.XtextWebRequest;
27import tools.refinery.language.web.xtext.server.message.XtextWebResponse; 18import tools.refinery.language.web.xtext.server.message.XtextWebResponse;
28 19
20import java.io.IOException;
21import java.io.Reader;
22
29@WebSocket 23@WebSocket
30public class XtextWebSocket implements WriteCallback, ResponseHandler { 24public class XtextWebSocket implements WriteCallback, ResponseHandler {
31 private static final Logger LOG = LoggerFactory.getLogger(XtextWebSocket.class); 25 private static final Logger LOG = LoggerFactory.getLogger(XtextWebSocket.class);
@@ -118,7 +112,7 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler {
118 webSocketSession.getRemote().sendPartialString(responseString, true, this); 112 webSocketSession.getRemote().sendPartialString(responseString, true, this);
119 } catch (IOException e) { 113 } catch (IOException e) {
120 throw new ResponseHandlerException( 114 throw new ResponseHandlerException(
121 "Cannot initiaite async write to websocket " + webSocketSession.getRemoteAddress(), e); 115 "Cannot initiate async write to websocket " + webSocketSession.getRemoteAddress(), e);
122 } 116 }
123 } 117 }
124 118