1 package org
.argeo
.cms
.ui
.rcp
;
3 import static java
.lang
.System
.Logger
.Level
.DEBUG
;
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
;
11 import java
.nio
.charset
.StandardCharsets
;
12 import java
.nio
.file
.Files
;
13 import java
.nio
.file
.Path
;
15 import java
.util
.concurrent
.CompletableFuture
;
17 import org
.argeo
.api
.cms
.CmsApp
;
19 import com
.sun
.net
.httpserver
.HttpExchange
;
20 import com
.sun
.net
.httpserver
.HttpHandler
;
21 import com
.sun
.net
.httpserver
.HttpServer
;
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
<>();
28 private CmsRcpDisplayFactory cmsRcpDisplayFactory
;
34 public void destroy() {
35 Path runFile
= CmsRcpDisplayFactory
.getUrlRunFile();
37 if (Files
.exists(runFile
)) {
38 Files
.delete(runFile
);
40 } catch (IOException e
) {
41 logger
.log(Level
.ERROR
, "Cannot delete " + runFile
, e
);
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() {
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
);
60 }).exceptionally(e
-> {
61 logger
.log(Level
.ERROR
, "Cannot register RCO app " + contextName
, e
);
64 logger
.log(Level
.DEBUG
, "Registered RCP CMS APP /" + contextName
);
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
);
77 public void setHttpServer(HttpServer httpServer
) {
78 Integer httpPort
= httpServer
.getAddress().getPort();
79 String baseUrl
= "http://localhost:" + httpPort
+ "/";
80 Path runFile
= CmsRcpDisplayFactory
.getUrlRunFile();
82 if (!Files
.exists(runFile
)) {
83 Files
.createDirectories(runFile
.getParent());
84 // TODO give read permission only to the owner
85 Files
.createFile(runFile
);
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
);
92 logger
.log(Level
.WARNING
,
93 "Run file " + runFile
+ " found but port of " + uri
+ " is available. Overwriting...");
96 Files
.writeString(runFile
, baseUrl
, StandardCharsets
.UTF_8
);
97 } catch (IOException e
) {
98 throw new RuntimeException("Cannot write run file to " + runFile
, e
);
100 logger
.log(DEBUG
, "RCP available under " + baseUrl
+ ", written to " + runFile
);
101 this.httpServer
.complete(httpServer
);
104 protected boolean isPortAvailable(int port
) {
105 ServerSocket ss
= null;
106 DatagramSocket ds
= null;
108 ss
= new ServerSocket(port
);
109 ss
.setReuseAddress(true);
110 ds
= new DatagramSocket(port
);
111 ds
.setReuseAddress(true);
113 } catch (IOException e
) {
122 } catch (IOException e
) {
123 /* should not be thrown */