Source code: com/RuntimeCollective/webapps/bean/Session.java
1 /* $Header: /home/CVS/rjp/src/com/RuntimeCollective/webapps/bean/Session.java,v 1.16 2003/09/30 15:13:09 joe Exp $
2 * $Revision: 1.16 $
3 * $Date: 2003/09/30 15:13:09 $
4 *
5 * ====================================================================
6 *
7 * Josephine : http://www.runtime-collective.com/josephine/index.html
8 *
9 * Copyright (C) 2003 Runtime Collective
10 *
11 * This product includes software developed by the
12 * Apache Software Foundation (http://www.apache.org/).
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30 package com.RuntimeCollective.webapps.bean;
31
32 import java.sql.SQLException;
33 import java.util.Date;
34
35 import com.RuntimeCollective.webapps.RuntimeParameters;
36 import com.RuntimeCollective.webapps.bean.EntityBean;
37 import com.RuntimeCollective.webapps.bean.DateBean;
38 import com.RuntimeCollective.webapps.bean.User;
39 import com.RuntimeCollective.webapps.RuntimeDataSource;
40 import com.RuntimeCollective.webapps.EntityBeanStore;
41 import com.RuntimeCollective.webapps.DateUtils;
42 import com.RuntimeCollective.permission.SecurityConstants;
43
44 import java.text.SimpleDateFormat;
45 import java.util.ArrayList;
46 import java.util.Iterator;
47 import java.util.List;
48 import javax.servlet.http.HttpServletRequest;
49
50
51 /**
52 * The Session object is the identification that a User has logged in, and when.
53 * <p>
54 * It is particularly useful in conjunction with TrackedUsers. EditorCheckLogon supports it,
55 * but CheckLogon doesn't (yet).
56 * <p>
57 * It is recommended to use the updateSessionTag at the top of all JSP pages, for the Session to be
58 * kept up-to-date.
59 *
60 * @version $Id: Session.java,v 1.16 2003/09/30 15:13:09 joe Exp $
61 */
62 public class Session implements EntityBean {
63
64 /** The name of the database table for this bean type. */
65 public static final String DATABASE_TABLE = "user_session";
66
67 /* The name of this bean within the <code>EntityBeanStore</code>. */
68 public static String ENTITY_NAME = Session.class.getName();
69
70 /* The key under which this Session objects are stored under the User's HttpSessions. */
71 public static String SESSION_KEY = "sessionForThisSession";
72
73 /* The key under which the no of minutes until TimeOut is stored. */
74 public static String TIMEOUT_KEY = "noMinutesUntilSessionTimeOut";
75
76 /* Where the name of the page used to redirect after the Session has timed out, is stored. */
77 public static String TIMEOUT_PAGE_KEY = "redirectPageAfterSessionTimeOut";
78
79 /** Get the entity name of this entity bean, used to identify this bean within the <code>EntityBeanStore</code>.
80 * And also optionally used as the key for this bean on the HttpSession.
81 */
82 public String getEntityName() { return ENTITY_NAME; }
83
84
85 private static final String SELECT_DATA = "select id, user_id, creation_date, last_used_date FROM user_session WHERE id=";
86 private static final String DELETE_FROM = "delete from ";
87 private static final String WHERE_ID = " where id = ";
88 private static final String WHERE_T_ID = " t where t.id = ";
89 private static final String USER_ID = "user_id";
90 private static final String CREATION_DATE = "creation_date";
91 private static final String LAST_USED_DATE = "last_used_date";
92 private static final String AND = " and ";
93 private static final String SPACE = " ";
94 private static final String SPACE_OPEN = " (";
95 private static final String CLOSE = ")";
96 private static final String LOGON_USER_KEY = "logonUserKey";
97 private static final String UPDATE = "update ";
98 private static final String SET_LAST_USED_DATE = " set last_used_date = ";
99 private static final String SELECT_ID = "select id from ";
100 private static final String WHERE_USER = " where user_id = ";
101 private static final String LAST_USED = " - last_used_date >= 60 * ";
102
103 // == Constructors =================================================
104
105 /**
106 /* Called to make a new session.
107 */
108 public Session() throws SQLException {
109 this.id = RuntimeDataSource.nextId();
110 // Set creation date to now
111 setCreateDate( new Date() );
112 }
113
114 /** Get a sesssion from the RuntimeDataSource, given an id.
115 * @param id ID of the session.
116 * @exception SQLException is thrown if no such session exists.
117 */
118 public Session(int id) throws SQLException {
119 Object[] result = RuntimeDataSource.queryRow(SELECT_DATA+id);
120 if ( result != null ) {
121 setId( Integer.parseInt( result[0].toString() ) );
122 setTheUser( (User) RuntimeParameters.getStore().get(User.class.getName(), Integer.parseInt( result[1].toString() ) ) );
123 setCreateDate( DateBean.fromSql( result[2] ) );
124 if (result[3] != null)
125 setLastUsedDate(DateBean.fromSql(result[3]));
126 else
127 setLastUsedDate(null);
128 }
129 }
130
131
132 // == Properties ===================================================
133
134 /** The session's User. */
135 protected User theUser = null;
136 /** Get the session's User. */
137 public User getTheUser() { return this.theUser; }
138 /** Set the session's User. */
139 public void setTheUser(User theUser) { this.theUser = theUser; }
140
141 /** The date of the session */
142 protected Date createDate = null;
143 /** Get the date of the session */
144 public Date getCreateDate() { return this.createDate; }
145 /** Set the date of the session */
146 public void setCreateDate(Date createDate) { this.createDate = createDate; }
147
148 /** The last used date of the session */
149 protected Date lastUsedDate = null;
150 /** Get the date of the session */
151 public Date getLastUsedDate() { return this.lastUsedDate; }
152 /** Set the date of the session */
153 public void setLastUsedDate(Date lastUsedDate) { this.lastUsedDate = lastUsedDate; }
154
155 /** Whether this Session has timed out.
156 * @return a boolean
157 */
158 public boolean hasTimedOut() {
159 return (System.currentTimeMillis() - getLastUsedDate().getTime() > timeout_span_millis);
160 }
161
162 /** No of minutes until time out. */
163 protected int timeout_span_mins = Integer.parseInt(RuntimeParameters.get(TIMEOUT_KEY));
164
165 /** No of millis until time out. */
166 protected int timeout_span_millis = timeout_span_mins * 60000;
167
168 /** The session id */
169 protected int id = -1;
170 /** Get the session id */
171 public int getId() { return this.id; }
172 /** Set the session id */
173 public void setId(int id) { this.id = id; }
174
175 /** Save this session */
176 public void save() throws SQLException {
177 // Make an entry in user_session
178
179 // Check if theUser is null; if so, there's a problem!
180 if (getTheUser() == null) {
181 throw new SQLException ("Cannot save a session that does not have a user!");
182 }
183 Integer theUserId = new Integer(getTheUser().getId());
184
185 RuntimeDataSource.save(getId(), DATABASE_TABLE, new String[]{ USER_ID, CREATION_DATE, LAST_USED_DATE }, new Object[] { theUserId, getCreateDate(), getLastUsedDate() });
186 }
187
188 /** Tear down this session */
189 public void delete() throws SQLException {
190 // Deletes from user_session
191 RuntimeDataSource.update(DELETE_FROM+DATABASE_TABLE+WHERE_ID+getId());
192 }
193
194 /** Log a user in to the website.
195 * Put their User object on the HttpSession, create a new <code>Session</code>, and update the user's
196 * last login date on the Pivotal database.
197 */
198 public static Session logUserIn(User user, HttpServletRequest request) throws SQLException {
199
200 if (user==null) {
201 return null;
202 }
203
204 // Make a new session
205 Session newSession = (Session) RuntimeParameters.getStore().create(Session.class.getName());
206 newSession.setTheUser(user);
207 Date now = new Date();
208 newSession.setCreateDate(now);
209 newSession.setLastUsedDate(now);
210 RuntimeParameters.getStore().save(Session.class.getName(), newSession.getId());
211
212 // Put the user on the session, in the correct place
213 request.getSession().setAttribute(RuntimeParameters.get(LOGON_USER_KEY), user);
214 request.getSession().setAttribute(SecurityConstants.AUTH_TOKEN, new Integer(user.getId()));
215
216 return newSession;
217 }
218
219 /**
220 * Update the last used date in the db, by hitting it only once.
221 * This to make UpdateSessionTag more efficient.
222 */
223 public void doQuickUpdate() {
224 try {
225 RuntimeDataSource.update((new StringBuffer(100)).append(UPDATE).append(DATABASE_TABLE).append(SET_LAST_USED_DATE).append(RuntimeDataSource.toSqlString(lastUsedDate)).append(WHERE_ID).append(id).toString());
226 } catch (SQLException e) {
227 RuntimeParameters.logError(this, "Could not perform doQuickUpdate.", e);
228 }
229 }
230
231
232 /** The date format used. */
233 protected static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
234
235
236
237 /**
238 * Delete all expired Sessions for a given User.
239 */
240 public static void deleteExpiredSessionsForUser(User user) {
241
242 if (user == null)
243 return;
244
245 int userId = user.getId();
246
247 int returnVal = 0;
248 String nowString = df.format(DateUtils.getCurrentDate());
249 Session session;
250 EntityBeanStore ebs = RuntimeParameters.getStore();
251 int[] ids;
252
253 try {
254 ids = RuntimeDataSource.queryInts((new StringBuffer(90))
255 .append(SELECT_ID)
256 .append(Session.DATABASE_TABLE)
257 .append(WHERE_USER)
258 .append(userId)
259 .append(AND)
260 .append(RuntimeDataSource.toSqlString(new Date()))
261 .append(LAST_USED)
262 .append(RuntimeParameters.get(Session.TIMEOUT_KEY))
263 .toString());
264
265 for (int i=0; i < ids.length; i++) {
266 session = (Session) ebs.get(Session.class.getName(), ids[i]);
267 RuntimeParameters.log(session, "Session deleted by Session.deleteExpiredSessionsForUser.");
268 ebs.delete(session);
269 }
270
271 } catch (SQLException sqle) {
272 RuntimeParameters.logDebug("Session", "Unable to get number of active sessions from the database.");
273 }
274 }
275
276
277 /**
278 * Gets the number of active sessions, for all users.
279 */
280 public static int getNumberOfActiveSessions() {
281 return getActiveSessionsList().size();
282 }
283
284
285 /**
286 * Gets an Iterator of all active User beans in the system.
287 */
288 public static Iterator getUsersWithActiveSessions() {
289 return getUsersWithActiveSessionsAsList().iterator();
290 }
291
292 /**
293 * Gets a List of all active User beans in the system.
294 */
295 public static List getUsersWithActiveSessionsAsList() {
296 List sessions = getActiveSessionsList();
297 List users = new ArrayList(sessions.size());
298 for (int i=0; i<sessions.size(); i++) {
299 users.add(((Session) sessions.get(i)).getTheUser());
300 }
301 return users;
302 }
303
304 /**
305 * Gets a List of all active session.
306 */
307 public static List getActiveSessionsList() {
308
309 int[] ids;
310 ArrayList objects = new ArrayList();
311 String nowString = df.format(DateUtils.getCurrentDate());
312
313 try {
314 ids = RuntimeDataSource.queryInts((new StringBuffer(150)).append("select id from ").append(DATABASE_TABLE).append(" where last_used_date > timestamp without time zone '").append(nowString).append("' - interval '").append(RuntimeParameters.get(TIMEOUT_KEY)).append(" minutes'").toString());
315 for (int i=0; i < ids.length; i++) {
316 objects.add(RuntimeParameters.getStore().get(Session.class.getName(), ids[i]));
317 }
318 }
319 catch (SQLException sqle) {
320 RuntimeParameters.logDebug("Session", "Unable to get active sessions from the database.");
321 }
322
323 return objects;
324 }
325 }
326