Added reading from files and safety execution.
This commit is contained in:
parent
9efc91f82f
commit
ce02d4d02b
|
@ -11,7 +11,7 @@ import java.util.List;
|
||||||
|
|
||||||
import static nl.andrewlalis.Window.*;
|
import static nl.andrewlalis.Window.*;
|
||||||
|
|
||||||
public class DatabaseHelper {
|
class DatabaseHelper {
|
||||||
|
|
||||||
private String host;
|
private String host;
|
||||||
private int port;
|
private int port;
|
||||||
|
@ -19,7 +19,7 @@ public class DatabaseHelper {
|
||||||
private String password;
|
private String password;
|
||||||
private Window window;
|
private Window window;
|
||||||
|
|
||||||
public DatabaseHelper(String host, int port, String user, String password, Window window) {
|
DatabaseHelper(String host, int port, String user, String password, Window window) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -27,7 +27,7 @@ public class DatabaseHelper {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void executeSQLComparison(String initializationSQL, String templateSQL, String testingSQL) {
|
void executeSQLComparison(String initializationSQL, String templateSQL, String testingSQL) {
|
||||||
// Run the database code in a separate thread to update the UI quickly.
|
// Run the database code in a separate thread to update the UI quickly.
|
||||||
Thread t = new Thread(() -> {
|
Thread t = new Thread(() -> {
|
||||||
// Setup both databases.
|
// Setup both databases.
|
||||||
|
@ -37,26 +37,26 @@ public class DatabaseHelper {
|
||||||
"DROP DATABASE " + DB_TESTING + ";";
|
"DROP DATABASE " + DB_TESTING + ";";
|
||||||
String createDatabases = "CREATE DATABASE " + DB_TEMPLATE + "; " +
|
String createDatabases = "CREATE DATABASE " + DB_TEMPLATE + "; " +
|
||||||
"CREATE DATABASE " + DB_TESTING + ";";
|
"CREATE DATABASE " + DB_TESTING + ";";
|
||||||
this.executeQueries("", dropDatabases);
|
this.executeQueries("", dropDatabases, false);
|
||||||
this.executeQueries("", createDatabases);
|
this.executeQueries("", createDatabases, false);
|
||||||
this.window.unindentOutput();
|
this.window.unindentOutput();
|
||||||
|
|
||||||
// Run initialization script on each database.
|
// Run initialization script on each database.
|
||||||
this.window.appendOutput("Running initialization SQL on databases...");
|
this.window.appendOutput("Running initialization SQL on databases...");
|
||||||
this.window.indentOutput();
|
this.window.indentOutput();
|
||||||
this.executeQueries(DB_TEMPLATE, initializationSQL);
|
this.executeQueries(DB_TEMPLATE, initializationSQL, false);
|
||||||
this.executeQueries(DB_TESTING, initializationSQL);
|
this.executeQueries(DB_TESTING, initializationSQL, false);
|
||||||
this.window.unindentOutput();
|
this.window.unindentOutput();
|
||||||
|
|
||||||
// TESTING SQL HERE
|
// TESTING SQL HERE
|
||||||
|
|
||||||
// Template-specific output.
|
// Template-specific output.
|
||||||
this.window.setOutputChannel(OUTPUT_TEMPLATE);
|
this.window.setOutputChannel(OUTPUT_TEMPLATE);
|
||||||
ExecutionLog templateLog = this.executeQueries(DB_TEMPLATE, templateSQL);
|
ExecutionLog templateLog = this.executeQueries(DB_TEMPLATE, templateSQL, true);
|
||||||
|
|
||||||
// Testing-specific output.
|
// Testing-specific output.
|
||||||
this.window.setOutputChannel(OUTPUT_TESTING);
|
this.window.setOutputChannel(OUTPUT_TESTING);
|
||||||
ExecutionLog testingLog = this.executeQueries(DB_TESTING, testingSQL);
|
ExecutionLog testingLog = this.executeQueries(DB_TESTING, testingSQL, true);
|
||||||
|
|
||||||
// Output results.
|
// Output results.
|
||||||
this.window.setOutputChannel(OUTPUT_GENERAL);
|
this.window.setOutputChannel(OUTPUT_GENERAL);
|
||||||
|
@ -65,13 +65,30 @@ public class DatabaseHelper {
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private void listDatabases() {
|
||||||
|
// try {
|
||||||
|
// PreparedStatement ps = connection
|
||||||
|
// .prepareStatement("SELECT datname FROM pg_database WHERE datistemplate = false;");
|
||||||
|
// ResultSet rs = ps.executeQuery();
|
||||||
|
// while (rs.next()) {
|
||||||
|
// System.out.println(rs.getString(1));
|
||||||
|
// }
|
||||||
|
// rs.close();
|
||||||
|
// ps.close();
|
||||||
|
//
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes possibly many queries which are contained in one string.
|
* Executes possibly many queries which are contained in one string.
|
||||||
* @param database The database name to connect to, or an empty string to connect to the user's database.
|
* @param database The database name to connect to, or an empty string to connect to the user's database.
|
||||||
* @param queriesString The string of queries.
|
* @param queriesString The string of queries.
|
||||||
|
* @param safe Whether the queries should be checked for safety.
|
||||||
* @return The execution log from this series of queries.
|
* @return The execution log from this series of queries.
|
||||||
*/
|
*/
|
||||||
public ExecutionLog executeQueries(String database, String queriesString) {
|
private ExecutionLog executeQueries(String database, String queriesString, boolean safe) {
|
||||||
ExecutionLog executionLog = new ExecutionLog();
|
ExecutionLog executionLog = new ExecutionLog();
|
||||||
String url = String.format(
|
String url = String.format(
|
||||||
"jdbc:postgresql://%s:%4d/%s?user=%s&password=%s",
|
"jdbc:postgresql://%s:%4d/%s?user=%s&password=%s",
|
||||||
|
@ -93,7 +110,11 @@ public class DatabaseHelper {
|
||||||
|
|
||||||
for (String query : queries) {
|
for (String query : queries) {
|
||||||
try {
|
try {
|
||||||
|
if (!safe || isQuerySafe(query)) {
|
||||||
executionLog.recordAction(executeQuery(query, st));
|
executionLog.recordAction(executeQuery(query, st));
|
||||||
|
} else {
|
||||||
|
window.appendOutput("Blocked execution of unsafe query: " + query);
|
||||||
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
window.appendOutput("Exception while executing statement: " + e.getMessage());
|
window.appendOutput("Exception while executing statement: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -152,6 +173,17 @@ public class DatabaseHelper {
|
||||||
return strings;
|
return strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the given query is safe to run.
|
||||||
|
* @param query The query to run.
|
||||||
|
* @return True if this query is safe, or false if it would cause damage to the system.
|
||||||
|
*/
|
||||||
|
private static boolean isQuerySafe(String query) {
|
||||||
|
String upper = query.trim().toUpperCase();
|
||||||
|
return !upper.startsWith("CREATE DATABASE")
|
||||||
|
&& !upper.startsWith("DROP DATABASE");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if an SQL string is a query (it should return a result set)
|
* Determines if an SQL string is a query (it should return a result set)
|
||||||
* @param str The string to check.
|
* @param str The string to check.
|
||||||
|
|
|
@ -4,7 +4,7 @@ import javax.swing.*;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
public static final String APPLICATION_NAME = "SQL-Assesser";
|
private static final String APPLICATION_NAME = "SQL-Assesser";
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Window window = new Window(APPLICATION_NAME);
|
Window window = new Window(APPLICATION_NAME);
|
||||||
|
|
|
@ -60,6 +60,12 @@
|
||||||
<text value="Load From File"/>
|
<text value="Load From File"/>
|
||||||
</properties>
|
</properties>
|
||||||
</component>
|
</component>
|
||||||
|
<component id="a7f77" class="javax.swing.JButton" binding="clearTemplateButton">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Clear"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
</children>
|
</children>
|
||||||
</grid>
|
</grid>
|
||||||
</children>
|
</children>
|
||||||
|
@ -105,6 +111,12 @@
|
||||||
<text value="Load From File"/>
|
<text value="Load From File"/>
|
||||||
</properties>
|
</properties>
|
||||||
</component>
|
</component>
|
||||||
|
<component id="2fbec" class="javax.swing.JButton" binding="clearTestingButton">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Clear"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
</children>
|
</children>
|
||||||
</grid>
|
</grid>
|
||||||
</children>
|
</children>
|
||||||
|
@ -210,6 +222,7 @@
|
||||||
<scrollpane id="adb12" binding="outputScrollPane">
|
<scrollpane id="adb12" binding="outputScrollPane">
|
||||||
<constraints border-constraint="Center"/>
|
<constraints border-constraint="Center"/>
|
||||||
<properties>
|
<properties>
|
||||||
|
<autoscrolls value="true"/>
|
||||||
<preferredSize width="2" height="300"/>
|
<preferredSize width="2" height="300"/>
|
||||||
<verticalScrollBarPolicy value="22"/>
|
<verticalScrollBarPolicy value="22"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package nl.andrewlalis;
|
package nl.andrewlalis;
|
||||||
|
|
||||||
|
import nl.andrewlalis.util.FileLoader;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.xml.crypto.Data;
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
import java.awt.event.ActionEvent;
|
import javax.swing.text.DefaultCaret;
|
||||||
import java.awt.event.ActionListener;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class Window extends JFrame {
|
public class Window extends JFrame {
|
||||||
private JPanel mainPanel;
|
private JPanel mainPanel;
|
||||||
|
@ -26,27 +28,34 @@ public class Window extends JFrame {
|
||||||
private JButton loadTemplateFromFileButton;
|
private JButton loadTemplateFromFileButton;
|
||||||
private JButton loadTestingFromFileButton;
|
private JButton loadTestingFromFileButton;
|
||||||
private JButton loadInitializationFromFileButton;
|
private JButton loadInitializationFromFileButton;
|
||||||
|
private JButton clearTestingButton;
|
||||||
|
private JButton clearTemplateButton;
|
||||||
|
|
||||||
public static final int OUTPUT_GENERAL = 0;
|
static final int OUTPUT_GENERAL = 0;
|
||||||
public static final int OUTPUT_TEMPLATE = 1;
|
static final int OUTPUT_TEMPLATE = 1;
|
||||||
public static final int OUTPUT_TESTING = 2;
|
static final int OUTPUT_TESTING = 2;
|
||||||
|
|
||||||
public static final String DB_TEMPLATE = "sql_assess_template";
|
static final String DB_TEMPLATE = "sql_assess_template";
|
||||||
public static final String DB_TESTING = "sql_assess_testing";
|
static final String DB_TESTING = "sql_assess_testing";
|
||||||
|
|
||||||
private int outputChannel;
|
private int outputChannel;
|
||||||
private int outputIndent;
|
private int outputIndent;
|
||||||
|
|
||||||
public Window(String applicationName) {
|
Window(String applicationName) {
|
||||||
super(applicationName);
|
super(applicationName);
|
||||||
|
|
||||||
|
// Setup autoscrolling on text areas.
|
||||||
|
DefaultCaret caret = (DefaultCaret) this.outputTextArea.getCaret();
|
||||||
|
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
|
||||||
|
|
||||||
|
// Setup default SQL values.
|
||||||
|
this.fillDefaultSQL();
|
||||||
|
|
||||||
this.setOutputChannel(OUTPUT_GENERAL);
|
this.setOutputChannel(OUTPUT_GENERAL);
|
||||||
|
|
||||||
this.setContentPane(mainPanel);
|
this.setContentPane(mainPanel);
|
||||||
|
|
||||||
executeButton.addActionListener(actionEvent -> {
|
executeButton.addActionListener(actionEvent -> this.executeSQL());
|
||||||
this.executeSQL();
|
|
||||||
});
|
|
||||||
|
|
||||||
clearOutputButton.addActionListener(actionEvent -> {
|
clearOutputButton.addActionListener(actionEvent -> {
|
||||||
this.templateOutputTextArea.setText(null);
|
this.templateOutputTextArea.setText(null);
|
||||||
|
@ -54,9 +63,11 @@ public class Window extends JFrame {
|
||||||
this.outputTextArea.setText(null);
|
this.outputTextArea.setText(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
loadInitializationFromFileButton.addActionListener(actionEvent -> {
|
loadInitializationFromFileButton.addActionListener(actionEvent -> this.fillSQLFromFileChooser(this.initializationTextArea));
|
||||||
|
loadTemplateFromFileButton.addActionListener(actionEvent -> this.fillSQLFromFileChooser(this.templateTextArea));
|
||||||
});
|
loadTestingFromFileButton.addActionListener(actionEvent -> this.fillSQLFromFileChooser(this.testingTextArea));
|
||||||
|
clearTemplateButton.addActionListener(actionEvent -> this.templateTextArea.setText(null));
|
||||||
|
clearTestingButton.addActionListener(actionEvent -> this.testingTextArea.setText(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,4 +130,27 @@ public class Window extends JFrame {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the input elements from the SQL packaged with this application.
|
||||||
|
*/
|
||||||
|
private void fillDefaultSQL() {
|
||||||
|
try {
|
||||||
|
this.initializationTextArea.setText(FileLoader.readResource("initialization.sql"));
|
||||||
|
this.templateTextArea.setText(FileLoader.readResource("template.sql"));
|
||||||
|
this.testingTextArea.setText(FileLoader.readResource("example_test.sql"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
this.appendOutput("Could not load default SQL resources.");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillSQLFromFileChooser(JTextArea textArea) {
|
||||||
|
JFileChooser fileChooser = new JFileChooser();
|
||||||
|
fileChooser.setFileFilter(new FileNameExtensionFilter("SQL", "sql"));
|
||||||
|
int result = fileChooser.showOpenDialog(this);
|
||||||
|
if (result == JFileChooser.APPROVE_OPTION) {
|
||||||
|
textArea.setText(FileLoader.readFile(fileChooser.getSelectedFile()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class ExecutionLog {
|
||||||
this.actions.add(action);
|
this.actions.add(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ExecutionAction> getActions() {
|
private List<ExecutionAction> getActions() {
|
||||||
return this.actions;
|
return this.actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package nl.andrewlalis.util;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helps with loading files.
|
||||||
|
*/
|
||||||
|
public class FileLoader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a resource file from the classpath, and returns its contents as a string.
|
||||||
|
* @param classPath The class path of the resource.
|
||||||
|
* @return The string containing the contents of the file.
|
||||||
|
* @throws IOException If an error occurred or the file could not be read.
|
||||||
|
*/
|
||||||
|
public static String readResource(String classPath) throws IOException {
|
||||||
|
String newLine = System.getProperty("line.separator");
|
||||||
|
InputStream is = FileLoader.class.getClassLoader().getResourceAsStream(classPath);
|
||||||
|
if (is == null) {
|
||||||
|
throw new IOException("Could not open input stream to resource.");
|
||||||
|
}
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
boolean flag = false;
|
||||||
|
for (String line; (line = reader.readLine()) != null; ) {
|
||||||
|
result.append(flag? newLine: "").append(line);
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a file into a string.
|
||||||
|
* @param selectedFile The file object, as it is often selected by a JFileChooser.
|
||||||
|
* @return The string containing the file, or an empty string.
|
||||||
|
*/
|
||||||
|
public static String readFile(File selectedFile) {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(selectedFile))) {
|
||||||
|
String line;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue