0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.catalina.session;
0019:
0020: import org.apache.catalina.Container;
0021: import org.apache.catalina.LifecycleException;
0022: import org.apache.catalina.Loader;
0023: import org.apache.catalina.Session;
0024: import org.apache.catalina.Store;
0025: import org.apache.catalina.util.CustomObjectInputStream;
0026: import java.io.BufferedInputStream;
0027: import java.io.BufferedOutputStream;
0028: import java.io.ByteArrayInputStream;
0029: import java.io.ByteArrayOutputStream;
0030: import java.io.IOException;
0031: import java.io.InputStream;
0032: import java.io.ObjectInputStream;
0033: import java.io.ObjectOutputStream;
0034: import java.sql.Connection;
0035: import java.sql.Driver;
0036: import java.sql.PreparedStatement;
0037: import java.sql.ResultSet;
0038: import java.sql.SQLException;
0039: import java.util.ArrayList;
0040: import java.util.Properties;
0041:
0042: /**
0043: * Implementation of the <code>Store</code> interface that stores
0044: * serialized session objects in a database. Sessions that are
0045: * saved are still subject to being expired based on inactivity.
0046: *
0047: * @author Bip Thelin
0048: * @version $Revision: 554109 $, $Date: 2007-07-07 03:40:19 +0200 (sam., 07 juil. 2007) $
0049: */
0050:
0051: public class JDBCStore extends StoreBase implements Store {
0052:
0053: /**
0054: * The descriptive information about this implementation.
0055: */
0056: protected static String info = "JDBCStore/1.0";
0057:
0058: /**
0059: * Context name associated with this Store
0060: */
0061: private String name = null;
0062:
0063: /**
0064: * Name to register for this Store, used for logging.
0065: */
0066: protected static String storeName = "JDBCStore";
0067:
0068: /**
0069: * Name to register for the background thread.
0070: */
0071: protected String threadName = "JDBCStore";
0072:
0073: /**
0074: * The connection username to use when trying to connect to the database.
0075: */
0076: protected String connectionName = null;
0077:
0078: /**
0079: * The connection URL to use when trying to connect to the database.
0080: */
0081: protected String connectionPassword = null;
0082:
0083: /**
0084: * Connection string to use when connecting to the DB.
0085: */
0086: protected String connectionURL = null;
0087:
0088: /**
0089: * The database connection.
0090: */
0091: private Connection dbConnection = null;
0092:
0093: /**
0094: * Instance of the JDBC Driver class we use as a connection factory.
0095: */
0096: protected Driver driver = null;
0097:
0098: /**
0099: * Driver to use.
0100: */
0101: protected String driverName = null;
0102:
0103: // ------------------------------------------------------------- Table & cols
0104:
0105: /**
0106: * Table to use.
0107: */
0108: protected String sessionTable = "tomcat$sessions";
0109:
0110: /**
0111: * Column to use for /Engine/Host/Context name
0112: */
0113: protected String sessionAppCol = "app";
0114:
0115: /**
0116: * Id column to use.
0117: */
0118: protected String sessionIdCol = "id";
0119:
0120: /**
0121: * Data column to use.
0122: */
0123: protected String sessionDataCol = "data";
0124:
0125: /**
0126: * Is Valid column to use.
0127: */
0128: protected String sessionValidCol = "valid";
0129:
0130: /**
0131: * Max Inactive column to use.
0132: */
0133: protected String sessionMaxInactiveCol = "maxinactive";
0134:
0135: /**
0136: * Last Accessed column to use.
0137: */
0138: protected String sessionLastAccessedCol = "lastaccess";
0139:
0140: // ------------------------------------------------------------- SQL Variables
0141:
0142: /**
0143: * Variable to hold the <code>getSize()</code> prepared statement.
0144: */
0145: protected PreparedStatement preparedSizeSql = null;
0146:
0147: /**
0148: * Variable to hold the <code>keys()</code> prepared statement.
0149: */
0150: protected PreparedStatement preparedKeysSql = null;
0151:
0152: /**
0153: * Variable to hold the <code>save()</code> prepared statement.
0154: */
0155: protected PreparedStatement preparedSaveSql = null;
0156:
0157: /**
0158: * Variable to hold the <code>clear()</code> prepared statement.
0159: */
0160: protected PreparedStatement preparedClearSql = null;
0161:
0162: /**
0163: * Variable to hold the <code>remove()</code> prepared statement.
0164: */
0165: protected PreparedStatement preparedRemoveSql = null;
0166:
0167: /**
0168: * Variable to hold the <code>load()</code> prepared statement.
0169: */
0170: protected PreparedStatement preparedLoadSql = null;
0171:
0172: // ------------------------------------------------------------- Properties
0173:
0174: /**
0175: * Return the info for this Store.
0176: */
0177: public String getInfo() {
0178: return (info);
0179: }
0180:
0181: /**
0182: * Return the name for this instance (built from container name)
0183: */
0184: public String getName() {
0185: if (name == null) {
0186: Container container = manager.getContainer();
0187: String contextName = container.getName();
0188: String hostName = "";
0189: String engineName = "";
0190:
0191: if (container.getParent() != null) {
0192: Container host = container.getParent();
0193: hostName = host.getName();
0194: if (host.getParent() != null) {
0195: engineName = host.getParent().getName();
0196: }
0197: }
0198: name = "/" + engineName + "/" + hostName + contextName;
0199: }
0200: return name;
0201: }
0202:
0203: /**
0204: * Return the thread name for this Store.
0205: */
0206: public String getThreadName() {
0207: return (threadName);
0208: }
0209:
0210: /**
0211: * Return the name for this Store, used for logging.
0212: */
0213: public String getStoreName() {
0214: return (storeName);
0215: }
0216:
0217: /**
0218: * Set the driver for this Store.
0219: *
0220: * @param driverName The new driver
0221: */
0222: public void setDriverName(String driverName) {
0223: String oldDriverName = this .driverName;
0224: this .driverName = driverName;
0225: support.firePropertyChange("driverName", oldDriverName,
0226: this .driverName);
0227: this .driverName = driverName;
0228: }
0229:
0230: /**
0231: * Return the driver for this Store.
0232: */
0233: public String getDriverName() {
0234: return (this .driverName);
0235: }
0236:
0237: /**
0238: * Return the username to use to connect to the database.
0239: *
0240: */
0241: public String getConnectionName() {
0242: return connectionName;
0243: }
0244:
0245: /**
0246: * Set the username to use to connect to the database.
0247: *
0248: * @param connectionName Username
0249: */
0250: public void setConnectionName(String connectionName) {
0251: this .connectionName = connectionName;
0252: }
0253:
0254: /**
0255: * Return the password to use to connect to the database.
0256: *
0257: */
0258: public String getConnectionPassword() {
0259: return connectionPassword;
0260: }
0261:
0262: /**
0263: * Set the password to use to connect to the database.
0264: *
0265: * @param connectionPassword User password
0266: */
0267: public void setConnectionPassword(String connectionPassword) {
0268: this .connectionPassword = connectionPassword;
0269: }
0270:
0271: /**
0272: * Set the Connection URL for this Store.
0273: *
0274: * @param connectionURL The new Connection URL
0275: */
0276: public void setConnectionURL(String connectionURL) {
0277: String oldConnString = this .connectionURL;
0278: this .connectionURL = connectionURL;
0279: support.firePropertyChange("connectionURL", oldConnString,
0280: this .connectionURL);
0281: }
0282:
0283: /**
0284: * Return the Connection URL for this Store.
0285: */
0286: public String getConnectionURL() {
0287: return (this .connectionURL);
0288: }
0289:
0290: /**
0291: * Set the table for this Store.
0292: *
0293: * @param sessionTable The new table
0294: */
0295: public void setSessionTable(String sessionTable) {
0296: String oldSessionTable = this .sessionTable;
0297: this .sessionTable = sessionTable;
0298: support.firePropertyChange("sessionTable", oldSessionTable,
0299: this .sessionTable);
0300: }
0301:
0302: /**
0303: * Return the table for this Store.
0304: */
0305: public String getSessionTable() {
0306: return (this .sessionTable);
0307: }
0308:
0309: /**
0310: * Set the App column for the table.
0311: *
0312: * @param sessionAppCol the column name
0313: */
0314: public void setSessionAppCol(String sessionAppCol) {
0315: String oldSessionAppCol = this .sessionAppCol;
0316: this .sessionAppCol = sessionAppCol;
0317: support.firePropertyChange("sessionAppCol", oldSessionAppCol,
0318: this .sessionAppCol);
0319: }
0320:
0321: /**
0322: * Return the web application name column for the table.
0323: */
0324: public String getSessionAppCol() {
0325: return (this .sessionAppCol);
0326: }
0327:
0328: /**
0329: * Set the Id column for the table.
0330: *
0331: * @param sessionIdCol the column name
0332: */
0333: public void setSessionIdCol(String sessionIdCol) {
0334: String oldSessionIdCol = this .sessionIdCol;
0335: this .sessionIdCol = sessionIdCol;
0336: support.firePropertyChange("sessionIdCol", oldSessionIdCol,
0337: this .sessionIdCol);
0338: }
0339:
0340: /**
0341: * Return the Id column for the table.
0342: */
0343: public String getSessionIdCol() {
0344: return (this .sessionIdCol);
0345: }
0346:
0347: /**
0348: * Set the Data column for the table
0349: *
0350: * @param sessionDataCol the column name
0351: */
0352: public void setSessionDataCol(String sessionDataCol) {
0353: String oldSessionDataCol = this .sessionDataCol;
0354: this .sessionDataCol = sessionDataCol;
0355: support.firePropertyChange("sessionDataCol", oldSessionDataCol,
0356: this .sessionDataCol);
0357: }
0358:
0359: /**
0360: * Return the data column for the table
0361: */
0362: public String getSessionDataCol() {
0363: return (this .sessionDataCol);
0364: }
0365:
0366: /**
0367: * Set the Is Valid column for the table
0368: *
0369: * @param sessionValidCol The column name
0370: */
0371: public void setSessionValidCol(String sessionValidCol) {
0372: String oldSessionValidCol = this .sessionValidCol;
0373: this .sessionValidCol = sessionValidCol;
0374: support.firePropertyChange("sessionValidCol",
0375: oldSessionValidCol, this .sessionValidCol);
0376: }
0377:
0378: /**
0379: * Return the Is Valid column
0380: */
0381: public String getSessionValidCol() {
0382: return (this .sessionValidCol);
0383: }
0384:
0385: /**
0386: * Set the Max Inactive column for the table
0387: *
0388: * @param sessionMaxInactiveCol The column name
0389: */
0390: public void setSessionMaxInactiveCol(String sessionMaxInactiveCol) {
0391: String oldSessionMaxInactiveCol = this .sessionMaxInactiveCol;
0392: this .sessionMaxInactiveCol = sessionMaxInactiveCol;
0393: support.firePropertyChange("sessionMaxInactiveCol",
0394: oldSessionMaxInactiveCol, this .sessionMaxInactiveCol);
0395: }
0396:
0397: /**
0398: * Return the Max Inactive column
0399: */
0400: public String getSessionMaxInactiveCol() {
0401: return (this .sessionMaxInactiveCol);
0402: }
0403:
0404: /**
0405: * Set the Last Accessed column for the table
0406: *
0407: * @param sessionLastAccessedCol The column name
0408: */
0409: public void setSessionLastAccessedCol(String sessionLastAccessedCol) {
0410: String oldSessionLastAccessedCol = this .sessionLastAccessedCol;
0411: this .sessionLastAccessedCol = sessionLastAccessedCol;
0412: support.firePropertyChange("sessionLastAccessedCol",
0413: oldSessionLastAccessedCol, this .sessionLastAccessedCol);
0414: }
0415:
0416: /**
0417: * Return the Last Accessed column
0418: */
0419: public String getSessionLastAccessedCol() {
0420: return (this .sessionLastAccessedCol);
0421: }
0422:
0423: // --------------------------------------------------------- Public Methods
0424:
0425: /**
0426: * Return an array containing the session identifiers of all Sessions
0427: * currently saved in this Store. If there are no such Sessions, a
0428: * zero-length array is returned.
0429: *
0430: * @exception IOException if an input/output error occurred
0431: */
0432: public String[] keys() throws IOException {
0433: ResultSet rst = null;
0434: String keys[] = null;
0435: synchronized (this ) {
0436: int numberOfTries = 2;
0437: while (numberOfTries > 0) {
0438:
0439: Connection _conn = getConnection();
0440: if (_conn == null) {
0441: return (new String[0]);
0442: }
0443: try {
0444: if (preparedKeysSql == null) {
0445: String keysSql = "SELECT " + sessionIdCol
0446: + " FROM " + sessionTable + " WHERE "
0447: + sessionAppCol + " = ?";
0448: preparedKeysSql = _conn
0449: .prepareStatement(keysSql);
0450: }
0451:
0452: preparedKeysSql.setString(1, getName());
0453: rst = preparedKeysSql.executeQuery();
0454: ArrayList tmpkeys = new ArrayList();
0455: if (rst != null) {
0456: while (rst.next()) {
0457: tmpkeys.add(rst.getString(1));
0458: }
0459: }
0460: keys = (String[]) tmpkeys
0461: .toArray(new String[tmpkeys.size()]);
0462: // Break out after the finally block
0463: numberOfTries = 0;
0464: } catch (SQLException e) {
0465: manager.getContainer().getLogger().error(
0466: sm.getString(getStoreName()
0467: + ".SQLException", e));
0468: keys = new String[0];
0469: // Close the connection so that it gets reopened next time
0470: if (dbConnection != null)
0471: close(dbConnection);
0472: } finally {
0473: try {
0474: if (rst != null) {
0475: rst.close();
0476: }
0477: } catch (SQLException e) {
0478: ;
0479: }
0480:
0481: release(_conn);
0482: }
0483: numberOfTries--;
0484: }
0485: }
0486:
0487: return (keys);
0488: }
0489:
0490: /**
0491: * Return an integer containing a count of all Sessions
0492: * currently saved in this Store. If there are no Sessions,
0493: * <code>0</code> is returned.
0494: *
0495: * @exception IOException if an input/output error occurred
0496: */
0497: public int getSize() throws IOException {
0498: int size = 0;
0499: ResultSet rst = null;
0500:
0501: synchronized (this ) {
0502: int numberOfTries = 2;
0503: while (numberOfTries > 0) {
0504: Connection _conn = getConnection();
0505:
0506: if (_conn == null) {
0507: return (size);
0508: }
0509:
0510: try {
0511: if (preparedSizeSql == null) {
0512: String sizeSql = "SELECT COUNT(" + sessionIdCol
0513: + ") FROM " + sessionTable + " WHERE "
0514: + sessionAppCol + " = ?";
0515: preparedSizeSql = _conn
0516: .prepareStatement(sizeSql);
0517: }
0518:
0519: preparedSizeSql.setString(1, getName());
0520: rst = preparedSizeSql.executeQuery();
0521: if (rst.next()) {
0522: size = rst.getInt(1);
0523: }
0524: // Break out after the finally block
0525: numberOfTries = 0;
0526: } catch (SQLException e) {
0527: manager.getContainer().getLogger().error(
0528: sm.getString(getStoreName()
0529: + ".SQLException", e));
0530: if (dbConnection != null)
0531: close(dbConnection);
0532: } finally {
0533: try {
0534: if (rst != null)
0535: rst.close();
0536: } catch (SQLException e) {
0537: ;
0538: }
0539:
0540: release(_conn);
0541: }
0542: numberOfTries--;
0543: }
0544: }
0545: return (size);
0546: }
0547:
0548: /**
0549: * Load the Session associated with the id <code>id</code>.
0550: * If no such session is found <code>null</code> is returned.
0551: *
0552: * @param id a value of type <code>String</code>
0553: * @return the stored <code>Session</code>
0554: * @exception ClassNotFoundException if an error occurs
0555: * @exception IOException if an input/output error occurred
0556: */
0557: public Session load(String id) throws ClassNotFoundException,
0558: IOException {
0559: ResultSet rst = null;
0560: StandardSession _session = null;
0561: Loader loader = null;
0562: ClassLoader classLoader = null;
0563: ObjectInputStream ois = null;
0564: BufferedInputStream bis = null;
0565: Container container = manager.getContainer();
0566:
0567: synchronized (this ) {
0568: int numberOfTries = 2;
0569: while (numberOfTries > 0) {
0570: Connection _conn = getConnection();
0571: if (_conn == null) {
0572: return (null);
0573: }
0574:
0575: try {
0576: if (preparedLoadSql == null) {
0577: String loadSql = "SELECT " + sessionIdCol
0578: + ", " + sessionDataCol + " FROM "
0579: + sessionTable + " WHERE "
0580: + sessionIdCol + " = ? AND "
0581: + sessionAppCol + " = ?";
0582: preparedLoadSql = _conn
0583: .prepareStatement(loadSql);
0584: }
0585:
0586: preparedLoadSql.setString(1, id);
0587: preparedLoadSql.setString(2, getName());
0588: rst = preparedLoadSql.executeQuery();
0589: if (rst.next()) {
0590: bis = new BufferedInputStream(rst
0591: .getBinaryStream(2));
0592:
0593: if (container != null) {
0594: loader = container.getLoader();
0595: }
0596: if (loader != null) {
0597: classLoader = loader.getClassLoader();
0598: }
0599: if (classLoader != null) {
0600: ois = new CustomObjectInputStream(bis,
0601: classLoader);
0602: } else {
0603: ois = new ObjectInputStream(bis);
0604: }
0605:
0606: if (manager.getContainer().getLogger()
0607: .isDebugEnabled()) {
0608: manager.getContainer().getLogger().debug(
0609: sm.getString(getStoreName()
0610: + ".loading", id,
0611: sessionTable));
0612: }
0613:
0614: _session = (StandardSession) manager
0615: .createEmptySession();
0616: _session.readObjectData(ois);
0617: _session.setManager(manager);
0618: } else if (manager.getContainer().getLogger()
0619: .isDebugEnabled()) {
0620: manager
0621: .getContainer()
0622: .getLogger()
0623: .debug(
0624: getStoreName()
0625: + ": No persisted data object found");
0626: }
0627: // Break out after the finally block
0628: numberOfTries = 0;
0629: } catch (SQLException e) {
0630: manager.getContainer().getLogger().error(
0631: sm.getString(getStoreName()
0632: + ".SQLException", e));
0633: if (dbConnection != null)
0634: close(dbConnection);
0635: } finally {
0636: try {
0637: if (rst != null) {
0638: rst.close();
0639: }
0640: } catch (SQLException e) {
0641: ;
0642: }
0643: if (ois != null) {
0644: try {
0645: ois.close();
0646: } catch (IOException e) {
0647: ;
0648: }
0649: }
0650: release(_conn);
0651: }
0652: numberOfTries--;
0653: }
0654: }
0655:
0656: return (_session);
0657: }
0658:
0659: /**
0660: * Remove the Session with the specified session identifier from
0661: * this Store, if present. If no such Session is present, this method
0662: * takes no action.
0663: *
0664: * @param id Session identifier of the Session to be removed
0665: *
0666: * @exception IOException if an input/output error occurs
0667: */
0668: public void remove(String id) throws IOException {
0669:
0670: synchronized (this ) {
0671: int numberOfTries = 2;
0672: while (numberOfTries > 0) {
0673: Connection _conn = getConnection();
0674:
0675: if (_conn == null) {
0676: return;
0677: }
0678:
0679: try {
0680: if (preparedRemoveSql == null) {
0681: String removeSql = "DELETE FROM "
0682: + sessionTable + " WHERE "
0683: + sessionIdCol + " = ? AND "
0684: + sessionAppCol + " = ?";
0685: preparedRemoveSql = _conn
0686: .prepareStatement(removeSql);
0687: }
0688:
0689: preparedRemoveSql.setString(1, id);
0690: preparedRemoveSql.setString(2, getName());
0691: preparedRemoveSql.execute();
0692: // Break out after the finally block
0693: numberOfTries = 0;
0694: } catch (SQLException e) {
0695: manager.getContainer().getLogger().error(
0696: sm.getString(getStoreName()
0697: + ".SQLException", e));
0698: if (dbConnection != null)
0699: close(dbConnection);
0700: } finally {
0701: release(_conn);
0702: }
0703: numberOfTries--;
0704: }
0705: }
0706:
0707: if (manager.getContainer().getLogger().isDebugEnabled()) {
0708: manager.getContainer().getLogger().debug(
0709: sm.getString(getStoreName() + ".removing", id,
0710: sessionTable));
0711: }
0712: }
0713:
0714: /**
0715: * Remove all of the Sessions in this Store.
0716: *
0717: * @exception IOException if an input/output error occurs
0718: */
0719: public void clear() throws IOException {
0720:
0721: synchronized (this ) {
0722: int numberOfTries = 2;
0723: while (numberOfTries > 0) {
0724: Connection _conn = getConnection();
0725: if (_conn == null) {
0726: return;
0727: }
0728:
0729: try {
0730: if (preparedClearSql == null) {
0731: String clearSql = "DELETE FROM " + sessionTable
0732: + " WHERE " + sessionAppCol + " = ?";
0733: preparedClearSql = _conn
0734: .prepareStatement(clearSql);
0735: }
0736:
0737: preparedClearSql.setString(1, getName());
0738: preparedClearSql.execute();
0739: // Break out after the finally block
0740: numberOfTries = 0;
0741: } catch (SQLException e) {
0742: manager.getContainer().getLogger().error(
0743: sm.getString(getStoreName()
0744: + ".SQLException", e));
0745: if (dbConnection != null)
0746: close(dbConnection);
0747: } finally {
0748: release(_conn);
0749: }
0750: numberOfTries--;
0751: }
0752: }
0753: }
0754:
0755: /**
0756: * Save a session to the Store.
0757: *
0758: * @param session the session to be stored
0759: * @exception IOException if an input/output error occurs
0760: */
0761: public void save(Session session) throws IOException {
0762: ObjectOutputStream oos = null;
0763: ByteArrayOutputStream bos = null;
0764: ByteArrayInputStream bis = null;
0765: InputStream in = null;
0766:
0767: synchronized (this ) {
0768: int numberOfTries = 2;
0769: while (numberOfTries > 0) {
0770: Connection _conn = getConnection();
0771: if (_conn == null) {
0772: return;
0773: }
0774:
0775: // If sessions already exist in DB, remove and insert again.
0776: // TODO:
0777: // * Check if ID exists in database and if so use UPDATE.
0778: remove(session.getIdInternal());
0779:
0780: try {
0781: bos = new ByteArrayOutputStream();
0782: oos = new ObjectOutputStream(
0783: new BufferedOutputStream(bos));
0784:
0785: ((StandardSession) session).writeObjectData(oos);
0786: oos.close();
0787: oos = null;
0788: byte[] obs = bos.toByteArray();
0789: int size = obs.length;
0790: bis = new ByteArrayInputStream(obs, 0, size);
0791: in = new BufferedInputStream(bis, size);
0792:
0793: if (preparedSaveSql == null) {
0794: String saveSql = "INSERT INTO " + sessionTable
0795: + " (" + sessionIdCol + ", "
0796: + sessionAppCol + ", " + sessionDataCol
0797: + ", " + sessionValidCol + ", "
0798: + sessionMaxInactiveCol + ", "
0799: + sessionLastAccessedCol
0800: + ") VALUES (?, ?, ?, ?, ?, ?)";
0801: preparedSaveSql = _conn
0802: .prepareStatement(saveSql);
0803: }
0804:
0805: preparedSaveSql.setString(1, session
0806: .getIdInternal());
0807: preparedSaveSql.setString(2, getName());
0808: preparedSaveSql.setBinaryStream(3, in, size);
0809: preparedSaveSql.setString(4,
0810: session.isValid() ? "1" : "0");
0811: preparedSaveSql.setInt(5, session
0812: .getMaxInactiveInterval());
0813: preparedSaveSql.setLong(6, session
0814: .getLastAccessedTime());
0815: preparedSaveSql.execute();
0816: // Break out after the finally block
0817: numberOfTries = 0;
0818: } catch (SQLException e) {
0819: manager.getContainer().getLogger().error(
0820: sm.getString(getStoreName()
0821: + ".SQLException", e));
0822: if (dbConnection != null)
0823: close(dbConnection);
0824: } catch (IOException e) {
0825: ;
0826: } finally {
0827: if (oos != null) {
0828: oos.close();
0829: }
0830: if (bis != null) {
0831: bis.close();
0832: }
0833: if (in != null) {
0834: in.close();
0835: }
0836:
0837: release(_conn);
0838: }
0839: numberOfTries--;
0840: }
0841: }
0842:
0843: if (manager.getContainer().getLogger().isDebugEnabled()) {
0844: manager.getContainer().getLogger().debug(
0845: sm.getString(getStoreName() + ".saving", session
0846: .getIdInternal(), sessionTable));
0847: }
0848: }
0849:
0850: // --------------------------------------------------------- Protected Methods
0851:
0852: /**
0853: * Check the connection associated with this store, if it's
0854: * <code>null</code> or closed try to reopen it.
0855: * Returns <code>null</code> if the connection could not be established.
0856: *
0857: * @return <code>Connection</code> if the connection suceeded
0858: */
0859: protected Connection getConnection() {
0860: try {
0861: if (dbConnection == null || dbConnection.isClosed()) {
0862: manager.getContainer().getLogger().info(
0863: sm.getString(getStoreName()
0864: + ".checkConnectionDBClosed"));
0865: open();
0866: if (dbConnection == null || dbConnection.isClosed()) {
0867: manager.getContainer().getLogger().info(
0868: sm.getString(getStoreName()
0869: + ".checkConnectionDBReOpenFail"));
0870: }
0871: }
0872: } catch (SQLException ex) {
0873: manager.getContainer().getLogger().error(
0874: sm.getString(getStoreName()
0875: + ".checkConnectionSQLException", ex
0876: .toString()));
0877: }
0878:
0879: return dbConnection;
0880: }
0881:
0882: /**
0883: * Open (if necessary) and return a database connection for use by
0884: * this Realm.
0885: *
0886: * @exception SQLException if a database error occurs
0887: */
0888: protected Connection open() throws SQLException {
0889:
0890: // Do nothing if there is a database connection already open
0891: if (dbConnection != null)
0892: return (dbConnection);
0893:
0894: // Instantiate our database driver if necessary
0895: if (driver == null) {
0896: try {
0897: Class clazz = Class.forName(driverName);
0898: driver = (Driver) clazz.newInstance();
0899: } catch (ClassNotFoundException ex) {
0900: manager
0901: .getContainer()
0902: .getLogger()
0903: .error(
0904: sm
0905: .getString(
0906: getStoreName()
0907: + ".checkConnectionClassNotFoundException",
0908: ex.toString()));
0909: } catch (InstantiationException ex) {
0910: manager
0911: .getContainer()
0912: .getLogger()
0913: .error(
0914: sm
0915: .getString(
0916: getStoreName()
0917: + ".checkConnectionClassNotFoundException",
0918: ex.toString()));
0919: } catch (IllegalAccessException ex) {
0920: manager
0921: .getContainer()
0922: .getLogger()
0923: .error(
0924: sm
0925: .getString(
0926: getStoreName()
0927: + ".checkConnectionClassNotFoundException",
0928: ex.toString()));
0929: }
0930: }
0931:
0932: // Open a new connection
0933: Properties props = new Properties();
0934: if (connectionName != null)
0935: props.put("user", connectionName);
0936: if (connectionPassword != null)
0937: props.put("password", connectionPassword);
0938: dbConnection = driver.connect(connectionURL, props);
0939: dbConnection.setAutoCommit(true);
0940: return (dbConnection);
0941:
0942: }
0943:
0944: /**
0945: * Close the specified database connection.
0946: *
0947: * @param dbConnection The connection to be closed
0948: */
0949: protected void close(Connection dbConnection) {
0950:
0951: // Do nothing if the database connection is already closed
0952: if (dbConnection == null)
0953: return;
0954:
0955: // Close our prepared statements (if any)
0956: try {
0957: preparedSizeSql.close();
0958: } catch (Throwable f) {
0959: ;
0960: }
0961: this .preparedSizeSql = null;
0962:
0963: try {
0964: preparedKeysSql.close();
0965: } catch (Throwable f) {
0966: ;
0967: }
0968: this .preparedKeysSql = null;
0969:
0970: try {
0971: preparedSaveSql.close();
0972: } catch (Throwable f) {
0973: ;
0974: }
0975: this .preparedSaveSql = null;
0976:
0977: try {
0978: preparedClearSql.close();
0979: } catch (Throwable f) {
0980: ;
0981: }
0982:
0983: try {
0984: preparedRemoveSql.close();
0985: } catch (Throwable f) {
0986: ;
0987: }
0988: this .preparedRemoveSql = null;
0989:
0990: try {
0991: preparedLoadSql.close();
0992: } catch (Throwable f) {
0993: ;
0994: }
0995: this .preparedLoadSql = null;
0996:
0997: // Close this database connection, and log any errors
0998: try {
0999: dbConnection.close();
1000: } catch (SQLException e) {
1001: manager.getContainer().getLogger().error(
1002: sm.getString(getStoreName() + ".close", e
1003: .toString())); // Just log it here
1004: } finally {
1005: this .dbConnection = null;
1006: }
1007:
1008: }
1009:
1010: /**
1011: * Release the connection, not needed here since the
1012: * connection is not associated with a connection pool.
1013: *
1014: * @param conn The connection to be released
1015: */
1016: protected void release(Connection conn) {
1017: ;
1018: }
1019:
1020: /**
1021: * Called once when this Store is first started.
1022: */
1023: public void start() throws LifecycleException {
1024: super .start();
1025:
1026: // Open connection to the database
1027: this .dbConnection = getConnection();
1028: }
1029:
1030: /**
1031: * Gracefully terminate everything associated with our db.
1032: * Called once when this Store is stopping.
1033: *
1034: */
1035: public void stop() throws LifecycleException {
1036: super .stop();
1037:
1038: // Close and release everything associated with our db.
1039: if (dbConnection != null) {
1040: try {
1041: dbConnection.commit();
1042: } catch (SQLException e) {
1043: ;
1044: }
1045: close(dbConnection);
1046: }
1047: }
1048: }
|