View Javadoc

1   /**
2    * Copyright 2005-2013 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.krad.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.CoreApiServiceLocator;
20  import org.kuali.rice.core.api.encryption.EncryptionService;
21  import org.kuali.rice.kew.api.WorkflowDocument;
22  import org.kuali.rice.krad.UserSession;
23  import org.kuali.rice.krad.UserSessionUtils;
24  import org.kuali.rice.krad.bo.SessionDocument;
25  import org.kuali.rice.krad.dao.SessionDocumentDao;
26  import org.kuali.rice.krad.datadictionary.DocumentEntry;
27  import org.kuali.rice.krad.service.BusinessObjectService;
28  import org.kuali.rice.krad.service.DataDictionaryService;
29  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
30  import org.kuali.rice.krad.service.SessionDocumentService;
31  import org.kuali.rice.krad.web.form.DocumentFormBase;
32  import org.springframework.transaction.annotation.Transactional;
33  
34  import java.io.ByteArrayInputStream;
35  import java.io.ByteArrayOutputStream;
36  import java.io.ObjectInputStream;
37  import java.io.ObjectOutputStream;
38  import java.sql.Timestamp;
39  import java.util.HashMap;
40  
41  /**
42   * Implementation of <code>SessionDocumentService</code> that persists the document form
43   * contents to the underlying database
44   *
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  @Transactional
48  public class SessionDocumentServiceImpl implements SessionDocumentService {
49      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SessionDocumentServiceImpl.class);
50  
51      protected static final String IP_ADDRESS = "ipAddress";
52      protected static final String PRINCIPAL_ID = "principalId";
53      protected static final String DOCUMENT_NUMBER = "documentNumber";
54      protected static final String SESSION_ID = "sessionId";
55  
56      private EncryptionService encryptionService;
57  
58      private BusinessObjectService businessObjectService;
59      private DataDictionaryService dataDictionaryService;
60      private SessionDocumentDao sessionDocumentDao;
61  
62      @Override
63      public DocumentFormBase getDocumentForm(String documentNumber, String docFormKey, UserSession userSession,
64              String ipAddress) {
65          DocumentFormBase documentForm = null;
66  
67          LOG.debug("getDocumentForm DocumentFormBase from db");
68          try {
69              // re-create the DocumentFormBase object
70              documentForm = (DocumentFormBase) retrieveDocumentForm(userSession, docFormKey, documentNumber, ipAddress);
71  
72              //re-store workFlowDocument into session
73              WorkflowDocument workflowDocument =
74                      documentForm.getDocument().getDocumentHeader().getWorkflowDocument();
75              UserSessionUtils.addWorkflowDocument(userSession, workflowDocument);
76          } catch (Exception e) {
77              LOG.error("getDocumentForm failed for SessId/DocNum/PrinId/IP:" + userSession.getKualiSessionId() + "/" +
78                      documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress, e);
79          }
80  
81          return documentForm;
82      }
83  
84      protected Object retrieveDocumentForm(UserSession userSession, String sessionId, String documentNumber,
85              String ipAddress) throws Exception {
86          HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
87          primaryKeys.put(SESSION_ID, sessionId);
88          if (documentNumber != null) {
89              primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
90          }
91          primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
92          primaryKeys.put(IP_ADDRESS, ipAddress);
93  
94          SessionDocument sessionDoc = getBusinessObjectService().findByPrimaryKey(SessionDocument.class, primaryKeys);
95          if (sessionDoc != null) {
96              byte[] formAsBytes = sessionDoc.getSerializedDocumentForm();
97              if (sessionDoc.isEncrypted()) {
98                  formAsBytes = getEncryptionService().decryptBytes(formAsBytes);
99              }
100             ByteArrayInputStream baip = new ByteArrayInputStream(formAsBytes);
101             ObjectInputStream ois = new ObjectInputStream(baip);
102 
103             return ois.readObject();
104         }
105 
106         return null;
107     }
108 
109     @Override
110     public WorkflowDocument getDocumentFromSession(UserSession userSession, String docId) {
111         return UserSessionUtils.getWorkflowDocument(userSession, docId);
112     }
113 
114     /**
115      * @see org.kuali.rice.krad.service.SessionDocumentService#addDocumentToUserSession(org.kuali.rice.krad.UserSession,
116      *      org.kuali.rice.kew.api.WorkflowDocument)
117      */
118     @Override
119     public void addDocumentToUserSession(UserSession userSession, WorkflowDocument document) {
120         UserSessionUtils.addWorkflowDocument(userSession, document);
121     }
122 
123     /**
124      * @see org.kuali.rice.krad.service.SessionDocumentService#purgeDocumentForm(String, String,
125      *      org.kuali.rice.krad.UserSession, String)
126      */
127     @Override
128     public void purgeDocumentForm(String documentNumber, String docFormKey, UserSession userSession, String ipAddress) {
129         synchronized (userSession) {
130 
131             LOG.debug("purge document form from session");
132             userSession.removeObject(docFormKey);
133             try {
134                 LOG.debug("purge document form from database");
135                 HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
136                 primaryKeys.put(SESSION_ID, userSession.getKualiSessionId());
137                 primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
138                 primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
139                 primaryKeys.put(IP_ADDRESS, ipAddress);
140                 getBusinessObjectService().deleteMatching(SessionDocument.class, primaryKeys);
141             } catch (Exception e) {
142                 LOG.error("purgeDocumentForm failed for SessId/DocNum/PrinId/IP:" + userSession.getKualiSessionId() +
143                         "/" + documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress, e);
144             }
145         }
146     }
147 
148     @Override
149     public void setDocumentForm(DocumentFormBase form, UserSession userSession, String ipAddress) {
150         synchronized (userSession) {
151             //formKey was set in KualiDocumentActionBase execute method
152             String formKey = form.getFormKey();
153             String key = userSession.getKualiSessionId() + "-" + formKey;
154 
155             String documentNumber = form.getDocument().getDocumentNumber();
156             if (StringUtils.isNotBlank(formKey)) {
157                 //FIXME: Currently using formKey for sessionId
158                 persistDocumentForm(form, userSession, ipAddress, formKey, documentNumber);
159             } else {
160                 LOG.warn("documentNumber is null on form's document: " + form);
161             }
162         }
163     }
164 
165     protected void persistDocumentForm(DocumentFormBase form, UserSession userSession, String ipAddress,
166             String sessionId, String documentNumber) {
167         try {
168             LOG.debug("set Document Form into database");
169 
170             Timestamp currentTime = new Timestamp(System.currentTimeMillis());
171             ByteArrayOutputStream baos = new ByteArrayOutputStream();
172             ObjectOutputStream oos = new ObjectOutputStream(baos);
173             oos.writeObject(form);
174 
175             // serialize the DocumentFormBase object into a byte array
176             byte[] formAsBytes = baos.toByteArray();
177             boolean encryptContent = false;
178             DocumentEntry documentEntry =
179                     getDataDictionaryService().getDataDictionary().getDocumentEntry(form.getDocTypeName());
180             if (documentEntry != null) {
181                 encryptContent = documentEntry.isEncryptDocumentDataInPersistentSessionStorage();
182             }
183 
184             if (encryptContent) {
185                 formAsBytes = getEncryptionService().encryptBytes(formAsBytes);
186             }
187 
188             // check if a record is already there in the database
189             // this may only happen under jMeter testing, but there is no way to be sure
190             HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
191             primaryKeys.put(SESSION_ID, sessionId);
192             primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
193             primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
194             primaryKeys.put(IP_ADDRESS, ipAddress);
195 
196             SessionDocument sessionDocument =
197                     getBusinessObjectService().findByPrimaryKey(SessionDocument.class, primaryKeys);
198             if (sessionDocument == null) {
199                 sessionDocument = new SessionDocument();
200                 sessionDocument.setSessionId(sessionId);
201                 sessionDocument.setDocumentNumber(documentNumber);
202                 sessionDocument.setPrincipalId(userSession.getPrincipalId());
203                 sessionDocument.setIpAddress(ipAddress);
204             }
205             sessionDocument.setSerializedDocumentForm(formAsBytes);
206             sessionDocument.setEncrypted(encryptContent);
207             sessionDocument.setLastUpdatedDate(currentTime);
208 
209             businessObjectService.save(sessionDocument);
210         } catch (Exception e) {
211             final String className = form != null ? form.getClass().getName() : "null";
212             LOG.error("setDocumentForm failed for SessId/DocNum/PrinId/IP/class:" + userSession.getKualiSessionId() +
213                     "/" + documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress + "/" + className, e);
214         }
215     }
216 
217     /**
218      * @see org.kuali.rice.krad.service.SessionDocumentService#purgeAllSessionDocuments(java.sql.Timestamp)
219      */
220     @Override
221     public void purgeAllSessionDocuments(Timestamp expirationDate) {
222         sessionDocumentDao.purgeAllSessionDocuments(expirationDate);
223     }
224 
225     protected SessionDocumentDao getSessionDocumentDao() {
226         return this.sessionDocumentDao;
227     }
228 
229     public void setSessionDocumentDao(SessionDocumentDao sessionDocumentDao) {
230         this.sessionDocumentDao = sessionDocumentDao;
231     }
232 
233     protected BusinessObjectService getBusinessObjectService() {
234         return this.businessObjectService;
235     }
236 
237     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
238         this.businessObjectService = businessObjectService;
239     }
240 
241     protected EncryptionService getEncryptionService() {
242         if (encryptionService == null) {
243             encryptionService = CoreApiServiceLocator.getEncryptionService();
244         }
245         return encryptionService;
246     }
247 
248     protected DataDictionaryService getDataDictionaryService() {
249         if (dataDictionaryService == null) {
250             dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
251         }
252         return dataDictionaryService;
253     }
254 }