]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.jshell/src/org/argeo/cms/jshell/CmsJShell.java
Merge tag 'v2.3.17' into testing
[lgpl/argeo-commons.git] / org.argeo.cms.jshell / src / org / argeo / cms / jshell / CmsJShell.java
1 package org.argeo.cms.jshell;
2
3 import java.io.IOException;
4 import java.nio.file.DirectoryStream;
5 import java.nio.file.FileSystems;
6 import java.nio.file.Files;
7 import java.nio.file.Path;
8 import java.nio.file.StandardWatchEventKinds;
9 import java.nio.file.WatchEvent;
10 import java.nio.file.WatchKey;
11 import java.nio.file.WatchService;
12 import java.util.HashMap;
13 import java.util.Map;
14 import java.util.UUID;
15
16 import org.argeo.api.cms.CmsLog;
17 import org.argeo.api.cms.CmsState;
18 import org.argeo.api.uuid.UuidFactory;
19 import org.argeo.cms.util.OS;
20 import org.argeo.internal.cms.jshell.osgi.OsgiExecutionControlProvider;
21 import org.osgi.framework.Bundle;
22
23 /** A factory for JShell sessions. */
24 public class CmsJShell {
25 private final static CmsLog log = CmsLog.getLog(CmsJShell.class);
26 static ClassLoader loader = CmsJShell.class.getClassLoader();
27
28 public static UuidFactory uuidFactory = null;
29
30 private CmsState cmsState;
31
32 private Map<Path, LocalJShellSession> localSessions = new HashMap<>();
33 private Map<Path, Path> bundleDirs = new HashMap<>();
34
35 private Path stateRunDir;
36 private Path jshBase;
37 private Path jshLinkedDir;
38 private Path jtermBase;
39 private Path jtermLinkedDir;
40
41 public void start() throws Exception {
42 // TODO better define application id, make it configurable
43 String applicationID;
44 if (Files.exists(cmsState.getStatePath("dev.properties"))) { // in Eclipse
45 applicationID = cmsState.getStatePath("").getFileName().toString();
46 } else {
47 applicationID = cmsState.getStatePath("").getParent().getFileName().toString();
48 }
49
50 // TODO centralise state run dir
51 stateRunDir = OS.getRunDir().resolve(applicationID);
52
53 jshBase = stateRunDir.resolve(JShellClient.JSH);
54 Files.createDirectories(jshBase);
55 jshLinkedDir = Files.createSymbolicLink(cmsState.getStatePath(JShellClient.JSH), jshBase);
56
57 jtermBase = stateRunDir.resolve(JShellClient.JTERM);
58 Files.createDirectories(jtermBase);
59 jtermLinkedDir = Files.createSymbolicLink(cmsState.getStatePath(JShellClient.JTERM), jtermBase);
60
61 log.info("Local JShell on " + jshBase + ", linked to " + jshLinkedDir);
62 log.info("Local JTerm on " + jtermBase + ", linked to " + jtermLinkedDir);
63
64 new Thread(() -> {
65 try {
66 WatchService watchService = FileSystems.getDefault().newWatchService();
67
68 jshBase.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
69 StandardWatchEventKinds.ENTRY_DELETE);
70 try (DirectoryStream<Path> bundleSns = Files.newDirectoryStream(jshBase)) {
71 for (Path bundleSnDir : bundleSns) {
72 addBundleSnDir(bundleSnDir, watchService);
73 }
74 }
75 jtermBase.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
76 StandardWatchEventKinds.ENTRY_DELETE);
77 try (DirectoryStream<Path> bundleSns = Files.newDirectoryStream(jtermBase)) {
78 for (Path bundleSnDir : bundleSns) {
79 addBundleSnDir(bundleSnDir, watchService);
80 }
81 }
82
83 WatchKey key;
84 while ((key = watchService.take()) != null) {
85 events: for (WatchEvent<?> event : key.pollEvents()) {
86 // System.out.println("Event kind:" + event.kind() + ". File affected: " + event.context() + ".");
87 Path parent = (Path) key.watchable();
88 // sessions
89 if (Files.isSameFile(jshBase, parent)) {
90 Path bundleSnDir = jshBase.resolve((Path) event.context());
91 if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
92 addBundleSnDir(bundleSnDir, watchService);
93 } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) {
94 }
95 } else if (Files.isSameFile(jtermBase, parent)) {
96 Path bundleSnDir = jtermBase.resolve((Path) event.context());
97 if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
98 addBundleSnDir(bundleSnDir, watchService);
99 } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) {
100 }
101 } else {
102 Path path = parent.resolve((Path) event.context());
103 if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
104 if (!Files.isDirectory(path)) {
105 log.warn("Ignoring " + path + " as it is not a directory");
106 continue events;
107 }
108 try {
109 UUID.fromString(path.getFileName().toString());
110 } catch (IllegalArgumentException e) {
111 log.warn("Ignoring " + path + " as it is not named as UUID");
112 continue events;
113 }
114
115 boolean interactive;
116 if (Files.isSameFile(jshBase, parent.getParent())) {
117 interactive = false;
118 } else if (Files.isSameFile(jtermBase, parent.getParent())) {
119 interactive = true;
120 } else {
121 log.warn("Ignoring " + path + " as we don't know whether it is interactive or not");
122 continue events;
123 }
124 Path bundleIdDir = bundleDirs.get(parent);
125 LocalJShellSession localSession = new LocalJShellSession(path, bundleIdDir,
126 interactive);
127 localSessions.put(path, localSession);
128 } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) {
129 localSessions.remove(path);
130 }
131 }
132 }
133 key.reset();
134 }
135 } catch (IOException | InterruptedException e) {
136 e.printStackTrace();
137 }
138 }, "JShell local sessions watcher").start();
139 }
140
141 private void addBundleSnDir(Path bundleSnDir, WatchService watchService) throws IOException {
142 String symbolicName = bundleSnDir.getFileName().toString();
143 Bundle fromBundle = OsgiExecutionControlProvider.getBundleFromSn(symbolicName);
144 if (fromBundle == null) {
145 log.error("Ignoring bundle " + symbolicName + " because it was not found");
146 return;
147 }
148 Long bundleId = fromBundle.getBundleId();
149 Path bundleIdDir = stateRunDir.resolve(bundleId.toString());
150 Files.createDirectories(bundleIdDir);
151 bundleDirs.put(bundleSnDir, bundleIdDir);
152
153 bundleSnDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
154 }
155
156 public void stop() {
157 try {
158 Files.delete(jshLinkedDir);
159 } catch (IOException e) {
160 log.error("Cannot remove " + jshLinkedDir);
161 }
162 try {
163 Files.delete(jtermLinkedDir);
164 } catch (IOException e) {
165 log.error("Cannot remove " + jtermLinkedDir);
166 }
167 }
168
169 public void setCmsState(CmsState cmsState) {
170 this.cmsState = cmsState;
171 }
172 }