Simplify CMS RCP
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 3 Nov 2022 08:05:34 +0000 (09:05 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 3 Nov 2022 08:05:34 +0000 (09:05 +0100)
swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpDisplayFactory.xml
swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpHttpLauncher.xml [new file with mode: 0644]
swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpServletFactory.xml [deleted file]
swt/rcp/org.argeo.cms.swt.rcp/bnd.bnd
swt/rcp/org.argeo.cms.swt.rcp/build.properties
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpDisplayFactory.java
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpHttpLauncher.java [new file with mode: 0644]
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServlet.java [deleted file]
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServletFactory.java [deleted file]

index a0c0f0f5c0cd61777a0d99ac5fce663a2e6e7a0b..8b1d1468478f9a786ab3037ee89eaec06ad0a833 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Display Factory">
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="CMS RCP Display Factory">
    <implementation class="org.argeo.cms.ui.rcp.CmsRcpDisplayFactory"/>
 </scr:component>
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpHttpLauncher.xml b/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpHttpLauncher.xml
new file mode 100644 (file)
index 0000000..03abe19
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="CMS RCP Servlet Factory">
+   <implementation class="org.argeo.cms.ui.rcp.CmsRcpHttpLauncher"/>
+   <reference bind="setHttpServer" cardinality="1..1" interface="com.sun.net.httpserver.HttpServer" name="HttpServer" policy="static"/>
+   <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
+</scr:component>
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpServletFactory.xml b/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpServletFactory.xml
deleted file mode 100644 (file)
index 5f6b94e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Servlet Factory">
-   <implementation class="org.argeo.cms.ui.rcp.servlet.CmsRcpServletFactory"/>
-   <reference bind="setHttpServer" cardinality="1..1" interface="com.sun.net.httpserver.HttpServer" name="HttpServer" policy="static"/>
-   <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
-</scr:component>
index 91f0a8a3718eb5cb4d1a5140d6fe8bca8bc160f1..5cf5164e1b69f8c09156c2ee14ec4e29367405df 100644 (file)
@@ -1,3 +1,4 @@
+Bundle-SymbolicName: org.argeo.cms.swt.rcp;singleton=true
 
 Import-Package:\
 org.argeo.cms.auth,\
@@ -8,5 +9,5 @@ org.w3c.css.sac,\
 
 Service-Component:\
 OSGI-INF/cmsRcpDisplayFactory.xml,\
-OSGI-INF/cmsRcpServletFactory.xml
+OSGI-INF/cmsRcpHttpLauncher.xml
 
index 5eef7058e47f4318354d9b883628b2ce2723114c..4ed1d4748afc3e7dc121f8f0fab5a1c1a56d24e3 100644 (file)
@@ -2,5 +2,5 @@ output.. = bin/
 bin.includes = META-INF/,\
                .,\
                OSGI-INF/,\
-               OSGI-INF/cmsRcpServletFactory.xml
+               OSGI-INF/cmsRcpHttpLauncher.xml
 source.. = src/
index 950acceceb1f0edff1c764143e62b1b63babe3e9..e94825db818c6014f30ea28ebf7be8ff42833884 100644 (file)
@@ -1,5 +1,7 @@
 package org.argeo.cms.ui.rcp;
 
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
 import java.nio.file.Path;
 
 import org.argeo.api.cms.CmsApp;
@@ -9,6 +11,8 @@ import org.eclipse.swt.widgets.Display;
 
 /** Creates the SWT {@link Display} in a dedicated thread. */
 public class CmsRcpDisplayFactory {
+       private final static Logger logger = System.getLogger(CmsRcpDisplayFactory.class.getName());
+
        /** File name in a run directory */
        private final static String ARGEO_RCP_URL = "argeo.rcp.url";
 
@@ -50,20 +54,22 @@ public class CmsRcpDisplayFactory {
 
                @Override
                public void run() {
-                       display = Display.getDefault();
-                       display.setRuntimeExceptionHandler((e) -> e.printStackTrace());
-                       display.setErrorHandler((e) -> e.printStackTrace());
-
-//                     for (String contextName : cmsApps.keySet()) {
-//                             openCmsApp(contextName);
-//                     }
-
-                       while (!shutdown) {
-                               if (!display.readAndDispatch())
-                                       display.sleep();
+                       try {
+                               display = Display.getDefault();
+                               display.setRuntimeExceptionHandler((e) -> e.printStackTrace());
+                               display.setErrorHandler((e) -> e.printStackTrace());
+
+                               while (!shutdown) {
+                                       if (!display.readAndDispatch())
+                                               display.sleep();
+                               }
+                               display.dispose();
+                               display = null;
+                       } catch (UnsatisfiedLinkError e) {
+                               logger.log(Level.ERROR,
+                                               "Cannot load SWT, probably because the OSGi framework has been refresh. Restart the application.",
+                                               e);
                        }
-                       display.dispose();
-                       display = null;
                }
        }
 
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpHttpLauncher.java b/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpHttpLauncher.java
new file mode 100644 (file)
index 0000000..6246b0d
--- /dev/null
@@ -0,0 +1,128 @@
+package org.argeo.cms.ui.rcp;
+
+import static java.lang.System.Logger.Level.DEBUG;
+
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import org.argeo.api.cms.CmsApp;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+/** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
+public class CmsRcpHttpLauncher {
+       private final static Logger logger = System.getLogger(CmsRcpHttpLauncher.class.getName());
+       private CompletableFuture<HttpServer> httpServer = new CompletableFuture<>();
+
+       public void init() {
+
+       }
+
+       public void destroy() {
+               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
+               try {
+                       if (Files.exists(runFile)) {
+                               Files.delete(runFile);
+                       }
+               } catch (IOException e) {
+                       logger.log(Level.ERROR, "Cannot delete " + runFile, e);
+               }
+       }
+
+       public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+               final String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+               if (contextName != null) {
+                       httpServer.thenAcceptAsync((httpServer) -> {
+                               httpServer.createContext("/" + contextName, new HttpHandler() {
+
+                                       @Override
+                                       public void handle(HttpExchange exchange) throws IOException {
+                                               String path = exchange.getRequestURI().getPath();
+                                               String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
+                                               CmsRcpDisplayFactory.openCmsApp(cmsApp, uiName, null);
+                                               exchange.sendResponseHeaders(200, -1);
+                                               logger.log(Level.DEBUG, "Opened RCP UI  " + uiName + " of  CMS App /" + contextName);
+                                       }
+                               });
+                       }).exceptionally(e -> {
+                               logger.log(Level.ERROR, "Cannot register RCO app " + contextName, e);
+                               return null;
+                       });
+                       logger.log(Level.DEBUG, "Registered RCP CMS APP /" + contextName);
+               }
+       }
+
+       public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+               String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+               if (contextName != null) {
+                       httpServer.thenAcceptAsync((httpServer) -> {
+                               httpServer.removeContext("/" + contextName);
+                       });
+               }
+       }
+
+       public void setHttpServer(HttpServer httpServer) {
+               Integer httpPort = httpServer.getAddress().getPort();
+               String baseUrl = "http://localhost:" + httpPort + "/";
+               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
+               try {
+                       if (!Files.exists(runFile)) {
+                               Files.createDirectories(runFile.getParent());
+                               // TODO give read permission only to the owner
+                               Files.createFile(runFile);
+                       } else {
+                               URI uri = URI.create(Files.readString(runFile));
+                               if (!httpPort.equals(uri.getPort()))
+                                       if (!isPortAvailable(uri.getPort())) {
+                                               throw new IllegalStateException("Another CMS is running on " + runFile);
+                                       } else {
+                                               logger.log(Level.WARNING,
+                                                               "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
+                                       }
+                       }
+                       Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot write run file to " + runFile, e);
+               }
+               logger.log(DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
+               this.httpServer.complete(httpServer);
+       }
+
+       protected boolean isPortAvailable(int port) {
+               ServerSocket ss = null;
+               DatagramSocket ds = null;
+               try {
+                       ss = new ServerSocket(port);
+                       ss.setReuseAddress(true);
+                       ds = new DatagramSocket(port);
+                       ds.setReuseAddress(true);
+                       return true;
+               } catch (IOException e) {
+               } finally {
+                       if (ds != null) {
+                               ds.close();
+                       }
+
+                       if (ss != null) {
+                               try {
+                                       ss.close();
+                               } catch (IOException e) {
+                                       /* should not be thrown */
+                               }
+                       }
+               }
+
+               return false;
+       }
+}
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServlet.java b/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServlet.java
deleted file mode 100644 (file)
index 8579527..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.cms.ui.rcp.servlet;
-
-import java.io.IOException;
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.util.Objects;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
-
-/** Open the related app when called. */
-public class CmsRcpServlet extends HttpServlet {
-       private static final long serialVersionUID = -3944472431354848923L;
-       private final static Logger logger = System.getLogger(CmsRcpServlet.class.getName());
-
-       private CmsApp cmsApp;
-
-       public CmsRcpServlet(CmsApp cmsApp) {
-               Objects.requireNonNull(cmsApp);
-               this.cmsApp = cmsApp;
-       }
-
-       @Override
-       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-               String path = req.getPathInfo();
-               String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
-               CmsRcpDisplayFactory.openCmsApp(cmsApp, uiName, null);
-               logger.log(Level.DEBUG, "Opened RCP UI  " + uiName + " of  CMS App " + req.getServletPath());
-       }
-
-}
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServletFactory.java b/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServletFactory.java
deleted file mode 100644 (file)
index 778cd1b..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.argeo.cms.ui.rcp.servlet;
-
-import static java.lang.System.Logger.Level.DEBUG;
-
-import java.io.IOException;
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.net.DatagramSocket;
-import java.net.ServerSocket;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
-
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
-
-/** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
-public class CmsRcpServletFactory {
-       private final static Logger logger = System.getLogger(CmsRcpServletFactory.class.getName());
-       private CompletableFuture<HttpServer> httpServer = new CompletableFuture<>();
-
-       public void init() {
-
-       }
-
-       public void destroy() {
-               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
-               try {
-                       if (Files.exists(runFile)) {
-                               Files.delete(runFile);
-                       }
-               } catch (IOException e) {
-                       logger.log(Level.ERROR, "Cannot delete " + runFile, e);
-               }
-       }
-
-       public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
-               final String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
-               if (contextName != null) {
-                       httpServer.thenAcceptAsync((httpServer) -> {
-                               httpServer.createContext("/" + contextName, new HttpHandler() {
-
-                                       @Override
-                                       public void handle(HttpExchange exchange) throws IOException {
-                                               String path = exchange.getRequestURI().getPath();
-                                               String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
-                                               CmsRcpDisplayFactory.openCmsApp(cmsApp, uiName, null);
-                                               exchange.sendResponseHeaders(200, -1);
-                                               logger.log(Level.DEBUG, "Opened RCP UI  " + uiName + " of  CMS App /" + contextName);
-                                       }
-                               });
-                       }).exceptionally(e -> {
-                               logger.log(Level.ERROR, "Cannot register RCO app " + contextName, e);
-                               return null;
-                       });
-                       logger.log(Level.DEBUG, "Registered RCP CMS APP /" + contextName);
-               }
-       }
-
-       public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
-               String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
-               if (contextName != null) {
-                       httpServer.thenAcceptAsync((httpServer) -> {
-                               httpServer.removeContext("/" + contextName);
-                       });
-               }
-       }
-
-       public void setHttpServer(HttpServer httpServer) {
-               Integer httpPort = httpServer.getAddress().getPort();
-               String baseUrl = "http://localhost:" + httpPort + "/";
-               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
-               try {
-                       if (!Files.exists(runFile)) {
-                               Files.createDirectories(runFile.getParent());
-                               // TODO give read permission only to the owner
-                               Files.createFile(runFile);
-                       } else {
-                               URI uri = URI.create(Files.readString(runFile));
-                               if (!httpPort.equals(uri.getPort()))
-                                       if (!isPortAvailable(uri.getPort())) {
-                                               throw new IllegalStateException("Another CMS is running on " + runFile);
-                                       } else {
-                                               logger.log(Level.WARNING,
-                                                               "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
-                                       }
-                       }
-                       Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot write run file to " + runFile, e);
-               }
-               logger.log(DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
-               this.httpServer.complete(httpServer);
-       }
-
-       protected boolean isPortAvailable(int port) {
-               ServerSocket ss = null;
-               DatagramSocket ds = null;
-               try {
-                       ss = new ServerSocket(port);
-                       ss.setReuseAddress(true);
-                       ds = new DatagramSocket(port);
-                       ds.setReuseAddress(true);
-                       return true;
-               } catch (IOException e) {
-               } finally {
-                       if (ds != null) {
-                               ds.close();
-                       }
-
-                       if (ss != null) {
-                               try {
-                                       ss.close();
-                               } catch (IOException e) {
-                                       /* should not be thrown */
-                               }
-                       }
-               }
-
-               return false;
-       }
-}