source: src/main/java/weka/gui/sql/SqlViewer.java @ 8

Last change on this file since 8 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 18.6 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 * SqlViewer.java
19 * Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.sql;
24
25import weka.core.Memory;
26import weka.gui.LookAndFeel;
27import weka.gui.sql.event.ConnectionEvent;
28import weka.gui.sql.event.ConnectionListener;
29import weka.gui.sql.event.HistoryChangedEvent;
30import weka.gui.sql.event.HistoryChangedListener;
31import weka.gui.sql.event.QueryExecuteEvent;
32import weka.gui.sql.event.QueryExecuteListener;
33import weka.gui.sql.event.ResultChangedEvent;
34import weka.gui.sql.event.ResultChangedListener;
35
36import java.awt.BorderLayout;
37import java.awt.Dimension;
38import java.awt.event.WindowAdapter;
39import java.awt.event.WindowEvent;
40import java.io.BufferedInputStream;
41import java.io.BufferedOutputStream;
42import java.io.File;
43import java.io.FileInputStream;
44import java.io.FileOutputStream;
45import java.util.Properties;
46
47import javax.swing.BorderFactory;
48import javax.swing.DefaultListModel;
49import javax.swing.JFrame;
50import javax.swing.JPanel;
51
52/**
53 * Represents a little tool for querying SQL databases.
54 *
55 * @author      FracPete (fracpete at waikato dot ac dot nz)
56 * @version     $Revision: 4724 $
57 */
58public class SqlViewer 
59  extends    JPanel
60  implements ConnectionListener, 
61             HistoryChangedListener,
62             QueryExecuteListener, 
63             ResultChangedListener {
64
65  /** for serialization. */
66  private static final long serialVersionUID = -4395028775566514329L;
67
68  /** the name of the history file (in the home directory). */
69  protected final static String HISTORY_FILE = "SqlViewerHistory.props";
70
71  /** the width property in the history file. */
72  public final static String WIDTH = "width";
73
74  /** the height property in the history file. */
75  public final static String HEIGHT = "height";
76 
77  /** the parent of this panel. */
78  protected JFrame m_Parent;
79
80  /** the connection panel. */
81  protected ConnectionPanel m_ConnectionPanel;
82
83  /** the query panel. */
84  protected QueryPanel m_QueryPanel;
85
86  /** the result panel. */
87  protected ResultPanel m_ResultPanel;
88
89  /** the info panel. */
90  protected InfoPanel m_InfoPanel;
91
92  /** the connect string with which the query was run. */
93  protected String m_URL;
94
95  /** the user that was used to connect to the DB. */
96  protected String m_User;
97
98  /** the password that was used to connect to the DB. */
99  protected String m_Password;
100
101  /** the currently selected query. */
102  protected String m_Query;
103
104  /** stores the history. */
105  protected Properties m_History;
106 
107  /**
108   * initializes the SqlViewer.
109   *
110   * @param parent        the parent of this panel
111   */
112  public SqlViewer(JFrame parent) {
113    super();
114   
115    m_Parent   = parent;
116    m_URL      = "";
117    m_User     = "";
118    m_Password = "";
119    m_Query    = "";
120    m_History  = new Properties();
121   
122    createPanel();
123  }
124
125  /**
126   * builds the interface.
127   */
128  protected void createPanel() {
129    JPanel          panel;
130    JPanel          panel2;
131   
132    setLayout(new BorderLayout());
133
134    // connection
135    m_ConnectionPanel = new ConnectionPanel(m_Parent);
136    panel = new JPanel(new BorderLayout());
137    add(panel, BorderLayout.NORTH);
138    panel.setBorder(BorderFactory.createCompoundBorder(
139                    BorderFactory.createTitledBorder("Connection"),
140                    BorderFactory.createEmptyBorder(0, 5, 5, 5)));
141    panel.add(m_ConnectionPanel, BorderLayout.CENTER);
142
143    // query
144    m_QueryPanel = new QueryPanel(m_Parent);
145    panel = new JPanel(new BorderLayout());
146    add(panel, BorderLayout.CENTER);
147    panel2 = new JPanel(new BorderLayout());
148    panel2.setBorder(BorderFactory.createCompoundBorder(
149                     BorderFactory.createTitledBorder("Query"),
150                     BorderFactory.createEmptyBorder(0, 5, 5, 5)));
151    panel2.add(m_QueryPanel, BorderLayout.NORTH);
152    panel.add(panel2, BorderLayout.NORTH);
153
154    // result
155    m_ResultPanel = new ResultPanel(m_Parent);
156    m_ResultPanel.setQueryPanel(m_QueryPanel);
157    panel2 = new JPanel(new BorderLayout());
158    panel2.setBorder(BorderFactory.createCompoundBorder(
159                     BorderFactory.createTitledBorder("Result"),
160                     BorderFactory.createEmptyBorder(0, 5, 5, 5)));
161    panel2.add(m_ResultPanel, BorderLayout.CENTER);
162    panel.add(panel2, BorderLayout.CENTER);
163
164    // info
165    m_InfoPanel = new InfoPanel(m_Parent);
166    panel = new JPanel(new BorderLayout());
167    add(panel, BorderLayout.SOUTH);
168    panel.setBorder(BorderFactory.createCompoundBorder(
169                    BorderFactory.createTitledBorder("Info"),
170                    BorderFactory.createEmptyBorder(0, 5, 5, 5)));
171    panel.add(m_InfoPanel, BorderLayout.CENTER);
172
173    // listeners
174    addConnectionListener(this);
175    addConnectionListener(m_QueryPanel);
176    addQueryExecuteListener(this);
177    addQueryExecuteListener(m_ResultPanel);
178    addResultChangedListener(this);
179    addHistoryChangedListener(this);
180
181    // history
182    loadHistory(true);
183  }
184 
185  /**
186   * This method gets called when the connection is either established
187   * or disconnected.
188   *
189   * @param evt         the event
190   */
191  public void connectionChange(ConnectionEvent evt) {
192    if (evt.getType() == ConnectionEvent.DISCONNECT) {
193      m_InfoPanel.append(   "disconnect from: " 
194                          + evt.getDbUtils().getDatabaseURL(),
195                          "information_small.gif" );
196    }
197    else {
198      m_InfoPanel.append(   "connecting to: " 
199                          + evt.getDbUtils().getDatabaseURL() 
200                          + " = " + evt.isConnected(),
201                          "information_small.gif" );
202    }
203
204    // did an exception happen?
205    if (evt.getException() != null)
206      m_InfoPanel.append("exception: " + evt.getException(), "error_small.gif");
207
208    // set focus
209    if (evt.isConnected())
210      m_QueryPanel.setFocus();
211    else
212      m_ConnectionPanel.setFocus();
213  }
214 
215  /**
216   * This method gets called when a query has been executed.
217   *
218   * @param evt         the event
219   */
220  public void queryExecuted(QueryExecuteEvent evt) {
221    ResultSetHelper   helper;
222   
223    if (evt.failed()) {
224      m_InfoPanel.append("Query:" + evt.getQuery(), "error_small.gif");
225      m_InfoPanel.append("exception: " + evt.getException(), "error_small.gif");
226    }
227    else {
228      m_InfoPanel.append("Query: " + evt.getQuery(), "information_small.gif");
229      try {
230        if (evt.hasResult()) {
231          helper = new ResultSetHelper(evt.getResultSet());
232          if ((evt.getMaxRows() > 0) && (helper.getRowCount() >= evt.getMaxRows()))
233            m_InfoPanel.append(helper.getRowCount() + " rows selected (" 
234                + evt.getMaxRows() + " displayed).", 
235                "information_small.gif");
236          else if (helper.getRowCount() == -1)
237            m_InfoPanel.append("Unknown number of rows selected (due to JDBC driver restrictions).", 
238              "information_small.gif");
239          else
240            m_InfoPanel.append(helper.getRowCount() + " rows selected.", 
241                "information_small.gif");
242        }
243
244        // save max rows
245        loadHistory(false);
246        m_History.setProperty(
247            QueryPanel.MAX_ROWS, Integer.toString(evt.getMaxRows()));
248        saveHistory();
249      }
250      catch (Exception e) {
251        e.printStackTrace();
252      }
253    }
254  }
255 
256  /**
257   * This method gets called when a query has been executed.
258   *
259   * @param evt         the event
260   */
261  public void resultChanged(ResultChangedEvent evt) {
262    m_URL      = evt.getURL();
263    m_User     = evt.getUser();
264    m_Password = evt.getPassword();
265    m_Query    = evt.getQuery();
266  }
267 
268  /**
269   * This method gets called when a history is modified.
270   * It saves the history immediately to the users home directory.
271   *
272   * @param evt         the event
273   */
274  public void historyChanged(HistoryChangedEvent evt) {
275    // load history, in case some other process changed it!
276    loadHistory(false);
277   
278    m_History.setProperty( 
279        evt.getHistoryName(), modelToString(evt.getHistory()));
280
281    // save it
282    saveHistory();
283  }
284
285  /**
286   * returns the filename of the history file.
287   *
288   * @return            the history file
289   */
290  protected String getHistoryFilename() {
291    return   System.getProperties().getProperty("user.home")
292           + File.separatorChar
293           + HISTORY_FILE;
294  }
295
296  /**
297   * transforms the given, comma-separated string into a DefaultListModel.
298   *
299   * @param s     the string to break up and transform into a list model
300   * @return      the generated DefaultListModel
301   */
302  protected DefaultListModel stringToModel(String s) {
303    DefaultListModel    result;
304    String              tmpStr;
305    int                 i;
306    boolean             quote;
307    String[]            find;
308    String[]            replace;
309    int                 index;
310
311    result = new DefaultListModel();
312   
313    // get rid of doubled quotes, \\n, etc.
314    find    = new String[]{"\"\"", "\\n", "\\r", "\\t"};
315    replace = new String[]{"\"",   "\n",  "\r",  "\t"};
316    for (i = 0; i < find.length; i++) {
317      tmpStr = "";
318      while (s.length() > 0) {
319        index = s.indexOf(find[i]);
320        if (index > -1) {
321          tmpStr += s.substring(0, index) + replace[i];
322          s       = s.substring(index + 2);
323        }
324        else {
325          tmpStr += s;
326          s       = "";
327        }
328      }
329      s = tmpStr;
330    }
331
332    quote  = false;
333    tmpStr = "";
334    for (i = 0; i < s.length(); i++) {
335      if (s.charAt(i) == '"') {
336        quote = !quote;
337        tmpStr += "" + s.charAt(i);
338      }
339      else if (s.charAt(i) == ',') {
340        if (quote) {
341          tmpStr += "" + s.charAt(i);
342        }
343        else {
344          if (tmpStr.startsWith("\""))
345            tmpStr = tmpStr.substring(1, tmpStr.length() - 1);
346          result.addElement(tmpStr);
347          tmpStr = "";
348        }
349      }
350      else {
351        tmpStr += "" + s.charAt(i);
352      }
353    }
354   
355    // add last element
356    if (!tmpStr.equals("")) {
357      if (tmpStr.startsWith("\""))
358        tmpStr = tmpStr.substring(1, tmpStr.length() - 1);
359      result.addElement(tmpStr);
360    }
361
362    return result;
363  }
364
365  /**
366   * converts the given model into a comma-separated string.
367   *
368   * @param m       the model to convert
369   * @return        the string representation of the model
370   */
371  protected String modelToString(DefaultListModel m) {
372    String      result;
373    String      tmpStr;
374    int         i;
375    int         n;
376    boolean     quote;
377
378    result = "";
379
380    for (i = 0; i < m.size(); i++) {
381      if (i > 0)
382        result += ",";
383     
384      tmpStr = m.get(i).toString();
385      quote  = (tmpStr.indexOf(",") > -1) || (tmpStr.indexOf(" ") > -1);
386     
387      if (quote)
388        result += "\"";
389     
390      for (n = 0; n < tmpStr.length(); n++) {
391        // double quotes
392        if (tmpStr.charAt(n) == '"')
393          result += "" + "\"\"";
394        // normal character
395        else
396          result += "" + tmpStr.charAt(n);
397      }
398     
399      if (quote)
400        result += "\"";
401    }
402
403    return result;
404  }
405
406  /**
407   * loads the history properties of the SqlViewer in the user's home directory.
408   *
409   * @param set       whether to set the read properties in the panels or not
410   * @see #HISTORY_FILE
411   */
412  protected void loadHistory(boolean set) {
413    BufferedInputStream         str;
414    File                        file;
415    int                         width;
416    int                         height;
417
418    try {
419      file = new File(getHistoryFilename());
420      if (file.exists()) {
421        str = new BufferedInputStream(
422            new FileInputStream(getHistoryFilename()));
423        m_History.load(str);
424      }
425    }
426    catch (Exception e) {
427      e.printStackTrace();
428    }
429
430    // set the histories
431    if (set) {
432      m_ConnectionPanel.setHistory(
433          stringToModel(
434            m_History.getProperty(ConnectionPanel.HISTORY_NAME, "")));
435      m_QueryPanel.setHistory(
436          stringToModel(
437            m_History.getProperty(QueryPanel.HISTORY_NAME, "")));
438      m_QueryPanel.setMaxRows(
439          Integer.parseInt(m_History.getProperty(QueryPanel.MAX_ROWS, "100")));
440
441      width  = Integer.parseInt(m_History.getProperty(WIDTH, "0"));
442      height = Integer.parseInt(m_History.getProperty(HEIGHT, "0"));
443      if ((width != 0) && (height != 0))
444        setPreferredSize(new Dimension(width, height));
445    }
446  }
447
448  /**
449   * saves the history properties of the SqlViewer in the user's home directory.
450   *
451   * @see #HISTORY_FILE
452   */
453  protected void saveHistory() {
454    BufferedOutputStream    str;
455   
456    try {
457      str = new BufferedOutputStream(
458          new FileOutputStream(getHistoryFilename()));
459      m_History.store(str, "SQL-Viewer-History");
460    }
461    catch (Exception e) {
462      e.printStackTrace();
463    }
464  }
465
466  /**
467   * obtains the size of the panel and saves it in the history.
468   *
469   * @see #saveHistory()
470   */
471  public void saveSize() {
472    m_History.setProperty(WIDTH, "" + getSize().width);
473    m_History.setProperty(HEIGHT, "" + getSize().height);
474
475    saveHistory();
476  }
477 
478  /**
479   * calls the clear method of all sub-panels to set back to default values
480   * and free up memory.
481   */
482  public void clear() {
483    m_ConnectionPanel.clear();
484    m_QueryPanel.clear();
485    m_ResultPanel.clear();
486    m_InfoPanel.clear();
487  }
488
489  /**
490   * returns the database URL from the currently active tab in the ResultPanel,
491   * otherwise an empty string.
492   *
493   * @see               ResultPanel
494   * @return            the currently selected tab's URL
495   */
496  public String getURL() {
497    return m_URL;
498  }
499
500  /**
501   * returns the user from the currently active tab in the ResultPanel,
502   * otherwise an empty string.
503   *
504   * @see               ResultPanel
505   * @return            the currently selected tab's user
506   */
507  public String getUser() {
508    return m_User;
509  }
510
511  /**
512   * returns the password from the currently active tab in the ResultPanel,
513   * otherwise an empty string.
514   *
515   * @see               ResultPanel
516   * @return            the currently selected tab's password
517   */
518  public String getPassword() {
519    return m_Password;
520  }
521
522  /**
523   * returns the query from the currently active tab in the ResultPanel,
524   * otherwise an empty string.
525   *
526   * @see               ResultPanel
527   * @return            the currently selected tab's query
528   */
529  public String getQuery() {
530    return m_Query;
531  }
532
533  /**
534   * adds the given listener to the list of listeners.
535   *
536   * @param l           the listener to add to the list
537   */
538  public void addConnectionListener(ConnectionListener l) {
539    m_ConnectionPanel.addConnectionListener(l);
540  }
541
542  /**
543   * removes the given listener from the list of listeners.
544   *
545   * @param l           the listener to remove
546   */
547  public void removeConnectionListener(ConnectionListener l) {
548    m_ConnectionPanel.removeConnectionListener(l);
549  }
550
551  /**
552   * adds the given listener to the list of listeners.
553   *
554   * @param l           the listener to add to the list
555   */
556  public void addQueryExecuteListener(QueryExecuteListener l) {
557    m_QueryPanel.addQueryExecuteListener(l);
558  }
559
560  /**
561   * removes the given listener from the list of listeners.
562   *
563   * @param l           the listener to remove
564   */
565  public void removeQueryExecuteListener(QueryExecuteListener l) {
566    m_QueryPanel.removeQueryExecuteListener(l);
567  }
568
569  /**
570   * adds the given listener to the list of listeners.
571   *
572   * @param l           the listener to add to the list
573   */
574  public void addResultChangedListener(ResultChangedListener l) {
575    m_ResultPanel.addResultChangedListener(l);
576  }
577
578  /**
579   * removes the given listener from the list of listeners.
580   *
581   * @param l           the listener to remove
582   */
583  public void removeResultChangedListener(ResultChangedListener l) {
584    m_ResultPanel.removeResultChangedListener(l);
585  }
586
587  /**
588   * adds the given listener to the list of listeners.
589   *
590   * @param l           the listener to add to the list
591   */
592  public void addHistoryChangedListener(HistoryChangedListener l) {
593    m_ConnectionPanel.addHistoryChangedListener(l);
594    m_QueryPanel.addHistoryChangedListener(l);
595  }
596
597  /**
598   * removes the given listener from the list of listeners.
599   *
600   * @param l           the listener to remove
601   */
602  public void removeHistoryChangedListener(HistoryChangedListener l) {
603    m_ConnectionPanel.removeHistoryChangedListener(l);
604    m_QueryPanel.removeHistoryChangedListener(l);
605  }
606
607  /** for monitoring the Memory consumption. */
608  private static Memory m_Memory = new Memory(true);
609 
610  /** the sql viewer. */
611  private static SqlViewer m_Viewer;
612 
613  /**
614   * starts the SQL-Viewer interface.
615   *
616   * @param args        the commandline arguments - ignored
617   */
618  public static void main(String[] args) {
619    weka.core.logging.Logger.log(weka.core.logging.Logger.Level.INFO, "Logging started");
620    LookAndFeel.setLookAndFeel();
621   
622    try {
623      // uncomment to disable the memory management:
624      //m_Memory.setEnabled(false);
625
626      final JFrame jf = new JFrame("Weka SQL-Viewer");
627      m_Viewer = new SqlViewer(jf);
628      jf.getContentPane().setLayout(new BorderLayout());
629      jf.getContentPane().add(m_Viewer, BorderLayout.CENTER);
630      jf.addWindowListener(new WindowAdapter() {
631        public void windowClosing(WindowEvent e) {
632          m_Viewer.saveSize();
633          jf.dispose();
634          System.exit(0);
635        }
636      });
637      jf.pack();
638      jf.setSize(800, 600);
639      jf.setVisible(true);
640
641      Thread memMonitor = new Thread() {
642        public void run() {
643          while (true) {
644            try {
645              this.sleep(4000);
646
647              System.gc();
648
649              if (m_Memory.isOutOfMemory()) {
650                // clean up
651                jf.dispose();
652                m_Viewer = null;
653                System.gc();
654
655                // stop threads
656                m_Memory.stopThreads();
657
658                // display error
659                System.err.println("\ndisplayed message:");
660                m_Memory.showOutOfMemory();
661                System.err.println("\nexiting");
662                System.exit(-1);
663              }
664
665            } 
666            catch (InterruptedException ex) { 
667              ex.printStackTrace(); 
668            }
669          }
670        }
671      };
672
673      memMonitor.setPriority(Thread.MAX_PRIORITY);
674      memMonitor.start();
675    } 
676    catch (Exception ex) {
677      ex.printStackTrace();
678      System.err.println(ex.getMessage());
679    }
680  }
681}
Note: See TracBrowser for help on using the repository browser.