001: /*
002: * Enhydra Java Application Server Project
003: *
004: * The contents of this file are subject to the Enhydra Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License on
007: * the Enhydra web site ( http://www.enhydra.org/ ).
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
011: * the License for the specific terms governing rights and limitations
012: * under the License.
013: *
014: * The Initial Developer of the Enhydra Application Server is Lutris
015: * Technologies, Inc. The Enhydra Application Server and portions created
016: * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
017: * All Rights Reserved.
018: *
019: * Contributor(s):
020: *
021: * $Id: PersistentSessionDO.java,v 1.2 2006-06-15 13:44:07 sinisa Exp $
022: */
023:
024: package com.lutris.appserver.server.sessionEnhydra.persistent;
025:
026: import java.io.ByteArrayInputStream;
027: import java.io.ByteArrayOutputStream;
028: import java.io.IOException;
029: import java.io.InputStream;
030: import java.io.ObjectInputStream;
031: import java.io.ObjectOutputStream;
032: import java.io.ObjectStreamClass;
033: import java.io.StreamCorruptedException;
034: import java.math.BigDecimal;
035: import java.sql.PreparedStatement;
036: import java.sql.ResultSet;
037: import java.sql.SQLException;
038: import java.sql.Types;
039:
040: import com.lutris.appserver.server.sql.DBConnection;
041: import com.lutris.appserver.server.sql.Transaction;
042: import com.lutris.appserver.server.user.User;
043:
044: /**
045: * Database interface for persistent session.
046: *
047: * @version $Revision: 1.2 $
048: * @author Kyle Clark
049: */
050: public class PersistentSessionDO implements Transaction {
051:
052: /**
053: * The session represented by this object.
054: */
055: private PersistentSession session;
056:
057: /**
058: * Holds the transaction status.
059: */
060: private boolean success = false;
061:
062: /**
063: * Holds the transaction row count.
064: */
065: private int rowCount = 0;
066:
067: /**
068: * @param session the session for which this data object
069: * will provide a database interface.
070: */
071: protected PersistentSessionDO(PersistentSession session) {
072: this .session = session;
073: }
074:
075: /**
076: * @param rs
077: * Result set from which to instantiate the session.
078: * @param loader
079: * The class loader to use when reconstructing the session
080: * from serialized data.
081: * @exception SQLException
082: * If a database connection error occurs.
083: * @exception IOException
084: * If the serialized session cannot be re-instantiated from the
085: * persistent data.
086: * @exception ClassNotFoundException
087: * If a class associated with the serialized session cannot
088: * be found.
089: */
090: public PersistentSessionDO(ResultSet rs, ClassLoader loader)
091: throws SQLException, IOException, ClassNotFoundException {
092: InputStream in = rs.getBinaryStream("data");
093: LoaderObjectInputStream objIn = new LoaderObjectInputStream(in,
094: loader);
095: session = (PersistentSession) objIn.readObject();
096: objIn.close();
097: }
098:
099: /**
100: * Inserts the session into the database.
101: *
102: * @param conn Database connection.
103: * @exception java.sql.SQLException If a database access error
104: * occurs or if the session data could not be serialized.
105: */
106: public void executeInsert(DBConnection conn) throws SQLException {
107: if (session == null) {
108: return;
109: }
110: String sql = "insert into " + PersistentSessionHome.dbTableName
111: + " values (?, ?, ?, ?, ?, ?, ?, ?, ?)";
112: PreparedStatement stmt = conn.prepareStatement(sql);
113: int param = 1;
114: stmt.setString(param++, session.getSessionKey());
115: if (session.isNew()) {
116: stmt.setString(param++, "1");
117: } else {
118: stmt.setString(param++, "0");
119: }
120: stmt.setBigDecimal(param++, new BigDecimal((double) session
121: .getTimeCreated()));
122: stmt.setBigDecimal(param++, new BigDecimal((double) session
123: .getTimeLastUsed()));
124: stmt.setBigDecimal(param++, new BigDecimal((double) session
125: .getTimeExpires()));
126: stmt.setBigDecimal(param++, new BigDecimal((double) session
127: .getMaxIdleTime()));
128: stmt.setBigDecimal(param++, new BigDecimal((double) session
129: .getMaxNoUserIdleTime()));
130: User user = session.getUser();
131: if (user != null) {
132: stmt.setString(param++, user.getName());
133: } else {
134: stmt.setNull(param++, Types.VARCHAR);
135: }
136: try {
137: InputStream in = getBinaryInputStream();
138: stmt.setBinaryStream(param++, in, in.available());
139: rowCount = conn.executeUpdate(stmt, sql);
140: in.close();
141: } catch (IOException e) {
142: throw new SQLException(e.getMessage());
143: }
144: }
145:
146: /**
147: * If this object's <code>executeInsert</code> method was
148: * called then <code>finalizeInsert</code> is called with
149: * the status of the database transaction. This method
150: * allows the data object to perform any post processing
151: * if the transaction succeeded or failed.
152: *
153: * @param success true if the transaction succeeded
154: * and this object was successfully inserted into the database.
155: */
156: public void finalizeInsert(boolean success) {
157: this .success = success;
158: if (!success) {
159: this .rowCount = 0;
160: }
161: }
162:
163: /**
164: * Method to update contents of object in database.
165: *
166: * @param conn Database connection.
167: * @exception java.sql.SQLException If a database access error
168: * occurs.
169: */
170: public void executeUpdate(DBConnection conn) throws SQLException {
171: String sql = "update "
172: + PersistentSessionHome.dbTableName
173: + " set isNew = ?, timeCreated = ?, timeLastUsed = ?, "
174: + " timeExpires = ?, maxIdleTime = ?, maxNoUserIdleTime = ?, "
175: + " userName = ?, data = ? where sessionKey = ?";
176: PreparedStatement stmt = conn.prepareStatement(sql);
177: int param = 1;
178: if (session.isNew()) {
179: stmt.setString(param++, "1");
180: } else {
181: stmt.setString(param++, "0");
182: }
183: stmt.setBigDecimal(param++, new BigDecimal((double) session
184: .getTimeCreated()));
185: stmt.setBigDecimal(param++, new BigDecimal((double) session
186: .getTimeLastUsed()));
187: stmt.setBigDecimal(param++, new BigDecimal((double) session
188: .getTimeExpires()));
189: stmt.setBigDecimal(param++, new BigDecimal((double) session
190: .getMaxIdleTime()));
191: stmt.setBigDecimal(param++, new BigDecimal((double) session
192: .getMaxNoUserIdleTime()));
193: User user = session.getUser();
194: if (user != null) {
195: stmt.setString(param++, user.getName());
196: } else {
197: stmt.setNull(param++, Types.VARCHAR);
198: }
199: try {
200: InputStream in = getBinaryInputStream();
201: stmt.setBinaryStream(param++, in, in.available());
202: stmt.setString(param++, session.getSessionKey());
203: rowCount = conn.executeUpdate(stmt, sql);
204: in.close();
205: } catch (IOException e) {
206: throw new SQLException(e.getMessage());
207: }
208: }
209:
210: /**
211: * If this object's <code>executeUpdate</code> method was
212: * called then <code>finalizeUpdate</code> is called with
213: * the status of the database transaction.
214: * For instance the data object may want to
215: * increment its version number once it has successfully
216: * been commited to the database.
217: *
218: * @param success true if the transaction succeeded
219: * and this object was successfully updated in the database.
220: */
221: public void finalizeUpdate(boolean success) {
222: this .success = success;
223: if (!success) {
224: this .rowCount = 0;
225: }
226: }
227:
228: /**
229: * Method to delete an object from the database.
230: *
231: * @param conn Database connection.
232: * @exception java.sql.SQLException If a database access error
233: * occurs.
234: */
235: public void executeDelete(DBConnection conn) throws SQLException {
236: String sql = "delete from " + PersistentSessionHome.dbTableName
237: + " where sessionKey = ?";
238: PreparedStatement stmt = conn.prepareStatement(sql);
239: stmt.setString(1, session.getSessionKey());
240: rowCount = conn.executeUpdate(stmt, sql);
241: }
242:
243: /**
244: * If this object's <code>executeDelete</code> method was
245: * called then <code>finalizeDelete</code> is called with
246: * the status of the database transaction.
247: *
248: * @param success true if the transaction succeeded
249: * and this object was successfully deleted from the
250: * database.
251: */
252: public void finalizeDelete(boolean success) {
253: this .success = success;
254: if (!success) {
255: this .rowCount = 0;
256: }
257: }
258:
259: /**
260: * Returns an input stream containing the serialized
261: * session data.
262: *
263: * @return the input stream.
264: */
265: private InputStream getBinaryInputStream() throws IOException {
266: ByteArrayOutputStream out = new ByteArrayOutputStream();
267: ObjectOutputStream objOut = new ObjectOutputStream(out);
268: objOut.writeObject(session);
269: objOut.flush();
270: ByteArrayInputStream in = new ByteArrayInputStream(out
271: .toByteArray());
272: objOut.close();
273: return in;
274: }
275:
276: /**
277: * Returns the session for which this data object is
278: * acting as a data base interface.
279: *
280: * @return the session
281: */
282: PersistentSession getSession() {
283: return session;
284: }
285:
286: /**
287: * Returns the transaction status.
288: *
289: * @return the transaction status.
290: */
291: boolean getTransactionStatus() {
292: return success;
293: }
294:
295: /**
296: * Returns the transaction count - i.e. the number
297: * of rows affected in the transaction.
298: */
299: int getTransactionRowCount() {
300: return rowCount;
301: }
302: }
303:
304: // Internal class that can load objects with the loader we specify.
305: class LoaderObjectInputStream extends ObjectInputStream {
306:
307: private ClassLoader loader;
308:
309: public LoaderObjectInputStream(InputStream in, ClassLoader loader)
310: throws IOException, StreamCorruptedException {
311: super (in);
312: this .loader = loader;
313: }
314:
315: /**
316: * Subclasses may implement this method to allow classes to be
317: * fetched from an alternate source.
318: *
319: * The corresponding method in ObjectOutputStream is
320: * annotateClass. This method will be invoked only once for each
321: * unique class in the stream. This method can be implemented by
322: * subclasses to use an alternate loading mechanism but must
323: * return a Class object. Once returned, the serialVersionUID of the
324: * class is compared to the serialVersionUID of the serialized class.
325: * If there is a mismatch, the deserialization fails and an exception
326: * is raised. <p>
327: *
328: * By default the class name is resolved relative to the class
329: * that called readObject. <p>
330: *
331: * @exception ClassNotFoundException If class of
332: * a serialized object cannot be found.
333: * @since JDK1.1
334: */
335: protected Class resolveClass(ObjectStreamClass v)
336: throws IOException, ClassNotFoundException {
337: if (loader != null) {
338: return loader.loadClass(v.getName());
339: } else {
340: return super.resolveClass(v);
341: }
342: }
343:
344: }
|