From b052c4ed70aef7f10fba192a8692dd8de92683d9 Mon Sep 17 00:00:00 2001 From: snuyanzin Date: Fri, 14 Jun 2019 01:38:36 +0200 Subject: [PATCH] SqlLine integration --- MatCalciteDependencies/pom.xml | 5 ++ .../com/github/vlsi/mat/calcite/Executor.java | 22 +++++- .../calcite/cli/DumpFileNameCompleter.java | 19 ++++++ .../vlsi/mat/calcite/cli/MCPApplication.java | 48 +++++++++++++ .../calcite/cli/OpenDumpCommandHandler.java | 68 +++++++++++++++++++ .../src/sqlline/MCPDatabaseConnection.java | 22 ++++++ MatCalcitePlugin/src/sqlline/MCPSqlLine.java | 27 ++++++++ 7 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/DumpFileNameCompleter.java create mode 100644 MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/MCPApplication.java create mode 100644 MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/OpenDumpCommandHandler.java create mode 100644 MatCalcitePlugin/src/sqlline/MCPDatabaseConnection.java create mode 100644 MatCalcitePlugin/src/sqlline/MCPSqlLine.java diff --git a/MatCalciteDependencies/pom.xml b/MatCalciteDependencies/pom.xml index 68a289c..d5e80d3 100644 --- a/MatCalciteDependencies/pom.xml +++ b/MatCalciteDependencies/pom.xml @@ -24,6 +24,11 @@ jsr305 3.0.2 + + sqlline + sqlline + 1.9.0 + diff --git a/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/Executor.java b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/Executor.java index 99511b3..30ca101 100644 --- a/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/Executor.java +++ b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/Executor.java @@ -1,5 +1,6 @@ package com.github.vlsi.mat.calcite; +import sqlline.MCPSqlLine; import com.google.common.base.Joiner; import com.google.common.escape.Escaper; import com.google.common.escape.Escapers; @@ -15,6 +16,7 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; +import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -22,6 +24,8 @@ import java.util.ArrayList; import java.util.List; +import static org.jline.terminal.TerminalBuilder.PROP_JANSI; + public class Executor implements IApplication { @Override @@ -29,8 +33,23 @@ public Object start(IApplicationContext context) { String[] args = (String[]) context.getArguments().get("application.args"); char delimiter = ','; - if (args.length < 3) { + if (args.length == 0 || (args.length < 3 && !"sqlline".equalsIgnoreCase(args[0]))) { System.out.println("java com.github.vlsi.mat.calcite.Executor "); + System.out.println("java com.github.vlsi.mat.calcite.Executor sqlline"); + return IApplication.EXIT_OK; + } + + if ("sqlline".equalsIgnoreCase(args[0])) { + try { + System.setProperty(PROP_JANSI, Boolean.TRUE.toString()); + MCPSqlLine sqlLine = new MCPSqlLine(); + String[] sqllineArgs = new String[args.length - 1]; + System.arraycopy(args, 1, sqllineArgs, 0, args.length - 1); + sqlLine.begin(sqllineArgs, null, false); + } catch (IOException e) { + e.printStackTrace(); + return IApplication.EXIT_OK; + } return IApplication.EXIT_OK; } @@ -57,7 +76,6 @@ public Object start(IApplicationContext context) { return IApplication.EXIT_OK; } - try (Connection con = CalciteDataSource.getConnection(openSnapshot(heapFile)); BufferedWriter w = new BufferedWriter(new FileWriter(resultsFile))) { PreparedStatement ps = con.prepareStatement(sbQuery.toString()); diff --git a/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/DumpFileNameCompleter.java b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/DumpFileNameCompleter.java new file mode 100644 index 0000000..1397301 --- /dev/null +++ b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/DumpFileNameCompleter.java @@ -0,0 +1,19 @@ +package com.github.vlsi.mat.calcite.cli; + +import org.jline.builtins.Completers; + +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; + +public class DumpFileNameCompleter extends Completers.FileNameCompleter { + private static final PathMatcher DUMP_FILE_MATCHER = + FileSystems.getDefault().getPathMatcher("glob:**.{bin,hprof}"); + + @Override + protected boolean accept(Path path) { + return super.accept(path) + && (Files.isDirectory(path) || DUMP_FILE_MATCHER.matches(path)); + } +} diff --git a/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/MCPApplication.java b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/MCPApplication.java new file mode 100644 index 0000000..3762782 --- /dev/null +++ b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/MCPApplication.java @@ -0,0 +1,48 @@ +package com.github.vlsi.mat.calcite.cli; + +import sqlline.Application; +import sqlline.CommandHandler; +import sqlline.MCPSqlLine; +import sqlline.SqlLine; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class MCPApplication extends Application { + private static final Set ALLOWED_SQLLINE_COMMANDS = new HashSet() {{ + add("quit"); + add("history"); + add("verbose"); + add("run"); + add("list"); + add("all"); + add("go"); + add("script"); + add("record"); + add("brief"); + add("close"); + add("closeall"); + add("outputformat"); + add("set"); + add("help"); + add("reset"); + add("save"); + add("rerun"); + add("prompthandler"); + }}; + + @Override + public Collection getCommandHandlers(SqlLine sqlLine) { + Collection handlers = new ArrayList<>(); + for (CommandHandler commandHandler : super.getCommandHandlers(sqlLine)) { + if (ALLOWED_SQLLINE_COMMANDS.contains(commandHandler.getName())) { + handlers.add(commandHandler); + } + } + handlers.add(new OpenDumpCommandHandler((MCPSqlLine) sqlLine, new DumpFileNameCompleter(), "Open heap dump", + "open_dump")); + return handlers; + } +} diff --git a/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/OpenDumpCommandHandler.java b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/OpenDumpCommandHandler.java new file mode 100644 index 0000000..19e0a44 --- /dev/null +++ b/MatCalcitePlugin/src/com/github/vlsi/mat/calcite/cli/OpenDumpCommandHandler.java @@ -0,0 +1,68 @@ +package com.github.vlsi.mat.calcite.cli; + +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.SnapshotFactory; +import org.eclipse.mat.util.VoidProgressListener; +import org.jline.reader.Completer; +import sqlline.AbstractCommandHandler; +import sqlline.Commands; +import sqlline.DispatchCallback; +import sqlline.MCPDatabaseConnection; +import sqlline.MCPSqlLine; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +public class OpenDumpCommandHandler extends AbstractCommandHandler { + public OpenDumpCommandHandler(MCPSqlLine sqlLine, List completers, + String helpText, String... cmds) { + super(sqlLine, cmds, helpText, completers); + } + + public OpenDumpCommandHandler(MCPSqlLine sqlLine, Completer completer, + String helpText, String... cmds) { + this(sqlLine, Collections.singletonList(completer), helpText, cmds); + } + + public void execute(String line, DispatchCallback callback) { + final String[] parts = sqlLine.split(line, " ", 0); + if (parts.length != 2) { + sqlLine.error("Usage: open_dump "); + callback.setToFailure(); + return; + } + // replace ~/ with user directory + final String filename = Commands.expand(parts[1]); + if (!new File(filename).isFile()) { + sqlLine.error("Dump file " + filename + " does not exists!"); + callback.setToFailure(); + return; + } + + final MCPSqlLine mcpSqlLine = (MCPSqlLine) sqlLine; + final MCPDatabaseConnection mcpDatabaseConnection; + try { + mcpDatabaseConnection = new MCPDatabaseConnection(mcpSqlLine, filename, openSnapshot(new File(filename))); + } catch (SnapshotException e) { + callback.setToFailure(); + mcpSqlLine.error(e); + return; + } + try { + mcpSqlLine.setUpConnection(mcpDatabaseConnection); + callback.setToSuccess(); + } catch (Exception e) { + mcpDatabaseConnection.close(); + mcpSqlLine.removeConnection(mcpDatabaseConnection); + callback.setToFailure(); + mcpSqlLine.error(e); + } + } + + private static ISnapshot openSnapshot(File heapDump) throws SnapshotException { + System.out.println("exists = " + heapDump.exists() + ", file = " + heapDump.getAbsolutePath()); + return SnapshotFactory.openSnapshot(heapDump, new VoidProgressListener()); + } +} diff --git a/MatCalcitePlugin/src/sqlline/MCPDatabaseConnection.java b/MatCalcitePlugin/src/sqlline/MCPDatabaseConnection.java new file mode 100644 index 0000000..28cc2ba --- /dev/null +++ b/MatCalcitePlugin/src/sqlline/MCPDatabaseConnection.java @@ -0,0 +1,22 @@ +package sqlline; + +import com.github.vlsi.mat.calcite.CalciteDataSource; + +import org.eclipse.mat.snapshot.ISnapshot; + +import java.sql.SQLException; + +public class MCPDatabaseConnection extends DatabaseConnection { + private final ISnapshot snapshot; + + public MCPDatabaseConnection(MCPSqlLine sqlLine, String filename, ISnapshot snapshot) { + super(sqlLine, null, filename, "username", "password", null); + this.snapshot = snapshot; + } + + @Override + boolean connect() throws SQLException { + connection = CalciteDataSource.getConnection(snapshot); + return true; + } +} diff --git a/MatCalcitePlugin/src/sqlline/MCPSqlLine.java b/MatCalcitePlugin/src/sqlline/MCPSqlLine.java new file mode 100644 index 0000000..bb45866 --- /dev/null +++ b/MatCalcitePlugin/src/sqlline/MCPSqlLine.java @@ -0,0 +1,27 @@ +package sqlline; + +import com.github.vlsi.mat.calcite.cli.MCPApplication; + +import java.lang.reflect.Proxy; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +public class MCPSqlLine extends SqlLine { + void setAppConfig(Application application) { + super.setAppConfig(new MCPApplication()); + } + + public void setUpConnection(final MCPDatabaseConnection mcpDatabaseConnection) throws SQLException { + getDatabaseConnections().setConnection(mcpDatabaseConnection); + Connection connection = getDatabaseConnection().getConnection(); + mcpDatabaseConnection.meta = (DatabaseMetaData) Proxy.newProxyInstance( + DatabaseMetaData.class.getClassLoader(), + new Class[]{DatabaseMetaData.class}, + new DatabaseMetaDataHandler(connection.getMetaData())); + } + + public void removeConnection(final MCPDatabaseConnection mcpDatabaseConnection) { + getDatabaseConnections().removeConnection(mcpDatabaseConnection); + } +}