Coverage Report - org.kuali.rice.kim.sesn.DistributedSession
 
Classes in this File Line Coverage Branch Coverage Complexity
DistributedSession
0%
0/90
0%
0/24
2.071
 
 1  
 /*
 2  
  * Copyright 2007-2008 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kim.sesn;
 17  
 
 18  
 import java.util.Date;
 19  
 import java.util.HashMap;
 20  
 import java.util.Iterator;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 
 24  
 import org.apache.commons.logging.Log;
 25  
 import org.apache.commons.logging.LogFactory;
 26  
 import org.kuali.rice.kim.sesn.timeouthandlers.TimeoutHandler;
 27  
 import org.springframework.dao.IncorrectResultSizeDataAccessException;
 28  
 import org.springframework.jdbc.core.JdbcTemplate;
 29  
 
 30  
 /**
 31  
  * This class is used to interface with the distributed session database.
 32  
  * 
 33  
  * TODO: add clear principals to clearSesn
 34  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 35  
  *
 36  
  */
 37  0
 public class DistributedSession {
 38  
     public static final String DEFAULT_PREFIX="DST";
 39  0
     private static String prefix = DEFAULT_PREFIX;
 40  
     private JdbcTemplate jdbcTemplate;
 41  
     private TimeoutHandler timeoutHandler;
 42  0
     private boolean allowInsertOnTouch = false;
 43  
     
 44  0
     private static final Log logger = LogFactory.getLog(DistributedSession.class);
 45  
 
 46  
     /**
 47  
      * @param timeoutHandler the timeoutHandler to set
 48  
      */
 49  
     public void setTimeoutHandler(TimeoutHandler timeoutHandler) {
 50  0
         this.timeoutHandler = timeoutHandler;
 51  0
     }
 52  
 
 53  
     /**
 54  
      * @param jdbcTemplate the jdbcTemplate to set
 55  
      */
 56  
     public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
 57  0
         this.jdbcTemplate = jdbcTemplate;
 58  0
     }
 59  
     
 60  
     /**
 61  
      * This method determines if the Session Ticket is valid.
 62  
      * 
 63  
      * @param DST - the Distributed Session Ticket
 64  
      * @return true if the session is valid
 65  
      */
 66  
     public boolean isSesnValid(String DST) {
 67  0
         logger.debug("isSesnValid(DST)");
 68  0
         return isSesnValid (DST, new HashMap<String,Object>());
 69  
     }
 70  
     
 71  
     /**
 72  
      * This method determines if the Session Ticket is valid.
 73  
      * 
 74  
      * @param DST - the Distributed Session Ticket
 75  
      * @param timoutArgs - Additional information on which to base timeouts
 76  
      * @return true if the session is valid
 77  
      */
 78  
     public boolean isSesnValid(String DST, Map<String,Object> timeoutArgs) {
 79  0
         logger.debug("isSesnValid(DST, timeoutArgs)");
 80  0
         boolean bRet = false;
 81  0
         String sql = "select sesnID, lastAccessDt, maxIdleTime from authnsesn where sesnID=?";
 82  
         
 83  0
         if (DST != null) {
 84  0
             Object[] args = { DST };
 85  
             
 86  
             try {
 87  0
                 Map<String,Object> fields = jdbcTemplate.queryForMap(sql, args);
 88  0
                 fields.put("maxIdleTime", this.getMaxIdleTime((Long)fields.get("maxIdleTime"), (Date)fields.get("lastAccessDt")));
 89  0
                 fields.putAll(timeoutArgs);
 90  
                 
 91  0
                 if (logger.isDebugEnabled()) {
 92  0
                     logger.debug("ARGUMENTS number:" + fields.size());
 93  0
                     for (Iterator<Map.Entry<String,Object>> i = fields.entrySet().iterator(); i.hasNext(); ) {
 94  0
                         Map.Entry<String,Object> entry = (Map.Entry<String,Object>)i.next();
 95  0
                         logger.debug("ARGUMENT " + entry.getKey() + ":" + entry.getValue());
 96  0
                     }
 97  
                 }
 98  
                 
 99  0
                 if(!timeoutHandler.hasTimedOut(fields)) {
 100  0
                     logger.debug("Session not timed out");
 101  0
                     bRet = true;
 102  
                 } else {
 103  0
                     logger.debug("Session timed out");
 104  
                 }
 105  0
             } catch (Exception e) {
 106  0
                 logger.debug(e);
 107  0
             }
 108  0
         } 
 109  
         else {
 110  0
             logger.debug("Session ID is null");           
 111  
         }
 112  
                 
 113  0
         return bRet;
 114  
     }
 115  
     
 116  
     
 117  
     /**
 118  
      * This method returns the list of principals currently authenticated
 119  
      * that are associated with the provided Distributed Session Ticket
 120  
      * 
 121  
      * @param DST - the Distributed Session Ticket
 122  
      * @return the List of authenticated principals
 123  
      */
 124  
     public List<String> getAuthenticatedPricipals(String DST) {
 125  0
         String sql = "select principalID from authnsesn where sesnID=?";
 126  0
         Object args[] = { DST };
 127  
         
 128  0
         return jdbcTemplate.queryForList(sql, args, String.class);
 129  
     }
 130  
     
 131  
     /**
 132  
      * This method removes the session
 133  
      * 
 134  
      * @param DST - the Distributed Session Ticket
 135  
      */
 136  
     public void clearSesn(String DST) {
 137  0
         String sql = "delete from authnsesn where sesnID='" + DST + "'";
 138  
         
 139  0
         jdbcTemplate.execute(sql);
 140  0
     }
 141  
     
 142  
     
 143  
     /**
 144  
      * This method takes an authenticated principal and generates a
 145  
      * Distributed Session Ticket and updates the session database
 146  
      * 
 147  
      * @param principalID - the id of the authenticated entity
 148  
      * @return DST - the Distributed Session Ticket
 149  
      */
 150  
     public String createSesn(String principalID) {
 151  0
         String DST = this.generateDST();
 152  
         
 153  0
         this.touchSesn(DST);
 154  0
         this.addPrincipalToSesn(DST, principalID);
 155  
 
 156  0
         return DST;
 157  
     }
 158  
     
 159  
     /**
 160  
      * This method generates a unique Distributed Session Ticket
 161  
      * 
 162  
      * @return DST - the Distributed Session Ticket
 163  
      */
 164  
     public String generateDST() {
 165  0
         return prefix + "-" + SessionIdGenerator.getNewString();
 166  
     }
 167  
     
 168  
     /**
 169  
      * This method updates the session
 170  
      * 
 171  
      * @param DST - the Distributed Session Ticket
 172  
      */
 173  
     public void touchSesn(String DST) {
 174  0
         String sql = "select lastAccessDt, maxIdleTime from authnsesn where sesnID=?";
 175  0
         String updateSql = "";
 176  0
         Object[] args = { DST },
 177  
                updateArgs;
 178  
         Long maxIdleTime;
 179  
         
 180  
         try {
 181  0
             if (logger.isDebugEnabled()) {
 182  0
                 logger.debug("ARGUMENTS number:" + args.length);
 183  0
                 logger.debug("ARGUMENTS 0:" + args[0]);
 184  
             }
 185  0
             Map<String,Object> fields = jdbcTemplate.queryForMap(sql, args);
 186  0
             Date lastAccessDt = (Date)fields.get("lastAccessDt");
 187  0
             if (logger.isDebugEnabled()) {
 188  0
                 logger.debug("Last Access:" + lastAccessDt);
 189  
             }
 190  0
             maxIdleTime = getMaxIdleTime((Long)fields.get("maxIdleTime"), lastAccessDt);
 191  
             
 192  
             
 193  0
             updateSql = "update authnsesn set lastAccessDt=NOW(), maxIdleTime = ? where sesnID=?";
 194  0
             updateArgs = new Object[] { maxIdleTime, DST };
 195  0
             jdbcTemplate.update(updateSql, updateArgs);
 196  
         } 
 197  
         // catch if no or more than 1 results are returned
 198  0
         catch (IncorrectResultSizeDataAccessException ex) {
 199  0
             if (this.allowInsertOnTouch) {
 200  0
                 maxIdleTime = new Long(0);
 201  
                 
 202  0
                 updateSql = "insert into authnsesn (sesnID, insertDt, lastAccessDt, maxIdleTime) values (?, NOW(), NOW(), ?)";
 203  0
                 updateArgs = new Object[] { DST, maxIdleTime };
 204  0
                 jdbcTemplate.update(updateSql, updateArgs);
 205  
             }
 206  0
         }
 207  0
     }
 208  
     
 209  
     
 210  
     /**
 211  
      * This method returns the greater of the stored max idle time and 
 212  
      * time since last access
 213  
      * 
 214  
      * @param oldMaxIdleTime - the previous max idle time
 215  
      * @param lastAccessDt - the timestamp of last access
 216  
      * @return the max idle time
 217  
      */
 218  
     public Long getMaxIdleTime(Long oldMaxIdleTime, Date lastAccessDt) {
 219  0
         Long maxIdleTime = oldMaxIdleTime;
 220  
         
 221  0
         if (logger.isDebugEnabled()) {
 222  0
             logger.debug("Max Idle:" + maxIdleTime);
 223  
         }
 224  0
         long curIdleTime = System.currentTimeMillis()-lastAccessDt.getTime();
 225  0
         if (logger.isDebugEnabled()) {
 226  0
             logger.debug("Curr Idle:" + curIdleTime);
 227  
         }
 228  0
         if (curIdleTime > maxIdleTime) {
 229  0
             maxIdleTime = new Long(curIdleTime);
 230  
         }
 231  
         
 232  0
         return maxIdleTime;
 233  
     }
 234  
     
 235  
     /**
 236  
      * This method appends a principal to an active session
 237  
      * 
 238  
      * @param DST - the Distributed Session Ticket
 239  
      * @param principalID - the id of the authenticated entity
 240  
      */
 241  
     public void addPrincipalToSesn(String DST, String principalID) {
 242  
         // this will fail if the record already exists 
 243  
         try {
 244  0
             String updateSql = "insert into authnsesnprincipal (sesnID, principalID) values (?, ?)";
 245  
             
 246  0
             jdbcTemplate.update(updateSql, new Object[] { DST, principalID });
 247  0
             if (logger.isDebugEnabled()) {
 248  0
                 logger.debug("Added Principal to Sesn:" + principalID + " " + DST);
 249  
             }
 250  
         }
 251  0
         catch (Exception e) {
 252  0
             if (logger.isDebugEnabled()) {
 253  0
                 logger.debug("Principal Probably already exists:" + principalID + " " + DST);
 254  
             }
 255  0
         }
 256  0
     }
 257  
 
 258  
     /**
 259  
      * @return the prefix
 260  
      */
 261  
     public static String getPrefix() {
 262  0
         return DistributedSession.prefix;
 263  
     }
 264  
 
 265  
     /**
 266  
      * @param prefix the prefix to set
 267  
      */
 268  
     public static void setPrefix(String prefix) {
 269  0
         DistributedSession.prefix = prefix;
 270  0
     }
 271  
 
 272  
     /**
 273  
      * @param allowInsertOnTouch the allowInsertOnTouch to set
 274  
      */
 275  
     public void setAllowInsertOnTouch(boolean allowInsertOnTouch) {
 276  0
         this.allowInsertOnTouch = allowInsertOnTouch;
 277  0
     }
 278  
 }