KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mq > sm > jdbc > JDBCStateManager


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.mq.sm.jdbc;
23
24 import java.io.ByteArrayInputStream JavaDoc;
25 import java.io.ByteArrayOutputStream JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.sql.Connection JavaDoc;
28 import java.sql.PreparedStatement JavaDoc;
29 import java.sql.ResultSet JavaDoc;
30 import java.sql.SQLException JavaDoc;
31 import java.sql.Statement JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Collection JavaDoc;
34 import java.util.HashSet JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.Properties JavaDoc;
39
40 import javax.jms.InvalidClientIDException JavaDoc;
41 import javax.jms.JMSException JavaDoc;
42 import javax.jms.JMSSecurityException JavaDoc;
43 import javax.management.ObjectName JavaDoc;
44 import javax.naming.InitialContext JavaDoc;
45 import javax.sql.DataSource JavaDoc;
46 import javax.transaction.Status JavaDoc;
47 import javax.transaction.Transaction JavaDoc;
48 import javax.transaction.TransactionManager JavaDoc;
49
50 import org.jboss.logging.Logger;
51 import org.jboss.mq.DurableSubscriptionID;
52 import org.jboss.mq.SpyJMSException;
53 import org.jboss.mq.SpyTopic;
54 import org.jboss.mq.sm.AbstractStateManager;
55 import org.jboss.mq.sm.StateManager;
56 import org.jboss.tm.TransactionManagerService;
57
58 /**
59  * A state manager that stores state in the database.
60  *
61  * @jmx:mbean extends="org.jboss.mq.sm.AbstractStateManagerMBean"
62  * @todo add support for jmx operations to maintain the database
63  * @todo create indices
64  *
65  * @author Adrian Brock (Adrian@jboss.org)
66  * @author Ivelin Ivanov (ivelin@jboss.org)
67  * @version $Revision: 57045 $
68  */

