001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.db.explorer.actions;
043:
044: import java.awt.Dialog;
045: import java.awt.Dimension;
046: import java.awt.event.ActionEvent;
047: import java.awt.event.ActionListener;
048: import java.beans.PropertyChangeEvent;
049: import java.beans.PropertyChangeListener;
050: import java.sql.ResultSet;
051: import java.sql.SQLException;
052: import java.sql.Connection;
053: import java.text.MessageFormat;
054: import java.util.Vector;
055: import java.util.logging.Level;
056: import java.util.logging.Logger;
057: import javax.swing.JComponent;
058:
059: import javax.swing.JTabbedPane;
060: import javax.swing.event.ChangeEvent;
061: import javax.swing.event.ChangeListener;
062: import org.netbeans.api.progress.ProgressHandle;
063: import org.netbeans.api.progress.ProgressHandleFactory;
064: import org.netbeans.modules.db.explorer.ConnectionList;
065: import org.netbeans.modules.db.explorer.DbUtilities;
066:
067: import org.openide.DialogDescriptor;
068: import org.openide.DialogDisplayer;
069: import org.openide.NotifyDescriptor;
070: import org.openide.nodes.Node;
071: import org.openide.util.HelpCtx;
072:
073: import org.netbeans.api.db.explorer.DatabaseException;
074: import org.netbeans.lib.ddl.DDLException;
075: import org.netbeans.modules.db.ExceptionListener;
076: import org.netbeans.modules.db.explorer.DatabaseConnection;
077:
078: //commented out for 3.6 release, need to solve for next Studio release
079: //import org.netbeans.modules.db.explorer.PointbasePlus;
080:
081: import org.netbeans.modules.db.explorer.dlg.ConnectionDialog;
082: import org.netbeans.modules.db.explorer.dlg.ConnectPanel;
083: import org.netbeans.modules.db.explorer.dlg.ConnectProgressDialog;
084: import org.netbeans.modules.db.explorer.dlg.ConnectionDialogMediator;
085: import org.netbeans.modules.db.explorer.dlg.SchemaPanel;
086: import org.netbeans.modules.db.explorer.infos.ConnectionNodeInfo;
087: import org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo;
088: import org.netbeans.modules.db.explorer.nodes.DatabaseNode;
089:
090: public class ConnectAction extends DatabaseAction {
091: static final long serialVersionUID = -6822218300035053411L;
092:
093: ConnectionDialog dlg;
094: boolean advancedPanel = false;
095: boolean okPressed = false;
096:
097: protected boolean enable(Node[] activatedNodes) {
098: Node node;
099: if (activatedNodes != null && activatedNodes.length == 1)
100: node = activatedNodes[0];
101: else
102: return false;
103:
104: DatabaseNodeInfo info = (DatabaseNodeInfo) node
105: .getCookie(DatabaseNodeInfo.class);
106: if (info != null) {
107: DatabaseNodeInfo nfo = info
108: .getParent(DatabaseNode.CONNECTION);
109: if (nfo != null)
110: return (nfo.getConnection() == null);
111: }
112:
113: return false;
114: }
115:
116: protected int mode() {
117: return MODE_ALL;
118: }
119:
120: public void performAction(Node[] activatedNodes) {
121: Node node = activatedNodes[0];
122: DatabaseNodeInfo info = (DatabaseNodeInfo) node
123: .getCookie(DatabaseNodeInfo.class);
124: ConnectionNodeInfo nfo = (ConnectionNodeInfo) info
125: .getParent(DatabaseNode.CONNECTION);
126:
127: // Don't show the dialog if all information is already available,
128: // just make the connection
129: new ConnectionDialogDisplayer().showDialog(nfo, false);
130: }
131:
132: public static final class ConnectionDialogDisplayer extends
133: ConnectionDialogMediator {
134:
135: ConnectionDialog dlg;
136: boolean advancedPanel = false;
137: boolean okPressed = false;
138:
139: // This flag is used to detect whether there was a failure to connect
140: // when using the progress bar. The flag is set in the property
141: // change listener when the status changes to "failed".
142: boolean failed = false;
143:
144: public void showDialog(final ConnectionNodeInfo nfo,
145: boolean showDialog) {
146: String user = nfo.getUser();
147: String pwd = nfo.getPassword();
148: Boolean rpwd = (Boolean) nfo
149: .get(DatabaseNodeInfo.REMEMBER_PWD);
150: boolean remember = ((rpwd != null) ? rpwd.booleanValue()
151: : false);
152:
153: final DatabaseConnection dbcon = nfo
154: .getDatabaseConnection();
155:
156: final ExceptionListener excListener = new ExceptionListener() {
157: public void exceptionOccurred(Exception exc) {
158: if (exc instanceof DDLException) {
159: Logger.getLogger("global").log(Level.INFO,
160: null, exc.getCause());
161: } else {
162: Logger.getLogger("global").log(Level.INFO,
163: null, exc);
164: }
165:
166: String message = null;
167: if (exc instanceof ClassNotFoundException) {
168: message = MessageFormat.format(bundle()
169: .getString("EXC_ClassNotFound"),
170: new String[] { exc.getMessage() }); //NOI18N
171: } else {
172: StringBuffer buffer = new StringBuffer();
173: buffer.append(DbUtilities.formatError(bundle()
174: .getString("ERR_UnableToConnect"), exc
175: .getMessage())); //NOI18N
176: if (exc instanceof DDLException
177: && exc.getCause() instanceof SQLException) {
178: SQLException sqlEx = ((SQLException) exc
179: .getCause()).getNextException();
180: while (sqlEx != null) {
181: buffer.append("\n\n"
182: + sqlEx.getMessage()); // NOI18N
183: sqlEx = sqlEx.getNextException();
184: }
185: }
186: message = buffer.toString();
187: }
188: DialogDisplayer.getDefault().notify(
189: new NotifyDescriptor.Message(message,
190: NotifyDescriptor.ERROR_MESSAGE));
191: }
192: };
193:
194: dbcon.addExceptionListener(excListener);
195:
196: // If showDialog is true, show the dialog even if we have all
197: // the connection info
198: //
199: // Note that we don't have to show the dialog if the password is
200: // null and remember is true; null is often a valid password
201: // (and is the default password for MySQL and PostgreSQL).
202: if (user == null || !remember || showDialog) {
203: final ConnectPanel basePanel = new ConnectPanel(this ,
204: dbcon);
205: final SchemaPanel schemaPanel = new SchemaPanel(this ,
206: dbcon);
207:
208: PropertyChangeListener argumentListener = new PropertyChangeListener() {
209: public void propertyChange(PropertyChangeEvent event) {
210: if (event.getPropertyName().equals(
211: "argumentChanged")) { //NOI18N
212: schemaPanel.setSchemas(new Vector(), ""); //NOI18N
213: schemaPanel.resetProgress();
214: try {
215: Connection conn = dbcon.getConnection();
216: if (conn != null && !conn.isClosed())
217: conn.close();
218: } catch (SQLException exc) {
219: //unable to close the connection
220: }
221: }
222: }
223: };
224: basePanel.addPropertyChangeListener(argumentListener);
225:
226: final PropertyChangeListener connectionListener = new PropertyChangeListener() {
227: public void propertyChange(PropertyChangeEvent event) {
228: if (event.getPropertyName()
229: .equals("connecting")) { // NOI18N
230: fireConnectionStarted();
231: }
232: if (event.getPropertyName().equals("failed")) { // NOI18N
233: fireConnectionFailed();
234: }
235: if (event.getPropertyName().equals("connected")) { //NOI18N
236: //connected by "Get Schemas" button in the schema panel => don't initialize the connection node,
237: //it will be done in actionListener
238: if (advancedPanel && !okPressed) {
239: // #67241: should not retrieve the schema list after connecting
240: // an existing connection, takes a long time on databases with a lot of schemas
241: // thus only retrieve the schema list when connected by the "Get schemas" button
242: if (retrieveSchemas(schemaPanel, dbcon,
243: nfo.getSchema())) {
244: dbcon.setSchema(nfo.getSchema());
245: }
246: dlg.setSelectedComponent(schemaPanel);
247: fireConnectionFinished();
248: return;
249: } else {
250: fireConnectionFinished();
251: dbcon.setSchema(nfo.getSchema());
252: }
253:
254: try {
255: nfo.finishConnect(null, dbcon, dbcon
256: .getConnection());
257: } catch (DatabaseException exc) {
258: Logger.getLogger("global").log(
259: Level.INFO, null, exc);
260: DbUtilities
261: .reportError(
262: bundle()
263: .getString(
264: "ERR_UnableToInitializeConnection"),
265: exc.getMessage()); // NOI18N
266: return;
267: }
268:
269: DatabaseConnection realDbcon = ConnectionList
270: .getDefault().getConnection(dbcon);
271: if (realDbcon != null) {
272: realDbcon.setPassword(dbcon
273: .getPassword());
274: realDbcon.setRememberPassword(dbcon
275: .rememberPassword());
276: }
277:
278: nfo.put(DatabaseNodeInfo.REMEMBER_PWD,
279: Boolean.valueOf(basePanel
280: .rememberPassword()));
281: if (basePanel.rememberPassword()) {
282: nfo.put(DatabaseNodeInfo.REMEMBER_PWD,
283: Boolean.TRUE);
284: }
285: if (dlg != null) {
286: dlg.close();
287: // removeListeners(cinfo);
288: }
289: } else
290: okPressed = false;
291: }
292: };
293:
294: dbcon.addPropertyChangeListener(connectionListener);
295:
296: ActionListener actionListener = new ActionListener() {
297: public void actionPerformed(ActionEvent event) {
298: if (event.getSource() == DialogDescriptor.OK_OPTION) {
299: okPressed = true;
300: nfo.setUser(basePanel.getUser());
301: nfo.setPassword(basePanel.getPassword());
302: dbcon.setUser(basePanel.getUser());
303: dbcon.setPassword(basePanel.getPassword());
304: dbcon.setRememberPassword(basePanel
305: .rememberPassword());
306:
307: try {
308: if (dbcon.getConnection() == null
309: || dbcon.getConnection()
310: .isClosed())
311: dbcon.connect();
312: else {
313: dbcon.setSchema(schemaPanel
314: .getSchema());
315: nfo.setSchema(schemaPanel
316: .getSchema());
317:
318: try {
319: nfo.finishConnect(null, dbcon,
320: dbcon.getConnection());
321: } catch (DatabaseException exc) {
322: Logger.getLogger("global").log(
323: Level.INFO, null, exc);
324: DbUtilities
325: .reportError(
326: bundle()
327: .getString(
328: "ERR_UnableToInitializeConnection"),
329: exc
330: .getMessage()); // NOI18N
331: return;
332: }
333:
334: DatabaseConnection realDbcon = ConnectionList
335: .getDefault()
336: .getConnection(dbcon);
337: if (realDbcon != null) {
338: realDbcon.setPassword(dbcon
339: .getPassword());
340: realDbcon
341: .setRememberPassword(basePanel
342: .rememberPassword());
343: }
344: nfo
345: .put(
346: DatabaseNodeInfo.REMEMBER_PWD,
347: Boolean
348: .valueOf(basePanel
349: .rememberPassword()));
350: if (dlg != null)
351: dlg.close();
352: }
353: } catch (SQLException exc) {
354: //isClosed() method failed, try to connect
355: dbcon.connect();
356: }
357: return;
358: }
359: }
360: };
361:
362: ChangeListener changeTabListener = new ChangeListener() {
363: public void stateChanged(ChangeEvent e) {
364: if (((JTabbedPane) e.getSource())
365: .getSelectedComponent().equals(
366: schemaPanel)) {
367: advancedPanel = true;
368: nfo.setUser(basePanel.getUser());
369: nfo.setPassword(basePanel.getPassword());
370: dbcon.setPassword(basePanel.getPassword());
371: } else
372: advancedPanel = false;
373: }
374: };
375:
376: dlg = new ConnectionDialog(this , basePanel,
377: schemaPanel, basePanel.getTitle(), new HelpCtx(
378: "db_save_password"), actionListener,
379: changeTabListener); // NOI18N
380: dlg.setVisible(true);
381: } else
382: // without dialog with connection data (username, password), just with progress dlg
383: try {
384: DialogDescriptor descriptor = null;
385: ProgressHandle progress = null;
386:
387: progress = ProgressHandleFactory
388: .createHandle("handle");
389: JComponent progressComponent = ProgressHandleFactory
390: .createProgressComponent(progress);
391: progressComponent.setPreferredSize(new Dimension(
392: 350, 20));
393: ConnectProgressDialog panel = new ConnectProgressDialog(
394: progressComponent);
395: descriptor = new DialogDescriptor(
396: panel,
397: bundle().getString("ConnectingDialogTitle"),
398: true,
399: new Object[] { DialogDescriptor.CANCEL_OPTION },
400: DialogDescriptor.CANCEL_OPTION,
401: DialogDescriptor.DEFAULT_ALIGN, null, null);
402: final Dialog dialog = DialogDisplayer.getDefault()
403: .createDialog(descriptor);
404:
405: final PropertyChangeListener connectionListener = new PropertyChangeListener() {
406: public void propertyChange(
407: PropertyChangeEvent event) {
408: if (event.getPropertyName().equals(
409: "connected")) { //NOI18N
410: try {
411: nfo.finishConnect(null, dbcon,
412: dbcon.getConnection());
413: if (dialog != null) {
414: dialog.setVisible(false);
415: }
416: } catch (DatabaseException exc) {
417: Logger.getLogger("global").log(
418: Level.INFO, null, exc);
419: DbUtilities
420: .reportError(
421: bundle()
422: .getString(
423: "ERR_UnableToInitializeConnection"),
424: exc.getMessage()); // NOI18N
425: return;
426: }
427: } else if (event.getPropertyName().equals(
428: "failed")) { // NOI18N
429: if (dialog != null) {
430: dialog.setVisible(false);
431: }
432:
433: // We want to bring up the Connect dialog if the
434: // attempt to connect using the progress bar fails.
435: // But we can't do it here because we can't control
436: // what processing the DatabaseConnection does
437: // after posting this failure notification. So
438: // we set a flag and wait for the connect process
439: // to fully complete, and *then* raise the Connect
440: // dialog.
441: failed = true;
442: }
443: }
444: };
445:
446: failed = false;
447:
448: dbcon.addPropertyChangeListener(connectionListener);
449: dbcon.connect();
450:
451: progress.start();
452: progress.switchToIndeterminate();
453: dialog.setVisible(true);
454: progress.finish();
455: dialog.dispose();
456:
457: if (failed) {
458: // If the connection fails with a progress bar only, then
459: // display the full Connect dialog so the user can give it
460: // another shot after changing some values, like the username
461: // or password.
462: showDialog(nfo, true);
463: }
464: } catch (Exception exc) {
465: String message = MessageFormat.format(bundle()
466: .getString("ERR_UnableToConnect"),
467: new String[] { exc.getMessage() }); // NOI18N
468: DialogDisplayer.getDefault().notify(
469: new NotifyDescriptor.Message(message,
470: NotifyDescriptor.ERROR_MESSAGE));
471:
472: // If the connection fails with a progress bar only, then
473: // display the full Connect dialog so the user can give it
474: // another shot after changing some values, like the username
475: // or password.
476: showDialog(nfo, true);
477: }
478: }
479:
480: protected boolean retrieveSchemas(SchemaPanel schemaPanel,
481: DatabaseConnection dbcon, String defaultSchema) {
482: fireConnectionStep(bundle().getString(
483: "ConnectionProgress_Schemas")); // NOI18N
484: Vector schemas = new Vector();
485: try {
486: ResultSet rs = dbcon.getConnection().getMetaData()
487: .getSchemas();
488: if (rs != null)
489: while (rs.next())
490: schemas.add(rs.getString(1).trim());
491: } catch (SQLException exc) {
492: //commented out for 3.6 release, need to solve for next Studio release
493: // hack for Pointbase Network Server
494: // if (dbcon.getDriver().equals(PointbasePlus.DRIVER))
495: // if (exc.getErrorCode() == PointbasePlus.ERR_SERVER_REJECTED) {
496: String message = MessageFormat.format(bundle()
497: .getString("ERR_UnableObtainSchemas"),
498: new String[] { exc.getMessage() }); // NOI18N
499: // message = MessageFormat.format(bundle().getString("EXC_PointbaseServerRejected"), new String[] {message, dbcon.getDatabase()}); // NOI18N
500: DialogDisplayer.getDefault().notify(
501: new NotifyDescriptor.Message(message,
502: NotifyDescriptor.ERROR_MESSAGE));
503: // schema will be set to null
504: // return true;
505: // }
506: }
507:
508: return schemaPanel.setSchemas(schemas, defaultSchema);
509: }
510: }
511: }
|