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.*;
|
||||
|
||||
public class DatabaseHelper {
|
||||
class DatabaseHelper {
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
|
@ -19,7 +19,7 @@ public class DatabaseHelper {
|
|||
private String password;
|
||||
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.port = port;
|
||||
this.user = user;
|
||||
|
@ -27,7 +27,7 @@ public class DatabaseHelper {
|
|||
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.
|
||||
Thread t = new Thread(() -> {
|
||||
// Setup both databases.
|
||||
|
@ -37,26 +37,26 @@ public class DatabaseHelper {
|
|||
"DROP DATABASE " + DB_TESTING + ";";
|
||||
String createDatabases = "CREATE DATABASE " + DB_TEMPLATE + "; " +
|
||||
"CREATE DATABASE " + DB_TESTING + ";";
|
||||
this.executeQueries("", dropDatabases);
|
||||
this.executeQueries("", createDatabases);
|
||||
this.executeQueries("", dropDatabases, false);
|
||||
this.executeQueries("", createDatabases, false);
|
||||
this.window.unindentOutput();
|
||||
|
||||
// Run initialization script on each database.
|
||||
this.window.appendOutput("Running initialization SQL on databases...");
|
||||
this.window.indentOutput();
|
||||
this.executeQueries(DB_TEMPLATE, initializationSQL);
|
||||
this.executeQueries(DB_TESTING, initializationSQL);
|
||||
this.executeQueries(DB_TEMPLATE, initializationSQL, false);
|
||||
this.executeQueries(DB_TESTING, initializationSQL, false);
|
||||
this.window.unindentOutput();
|
||||
|
||||
// TESTING SQL HERE
|
||||
|
||||
// Template-specific output.
|
||||
this.window.setOutputChannel(OUTPUT_TEMPLATE);
|
||||
ExecutionLog templateLog = this.executeQueries(DB_TEMPLATE, templateSQL);
|
||||
ExecutionLog templateLog = this.executeQueries(DB_TEMPLATE, templateSQL, true);
|
||||
|
||||
// Testing-specific output.
|
||||
this.window.setOutputChannel(OUTPUT_TESTING);
|
||||
ExecutionLog testingLog = this.executeQueries(DB_TESTING, testingSQL);
|
||||
ExecutionLog testingLog = this.executeQueries(DB_TESTING, testingSQL, true);
|
||||
|
||||
// Output results.
|
||||
this.window.setOutputChannel(OUTPUT_GENERAL);
|
||||
|
@ -65,13 +65,30 @@ public class DatabaseHelper {
|
|||
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.
|
||||
* @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 safe Whether the queries should be checked for safety.
|
||||
* @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();
|
||||
String url = String.format(
|
||||
"jdbc:postgresql://%s:%4d/%s?user=%s&password=%s",
|
||||
|
@ -93,7 +110,11 @@ public class DatabaseHelper {
|
|||
|
||||
for (String query : queries) {
|
||||
try {
|
||||
if (!safe || isQuerySafe(query)) {
|
||||
executionLog.recordAction(executeQuery(query, st));
|
||||
} else {
|
||||
window.appendOutput("Blocked execution of unsafe query: " + query);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
window.appendOutput("Exception while executing statement: " + e.getMessage());
|
||||
}
|
||||
|
@ -152,6 +173,17 @@ public class DatabaseHelper {
|
|||
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)
|
||||
* @param str The string to check.
|
||||
|
|
|
@ -4,7 +4,7 @@ import javax.swing.*;
|
|||
|
||||
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) {
|
||||
Window window = new Window(APPLICATION_NAME);
|
||||
|
|
|
@ -60,6 +60,12 @@
|
|||
<text value="Load From File"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="a7f77" class="javax.swing.JButton" binding="clearTemplateButton">
|
||||
<constraints/>
|
||||
<properties>
|
||||
<text value="Clear"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
|
@ -105,6 +111,12 @@
|
|||
<text value="Load From File"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="2fbec" class="javax.swing.JButton" binding="clearTestingButton">
|
||||
<constraints/>
|
||||
<properties>
|
||||
<text value="Clear"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
|
@ -210,6 +222,7 @@
|
|||
<scrollpane id="adb12" binding="outputScrollPane">
|
||||
<constraints border-constraint="Center"/>
|
||||
<properties>
|
||||
<autoscrolls value="true"/>
|
||||
<preferredSize width="2" height="300"/>
|
||||
<verticalScrollBarPolicy value="22"/>
|
||||
</properties>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package nl.andrewlalis;
|
||||
|
||||
import nl.andrewlalis.util.FileLoader;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.xml.crypto.Data;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Window extends JFrame {
|
||||
private JPanel mainPanel;
|
||||
|
@ -26,27 +28,34 @@ public class Window extends JFrame {
|
|||
private JButton loadTemplateFromFileButton;
|
||||
private JButton loadTestingFromFileButton;
|
||||
private JButton loadInitializationFromFileButton;
|
||||
private JButton clearTestingButton;
|
||||
private JButton clearTemplateButton;
|
||||
|
||||
public static final int OUTPUT_GENERAL = 0;
|
||||
public static final int OUTPUT_TEMPLATE = 1;
|
||||
public static final int OUTPUT_TESTING = 2;
|
||||
static final int OUTPUT_GENERAL = 0;
|
||||
static final int OUTPUT_TEMPLATE = 1;
|
||||
static final int OUTPUT_TESTING = 2;
|
||||
|
||||
public static final String DB_TEMPLATE = "sql_assess_template";
|
||||
public static final String DB_TESTING = "sql_assess_testing";
|
||||
static final String DB_TEMPLATE = "sql_assess_template";
|
||||
static final String DB_TESTING = "sql_assess_testing";
|
||||
|
||||
private int outputChannel;
|
||||
private int outputIndent;
|
||||
|
||||
public Window(String applicationName) {
|
||||
Window(String 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.setContentPane(mainPanel);
|
||||
|
||||
executeButton.addActionListener(actionEvent -> {
|
||||
this.executeSQL();
|
||||
});
|
||||
executeButton.addActionListener(actionEvent -> this.executeSQL());
|
||||
|
||||
clearOutputButton.addActionListener(actionEvent -> {
|
||||
this.templateOutputTextArea.setText(null);
|
||||
|
@ -54,9 +63,11 @@ public class Window extends JFrame {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
public List<ExecutionAction> getActions() {
|
||||
private List<ExecutionAction> getActions() {
|
||||
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