diff options
Diffstat (limited to 'language-web/src/main/java/org/eclipse/viatra/solver/language')
-rw-r--r-- | language-web/src/main/java/org/eclipse/viatra/solver/language/web/ProblemServlet.java | 2 | ||||
-rw-r--r-- | language-web/src/main/java/org/eclipse/viatra/solver/language/web/ServerLauncher.java | 141 |
2 files changed, 91 insertions, 52 deletions
diff --git a/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ProblemServlet.java b/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ProblemServlet.java index 337df54b..18b86ade 100644 --- a/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ProblemServlet.java +++ b/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ProblemServlet.java | |||
@@ -4,7 +4,6 @@ | |||
4 | package org.eclipse.viatra.solver.language.web; | 4 | package org.eclipse.viatra.solver.language.web; |
5 | 5 | ||
6 | import javax.servlet.ServletException; | 6 | import javax.servlet.ServletException; |
7 | import javax.servlet.annotation.WebServlet; | ||
8 | 7 | ||
9 | import org.eclipse.xtext.util.DisposableRegistry; | 8 | import org.eclipse.xtext.util.DisposableRegistry; |
10 | import org.eclipse.xtext.web.servlet.XtextServlet; | 9 | import org.eclipse.xtext.web.servlet.XtextServlet; |
@@ -12,7 +11,6 @@ import org.eclipse.xtext.web.servlet.XtextServlet; | |||
12 | /** | 11 | /** |
13 | * Deploy this class into a servlet container to enable DSL-specific services. | 12 | * Deploy this class into a servlet container to enable DSL-specific services. |
14 | */ | 13 | */ |
15 | @WebServlet(name = "XtextServices", urlPatterns = "/xtext-service/*") | ||
16 | public class ProblemServlet extends XtextServlet { | 14 | public class ProblemServlet extends XtextServlet { |
17 | 15 | ||
18 | private static final long serialVersionUID = 1L; | 16 | private static final long serialVersionUID = 1L; |
diff --git a/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ServerLauncher.java b/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ServerLauncher.java index 2c0413df..d92c7735 100644 --- a/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ServerLauncher.java +++ b/language-web/src/main/java/org/eclipse/viatra/solver/language/web/ServerLauncher.java | |||
@@ -3,37 +3,67 @@ | |||
3 | */ | 3 | */ |
4 | package org.eclipse.viatra.solver.language.web; | 4 | package org.eclipse.viatra.solver.language.web; |
5 | 5 | ||
6 | import java.io.File; | ||
6 | import java.io.IOException; | 7 | import java.io.IOException; |
7 | import java.net.InetSocketAddress; | 8 | import java.net.InetSocketAddress; |
8 | import java.net.URI; | 9 | import java.net.URI; |
9 | import java.net.URISyntaxException; | 10 | import java.net.URISyntaxException; |
11 | import java.util.Set; | ||
12 | |||
13 | import javax.servlet.SessionTrackingMode; | ||
10 | 14 | ||
11 | import org.eclipse.jetty.annotations.AnnotationConfiguration; | ||
12 | import org.eclipse.jetty.server.Server; | 15 | import org.eclipse.jetty.server.Server; |
16 | import org.eclipse.jetty.server.session.SessionHandler; | ||
17 | import org.eclipse.jetty.servlet.DefaultServlet; | ||
18 | import org.eclipse.jetty.servlet.ServletContextHandler; | ||
19 | import org.eclipse.jetty.servlet.ServletHolder; | ||
13 | import org.eclipse.jetty.util.log.Slf4jLog; | 20 | import org.eclipse.jetty.util.log.Slf4jLog; |
14 | import org.eclipse.jetty.util.resource.Resource; | 21 | import org.eclipse.jetty.util.resource.Resource; |
15 | import org.eclipse.jetty.webapp.Configuration; | ||
16 | import org.eclipse.jetty.webapp.MetaInfConfiguration; | ||
17 | import org.eclipse.jetty.webapp.WebAppContext; | ||
18 | import org.eclipse.jetty.webapp.WebInfConfiguration; | ||
19 | import org.eclipse.jetty.webapp.WebXmlConfiguration; | ||
20 | 22 | ||
21 | public class ServerLauncher { | 23 | public class ServerLauncher { |
24 | public static final String DEFAULT_LISTEN_ADDRESS = "localhost"; | ||
25 | |||
26 | public static final int DEFAULT_LISTEN_PORT = 1312; | ||
27 | |||
28 | // Use this cookie name for load balancing. | ||
29 | public static final String SESSION_COOKIE_NAME = "JSESSIONID"; | ||
30 | |||
22 | private static final Slf4jLog LOG = new Slf4jLog(ServerLauncher.class.getName()); | 31 | private static final Slf4jLog LOG = new Slf4jLog(ServerLauncher.class.getName()); |
23 | 32 | ||
24 | private final Server server; | 33 | private final Server server; |
25 | 34 | ||
26 | public ServerLauncher(InetSocketAddress bindAddress, Resource baseResource) { | 35 | public ServerLauncher(InetSocketAddress bindAddress, Resource baseResource) { |
27 | server = new Server(bindAddress); | 36 | server = new Server(bindAddress); |
28 | var ctx = new WebAppContext(); | 37 | var handler = new ServletContextHandler(); |
29 | ctx.setBaseResource(baseResource); | 38 | addSessionHandler(handler); |
30 | ctx.setWelcomeFiles(new String[] { "index.html" }); | 39 | addProblemServlet(handler); |
31 | ctx.setContextPath("/"); | 40 | if (baseResource != null) { |
32 | ctx.setConfigurations(new Configuration[] { new AnnotationConfiguration(), new WebXmlConfiguration(), | 41 | handler.setBaseResource(baseResource); |
33 | new WebInfConfiguration(), new MetaInfConfiguration() }); | 42 | handler.setWelcomeFiles(new String[] { "index.html" }); |
34 | ctx.setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, ".*/build/classes/.*,.*\\.jar"); | 43 | addDefaultServlet(handler); |
35 | ctx.setInitParameter("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false"); | 44 | } |
36 | server.setHandler(ctx); | 45 | server.setHandler(handler); |
46 | } | ||
47 | |||
48 | private void addSessionHandler(ServletContextHandler handler) { | ||
49 | var sessionHandler = new SessionHandler(); | ||
50 | sessionHandler.setSessionTrackingModes(Set.of(SessionTrackingMode.COOKIE)); | ||
51 | sessionHandler.setSessionCookie(SESSION_COOKIE_NAME); | ||
52 | handler.setSessionHandler(sessionHandler); | ||
53 | } | ||
54 | |||
55 | private void addProblemServlet(ServletContextHandler handler) { | ||
56 | handler.addServlet(ProblemServlet.class, "/xtext-service/*"); | ||
57 | } | ||
58 | |||
59 | private void addDefaultServlet(ServletContextHandler handler) { | ||
60 | var defaultServletHolder = new ServletHolder(DefaultServlet.class); | ||
61 | var isWindows = System.getProperty("os.name").toLowerCase().contains("win"); | ||
62 | // Avoid file locking on Windows: https://stackoverflow.com/a/4985717 | ||
63 | // See also the related Jetty ticket: | ||
64 | // https://github.com/eclipse/jetty.project/issues/2925 | ||
65 | defaultServletHolder.setInitParameter("useFileMappedBuffer", isWindows ? "false" : "true"); | ||
66 | handler.addServlet(defaultServletHolder, "/"); | ||
37 | } | 67 | } |
38 | 68 | ||
39 | public void start() throws Exception { | 69 | public void start() throws Exception { |
@@ -44,54 +74,65 @@ public class ServerLauncher { | |||
44 | if (key != -1) { | 74 | if (key != -1) { |
45 | server.stop(); | 75 | server.stop(); |
46 | } else { | 76 | } else { |
47 | LOG.warn( | 77 | LOG.warn("Console input is not available. " |
48 | "Console input is not available. In order to stop the server, you need to cancel process manually."); | 78 | + "In order to stop the server, you need to cancel process manually."); |
49 | } | 79 | } |
50 | } | 80 | } |
51 | 81 | ||
52 | private static InetSocketAddress getBindAddress(String listenAddress, int port) { | 82 | public static void main(String[] args) { |
53 | if (listenAddress == null) { | 83 | try { |
54 | return new InetSocketAddress(port); | 84 | var bindAddress = getBindAddress(); |
55 | } | 85 | var baseResource = getBaseResource(); |
56 | return new InetSocketAddress(listenAddress, port); | 86 | var serverLauncher = new ServerLauncher(bindAddress, baseResource); |
57 | } | 87 | serverLauncher.start(); |
58 | 88 | } catch (Exception exception) { | |
59 | private static Resource getBaseResource(String baseResourceOverride) throws IOException, URISyntaxException { | 89 | LOG.warn(exception); |
60 | if (baseResourceOverride != null) { | 90 | System.exit(1); |
61 | return Resource.newResource(baseResourceOverride); | ||
62 | } | ||
63 | var indexUrlInJar = ServerLauncher.class.getResource("/webapp/index.html"); | ||
64 | if (indexUrlInJar == null) { | ||
65 | throw new IOException("Cannot find pacakged web assets"); | ||
66 | } | 91 | } |
67 | var webRootUri = URI.create(indexUrlInJar.toURI().toASCIIString().replaceFirst("/index.html$", "/")); | ||
68 | return Resource.newResource(webRootUri); | ||
69 | } | 92 | } |
70 | 93 | ||
71 | public static void main(String[] args) { | 94 | private static String getListenAddress() { |
72 | var listenAddress = System.getenv("LISTEN_ADDRESS"); | 95 | var listenAddress = System.getenv("LISTEN_ADDRESS"); |
73 | if (listenAddress == null) { | 96 | if (listenAddress == null) { |
74 | listenAddress = "localhost"; | 97 | return DEFAULT_LISTEN_ADDRESS; |
75 | } | 98 | } |
76 | var port = 1312; | 99 | return listenAddress; |
100 | } | ||
101 | |||
102 | private static int getListenPort() { | ||
77 | var portStr = System.getenv("LISTEN_PORT"); | 103 | var portStr = System.getenv("LISTEN_PORT"); |
78 | if (portStr != null) { | 104 | if (portStr != null) { |
79 | try { | 105 | return Integer.parseInt(portStr); |
80 | port = Integer.parseInt(portStr); | ||
81 | } catch (NumberFormatException e) { | ||
82 | LOG.warn(e); | ||
83 | System.exit(1); | ||
84 | } | ||
85 | } | 106 | } |
107 | return DEFAULT_LISTEN_PORT; | ||
108 | } | ||
109 | |||
110 | private static InetSocketAddress getBindAddress() { | ||
111 | var listenAddress = getListenAddress(); | ||
112 | var listenPort = getListenPort(); | ||
113 | return new InetSocketAddress(listenAddress, listenPort); | ||
114 | } | ||
115 | |||
116 | private static Resource getBaseResource() throws IOException, URISyntaxException { | ||
86 | var baseResourceOverride = System.getenv("BASE_RESOURCE"); | 117 | var baseResourceOverride = System.getenv("BASE_RESOURCE"); |
87 | try { | 118 | if (baseResourceOverride != null) { |
88 | var bindAddress = getBindAddress(listenAddress, port); | 119 | // If a user override is provided, use it. |
89 | var baseResource = getBaseResource(baseResourceOverride); | 120 | return Resource.newResource(baseResourceOverride); |
90 | var serverLauncher = new ServerLauncher(bindAddress, baseResource); | 121 | } |
91 | serverLauncher.start(); | 122 | var indexUrlInJar = ServerLauncher.class.getResource("/webapp/index.html"); |
92 | } catch (Exception exception) { | 123 | if (indexUrlInJar != null) { |
93 | LOG.warn(exception); | 124 | // If the app is packaged in the jar, serve it. |
94 | System.exit(1); | 125 | var webRootUri = URI.create(indexUrlInJar.toURI().toASCIIString().replaceFirst("/index.html$", "/")); |
126 | return Resource.newResource(webRootUri); | ||
127 | } | ||
128 | // Look for unpacked production artifacts (convenience for running from IDE). | ||
129 | var unpackedResourcePathComponents = new String[] { System.getProperty("user.dir"), "build", "webpack", | ||
130 | "production" }; | ||
131 | var unpackedResourceDir = new File(String.join(File.separator, unpackedResourcePathComponents)); | ||
132 | if (unpackedResourceDir.isDirectory()) { | ||
133 | return Resource.newResource(unpackedResourceDir); | ||
95 | } | 134 | } |
135 | // Fall back to just serving a 404. | ||
136 | return null; | ||
96 | } | 137 | } |
97 | } | 138 | } |