]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.jshell/src/org/argeo/cms/jshell/CmsJShell.java
4df9b819e95591fdb8df809e0d2b7426351d6f6b
[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 public class CmsJShell {
24 private final static CmsLog log = CmsLog.getLog(CmsJShell.class);
25 static ClassLoader loader = CmsJShell.class.getClassLoader();
26
27 public static UuidFactory uuidFactory = null;
28
29 private CmsState cmsState;
30
31 private Map<Path, LocalJShellSession> localSessions = new HashMap<>();
32 private Map<Path, Path> bundleDirs = new HashMap<>();
33
34 private Path stateRunDir;
35 private Path localBase;
36 private Path linkedDir;
37
38 // private String defaultBundle = "org.argeo.cms.cli";
39
40 public void start() throws Exception {
41
42 // Path localBase = cmsState.getStatePath("org.argeo.cms.jshell/local");
43 // UUID stateUuid = cmsState.getUuid();
44
45 // TODO better define application id, make it configurable
46 String applicationID = cmsState.getStatePath("").getFileName().toString();
47
48 // TODO centralise state run dir
49 stateRunDir = OS.getRunDir().resolve(applicationID);
50 localBase = stateRunDir.resolve("jsh");
51 Files.createDirectories(localBase);
52
53 linkedDir = Files.createSymbolicLink(cmsState.getStatePath("jsh"), localBase);
54
55 log.info("Local JShell on " + localBase + ", linked to " + linkedDir);
56
57 new Thread(() -> {
58 try {
59 WatchService watchService = FileSystems.getDefault().newWatchService();
60
61 localBase.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
62 StandardWatchEventKinds.ENTRY_DELETE);
63 try (DirectoryStream<Path> bundleSns = Files.newDirectoryStream(localBase)) {
64 for (Path bundleSnDir : bundleSns) {
65 addBundleSnDir(bundleSnDir);
66 if (bundleDirs.containsKey(bundleSnDir)) {
67 bundleSnDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
68 StandardWatchEventKinds.ENTRY_DELETE);
69 }
70 }
71 }
72
73 WatchKey key;
74 while ((key = watchService.take()) != null) {
75 events: for (WatchEvent<?> event : key.pollEvents()) {
76 // System.out.println("Event kind:" + event.kind() + ". File affected: " + event.context() + ".");
77 Path parent = (Path) key.watchable();
78 // sessions
79 if (Files.isSameFile(localBase, parent)) {
80 Path bundleSnDir = localBase.resolve((Path) event.context());
81 if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
82 addBundleSnDir(bundleSnDir);
83 if (bundleDirs.containsKey(bundleSnDir)) {
84 bundleSnDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
85 StandardWatchEventKinds.ENTRY_DELETE);
86 }
87 } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) {
88 }
89 } else {
90 Path path = parent.resolve((Path) event.context());
91 if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
92 if (!Files.isDirectory(path)) {
93 log.warn("Ignoring " + path + " as it is not a directory");
94 continue events;
95 }
96 try {
97 UUID.fromString(path.getFileName().toString());
98 } catch (IllegalArgumentException e) {
99 log.warn("Ignoring " + path + " as it is not named as UUID");
100 continue events;
101 }
102
103 Path bundleIdDir = bundleDirs.get(parent);
104 LocalJShellSession localSession = new LocalJShellSession(path, bundleIdDir);
105 localSessions.put(path, localSession);
106 } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) {
107 // TODO clean up session
108 LocalJShellSession localSession = localSessions.remove(path);
109 localSession.cleanUp();
110 }
111 }
112 }
113 key.reset();
114 }
115 } catch (IOException | InterruptedException e) {
116 e.printStackTrace();
117 }
118 }, "JShell local sessions watcher").start();
119
120 // thread context class loader should be where the service is defined
121 // Thread.currentThread().setContextClassLoader(loader);
122 // JavaShellToolBuilder builder = JavaShellToolBuilder.builder();
123 //
124 // builder.start("--execution", "osgi:bundle(org.argeo.cms.jshell)");
125
126 }
127
128 private void addBundleSnDir(Path bundleSnDir) throws IOException {
129 String symbolicName = bundleSnDir.getFileName().toString();
130 Bundle fromBundle = OsgiExecutionControlProvider.getBundleFromSn(symbolicName);
131 if (fromBundle == null) {
132 log.error("Ignoring bundle " + symbolicName + " because it was not found");
133 return;
134 }
135 Long bundleId = fromBundle.getBundleId();
136 Path bundleIdDir = stateRunDir.resolve(bundleId.toString());
137 Files.createDirectories(bundleIdDir);
138 bundleDirs.put(bundleSnDir, bundleIdDir);
139 }
140
141 // public void startX(BundleContext bc) {
142 // uuidFactory = new NoOpUuidFactory();
143 //
144 // List<String> locations = new ArrayList<>();
145 // for (Bundle bundle : bc.getBundles()) {
146 // locations.add(bundle.getLocation());
147 //// System.out.println(bundle.getLocation());
148 // }
149 //
150 // CmsState cmsState = (CmsState) bc.getService(bc.getServiceReference("org.argeo.api.cms.CmsState"));
151 // System.out.println(cmsState.getDeployProperties(CmsDeployProperty.HTTP_PORT.getProperty()));
152 // System.out.println(cmsState.getUuid());
153 //
154 // ExecutionControlProvider executionControlProvider = new ExecutionControlProvider() {
155 // @Override
156 // public String name() {
157 // return "name";
158 // }
159 //
160 // @Override
161 // public ExecutionControl generate(ExecutionEnv ee, Map<String, String> map) throws Throwable {
162 // return new LocalExecutionControl(new WrappingLoaderDelegate(loader));
163 //// Thread.currentThread().setContextClassLoader(loader);
164 //// return new DirectExecutionControl();
165 // }
166 // };
167 //
168 //// Thread.currentThread().setContextClassLoader(loader);
169 //
170 // try (JShell js = JShell.builder().executionEngine(executionControlProvider, null).build()) {
171 // js.addToClasspath("/home/mbaudier/dev/git/unstable/output/a2/org.argeo.cms/org.argeo.api.cms.2.3.jar");
172 // js.addToClasspath("/home/mbaudier/dev/git/unstable/output/a2/org.argeo.cms/org.argeo.cms.2.3.jar");
173 // js.addToClasspath(
174 // "/home/mbaudier/dev/git/unstable/output/a2/osgi/equinox/org.argeo.tp.osgi/org.eclipse.osgi.3.18.jar");
175 //// do {
176 // System.out.print("Enter some Java code: ");
177 // // String input = console.readLine();
178 // String imports = """
179 // import org.argeo.api.cms.*;
180 // import org.argeo.cms.*;
181 // import org.argeo.slc.jshell.*;
182 // """;
183 // js.eval(imports);
184 // String input = """
185 // var bc = org.osgi.framework.FrameworkUtil.getBundle(org.argeo.cms.CmsDeployProperty.class).getBundleContext();
186 // var cmsState =(org.argeo.api.cms.CmsState) bc.getService(bc.getServiceReference("org.argeo.api.cms.CmsState"));
187 // System.out.println(cmsState.getDeployProperties(org.argeo.cms.CmsDeployProperty.HTTP_PORT.getProperty()));
188 // cmsState.getUuid();
189 // """;
190 //// if (input == null) {
191 //// break;
192 //// }
193 //
194 // input.lines().forEach((l) -> {
195 //
196 // List<SnippetEvent> events = js.eval(l);
197 // for (SnippetEvent e : events) {
198 // StringBuilder sb = new StringBuilder();
199 // if (e.causeSnippet() == null) {
200 // // We have a snippet creation event
201 // switch (e.status()) {
202 // case VALID:
203 // sb.append("Successful ");
204 // break;
205 // case RECOVERABLE_DEFINED:
206 // sb.append("With unresolved references ");
207 // break;
208 // case RECOVERABLE_NOT_DEFINED:
209 // sb.append("Possibly reparable, failed ");
210 // break;
211 // case REJECTED:
212 // sb.append("Failed ");
213 // break;
214 // }
215 // if (e.previousStatus() == Status.NONEXISTENT) {
216 // sb.append("addition");
217 // } else {
218 // sb.append("modification");
219 // }
220 // sb.append(" of ");
221 // sb.append(e.snippet().source());
222 // System.out.println(sb);
223 // if (e.value() != null) {
224 // System.out.printf("Value is: %s\n", e.value());
225 // }
226 // System.out.flush();
227 // }
228 // }
229 // });
230 //// } while (true);
231 // }
232 // }
233
234 public void stop() {
235 try {
236 Files.delete(linkedDir);
237 } catch (IOException e) {
238 log.error("Cannot remove " + linkedDir);
239 }
240 }
241
242 public void setCmsState(CmsState cmsState) {
243 this.cmsState = cmsState;
244 }
245
246 // public static void main(String[] args) throws Exception {
247 // Pipe inPipe = Pipe.open();
248 // Pipe outPipe = Pipe.open();
249 //
250 // InputStream in = Channels.newInputStream(inPipe.source());
251 // OutputStream out = Channels.newOutputStream(outPipe.sink());
252 // JavaShellToolBuilder builder = JavaShellToolBuilder.builder();
253 // builder.in(in, null);
254 // builder.interactiveTerminal(true);
255 // builder.out(new PrintStream(out));
256 //
257 // UnixDomainSocketAddress ioSocketAddress = JShellClient.ioSocketAddress();
258 // Files.deleteIfExists(ioSocketAddress.getPath());
259 //
260 // try (ServerSocketChannel serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) {
261 // serverChannel.bind(ioSocketAddress);
262 //
263 // try (SocketChannel channel = serverChannel.accept()) {
264 // new Thread(() -> {
265 //
266 // try {
267 // ByteBuffer buffer = ByteBuffer.allocate(1024);
268 // while (true) {
269 // if (channel.read(buffer) < 0)
270 // break;
271 // buffer.flip();
272 // inPipe.sink().write(buffer);
273 // buffer.rewind();
274 // }
275 // } catch (IOException e) {
276 // e.printStackTrace();
277 // }
278 // }, "Read in").start();
279 //
280 // new Thread(() -> {
281 //
282 // try {
283 // ByteBuffer buffer = ByteBuffer.allocate(1024);
284 // while (true) {
285 // if (outPipe.source().read(buffer) < 0)
286 // break;
287 // buffer.flip();
288 // channel.write(buffer);
289 // buffer.rewind();
290 // }
291 // } catch (IOException e) {
292 // e.printStackTrace();
293 // }
294 // }, "Write out").start();
295 //
296 // builder.start();
297 // }
298 // } finally {
299 // System.out.println("Completed");
300 // }
301 // }
302
303 }