Database Management Program

Alex Edwards Alex Edwards is offline Offline Sep 1st, 2008, 9:12 pm |
0
I'm not sure if it has been done yet or not, but I thought this program might be helpful to those that want to practice SQL in Java, because it sure is helpful for me! =)

The assumption is that you're running Java 5+ and that you have a Database linked already.

You can provide your own Driver argument as well - you'll have to add a comma an the String version of the location of your Driver in the DatabaseAccess object in the main method of the DatabaseProgram class.


I'm hoping to make a much better front-end version of this program in the future.

Anyways, Have fun! =)
Quick reply to this message  
Java Syntax
  1. package _SQL_Training_;
  2. import java.sql.*;
  3. import java.util.ArrayList;
  4.  
  5. /**
  6.  * Responsible for establishing a connection with the
  7.  * argument Database and sending queries to be executed
  8.  * on the target Database.
  9.  */
  10. public final class DatabaseAccess{
  11.  
  12. private Connection con = null;
  13. private ResultSet rs = null;
  14. private Statement st = null;
  15. private String dbName = "", driverName = "sun.jdbc.odbc.JdbcOdbcDriver",
  16. theTable = "";
  17. private ArrayList< String > queryList =
  18. new ArrayList< String >(0);
  19. private ArrayList< ArrayList<String> > tableList =
  20. new ArrayList< ArrayList<String> >(0);
  21.  
  22. /**
  23.   * Accepts the name of the String as a Database and attempts
  24.   * to load the default Driver supported by Java SE 6.0+
  25.   */
  26. public DatabaseAccess(String dbName){
  27. setDatabase(dbName);
  28. setDriver(driverName);
  29. }
  30.  
  31. /**
  32.   * Accepts the name of the first String as the name
  33.   * of the argument Database, with the argument Driver.
  34.   */
  35. public DatabaseAccess(String dbName, String driver){
  36. setDatabase(dbName);
  37. setDriver(driver);
  38. }
  39.  
  40. /**
  41.   * Attempts to load the argument Driver
  42.   */
  43. public void setDriver(String name){
  44. driverName = name;
  45. try{
  46. Class.forName(driverName);
  47. con = DriverManager.getConnection("jdbc:odbc:" + dbName);
  48. st = con.createStatement();
  49. }catch(Exception e){
  50. System.out.println("An error occurred with the"
  51. + "argument Driver.");
  52. }
  53. }
  54.  
  55. /**
  56.   * Sets the database to be that of the argument.
  57.   * Throws an exception if the database cannot be found
  58.   * or accessed.
  59.   */
  60. public void setDatabase(String dbName){
  61. this.dbName = dbName;
  62. }
  63.  
  64. /**
  65.   * Attempts to update the existing table
  66.   */
  67. public void doUpdate(String query){
  68. try{
  69. st.executeUpdate(query);
  70. queryList.add(query);
  71. }catch(Exception e){
  72. System.out.println("An error occurred with the update query--");
  73. }
  74. }
  75.  
  76. /**
  77.   * Attempts to perform a query for the existing table
  78.   */
  79. public void doQuery(String query){
  80. try{
  81. rs = st.executeQuery(query);
  82. queryList.add(query);
  83. }catch(Exception e){
  84. System.out.println("An error occurred with the action query--");
  85. }
  86. }
  87.  
  88. /**
  89.   * Prints a list of successful queries executed during a session.
  90.   */
  91. public void printQueries(){
  92. for(String element : queryList){
  93. System.out.println(element);
  94. }
  95. System.out.println();
  96. }
  97.  
  98. /**
  99.   * Attempts to display the current table, based on the last
  100.   * selection query.
  101.   */
  102. public void displayTable(){
  103.  
  104. ResultSetMetaData metaData = null;
  105. try{
  106. if(rs != null)
  107. metaData = rs.getMetaData();
  108. else{
  109. System.out.println("Error - Null ResultSet!");
  110. return;
  111. }
  112.  
  113. if(metaData != null){
  114. theTable = "";
  115. int numberOfColumns = metaData.getColumnCount();
  116. System.out.println( );
  117. String other = "";
  118. for ( int i = 1; i <= numberOfColumns; i++ ){
  119. other = "\t" + metaData.getColumnName(i);
  120. theTable += other;
  121. }
  122.  
  123. theTable += "\n";
  124.  
  125. while ( rs.next() ){
  126. String temp = "";
  127. for ( int i = 1; i <= numberOfColumns; i++ ){
  128. temp = "\t" + rs.getObject(i);
  129. theTable += temp;
  130. }
  131. theTable += "\n";
  132. }
  133. }else{
  134. System.out.println("Last query made no visual changes. "
  135. + "Displaying current Table\n");
  136. }
  137. System.out.println(theTable);
  138. }catch(Exception e){
  139. System.out.println("An error occurred while attempting to display "
  140. + "the table.");
  141. }
  142. }
  143.  
  144. /**
  145.   * Simply returns the String value of the current database the
  146.   * user is accessing via this DatabaseAccess object.
  147.   */
  148. @Override public String toString(){
  149. return this.dbName;
  150. }
  151. }
  152.  
  153. /////////////
  154.  
  155. package _SQL_Training_;
  156. import java.util.Scanner;
  157.  
  158. /**
  159.  * The abstraction/commonality of all DatabaseCommands
  160.  */
  161. public abstract class DatabaseCommand {
  162.  
  163. protected DatabaseAccess da;
  164. protected Scanner getInput;
  165.  
  166. /**
  167.   * Constructor
  168.   */
  169. public DatabaseCommand(DatabaseAccess da, Scanner input){
  170. this.da = da;
  171. getInput = input;
  172. }
  173.  
  174. /**
  175.   * Execute the command
  176.   */
  177. public abstract void execute();
  178. }
  179.  
  180.  
  181. /////////////
  182.  
  183. package _SQL_Training_;
  184. import javax.swing.SwingUtilities;
  185. import java.util.Scanner;
  186.  
  187. /**
  188.  * A program that gives the user the ability to execute
  189.  * commands and queries for a the given Databases, as well
  190.  * as enable displays for the user to see the current information
  191.  * in the database.
  192.  */
  193. public class DatabaseProgram {
  194.  
  195. private DatabaseAccess dbObjs[], chosenDatabase = null;
  196. private volatile boolean locked = false;
  197. private DatabaseCommandFactory dcf =
  198. new DatabaseCommandFactory();
  199. private final Scanner kb = new Scanner(System.in);
  200.  
  201. /**
  202.   * Constructs a DatabaseProgram
  203.   */
  204. public DatabaseProgram(DatabaseAccess... objs){
  205. if(objs.length > 0)
  206. setDatabaseObjects(objs);
  207. else{
  208. System.out.println("Error! You must submit at least 1 DatabaseAccess "
  209. + "object!");
  210. }
  211. }
  212.  
  213. /**
  214.   * Driver method - entrypoint of the program
  215.   */
  216. public static void main(String... args){
  217. DatabaseAccess da = new DatabaseAccess("TD");
  218. DatabaseProgram dp = new DatabaseProgram(da);
  219. dp.startProgram();
  220. }
  221.  
  222. /**
  223.   * Sets the DatabaseObjects if the class isn't locked.
  224.   */
  225. public void setDatabaseObjects(DatabaseAccess... objs){
  226. if(!locked)
  227. dbObjs = objs;
  228. }
  229.  
  230. /**
  231.   * Applies a Double-Check lock before officially starting the program.
  232.   */
  233. public void startProgram(){
  234. if(!locked
  235. && dbObjs != null) // not thread safe, but negates slowing from sync in the future
  236. synchronized(this){ // halts threads except the one with the lock
  237. if(!locked
  238. && dbObjs != null){ // thread with the lock does its job here while others wait
  239. System.out.println("Program Started!\n");
  240. locked = true;
  241. SwingUtilities.invokeLater(rt);
  242. }
  243. }
  244. }
  245.  
  246. /**
  247.   * Escape-Thread for the Thread that is capable of triggerring
  248.   * the program before a lock. This technique should allow other
  249.   * threads to fail the start and continue performing other tasks.
  250.   */
  251. private Runnable rt = new Runnable(){
  252. boolean stopped = false;
  253. @Override public void run(){
  254. do{
  255. System.out.println("Which Database will you access?\n");
  256.  
  257. for(DatabaseAccess element : dbObjs)
  258. System.out.println(element);
  259.  
  260. String result = kb.nextLine();
  261. boolean validAnswer = false;
  262. for(DatabaseAccess element : dbObjs){
  263. if(result.equalsIgnoreCase(element.toString())){
  264. validAnswer = true;
  265. chosenDatabase = element;
  266. dcf.setHandles(chosenDatabase, kb);
  267. }
  268. }
  269.  
  270. if(!validAnswer){
  271. System.out.println("Invalid Database selected--\n");
  272. System.out.println("Continue? Enter EXIT to end or any "
  273. + "other key to continue.\n");
  274. if(!kb.nextLine().equalsIgnoreCase("EXIT"))
  275. continue;
  276. else stopped = true;
  277. }
  278. if(!stopped){
  279. boolean doingCommands = true;
  280. do{
  281. System.out.println("Which action would you like to do for "
  282. + chosenDatabase + "?");
  283. String options[] = dcf.getOptions();
  284. for(String element : options)
  285. System.out.println(element);
  286. System.out.println("\nIf no action, then enter EXIT\n\n");
  287. String choice = kb.nextLine();
  288. DatabaseCommand dc = dcf.getCommand(choice);
  289.  
  290. if(dc != null){
  291. dc.execute();
  292. }else{
  293. if(choice.equalsIgnoreCase("Exit")){
  294. doingCommands = false;
  295. }
  296. else System.out.println("Invalid Command\n");
  297. }
  298. }while(doingCommands);
  299. }
  300. }while(!stopped);
  301. locked = false;
  302. }
  303. };
  304.  
  305. /**
  306.   * The QueryAndDisplay Command - this is a combination command
  307.   * that supports the execution of a query and additionally displays
  308.   * the current table.
  309.   */
  310. private class QueryAndDisplay extends QueryCommand{
  311. public QueryAndDisplay(DatabaseAccess da, Scanner s){super(da, s);}
  312. @Override public void execute(){super.execute();da.displayTable();}
  313. }
  314.  
  315. /**
  316.   * The Query Command - responsible for sending a query to the target
  317.   * database. In addition, a query is likely to update the resultSet
  318.   * and therefore update the display.
  319.   */
  320. private class QueryCommand extends DatabaseCommand{
  321. public QueryCommand(DatabaseAccess da, Scanner s){super(da, s);}
  322. @Override public void execute(){
  323. System.out.println("Enter a query to execute:\n");
  324. da.doQuery(getInput.nextLine());
  325. }
  326. }
  327.  
  328. /**
  329.   * The PrintQueries Command - responsible for printing all
  330.   * queries performed during a DatabaseProgram session..
  331.   */
  332. private class PrintQueriesCommand extends DatabaseCommand{
  333. public PrintQueriesCommand(DatabaseAccess da, Scanner s){super(da, s);}
  334. @Override public void execute(){
  335. System.out.println("Printing Queries...\n");
  336. da.printQueries();
  337. System.out.println();
  338. }
  339. }
  340.  
  341. /**
  342.   * The Update Command - responsible for sending a query
  343.   * to the target database.
  344.   */
  345. private class UpdateCommand extends DatabaseCommand{
  346. public UpdateCommand(DatabaseAccess da, Scanner s){super(da, s);}
  347. @Override public void execute(){
  348. System.out.println("Enter an update query:\n");
  349. da.doUpdate(getInput.nextLine());
  350. }
  351. }
  352.  
  353. /**
  354.   * The DisplayCommand - responsible for displaying the current table.
  355.   */
  356. private class DisplayCommand extends DatabaseCommand{
  357. public DisplayCommand(DatabaseAccess da, Scanner s){super(da, s);}
  358. @Override public void execute(){da.displayTable();}
  359. }
  360.  
  361. /**
  362.   * Producer class for commands relative to the DatabaseProgram
  363.   */
  364. private class DatabaseCommandFactory{
  365. private Scanner theInput;
  366. private DatabaseAccess myDBObj;
  367.  
  368. /**
  369.   * Sets the handle for the Database and the Input
  370.   * for each DatabaseCommand.
  371.   */
  372. public void setHandles(DatabaseAccess da, Scanner kb){
  373. theInput = kb;
  374. myDBObj = da;
  375. }
  376.  
  377. /**
  378.   * Factory method that produces a command to use
  379.   */
  380. public DatabaseCommand getCommand(String arg){
  381. DatabaseCommand tempDC = (arg.equalsIgnoreCase("QUERY"))
  382. ? new QueryCommand(myDBObj, theInput):(arg.equalsIgnoreCase("UPDATE"))
  383. ? new UpdateCommand(myDBObj, theInput):(arg.equalsIgnoreCase("DISPLAY"))
  384. ? new DisplayCommand(myDBObj, theInput):(arg.equalsIgnoreCase("PRINTQUERIES"))
  385. ? new PrintQueriesCommand(myDBObj, theInput):(arg.equalsIgnoreCase("QnD"))
  386. ? new QueryAndDisplay(myDBObj, theInput): null;
  387. return tempDC;
  388. }
  389.  
  390. /**
  391.   * Returns a list of options for the commands available
  392.   * from this factory.
  393.   */
  394. public String[] getOptions(){
  395. String temp[] ={
  396. "Query",
  397. "Update",
  398. "Display",
  399. "QnD",
  400. "PrintQueries"
  401. };
  402. return temp;
  403. }
  404. }
  405. }
  406.  
  407. /////////////////////////////////////////////
  408.  
  409. /**
  410.  A test run of the program using NetBeans 6.1--
  411.  
  412. init:
  413. deps-jar:
  414. compile-single:
  415. run-single:
  416. Program Started!
  417.  
  418. Which Database will you access?
  419.  
  420. TD
  421. TD
  422. Which action would you like to do for TD?
  423. Query
  424. Update
  425. Display
  426. QnD
  427. PrintQueries
  428.  
  429. If no action, then enter EXIT
  430.  
  431.  
  432. QnD
  433. Enter a query to execute:
  434.  
  435. SELECT Name FROM MyTable
  436.  
  437.   Name
  438.   Mark
  439.  
  440. Which action would you like to do for TD?
  441. Query
  442. Update
  443. Display
  444. QnD
  445. PrintQueries
  446.  
  447. If no action, then enter EXIT
  448.  
  449.  
  450. PRINTQUERIES
  451. Printing Queries...
  452.  
  453. SELECT Name FROM MyTable
  454.  
  455.  
  456. Which action would you like to do for TD?
  457. Query
  458. Update
  459. Display
  460. QnD
  461. PrintQueries
  462.  
  463. If no action, then enter EXIT
  464.  
  465.  
  466. QUERY
  467. Enter a query to execute:
  468.  */
