8133777: Use file based persistence for history instead of preferences
Reviewed-by: attila, mhaupt
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java Mon Aug 17 18:36:28 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java Tue Aug 18 11:40:18 2015 +0530
@@ -25,6 +25,7 @@
package jdk.nashorn.tools.jjs;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
@@ -33,75 +34,41 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
-import java.util.prefs.BackingStoreException;
-import java.util.prefs.Preferences;
import jdk.internal.jline.console.ConsoleReader;
import jdk.internal.jline.console.completer.Completer;
-import jdk.internal.jline.console.history.History.Entry;
-import jdk.internal.jline.console.history.MemoryHistory;
+import jdk.internal.jline.console.history.FileHistory;
class Console implements AutoCloseable {
private final ConsoleReader in;
- private final PersistentHistory history;
+ private final FileHistory history;
- Console(final InputStream cmdin, final PrintStream cmdout, final Preferences prefs,
+ Console(final InputStream cmdin, final PrintStream cmdout, final File historyFile,
final Completer completer) throws IOException {
in = new ConsoleReader(cmdin, cmdout);
in.setExpandEvents(false);
in.setHandleUserInterrupt(true);
in.setBellEnabled(true);
- in.setHistory(history = new PersistentHistory(prefs));
+ in.setHistory(history = new FileHistory(historyFile));
in.addCompleter(completer);
- Runtime.getRuntime().addShutdownHook(new Thread(()->close()));
+ Runtime.getRuntime().addShutdownHook(new Thread((Runnable)this::saveHistory));
}
String readLine(final String prompt) throws IOException {
return in.readLine(prompt);
}
-
@Override
public void close() {
- history.save();
+ saveHistory();
}
- public static class PersistentHistory extends MemoryHistory {
-
- private final Preferences prefs;
-
- protected PersistentHistory(final Preferences prefs) {
- this.prefs = prefs;
- load();
- }
-
- private static final String HISTORY_LINE_PREFIX = "HISTORY_LINE_";
+ private void saveHistory() {
+ try {
+ getHistory().flush();
+ } catch (final IOException exp) {}
+ }
- public final void load() {
- try {
- final List<String> keys = new ArrayList<>(Arrays.asList(prefs.keys()));
- Collections.sort(keys);
- for (String key : keys) {
- if (!key.startsWith(HISTORY_LINE_PREFIX))
- continue;
- CharSequence line = prefs.get(key, "");
- add(line);
- }
- } catch (BackingStoreException ex) {
- throw new IllegalStateException(ex);
- }
- }
-
- public void save() {
- Iterator<Entry> entries = iterator();
- if (entries.hasNext()) {
- int len = (int) Math.ceil(Math.log10(size()+1));
- String format = HISTORY_LINE_PREFIX + "%0" + len + "d";
- while (entries.hasNext()) {
- Entry entry = entries.next();
- prefs.put(String.format(format, entry.index()), entry.value().toString());
- }
- }
- }
-
+ FileHistory getHistory() {
+ return (FileHistory) in.getHistory();
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/HistoryObject.java Tue Aug 18 11:40:18 2015 +0530
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.tools.jjs;
+
+import java.io.IOException;
+import java.util.function.Function;
+import jdk.internal.jline.console.history.FileHistory;
+import jdk.internal.jline.console.history.History;
+import jdk.nashorn.api.scripting.AbstractJSObject;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.internal.runtime.JSType;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
+/*
+ * A script friendly object that exposes history of commands to scripts.
+ */
+final class HistoryObject extends AbstractJSObject {
+ private final FileHistory hist;
+
+ HistoryObject(final FileHistory hist) {
+ this.hist = hist;
+ }
+
+ @Override
+ public Object getMember(final String name) {
+ switch (name) {
+ case "clear":
+ return (Runnable)hist::clear;
+ case "forEach":
+ return (Function<JSObject, Object>)this::iterate;
+ case "print":
+ return (Runnable)this::print;
+ case "size":
+ return hist.size();
+ }
+ return UNDEFINED;
+ }
+
+ @Override
+ public Object getDefaultValue(final Class<?> hint) {
+ if (hint == String.class) {
+ return toString();
+ }
+ return UNDEFINED;
+ }
+
+ @Override
+ public String toString() {
+ return "[object history]";
+ }
+
+ private void print() {
+ for (History.Entry e : hist) {
+ System.out.println(e.value());
+ }
+ }
+
+ private Object iterate(final JSObject func) {
+ for (History.Entry e : hist) {
+ if (JSType.toBoolean(func.call(this, e.value().toString()))) {
+ break; // return true from callback to skip iteration
+ }
+ }
+ return UNDEFINED;
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java Mon Aug 17 18:36:28 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java Tue Aug 18 11:40:18 2015 +0530
@@ -26,12 +26,12 @@
package jdk.nashorn.tools.jjs;
import java.io.BufferedReader;
+import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
-import java.util.prefs.Preferences;
import jdk.internal.jline.console.completer.Completer;
import jdk.internal.jline.console.UserInterruptException;
import jdk.nashorn.api.scripting.NashornException;
@@ -48,7 +48,8 @@
public final class Main extends Shell {
private Main() {}
- static final Preferences PREFS = Preferences.userRoot().node("tool/jjs");
+ // file where history is persisted.
+ private static final File HIST_FILE = new File(new File(System.getProperty("user.home")), ".jjs.history");
/**
* Main entry point with the default input, output and error streams.
@@ -99,12 +100,14 @@
final boolean globalChanged = (oldGlobal != global);
final Completer completer = new NashornCompleter(context, global);
- try (final Console in = new Console(System.in, System.out, PREFS, completer)) {
+ try (final Console in = new Console(System.in, System.out, HIST_FILE, completer)) {
if (globalChanged) {
Context.setGlobal(global);
}
global.addShellBuiltins();
+ // expose history object for reflecting on command line history
+ global.put("history", new HistoryObject(in.getHistory()), false);
while (true) {
String source = "";