Skip to content

Commit eb2e305

Browse files
committed
restified main console
1 parent 17ffb76 commit eb2e305

File tree

10 files changed

+375
-299
lines changed

10 files changed

+375
-299
lines changed

intellij-plugin/src/javarepl/plugin/JavaREPLConsoleRunner.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545
public class JavaREPLConsoleRunner {
4646
public static final String REPL_TITLE = "Java REPL";
47-
public static final String REPL_MAIN_CLASS = "javarepl.Main";
47+
public static final String REPL_MAIN_CLASS = "javarepl.Repl";
4848

4949
public static final String EXECUTE_ACTION_IMMEDIATELY_ID = "JavaREPL.Console.Execute.Immediately";
5050

@@ -273,7 +273,6 @@ private GeneralCommandLine createCommandLine(Module module, String workingDir) t
273273
Map<String, String> envParams = new HashMap<String, String>();
274274
envParams.putAll(System.getenv());
275275
line.setEnvParams(envParams);
276-
line.addParameter("--simpleConsole");
277276
line.addParameter("--port=" + port);
278277

279278
return line;

src/javarepl/Main.java

+114-168
Large diffs are not rendered by default.

src/javarepl/RemoteMain.java

-109
This file was deleted.

src/javarepl/Repl.java

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package javarepl;
2+
3+
import com.googlecode.totallylazy.Mapper;
4+
import com.googlecode.totallylazy.Option;
5+
import com.googlecode.totallylazy.Sequence;
6+
import com.googlecode.totallylazy.predicates.LogicalPredicate;
7+
import javarepl.console.*;
8+
import javarepl.console.rest.RestConsole;
9+
10+
import java.io.BufferedReader;
11+
import java.io.File;
12+
import java.io.FilePermission;
13+
import java.io.InputStreamReader;
14+
import java.lang.management.ManagementPermission;
15+
import java.lang.reflect.ReflectPermission;
16+
import java.net.SocketPermission;
17+
import java.security.CodeSource;
18+
import java.security.PermissionCollection;
19+
import java.security.Permissions;
20+
import java.security.Policy;
21+
import java.util.PropertyPermission;
22+
23+
import static com.googlecode.totallylazy.Callables.compose;
24+
import static com.googlecode.totallylazy.Files.temporaryDirectory;
25+
import static com.googlecode.totallylazy.Option.none;
26+
import static com.googlecode.totallylazy.Option.some;
27+
import static com.googlecode.totallylazy.Sequences.sequence;
28+
import static com.googlecode.totallylazy.Strings.replaceAll;
29+
import static com.googlecode.totallylazy.Strings.startsWith;
30+
import static com.googlecode.totallylazy.numbers.Numbers.intValue;
31+
import static com.googlecode.totallylazy.numbers.Numbers.valueOf;
32+
import static java.lang.String.format;
33+
import static java.lang.System.getProperty;
34+
import static javarepl.Utils.applicationVersion;
35+
import static javarepl.Utils.randomServerPort;
36+
import static javarepl.console.ConsoleConfig.consoleConfig;
37+
import static javarepl.console.ConsoleLog.Type.ERROR;
38+
import static javarepl.console.ConsoleLog.Type.SUCCESS;
39+
import static javax.tools.ToolProvider.getSystemJavaCompiler;
40+
41+
public class Repl {
42+
public static void main(String... args) throws Exception {
43+
ConsoleLogger logger = systemStreamsLogger();
44+
boolean sandboxed = isSandboxed(args);
45+
Integer port = port(args);
46+
47+
if (!ignoreConsole(args)) {
48+
logger.info(format("Welcome to JavaREPL version %s (%s, %s, Java %s)",
49+
applicationVersion(),
50+
sandboxed ? "sandboxed" : "unrestricted",
51+
getProperty("java.vm.name"),
52+
getProperty("java.version")));
53+
}
54+
55+
if (getSystemJavaCompiler() == null) {
56+
logger.error("\nERROR: Java compiler not found.\n" +
57+
"This can occur when JavaREPL was run with JRE instead of JDK or JDK is not configured correctly.");
58+
System.exit(2000);
59+
}
60+
61+
ConsoleConfig consoleConfig = consoleConfig()
62+
.historyFile(historyFile(!sandboxed))
63+
.expressions(initialExpressions(args))
64+
.sandboxed(sandboxed)
65+
.logger(logger);
66+
67+
RestConsole console = new RestConsole(new TimingOutConsole(new SimpleConsole(consoleConfig), expressionTimeout(args), inactivityTimeout(args)), port);
68+
ExpressionReader reader = new ExpressionReader(ignoreConsole(args) ? ignoreConsoleInput() : readFromConsole());
69+
70+
if (sandboxed)
71+
sandboxApplication();
72+
73+
for (String expression : consoleConfig.expressions) {
74+
console.execute(expression);
75+
}
76+
77+
do {
78+
console.execute(reader.readExpression().getOrNull());
79+
logger.info("");
80+
} while (true);
81+
}
82+
83+
private static boolean ignoreConsole(String[] args) {
84+
return sequence(args).contains("--ignoreConsole");
85+
}
86+
87+
private static Mapper<Sequence<String>, String> ignoreConsoleInput() {
88+
return new Mapper<Sequence<String>, String>() {
89+
public String call(Sequence<String> strings) throws Exception {
90+
while (true) {
91+
Thread.sleep(100);
92+
}
93+
}
94+
};
95+
}
96+
97+
private static Mapper<Sequence<String>, String> readFromConsole() {
98+
return new Mapper<Sequence<String>, String>() {
99+
private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
100+
101+
public String call(Sequence<String> lines) throws Exception {
102+
return reader.readLine();
103+
}
104+
};
105+
}
106+
107+
private static String[] initialExpressions(String[] args) {
108+
return sequence(args)
109+
.find(startsWith("--expression="))
110+
.map(replaceAll("--expression=", ""))
111+
.toSequence()
112+
.toArray(String.class);
113+
}
114+
115+
private static ConsoleLogger systemStreamsLogger() {
116+
ConsoleLogger logger = new ConsoleLogger(System.out, System.err, false);
117+
118+
LogicalPredicate<String> ignoredLogs = startsWith("POST /")
119+
.or(startsWith("GET /"))
120+
.or(startsWith("Listening on http://"));
121+
122+
System.setOut(new ConsoleLoggerPrintStream(SUCCESS, ignoredLogs, logger));
123+
System.setErr(new ConsoleLoggerPrintStream(ERROR, ignoredLogs, logger));
124+
125+
return logger;
126+
}
127+
128+
private static Option<File> historyFile(boolean createFile) {
129+
return createFile
130+
? some(new File(getProperty("user.home"), ".javarepl.history"))
131+
: none(File.class);
132+
}
133+
134+
private static boolean isSandboxed(String[] args) {
135+
return sequence(args).contains("--sandboxed");
136+
}
137+
138+
private static Integer port(String[] args) {
139+
return sequence(args).find(startsWith("--port=")).map(compose(replaceAll("--port=", ""), compose(valueOf, intValue))).getOrElse(randomServerPort());
140+
}
141+
142+
private static Option<Integer> expressionTimeout(String[] args) {
143+
return sequence(args).find(startsWith("--expressionTimeout=")).map(compose(replaceAll("--expressionTimeout=", ""), compose(valueOf, intValue)));
144+
}
145+
146+
private static Option<Integer> inactivityTimeout(String[] args) {
147+
return sequence(args).find(startsWith("--inactivityTimeout=")).map(compose(replaceAll("--inactivityTimeout=", ""), compose(valueOf, intValue)));
148+
}
149+
150+
private static void sandboxApplication() {
151+
Policy.setPolicy(new Policy() {
152+
private final PermissionCollection permissions = new Permissions();
153+
154+
{
155+
permissions.add(new SocketPermission("*", "accept, connect, resolve"));
156+
permissions.add(new RuntimePermission("accessClassInPackage.sun.misc.*"));
157+
permissions.add(new RuntimePermission("accessClassInPackage.sun.misc"));
158+
permissions.add(new RuntimePermission("getProtectionDomain"));
159+
permissions.add(new RuntimePermission("accessDeclaredMembers"));
160+
permissions.add(new RuntimePermission("createClassLoader"));
161+
permissions.add(new RuntimePermission("closeClassLoader"));
162+
permissions.add(new RuntimePermission("modifyThreadGroup"));
163+
permissions.add(new RuntimePermission("getStackTrace"));
164+
permissions.add(new ManagementPermission("monitor"));
165+
permissions.add(new ReflectPermission("suppressAccessChecks"));
166+
permissions.add(new PropertyPermission("*", "read"));
167+
permissions.add(new FilePermission(temporaryDirectory("JavaREPL").getAbsolutePath() + "/-", "read, write, delete"));
168+
permissions.add(new FilePermission("<<ALL FILES>>", "read"));
169+
}
170+
171+
@Override
172+
public PermissionCollection getPermissions(CodeSource codesource) {
173+
return permissions;
174+
}
175+
});
176+
177+
System.setSecurityManager(new SecurityManager());
178+
}
179+
}

src/javarepl/client/JavaREPLClient.java

+22-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
import com.googlecode.funclate.Model;
44
import com.googlecode.totallylazy.Mapper;
5+
import com.googlecode.totallylazy.Option;
56
import com.googlecode.totallylazy.Sequence;
7+
import com.googlecode.utterlyidle.Response;
68
import com.googlecode.utterlyidle.handlers.ClientHttpHandler;
79
import javarepl.completion.CompletionResult;
810

911
import static com.googlecode.funclate.Model.persistent.parse;
12+
import static com.googlecode.totallylazy.Option.none;
13+
import static com.googlecode.totallylazy.Option.some;
1014
import static com.googlecode.totallylazy.Sequences.sequence;
1115
import static com.googlecode.utterlyidle.RequestBuilder.get;
1216
import static com.googlecode.utterlyidle.RequestBuilder.post;
@@ -29,12 +33,17 @@ public synchronized ExpressionTemplate template(String expression) throws Except
2933
}
3034

