X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms.jshell%2Fsrc%2Forg%2Fargeo%2Fcms%2Fjshell%2FLocalJShellSession.java;h=e77f653b7ce63a394a55546957461b498baa8119;hb=7a1298bb4b78713553a37fba483373eeaf738069;hp=196ee04689c9154e613e303b174c47c2624dda40;hpb=c31e21e07586e1a3937ac3c79d71941f047234ae;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms.jshell/src/org/argeo/cms/jshell/LocalJShellSession.java b/org.argeo.cms.jshell/src/org/argeo/cms/jshell/LocalJShellSession.java index 196ee0468..e77f653b7 100644 --- a/org.argeo.cms.jshell/src/org/argeo/cms/jshell/LocalJShellSession.java +++ b/org.argeo.cms.jshell/src/org/argeo/cms/jshell/LocalJShellSession.java @@ -1,8 +1,10 @@ package org.argeo.cms.jshell; +import static java.net.StandardProtocolFamily.UNIX; + import java.io.IOException; +import java.io.OutputStream; import java.io.PrintStream; -import java.net.StandardProtocolFamily; import java.net.UnixDomainSocketAddress; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; @@ -22,6 +24,7 @@ import org.argeo.internal.cms.jshell.osgi.OsgiExecutionControlProvider; import jdk.jshell.tool.JavaShellToolBuilder; +/** A JShell session based on local UNIX sockets. */ class LocalJShellSession implements Runnable { private final static CmsLog log = CmsLog.getLog(LocalJShellSession.class); @@ -29,9 +32,8 @@ class LocalJShellSession implements Runnable { private Path sessionDir; private Path socketsDir; - private Path stdioPath; - private Path stderrPath; - private Path cmdioPath; + private Path stdPath; + private Path ctlPath; private Thread replThread; @@ -39,7 +41,10 @@ class LocalJShellSession implements Runnable { private Long bundleId; - LocalJShellSession(Path sessionDir, Path bundleIdDir) { + private final boolean interactive; + + LocalJShellSession(Path sessionDir, Path bundleIdDir, boolean interactive) { + this.interactive = interactive; try { this.sessionDir = sessionDir; this.uuid = UUID.fromString(sessionDir.getFileName().toString()); @@ -47,8 +52,11 @@ class LocalJShellSession implements Runnable { socketsDir = bundleIdDir.resolve(uuid.toString()); Files.createDirectories(socketsDir); - stdioPath = socketsDir.resolve(JShellClient.STDIO); - Files.createSymbolicLink(sessionDir.resolve(JShellClient.STDIO), stdioPath); + stdPath = socketsDir.resolve(JShellClient.STD); + Files.createSymbolicLink(sessionDir.resolve(JShellClient.STD), stdPath); + + ctlPath = socketsDir.resolve(JShellClient.CTL); + Files.createSymbolicLink(sessionDir.resolve(JShellClient.CTL), ctlPath); // TODO proper login try { @@ -62,6 +70,7 @@ class LocalJShellSession implements Runnable { } catch (IOException e) { log.error("Cannot initiate local session " + uuid, e); cleanUp(); + return; } replThread = new Thread(() -> CurrentSubject.callAs(loginContext.getSubject(), Executors.callable(this)), "JShell " + sessionDir); @@ -71,29 +80,44 @@ class LocalJShellSession implements Runnable { public void run() { log.debug(() -> "Started JShell session " + sessionDir); - try (SocketPipeMirror std = new SocketPipeMirror()) { + try (SocketPipeMirror std = new SocketPipeMirror(JShellClient.STD + " " + uuid); // + SocketPipeMirror ctl = new SocketPipeMirror(JShellClient.CTL + " " + uuid);) { // prepare jshell tool builder + String feedbackMode; JavaShellToolBuilder builder = JavaShellToolBuilder.builder(); - builder.in(std.getInputStream(), null); - builder.interactiveTerminal(true); - builder.out(new PrintStream(std.getOutputStream())); + if (interactive) { + builder.in(std.getInputStream(), null); + builder.out(new PrintStream(std.getOutputStream())); + builder.err(new PrintStream(ctl.getOutputStream())); + builder.interactiveTerminal(true); + feedbackMode = "concise"; + } else { + builder.in(ctl.getInputStream(), std.getInputStream()); + PrintStream cmdOut = new PrintStream(ctl.getOutputStream()); + PrintStream discard = new PrintStream(OutputStream.nullOutputStream()); + builder.out(cmdOut, discard, new PrintStream(std.getOutputStream())); + builder.err(cmdOut); + builder.promptCapture(true); + feedbackMode = "silent"; + } - // UnixDomainSocketAddress ioSocketAddress = JSchellClient.ioSocketAddress(); - // Files.deleteIfExists(ioSocketAddress.getPath()); - UnixDomainSocketAddress stdSocketAddress = UnixDomainSocketAddress.of(stdioPath); + UnixDomainSocketAddress stdSocketAddress = UnixDomainSocketAddress.of(stdPath); + UnixDomainSocketAddress ctlSocketAddress = UnixDomainSocketAddress.of(ctlPath); - try (ServerSocketChannel stdServerChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) { + try (ServerSocketChannel stdServerChannel = ServerSocketChannel.open(UNIX); + ServerSocketChannel ctlServerChannel = ServerSocketChannel.open(UNIX);) { stdServerChannel.bind(stdSocketAddress); - try (SocketChannel channel = stdServerChannel.accept()) { - std.open(channel); - -// StringJoiner classpath = new StringJoiner(File.pathSeparator); -// String frameworkLocation = System.getProperty("osgi.framework"); -// classpath.add(Paths.get(URI.create(frameworkLocation)).toAbsolutePath().toString()); + ctlServerChannel.bind(ctlSocketAddress); + try (SocketChannel stdChannel = stdServerChannel.accept(); + SocketChannel ctlChannel = ctlServerChannel.accept();) { + std.open(stdChannel); + ctl.open(ctlChannel); ClassLoader cmsJShellBundleCL = OsgiExecutionControlProvider.class.getClassLoader(); ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader(); try { + String classpath = OsgiExecutionControlProvider.getBundleClasspath(bundleId); + Path bundleStartupScript = OsgiExecutionControlProvider.getBundleStartupScript(bundleId); // we need our own class loader so that Java service loader // finds our ExecutionControlProvider implementation Thread.currentThread().setContextClassLoader(cmsJShellBundleCL); @@ -101,13 +125,13 @@ class LocalJShellSession implements Runnable { // START JSHELL // int exitCode = builder.start("--execution", "osgi:bundle(" + bundleId + ")", "--class-path", - OsgiExecutionControlProvider.getBundleClasspath(bundleId), "--startup", - OsgiExecutionControlProvider.getBundleStartupScript(bundleId).toString()); + classpath, "--startup", bundleStartupScript.toString(), "--feedback", feedbackMode); // log.debug("JShell " + sessionDir + " completed with exit code " + exitCode); } finally { Thread.currentThread().setContextClassLoader(currentContextClassLoader); } + } finally { } } } catch (Exception e) { @@ -117,7 +141,7 @@ class LocalJShellSession implements Runnable { } } - void cleanUp() { + private void cleanUp() { try { if (Files.exists(socketsDir)) FsUtils.delete(socketsDir); @@ -127,33 +151,11 @@ class LocalJShellSession implements Runnable { log.error("Cannot clean up JShell " + sessionDir, e); } - try { - loginContext.logout(); - } catch (LoginException e) { - log.error("Cannot log out JShell " + sessionDir, e); - } + if (loginContext != null) + try { + loginContext.logout(); + } catch (LoginException e) { + log.error("Cannot log out JShell " + sessionDir, e); + } } - -// void addChild(Path p) throws IOException { -// if (replThread != null) -// throw new IllegalStateException("JShell " + sessionDir + " is already started"); -// -// if (STDIO.equals(p.getFileName().toString())) { -// stdioPath = p; -// } else if (STDERR.equals(p.getFileName().toString())) { -// stderrPath = p; -// } else if (CMDIO.equals(p.getFileName().toString())) { -// cmdioPath = p; -// } else { -// log.warn("Unkown file name " + p.getFileName() + " in " + sessionDir); -// } -// -// // check that all paths are available -// // if (stdioPath != null && stderrPath != null && cmdioPath != null) { -// if (stdioPath != null) { -// replThread = new Thread(this, "JShell " + sessionDir); -// replThread.start(); -// } -// } - }