1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
48
49
50
51
52 @Deprecated
53 @Transactional
54 public class SessionDocumentServiceImpl implements SessionDocumentService, InitializingBean {
55 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 CachedObject(UserSession userSession, String formKey) {
75 this.userSession = userSession;
76 this.formKey = formKey;
77 }
78
79 @Override
80 public String toString() {
81 return "CachedObject: principalId=" + userSession.getPrincipalId() + " / objectWithFormKey=" +
82 userSession.retrieveObject(formKey);
83 }
84
85 public UserSession getUserSession() {
86 return this.userSession;
87 }
88
89 public String getFormKey() {
90 return this.formKey;
91 }
92 }
93
94
95
96
97
98
99 private static class KualiLRUMap extends LRUMap {
100
101
102 private static final long serialVersionUID = 1L;
103
104 private KualiLRUMap() {
105 super();
106 }
107
108 private KualiLRUMap(int maxSize) {
109 super(maxSize);
110 }
111
112 @Override
113 protected void removeEntry(HashEntry entry, int hashIndex, HashEntry previous) {
114
115
116
117
118
119 try {
120 CachedObject cachedObject
121 = (CachedObject)this.entryValue(entry);
122 cachedObject.getUserSession().removeObject(cachedObject.getFormKey());
123 } catch (Exception ex) {
124 Logger.getLogger(getClass()).warn( "Problem purging old entry from the user session when removing from the map: ", ex);
125 }
126
127 super.removeEntry(entry, hashIndex, previous);
128 }
129
130 }
131
132 @Override
133 @SuppressWarnings("unchecked")
134 public void afterPropertiesSet() throws Exception {
135 cachedObjects = Collections.synchronizedMap(new KualiLRUMap(maxCacheSize));
136 }
137
138
139 @Override
140 public KualiDocumentFormBase getDocumentForm(String documentNumber, String docFormKey, UserSession userSession,
141 String ipAddress) {
142 KualiDocumentFormBase documentForm = null;
143
144 LOG.debug("getDocumentForm KualiDocumentFormBase from db");
145 try {
146
147 documentForm = (KualiDocumentFormBase) retrieveDocumentForm(userSession, userSession.getKualiSessionId(),
148 documentNumber, ipAddress);
149
150
151 WorkflowDocument workflowDocument =
152 documentForm.getDocument().getDocumentHeader().getWorkflowDocument();
153 addDocumentToUserSession(userSession, workflowDocument);
154 } catch (Exception e) {
155 LOG.error("getDocumentForm failed for SessId/DocNum/PrinId/IP:" + userSession.getKualiSessionId() + "/" +
156 documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress, e);
157 }
158
159 return documentForm;
160 }
161
162 protected Object retrieveDocumentForm(UserSession userSession, String sessionId, String documentNumber,
163 String ipAddress) throws Exception {
164 HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
165 primaryKeys.put(SESSION_ID, sessionId);
166 if (documentNumber != null) {
167 primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
168 }
169 primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
170 primaryKeys.put(IP_ADDRESS, ipAddress);
171
172 SessionDocument sessionDoc = getBusinessObjectService().findByPrimaryKey(SessionDocument.class, primaryKeys);
173 if (sessionDoc != null) {
174 byte[] formAsBytes = sessionDoc.getSerializedDocumentForm();
175 if (sessionDoc.isEncrypted()) {
176 formAsBytes = getEncryptionService().decryptBytes(formAsBytes);
177 }
178 ByteArrayInputStream baip = new ByteArrayInputStream(formAsBytes);
179 ObjectInputStream ois = new ObjectInputStream(baip);
180
181 return ois.readObject();
182 }
183
184 return null;
185 }
186
187 @Override
188 public WorkflowDocument getDocumentFromSession(UserSession userSession, String docId) {
189 @SuppressWarnings("unchecked") Map<String, WorkflowDocument> workflowDocMap =
190 (Map<String, WorkflowDocument>) userSession
191 .retrieveObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME);
192
193 if (workflowDocMap == null) {
194 workflowDocMap = new HashMap<String, WorkflowDocument>();
195 userSession.addObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME, workflowDocMap);
196 return null;
197 }
198 return workflowDocMap.get(docId);
199 }
200
201
202
203
204
205 @Override
206 public void addDocumentToUserSession(UserSession userSession, WorkflowDocument document) {
207 @SuppressWarnings("unchecked") Map<String, WorkflowDocument> workflowDocMap =
208 (Map<String, WorkflowDocument>) userSession
209 .retrieveObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME);
210 if (workflowDocMap == null) {
211 workflowDocMap = new HashMap<String, WorkflowDocument>();
212 }
213 workflowDocMap.put(document.getDocumentId(), document);
214 userSession.addObject(KewApiConstants.WORKFLOW_DOCUMENT_MAP_ATTR_NAME, workflowDocMap);
215 }
216
217
218
219
220
221 @Override
222 public void purgeDocumentForm(String documentNumber, String docFormKey, UserSession userSession, String ipAddress) {
223 synchronized (userSession) {
224
225 LOG.debug("purge document form from session");
226 userSession.removeObject(docFormKey);
227 try {
228 LOG.debug("purge document form from database");
229 HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
230 primaryKeys.put(SESSION_ID, userSession.getKualiSessionId());
231 primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
232 primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
233 primaryKeys.put(IP_ADDRESS, ipAddress);
234 getBusinessObjectService().deleteMatching(SessionDocument.class, primaryKeys);
235 } catch (Exception e) {
236 LOG.error("purgeDocumentForm failed for SessId/DocNum/PrinId/IP:" + userSession.getKualiSessionId() +
237 "/" + documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress, e);
238 }
239 }
240 }
241
242 @Override
243 public void setDocumentForm(KualiDocumentFormBase form, UserSession userSession, String ipAddress) {
244 synchronized (userSession) {
245
246 String formKey = form.getFormKey();
247 String key = userSession.getKualiSessionId() + "-" + formKey;
248 cachedObjects.put(key, new CachedObject(userSession, formKey));
249
250 String documentNumber = form.getDocument().getDocumentNumber();
251
252 if (StringUtils.isNotBlank(documentNumber)) {
253 persistDocumentForm(form, userSession, ipAddress, userSession.getKualiSessionId(), documentNumber);
254 } else {
255 LOG.warn("documentNumber is null on form's document: " + form);
256 }
257 }
258 }
259
260 protected void persistDocumentForm(Object form, UserSession userSession, String ipAddress, String sessionId,
261 String documentNumber) {
262 try {
263 LOG.debug("set Document Form into database");
264 Timestamp currentTime = new Timestamp(System.currentTimeMillis());
265 ByteArrayOutputStream baos = new ByteArrayOutputStream();
266 ObjectOutputStream oos = new ObjectOutputStream(baos);
267 oos.writeObject(form);
268
269 byte[] formAsBytes = baos.toByteArray();
270 boolean encryptContent = false;
271
272 if ((form instanceof KualiDocumentFormBase) && ((KualiDocumentFormBase) form).getDocTypeName() != null) {
273 DocumentEntry documentEntry = getDataDictionaryService().getDataDictionary()
274 .getDocumentEntry(((KualiDocumentFormBase) form).getDocTypeName());
275 if (documentEntry != null) {
276 encryptContent = documentEntry.isEncryptDocumentDataInPersistentSessionStorage();
277 }
278 }
279 if (encryptContent) {
280 formAsBytes = getEncryptionService().encryptBytes(formAsBytes);
281 }
282
283
284
285 HashMap<String, String> primaryKeys = new HashMap<String, String>(4);
286 primaryKeys.put(SESSION_ID, sessionId);
287 primaryKeys.put(DOCUMENT_NUMBER, documentNumber);
288 primaryKeys.put(PRINCIPAL_ID, userSession.getPrincipalId());
289 primaryKeys.put(IP_ADDRESS, ipAddress);
290
291 SessionDocument sessionDocument =
292 getBusinessObjectService().findByPrimaryKey(SessionDocument.class, primaryKeys);
293 if (sessionDocument == null) {
294 sessionDocument = new SessionDocument();
295 sessionDocument.setSessionId(sessionId);
296 sessionDocument.setDocumentNumber(documentNumber);
297 sessionDocument.setPrincipalId(userSession.getPrincipalId());
298 sessionDocument.setIpAddress(ipAddress);
299 }
300 sessionDocument.setSerializedDocumentForm(formAsBytes);
301 sessionDocument.setEncrypted(encryptContent);
302 sessionDocument.setLastUpdatedDate(currentTime);
303
304 businessObjectService.save(sessionDocument);
305 } catch (Exception e) {
306 final String className = form != null ? form.getClass().getName() : "null";
307 LOG.error("setDocumentForm failed for SessId/DocNum/PrinId/IP/class:" + userSession.getKualiSessionId() +
308 "/" + documentNumber + "/" + userSession.getPrincipalId() + "/" + ipAddress + "/" + className, e);
309 }
310 }
311
312
313
314
315 @Override
316 public void purgeAllSessionDocuments(Timestamp expirationDate) {
317 sessionDocumentDao.purgeAllSessionDocuments(expirationDate);
318 }
319
320 protected SessionDocumentDao getSessionDocumentDao() {
321 return this.sessionDocumentDao;
322 }
323
324 public void setSessionDocumentDao(SessionDocumentDao sessionDocumentDao) {
325 this.sessionDocumentDao = sessionDocumentDao;
326 }
327
328 protected BusinessObjectService getBusinessObjectService() {
329 return this.businessObjectService;
330 }
331
332 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
333 this.businessObjectService = businessObjectService;
334 }
335
336 public int getMaxCacheSize() {
337 return maxCacheSize;
338 }
339
340 public void setMaxCacheSize(int maxCacheSize) {
341 this.maxCacheSize = maxCacheSize;
342 }
343
344 protected EncryptionService getEncryptionService() {
345 if (encryptionService == null) {
346 encryptionService = CoreApiServiceLocator.getEncryptionService();
347 }
348 return encryptionService;
349 }
350
351 protected DataDictionaryService getDataDictionaryService() {
352 if (dataDictionaryService == null) {
353 dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
354 }
355 return dataDictionaryService;
356 }
357 }