001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.session;
018:
019: import org.apache.catalina.Container;
020: import org.apache.catalina.LifecycleException;
021: import org.apache.catalina.Loader;
022: import org.apache.catalina.Session;
023: import org.apache.catalina.Store;
024: import org.apache.catalina.util.CustomObjectInputStream;
025: import java.io.BufferedInputStream;
026: import java.io.BufferedOutputStream;
027: import java.io.ByteArrayInputStream;
028: import java.io.ByteArrayOutputStream;
029: import java.io.IOException;
030: import java.io.InputStream;
031: import java.io.ObjectInputStream;
032: import java.io.ObjectOutputStream;
033: import java.sql.Connection;
034: import java.sql.Driver;
035: import java.sql.PreparedStatement;
036: import java.sql.ResultSet;
037: import java.sql.SQLException;
038: import java.util.ArrayList;
039: import java.util.Properties;
040:
041: /**
042: * Implementation of the <code>Store</code> interface that stores
043: * serialized session objects in a database. Sessions that are
044: * saved are still subject to being expired based on inactivity.
045: *
046: * @author Bip Thelin
047: * @version $Revision: 1.9 $, $Date: 2004/03/20 11:11:07 $
048: */
049:
050: public class JDBCStore extends StoreBase implements Store {
051:
052: /**
053: * The descriptive information about this implementation.
054: */
055: protected static String info = "JDBCStore/1.0";
056:
057: /**
058: * Context name associated with this Store
059: */
060: private String name = null;
061:
062: /**
063: * Name to register for this Store, used for logging.
064: */
065: protected static String storeName = "JDBCStore";
066:
067: /**
068: * Name to register for the background thread.
069: */
070: protected String threadName = "JDBCStore";
071:
072: /**
073: * The connection username to use when trying to connect to the database.
074: */
075: protected String connectionName = null;
076:
077: /**
078: * The connection URL to use when trying to connect to the database.
079: */
080: protected String connectionPassword = null;
081:
082: /**
083: * Connection string to use when connecting to the DB.
084: */
085: protected String connectionURL = null;
086:
087: /**
088: * The database connection.
089: */
090: private Connection dbConnection = null;
091:
092: /**
093: * Instance of the JDBC Driver class we use as a connection factory.
094: */
095: protected Driver driver = null;
096:
097: /**
098: * Driver to use.
099: */
100: protected String driverName = null;
101:
102: // ------------------------------------------------------------- Table & cols
103:
104: /**
105: * Table to use.
106: */
107: protected String sessionTable = "tomcat$sessions";
108:
109: /**
110: * Column to use for /Engine/Host/Context name
111: */
112: protected String sessionAppCol = "app";
113:
114: /**
115: * Id column to use.
116: */
117: protected String sessionIdCol = "id";
118:
119: /**
120: * Data column to use.
121: */
122: protected String sessionDataCol = "data";
123:
124: /**
125: * Is Valid column to use.
126: */
127: protected String sessionValidCol = "valid";
128:
129: /**
130: * Max Inactive column to use.
131: */
132: protected String sessionMaxInactiveCol = "maxinactive";
133:
134: /**
135: * Last Accessed column to use.
136: */
137: protected String sessionLastAccessedCol = "lastaccess";
138:
139: // ------------------------------------------------------------- SQL Variables
140:
141: /**
142: * Variable to hold the <code>getSize()</code> prepared statement.
143: */
144: protected PreparedStatement preparedSizeSql = null;
145:
146: /**
147: * Variable to hold the <code>keys()</code> prepared statement.
148: */
149: protected PreparedStatement preparedKeysSql = null;
150:
151: /**
152: * Variable to hold the <code>save()</code> prepared statement.
153: */
154: protected PreparedStatement preparedSaveSql = null;
155:
156: /**
157: * Variable to hold the <code>clear()</code> prepared statement.
158: */
159: protected PreparedStatement preparedClearSql = null;
160:
161: /**
162: * Variable to hold the <code>remove()</code> prepared statement.
163: */
164: protected PreparedStatement preparedRemoveSql = null;
165:
166: /**
167: * Variable to hold the <code>load()</code> prepared statement.
168: */
169: protected PreparedStatement preparedLoadSql = null;
170:
171: // ------------------------------------------------------------- Properties
172:
173: /**
174: * Return the info for this Store.
175: */
176: public String getInfo() {
177: return (info);
178: }
179:
180: /**
181: * Return the name for this instance (built from container name)
182: */
183: public String getName() {
184: if (name == null) {
185: Container container = manager.getContainer();
186: String contextName = container.getName();
187: String hostName = "";
188: String engineName = "";
189:
190: if (container.getParent() != null) {
191: Container host = container.getParent();
192: hostName = host.getName();
193: if (host.getParent() != null) {
194: engineName = host.getParent().getName();
195: }
196: }
197: name = "/" + engineName + "/" + hostName + contextName;
198: }
199: return name;
200: }
201:
202: /**
203: * Return the thread name for this Store.
204: */
205: public String getThreadName() {
206: return (threadName);
207: }
208:
209: /**
210: * Return the name for this Store, used for logging.
211: */
212: public String getStoreName() {
213: return (storeName);
214: }
215:
216: /**
217: * Set the driver for this Store.
218: *
219: * @param driverName The new driver
220: */
221: public void setDriverName(String driverName) {
222: String oldDriverName = this .driverName;
223: this .driverName = driverName;
224: support.firePropertyChange("driverName", oldDriverName,
225: this .driverName);
226: this .driverName = driverName;
227: }
228:
229: /**
230: * Return the driver for this Store.
231: */
232: public String getDriverName() {
233: return (this .driverName);
234: }
235:
236: /**
237: * Return the username to use to connect to the database.
238: *
239: */
240: public String getConnectionName() {
241: return connectionName;
242: }
243:
244: /**
245: * Set the username to use to connect to the database.
246: *
247: * @param connectionName Username
248: */
249: public void setConnectionName(String connectionName) {
250: this .connectionName = connectionName;
251: }
252:
253: /**
254: * Return the password to use to connect to the database.
255: *
256: */
257: public String getConnectionPassword() {
258: return connectionPassword;
259: }
260:
261: /**
262: * Set the password to use to connect to the database.
263: *
264: * @param connectionPassword User password
265: */
266: public void setConnectionPassword(String connectionPassword) {
267: this .connectionPassword = connectionPassword;
268: }
269:
270: /**
271: * Set the Connection URL for this Store.
272: *
273: * @param connectionURL The new Connection URL
274: */
275: public void setConnectionURL(String connectionURL) {
276: String oldConnString = this .connectionURL;
277: this .connectionURL = connectionURL;
278: support.firePropertyChange("connectionURL", oldConnString,
279: this .connectionURL);
280: }
281:
282: /**
283: * Return the Connection URL for this Store.
284: */
285: public String getConnectionURL() {
286: return (this .connectionURL);
287: }
288:
289: /**
290: * Set the table for this Store.
291: *
292: * @param sessionTable The new table
293: */
294: public void setSessionTable(String sessionTable) {
295: String oldSessionTable = this .sessionTable;
296: this .sessionTable = sessionTable;
297: support.firePropertyChange("sessionTable", oldSessionTable,
298: this .sessionTable);
299: }
300:
301: /**
302: * Return the table for this Store.
303: */
304: public String getSessionTable() {
305: return (this .sessionTable);
306: }
307:
308: /**
309: * Set the App column for the table.
310: *
311: * @param sessionAppCol the column name
312: */
313: public void setSessionAppCol(String sessionAppCol) {
314: String oldSessionAppCol = this .sessionAppCol;
315: this .sessionAppCol = sessionAppCol;
316: support.firePropertyChange("sessionAppCol", oldSessionAppCol,
317: this .sessionAppCol);
318: }
319:
320: /**
321: * Return the web application name column for the table.
322: */
323: public String getSessionAppCol() {
324: return (this .sessionAppCol);
325: }
326:
327: /**
328: * Set the Id column for the table.
329: *
330: * @param sessionIdCol the column name
331: */
332: public void setSessionIdCol(String sessionIdCol) {
333: String oldSessionIdCol = this .sessionIdCol;
334: this .sessionIdCol = sessionIdCol;
335: support.firePropertyChange("sessionIdCol", oldSessionIdCol,
336: this .sessionIdCol);
337: }
338:
339: /**
340: * Return the Id column for the table.
341: */
342: public String getSessionIdCol() {
343: return (this .sessionIdCol);
344: }
345:
346: /**
347: * Set the Data column for the table
348: *
349: * @param sessionDataCol the column name
350: */
351: public void setSessionDataCol(String sessionDataCol) {
352: String oldSessionDataCol = this .sessionDataCol;
353: this .sessionDataCol = sessionDataCol;
354: support.firePropertyChange("sessionDataCol", oldSessionDataCol,
355: this .sessionDataCol);
356: }
357:
358: /**
359: * Return the data column for the table
360: */
361: public String getSessionDataCol() {
362: return (this .sessionDataCol);
363: }
364:
365: /**
366: * Set the Is Valid column for the table
367: *
368: * @param sessionValidCol The column name
369: */
370: public void setSessionValidCol(String sessionValidCol) {
371: String oldSessionValidCol = this .sessionValidCol;
372: this .sessionValidCol = sessionValidCol;
373: support.firePropertyChange("sessionValidCol",
374: oldSessionValidCol, this .sessionValidCol);
375: }
376:
377: /**
378: * Return the Is Valid column
379: */
380: public String getSessionValidCol() {
381: return (this .sessionValidCol);
382: }
383:
384: /**
385: * Set the Max Inactive column for the table
386: *
387: * @param sessionMaxInactiveCol The column name
388: */
389: public void setSessionMaxInactiveCol(String sessionMaxInactiveCol) {
390: String oldSessionMaxInactiveCol = this .sessionMaxInactiveCol;
391: this .sessionMaxInactiveCol = sessionMaxInactiveCol;
392: support.firePropertyChange("sessionMaxInactiveCol",
393: oldSessionMaxInactiveCol, this .sessionMaxInactiveCol);
394: }
395:
396: /**
397: * Return the Max Inactive column
398: */
399: public String getSessionMaxInactiveCol() {
400: return (this .sessionMaxInactiveCol);
401: }
402:
403: /**
404: * Set the Last Accessed column for the table
405: *
406: * @param sessionLastAccessedCol The column name
407: */
408: public void setSessionLastAccessedCol(String sessionLastAccessedCol) {
409: String oldSessionLastAccessedCol = this .sessionLastAccessedCol;
410: this .sessionLastAccessedCol = sessionLastAccessedCol;
411: support.firePropertyChange("sessionLastAccessedCol",
412: oldSessionLastAccessedCol, this .sessionLastAccessedCol);
413: }
414:
415: /**
416: * Return the Last Accessed column
417: */
418: public String getSessionLastAccessedCol() {
419: return (this .sessionLastAccessedCol);
420: }
421:
422: // --------------------------------------------------------- Public Methods
423:
424: /**
425: * Return an array containing the session identifiers of all Sessions
426: * currently saved in this Store. If there are no such Sessions, a
427: * zero-length array is returned.
428: *
429: * @exception IOException if an input/output error occurred
430: */
431: public String[] keys() throws IOException {
432: String keysSql = "SELECT " + sessionIdCol + " FROM "
433: + sessionTable + " WHERE " + sessionAppCol + " = ?";
434: ResultSet rst = null;
435: String keys[] = null;
436: synchronized (this ) {
437: int numberOfTries = 2;
438: while (numberOfTries > 0) {
439:
440: Connection _conn = getConnection();
441: if (_conn == null) {
442: return (new String[0]);
443: }
444: try {
445: if (preparedKeysSql == null) {
446: preparedKeysSql = _conn
447: .prepareStatement(keysSql);
448: }
449:
450: preparedKeysSql.setString(1, getName());
451: rst = preparedKeysSql.executeQuery();
452: ArrayList tmpkeys = new ArrayList();
453: if (rst != null) {
454: while (rst.next()) {
455: tmpkeys.add(rst.getString(1));
456: }
457: }
458: keys = (String[]) tmpkeys
459: .toArray(new String[tmpkeys.size()]);
460: } catch (SQLException e) {
461: log(sm.getString(getStoreName() + ".SQLException",
462: e));
463: keys = new String[0];
464: // Close the connection so that it gets reopened next time
465: if (dbConnection != null)
466: close(dbConnection);
467: } finally {
468: try {
469: if (rst != null) {
470: rst.close();
471: }
472: } catch (SQLException e) {
473: ;
474: }
475:
476: release(_conn);
477: }
478: numberOfTries--;
479: }
480: }
481:
482: return (keys);
483: }
484:
485: /**
486: * Return an integer containing a count of all Sessions
487: * currently saved in this Store. If there are no Sessions,
488: * <code>0</code> is returned.
489: *
490: * @exception IOException if an input/output error occurred
491: */
492: public int getSize() throws IOException {
493: int size = 0;
494: String sizeSql = "SELECT COUNT(" + sessionIdCol + ") FROM "
495: + sessionTable + " WHERE " + sessionAppCol + " = ?";
496: ResultSet rst = null;
497:
498: synchronized (this ) {
499: int numberOfTries = 2;
500: while (numberOfTries > 0) {
501: Connection _conn = getConnection();
502:
503: if (_conn == null) {
504: return (size);
505: }
506:
507: try {
508: if (preparedSizeSql == null) {
509: preparedSizeSql = _conn
510: .prepareStatement(sizeSql);
511: }
512:
513: preparedSizeSql.setString(1, getName());
514: rst = preparedSizeSql.executeQuery();
515: if (rst.next()) {
516: size = rst.getInt(1);
517: }
518: } catch (SQLException e) {
519: log(sm.getString(getStoreName() + ".SQLException",
520: e));
521: if (dbConnection != null)
522: close(dbConnection);
523: } finally {
524: try {
525: if (rst != null)
526: rst.close();
527: } catch (SQLException e) {
528: ;
529: }
530:
531: release(_conn);
532: }
533: numberOfTries--;
534: }
535: }
536: return (size);
537: }
538:
539: /**
540: * Load the Session associated with the id <code>id</code>.
541: * If no such session is found <code>null</code> is returned.
542: *
543: * @param id a value of type <code>String</code>
544: * @return the stored <code>Session</code>
545: * @exception ClassNotFoundException if an error occurs
546: * @exception IOException if an input/output error occurred
547: */
548: public Session load(String id) throws ClassNotFoundException,
549: IOException {
550: ResultSet rst = null;
551: StandardSession _session = null;
552: Loader loader = null;
553: ClassLoader classLoader = null;
554: ObjectInputStream ois = null;
555: BufferedInputStream bis = null;
556: Container container = manager.getContainer();
557: String loadSql = "SELECT " + sessionIdCol + ", "
558: + sessionDataCol + " FROM " + sessionTable + " WHERE "
559: + sessionIdCol + " = ? AND " + sessionAppCol + " = ?";
560:
561: synchronized (this ) {
562: int numberOfTries = 2;
563: while (numberOfTries > 0) {
564: Connection _conn = getConnection();
565: if (_conn == null) {
566: return (null);
567: }
568:
569: try {
570: if (preparedLoadSql == null) {
571: preparedLoadSql = _conn
572: .prepareStatement(loadSql);
573: }
574:
575: preparedLoadSql.setString(1, id);
576: preparedLoadSql.setString(2, getName());
577: rst = preparedLoadSql.executeQuery();
578: if (rst.next()) {
579: bis = new BufferedInputStream(rst
580: .getBinaryStream(2));
581:
582: if (container != null) {
583: loader = container.getLoader();
584: }
585: if (loader != null) {
586: classLoader = loader.getClassLoader();
587: }
588: if (classLoader != null) {
589: ois = new CustomObjectInputStream(bis,
590: classLoader);
591: } else {
592: ois = new ObjectInputStream(bis);
593: }
594:
595: if (debug > 0) {
596: log(sm.getString(getStoreName()
597: + ".loading", id, sessionTable));
598: }
599:
600: _session = (StandardSession) manager
601: .createEmptySession();
602: _session.readObjectData(ois);
603: _session.setManager(manager);
604:
605: } else if (debug > 0) {
606: log(getStoreName()
607: + ": No persisted data object found");
608: }
609: } catch (SQLException e) {
610: log(sm.getString(getStoreName() + ".SQLException",
611: e));
612: if (dbConnection != null)
613: close(dbConnection);
614: } finally {
615: try {
616: if (rst != null) {
617: rst.close();
618: }
619: } catch (SQLException e) {
620: ;
621: }
622: if (ois != null) {
623: try {
624: ois.close();
625: } catch (IOException e) {
626: ;
627: }
628: }
629: release(_conn);
630: }
631: numberOfTries--;
632: }
633: }
634:
635: return (_session);
636: }
637:
638: /**
639: * Remove the Session with the specified session identifier from
640: * this Store, if present. If no such Session is present, this method
641: * takes no action.
642: *
643: * @param id Session identifier of the Session to be removed
644: *
645: * @exception IOException if an input/output error occurs
646: */
647: public void remove(String id) throws IOException {
648: String removeSql = "DELETE FROM " + sessionTable + " WHERE "
649: + sessionIdCol + " = ? AND " + sessionAppCol + " = ?";
650:
651: synchronized (this ) {
652: int numberOfTries = 2;
653: while (numberOfTries > 0) {
654: Connection _conn = getConnection();
655:
656: if (_conn == null) {
657: return;
658: }
659:
660: try {
661: if (preparedRemoveSql == null) {
662: preparedRemoveSql = _conn
663: .prepareStatement(removeSql);
664: }
665:
666: preparedRemoveSql.setString(1, id);
667: preparedRemoveSql.setString(2, getName());
668: preparedRemoveSql.execute();
669: } catch (SQLException e) {
670: log(sm.getString(getStoreName() + ".SQLException",
671: e));
672: if (dbConnection != null)
673: close(dbConnection);
674: } finally {
675: release(_conn);
676: }
677: numberOfTries--;
678: }
679: }
680:
681: if (debug > 0) {
682: log(sm.getString(getStoreName() + ".removing", id,
683: sessionTable));
684: }
685: }
686:
687: /**
688: * Remove all of the Sessions in this Store.
689: *
690: * @exception IOException if an input/output error occurs
691: */
692: public void clear() throws IOException {
693: String clearSql = "DELETE FROM " + sessionTable + " WHERE "
694: + sessionAppCol + " = ?";
695:
696: synchronized (this ) {
697: int numberOfTries = 2;
698: while (numberOfTries > 0) {
699: Connection _conn = getConnection();
700: if (_conn == null) {
701: return;
702: }
703:
704: try {
705: if (preparedClearSql == null) {
706: preparedClearSql = _conn
707: .prepareStatement(clearSql);
708: }
709:
710: preparedClearSql.setString(1, getName());
711: preparedClearSql.execute();
712: } catch (SQLException e) {
713: log(sm.getString(getStoreName() + ".SQLException",
714: e));
715: if (dbConnection != null)
716: close(dbConnection);
717: } finally {
718: release(_conn);
719: }
720: numberOfTries--;
721: }
722: }
723: }
724:
725: /**
726: * Save a session to the Store.
727: *
728: * @param session the session to be stored
729: * @exception IOException if an input/output error occurs
730: */
731: public void save(Session session) throws IOException {
732: String saveSql = "INSERT INTO " + sessionTable + " ("
733: + sessionIdCol + ", " + sessionAppCol + ", "
734: + sessionDataCol + ", " + sessionValidCol + ", "
735: + sessionMaxInactiveCol + ", " + sessionLastAccessedCol
736: + ") VALUES (?, ?, ?, ?, ?, ?)";
737: ObjectOutputStream oos = null;
738: ByteArrayOutputStream bos = null;
739: ByteArrayInputStream bis = null;
740: InputStream in = null;
741:
742: synchronized (this ) {
743: int numberOfTries = 2;
744: while (numberOfTries > 0) {
745: Connection _conn = getConnection();
746: if (_conn == null) {
747: return;
748: }
749:
750: // If sessions already exist in DB, remove and insert again.
751: // TODO:
752: // * Check if ID exists in database and if so use UPDATE.
753: remove(session.getId());
754:
755: try {
756: bos = new ByteArrayOutputStream();
757: oos = new ObjectOutputStream(
758: new BufferedOutputStream(bos));
759:
760: ((StandardSession) session).writeObjectData(oos);
761: oos.close();
762: oos = null;
763: byte[] obs = bos.toByteArray();
764: int size = obs.length;
765: bis = new ByteArrayInputStream(obs, 0, size);
766: in = new BufferedInputStream(bis, size);
767:
768: if (preparedSaveSql == null) {
769: preparedSaveSql = _conn
770: .prepareStatement(saveSql);
771: }
772:
773: preparedSaveSql.setString(1, session.getId());
774: preparedSaveSql.setString(2, getName());
775: preparedSaveSql.setBinaryStream(3, in, size);
776: preparedSaveSql.setString(4,
777: session.isValid() ? "1" : "0");
778: preparedSaveSql.setInt(5, session
779: .getMaxInactiveInterval());
780: preparedSaveSql.setLong(6, session
781: .getLastAccessedTime());
782: preparedSaveSql.execute();
783: } catch (SQLException e) {
784: log(sm.getString(getStoreName() + ".SQLException",
785: e));
786: if (dbConnection != null)
787: close(dbConnection);
788: } catch (IOException e) {
789: ;
790: } finally {
791: if (oos != null) {
792: oos.close();
793: }
794: if (bis != null) {
795: bis.close();
796: }
797: if (in != null) {
798: in.close();
799: }
800:
801: release(_conn);
802: }
803: numberOfTries--;
804: }
805: }
806:
807: if (debug > 0) {
808: log(sm.getString(getStoreName() + ".saving", session
809: .getId(), sessionTable));
810: }
811: }
812:
813: // --------------------------------------------------------- Protected Methods
814:
815: /**
816: * Check the connection associated with this store, if it's
817: * <code>null</code> or closed try to reopen it.
818: * Returns <code>null</code> if the connection could not be established.
819: *
820: * @return <code>Connection</code> if the connection suceeded
821: */
822: protected Connection getConnection() {
823: try {
824: if (dbConnection == null || dbConnection.isClosed()) {
825: log(sm.getString(getStoreName()
826: + ".checkConnectionDBClosed"));
827: open();
828: if (dbConnection == null || dbConnection.isClosed()) {
829: log(sm.getString(getStoreName()
830: + ".checkConnectionDBReOpenFail"));
831: }
832: }
833: } catch (SQLException ex) {
834: log(sm.getString(getStoreName()
835: + ".checkConnectionSQLException", ex.toString()));
836: }
837:
838: return dbConnection;
839: }
840:
841: /**
842: * Open (if necessary) and return a database connection for use by
843: * this Realm.
844: *
845: * @exception SQLException if a database error occurs
846: */
847: protected Connection open() throws SQLException {
848:
849: // Do nothing if there is a database connection already open
850: if (dbConnection != null)
851: return (dbConnection);
852:
853: // Instantiate our database driver if necessary
854: if (driver == null) {
855: try {
856: Class clazz = Class.forName(driverName);
857: driver = (Driver) clazz.newInstance();
858: } catch (ClassNotFoundException ex) {
859: log(sm.getString(getStoreName()
860: + ".checkConnectionClassNotFoundException", ex
861: .toString()));
862: } catch (InstantiationException ex) {
863: log(sm.getString(getStoreName()
864: + ".checkConnectionClassNotFoundException", ex
865: .toString()));
866: } catch (IllegalAccessException ex) {
867: log(sm.getString(getStoreName()
868: + ".checkConnectionClassNotFoundException", ex
869: .toString()));
870: }
871: }
872:
873: // Open a new connection
874: Properties props = new Properties();
875: if (connectionName != null)
876: props.put("user", connectionName);
877: if (connectionPassword != null)
878: props.put("password", connectionPassword);
879: dbConnection = driver.connect(connectionURL, props);
880: dbConnection.setAutoCommit(true);
881: return (dbConnection);
882:
883: }
884:
885: /**
886: * Close the specified database connection.
887: *
888: * @param dbConnection The connection to be closed
889: */
890: protected void close(Connection dbConnection) {
891:
892: // Do nothing if the database connection is already closed
893: if (dbConnection == null)
894: return;
895:
896: // Close our prepared statements (if any)
897: try {
898: preparedSizeSql.close();
899: } catch (Throwable f) {
900: ;
901: }
902: this .preparedSizeSql = null;
903:
904: try {
905: preparedKeysSql.close();
906: } catch (Throwable f) {
907: ;
908: }
909: this .preparedKeysSql = null;
910:
911: try {
912: preparedSaveSql.close();
913: } catch (Throwable f) {
914: ;
915: }
916: this .preparedSaveSql = null;
917:
918: try {
919: preparedClearSql.close();
920: } catch (Throwable f) {
921: ;
922: }
923: this .preparedClearSql = null;
924:
925: try {
926: preparedRemoveSql.close();
927: } catch (Throwable f) {
928: ;
929: }
930: this .preparedRemoveSql = null;
931:
932: try {
933: preparedLoadSql.close();
934: } catch (Throwable f) {
935: ;
936: }
937: this .preparedLoadSql = null;
938:
939: // Close this database connection, and log any errors
940: try {
941: dbConnection.close();
942: } catch (SQLException e) {
943: log(sm.getString(getStoreName() + ".close", e.toString())); // Just log it here
944: } finally {
945: this .dbConnection = null;
946: }
947:
948: }
949:
950: /**
951: * Release the connection, not needed here since the
952: * connection is not associated with a connection pool.
953: *
954: * @param conn The connection to be released
955: */
956: protected void release(Connection conn) {
957: ;
958: }
959:
960: /**
961: * Called once when this Store is first started.
962: */
963: public void start() throws LifecycleException {
964: super .start();
965:
966: // Open connection to the database
967: this .dbConnection = getConnection();
968: }
969:
970: /**
971: * Gracefully terminate everything associated with our db.
972: * Called once when this Store is stoping.
973: *
974: */
975: public void stop() throws LifecycleException {
976: super .stop();
977:
978: // Close and release everything associated with our db.
979: if (dbConnection != null) {
980: try {
981: dbConnection.commit();
982: } catch (SQLException e) {
983: ;
984: }
985: close(dbConnection);
986: }
987: }
988: }
|