Coverage Report - org.kuali.rice.kns.service.impl.SessionDocumentServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
SessionDocumentServiceImpl
0%
0/117
0%
0/28
1.833
SessionDocumentServiceImpl$1
N/A
N/A
1.833
SessionDocumentServiceImpl$CachedObject
0%
0/7
N/A
1.833
SessionDocumentServiceImpl$KualiLRUMap
0%
0/12
N/A
1.833
 
 1  
 /**
 2  
  * Copyright 2005-2011 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.kns.service.impl;
 17  
 
 18  
 import org.apache.commons.collections.map.LRUMap;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.apache.log4j.Logger;
 21  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 22  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 23  
 import org.kuali.rice.kew.api.WorkflowDocument;
 24  
 import org.kuali.rice.kew.api.KewApiConstants;
 25  
 import org.kuali.rice.kns.service.SessionDocumentService;
 26  
 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
 27  
 import org.kuali.rice.krad.UserSession;
 28  
 import org.kuali.rice.krad.bo.SessionDocument;
 29  
 import org.kuali.rice.krad.dao.SessionDocumentDao;
 30  
 import org.kuali.rice.krad.datadictionary.DocumentEntry;
 31  
 import org.kuali.rice.krad.service.BusinessObjectService;
 32  
 import org.kuali.rice.krad.service.DataDictionaryService;
 33  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 34  
 import org.springframework.beans.factory.InitializingBean;
 35  
 import org.springframework.transaction.annotation.Transactional;
 36  
 
 37  
 import java.io.ByteArrayInputStream;
 38  
 import java.io.ByteArrayOutputStream;
 39  
 import java.io.ObjectInputStream;
 40  
 import java.io.ObjectOutputStream;
 41  
 import java.sql.Timestamp;
 42  
 import java.util.Collections;
 43  
 import java.util.HashMap;
 44  
 import java.util.Map;
 45  
 
 46  
 /**
 47  
  * Implementation of <code>SessionDocumentService</code> that persists the document form
 48  
  * contents to the underlying database
 49  
  *
 50  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 51  
  */
 52  
 @Deprecated
 53  
 @Transactional
 54  0
 public class SessionDocumentServiceImpl implements SessionDocumentService, InitializingBean {
 55  0
     private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SessionDocumentServiceImpl.class);
 56  
 
 57  
     protected static final String IP_ADDRESS = "ipAddress";
 58  
     protected static final String PRINCIPAL_ID = "principalId";
 59  
     protected static final String DOCUMENT_NUMBER = "documentNumber";
 60  
     protected static final String SESSION_ID = "sessionId";
 61  
 
 62  
     private Map<String, CachedObject> cachedObjects;
 63  
     private EncryptionService encryptionService;
 64  
     private int maxCacheSize;
 65  
 
 66  
     private BusinessObjectService businessObjectService;
 67  
     private DataDictionaryService dataDictionaryService;
 68  
     private SessionDocumentDao sessionDocumentDao;
 69  
 
 70  
     private static class CachedObject {
 71  
         private UserSession userSession;
 72  
         private String formKey;
 73  
 
 74  0
         CachedObject(UserSession userSession, String formKey) {
 75  0
             this.userSession = userSession;
 76  0
             this.formKey = formKey;
 77  0
         }
 78  
 
 79  
         @Override
 80  
         public String toString() {
 81  0
             return "CachedObject: principalId=" + userSession.getPrincipalId() + " / objectWithFormKey=" +
 82  
                     userSession.retrieveObject(formKey);
 83  
         }
 84  
 
 85  
         public UserSession getUserSession() {
 86  0
             return this.userSession;
 87  
         }
 88  
 
 89  
         public String getFormKey() {
 90  0
             return this.formKey;
 91  
         }
 92  
     }
 93  
 
 94  
     /**
 95  
      * Override LRUMap removeEntity method
 96  
      *
 97  
      *
 98  
      */
 99  0
     private static class KualiLRUMap extends LRUMap {
 100  
 
 101  
         /** Serialization version */
 102  
         private static final long serialVersionUID = 1L;
 103  
 
 104  
         private KualiLRUMap() {
 105  0
             super();
 106  0
         }
 107  
 
 108  
         private KualiLRUMap(int maxSize) {
 109  0
             super(maxSize);
 110  0
         }
 111  
 
 112  
         @Override
 113  
         protected void removeEntry(HashEntry entry, int hashIndex, HashEntry previous) {
 114  
 
 115  
             // It is for session document cache enhancement.
 116  
             // To control the size of cache. When the LRUMap reach the maxsize.
 117  
             // It will remove session document entries from the in-memory user
 118  
             // session objects.
 119  
             try {
 120  0
                 CachedObject cachedObject
 121  
                         = (CachedObject)this.entryValue(entry);
 122  0
                 cachedObject.getUserSession().removeObject(cachedObject.getFormKey());
 123  0
             } catch (Exception ex) {
 124  0
                 Logger.getLogger(getClass()).warn( "Problem purging old entry from the user session when removing from the map: ", ex);
 125  0
             }
 126  
 
 127  0
             super.removeEntry(entry, hashIndex, previous);
 128  0
         }
 129  
 
 130  
     }
 131  
 
 132  
     @Override
 133  
     @SuppressWarnings("unchecked")
 134  
     public void afterPropertiesSet() throws Exception {
 135  0
         cachedObjects = Collections.synchronizedMap(new KualiLRUMap(maxCacheSize));
 136  0
     }
 137  
 
 138  
 
 139  
     @Override
 140  
     public KualiDocumentFormBase getDocumentForm(String documentNumber, String docFormKey, UserSession userSession,
 141  
             String ipAddress) {
 142  0
         KualiDocumentFormBase documentForm = null;
 143  
 
 144  0
         LOG.debug("getDocumentForm KualiDocumentFormBase from db");
 145  
         try {
 146  
             // re-create the KualiDocumentFormBase object
 147  0
             documentForm = (KualiDocumentFormBase) retrieveDocumentForm(userSession, userSession.getKualiSessionId(),
 148  
                     documentNumber, ipAddress);
 149  
 
 150  
             //re-store workFlowDocument into session
 151  0
             WorkflowDocument workflowDocument =
 152  
                     documentForm.getDocument().getDocumentHeader().getWorkflowDocument();
 153  0
             addDocumentToUserSession(userSession, workflowDocument);
 154  0
         } catch (Exception e) {
 155  0
             LOG.error("getDocumentForm failed for SessId/DocNum/PrinId/IP:" + userSession.getKualiSessionId() + "/" +
 156  
                     documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress, e);
 157  0
         }
 158  
 
 159  0
         return documentForm;
 160  
     }
 161  
 
 162  
     protected Object retrieveDocumentForm(UserSession userSession, String sessionId, String documentNumber,
 163  
             String ipAddress) throws Exception {
 164  0
         HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
 165  0
         primaryKeys.put(SESSION_ID, sessionId);
 166  0
         if (documentNumber != null) {
 167  0
             primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
 168  
         }
 169  0
         primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
 170  0
         primaryKeys.put(IP_ADDRESS, ipAddress);
 171  
 
 172  0
         SessionDocument sessionDoc = getBusinessObjectService().findByPrimaryKey(SessionDocument.class, primaryKeys);
 173  0
         if (sessionDoc != null) {
 174  0
             byte[] formAsBytes = sessionDoc.getSerializedDocumentForm();
 175  0
             if (sessionDoc.isEncrypted()) {
 176  0
                 formAsBytes = getEncryptionService().decryptBytes(formAsBytes);
 177  
             }
 178  0
             ByteArrayInputStream baip = new ByteArrayInputStream(formAsBytes);
 179  0
             ObjectInputStream ois = new ObjectInputStream(baip);
 180  
 
 181  0
             return ois.readObject();
 182  
         }
 183  
 
 184  0
         return null;
 185  
     }
 186  
 
 187  
     @Override
 188  
     public WorkflowDocument getDocumentFromSession(UserSession userSession, String docId) {
 189  0
         @SuppressWarnings("unchecked") Map<String, WorkflowDocument> workflowDocMap =
 190  
                 (Map<String, WorkflowDocument>) userSession
 191  
                         .retrieveObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME);
 192  
 
 193  0
         if (workflowDocMap == null) {
 194  0
             workflowDocMap = new HashMap<String, WorkflowDocument>();
 195  0
             userSession.addObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME, workflowDocMap);
 196  0
             return null;
 197  
         }
 198  0
         return workflowDocMap.get(docId);
 199  
     }
 200  
 
 201  
     /**
 202  
      * @see org.kuali.rice.krad.service.SessionDocumentService#addDocumentToUserSession(org.kuali.rice.krad.UserSession,
 203  
      *      org.kuali.rice.krad.workflow.service.KualiWorkflowDocument)
 204  
      */
 205  
     @Override
 206  
     public void addDocumentToUserSession(UserSession userSession, WorkflowDocument document) {
 207  0
         @SuppressWarnings("unchecked") Map<String, WorkflowDocument> workflowDocMap =
 208  
                 (Map<String, WorkflowDocument>) userSession
 209  
                         .retrieveObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME);
 210  0
         if (workflowDocMap == null) {
 211  0
             workflowDocMap = new HashMap<String, WorkflowDocument>();
 212  
         }
 213  0
         workflowDocMap.put(document.getDocumentId(), document);
 214  0
         userSession.addObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME, workflowDocMap);
 215  0
     }
 216  
 
 217  
     /**
 218  
      * @see org.kuali.rice.krad.service.SessionDocumentService#purgeDocumentForm(String
 219  
      *      documentNumber, String docFormKey, UserSession userSession)
 220  
      */
 221  
     @Override
 222  
     public void purgeDocumentForm(String documentNumber, String docFormKey, UserSession userSession, String ipAddress) {
 223  0
         synchronized (userSession) {
 224  
 
 225  0
             LOG.debug("purge document form from session");
 226  0
             userSession.removeObject(docFormKey);
 227  
             try {
 228  0
                 LOG.debug("purge document form from database");
 229  0
                 HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
 230  0
                 primaryKeys.put(SESSION_ID, userSession.getKualiSessionId());
 231  0
                 primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
 232  0
                 primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
 233  0
                 primaryKeys.put(IP_ADDRESS, ipAddress);
 234  0
                 getBusinessObjectService().deleteMatching(SessionDocument.class, primaryKeys);
 235  0
             } catch (Exception e) {
 236  0
                 LOG.error("purgeDocumentForm failed for SessId/DocNum/PrinId/IP:" + userSession.getKualiSessionId() +
 237  
                         "/" + documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress, e);
 238  0
             }
 239  0
         }
 240  0
     }
 241  
 
 242  
     @Override
 243  
     public void setDocumentForm(KualiDocumentFormBase form, UserSession userSession, String ipAddress) {
 244  0
         synchronized (userSession) {
 245  
             //formKey was set in KualiDocumentActionBase execute method
 246  0
             String formKey = form.getFormKey();
 247  0
             String key = userSession.getKualiSessionId() + "-" + formKey;
 248  0
             cachedObjects.put(key, new CachedObject(userSession, formKey));
 249  
 
 250  0
             String documentNumber = form.getDocument().getDocumentNumber();
 251  
 
 252  0
             if (StringUtils.isNotBlank(documentNumber)) {
 253  0
                 persistDocumentForm(form, userSession, ipAddress, userSession.getKualiSessionId(), documentNumber);
 254  
             } else {
 255  0
                 LOG.warn("documentNumber is null on form's document: " + form);
 256  
             }
 257  0
         }
 258  0
     }
 259  
 
 260  
     protected void persistDocumentForm(Object form, UserSession userSession, String ipAddress, String sessionId,
 261  
             String documentNumber) {
 262  
         try {
 263  0
             LOG.debug("set Document Form into database");
 264  0
             Timestamp currentTime = new Timestamp(System.currentTimeMillis());
 265  0
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 266  0
             ObjectOutputStream oos = new ObjectOutputStream(baos);
 267  0
             oos.writeObject(form);
 268  
             // serialize the KualiDocumentFormBase object into a byte array
 269  0
             byte[] formAsBytes = baos.toByteArray();
 270  0
             boolean encryptContent = false;
 271  
 
 272  0
             if ((form instanceof KualiDocumentFormBase) && ((KualiDocumentFormBase) form).getDocTypeName() != null) {
 273  0
                 DocumentEntry documentEntry = getDataDictionaryService().getDataDictionary()
 274  
                         .getDocumentEntry(((KualiDocumentFormBase) form).getDocTypeName());
 275  0
                 if (documentEntry != null) {
 276  0
                     encryptContent = documentEntry.isEncryptDocumentDataInPersistentSessionStorage();
 277  
                 }
 278  
             }
 279  0
             if (encryptContent) {
 280  0
                 formAsBytes = getEncryptionService().encryptBytes(formAsBytes);
 281  
             }
 282  
 
 283  
             // check if a record is already there in the database
 284  
             // this may only happen under jMeter testing, but there is no way to be sure
 285  0
             HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
 286  0
             primaryKeys.put(SESSION_ID, sessionId);
 287  0
             primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
 288  0
             primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
 289  0
             primaryKeys.put(IP_ADDRESS, ipAddress);
 290  
 
 291  0
             SessionDocument sessionDocument =
 292  
                     getBusinessObjectService().findByPrimaryKey(SessionDocument.class, primaryKeys);
 293  0
             if (sessionDocument == null) {
 294  0
                 sessionDocument = new SessionDocument();
 295  0
                 sessionDocument.setSessionId(sessionId);
 296  0
                 sessionDocument.setDocumentNumber(documentNumber);
 297  0
                 sessionDocument.setPrincipalId(userSession.getPrincipalId());
 298  0
                 sessionDocument.setIpAddress(ipAddress);
 299  
             }
 300  0
             sessionDocument.setSerializedDocumentForm(formAsBytes);
 301  0
             sessionDocument.setEncrypted(encryptContent);
 302  0
             sessionDocument.setLastUpdatedDate(currentTime);
 303  
 
 304  0
             businessObjectService.save(sessionDocument);
 305  0
         } catch (Exception e) {
 306  0
             final String className = form != null ? form.getClass().getName() : "null";
 307  0
             LOG.error("setDocumentForm failed for SessId/DocNum/PrinId/IP/class:" + userSession.getKualiSessionId() +
 308  
                     "/" + documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress + "/" + className, e);
 309  0
         }
 310  0
     }
 311  
 
 312  
     /**
 313  
      * @see org.kuali.rice.krad.service.SessionDocumentService#purgeAllSessionDocuments(java.sql.Timestamp)
 314  
      */
 315  
     @Override
 316  
     public void purgeAllSessionDocuments(Timestamp expirationDate) {
 317  0
         sessionDocumentDao.purgeAllSessionDocuments(expirationDate);
 318  0
     }
 319  
 
 320  
     protected SessionDocumentDao getSessionDocumentDao() {
 321  0
         return this.sessionDocumentDao;
 322  
     }
 323  
 
 324  
     public void setSessionDocumentDao(SessionDocumentDao sessionDocumentDao) {
 325  0
         this.sessionDocumentDao = sessionDocumentDao;
 326  0
     }
 327  
 
 328  
     protected BusinessObjectService getBusinessObjectService() {
 329  0
         return this.businessObjectService;
 330  
     }
 331  
 
 332  
     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
 333  0
         this.businessObjectService = businessObjectService;
 334  0
     }
 335  
 
 336  
     public int getMaxCacheSize() {
 337  0
         return maxCacheSize;
 338  
     }
 339  
 
 340  
     public void setMaxCacheSize(int maxCacheSize) {
 341  0
         this.maxCacheSize = maxCacheSize;
 342  0
     }
 343  
 
 344  
     protected EncryptionService getEncryptionService() {
 345  0
         if (encryptionService == null) {
 346  0
             encryptionService = CoreApiServiceLocator.getEncryptionService();
 347  
         }
 348  0
         return encryptionService;
 349  
     }
 350  
 
 351  
     protected DataDictionaryService getDataDictionaryService() {
 352  0
         if (dataDictionaryService == null) {
 353  0
             dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
 354  
         }
 355  0
         return dataDictionaryService;
 356  
     }
 357  
 }