<?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>
--- /dev/null
+<?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>
+++ /dev/null
-<?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>
+Bundle-SymbolicName: org.argeo.cms.swt.rcp;singleton=true
Import-Package:\
org.argeo.cms.auth,\
Service-Component:\
OSGI-INF/cmsRcpDisplayFactory.xml,\
-OSGI-INF/cmsRcpServletFactory.xml
+OSGI-INF/cmsRcpHttpLauncher.xml
bin.includes = META-INF/,\
.,\
OSGI-INF/,\
- OSGI-INF/cmsRcpServletFactory.xml
+ OSGI-INF/cmsRcpHttpLauncher.xml
source.. = src/
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;
/** 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";
@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;
}
}
--- /dev/null
+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;
+ }
+}
+++ /dev/null
-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());
- }
-
-}
+++ /dev/null
-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;
- }
-}