JAVA
page 7 / 16 MODULE 3 | APPLICATIONS & TABLE VIEW Topics: Tables, iteration, string builders, truncation This module is graded by inspection with the M3 tag based on the weighted percentages given. There is no dependency. [20%] Implement the apps.Console.main method to provide a REPL (read-evaluate-print loop) as an entry point. A Prompt the user to input a script and split it on semicolons into a list of single queries. It is always safe to split on semicolons because they are used exclusively as delimiters between queries in a script and never within a single query. B Send the list of queries to the database to be interpreted, and receive back a list of responses. C For each response in the list of responses, display all properties of the response. D Repeat until the case-insensitive non-query sentinel EXIT is entered. Do not implement a driver for the sentinel. [20%] Implement the apps.Database constructor and methods to provide a database management system with an interpreter. E Implement the constructor as follows. 1 If the database is persistent, then for each file in the data folder, reopen it as a hash file table using the 1-ary constructor and recreate it in the database. Otherwise, if the database is not persistent, then initialize the database without tables. 2 Initialize the driver list with ECHO, RANGE, DUMP TABLE, and any other implemented drivers. F Implement the interpret method to interpret a list of queries and return a corresponding list of responses. 1 Create a new list of responses, initialized to empty. 2 For each query in order, execute the query once per driver until a driver returns a successful or failed response. Then add that response to the list of responses, skip all remaining drivers for that query, and continue to the next query, if any. i Do not execute a query more than once per driver or else erroneous mutations may occur. ii If no driver returns a successful or failed response for a query, add an unrecognized response as a fallback. 3 Return the list of responses, ordered to correspond with the list of queries. G Implement all other methods according to their documentation. To earn a grade on this portion, you must demonstrate SQL queries which prove the functionality of the console and database. Implement the tables.Table.toString method to represent any table in a pretty format similar to the example below. example_table word* length is_noun “tabular” 7 false “view” 4 null “demonstration” 14 true / example_table \ +--------------------------------------------------+ | word* | length | is_noun | |==================================================| | "tabular" | 7 | false | | "view" | 4 | | | "demonstrat... | 14 | true | +--------------------------------------------------+ H [20%] The string representation of the table must be formatted as follows. 1 It must be legible, attractive, and free of errors, but it should not be identical to the example above. 2 It must be generated in efficient time using minimally nested loops. 3 It must be generated in efficient space using a string builder instead of concatenation when possible. I [10%] The header of the table must include the following features. 1 The table name must be shown above the header. 2 The column names must be shown in the header as ordered in the schema. 3 The primary column must be indicated in the header. J [10%] The columns of the table must include the following features. 1 Each column must have a constant width. 2 String and boolean columns must be left-aligned, but integer columns must be right-aligned. K [20%] The rows of the table must include the following features. 1 String fields must be wrapped in quotation marks to disambiguate them from integer and boolean fields. 2 Null fields must be displayed as empty cells, not as null literals. 3 If a string field is too wide for its column then it must be truncated with an ellipsis (...) to fit the width. To earn a grade on this portion, you must demonstrate a sandbox and/or SQL queries that create and output the string representations of at least three nontrivial tables, each with at least three columns in its schema and at least five rows in its state. You must also prepare for an audit of the hash tables from MODULE 1 and MODULE 2 at the discretion of the instructor. Mod3/Console.java Mod3/Console.java package apps; import java.io.IOException; import java.io.PrintStream; import java.util.LinkedList; import java.util.List; import java.util.Scanner; import drivers.Response; /** * Implements a user console for * interacting with a database. *
* Do not modify existing protocols, * but you may add new protocols. */ public class Console { /** * The entry point for execution * with user input/output. * * @param args unused. */ public static void main(String[] args) { try ( final Database db = new Database(true); final Scanner in = new Scanner(System.in); final PrintStream out = System.out; ) { out.print(">> "); String text = in.nextLine(); List queries = new LinkedList<>(); queries.add(text); List responses = db.interpret(queries); out.println("Query: " + responses.get(0).query()); out.println("Status: " + responses.get(0).status()); out.println("Message: " + responses.get(0).message()); out.println("Table: " + responses.get(0).table()); } catch (IOException e) { e.printStackTrace(); } } } Mod3/Database.java Mod3/Database.java package apps; import java.io.Closeable; import java.io.IOException; import java.util.LinkedList; import java.util.List; import drivers.Driver; import drivers.Echo; import drivers.Response; import tables.Table; /** * This class implements a * database management system. *
* Do not modify existing protocols, * but you may add new protocols. */ public class Database implements Closeable { private final List
tables; private final List drivers; private final boolean persistent; /** * Initializes the drivers and the tables. * * @param persistent whether the database is persistent. */ public Database(boolean persistent) { this.persistent = persistent; tables = new LinkedList<>(); drivers = List.of( new Echo() ); } /** * Returns whether the database is persistent. * * @return whether the database is persistent. */ public boolean isPersistent() { return persistent; } /** * Returns an unmodifiable list * of the tables in the database. * * @return the list of tables. */ public List tables() { return List.copyOf(tables); } /** * Returns the table with the given name, * ornull
if there is none. * * @param tableName a table name. * @return the corresponding table, if any. */ public Table find(String tableName) { return null; } /** * Returnstrue
if a table with the * given name exists orfalse
otherwise. * * @param tableName a table name. * @return whether the corresponding table exists. */ public boolean exists(String tableName) { return false; } /** * Creates the given table, unless * a table with the corresponding name exists. *
* Returnstrue
if created * orfalse
otherwise. * * @return whether the table was created. */ public boolean create(Table table) { return false; } /** * Drops the table with the given name, unless * no table with the given name exists. *
* Returnstrue
if dropped * orfalse
otherwise. * * @return whether the table was dropped. */ public boolean drop(String tableName) { return false; } /** * Interprets a list of queries and returns * a list of responses to each in sequence. * * @param queries the list of queries. * @return the list of responses. */ public List interpret(List queries) { List responses = new LinkedList<>(); Response res = drivers.get(0).execute(queries.get(0), this); responses.add(res); return responses; } /** * Executes any required tasks when * the database is closed. */ @Override public void close() throws IOException { } } Mod3/Sandbox.java Mod3/Sandbox.java package apps; /** * Sandbox for execution of arbitrary code * for testing or grading purposes. */ @Deprecated public class Sandbox { public static void main(String[] args) { } } Mod3/Table.java Mod3/Table.java package tables; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Defines the protocols for a table * with a schema and a state. *
* Do not modify existing protocols, * but you may add new protocols. */ public abstract class Table implements Iterable { protected String tableName; protected List columnNames; protected List columnTypes; protected Integer primaryIndex; /** * Sets the table name in the schema. * * @param tableName the table name. */ public void setTableName(String tableName) { this.tableName = tableName; } /** * Gets the table name from the schema. * * @return the table name. */ public String getTableName() { return tableName; } /** * Sets an unmodifiable list of * the column names in the schema. * * @param columnNames the column names. */ public void setColumnNames(List columnNames) { this.columnNames = List.copyOf(columnNames); } /** * Gets an unmodifiable list of * the column names from the schema. * * @return the column names. */ public List getColumnNames() { return columnNames; } /** * Sets an unmodifiable list of * the column types in the schema. * * @param columnTypes the column types. */ public void setColumnTypes(List columnTypes) { this.columnTypes = List.copyOf(columnTypes); } /** * Gets an unmodifiable list of * the column types from the schema. * * @return the column types. */ public List getColumnTypes() { return columnTypes; } /** * Sets the primary index in the schema. * * @param primaryIndex the primary index. */ public void setPrimaryIndex(Integer primaryIndex) { this.primaryIndex = primaryIndex; } /** * Gets the primary index from the schema. * * @return the primary index. */ public Integer getPrimaryIndex() { return primaryIndex; } /** * Removes all rows from the state. */ public abstract void clear(); /** * On a hit, updates the corresponding row in the state, * then returnstrue
. *
* On a miss, creates the given row in the state, * then returnsfalse
. * * @param row a row. * @return whether the operation was a hit. */ public abstract boolean put(List row); /** * On a hit, removes the corresponding row * from the state, then returnstrue
. *
* On a miss, returnsfalse
. * * @param key a key. * @return whether the operation was a hit. */ public abstract boolean remove(Object key); /** * On a hit, returns the corresponding row * from the state. *
* On a miss, returnsnull
. * * @param key a key. * @return whether the operation was a hit. */ public abstract List get(Object key); /** * On a hit, returnstrue
. *
* On a miss, returnsfalse
. * * @param key a key. * @return whether the operation was a hit. */ public boolean contains(Object key) { return get(key) != null; } /** * Returns the size of the table, which is * the number of rows in the state. * * @return the size of the table. */ public abstract int size(); /** * Returns whether the {@link #size()} is zero. * * @returntrue
if there are no rows * orfalse
if there are rows. */ public boolean isEmpty() { return size() == 0; }; /** * Returns the capacity of the table, which is * the length of the data/file structure or * the maximum size before resizing it. * * @return the capacity of the table. */ public abstract int capacity(); /** * Returns the load factor of the table, * which is the {@link #size()} * divided by the {@link #capacity()}. * * @return the load factor. */ public double loadFactor() { return (double) size() / (double) capacity(); }; /** * Returns a string representation of this table, * including its schema and state. * * @return a string representation of this table. */ @Override public String toString() { return "Table".formatted( tableName, columnNames, columnTypes, primaryIndex, rows() ); } /** * Returns whether the given object is also a table * and has the same fingerprint as this table. *
* Atrue
result indicates with near * certainty that the given object is equal. * * @param an object. * @return whether the given object equals this table. */ @Override public boolean equals(Object o) { if (o instanceof Table t) return this.hashCode() == t.hashCode(); else return false; } /** * Returns the fingerprint of this table, * which is the sum of the hash codes of * each property value in the schema and * each field value in each row in the state. * * @return this table's fingerprint. */ @Override public int hashCode() { int sum = tableName.hashCode() + primaryIndex.hashCode(); for (String name: columnNames) sum += name.hashCode(); for (String type: columnTypes) sum += type.hashCode(); for (List row: rows()) for (Object field: row) sum += field != null ? field.hashCode() : 0; return sum; } /** * Returns an iterator over each row in the state. *
* This method is an alias of {@link #rows()}. * * @return an iterator of rows. */ @Override public abstract Iterator iterator(); /** * Returns an unmodifiable set of * the rows in the state. * * @return the set of rows. */ public Set rows() { Set rows = new HashSet<>(); for (List row: this) rows.add(row); return Set.copyOf(rows); }; /** * Returns an unmodifiable set of * the keys of the rows in the state. * * @return the set of keys. */ public Set keys() { Set keys = new HashSet<>(); for (List row: this) keys.add(row.get(getPrimaryIndex())); return Set.copyOf(keys); }; }