1 package org
.argeo
.cms
.jshell
;
4 import java
.io
.IOException
;
5 import java
.io
.PrintStream
;
6 import java
.net
.StandardProtocolFamily
;
8 import java
.net
.UnixDomainSocketAddress
;
9 import java
.nio
.channels
.ServerSocketChannel
;
10 import java
.nio
.channels
.SocketChannel
;
11 import java
.nio
.file
.Files
;
12 import java
.nio
.file
.Path
;
13 import java
.nio
.file
.Paths
;
14 import java
.util
.StringJoiner
;
15 import java
.util
.UUID
;
16 import java
.util
.concurrent
.Executors
;
18 import javax
.security
.auth
.login
.LoginContext
;
19 import javax
.security
.auth
.login
.LoginException
;
21 import org
.argeo
.api
.cms
.CmsAuth
;
22 import org
.argeo
.api
.cms
.CmsLog
;
23 import org
.argeo
.cms
.util
.CurrentSubject
;
24 import org
.argeo
.internal
.cms
.jshell
.osgi
.OsgiExecutionControlProvider
;
26 import jdk
.jshell
.tool
.JavaShellToolBuilder
;
28 class LocalJShellSession
implements Runnable
{
29 private final static CmsLog log
= CmsLog
.getLog(LocalJShellSession
.class);
32 private Path sessionDir
;
34 private String fromBundle
= "eu.netiket.on.apaf.project.togo2023";
36 private Path stdioPath
;
37 private Path stderrPath
;
38 private Path cmdioPath
;
40 private Thread replThread
;
42 private LoginContext loginContext
;
44 LocalJShellSession(Path sessionDir
) {
45 this.sessionDir
= sessionDir
;
46 this.uuid
= UUID
.fromString(sessionDir
.getFileName().toString());
48 stdioPath
= sessionDir
.resolve(JShellClient
.STDIO
);
52 loginContext
= new LoginContext(CmsAuth
.DATA_ADMIN
.getLoginContextName());
54 } catch (LoginException e1
) {
55 throw new RuntimeException("Could not login as data admin", e1
);
59 replThread
= new Thread(() -> CurrentSubject
.callAs(loginContext
.getSubject(), Executors
.callable(this)),
60 "JShell " + sessionDir
);
66 log
.debug(() -> "Started JShell session " + sessionDir
);
67 try (SocketPipeMirror std
= new SocketPipeMirror()) {
68 // prepare jshell tool builder
69 JavaShellToolBuilder builder
= JavaShellToolBuilder
.builder();
70 builder
.in(std
.getInputStream(), null);
71 builder
.interactiveTerminal(true);
72 builder
.out(new PrintStream(std
.getOutputStream()));
74 // UnixDomainSocketAddress ioSocketAddress = JSchellClient.ioSocketAddress();
75 // Files.deleteIfExists(ioSocketAddress.getPath());
76 UnixDomainSocketAddress stdSocketAddress
= UnixDomainSocketAddress
.of(stdioPath
);
78 try (ServerSocketChannel stdServerChannel
= ServerSocketChannel
.open(StandardProtocolFamily
.UNIX
)) {
79 stdServerChannel
.bind(stdSocketAddress
);
80 try (SocketChannel channel
= stdServerChannel
.accept()) {
83 String frameworkLocation
= System
.getProperty("osgi.framework");
84 StringJoiner classpath
= new StringJoiner(File
.pathSeparator
);
85 classpath
.add(Paths
.get(URI
.create(frameworkLocation
)).toAbsolutePath().toString());
87 ClassLoader cmsJShellBundleCL
= OsgiExecutionControlProvider
.class.getClassLoader();
88 ClassLoader currentContextClassLoader
= Thread
.currentThread().getContextClassLoader();
90 // we need our own class loader so that Java service loader
91 // finds our ExecutionControlProvider implementation
92 Thread
.currentThread().setContextClassLoader(cmsJShellBundleCL
);
96 int exitCode
= builder
.start("--execution", "osgi:bundle(" + fromBundle
+ ")", "--class-path",
97 classpath
.toString());
99 log
.debug("JShell " + sessionDir
+ " completed with exit code " + exitCode
);
101 Thread
.currentThread().setContextClassLoader(currentContextClassLoader
);
105 } catch (Exception e
) {
106 throw new RuntimeException("JShell " + sessionDir
+ " failed", e
);
114 if (Files
.exists(stdioPath
))
115 Files
.delete(stdioPath
);
116 if (Files
.exists(sessionDir
))
117 Files
.delete(sessionDir
);
118 } catch (IOException e
) {
119 log
.error("Cannot clean up JShell " + sessionDir
, e
);
123 loginContext
.logout();
124 } catch (LoginException e
) {
125 log
.error("Cannot log out JShell " + sessionDir
, e
);
129 // void addChild(Path p) throws IOException {
130 // if (replThread != null)
131 // throw new IllegalStateException("JShell " + sessionDir + " is already started");
133 // if (STDIO.equals(p.getFileName().toString())) {
135 // } else if (STDERR.equals(p.getFileName().toString())) {
137 // } else if (CMDIO.equals(p.getFileName().toString())) {
140 // log.warn("Unkown file name " + p.getFileName() + " in " + sessionDir);
143 // // check that all paths are available
144 // // if (stdioPath != null && stderrPath != null && cmdioPath != null) {
145 // if (stdioPath != null) {
146 // replThread = new Thread(this, "JShell " + sessionDir);
147 // replThread.start();