0
Alex Edwards Alex Edwards is offline Offline | Sep 9th, 2008
Quite a few flaws noted in this version--


-It would probably be more advantageous to use ConsoleIOProgram

-Invoking a thread on the EDT isn't desirable. It would be more beneficial to run a thread from the EDT (via swing or awt) to run a runnable that executes this program.

-This version doesn't account for password-protected Databases (i.e., Oracle)

-Ridiculous use of 2 Design Patterns. It probably would have been more beneficial had I allowed the user to load commands for the Database Program. Either that or allow a user to supply a factory to produce Command objects. Even then, there's the question of heap usage - why make things hard for the Garbage Collecting threads? A Factory that retrieves a reference to a singleton command (one that is instantiated once) would be more preferable, though depending on the necessity of reuse and the future of querying (or the type of Database you're accessing), etc.


-Pluses

-One good implementation in this program is the getOptions[]() method that produces a new set of the existing Instructions. Though this doesn't adhere to reusable code, the idea is straightforward to prevent catastrophes like this--

  1. public class MyTypes{
  2.  
  3. private String values[] = {"North", "South", "East", "West"};
  4.  
  5. public String[] getValues(boolean theReference){
  6. return (theReference) ? values : new String[]{"North", "South", "East", "West"};
  7. }
  8.  
  9. @Override public String toString(){
  10. String temp = "";
  11. for(String element : getValues(true))
  12. temp += element + "\t";
  13. temp += "\n";
  14. for(String element : getValues(false))
  15. temp += element + "\t";
  16. return temp;
  17. }
  18.  
  19. public static void main(String... args){
  20. MyTypes mt = new MyTypes();
  21.  
  22. String thief[] = mt.getValues(true); // thief points to the global array
  23.  
  24. // changing the address the pointer at mt.values[2] poitns to from "East" to "CENTER"
  25. thief[2] = "CENTER";
  26.  
  27. System.out.println(mt); // Strings are immutable, but in java pointers aren't unless marked final!
  28. }
  29. }

-- but it can easily be make in a reusable manner for all commands registered in a factory, or if commands are loaded into the program, one can call ArrayList<T>.<T>toArray(new T[ArrayList<T>.size()]); granted T is known before compile time.

- The double-checked lock is a plus, though it's not immediately apparent in this version because I'm not using multi-threading in this example and I also screwed up with running the program in the EDT.


-More updates to come in the future.
 
0
newtonorina newtonorina is offline Offline | Nov 13th, 2008
isn't that code long for one to understand
 
 

Message:


Thread Tools Search this Thread



Tag cloud for Java
About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2010 DaniWeb® LLC