1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.routeheader.service.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.commons.lang.exception.ExceptionUtils;
20 import org.kuali.rice.kew.api.KewApiConstants;
21 import org.kuali.rice.kew.api.action.ActionItem;
22 import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
23 import org.kuali.rice.kew.docsearch.dao.SearchableAttributeDAO;
24 import org.kuali.rice.kew.doctype.bo.DocumentType;
25 import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
26 import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
27 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
28 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
29 import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO;
30 import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
31 import org.kuali.rice.kew.service.KEWServiceLocator;
32 import org.kuali.rice.kim.api.identity.principal.Principal;
33 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
34 import org.kuali.rice.krad.data.DataObjectService;
35 import org.kuali.rice.krad.data.PersistenceOption;
36 import org.springframework.beans.factory.annotation.Required;
37
38 import javax.persistence.OptimisticLockException;
39 import java.math.BigDecimal;
40 import java.sql.Timestamp;
41 import java.util.ArrayList;
42 import java.util.Collection;
43 import java.util.HashMap;
44 import java.util.HashSet;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48
49 public class RouteHeaderServiceImpl implements RouteHeaderService {
50
51 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RouteHeaderServiceImpl.class);
52
53 private DocumentRouteHeaderDAO routeHeaderDAO;
54 private SearchableAttributeDAO searchableAttributeDAO;
55
56 private DataObjectService dataObjectService;
57
58 public DocumentRouteHeaderValue getRouteHeader(String documentId) {
59 return getDataObjectService().find(DocumentRouteHeaderValue.class, documentId);
60 }
61
62 public DocumentRouteHeaderValue getRouteHeader(String documentId, boolean clearCache) {
63 return getRouteHeaderDAO().findRouteHeader(documentId, clearCache);
64 }
65
66 public Collection<DocumentRouteHeaderValue> getRouteHeaders(Collection<String> documentIds) {
67 return getRouteHeaderDAO().findRouteHeaders(documentIds);
68 }
69
70 public Collection<DocumentRouteHeaderValue> getRouteHeaders(Collection<String> documentIds, boolean clearCache) {
71 return getRouteHeaderDAO().findRouteHeaders(documentIds, clearCache);
72 }
73
74 public Map<String,DocumentRouteHeaderValue> getRouteHeadersForActionItems(Collection<ActionItem> actionItems) {
75 Map<String,DocumentRouteHeaderValue> routeHeaders = new HashMap<String,DocumentRouteHeaderValue>();
76 List<String> documentIds = new ArrayList<String>(actionItems.size());
77 for (ActionItem actionItem : actionItems) {
78 documentIds.add(actionItem.getDocumentId());
79 }
80 Collection<DocumentRouteHeaderValue> actionItemRouteHeaders = getRouteHeaders(documentIds);
81 if (actionItemRouteHeaders != null) {
82 for (DocumentRouteHeaderValue routeHeader : actionItemRouteHeaders) {
83 routeHeaders.put(routeHeader.getDocumentId(), routeHeader);
84 }
85 }
86 return routeHeaders;
87 }
88
89 public void lockRouteHeader(String documentId) {
90 getRouteHeaderDAO().lockRouteHeader(documentId);
91 LOG.debug("Successfully locked document [docId=" + documentId + "]");
92 }
93
94 public DocumentRouteHeaderValue saveRouteHeader(DocumentRouteHeaderValue routeHeader) {
95 if ( LOG.isDebugEnabled() ) {
96 LOG.debug( "About to Save the route Header: " + routeHeader.getDocumentId() + " / version="
97 + routeHeader.getVersionNumber() );
98 DocumentRouteHeaderValue currHeader = getDataObjectService().find(DocumentRouteHeaderValue.class,
99 routeHeader.getDocumentId());
100 if ( currHeader != null ) {
101 LOG.debug( "Current Header Version: " + currHeader.getVersionNumber() );
102 } else {
103 LOG.debug( "Current Header: null" );
104 }
105 LOG.debug( ExceptionUtils.getStackTrace(new Throwable()) );
106 }
107 try {
108
109 DocumentRouteHeaderValueContent content = routeHeader.getDocumentContent();
110 DocumentRouteHeaderValue drvPersisted = dataObjectService.save(routeHeader, PersistenceOption.FLUSH);
111
112 content.setDocumentId(drvPersisted.getDocumentId());
113 content = dataObjectService.save(content);
114 drvPersisted.setDocumentContent(content);
115 return drvPersisted;
116 } catch ( RuntimeException ex ) {
117 if ( ex.getCause() instanceof OptimisticLockException) {
118 LOG.error( "Optimistic Locking Exception saving document header or content. Offending object: "
119 + ex.getCause()
120 + "; DocumentId = " + routeHeader.getDocumentId() + " ; Version Number = "
121 + routeHeader.getVersionNumber());
122 }
123 LOG.error( "Unable to save document header or content. Route Header: " + routeHeader, ex );
124 throw ex;
125 }
126 }
127
128 public void deleteRouteHeader(DocumentRouteHeaderValue routeHeader) {
129 dataObjectService.delete(routeHeader);
130 }
131
132 public String getNextDocumentId() {
133 return getRouteHeaderDAO().getNextDocumentId();
134 }
135
136 public Collection findPendingByResponsibilityIds(Set responsibilityIds) {
137 return getRouteHeaderDAO().findPendingByResponsibilityIds(responsibilityIds);
138 }
139
140 public void clearRouteHeaderSearchValues(String documentId) {
141 getRouteHeaderDAO().clearRouteHeaderSearchValues(documentId);
142 }
143
144 public void updateRouteHeaderSearchValues(String documentId, List<SearchableAttributeValue> searchAttributes) {
145 getRouteHeaderDAO().clearRouteHeaderSearchValues(documentId);
146 HashSet<String> dupedSet = new HashSet<String>();
147
148 for (SearchableAttributeValue searchAttribute : searchAttributes) {
149 if(searchAttribute != null){
150 String fakeKey = searchAttribute.getSearchableAttributeKey() + "-" + searchAttribute.getSearchableAttributeValue();
151 if(!dupedSet.contains(fakeKey)){
152 getRouteHeaderDAO().save(searchAttribute);
153 dupedSet.add(fakeKey);
154 }
155 }
156 }
157 LOG.warn("Deduplication adjusted incoming SearchableAttributeValue list from original: " + searchAttributes.size() + " entries into : " + (searchAttributes.size() - dupedSet.size()) + " entries.");
158 }
159
160 public void validateRouteHeader(DocumentRouteHeaderValue routeHeader){
161 LOG.debug("Enter validateRouteHeader(..)");
162 List errors = new ArrayList();
163
164 if (routeHeader.getDocRouteStatus() == null || routeHeader.getDocRouteStatus().trim().equals("")) {
165 errors.add(new WorkflowServiceErrorImpl("RouteHeader route status null.", "routeheader.routestatus.empty"));
166 } else if (!KewApiConstants.DOCUMENT_STATUSES.containsKey(routeHeader.getDocRouteStatus())){
167 errors.add(new WorkflowServiceErrorImpl("RouteHeader route status invalid.", "routeheader.routestatus.invalid"));
168 }
169
170 if(routeHeader.getDocRouteLevel() == null || routeHeader.getDocRouteLevel().intValue() < 0){
171 errors.add(new WorkflowServiceErrorImpl("RouteHeader route level invalid.", "routeheader.routelevel.invalid"));
172 }
173
174 if(routeHeader.getDateLastModified() == null){
175 errors.add(new WorkflowServiceErrorImpl("RouteHeader status modification date empty.", "routeheader.statusmoddate.empty"));
176 }
177
178 if(routeHeader.getCreateDate() == null){
179 errors.add(new WorkflowServiceErrorImpl("RouteHeader status create date empty.", "routeheader.createdate.empty"));
180 }
181 if(routeHeader.getDocVersion() == null || routeHeader.getDocVersion().intValue() < 0){
182 errors.add(new WorkflowServiceErrorImpl("RouteHeader doc version invalid.", "routeheader.docversion.invalid"));
183 }
184
185 if (routeHeader.getInitiatorWorkflowId () == null || routeHeader.getInitiatorWorkflowId().trim().equals("")) {
186 errors.add(new WorkflowServiceErrorImpl("RouteHeader initiator null.", "routeheader.initiator.empty"));
187 }
188 else
189 {
190 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(routeHeader.getInitiatorWorkflowId());
191 if(principal == null)
192 {
193 errors.add(new WorkflowServiceErrorImpl("RouteHeader initiator id invalid.", "routeheader.initiator.invalid"));
194 }
195 }
196
197 if(!StringUtils.isBlank(routeHeader.getDocumentTypeId())){
198 DocumentType docType = KEWServiceLocator.getDocumentTypeService().findById(routeHeader.getDocumentTypeId());
199 if(docType == null){
200 errors.add(new WorkflowServiceErrorImpl("RouteHeader document type id invalid.", "routeheader.doctypeid.invalid"));
201 }
202 }
203
204 LOG.debug("Exit validateRouteHeader(..) ");
205 if (!errors.isEmpty()) {
206 throw new WorkflowServiceErrorException("RouteHeader Validation Error", errors);
207 }
208 }
209
210 public String getApplicationIdByDocumentId(String documentId) {
211 return getRouteHeaderDAO().getApplicationIdByDocumentId(documentId);
212 }
213
214 public DocumentRouteHeaderValueContent getContent(String documentId) {
215 if (documentId == null) {
216 return new DocumentRouteHeaderValueContent();
217 }
218 DocumentRouteHeaderValueContent content = getRouteHeaderDAO().getContent(documentId);
219 if (content == null) {
220 content = new DocumentRouteHeaderValueContent(documentId);
221 }
222 return content;
223 }
224
225 public boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue) {
226 return getRouteHeaderDAO().hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue);
227 }
228
229 public String getDocumentStatus(String documentId) {
230 return getRouteHeaderDAO().getDocumentStatus(documentId);
231 }
232
233 public String getAppDocId(String documentId) {
234 if (documentId == null) {
235 return null;
236 }
237 return getRouteHeaderDAO().getAppDocId(documentId);
238 }
239
240 public String getAppDocStatus(String documentId) {
241 if (documentId == null) {
242 return null;
243 }
244 return getRouteHeaderDAO().getAppDocStatus(documentId);
245 }
246
247 public DocumentRouteHeaderDAO getRouteHeaderDAO() {
248 return routeHeaderDAO;
249 }
250
251 public void setRouteHeaderDAO(DocumentRouteHeaderDAO routeHeaderDAO) {
252 this.routeHeaderDAO = routeHeaderDAO;
253 }
254
255 public List<Timestamp> getSearchableAttributeDateTimeValuesByKey(
256 String documentId, String key) {
257 return getSearchableAttributeDAO().getSearchableAttributeDateTimeValuesByKey(documentId, key);
258 }
259
260 public List<BigDecimal> getSearchableAttributeFloatValuesByKey(
261 String documentId, String key) {
262 return getSearchableAttributeDAO().getSearchableAttributeFloatValuesByKey(documentId, key);
263 }
264
265 public List<Long> getSearchableAttributeLongValuesByKey(String documentId,
266 String key) {
267 return getSearchableAttributeDAO().getSearchableAttributeLongValuesByKey(documentId, key);
268 }
269
270 public List<String> getSearchableAttributeStringValuesByKey(
271 String documentId, String key) {
272
273 return getSearchableAttributeDAO().getSearchableAttributeStringValuesByKey(documentId, key);
274 }
275
276 public void setSearchableAttributeDAO(SearchableAttributeDAO searchableAttributeDAO) {
277 this.searchableAttributeDAO = searchableAttributeDAO;
278 }
279
280 public SearchableAttributeDAO getSearchableAttributeDAO() {
281 return searchableAttributeDAO;
282 }
283
284 public Collection findByDocTypeAndAppId(String documentTypeName,
285 String appId) {
286 return getRouteHeaderDAO().findByDocTypeAndAppId(documentTypeName, appId);
287 }
288
289 public DataObjectService getDataObjectService(){
290 return dataObjectService;
291 }
292
293 @Required
294 public void setDataObjectService(DataObjectService dataObjectService) {
295 this.dataObjectService = dataObjectService;
296 }
297 }