0001: package net.sourceforge.squirrel_sql.client.session;
0002:
0003: /*
0004: * Copyright (C) 2001-2004 Colin Bell
0005: * colbell@users.sourceforge.net
0006: *
0007: * Modifications copyright (C) 2001-2004 Johan Compagner
0008: * jcompagner@j-com.nl
0009: *
0010: * Modifications Copyright (C) 2003-2004 Jason Height
0011: *
0012: * This library is free software; you can redistribute it and/or
0013: * modify it under the terms of the GNU Lesser General Public
0014: * License as published by the Free Software Foundation; either
0015: * version 2.1 of the License, or (at your option) any later version.
0016: *
0017: * This library is distributed in the hope that it will be useful,
0018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0020: * Lesser General Public License for more details.
0021: *
0022: * You should have received a copy of the GNU Lesser General Public
0023: * License along with this library; if not, write to the Free Software
0024: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0025: */
0026: import java.beans.PropertyChangeEvent;
0027: import java.beans.PropertyChangeListener;
0028: import java.sql.ResultSet;
0029: import java.sql.SQLException;
0030: import java.util.ArrayList;
0031: import java.util.HashMap;
0032: import java.util.Hashtable;
0033: import java.util.List;
0034: import java.util.ListIterator;
0035: import java.util.Map;
0036:
0037: import javax.swing.Action;
0038: import javax.swing.JComponent;
0039: import javax.swing.JFrame;
0040: import javax.swing.JOptionPane;
0041: import javax.swing.SwingUtilities;
0042:
0043: import net.sourceforge.squirrel_sql.client.IApplication;
0044: import net.sourceforge.squirrel_sql.client.gui.db.ISQLAliasExt;
0045: import net.sourceforge.squirrel_sql.client.gui.db.SQLAlias;
0046: import net.sourceforge.squirrel_sql.client.gui.session.BaseSessionInternalFrame;
0047: import net.sourceforge.squirrel_sql.client.gui.session.ObjectTreeInternalFrame;
0048: import net.sourceforge.squirrel_sql.client.gui.session.SQLInternalFrame;
0049: import net.sourceforge.squirrel_sql.client.gui.session.SessionInternalFrame;
0050: import net.sourceforge.squirrel_sql.client.gui.session.SessionPanel;
0051: import net.sourceforge.squirrel_sql.client.mainframe.action.OpenConnectionCommand;
0052: import net.sourceforge.squirrel_sql.client.plugin.IPlugin;
0053: import net.sourceforge.squirrel_sql.client.session.mainpanel.IMainPanelTab;
0054: import net.sourceforge.squirrel_sql.client.session.parser.IParserEventsProcessor;
0055: import net.sourceforge.squirrel_sql.client.session.parser.ParserEventsProcessor;
0056: import net.sourceforge.squirrel_sql.client.session.properties.SessionProperties;
0057: import net.sourceforge.squirrel_sql.client.session.schemainfo.SchemaInfo;
0058: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
0059: import net.sourceforge.squirrel_sql.fw.persist.ValidationException;
0060: import net.sourceforge.squirrel_sql.fw.sql.IQueryTokenizer;
0061: import net.sourceforge.squirrel_sql.fw.sql.ISQLConnection;
0062: import net.sourceforge.squirrel_sql.fw.sql.ISQLDatabaseMetaData;
0063: import net.sourceforge.squirrel_sql.fw.sql.ISQLDriver;
0064: import net.sourceforge.squirrel_sql.fw.sql.QueryTokenizer;
0065: import net.sourceforge.squirrel_sql.fw.sql.SQLConnection;
0066: import net.sourceforge.squirrel_sql.fw.sql.SQLConnectionState;
0067: import net.sourceforge.squirrel_sql.fw.sql.SQLDatabaseMetaData;
0068: import net.sourceforge.squirrel_sql.fw.util.DefaultExceptionFormatter;
0069: import net.sourceforge.squirrel_sql.fw.util.ExceptionFormatter;
0070: import net.sourceforge.squirrel_sql.fw.util.IMessageHandler;
0071: import net.sourceforge.squirrel_sql.fw.util.NullMessageHandler;
0072: import net.sourceforge.squirrel_sql.fw.util.StringManager;
0073: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
0074: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
0075: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
0076:
0077: /**
0078: * Think of a session as being the users view of the database. IE it includes
0079: * the database connection and the UI.
0080: *
0081: * @author <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
0082: */
0083: class Session implements ISession {
0084: /** Logger for this class. */
0085: private static final ILogger s_log = LoggerController
0086: .createLogger(Session.class);
0087:
0088: /** Internationalized strings for this class. */
0089: private static final StringManager s_stringMgr = StringManagerFactory
0090: .getStringManager(Session.class);
0091:
0092: /** Factory used to generate unique IDs for sessions.
0093: /** Descriptive title for session. */
0094: private String _title = "";
0095:
0096: private SessionPanel _sessionSheet;
0097:
0098: /** The <TT>IIdentifier</TT> that uniquely identifies this object. */
0099: private final IIdentifier _id;
0100:
0101: /** Application API. */
0102: private IApplication _app;
0103:
0104: /** Connection to database. */
0105: private SQLConnection _conn;
0106:
0107: /** Driver used to connect to database. */
0108: private ISQLDriver _driver;
0109:
0110: /** Alias describing how to connect to database. */
0111: private SQLAlias _alias;
0112:
0113: private final String _user;
0114: private final String _password;
0115:
0116: /** Properties for this session. */
0117: private SessionProperties _props;
0118:
0119: /**
0120: * Objects stored in session. Each entry is a <TT>Map</TT>
0121: * keyed by <TT>IPlugin.getInternalName()</TT>. Each <TT>Map</TT>
0122: * contains the objects saved for the plugin.
0123: */
0124: private final Map<String, Map<String, Object>> _pluginObjects = new HashMap<String, Map<String, Object>>();
0125:
0126: private IMessageHandler _msgHandler = NullMessageHandler
0127: .getInstance();
0128:
0129: /** Xref info about the current connection. */
0130: private final net.sourceforge.squirrel_sql.client.session.schemainfo.SchemaInfo _schemaInfo;
0131:
0132: /** Set to <TT>true</TT> once session closed. */
0133: private boolean _closed;
0134:
0135: private List<JComponent> _statusBarToBeAdded = new ArrayList<JComponent>();
0136:
0137: private SQLConnectionListener _connLis = null;
0138:
0139: private BaseSessionInternalFrame _activeActiveSessionWindow;
0140: private SessionInternalFrame _sessionInternalFrame;
0141: private Hashtable<IIdentifier, ParserEventsProcessor> _parserEventsProcessorsByEntryPanelIdentifier = new Hashtable<IIdentifier, ParserEventsProcessor>();
0142:
0143: /** flag to track whether or not the table data has been loaded in the object tree */
0144: private boolean _finishedLoading = false;
0145:
0146: /** flag to track whether or not the plugins have finished loading for this new session */
0147: private boolean _pluginsFinishedLoading = false;
0148:
0149: /** This is set to true when a plugin sets a custom IQueryTokenizer */
0150: private boolean customTokenizerInstalled = false;
0151:
0152: private IQueryTokenizer tokenizer = null;
0153:
0154: /** The default exception formatter */
0155: private DefaultExceptionFormatter formatter = new DefaultExceptionFormatter();
0156:
0157: /**
0158: * Create a new session.
0159: *
0160: * @param app Application API.
0161: * @param driver JDBC driver for session.
0162: * @param alias Defines URL to database.
0163: * @param conn Connection to database.
0164: * @param user User name connected with.
0165: * @param password Password for <TT>user</TT>
0166: * @param sessionId ID that uniquely identifies this session.
0167: *
0168: * @throws IllegalArgumentException if any parameter is null.
0169: */
0170: public Session(IApplication app, ISQLDriver driver, SQLAlias alias,
0171: SQLConnection conn, String user, String password,
0172: IIdentifier sessionId) {
0173: super ();
0174: _schemaInfo = new SchemaInfo(app);
0175:
0176: if (app == null) {
0177: throw new IllegalArgumentException(
0178: "null IApplication passed");
0179: }
0180: if (driver == null) {
0181: throw new IllegalArgumentException("null ISQLDriver passed");
0182: }
0183: if (alias == null) {
0184: throw new IllegalArgumentException("null ISQLAlias passed");
0185: }
0186: if (conn == null) {
0187: throw new IllegalArgumentException(
0188: "null SQLConnection passed");
0189: }
0190: if (sessionId == null) {
0191: throw new IllegalArgumentException("sessionId == null");
0192: }
0193:
0194: _app = app;
0195: _driver = driver;
0196:
0197: _alias = new SQLAlias();
0198:
0199: try {
0200: _alias.assignFrom(alias, true);
0201: } catch (ValidationException e) {
0202: throw new RuntimeException(e);
0203: }
0204:
0205: _conn = conn;
0206: _user = user;
0207: _password = password;
0208: _id = sessionId;
0209:
0210: setupTitle();
0211:
0212: _props = (SessionProperties) _app.getSquirrelPreferences()
0213: .getSessionProperties().clone();
0214:
0215: _connLis = new SQLConnectionListener();
0216: _conn.addPropertyChangeListener(_connLis);
0217:
0218: checkDriverVersion();
0219:
0220: // Start loading table/column info about the current database.
0221: _app.getThreadPool().addTask(new Runnable() {
0222: public void run() {
0223: _schemaInfo.initialLoad(Session.this );
0224: _finishedLoading = true;
0225: }
0226: });
0227:
0228: }
0229:
0230: /**
0231: * Close this session.
0232: *
0233: * @throws SQLException
0234: * Thrown if an error closing the SQL connection. The session
0235: * will still be closed even though the connection may not have
0236: * been.
0237: */
0238: public void close() throws SQLException {
0239: if (!_closed) {
0240: s_log.debug("Closing session: " + _id);
0241:
0242: _conn.removePropertyChangeListener(_connLis);
0243: _connLis = null;
0244:
0245: ParserEventsProcessor[] procs = _parserEventsProcessorsByEntryPanelIdentifier
0246: .values().toArray(new ParserEventsProcessor[0]);
0247:
0248: for (int i = 0; i < procs.length; i++) {
0249: try {
0250: procs[i].endProcessing();
0251: } catch (Exception e) {
0252: s_log.info("Error stopping parser event processor",
0253: e);
0254: }
0255: }
0256:
0257: _schemaInfo.dispose();
0258:
0259: try {
0260: closeSQLConnection();
0261: } finally {
0262: // This is set here as SessionPanel.dispose() will attempt
0263: // to close the session.
0264: _closed = true;
0265:
0266: if (_sessionSheet != null) {
0267: _sessionSheet.sessionHasClosed();
0268: _sessionSheet = null;
0269: }
0270: }
0271: s_log.debug("Successfully closed session: " + _id);
0272: }
0273: }
0274:
0275: /**
0276: * Commit the current SQL transaction.
0277: */
0278: public synchronized void commit() {
0279: try {
0280: getSQLConnection().commit();
0281: final String msg = s_stringMgr.getString("Session.commit");
0282: _msgHandler.showMessage(msg);
0283: } catch (Throwable ex) {
0284: _msgHandler.showErrorMessage(ex, formatter);
0285: }
0286: }
0287:
0288: /**
0289: * Rollback the current SQL transaction.
0290: */
0291: public synchronized void rollback() {
0292: try {
0293: getSQLConnection().rollback();
0294: final String msg = s_stringMgr
0295: .getString("Session.rollback");
0296: _msgHandler.showMessage(msg);
0297: } catch (Exception ex) {
0298: _msgHandler.showErrorMessage(ex, formatter);
0299: }
0300: }
0301:
0302: /**
0303: * Return the unique identifier for this session.
0304: *
0305: * @return the unique identifier for this session.
0306: */
0307: public IIdentifier getIdentifier() {
0308: return _id;
0309: }
0310:
0311: /**
0312: * Retrieve whether this session has been closed.
0313: *
0314: * @return <TT>true</TT> if session closed else <TT>false</TT>.
0315: */
0316: public boolean isClosed() {
0317: return _closed;
0318: }
0319:
0320: /**
0321: * Return the Application API object.
0322: *
0323: * @return the Application API object.
0324: */
0325: public IApplication getApplication() {
0326: return _app;
0327: }
0328:
0329: /**
0330: * @return <TT>SQLConnection</TT> for this session.
0331: */
0332: public ISQLConnection getSQLConnection() {
0333: checkThread();
0334: return _conn;
0335: }
0336:
0337: /**
0338: * @return <TT>ISQLDriver</TT> for this session.
0339: */
0340: public ISQLDriver getDriver() {
0341: return _driver;
0342: }
0343:
0344: /**
0345: * @return <TT>ISQLAlias</TT> for this session.
0346: */
0347: public ISQLAliasExt getAlias() {
0348: return _alias;
0349: }
0350:
0351: public SessionProperties getProperties() {
0352: return _props;
0353: }
0354:
0355: /**
0356: * Retrieve the schema information object for this session.
0357: */
0358: public SchemaInfo getSchemaInfo() {
0359: return _schemaInfo;
0360: }
0361:
0362: public synchronized Object getPluginObject(IPlugin plugin,
0363: String key) {
0364: if (plugin == null) {
0365: throw new IllegalArgumentException("Null IPlugin passed");
0366: }
0367: if (key == null) {
0368: throw new IllegalArgumentException("Null key passed");
0369: }
0370: Map<String, Object> map = _pluginObjects.get(plugin
0371: .getInternalName());
0372: if (map == null) {
0373: map = new HashMap<String, Object>();
0374: _pluginObjects.put(plugin.getInternalName(), map);
0375: }
0376: return map.get(key);
0377: }
0378:
0379: /**
0380: * Add the passed action to the session toolbar.
0381: *
0382: * @param action Action to be added.
0383: */
0384: public void addToToolbar(Action action) {
0385: _sessionSheet.addToToolbar(action);
0386: }
0387:
0388: public void addSeparatorToToolbar() {
0389: _sessionSheet.addSeparatorToToolbar();
0390: }
0391:
0392: public synchronized Object putPluginObject(IPlugin plugin,
0393: String key, Object value) {
0394: if (plugin == null) {
0395: throw new IllegalArgumentException("Null IPlugin passed");
0396: }
0397: if (key == null) {
0398: throw new IllegalArgumentException("Null key passed");
0399: }
0400: Map<String, Object> map = _pluginObjects.get(plugin
0401: .getInternalName());
0402: if (map == null) {
0403: map = new HashMap<String, Object>();
0404: _pluginObjects.put(plugin.getInternalName(), map);
0405: }
0406: return map.put(key, value);
0407: }
0408:
0409: public synchronized void removePluginObject(IPlugin plugin,
0410: String key) {
0411: if (plugin == null) {
0412: throw new IllegalArgumentException("Null IPlugin passed");
0413: }
0414: if (key == null) {
0415: throw new IllegalArgumentException("Null key passed");
0416: }
0417: Map<String, Object> map = _pluginObjects.get(plugin
0418: .getInternalName());
0419: if (map != null) {
0420: map.remove(key);
0421: }
0422: }
0423:
0424: public synchronized void closeSQLConnection() throws SQLException {
0425: if (_conn != null) {
0426: try {
0427: _conn.close();
0428: } finally {
0429: _conn = null;
0430: }
0431: }
0432: }
0433:
0434: /**
0435: * Reconnect to the database.
0436: */
0437: public void reconnect() {
0438: SQLConnectionState connState = new SQLConnectionState();
0439: if (_conn != null) {
0440: try {
0441: connState
0442: .saveState(_conn, getProperties(), _msgHandler);
0443: } catch (SQLException ex) {
0444: s_log.error("Unexpected SQLException", ex);
0445: }
0446: }
0447: OpenConnectionCommand cmd = new OpenConnectionCommand(_app,
0448: _alias, _user, _password, connState
0449: .getConnectionProperties());
0450: try {
0451: closeSQLConnection();
0452: _app.getSessionManager().fireConnectionClosedForReconnect(
0453: this );
0454: } catch (SQLException ex) {
0455: final String msg = s_stringMgr
0456: .getString("Session.error.connclose");
0457: s_log.error(msg, ex);
0458: _msgHandler.showErrorMessage(msg);
0459: _msgHandler.showErrorMessage(ex, this
0460: .getExceptionFormatter());
0461: }
0462: try {
0463: cmd.execute();
0464: _conn = cmd.getSQLConnection();
0465: if (connState != null) {
0466: connState.restoreState(_conn, _msgHandler);
0467: getProperties()
0468: .setAutoCommit(connState.getAutoCommit());
0469: }
0470: final String msg = s_stringMgr.getString("Session.reconn",
0471: _alias.getName());
0472: _msgHandler.showMessage(msg);
0473: _app.getSessionManager().fireReconnected(this );
0474: } catch (Throwable t) {
0475: final String msg = s_stringMgr.getString(
0476: "Session.reconnError", _alias.getName());
0477: _msgHandler.showErrorMessage(msg + "\n" + t.toString());
0478: s_log.error(msg, t);
0479: _app.getSessionManager().fireReconnectFailed(this );
0480: }
0481: }
0482:
0483: public void setMessageHandler(IMessageHandler handler) {
0484: _msgHandler = handler != null ? handler : NullMessageHandler
0485: .getInstance();
0486: }
0487:
0488: public synchronized void setSessionSheet(SessionPanel child) {
0489: _sessionSheet = child;
0490: if (_sessionSheet != null) {
0491: final ListIterator<JComponent> it = _statusBarToBeAdded
0492: .listIterator();
0493: while (it.hasNext()) {
0494: addToStatusBar(it.next());
0495: it.remove();
0496: }
0497: }
0498: }
0499:
0500: public synchronized void setSessionInternalFrame(
0501: SessionInternalFrame sif) {
0502: _sessionInternalFrame = sif;
0503:
0504: // This is a reasonable default and makes initialization code run well
0505: _activeActiveSessionWindow = sif;
0506:
0507: _sessionSheet = sif.getSessionPanel();
0508: final ListIterator<JComponent> it = _statusBarToBeAdded
0509: .listIterator();
0510: while (it.hasNext()) {
0511: addToStatusBar(it.next());
0512: it.remove();
0513: }
0514: }
0515:
0516: public synchronized SessionInternalFrame getSessionInternalFrame() {
0517: return _sessionInternalFrame;
0518: }
0519:
0520: public synchronized SessionPanel getSessionSheet() {
0521: return _sessionSheet;
0522: }
0523:
0524: /**
0525: * Select a tab in the main tabbed pane.
0526: *
0527: * @param tabIndex The tab to select. @see ISession.IMainTabIndexes
0528: *
0529: * @throws IllegalArgumentException
0530: * Thrown if an invalid <TT>tabId</TT> passed.
0531: */
0532: public void selectMainTab(int tabIndex) {
0533: _sessionSheet.selectMainTab(tabIndex);
0534: }
0535:
0536: /**
0537: * Add a tab to the main tabbed panel.
0538: *
0539: * @param tab The tab to be added.
0540: *
0541: * @return the index of the new tab that was added.
0542: *
0543: * @throws IllegalArgumentException
0544: * Thrown if a <TT>null</TT> <TT>IMainPanelTab</TT> passed.
0545: */
0546: public int addMainTab(IMainPanelTab tab) {
0547: return _sessionSheet.addMainTab(tab);
0548: }
0549:
0550: /**
0551: * Add component to the session sheets status bar.
0552: *
0553: * @param comp Component to add.
0554: */
0555: public synchronized void addToStatusBar(JComponent comp) {
0556: if (_sessionSheet != null) {
0557: _sessionSheet.addToStatusBar(comp);
0558: } else {
0559: _statusBarToBeAdded.add(comp);
0560: }
0561: }
0562:
0563: /**
0564: * Remove component from the session sheets status bar.
0565: *
0566: * @param comp Component to remove.
0567: */
0568: public synchronized void removeFromStatusBar(JComponent comp) {
0569: if (_sessionSheet != null) {
0570: _sessionSheet.removeFromStatusBar(comp);
0571: } else {
0572: _statusBarToBeAdded.remove(comp);
0573: }
0574: }
0575:
0576: // public SQLFilterClauses getSQLFilterClauses()
0577: // {
0578: // return _sqlFilterClauses;
0579: // }
0580:
0581: /**
0582: * Retrieve the descriptive title of this session.
0583: *
0584: * @return The descriptive title of this session.
0585: */
0586: public String getTitle() {
0587: return _title;
0588: }
0589:
0590: public String toString() {
0591: return getTitle();
0592: }
0593:
0594: private void setupTitle() {
0595: String catalog = null;
0596: try {
0597: catalog = getSQLConnection().getCatalog();
0598: } catch (SQLException ex) {
0599: s_log
0600: .error(
0601: "Error occured retrieving current catalog from Connection",
0602: ex);
0603: }
0604: if (catalog == null) {
0605: catalog = "";
0606: } else {
0607: catalog = "(" + catalog + ")";
0608: }
0609:
0610: String title = null;
0611: String user = _user != null ? _user : "";
0612: if (user.length() > 0) {
0613: String[] args = new String[3];
0614: args[0] = getAlias().getName();
0615: args[1] = catalog;
0616: args[2] = user;
0617: title = s_stringMgr.getString("Session.title1", args);
0618: } else {
0619: String[] args = new String[2];
0620: args[0] = getAlias().getName();
0621: args[1] = catalog;
0622: title = s_stringMgr.getString("Session.title0", args);
0623: }
0624:
0625: _title = _id + " - " + title;
0626: }
0627:
0628: /**
0629: * The code in any SQLEditor is parsed in the background. You may attach a listener to the ParserEventsProcessor
0630: * to get to know about the results of parsing. The events are passed synchron with the event queue
0631: * (via SwingUtils.invokeLater()). At the moment events are produced for errors in the SQLScript
0632: * which are highlighted in the syntax plugin and for aliases of table names which are used in the
0633: * code completion plugin.
0634: * <p>
0635: * If you want the ParserEventsProcessor to produce further events feel free to contact gerdwagner@users.sourceforge.net.
0636: */
0637: public IParserEventsProcessor getParserEventsProcessor(
0638: IIdentifier entryPanelIdentifier) {
0639: ParserEventsProcessor pep = _parserEventsProcessorsByEntryPanelIdentifier
0640: .get(entryPanelIdentifier);
0641:
0642: if (null == pep) {
0643: pep = new ParserEventsProcessor(
0644: getSqlPanelApi(entryPanelIdentifier), this );
0645: _parserEventsProcessorsByEntryPanelIdentifier.put(
0646: entryPanelIdentifier, pep);
0647: }
0648: return pep;
0649: }
0650:
0651: private ISQLPanelAPI getSqlPanelApi(IIdentifier entryPanelIdentifier) {
0652: BaseSessionInternalFrame[] frames = getApplication()
0653: .getWindowManager().getAllFramesOfSession(
0654: getIdentifier());
0655:
0656: for (int i = 0; i < frames.length; i++) {
0657: if (frames[i] instanceof SQLInternalFrame) {
0658: ISQLPanelAPI sqlPanelAPI = ((SQLInternalFrame) frames[i])
0659: .getSQLPanelAPI();
0660: IIdentifier id = sqlPanelAPI.getSQLEntryPanel()
0661: .getIdentifier();
0662:
0663: if (id.equals(entryPanelIdentifier)) {
0664: return sqlPanelAPI;
0665: }
0666: }
0667:
0668: if (frames[i] instanceof SessionInternalFrame) {
0669: ISQLPanelAPI sqlPanelAPI = ((SessionInternalFrame) frames[i])
0670: .getSQLPanelAPI();
0671: IIdentifier id = sqlPanelAPI.getSQLEntryPanel()
0672: .getIdentifier();
0673:
0674: if (id.equals(entryPanelIdentifier)) {
0675: return sqlPanelAPI;
0676: }
0677: }
0678: }
0679:
0680: throw new IllegalStateException(
0681: "Session has no entry panel for ID="
0682: + entryPanelIdentifier);
0683: }
0684:
0685: public void setActiveSessionWindow(
0686: BaseSessionInternalFrame activeActiveSessionWindow) {
0687: _activeActiveSessionWindow = activeActiveSessionWindow;
0688: }
0689:
0690: public BaseSessionInternalFrame getActiveSessionWindow() {
0691: return _activeActiveSessionWindow;
0692: }
0693:
0694: /**
0695: *
0696: * @throws IllegalStateException if ActiveSessionWindow doesn't provide an SQLPanelAPI
0697: * for example if it is an ObjectTreeInternalFrame
0698: */
0699: public ISQLPanelAPI getSQLPanelAPIOfActiveSessionWindow() {
0700: ISQLPanelAPI sqlPanelAPI;
0701: if (_activeActiveSessionWindow instanceof SessionInternalFrame) {
0702: sqlPanelAPI = ((SessionInternalFrame) _activeActiveSessionWindow)
0703: .getSQLPanelAPI();
0704: } else if (_activeActiveSessionWindow instanceof SQLInternalFrame) {
0705: sqlPanelAPI = ((SQLInternalFrame) _activeActiveSessionWindow)
0706: .getSQLPanelAPI();
0707: } else {
0708: throw new IllegalStateException(
0709: "SQLPanelApi can only be provided for SessionInternalFrame or SQLInternalFrame");
0710: }
0711:
0712: return sqlPanelAPI;
0713: }
0714:
0715: /**
0716: *
0717: * @throws IllegalStateException if ActiveSessionWindow doesn't provide an IObjectTreeAPI
0718: * for example if it is an SQLInternalFrame
0719: */
0720: public IObjectTreeAPI getObjectTreeAPIOfActiveSessionWindow() {
0721: IObjectTreeAPI objectTreeAPI;
0722: if (_activeActiveSessionWindow instanceof SessionInternalFrame) {
0723: objectTreeAPI = ((SessionInternalFrame) _activeActiveSessionWindow)
0724: .getObjectTreeAPI();
0725: } else if (_activeActiveSessionWindow instanceof ObjectTreeInternalFrame) {
0726: objectTreeAPI = ((ObjectTreeInternalFrame) _activeActiveSessionWindow)
0727: .getObjectTreeAPI();
0728: } else {
0729: throw new IllegalStateException(
0730: "ObjectTreeApi can only be provided for SessionInternalFrame or ObjectTreeInternalFrame");
0731: }
0732:
0733: return objectTreeAPI;
0734: }
0735:
0736: /**
0737: * The point of this method is to try to determine if the driver being used
0738: * for this session supports the API methods we are likely to use with this
0739: * version of the Java runtime environment. It's not a showstopper to use
0740: * an older driver, but we noticed that in some cases, older versions of
0741: * drivers connecting to newer databases causes various unpredictable error
0742: * conditions that are hard to troubleshoot, given that we don't have the
0743: * source to the driver. Be that as it may, the user will inevitably claim
0744: * that their xyz java app works fine with their antiquated driver,
0745: * whereas SQuirreL does not - therefore it's a SQuirreL bug. So this will
0746: * warn the user when this condition exists and hopefully persuade them to
0747: * correct the problem.
0748: */
0749: private void checkDriverVersion() {
0750: if (!_app.getSquirrelPreferences().getWarnJreJdbcMismatch()) {
0751: return;
0752: }
0753: String javaVersion = System.getProperty("java.vm.version");
0754: boolean javaVersionIsAtLeast14 = true;
0755: if (javaVersion != null) {
0756: if (javaVersion.startsWith("1.1")
0757: || javaVersion.startsWith("1.2")
0758: || javaVersion.startsWith("1.3")) {
0759: javaVersionIsAtLeast14 = false;
0760: }
0761: }
0762: if (!javaVersionIsAtLeast14) {
0763: return;
0764: }
0765: // At this point we know that we have a 1.4 or higher java runtime
0766: boolean driverIs21Compliant = true;
0767:
0768: // Since 1.4 implements interfaces that became available in JDBC 3.0,
0769: // let's warn the user if the driver doesn't support DatabaseMetaData
0770: // methods that were added in JDBC 2.1 and JDBC 3.0 specifications.
0771:
0772: SQLDatabaseMetaData md = _conn.getSQLMetaData();
0773: try {
0774: md.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY);
0775: } catch (Throwable e) {
0776: driverIs21Compliant = false;
0777: }
0778:
0779: if (!driverIs21Compliant) {
0780: // i18n[Session.driverCompliance=The driver being used for alias ''{0}'' is not JDBC 2.1 compliant.\nYou should consider getting a more recent version of this driver]
0781: String msg = s_stringMgr.getString(
0782: "Session.driverCompliance", _alias.getName());
0783: // i18n[Session.driverComplianceTitle=JRE/JDBC Version Mismatch]
0784: String title = s_stringMgr
0785: .getString("Session.driverComplianceTitle");
0786: showMessageDialog(msg, title, JOptionPane.WARNING_MESSAGE);
0787: s_log.info(msg);
0788: return;
0789: }
0790: boolean driverIs30Compliant = true;
0791: try {
0792: md.supportsSavepoints();
0793: } catch (Throwable e) {
0794: driverIs30Compliant = false;
0795: }
0796:
0797: if (!driverIs30Compliant) {
0798: // i18n[Session.driverCompliance3.0=The driver being used for alias ''{0}'' is not JDBC 3.0 compliant.\nYou should consider getting a more recent version of this driver]
0799: String msg = s_stringMgr.getString(
0800: "Session.driverCompliance3.0", _alias.getName());
0801: // i18n[Session.driverComplianceTitle=JRE/JDBC Version Mismatch]
0802: String title = s_stringMgr
0803: .getString("Session.driverComplianceTitle");
0804: showMessageDialog(msg, title, JOptionPane.WARNING_MESSAGE);
0805: s_log.info(msg);
0806: }
0807: }
0808:
0809: private void showMessageDialog(final String message,
0810: final String title, final int messageType) {
0811: final JFrame f = _app.getMainFrame();
0812: SwingUtilities.invokeLater(new Runnable() {
0813: public void run() {
0814: JOptionPane.showMessageDialog(f, message, title,
0815: messageType);
0816: }
0817: });
0818: }
0819:
0820: /**
0821: * Check the thread of the caller to see if it is the event dispatch thread
0822: * and if we are debugging print a debug log message with the call trace.
0823: */
0824: private void checkThread() {
0825: /* This is extremely useful when trying to track down Swing UI freezing.
0826: * However, it currently fills the log which obscures other debug
0827: * messages even though UI performance is acceptable, so it is commented
0828: * out until it is needed later.
0829: if (s_log.isDebugEnabled() && SwingUtilities.isEventDispatchThread()) {
0830: try {
0831: throw new Exception("GUI Thread is doing database work");
0832: } catch (Exception e) {
0833: s_log.debug(e.getMessage(), e);
0834: }
0835: }
0836: */
0837: }
0838:
0839: private class SQLConnectionListener implements
0840: PropertyChangeListener {
0841: public void propertyChange(PropertyChangeEvent evt) {
0842: final String propName = evt.getPropertyName();
0843: if (propName == null
0844: || propName == ISQLConnection.IPropertyNames.CATALOG) {
0845: setupTitle();
0846: }
0847: }
0848: }
0849:
0850: protected void finalize() throws Throwable {
0851: // System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
0852: // System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
0853: // System.out.println("+ Finalize " + getClass() + ". Hash code:" + hashCode());
0854: // System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
0855: // System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
0856: _app.getSessionManager().fireSessionFinalized(_id);
0857:
0858: }
0859:
0860: /**
0861: * @param _finishedLoading The _finishedLoading to set.
0862: */
0863: public void setPluginsfinishedLoading(boolean pluginsFinishedLoading) {
0864: this ._pluginsFinishedLoading = pluginsFinishedLoading;
0865: }
0866:
0867: /**
0868: * @return Returns the _finishedLoading.
0869: */
0870: public boolean isfinishedLoading() {
0871: return _finishedLoading && _pluginsFinishedLoading;
0872: }
0873:
0874: /* (non-Javadoc)
0875: * @see net.sourceforge.squirrel_sql.client.session.ISession#confirmCloseWithUnsavedEdits()
0876: */
0877: public boolean confirmClose() {
0878: if (getActiveSessionWindow() instanceof SQLInternalFrame
0879: || getActiveSessionWindow() instanceof SessionInternalFrame) {
0880: if (getSQLPanelAPIOfActiveSessionWindow().confirmClose()) {
0881: return true;
0882: } else {
0883: return false;
0884: }
0885: }
0886:
0887: return true;
0888:
0889: }
0890:
0891: /**
0892: * Returns the IQueryTokenizer implementation to use for tokenizing scripts
0893: * statements that should be sent to the server. If the tokenizer hasn't
0894: * been initialized yet, then a default one will be created. If a cutom
0895: * tokenizer has been installed, this will just return that one, in lieu of
0896: * the default one.
0897: *
0898: * @return an implementation of IQueryTokenizer
0899: */
0900: public IQueryTokenizer getQueryTokenizer() {
0901: if (tokenizer == null || !customTokenizerInstalled) {
0902: // No tokenizer has been set by any installed plugin. Go ahead and
0903: // give the default tokenizer. It is important to not cache this
0904: // object so that session property changes to the current session
0905: // are reflected in this default tokenizer.
0906: tokenizer = new QueryTokenizer(_props
0907: .getSQLStatementSeparator(), _props
0908: .getStartOfLineComment(), _props
0909: .getRemoveMultiLineComment());
0910: }
0911: return tokenizer;
0912: }
0913:
0914: /**
0915: * Sets the IQueryTokenizer implementation to use for this session.
0916: *
0917: * @param tokenizer
0918: *
0919: * @throws IllegalArgumentException for null argument
0920: * @throws IllegalStateException if a custom tokenizer is already installed.
0921: */
0922: public void setQueryTokenizer(IQueryTokenizer aTokenizer) {
0923: if (aTokenizer == null) {
0924: throw new IllegalArgumentException(
0925: "aTokenizer arg cannot be null");
0926: }
0927: if (customTokenizerInstalled) {
0928: String currentTokenizer = tokenizer.getClass().getName();
0929: String newTokenizer = tokenizer.getClass().getName();
0930: throw new IllegalStateException(
0931: "Only one custom query tokenizer can be installed. "
0932: + "Current tokenizer is "
0933: + currentTokenizer + ". New tokenizer is "
0934: + newTokenizer);
0935: }
0936: customTokenizerInstalled = true;
0937: tokenizer = aTokenizer;
0938: }
0939:
0940: /**
0941: * @see net.sourceforge.squirrel_sql.client.session.ISession#getMetaData()
0942: */
0943: public ISQLDatabaseMetaData getMetaData() {
0944: if (_conn != null) {
0945: return _conn.getSQLMetaData();
0946: } else {
0947: return null;
0948: }
0949: }
0950:
0951: /**
0952: * @see net.sourceforge.squirrel_sql.client.session.ISession#setExceptionFormatter(net.sourceforge.squirrel_sql.fw.util.ExceptionFormatter)
0953: */
0954: public void setExceptionFormatter(ExceptionFormatter formatter) {
0955: this .formatter.setCustomExceptionFormatter(formatter);
0956: }
0957:
0958: /**
0959: * @see net.sourceforge.squirrel_sql.client.session.ISession#getExceptionFormatter()
0960: */
0961: public ExceptionFormatter getExceptionFormatter() {
0962: return this .formatter;
0963: }
0964:
0965: /**
0966: * @see net.sourceforge.squirrel_sql.client.session.ISession#formatException(java.lang.Throwable)
0967: */
0968: public String formatException(Throwable th) {
0969: return this .formatter.format(th);
0970: }
0971:
0972: /**
0973: * @see net.sourceforge.squirrel_sql.client.session.ISession#showErrorMessage(java.lang.String)
0974: */
0975: public void showErrorMessage(String msg) {
0976: _msgHandler.showErrorMessage(msg);
0977: }
0978:
0979: /**
0980: * @see net.sourceforge.squirrel_sql.client.session.ISession#showErrorMessage(java.lang.Throwable, net.sourceforge.squirrel_sql.fw.util.ExceptionFormatter)
0981: */
0982: public void showErrorMessage(Throwable th) {
0983: _msgHandler.showErrorMessage(th, formatter);
0984: }
0985:
0986: /**
0987: * @see net.sourceforge.squirrel_sql.client.session.ISession#showMessage(java.lang.String)
0988: */
0989: public void showMessage(String msg) {
0990: _msgHandler.showMessage(msg);
0991: }
0992:
0993: /**
0994: * @see net.sourceforge.squirrel_sql.client.session.ISession#showMessage(java.lang.Throwable, net.sourceforge.squirrel_sql.fw.util.ExceptionFormatter)
0995: */
0996: public void showMessage(Throwable th) {
0997: _msgHandler.showMessage(th, formatter);
0998: }
0999:
1000: /**
1001: * @see net.sourceforge.squirrel_sql.client.session.ISession#showWarningMessage(java.lang.String)
1002: */
1003: public void showWarningMessage(String msg) {
1004: _msgHandler.showWarningMessage(msg);
1005: }
1006:
1007: }
|