]> git.argeo.org Git - lgpl/argeo-commons.git/blob - servlet/CmsRcpServletFactory.java
Prepare next development cycle
[lgpl/argeo-commons.git] / servlet / CmsRcpServletFactory.java
1 package org.argeo.cms.ui.rcp.servlet;
2
3 import java.io.IOException;
4 import java.lang.System.Logger;
5 import java.lang.System.Logger.Level;
6 import java.net.DatagramSocket;
7 import java.net.ServerSocket;
8 import java.net.URI;
9 import java.nio.charset.StandardCharsets;
10 import java.nio.file.Files;
11 import java.nio.file.Path;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.Hashtable;
15 import java.util.Map;
16 import java.util.concurrent.CompletableFuture;
17
18 import javax.servlet.Servlet;
19
20 import org.argeo.api.cms.CmsApp;
21 import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
22 import org.osgi.framework.BundleContext;
23 import org.osgi.framework.FrameworkUtil;
24 import org.osgi.framework.ServiceRegistration;
25 import org.osgi.service.event.EventAdmin;
26 import org.osgi.service.http.HttpService;
27
28 /** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
29 public class CmsRcpServletFactory {
30 private final static Logger logger = System.getLogger(CmsRcpServletFactory.class.getName());
31
32 private BundleContext bundleContext = FrameworkUtil.getBundle(CmsRcpServletFactory.class).getBundleContext();
33
34 private CompletableFuture<EventAdmin> eventAdmin = new CompletableFuture<>();
35
36 private Map<String, ServiceRegistration<Servlet>> registrations = Collections.synchronizedMap(new HashMap<>());
37
38 public void init() {
39
40 }
41
42 public void destroy() {
43 Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
44 try {
45 if (Files.exists(runFile)) {
46 Files.delete(runFile);
47 }
48 } catch (IOException e) {
49 logger.log(Level.ERROR, "Cannot delete " + runFile, e);
50 }
51 }
52
53 public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
54 String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
55 if (contextName != null) {
56 eventAdmin.thenAccept((eventAdmin) -> {
57 CmsRcpServlet servlet = new CmsRcpServlet(eventAdmin, cmsApp);
58 Hashtable<String, String> serviceProperties = new Hashtable<>();
59 serviceProperties.put("osgi.http.whiteboard.servlet.pattern", "/" + contextName + "/*");
60 ServiceRegistration<Servlet> sr = bundleContext.registerService(Servlet.class, servlet,
61 serviceProperties);
62 registrations.put(contextName, sr);
63 });
64 }
65 }
66
67 public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
68 String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
69 if (contextName != null) {
70 ServiceRegistration<Servlet> sr = registrations.get(contextName);
71 sr.unregister();
72 }
73 }
74
75 public void setEventAdmin(EventAdmin eventAdmin) {
76 this.eventAdmin.complete(eventAdmin);
77 }
78
79 public void setHttpService(HttpService httpService, Map<String, Object> properties) {
80 Integer httpPort = Integer.parseInt(properties.get("http.port").toString());
81 String baseUrl = "http://localhost:" + httpPort + "/";
82 Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
83 try {
84 if (!Files.exists(runFile)) {
85 Files.createDirectories(runFile.getParent());
86 // TODO give read permission only to the owner
87 Files.createFile(runFile);
88 } else {
89 URI uri = URI.create(Files.readString(runFile));
90 if (!httpPort.equals(uri.getPort()))
91 if (!isPortAvailable(uri.getPort())) {
92 throw new IllegalStateException("Another CMS is running on " + runFile);
93 } else {
94 logger.log(Level.WARNING,
95 "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
96 }
97 }
98 Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
99 } catch (IOException e) {
100 throw new RuntimeException("Cannot write run file to " + runFile, e);
101 }
102 logger.log(Level.DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
103 }
104
105 protected boolean isPortAvailable(int port) {
106 ServerSocket ss = null;
107 DatagramSocket ds = null;
108 try {
109 ss = new ServerSocket(port);
110 ss.setReuseAddress(true);
111 ds = new DatagramSocket(port);
112 ds.setReuseAddress(true);
113 return true;
114 } catch (IOException e) {
115 } finally {
116 if (ds != null) {
117 ds.close();
118 }
119
120 if (ss != null) {
121 try {
122 ss.close();
123 } catch (IOException e) {
124 /* should not be thrown */
125 }
126 }
127 }
128
129 return false;
130 }
131 }