]> git.argeo.org Git - lgpl/argeo-commons.git/blob - swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpHttpLauncher.java
Merge tag 'v2.3.23' into testing
[lgpl/argeo-commons.git] / swt / rcp / org.argeo.cms.swt.rcp / src / org / argeo / cms / ui / rcp / CmsRcpHttpLauncher.java
1 package org.argeo.cms.ui.rcp;
2
3 import static java.lang.System.Logger.Level.DEBUG;
4
5 import java.io.IOException;
6 import java.lang.System.Logger;
7 import java.lang.System.Logger.Level;
8 import java.net.DatagramSocket;
9 import java.net.ServerSocket;
10 import java.net.URI;
11 import java.nio.charset.StandardCharsets;
12 import java.nio.file.Files;
13 import java.nio.file.Path;
14 import java.util.Map;
15 import java.util.concurrent.CompletableFuture;
16
17 import org.argeo.api.cms.CmsApp;
18
19 import com.sun.net.httpserver.HttpExchange;
20 import com.sun.net.httpserver.HttpHandler;
21 import com.sun.net.httpserver.HttpServer;
22
23 /** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
24 public class CmsRcpHttpLauncher {
25 private final static Logger logger = System.getLogger(CmsRcpHttpLauncher.class.getName());
26 private CompletableFuture<HttpServer> httpServer = new CompletableFuture<>();
27
28 private CmsRcpDisplayFactory cmsRcpDisplayFactory;
29
30 public void init() {
31
32 }
33
34 public void destroy() {
35 Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
36 try {
37 if (Files.exists(runFile)) {
38 Files.delete(runFile);
39 }
40 } catch (IOException e) {
41 logger.log(Level.ERROR, "Cannot delete " + runFile, e);
42 }
43 }
44
45 public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
46 final String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
47 if (contextName != null) {
48 httpServer.thenAcceptAsync((httpServer) -> {
49 httpServer.createContext("/" + contextName, new HttpHandler() {
50
51 @Override
52 public void handle(HttpExchange exchange) throws IOException {
53 String path = exchange.getRequestURI().getPath();
54 String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
55 cmsRcpDisplayFactory.openCmsApp(cmsApp, uiName, null);
56 exchange.sendResponseHeaders(200, -1);
57 logger.log(Level.DEBUG, "Opened RCP UI " + uiName + " of CMS App /" + contextName);
58 }
59 });
60 }).exceptionally(e -> {
61 logger.log(Level.ERROR, "Cannot register RCO app " + contextName, e);
62 return null;
63 });
64 logger.log(Level.DEBUG, "Registered RCP CMS APP /" + contextName);
65 }
66 }
67
68 public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
69 String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
70 if (contextName != null) {
71 httpServer.thenAcceptAsync((httpServer) -> {
72 httpServer.removeContext("/" + contextName);
73 });
74 }
75 }
76
77 public void setHttpServer(HttpServer httpServer) {
78 Integer httpPort = httpServer.getAddress().getPort();
79 String baseUrl = "http://localhost:" + httpPort + "/";
80 Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
81 try {
82 if (!Files.exists(runFile)) {
83 Files.createDirectories(runFile.getParent());
84 // TODO give read permission only to the owner
85 Files.createFile(runFile);
86 } else {
87 URI uri = URI.create(Files.readString(runFile));
88 if (!httpPort.equals(uri.getPort()))
89 if (!isPortAvailable(uri.getPort())) {
90 throw new IllegalStateException("Another CMS is running on " + runFile);
91 } else {
92 logger.log(Level.WARNING,
93 "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
94 }
95 }
96 Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
97 } catch (IOException e) {
98 throw new RuntimeException("Cannot write run file to " + runFile, e);
99 }
100 logger.log(DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
101 this.httpServer.complete(httpServer);
102 }
103
104 protected boolean isPortAvailable(int port) {
105 ServerSocket ss = null;
106 DatagramSocket ds = null;
107 try {
108 ss = new ServerSocket(port);
109 ss.setReuseAddress(true);
110 ds = new DatagramSocket(port);
111 ds.setReuseAddress(true);
112 return true;
113 } catch (IOException e) {
114 } finally {
115 if (ds != null) {
116 ds.close();
117 }
118
119 if (ss != null) {
120 try {
121 ss.close();
122 } catch (IOException e) {
123 /* should not be thrown */
124 }
125 }
126 }
127
128 return false;
129 }
130 }