3135

32-
public synchronized EvaluationResult execute(String expr) throws Exception {
33-
Model model = parse(client.handle(post(url("execute")).form("expression", expr).build()).entity().toString());
36+
public synchronized Option<EvaluationResult> execute(String expr) throws Exception {
37+
String json = client.handle(post(url("execute")).form("expression", expr).build()).entity().toString();
38+
39+
if (json.isEmpty())
40+
return none();
41+
42+
Model model = parse(json);
3443
Sequence<Model> logs = sequence(model.getValues("logs", Model.class));
3544
String expression = model.get("expression", String.class);
3645

37-
return new EvaluationResult(expression, logs.map(modelToEvaluationLog()));
46+
return some(new EvaluationResult(expression, logs.map(modelToEvaluationLog())));
3847
}
3948

4049
public synchronized CompletionResult completions(String expr) throws Exception {
@@ -44,8 +53,17 @@ public synchronized CompletionResult completions(String expr) throws Exception {
4453
sequence(model.getValues("candidates", String.class)));
4554
}
4655

56+
public synchronized boolean isAlive() {
57+
try {
58+
return parse(client.handle(get(url("status")).build()).entity().toString()).get("isAlive", Boolean.class);
59+
} catch (Exception e) {
60+
return false;
61+
}
62+
}
63+
4764
public synchronized Sequence<String> history() throws Exception {
48-
Model model = parse(client.handle(get(url("history")).build()).entity().toString());
65+
Response history = client.handle(get(url("history")).build());
66+
Model model = parse(history.entity().toString());
4967
return sequence(model.getValues("history", String.class));
5068
}
5169

0 commit comments

Comments
 (0)