69 public class JDBCStateManager extends AbstractStateManager implements JDBCStateManagerMBean
70 {
71    static final Logger log = Logger.getLogger(JDBCStateManager.class);
72
73    /** The connection manager */
74    private ObjectName JavaDoc connectionManagerName;
75
76    /** The data source */
77    protected DataSource JavaDoc dataSource;
78
79    /** The connection retries */
80    protected int connectionRetryAttempts = 5;
81
82    /** Whether there is a security manager */
83    private boolean hasSecurityManager = true;
84
85    /** The transaction manager */
86    protected TransactionManager JavaDoc tm;
87
88    /** The sql properties */
89    private Properties JavaDoc sqlProperties = new Properties JavaDoc();
90
91    /** Whether to create tables */
92    private boolean createTables = true;
93
94    /** Create the user table */
95    private String JavaDoc CREATE_USER_TABLE = "CREATE TABLE JMS_USERS (USERID VARCHAR(32) NOT NULL, PASSWD VARCHAR(32) NOT NULL, CLIENTID VARCHAR(128),"
96          + " PRIMARY KEY(USERID))";
97
98    /** Create the role table */
99    private String JavaDoc CREATE_ROLE_TABLE = "CREATE TABLE JMS_ROLES (ROLEID VARCHAR(32) NOT NULL, USERID VARCHAR(32) NOT NULL,"
100          + " PRIMARY KEY(USERID, ROLEID))";
101
102    private String JavaDoc CREATE_SUBSCRIPTION_TABLE = "CREATE TABLE JMS_SUBSCRIPTIONS (CLIENTID VARCHAR(128) NOT NULL, NAME VARCHAR(128) NOT NULL,"
103          + " TOPIC VARCHAR(255) NOT NULL, SELECTOR VARCHAR(255)," + " PRIMARY KEY(CLIENTID, NAME))";
104
105    /** Get a subscription */
106    private String JavaDoc GET_SUBSCRIPTION = "SELECT TOPIC, SELECTOR FROM JMS_SUBSCRIPTIONS WHERE CLIENTID=? AND NAME=?";
107
108    /** Get subscriptions for a topic */
109    private String JavaDoc GET_SUBSCRIPTIONS_FOR_TOPIC = "SELECT CLIENTID, NAME, SELECTOR FROM JMS_SUBSCRIPTIONS WHERE TOPIC=?";
110
111    /** Lock a subscription */
112    private String JavaDoc LOCK_SUBSCRIPTION = "SELECT TOPIC, SELECTOR FROM JMS_SUBSCRIPTIONS WHERE CLIENTID=? AND NAME=?";
113
114    /** Insert a subscription */
115    private String JavaDoc INSERT_SUBSCRIPTION = "INSERT INTO JMS_SUBSCRIPTIONS (CLIENTID, NAME, TOPIC, SELECTOR) VALUES(?,?,?,?)";
116
117    /** Update a subscription */
118    private String JavaDoc UPDATE_SUBSCRIPTION = "UPDATE JMS_SUBSCRIPTIONS SET TOPIC=?, SELECTOR=? WHERE CLIENTID=? AND NAME=?";
119
120    /** Remove a subscription */
121    private String JavaDoc REMOVE_SUBSCRIPTION = "DELETE FROM JMS_SUBSCRIPTIONS WHERE CLIENTID=? AND NAME=?";
122
123    /** Get a user with the given client id */
124    private String JavaDoc GET_USER_BY_CLIENTID = "SELECT USERID, PASSWD, CLIENTID FROM JMS_USERS WHERE CLIENTID=?";
125
126    /** Get a user with the given user id */
127    private String JavaDoc GET_USER = "SELECT PASSWD, CLIENTID FROM JMS_USERS WHERE USERID=?";
128
129    /** Populate tables with initial data */
130    private List JavaDoc POPULATE_TABLES = new ArrayList JavaDoc();
131
132    public ObjectName JavaDoc getConnectionManager()
133    {
134       return connectionManagerName;
135    }
136
137    public void setConnectionManager(ObjectName JavaDoc connectionManagerName)
138    {
139       this.connectionManagerName = connectionManagerName;
140    }
141
142    public boolean hasSecurityManager()
143    {
144       return hasSecurityManager;
145    }
146
147    public void setHasSecurityManager(boolean hasSecurityManager)
148    {
149       this.hasSecurityManager = hasSecurityManager;
150    }
151
152    public String JavaDoc getSqlProperties()
153    {
154       try
155       {
156          ByteArrayOutputStream JavaDoc boa = new ByteArrayOutputStream JavaDoc();
157          sqlProperties.store(boa, "");
158          return new String JavaDoc(boa.toByteArray());
159       }
160       catch (IOException JavaDoc shouldnothappen)
161       {
162          return "";
163       }
164    }
165
166    public void setSqlProperties(String JavaDoc value)
167    {
168       try
169       {
170
171          ByteArrayInputStream JavaDoc is = new ByteArrayInputStream JavaDoc(value.getBytes());
172          sqlProperties = new Properties JavaDoc();
173          sqlProperties.load(is);
174
175       }
176       catch (IOException JavaDoc shouldnothappen)
177       {
178       }
179    }
180
181    public void setConnectionRetryAttempts(int value)
182    {
183       this.connectionRetryAttempts = value;
184    }
185
186    public int getConnectionRetryAttempts()
187    {
188       return this.connectionRetryAttempts;
189    }
190
191    protected DurableSubscription getDurableSubscription(DurableSubscriptionID sub) throws JMSException JavaDoc
192    {
193       JDBCSession session = new JDBCSession();
194       try
195       {
196          PreparedStatement JavaDoc statement = session.prepareStatement(GET_SUBSCRIPTION);
197          statement.setString(1, sub.getClientID());
198          statement.setString(2, sub.getSubscriptionName());
199          ResultSet JavaDoc rs = statement.executeQuery();
200          session.addResultSet(rs);
201          if (rs.next() == false)
202             return null;
203
204          return new DurableSubscription(sub.getClientID(), sub.getSubscriptionName(), rs.getString(1), rs.getString(2));
205       }
206       catch (SQLException JavaDoc e)
207       {
208          session.setRollbackOnly();
209          throw new SpyJMSException("Error getting durable subscription " + sub, e);
210       }
211       finally
212       {
213          session.close();
214       }
215    }
216
217    protected void saveDurableSubscription(DurableSubscription ds) throws JMSException JavaDoc
218    {
219       JDBCSession session = new JDBCSession();
220       try
221       {
222          PreparedStatement JavaDoc statement = session.prepareStatement(LOCK_SUBSCRIPTION);
223          statement.setString(1, ds.getClientID());
224          statement.setString(2, ds.getName());
225          ResultSet JavaDoc rs = statement.executeQuery();
226          session.addResultSet(rs);
227          if (rs.next() == false)
228          {
229             statement = session.prepareStatement(INSERT_SUBSCRIPTION);
230             statement.setString(1, ds.getClientID());
231             statement.setString(2, ds.getName());
232             statement.setString(3, ds.getTopic());
233             statement.setString(4, ds.getSelector());
234          }
235          else
236          {
237             statement = session.prepareStatement(UPDATE_SUBSCRIPTION);
238             statement.setString(1, ds.getTopic());
239             statement.setString(2, ds.getSelector());
240             statement.setString(3, ds.getClientID());
241             statement.setString(4, ds.getName());
242          }
243          if (statement.executeUpdate() != 1)
244          {
245             session.setRollbackOnly();
246             throw new SpyJMSException("Insert subscription failed " + ds);
247          }
248       }
249       catch (SQLException JavaDoc e)
250       {
251          session.setRollbackOnly();
252          throw new SpyJMSException("Error saving durable subscription " + ds, e);
253       }
254       finally
255       {
256          session.close();
257       }
258    }
259
260    protected void removeDurableSubscription(DurableSubscription ds) throws JMSException JavaDoc
261    {
262       JDBCSession session = new JDBCSession();
263       try
264       {
265          PreparedStatement JavaDoc statement = session.prepareStatement(REMOVE_SUBSCRIPTION);
266          statement.setString(1, ds.getClientID());
267          statement.setString(2, ds.getName());
268          if (statement.executeUpdate() != 1)
269             throw new JMSException JavaDoc("Durable subscription does not exist " + ds);
270       }
271       catch (SQLException JavaDoc e)
272       {
273          session.setRollbackOnly();
274          throw new SpyJMSException("Error removing durable subscription " + ds, e);
275       }
276       finally
277       {
278          session.close();
279       }
280    }
281
282    public Collection JavaDoc getDurableSubscriptionIdsForTopic(SpyTopic topic) throws JMSException JavaDoc
283    {
284       ArrayList JavaDoc result = new ArrayList JavaDoc();
285
286       JDBCSession session = new JDBCSession();
287       try
288       {
289          PreparedStatement JavaDoc statement = session.prepareStatement(GET_SUBSCRIPTIONS_FOR_TOPIC);
290          statement.setString(1, topic.getName());
291          ResultSet JavaDoc rs = statement.executeQuery();
292          session.addResultSet(rs);
293          while (rs.next())
294          {
295             result.add(new DurableSubscriptionID(rs.getString(1), rs.getString(2), rs.getString(3)));
296          }
297
298          return result;
299       }
300       catch (SQLException JavaDoc e)
301       {
302          session.setRollbackOnly();
303          throw new SpyJMSException("Error getting durable subscriptions for topic " + topic, e);
304       }
305       finally
306       {
307          session.close();
308       }
309    }
310
311    protected void checkLoggedOnClientId(String JavaDoc clientID) throws JMSException JavaDoc
312    {
313       JDBCSession session = new JDBCSession();
314       try
315       {
316          PreparedStatement JavaDoc statement = session.prepareStatement(GET_USER_BY_CLIENTID);
317          statement.setString(1, clientID);
318          ResultSet JavaDoc rs = statement.executeQuery();
319          session.addResultSet(rs);
320          if (rs.next())
321             throw new InvalidClientIDException JavaDoc("This client id is password protected " + clientID);
322       }
323       catch (SQLException JavaDoc e)
324       {
325          session.setRollbackOnly();
326          throw new SpyJMSException("Error checking logged on client id " + clientID, e);
327       }
328       finally
329       {
330          session.close();
331       }
332    }
333
334    protected String JavaDoc getPreconfClientId(String JavaDoc logon, String JavaDoc passwd) throws JMSException JavaDoc
335    {
336       JDBCSession session = new JDBCSession();
337       try
338       {
339          PreparedStatement JavaDoc statement = session.prepareStatement(GET_USER);
340          statement.setString(1, logon);
341          ResultSet JavaDoc rs = statement.executeQuery();
342          session.addResultSet(rs);
343          if (rs.next() == false)
344          {
345             if (hasSecurityManager)
346                return null;
347             else
348                throw new JMSSecurityException JavaDoc("This user does not exist " + logon);
349          }
350
351          if (hasSecurityManager == false && passwd.equals(rs.getString(1)) == false)
352             throw new JMSSecurityException JavaDoc("Bad password for user " + logon);
353
354          return rs.getString(2);
355       }
356       catch (SQLException JavaDoc e)
357       {
358          session.setRollbackOnly();
359          throw new SpyJMSException("Error retrieving preconfigured user " + logon, e);
360       }
361       finally
362       {
363          session.close();
364       }
365    }
366
367    public StateManager getInstance()
368    {
369       return this;
370    }
371
372    protected void startService() throws Exception JavaDoc
373    {
374       if (connectionManagerName == null)
375          throw new IllegalStateException JavaDoc("No connection manager configured");
376
377       //Find the ConnectionFactoryLoader MBean so we can find the datasource
378
String JavaDoc dsName = (String JavaDoc) getServer().getAttribute(connectionManagerName, "BindName");
379
380       InitialContext JavaDoc ctx = new InitialContext JavaDoc();
381       try
382       {
383          dataSource = (DataSource JavaDoc) ctx.lookup(dsName);
384          tm = (TransactionManager JavaDoc) ctx.lookup(TransactionManagerService.JNDI_NAME);
385       }
386       finally
387       {
388          ctx.close();
389       }
390
391       try
392       {
393          initDB();
394       }
395       catch (Exception JavaDoc e)
396       {
397          log.warn("Error initialising state manager db", e);
398       }
399    }
400
401    protected void initDB() throws Exception JavaDoc
402    {
403       CREATE_USER_TABLE = sqlProperties.getProperty("CREATE_USER_TABLE", CREATE_USER_TABLE);
404       CREATE_ROLE_TABLE = sqlProperties.getProperty("CREATE_ROLE_TABLE", CREATE_ROLE_TABLE);
405       CREATE_SUBSCRIPTION_TABLE = sqlProperties.getProperty("CREATE_SUBSCRIPTION_TABLE", CREATE_SUBSCRIPTION_TABLE);
406       GET_SUBSCRIPTION = sqlProperties.getProperty("GET_SUBSCRIPTION", GET_SUBSCRIPTION);
407       GET_SUBSCRIPTIONS_FOR_TOPIC = sqlProperties.getProperty("GET_SUBSCRIPTIONS_FOR_TOPIC",
408             GET_SUBSCRIPTIONS_FOR_TOPIC);
409       LOCK_SUBSCRIPTION = sqlProperties.getProperty("LOCK_SUBSCRIPTION", LOCK_SUBSCRIPTION);
410       INSERT_SUBSCRIPTION = sqlProperties.getProperty("INSERT_SUBSCRIPTION", INSERT_SUBSCRIPTION);
411       UPDATE_SUBSCRIPTION = sqlProperties.getProperty("UPDATE_SUBSCRIPTION", UPDATE_SUBSCRIPTION);
412       REMOVE_SUBSCRIPTION = sqlProperties.getProperty("REMOVE_SUBSCRIPTION", REMOVE_SUBSCRIPTION);
413       GET_USER_BY_CLIENTID = sqlProperties.getProperty("GET_USER_BY_CLIENTID", GET_USER_BY_CLIENTID);
414       GET_USER = sqlProperties.getProperty("GET_USER", GET_USER);
415
416       // Read the queries to populate the tables with initial data
417
for (Iterator JavaDoc i = sqlProperties.entrySet().iterator(); i.hasNext();)
418       {
419          Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
420          String JavaDoc key = (String JavaDoc) entry.getKey();
421          if (key.startsWith("POPULATE.TABLES."))
422             POPULATE_TABLES.add(entry.getValue());
423       }
424
425       String JavaDoc createString = sqlProperties.getProperty("CREATE_TABLES_ON_START_UP");
426       if (createString == null)
427          createString = sqlProperties.getProperty("CREATE_TABLES_ON_STARTUP");
428       if (createString == null)
429          createTables = true;
430       else
431          createTables = createString.trim().equalsIgnoreCase("true");
432
433       if (createTables)
434       {
435          JDBCSession session = new JDBCSession();
436          try
437          {
438             PreparedStatement JavaDoc statement;
439             try
440             {
441                statement = session.prepareStatement(CREATE_USER_TABLE);
442                statement.executeUpdate();
443             }
444             catch (SQLException JavaDoc ignored)
445             {
446                log.trace("Error creating table: " + CREATE_USER_TABLE, ignored);
447             }
448             try
449             {
450                statement = session.prepareStatement(CREATE_ROLE_TABLE);
451                statement.executeUpdate();
452             }
453             catch (SQLException JavaDoc ignored)
454             {
455                log.trace("Error creating table: " + CREATE_ROLE_TABLE, ignored);
456             }
457             try
458             {
459                statement = session.prepareStatement(CREATE_SUBSCRIPTION_TABLE);
460                statement.executeUpdate();
461             }
462             catch (SQLException JavaDoc ignored)
463             {
464                log.trace("Error creating table: " + CREATE_SUBSCRIPTION_TABLE, ignored);
465             }
466
467             Iterator JavaDoc iter = POPULATE_TABLES.iterator();
468             String JavaDoc nextQry = null;
469             while (iter.hasNext())
470             {
471                try
472                {
473                   nextQry = (String JavaDoc) iter.next();
474                   statement = session.prepareStatement(nextQry);
475                   statement.execute();
476                }
477                catch (SQLException JavaDoc ignored)
478                {
479                   log.trace("Error populating tables: " + nextQry, ignored);
480                }
481             }
482          }
483          finally
484          {
485             session.close();
486          }
487       }
488    }
489
490    /**
491     * This inner class helps handle the jdbc connections.
492     */

493    class JDBCSession
494    {
495       boolean trace = log.isTraceEnabled();
496
497       Transaction JavaDoc threadTx;
498
499       Connection JavaDoc connection;
500
501       HashSet JavaDoc statements = new HashSet JavaDoc();
502
503       HashSet JavaDoc resultSets = null;
504
505       JDBCSession() throws JMSException JavaDoc
506       {
507          try
508          {
509             // Suspend any previous transaction
510
threadTx = tm.suspend();
511             try
512             {
513                // Always begin a transaction
514
tm.begin();
515                try
516                {
517                   // Retrieve a connection
518
connection = getConnection();
519                }
520                catch (Throwable JavaDoc t)
521                {
522                   // Rollback the previously started transaction
523
try
524                   {
525                      tm.rollback();
526                   }
527                   catch (Throwable JavaDoc ignored)
528                   {
529                      log.warn("Unable to rollback transaction", ignored);
530                   }
531                   throw t;
532                }
533             }
534             catch (Throwable JavaDoc t)
535             {
536                // Resume the previous transaction
537
try
538                {
539                   if (threadTx != null)
540                      tm.resume(threadTx);
541                }
542                catch (Throwable JavaDoc ignored)
543                {
544                   log.warn("Unable to resume transaction " + threadTx, ignored);
545                }
546                throw t;
547             }
548          }
549          catch (Throwable JavaDoc t)
550          {
551             throw new SpyJMSException("Error creating connection to the database.", t);
552          }
553       }
554
555       PreparedStatement JavaDoc prepareStatement(String JavaDoc sql) throws SQLException JavaDoc
556       {
557          PreparedStatement JavaDoc result = connection.prepareStatement(sql);
558          statements.add(result);
559          return result;
560       }
561
562       void setRollbackOnly() throws JMSException JavaDoc
563       {
564          try
565          {
566             tm.setRollbackOnly();
567          }
568          catch (Exception JavaDoc e)
569          {
570             throw new SpyJMSException("Could not mark the transaction for rollback.", e);
571          }
572       }
573
574       void addResultSet(ResultSet JavaDoc rs)
575       {
576          if (resultSets == null)
577             resultSets = new HashSet JavaDoc();
578          resultSets.add(rs);
579       }
580
581       void close() throws JMSException JavaDoc
582       {
583          if (resultSets != null)
584          {
585             for (Iterator JavaDoc i = resultSets.iterator(); i.hasNext();)
586             {
587                ResultSet JavaDoc rs = (ResultSet JavaDoc) i.next();
588                try
589                {
590                   rs.close();
591                }
592                catch (Throwable JavaDoc ignored)
593                {
594                   if (trace)
595                      log.trace("Unable to close result set", ignored);
596                }
597             }
598          }
599
600          for (Iterator JavaDoc i = statements.iterator(); i.hasNext();)
601          {
602             Statement JavaDoc s = (Statement JavaDoc) i.next();
603             try
604             {
605                s.close();
606             }
607             catch (Throwable JavaDoc ignored)
608             {
609                if (trace)
610                   log.trace("Unable to close statement", ignored);
611             }
612          }
613
614          try
615          {
616             if (connection != null)
617                connection.close();
618          }
619          catch (Throwable JavaDoc ignored)
620          {
621             if (trace)
622                log.trace("Unable to close connection", ignored);
623          }
624
625          try
626          {
627             if (tm.getStatus() == Status.STATUS_MARKED_ROLLBACK)
628             {
629                tm.rollback();
630             }
631             else
632             {
633                tm.commit();
634             }
635          }
636          catch (Exception JavaDoc e)
637          {
638             throw new SpyJMSException("Could not commit/rollback a transaction with the transaction manager.", e);
639          }
640          finally
641          {
642             try
643             {
644                if (threadTx != null)
645                   tm.resume(threadTx);
646             }
647             catch (Throwable JavaDoc ignored)
648             {
649                log.warn("Unable to resume transaction " + threadTx, ignored);
650             }
651          }
652       }
653
654       /**
655        * Gets a connection from the datasource, retrying as needed. This was
656        * implemented because in some minimal configurations (i.e. little logging
657        * and few services) the database wasn't ready when we tried to get a
658        * connection. We, therefore, implement a retry loop wich is controled
659        * by the ConnectionRetryAttempts attribute. Submitted by terry@amicas.com
660        *
661        * @exception SQLException if an error occurs.
662        */

663       protected Connection JavaDoc getConnection() throws SQLException JavaDoc
664       {
665          int attempts = connectionRetryAttempts;
666          int attemptCount = 0;
667          SQLException JavaDoc sqlException = null;
668          while (attempts-- > 0)
669          {
670             if (++attemptCount > 1)
671             {
672                log.debug("Retrying connection: attempt # " + attemptCount);
673             }
674             try
675             {
676                sqlException = null;
677                return dataSource.getConnection();
678             }
679             catch (SQLException JavaDoc exception)
680             {
681                log.debug("Connection attempt # " + attemptCount + " failed with SQLException", exception);
682                sqlException = exception;
683             }
684             finally
685             {
686                if (sqlException == null && attemptCount > 1)
687                {
688                   log.debug("Connection succeeded on attempt # " + attemptCount);
689                }
690             }
691
692             if (attempts > 0)
693             {
694                try
695                {
696                   Thread.sleep(1500);
697                }
698                catch (InterruptedException JavaDoc interruptedException)
699                {
700                   break;
701                }
702             }
703          }
704          if (sqlException != null)
705          {
706             throw sqlException;
707          }
708          throw new SQLException JavaDoc("connection attempt interrupted");
709       }
710    }
711 }
712
Popular Tags