1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.impl.document;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.log4j.Logger;
20 import org.joda.time.DateTime;
21 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
22 import org.kuali.rice.core.api.exception.RiceIllegalStateException;
23 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
24 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
25 import org.kuali.rice.kew.api.action.ActionRequest;
26 import org.kuali.rice.kew.api.action.ActionTaken;
27 import org.kuali.rice.kew.api.doctype.RouteNode;
28 import org.kuali.rice.kew.api.document.Document;
29 import org.kuali.rice.kew.api.document.DocumentContent;
30 import org.kuali.rice.kew.api.document.DocumentDetail;
31 import org.kuali.rice.kew.api.document.DocumentLink;
32 import org.kuali.rice.kew.api.document.WorkflowDocumentService;
33 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
34 import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
35 import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
36 import org.kuali.rice.kew.dto.DTOConverter;
37 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
38 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
39 import org.kuali.rice.kew.routeheader.DocumentStatusTransition;
40 import org.kuali.rice.kew.service.KEWServiceLocator;
41
42 import javax.jws.WebParam;
43 import java.math.BigDecimal;
44 import java.sql.Timestamp;
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.Collections;
48 import java.util.HashMap;
49 import java.util.LinkedHashSet;
50 import java.util.List;
51 import java.util.Map;
52 import java.util.Set;
53
54
55
56
57
58
59 public class WorkflowDocumentServiceImpl implements WorkflowDocumentService {
60
61 private static final Logger LOG = Logger.getLogger(WorkflowDocumentServiceImpl.class);
62
63 @Override
64 public Document getDocument(String documentId) {
65 if (StringUtils.isBlank(documentId)) {
66 throw new RiceIllegalArgumentException("documentId was blank or null");
67 }
68 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
69 return DocumentRouteHeaderValue.to(documentBo);
70 }
71
72 @Override
73 public boolean doesDocumentExist(String documentId) {
74 if (StringUtils.isBlank(documentId)) {
75 throw new RiceIllegalArgumentException("documentId was blank or null");
76 }
77 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
78 return documentBo != null;
79 }
80
81 @Override
82 public DocumentDetail getDocumentDetailByAppId(String documentTypeName, String appId) {
83 if (StringUtils.isEmpty(documentTypeName)) {
84 throw new RiceIllegalArgumentException("documentTypeName was blank or null");
85 }
86 if (StringUtils.isEmpty(appId)) {
87 throw new RiceIllegalArgumentException("appId was blank or null");
88 }
89
90 Collection documentIds = KEWServiceLocator.getRouteHeaderService().findByDocTypeAndAppId(documentTypeName, appId);
91 if(documentIds==null||documentIds.isEmpty()){
92 throw new RiceIllegalStateException("No RouteHeader Ids found for documentTypName: " + documentTypeName + ", appId: " + appId);
93 }
94 if(documentIds.size()>1){
95 throw new RiceIllegalStateException("Multiple RouteHeader Ids found for documentTypName: " + documentTypeName + ", appId: " + appId);
96 }
97
98 return getDocumentDetail((String)documentIds.iterator().next());
99 }
100
101 public RouteNodeInstance getRouteNodeInstance(String nodeInstanceId) {
102 if (StringUtils.isEmpty(nodeInstanceId)) {
103 throw new RiceIllegalArgumentException("nodeInstanceId was blank or null");
104 }
105 if ( LOG.isDebugEnabled() ) {
106 LOG.debug("Fetching RouteNodeInstanceVO [id="+nodeInstanceId+"]");
107 }
108 org.kuali.rice.kew.engine.node.RouteNodeInstance nodeInstance = KEWServiceLocator.getRouteNodeService().findRouteNodeInstanceById(nodeInstanceId);
109 return org.kuali.rice.kew.engine.node.RouteNodeInstance.to(nodeInstance);
110 }
111
112 @Override
113 public String getDocumentStatus(String documentId) {
114 if (StringUtils.isEmpty(documentId)) {
115 throw new RiceIllegalArgumentException("documentId was blank or null");
116 }
117 String documentStatus = KEWServiceLocator.getRouteHeaderService().getDocumentStatus(documentId);
118 if (StringUtils.isEmpty(documentStatus)) {
119 throw new RiceIllegalStateException("DocumentStatus not found for documentId: " + documentId);
120 }
121 return documentStatus;
122 }
123
124 @Override
125 public String getApplicationDocumentId(String documentId) {
126 if (StringUtils.isEmpty(documentId)) {
127 throw new RiceIllegalArgumentException("documentId was blank or null");
128 }
129 return KEWServiceLocator.getRouteHeaderService().getAppDocId(documentId);
130 }
131
132 @Override
133 public DocumentSearchResults documentSearch(String principalId, DocumentSearchCriteria criteria) {
134 if (criteria == null) {
135 throw new RiceIllegalArgumentException("criteria was null");
136 }
137 return KEWServiceLocator.getDocumentSearchService().lookupDocuments(principalId, criteria);
138 }
139
140 @Override
141 public List<String> getSearchableAttributeStringValuesByKey(String documentId, String key) {
142 if (StringUtils.isEmpty(documentId)) {
143 throw new RiceIllegalArgumentException("documentId was blank or null");
144 }
145 if (StringUtils.isEmpty(key)) {
146 throw new RiceIllegalArgumentException("key was blank or null");
147 }
148 return KEWServiceLocator.getRouteHeaderService().getSearchableAttributeStringValuesByKey(documentId, key);
149 }
150
151 @Override
152 public List<DateTime> getSearchableAttributeDateTimeValuesByKey(String documentId, String key) {
153 if (StringUtils.isEmpty(documentId)) {
154 throw new RiceIllegalArgumentException("documentId was blank or null");
155 }
156 if (StringUtils.isEmpty(key)) {
157 throw new RiceIllegalArgumentException("key was blank or null");
158 }
159
160 List<Timestamp> results = KEWServiceLocator.getRouteHeaderService().getSearchableAttributeDateTimeValuesByKey(documentId, key);
161 if (results == null) {
162 return null;
163 }
164 List<DateTime> dateTimes = new ArrayList<DateTime>();
165
166 for(Timestamp time : results) {
167 dateTimes.add(new DateTime(time.getTime()));
168 }
169 return dateTimes;
170 }
171
172 @Override
173 public List<BigDecimal> getSearchableAttributeFloatValuesByKey(String documentId, String key) {
174 if (StringUtils.isEmpty(documentId)) {
175 throw new RiceIllegalArgumentException("documentId was blank or null");
176 }
177 if (StringUtils.isEmpty(key)) {
178 throw new RiceIllegalArgumentException("key was blank or null");
179 }
180 return KEWServiceLocator.getRouteHeaderService().getSearchableAttributeFloatValuesByKey(documentId, key);
181 }
182
183 @Override
184 public List<Long> getSearchableAttributeLongValuesByKey(String documentId, String key) {
185 if (StringUtils.isEmpty(documentId)) {
186 throw new RiceIllegalArgumentException("documentId was blank or null");
187 }
188 if (StringUtils.isEmpty(key)) {
189 throw new RiceIllegalArgumentException("key was blank or null");
190 }
191 return KEWServiceLocator.getRouteHeaderService().getSearchableAttributeLongValuesByKey(documentId, key);
192 }
193
194 @Override
195 public DocumentContent getDocumentContent(String documentId) {
196 if (StringUtils.isBlank(documentId)) {
197 throw new RiceIllegalArgumentException("documentId was blank or null");
198 }
199 DocumentRouteHeaderValueContent content = KEWServiceLocator.getRouteHeaderService().getContent(documentId);
200 return DocumentRouteHeaderValueContent.to(content);
201 }
202
203 @Override
204 public List<ActionRequest> getRootActionRequests(String documentId) {
205 if (StringUtils.isBlank(documentId)) {
206 throw new RiceIllegalArgumentException("documentId was blank or null");
207 }
208 List<ActionRequest> actionRequests = new ArrayList<ActionRequest>();
209 List<ActionRequestValue> actionRequestBos = KEWServiceLocator.getActionRequestService().findAllRootActionRequestsByDocumentId(documentId);
210 for (ActionRequestValue actionRequestBo : actionRequestBos) {
211 actionRequests.add(ActionRequestValue.to(actionRequestBo));
212 }
213 return Collections.unmodifiableList(actionRequests);
214 }
215
216 @Override
217 public List<ActionRequest> getActionRequestsForPrincipalAtNode(String documentId, String nodeName,
218 String principalId) {
219 if (StringUtils.isBlank(documentId)) {
220 throw new RiceIllegalArgumentException("documentId was null or blank");
221 }
222 if ( LOG.isDebugEnabled() ) {
223 LOG.debug("Fetching ActionRequests [docId="+documentId+", nodeName="+nodeName+", principalId="+principalId+"]");
224 }
225 List<ActionRequestValue> actionRequestBos = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
226 List<ActionRequestValue> matchingActionRequests = new ArrayList<ActionRequestValue>();
227 for (ActionRequestValue actionRequestValue : actionRequestBos) {
228 if (actionRequestMatches(actionRequestValue, nodeName, principalId)) {
229 matchingActionRequests.add(actionRequestValue);
230 }
231 }
232 List<ActionRequest> actionRequests = new ArrayList<ActionRequest>(matchingActionRequests.size());
233 for (ActionRequestValue matchingActionRequest : matchingActionRequests) {
234 actionRequests.add(ActionRequestValue.to(matchingActionRequest));
235 }
236 return actionRequests;
237 }
238
239 public Map<String, String> getActionsRequested(String principalId, String documentId) {
240 if (StringUtils.isEmpty(documentId)) {
241 throw new RiceIllegalArgumentException("documentId is null or empty.");
242 }
243 if (StringUtils.isEmpty(principalId)) {
244 throw new RiceIllegalArgumentException("principalId is null or empty.");
245 }
246 if ( LOG.isDebugEnabled() ) {
247 LOG.debug("Fetching DocumentRouteHeaderValue [id="+documentId+", user="+principalId+"]");
248 }
249 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
250 return KEWServiceLocator.getActionRequestService().getActionsRequested(document, principalId, true);
251 }
252
253 protected boolean actionRequestMatches(ActionRequestValue actionRequest, String nodeName, String principalId) {
254 boolean matchesUserId = true;
255 boolean matchesNodeName = true;
256 if (StringUtils.isNotBlank(nodeName)) {
257 matchesNodeName = nodeName.equals(actionRequest.getPotentialNodeName());
258 }
259 if (principalId != null) {
260 matchesUserId = actionRequest.isRecipientRoutedRequest(principalId);
261 }
262 return matchesNodeName && matchesUserId;
263 }
264
265
266 @Override
267 public List<ActionTaken> getActionsTaken(String documentId) {
268 if (StringUtils.isEmpty(documentId)) {
269 throw new RiceIllegalArgumentException("documentId is null or empty.");
270 }
271 List<ActionTaken> actionTakens = new ArrayList<ActionTaken>();
272 Collection<ActionTakenValue> actionTakenBos = KEWServiceLocator.getActionTakenService().findByDocumentId(documentId);
273 for (ActionTakenValue actionTakenBo : actionTakenBos) {
274 actionTakens.add(ActionTakenValue.to(actionTakenBo));
275 }
276 return actionTakens;
277 }
278
279 @Override
280 public DocumentDetail getDocumentDetail(@WebParam(name = "documentId") String documentId) {
281 if (StringUtils.isBlank(documentId)) {
282 throw new RiceIllegalArgumentException("documentId was null or blank");
283 }
284 if ( LOG.isDebugEnabled() ) {
285 LOG.debug("Fetching DocumentDetail [id="+documentId+"]");
286 }
287 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
288 if (document == null) {
289 return null;
290 }
291 DocumentDetail documentDetailVO = DTOConverter.convertDocumentDetailNew(document);
292 if ( LOG.isDebugEnabled() ) {
293 LOG.debug("Returning DocumentDetailVO [id=" + documentId + "]");
294 }
295 return documentDetailVO;
296 }
297
298 @Override
299 public List<org.kuali.rice.kew.api.document.DocumentStatusTransition> getDocumentStatusTransitionHistory(String documentId) {
300 if (StringUtils.isBlank(documentId)) {
301 throw new RiceIllegalArgumentException("documentId was null or blank");
302 }
303 if ( LOG.isDebugEnabled() ) {
304 LOG.debug("Fetching document status transition history [id="+documentId+"]");
305 }
306 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);;
307
308 List<DocumentStatusTransition> list = document.getAppDocStatusHistory();
309
310 List<org.kuali.rice.kew.api.document.DocumentStatusTransition> transitionHistory = new ArrayList<org.kuali.rice.kew.api.document.DocumentStatusTransition>(list.size());
311
312 for (DocumentStatusTransition transition : list) {
313 transitionHistory.add(DocumentStatusTransition.to(transition));
314 }
315 return transitionHistory;
316 }
317
318 @Override
319 public List<RouteNodeInstance> getRouteNodeInstances(String documentId) {
320 if (StringUtils.isBlank(documentId)) {
321 throw new RiceIllegalArgumentException("documentId was null or blank");
322 }
323
324 if ( LOG.isDebugEnabled() ) {
325 LOG.debug("Fetching RouteNodeInstances [documentId=" + documentId + "]");
326 }
327 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
328 if (documentBo == null) {
329 return Collections.emptyList();
330 }
331 return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getFlattenedNodeInstances(documentBo, true));
332 }
333
334 @Override
335 public List<RouteNodeInstance> getActiveRouteNodeInstances(String documentId) {
336 if (StringUtils.isBlank(documentId)) {
337 throw new RiceIllegalArgumentException("documentId was null or blank");
338 }
339
340 if ( LOG.isDebugEnabled() ) {
341 LOG.debug("Fetching active RouteNodeInstances [documentId=" + documentId + "]");
342 }
343 return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(documentId));
344 }
345
346 @Override
347 public List<RouteNodeInstance> getTerminalRouteNodeInstances(String documentId) {
348 if (StringUtils.isBlank(documentId)) {
349 throw new RiceIllegalArgumentException("documentId was null or blank");
350 }
351
352 if ( LOG.isDebugEnabled() ) {
353 LOG.debug("Fetching terminal RouteNodeInstanceVOs [docId=" + documentId + "]");
354 }
355 return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getTerminalNodeInstances(documentId));
356 }
357
358 public List<RouteNodeInstance> getCurrentRouteNodeInstances(String documentId) {
359 if (StringUtils.isBlank(documentId)) {
360 throw new RiceIllegalArgumentException("documentId was null or blank");
361 }
362
363 if ( LOG.isDebugEnabled() ) {
364 LOG.debug("Fetching current RouteNodeInstanceVOs [docId=" + documentId + "]");
365 }
366 return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getCurrentNodeInstances(documentId));
367 }
368
369 private List<RouteNodeInstance> convertRouteNodeInstances(List<org.kuali.rice.kew.engine.node.RouteNodeInstance> routeNodeInstanceBos) {
370 List<RouteNodeInstance> routeNodeInstances = new ArrayList<RouteNodeInstance>();
371 for (org.kuali.rice.kew.engine.node.RouteNodeInstance routeNodeInstanceBo : routeNodeInstanceBos) {
372 routeNodeInstances.add(org.kuali.rice.kew.engine.node.RouteNodeInstance.to(routeNodeInstanceBo));
373 }
374 return Collections.unmodifiableList(routeNodeInstances);
375 }
376
377 @Override
378 public List<String> getPreviousRouteNodeNames(String documentId) {
379
380 if (StringUtils.isBlank(documentId)) {
381 throw new RiceIllegalArgumentException("documentId was null or blank");
382 }
383 if ( LOG.isDebugEnabled() ) {
384 LOG.debug("Fetching previous node names [documentId=" + documentId + "]");
385 }
386 return new ArrayList<String>(KEWServiceLocator.getRouteNodeService().findPreviousNodeNames(documentId));
387 }
388
389 @Override
390 public List<String> getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(String actionRequestedCd, String documentId){
391 if (StringUtils.isEmpty(actionRequestedCd)) {
392 throw new RiceIllegalArgumentException("actionRequestCd was blank or null");
393 }
394 if (StringUtils.isEmpty(documentId)) {
395 throw new RiceIllegalArgumentException("documentId was blank or null");
396 }
397 return KEWServiceLocator.getActionRequestService().
398 getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(actionRequestedCd, documentId);
399 }
400
401 @Override
402 public String getDocumentInitiatorPrincipalId(String documentId) {
403 if (StringUtils.isEmpty(documentId)) {
404 throw new RiceIllegalArgumentException("documentId was blank or null");
405 }
406
407 DocumentRouteHeaderValue header = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId, false);
408 if ( header == null) {
409 return null;
410 }
411 return header.getInitiatorWorkflowId();
412 }
413
414 @Override
415 public String getRoutedByPrincipalIdByDocumentId(String documentId) {
416 if (StringUtils.isEmpty(documentId)) {
417 throw new RiceIllegalArgumentException("documentId was blank or null");
418 }
419
420 DocumentRouteHeaderValue header = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId, false);
421 if ( header == null) {
422 return null;
423 }
424 return header.getRoutedByUserWorkflowId();
425 }
426
427 @Override
428 public DocumentLink addDocumentLink(DocumentLink documentLink) throws RiceIllegalArgumentException {
429 if (documentLink == null) {
430 throw new RiceIllegalArgumentException("documentLink was null");
431 }
432 if (documentLink.getId() != null) {
433 throw new RiceIllegalArgumentException("the given documentLink already has an id, cannot add a document link with an existing id");
434 }
435 org.kuali.rice.kew.documentlink.DocumentLink documentLinkBo = org.kuali.rice.kew.documentlink.DocumentLink.from(documentLink);
436 KEWServiceLocator.getDocumentLinkService().saveDocumentLink(documentLinkBo);
437 return org.kuali.rice.kew.documentlink.DocumentLink.to(documentLinkBo);
438 }
439
440 @Override
441 public DocumentLink deleteDocumentLink(String documentLinkId) throws RiceIllegalArgumentException {
442 if (StringUtils.isBlank(documentLinkId)) {
443 throw new RiceIllegalArgumentException("documentLinkId was null or blank");
444 }
445 org.kuali.rice.kew.documentlink.DocumentLink documentLinkBo = KEWServiceLocator.getDocumentLinkService().getDocumentLink(Long.valueOf(documentLinkId));
446 if (documentLinkBo == null) {
447 throw new RiceIllegalStateException("Failed to locate document link with the given documentLinkId: " + documentLinkId);
448 }
449 KEWServiceLocator.getDocumentLinkService().deleteDocumentLink(documentLinkBo);
450 return org.kuali.rice.kew.documentlink.DocumentLink.to(documentLinkBo);
451 }
452
453 @Override
454 public List<DocumentLink> deleteDocumentLinksByDocumentId(String originatingDocumentId) throws RiceIllegalArgumentException {
455 if (StringUtils.isBlank(originatingDocumentId)) {
456 throw new RiceIllegalArgumentException("originatingDocumentId was null or blank");
457 }
458 List<org.kuali.rice.kew.documentlink.DocumentLink> documentLinkBos = KEWServiceLocator.getDocumentLinkService().getLinkedDocumentsByDocId(originatingDocumentId);
459 if (documentLinkBos == null || documentLinkBos.isEmpty()) {
460 return Collections.emptyList();
461 }
462 List<DocumentLink> deletedDocumentLinks = new ArrayList<DocumentLink>();
463 for (org.kuali.rice.kew.documentlink.DocumentLink documentLinkBo : documentLinkBos) {
464 deletedDocumentLinks.add(org.kuali.rice.kew.documentlink.DocumentLink.to(documentLinkBo));
465 KEWServiceLocator.getDocumentLinkService().deleteDocumentLink(documentLinkBo);
466 }
467 return Collections.unmodifiableList(deletedDocumentLinks);
468 }
469
470 @Override
471 public List<DocumentLink> getOutgoingDocumentLinks(String originatingDocumentId) throws RiceIllegalArgumentException {
472 if (StringUtils.isBlank(originatingDocumentId)) {
473 throw new RiceIllegalArgumentException("originatingDocumentId was null or blank");
474 }
475 List<org.kuali.rice.kew.documentlink.DocumentLink> outgoingDocumentLinkBos = KEWServiceLocator.getDocumentLinkService().getLinkedDocumentsByDocId(originatingDocumentId);
476 List<DocumentLink> outgoingDocumentLinks = new ArrayList<DocumentLink>();
477 for (org.kuali.rice.kew.documentlink.DocumentLink outgoingDocumentLinkBo : outgoingDocumentLinkBos) {
478 outgoingDocumentLinks.add(org.kuali.rice.kew.documentlink.DocumentLink.to(outgoingDocumentLinkBo));
479 }
480 return Collections.unmodifiableList(outgoingDocumentLinks);
481 }
482
483 @Override
484 public List<DocumentLink> getIncomingDocumentLinks(String destinationDocumentId) throws RiceIllegalArgumentException {
485 if (StringUtils.isBlank(destinationDocumentId)) {
486 throw new RiceIllegalArgumentException("destinationDocumentId was null or blank");
487 }
488 List<org.kuali.rice.kew.documentlink.DocumentLink> incomingDocumentLinkBos = KEWServiceLocator.getDocumentLinkService().getOutgoingLinkedDocumentsByDocId(destinationDocumentId);
489 List<DocumentLink> incomingDocumentLinks = new ArrayList<DocumentLink>();
490 for (org.kuali.rice.kew.documentlink.DocumentLink incomingDocumentLinkBo : incomingDocumentLinkBos) {
491 incomingDocumentLinks.add(org.kuali.rice.kew.documentlink.DocumentLink.to(incomingDocumentLinkBo));
492 }
493 return Collections.unmodifiableList(incomingDocumentLinks);
494 }
495
496 @Override
497 public DocumentLink getDocumentLink(String documentLinkId) throws RiceIllegalArgumentException {
498 if (StringUtils.isBlank(documentLinkId)) {
499 throw new RiceIllegalArgumentException("documentLinkId was null or blank");
500 }
501 org.kuali.rice.kew.documentlink.DocumentLink documentLinkBo = KEWServiceLocator.getDocumentLinkService().getDocumentLink(Long.valueOf(documentLinkId));
502 return org.kuali.rice.kew.documentlink.DocumentLink.to(documentLinkBo);
503 }
504
505 }