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