From 00d7430765eba4f0c13f8300515a679a808bc7b1 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sun, 3 May 2020 12:25:56 +0200 Subject: [PATCH] Introduce lightweight RWT runner. --- org.argeo.eclipse.ui.rap/bnd.bnd | 6 + .../org/argeo/eclipse/ui/jetty/RwtRunner.java | 135 ++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/jetty/RwtRunner.java diff --git a/org.argeo.eclipse.ui.rap/bnd.bnd b/org.argeo.eclipse.ui.rap/bnd.bnd index fb50c88ef..f73a8d019 100644 --- a/org.argeo.eclipse.ui.rap/bnd.bnd +++ b/org.argeo.eclipse.ui.rap/bnd.bnd @@ -2,4 +2,10 @@ Import-Package: org.eclipse.swt,\ org.eclipse.jface.dialogs,\ org.argeo.eclipse.ui.util,\ org.eclipse.swt.events,\ +org.eclipse.jetty.util.component;resolution:=optional,\ +org.eclipse.jetty.http;resolution:=optional,\ +org.eclipse.jetty.io;resolution:=optional,\ +org.eclipse.jetty.security;resolution:=optional,\ +org.eclipse.jetty.server.handler;resolution:=optional,\ +org.eclipse.jetty.*;resolution:=optional,\ * diff --git a/org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/jetty/RwtRunner.java b/org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/jetty/RwtRunner.java new file mode 100644 index 000000000..29165a4ef --- /dev/null +++ b/org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/jetty/RwtRunner.java @@ -0,0 +1,135 @@ +package org.argeo.eclipse.ui.jetty; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.rap.rwt.application.AbstractEntryPoint; +import org.eclipse.rap.rwt.application.ApplicationRunner; +import org.eclipse.rap.rwt.engine.RWTServlet; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; + +/** A minimal RWT runner based on embedded Jetty. */ +public class RwtRunner { + + private final Server server; + private final ServerConnector serverConnector; + private Path tempDir; + + public RwtRunner() { + server = new Server(new QueuedThreadPool(10, 1)); + serverConnector = new ServerConnector(server); + serverConnector.setPort(0); + server.setConnectors(new Connector[] { serverConnector }); + } + + protected Control createUi(Composite parent, Object context) { + return new Label(parent, SWT.NONE); + } + + public void init() { + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + server.setHandler(context); + + String entryPoint = "app"; + + // rwt-resources requires a file system + try { + tempDir = Files.createTempDirectory("argeo-rwtRunner"); + context.setBaseResource(Resource.newResource(tempDir.resolve("www").toString())); + } catch (IOException e) { + throw new IllegalStateException("Cannot create temporary directory", e); + } + context.addEventListener(new ServletContextListener() { + ApplicationRunner applicationRunner; + + @Override + public void contextInitialized(ServletContextEvent sce) { + applicationRunner = new ApplicationRunner( + (application) -> application.addEntryPoint("/" + entryPoint, () -> new AbstractEntryPoint() { + private static final long serialVersionUID = 5678385921969090733L; + + @Override + protected void createContents(Composite parent) { + createUi(parent, null); + } + }, null), sce.getServletContext()); + applicationRunner.start(); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + applicationRunner.stop(); + } + }); + + context.addServlet(new ServletHolder(new RWTServlet()), "/" + entryPoint); + + // Required to serve rwt-resources. It is important that this is last. + ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class); + context.addServlet(holderPwd, "/"); + + try { + server.start(); + } catch (Exception e) { + throw new IllegalStateException("Cannot start Jetty server", e); + } + } + + public void destroy() { + try { + serverConnector.close(); + server.stop(); + // TODO delete temp dir + } catch (Exception e) { + e.printStackTrace(); + } + } + + public Integer getEffectivePort() { + return serverConnector.getLocalPort(); + } + + public void waitFor() throws InterruptedException { + server.join(); + } + + public static void main(String[] args) throws Exception { + RwtRunner rwtRunner = new RwtRunner() { + + @Override + protected Control createUi(Composite parent, Object context) { + Label label = new Label(parent, SWT.NONE); + label.setText("Hello world!"); + return label; + } + }; + rwtRunner.init(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> rwtRunner.destroy(), "Jetty shutdown")); + + long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime(); + System.out.println("App available in " + jvmUptime + " ms, on port " + rwtRunner.getEffectivePort()); + + // open browser in app mode + Thread.sleep(2000);// wait for RWT to be ready + Runtime.getRuntime().exec("google-chrome --app=http://localhost:" + rwtRunner.getEffectivePort() + "/app"); + + rwtRunner.waitFor(); + } +} -- 2.30.2