X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms.jshell%2Fsrc%2Forg%2Fargeo%2Fcms%2Fjshell%2FCmsJShell.java;h=e3718ae73119f693d99c78441e194d9bf7199255;hb=9a975983b2f3509a287dfb5751799544ec97ce70;hp=aec3da1f6fb5a7b1da6151f4455ec2a0aca50bc5;hpb=2c5da70747629282585d5515720dcb1515a0011c;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms.jshell/src/org/argeo/cms/jshell/CmsJShell.java b/org.argeo.cms.jshell/src/org/argeo/cms/jshell/CmsJShell.java index aec3da1f6..e3718ae73 100644 --- a/org.argeo.cms.jshell/src/org/argeo/cms/jshell/CmsJShell.java +++ b/org.argeo.cms.jshell/src/org/argeo/cms/jshell/CmsJShell.java @@ -1,6 +1,7 @@ package org.argeo.cms.jshell; import java.io.IOException; +import java.nio.file.DirectoryStream; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -16,7 +17,10 @@ import org.argeo.api.cms.CmsLog; import org.argeo.api.cms.CmsState; import org.argeo.api.uuid.UuidFactory; import org.argeo.cms.util.OS; +import org.argeo.internal.cms.jshell.osgi.OsgiExecutionControlProvider; +import org.osgi.framework.Bundle; +/** A factory for JShell sessions. */ public class CmsJShell { private final static CmsLog log = CmsLog.getLog(CmsJShell.class); static ClassLoader loader = CmsJShell.class.getClassLoader(); @@ -26,38 +30,71 @@ public class CmsJShell { private CmsState cmsState; private Map localSessions = new HashMap<>(); + private Map bundleDirs = new HashMap<>(); - private Path localBase; - private Path linkedDir; + private Path stateRunDir; + private Path jshBase; + private Path jshLinkedDir; + private Path jtermBase; + private Path jtermLinkedDir; public void start() throws Exception { - - // Path localBase = cmsState.getStatePath("org.argeo.cms.jshell/local"); - UUID stateUuid = cmsState.getUuid(); + // TODO better define application id, make it configurable + String applicationID = cmsState.getStatePath("").getFileName().toString(); // TODO centralise state run dir - Path stateRunDir = OS.getRunDir().resolve(stateUuid.toString()); - localBase = stateRunDir.resolve("jsh"); - Files.createDirectories(localBase); + stateRunDir = OS.getRunDir().resolve(applicationID); + + jshBase = stateRunDir.resolve(JShellClient.JSH); + Files.createDirectories(jshBase); + jshLinkedDir = Files.createSymbolicLink(cmsState.getStatePath(JShellClient.JSH), jshBase); - linkedDir = Files.createSymbolicLink(cmsState.getStatePath("jsh"), localBase); + jtermBase = stateRunDir.resolve(JShellClient.JTERM); + Files.createDirectories(jtermBase); + jtermLinkedDir = Files.createSymbolicLink(cmsState.getStatePath(JShellClient.JTERM), jtermBase); - log.info("Local JShell on " + localBase + ", linked to " + linkedDir); + log.info("Local JShell on " + jshBase + ", linked to " + jshLinkedDir); + log.info("Local JTerml on " + jtermBase + ", linked to " + jtermLinkedDir); new Thread(() -> { try { WatchService watchService = FileSystems.getDefault().newWatchService(); - localBase.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, + jshBase.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, + StandardWatchEventKinds.ENTRY_DELETE); + try (DirectoryStream bundleSns = Files.newDirectoryStream(jshBase)) { + for (Path bundleSnDir : bundleSns) { + addBundleSnDir(bundleSnDir, watchService); + } + } + jtermBase.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE); + try (DirectoryStream bundleSns = Files.newDirectoryStream(jtermBase)) { + for (Path bundleSnDir : bundleSns) { + addBundleSnDir(bundleSnDir, watchService); + } + } WatchKey key; while ((key = watchService.take()) != null) { events: for (WatchEvent event : key.pollEvents()) { // System.out.println("Event kind:" + event.kind() + ". File affected: " + event.context() + "."); - Path path = localBase.resolve((Path) event.context()); + Path parent = (Path) key.watchable(); // sessions - if (Files.isSameFile(localBase, path.getParent())) { + if (Files.isSameFile(jshBase, parent)) { + Path bundleSnDir = jshBase.resolve((Path) event.context()); + if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) { + addBundleSnDir(bundleSnDir, watchService); + } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) { + } + } else if (Files.isSameFile(jtermBase, parent)) { + Path bundleSnDir = jtermBase.resolve((Path) event.context()); + if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) { + addBundleSnDir(bundleSnDir, watchService); + } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) { + } + } else { + Path path = parent.resolve((Path) event.context()); if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) { if (!Files.isDirectory(path)) { log.warn("Ignoring " + path + " as it is not a directory"); @@ -70,32 +107,22 @@ public class CmsJShell { continue events; } - LocalJShellSession localSession = new LocalJShellSession(path); + boolean interactive; + if (Files.isSameFile(jshBase, parent.getParent())) { + interactive = false; + } else if (Files.isSameFile(jtermBase, parent.getParent())) { + interactive = true; + } else { + log.warn("Ignoring " + path + " as we don't know whether it is interactive or not"); + continue events; + } + Path bundleIdDir = bundleDirs.get(parent); + LocalJShellSession localSession = new LocalJShellSession(path, bundleIdDir, + interactive); localSessions.put(path, localSession); } else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind())) { - // TODO clean up session - LocalJShellSession localSession = localSessions.remove(path); - localSession.cleanUp(); + localSessions.remove(path); } - } else { -// if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) { -// Path sessionDir = path.getParent(); -// LocalSession session = localSessions.get(sessionDir); -// if (session == null) { -// sessions: for (Path p : localSessions.keySet()) { -// if (Files.isSameFile(sessionDir, p)) { -// session = localSessions.get(p); -// break sessions; -// } -// } -// } -// if (session == null) { -// log.warn("Ignoring " + path + " as its parent is not a registered session"); -// continue events; -// } -// session.addChild(path); -// } - } } key.reset(); @@ -103,176 +130,33 @@ public class CmsJShell { } catch (IOException | InterruptedException e) { e.printStackTrace(); } - }, "JSChell local sessions watcher").start(); + }, "JShell local sessions watcher").start(); + } - // thread context class loader should be where the service is defined -// Thread.currentThread().setContextClassLoader(loader); -// JavaShellToolBuilder builder = JavaShellToolBuilder.builder(); -// -// builder.start("--execution", "osgi:bundle(org.argeo.cms.jshell)"); + private void addBundleSnDir(Path bundleSnDir, WatchService watchService) throws IOException { + String symbolicName = bundleSnDir.getFileName().toString(); + Bundle fromBundle = OsgiExecutionControlProvider.getBundleFromSn(symbolicName); + if (fromBundle == null) { + log.error("Ignoring bundle " + symbolicName + " because it was not found"); + return; + } + Long bundleId = fromBundle.getBundleId(); + Path bundleIdDir = stateRunDir.resolve(bundleId.toString()); + Files.createDirectories(bundleIdDir); + bundleDirs.put(bundleSnDir, bundleIdDir); + bundleSnDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE); } -// public void startX(BundleContext bc) { -// uuidFactory = new NoOpUuidFactory(); -// -// List locations = new ArrayList<>(); -// for (Bundle bundle : bc.getBundles()) { -// locations.add(bundle.getLocation()); -//// System.out.println(bundle.getLocation()); -// } -// -// CmsState cmsState = (CmsState) bc.getService(bc.getServiceReference("org.argeo.api.cms.CmsState")); -// System.out.println(cmsState.getDeployProperties(CmsDeployProperty.HTTP_PORT.getProperty())); -// System.out.println(cmsState.getUuid()); -// -// ExecutionControlProvider executionControlProvider = new ExecutionControlProvider() { -// @Override -// public String name() { -// return "name"; -// } -// -// @Override -// public ExecutionControl generate(ExecutionEnv ee, Map map) throws Throwable { -// return new LocalExecutionControl(new WrappingLoaderDelegate(loader)); -//// Thread.currentThread().setContextClassLoader(loader); -//// return new DirectExecutionControl(); -// } -// }; -// -//// Thread.currentThread().setContextClassLoader(loader); -// -// try (JShell js = JShell.builder().executionEngine(executionControlProvider, null).build()) { -// js.addToClasspath("/home/mbaudier/dev/git/unstable/output/a2/org.argeo.cms/org.argeo.api.cms.2.3.jar"); -// js.addToClasspath("/home/mbaudier/dev/git/unstable/output/a2/org.argeo.cms/org.argeo.cms.2.3.jar"); -// js.addToClasspath( -// "/home/mbaudier/dev/git/unstable/output/a2/osgi/equinox/org.argeo.tp.osgi/org.eclipse.osgi.3.18.jar"); -//// do { -// System.out.print("Enter some Java code: "); -// // String input = console.readLine(); -// String imports = """ -// import org.argeo.api.cms.*; -// import org.argeo.cms.*; -// import org.argeo.slc.jshell.*; -// """; -// js.eval(imports); -// String input = """ -// var bc = org.osgi.framework.FrameworkUtil.getBundle(org.argeo.cms.CmsDeployProperty.class).getBundleContext(); -// var cmsState =(org.argeo.api.cms.CmsState) bc.getService(bc.getServiceReference("org.argeo.api.cms.CmsState")); -// System.out.println(cmsState.getDeployProperties(org.argeo.cms.CmsDeployProperty.HTTP_PORT.getProperty())); -// cmsState.getUuid(); -// """; -//// if (input == null) { -//// break; -//// } -// -// input.lines().forEach((l) -> { -// -// List events = js.eval(l); -// for (SnippetEvent e : events) { -// StringBuilder sb = new StringBuilder(); -// if (e.causeSnippet() == null) { -// // We have a snippet creation event -// switch (e.status()) { -// case VALID: -// sb.append("Successful "); -// break; -// case RECOVERABLE_DEFINED: -// sb.append("With unresolved references "); -// break; -// case RECOVERABLE_NOT_DEFINED: -// sb.append("Possibly reparable, failed "); -// break; -// case REJECTED: -// sb.append("Failed "); -// break; -// } -// if (e.previousStatus() == Status.NONEXISTENT) { -// sb.append("addition"); -// } else { -// sb.append("modification"); -// } -// sb.append(" of "); -// sb.append(e.snippet().source()); -// System.out.println(sb); -// if (e.value() != null) { -// System.out.printf("Value is: %s\n", e.value()); -// } -// System.out.flush(); -// } -// } -// }); -//// } while (true); -// } -// } - public void stop() { try { - Files.delete(linkedDir); + Files.delete(jshLinkedDir); } catch (IOException e) { - log.error("Cannot remove " + linkedDir); + log.error("Cannot remove " + jshLinkedDir); } } public void setCmsState(CmsState cmsState) { this.cmsState = cmsState; } - -// public static void main(String[] args) throws Exception { -// Pipe inPipe = Pipe.open(); -// Pipe outPipe = Pipe.open(); -// -// InputStream in = Channels.newInputStream(inPipe.source()); -// OutputStream out = Channels.newOutputStream(outPipe.sink()); -// JavaShellToolBuilder builder = JavaShellToolBuilder.builder(); -// builder.in(in, null); -// builder.interactiveTerminal(true); -// builder.out(new PrintStream(out)); -// -// UnixDomainSocketAddress ioSocketAddress = JShellClient.ioSocketAddress(); -// Files.deleteIfExists(ioSocketAddress.getPath()); -// -// try (ServerSocketChannel serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) { -// serverChannel.bind(ioSocketAddress); -// -// try (SocketChannel channel = serverChannel.accept()) { -// new Thread(() -> { -// -// try { -// ByteBuffer buffer = ByteBuffer.allocate(1024); -// while (true) { -// if (channel.read(buffer) < 0) -// break; -// buffer.flip(); -// inPipe.sink().write(buffer); -// buffer.rewind(); -// } -// } catch (IOException e) { -// e.printStackTrace(); -// } -// }, "Read in").start(); -// -// new Thread(() -> { -// -// try { -// ByteBuffer buffer = ByteBuffer.allocate(1024); -// while (true) { -// if (outPipe.source().read(buffer) < 0) -// break; -// buffer.flip(); -// channel.write(buffer); -// buffer.rewind(); -// } -// } catch (IOException e) { -// e.printStackTrace(); -// } -// }, "Write out").start(); -// -// builder.start(); -// } -// } finally { -// System.out.println("Completed"); -// } -// } - }