001    /**
002     * Copyright 2005-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.kew.actionrequest;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.apache.commons.lang.builder.ToStringBuilder;
020    import org.apache.commons.lang.builder.ToStringStyle;
021    import org.hibernate.annotations.Fetch;
022    import org.hibernate.annotations.FetchMode;
023    import org.hibernate.annotations.GenericGenerator;
024    import org.hibernate.annotations.Parameter;
025    import org.joda.time.DateTime;
026    import org.kuali.rice.core.api.delegation.DelegationType;
027    import org.kuali.rice.core.api.util.RiceConstants;
028    import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
029    import org.kuali.rice.kew.actionitem.ActionItem;
030    import org.kuali.rice.kew.actiontaken.ActionTakenValue;
031    import org.kuali.rice.kew.api.action.ActionRequest;
032    import org.kuali.rice.kew.api.action.ActionRequestPolicy;
033    import org.kuali.rice.kew.api.action.ActionRequestStatus;
034    import org.kuali.rice.kew.api.action.ActionRequestType;
035    import org.kuali.rice.kew.api.action.ActionTaken;
036    import org.kuali.rice.kew.api.action.RecipientType;
037    import org.kuali.rice.kew.api.util.CodeTranslator;
038    import org.kuali.rice.kew.dto.DTOConverter.RouteNodeInstanceLoader;
039    import org.kuali.rice.kew.engine.CompatUtils;
040    import org.kuali.rice.kew.engine.node.RouteNode;
041    import org.kuali.rice.kew.engine.node.RouteNodeInstance;
042    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
043    import org.kuali.rice.kew.rule.RuleBaseValues;
044    import org.kuali.rice.kew.rule.service.RuleServiceInternal;
045    import org.kuali.rice.kew.service.KEWServiceLocator;
046    import org.kuali.rice.kew.user.RoleRecipient;
047    import org.kuali.rice.kew.api.KewApiConstants;
048    import org.kuali.rice.kim.api.group.Group;
049    import org.kuali.rice.kim.api.identity.Person;
050    import org.kuali.rice.kim.api.identity.principal.Principal;
051    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
052    
053    import javax.persistence.CascadeType;
054    import javax.persistence.Column;
055    import javax.persistence.Entity;
056    import javax.persistence.FetchType;
057    import javax.persistence.GeneratedValue;
058    import javax.persistence.Id;
059    import javax.persistence.JoinColumn;
060    import javax.persistence.ManyToOne;
061    import javax.persistence.NamedQueries;
062    import javax.persistence.NamedQuery;
063    import javax.persistence.OneToMany;
064    import javax.persistence.Table;
065    import javax.persistence.Transient;
066    import java.io.Serializable;
067    import java.sql.Timestamp;
068    import java.util.ArrayList;
069    import java.util.Arrays;
070    import java.util.Iterator;
071    import java.util.List;
072    /**
073     * Bean mapped to DB. Represents ActionRequest to a workgroup, user or role.  Contains
074     * references to children/parent if a member of a graph
075     *
076     * @author Kuali Rice Team (rice.collab@kuali.org)
077     */
078    @Entity
079    @Table(name="KREW_ACTN_RQST_T")
080    //@Sequence(name="KREW_ACTN_RQST_S", property="actionRequestId")
081    @NamedQueries({
082      @NamedQuery(name="ActionRequestValue.FindByDocumentId", query="select arv from ActionRequestValue arv where arv.documentId = :documentId"),
083      @NamedQuery(name="ActionRequestValue.GetUserRequestCount", query="select count(arv) from ActionRequestValue arv where arv.documentId = :documentId and arv.recipientTypeCd = :recipientTypeCd and arv.principalId = :principalId and arv.currentIndicator = :currentIndicator"),
084      @NamedQuery(name="ActionRequestValue.FindActivatedByGroup", query="select count(arv) from ActionRequestValue arv where arv.groupId = :groupId and arv.currentIndicator = :currentIndicator and arv.status = :status"),
085      @NamedQuery(name="ActionRequestValue.FindAllByDocId", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator"),
086      @NamedQuery(name="ActionRequestValue.FindAllPendingByDocId", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and (arv.status = :actionRequestStatus1 or arv.status = :actionRequestStatus2)"),
087      @NamedQuery(name="ActionRequestValue.FindAllRootByDocId", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.parentActionRequest is null"),
088      @NamedQuery(name="ActionRequestValue.FindByStatusAndDocId", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.status = :status"),
089      @NamedQuery(name="ActionRequestValue.FindPendingByActionRequestedAndDocId", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.actionRequested = :actionRequested and (arv.status = :actionRequestStatus1 or arv.status = :actionRequestStatus2)"),
090      @NamedQuery(name="ActionRequestValue.FindPendingByDocIdAtOrBelowRouteLevel", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.status <> :status and arv.routeLevel <= :routeLevel"),
091      @NamedQuery(name="ActionRequestValue.FindPendingRootRequestsByDocIdAtOrBelowRouteLevel", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.parentActionRequest is null and arv.status <> :status and routeLevel <= :routeLevel"),
092      @NamedQuery(name="ActionRequestValue.FindPendingRootRequestsByDocIdAtRouteLevel", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.parentActionRequest is null and arv.status <> :status and routeLevel = :routeLevel"),
093      @NamedQuery(name="ActionRequestValue.FindPendingRootRequestsByDocIdAtRouteNode", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.parentActionRequest is null and arv.nodeInstance.routeNodeInstanceId = :routeNodeInstanceId and (arv.status = :actionRequestStatus1 or arv.status = :actionRequestStatus2)"),
094      @NamedQuery(name="ActionRequestValue.FindPendingRootRequestsByDocumentType", query="select arv from ActionRequestValue arv where arv.documentId in (select drhv.documentId from DocumentRouteHeaderValue drhv where drhv.documentTypeId = :documentTypeId) and arv.currentIndicator = :currentIndicator and arv.parentActionRequest is null and (arv.status = :actionRequestStatus1 or arv.status = :actionRequestStatus2)"),
095      @NamedQuery(name="ActionRequestValue.FindRootRequestsByDocIdAtRouteNode", query="select arv from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.parentActionRequest is null and arv.nodeInstance.routeNodeInstanceId = :routeNodeInstanceId"),
096      @NamedQuery(name="ActionRequestValue.GetRequestGroupIds", query="select arv.groupId from ActionRequestValue arv where arv.documentId = :documentId and arv.currentIndicator = :currentIndicator and arv.recipientTypeCd = :recipientTypeCd"),
097      @NamedQuery(name="ActionRequestValue.FindByStatusAndGroupId", query="select arv from ActionRequestValue arv where arv.groupId = :groupId and arv.currentIndicator = :currentIndicator and arv.status = :status")
098    })
099    public class ActionRequestValue implements Serializable {
100    
101            private static final long serialVersionUID = 8781414791855848385L;
102    
103            private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ActionRequestValue.class);
104    
105        private static final String ACTION_CODE_RANK = "FKACB";//B is a hack for allowing blanket approves to count for approve and complete requests in findPreviousAction in ActionTakenService this is a hack and accounts for the -3 on compareActionCode
106        private static final String RECIPIENT_TYPE_RANK = "RWU";
107        private static final List DELEGATION_TYPE_RANK = Arrays.asList(new Object[]{DelegationType.SECONDARY, DelegationType.PRIMARY, null});
108    
109        @Id
110        @GeneratedValue(generator="KREW_ACTN_RQST_S")
111            @GenericGenerator(name="KREW_ACTN_RQST_S",strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",parameters={
112                            @Parameter(name="sequence_name",value="KREW_ACTN_RQST_S"),
113                            @Parameter(name="value_column",value="id")
114            })
115            @Column(name="ACTN_RQST_ID")
116            private String actionRequestId;
117        @Column(name="ACTN_RQST_CD")
118            private String actionRequested;
119        @Column(name="DOC_HDR_ID")
120            private String documentId;
121        @Column(name="STAT_CD")
122            private String status;
123        @Column(name="RSP_ID")
124            private String responsibilityId;
125        @Column(name="GRP_ID")
126            private String groupId;
127        @Column(name="RECIP_TYP_CD")
128            private String recipientTypeCd;
129        @Column(name="PRIO_NBR")
130            private Integer priority;
131        @Column(name="RTE_LVL_NBR")
132            private Integer routeLevel;
133        @Column(name="ACTN_TKN_ID", insertable=false, updatable=false)
134            private String actionTakenId;
135        @Column(name="DOC_VER_NBR")
136        private Integer docVersion = 1;
137            @Column(name="CRTE_DT")
138            private java.sql.Timestamp createDate;
139        @Column(name="RSP_DESC_TXT")
140            private String responsibilityDesc;
141        @Column(name="ACTN_RQST_ANNOTN_TXT")
142            private String annotation;
143        @Column(name="VER_NBR")
144            private Integer jrfVerNbr;
145        @Column(name="PRNCPL_ID")
146            private String principalId;
147        @Column(name="FRC_ACTN")
148            private Boolean forceAction;
149        @Column(name="PARNT_ID", insertable=false, updatable=false)
150            private String parentActionRequestId;
151        @Column(name="QUAL_ROLE_NM")
152            private String qualifiedRoleName;
153        @Column(name="ROLE_NM")
154            private String roleName;
155        @Column(name="QUAL_ROLE_NM_LBL_TXT")
156            private String qualifiedRoleNameLabel;
157        @Transient
158        private String displayStatus;
159        @Column(name="RULE_ID")
160            private String ruleBaseValuesId;
161    
162        @Column(name="DLGN_TYP")
163        private String delegationTypeCode;
164        @Column(name="APPR_PLCY")
165            private String approvePolicy;
166    
167        @ManyToOne(fetch=FetchType.EAGER)
168            @JoinColumn(name="PARNT_ID")
169            private ActionRequestValue parentActionRequest;
170        @Fetch(value = FetchMode.SELECT)
171        @OneToMany(mappedBy="parentActionRequest",cascade={CascadeType.PERSIST, CascadeType.MERGE},fetch=FetchType.EAGER)
172        private List<ActionRequestValue> childrenRequests = new ArrayList<ActionRequestValue>();
173        @ManyToOne(fetch=FetchType.EAGER)
174            @JoinColumn(name="ACTN_TKN_ID")
175            private ActionTakenValue actionTaken;
176        //@OneToMany(fetch=FetchType.LAZY,mappedBy="actionRequestId")
177        //private List<ActionItem> actionItems = new ArrayList<ActionItem>();
178        @Column(name="CUR_IND")
179        private Boolean currentIndicator = true;
180        @Transient
181        private String createDateString;
182    
183        /* New Workflow 2.1 Field */
184        // The node instance at which this request was generated
185        @ManyToOne(fetch=FetchType.EAGER)
186            @JoinColumn(name="RTE_NODE_INSTN_ID")
187            private RouteNodeInstance nodeInstance;
188    
189        @Column(name="RQST_LBL")
190        private String requestLabel;
191        
192        @Transient
193        private boolean resolveResponsibility = true;
194        @Transient
195        private DocumentRouteHeaderValue routeHeader;
196        @Transient
197        private List<ActionItem> simulatedActionItems;
198        
199        public ActionRequestValue() {
200            createDate = new Timestamp(System.currentTimeMillis());
201        }
202        
203        //@PrePersist
204        public void beforeInsert(){
205            OrmUtils.populateAutoIncValue(this, KEWServiceLocator.getEntityManagerFactory().createEntityManager());
206        }
207       
208        public Group getGroup() {
209            if (getGroupId() == null) {
210                LOG.error("Attempting to get a group with a blank group id");
211                return null;
212            }
213            return KimApiServiceLocator.getGroupService().getGroup(getGroupId());
214        }
215    
216        public String getRouteLevelName() {
217            // this is for backward compatibility of requests which have not been converted
218            if (CompatUtils.isRouteLevelRequest(this)) {
219                int routeLevelInt = getRouteLevel();
220                if (routeLevelInt == KewApiConstants.EXCEPTION_ROUTE_LEVEL) {
221                    return "Exception";
222                }
223    
224                List<RouteNode> routeLevelNodes = CompatUtils.getRouteLevelCompatibleNodeList(KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId).getDocumentType());
225                if (!(routeLevelInt < routeLevelNodes.size())) {
226                    return "Not Found";
227                }
228                return ((RouteNode)routeLevelNodes.get(routeLevelInt)).getRouteNodeName();
229            } else {
230                return (nodeInstance == null ? "Exception" : nodeInstance.getName());
231            }
232        }
233    
234        public boolean isUserRequest() {
235            return principalId != null;
236        }
237    
238        public Principal getPrincipal() {
239            if (getPrincipalId() == null) {
240                    return null;
241            }
242            return KEWServiceLocator.getIdentityHelperService().getPrincipal(getPrincipalId());
243        }
244        
245        public Person getPerson() {
246            if (getPrincipalId() == null) {
247                    return null;
248            }
249            return KimApiServiceLocator.getPersonService().getPerson(getPrincipalId());
250        }
251    
252        public String getDisplayName() {
253            if (isUserRequest()) {
254                Person person = getPerson();
255                if ( person != null ) {
256                    return person.getName();
257                }
258            } else if (isGroupRequest()) {
259                Group group = getGroup();
260                if ( group != null ) {
261                        return group.getName();
262                } else {
263                    return getGroupId();
264                }
265            } else if (isRoleRequest()) {
266                    return getRoleName();
267            }
268            return "";
269        }
270    
271        public Recipient getRecipient() {
272            if (getPrincipalId() != null) {
273                return new KimPrincipalRecipient(getPrincipal());
274            } else if (getGroupId() != null){
275                return new KimGroupRecipient(getGroup());
276            } else {
277                    return new RoleRecipient(this.getRoleName());
278            }
279        }
280    
281        public boolean isPending() {
282            return ActionRequestStatus.INITIALIZED.getCode().equals(getStatus()) || ActionRequestStatus.ACTIVATED.getCode().equals(getStatus());
283        }
284    
285        public String getStatusLabel() {
286            return CodeTranslator.getActionRequestStatusLabel(getStatus());
287        }
288    
289        public String getActionRequestedLabel() {
290            if (StringUtils.isNotBlank(getRequestLabel())) {
291                    return getRequestLabel();
292            }
293            return CodeTranslator.getActionRequestLabel(getActionRequested());
294        }
295    
296        /**
297         * @return Returns the actionTaken.
298         */
299        public ActionTakenValue getActionTaken() {
300            return actionTaken;
301        }
302    
303        /**
304         * @param actionTaken
305         *            The actionTaken to set.
306         */
307        public void setActionTaken(ActionTakenValue actionTaken) {
308            this.actionTaken = actionTaken;
309        }
310    
311        /**
312         * @return Returns the actionRequested.
313         */
314        public String getActionRequested() {
315            return actionRequested;
316        }
317    
318        /**
319         * @param actionRequested
320         *            The actionRequested to set.
321         */
322        public void setActionRequested(String actionRequested) {
323            this.actionRequested = actionRequested;
324        }
325    
326        /**
327         * @return Returns the actionRequestId.
328         */
329        public String getActionRequestId() {
330            return actionRequestId;
331        }
332    
333        /**
334         * @param actionRequestId
335         *            The actionRequestId to set.
336         */
337        public void setActionRequestId(String actionRequestId) {
338            this.actionRequestId = actionRequestId;
339        }
340    
341        /**
342         * @return Returns the actionTakenId.
343         */
344        public String getActionTakenId() {
345            return actionTakenId;
346        }
347    
348        /**
349         * @param actionTakenId
350         *            The actionTakenId to set.
351         */
352        public void setActionTakenId(String actionTakenId) {
353            this.actionTakenId = actionTakenId;
354        }
355    
356        /**
357         * @return Returns the annotation.
358         */
359        public String getAnnotation() {
360            return annotation;
361        }
362    
363        /**
364         * @param annotation
365         *            The annotation to set.
366         */
367        public void setAnnotation(String annotation) {
368            this.annotation = annotation;
369        }
370    
371        /**
372         * @return Returns the createDate.
373         */
374        public java.sql.Timestamp getCreateDate() {
375            return createDate;
376        }
377    
378        /**
379         * @param createDate
380         *            The createDate to set.
381         */
382        public void setCreateDate(java.sql.Timestamp createDate) {
383            this.createDate = createDate;
384        }
385    
386        /**
387         * @return Returns the docVersion.
388         */
389        public Integer getDocVersion() {
390            return docVersion;
391        }
392    
393        /**
394         * @param docVersion
395         *            The docVersion to set.
396         */
397        public void setDocVersion(Integer docVersion) {
398            this.docVersion = docVersion;
399        }
400    
401        public String getPrincipalId() {
402            return principalId;
403        }
404    
405        public void setPrincipalId(String principalId) {
406            this.principalId = principalId;
407        }
408        
409        /**
410         * @return Returns the forceAction.
411         */
412        public Boolean getForceAction() {
413            return forceAction;
414        }
415    
416        /**
417         * @param forceAction
418         *            The forceAction to set.
419         */
420        public void setForceAction(Boolean forceAction) {
421            this.forceAction = forceAction;
422        }
423    
424        /**
425         * @return Returns the jrfVerNbr.
426         */
427        public Integer getJrfVerNbr() {
428            return jrfVerNbr;
429        }
430    
431        /**
432         * @param jrfVerNbr
433         *            The jrfVerNbr to set.
434         */
435        public void setJrfVerNbr(Integer jrfVerNbr) {
436            this.jrfVerNbr = jrfVerNbr;
437        }
438    
439        /**
440         * @return Returns the priority.
441         */
442        public Integer getPriority() {
443            return priority;
444        }
445    
446        /**
447         * @param priority
448         *            The priority to set.
449         */
450        public void setPriority(Integer priority) {
451            this.priority = priority;
452        }
453    
454        /**
455         * @return Returns the recipientTypeCd.
456         */
457        public String getRecipientTypeCd() {
458            return recipientTypeCd;
459        }
460    
461        /**
462         * @param recipientTypeCd
463         *            The recipientTypeCd to set.
464         */
465        public void setRecipientTypeCd(String recipientTypeCd) {
466            this.recipientTypeCd = recipientTypeCd;
467        }
468    
469        /**
470         * @return Returns the responsibilityDesc.
471         */
472        public String getResponsibilityDesc() {
473            return responsibilityDesc;
474        }
475    
476        /**
477         * @param responsibilityDesc
478         *            The responsibilityDesc to set.
479         */
480        public void setResponsibilityDesc(String responsibilityDesc) {
481            this.responsibilityDesc = responsibilityDesc;
482        }
483    
484        /**
485         * @return Returns the responsibilityId.
486         */
487        public String getResponsibilityId() {
488            return responsibilityId;
489        }
490    
491        /**
492         * @param responsibilityId
493         *            The responsibilityId to set.
494         */
495        public void setResponsibilityId(String responsibilityId) {
496            this.responsibilityId = responsibilityId;
497        }
498    
499        /**
500         * @return Returns the documentId.
501         */
502        public String getDocumentId() {
503            return documentId;
504        }
505    
506        public void setDocumentId(String documentId) {
507            this.documentId = documentId;
508        }
509    
510        public Integer getRouteLevel() {
511            return routeLevel;
512        }
513    
514        public void setRouteLevel(Integer routeLevel) {
515            this.routeLevel = routeLevel;
516        }
517    
518        public String getStatus() {
519            return status;
520        }
521    
522        public void setStatus(String status) {
523            this.status = status;
524        }
525    
526        public String getGroupId() {
527            return groupId;
528        }
529    
530        public void setGroupId(String groupId) {
531            this.groupId = groupId;
532        }
533    
534        public boolean isInitialized() {
535            return ActionRequestStatus.INITIALIZED.getCode().equals(getStatus());
536        }
537    
538        public boolean isActive() {
539            return ActionRequestStatus.ACTIVATED.getCode().equals(getStatus());
540        }
541    
542        public boolean isApproveOrCompleteRequest() {
543            return KewApiConstants.ACTION_REQUEST_APPROVE_REQ.equals(getActionRequested()) || KewApiConstants.ACTION_REQUEST_COMPLETE_REQ.equals(getActionRequested());
544        }
545    
546        public boolean isDone() {
547            return ActionRequestStatus.DONE.getCode().equals(getStatus());
548        }
549    
550        public boolean isReviewerUser() {
551            return RecipientType.PRINCIPAL.getCode().equals(getRecipientTypeCd());
552        }
553    
554        /**
555         * Determines whether the specified principalId is in the recipient graph of this action request
556         * @param principalId the principal id to check
557         * @return whether the specified principalId is in the recipient graph of this action request
558         */
559        public boolean isRecipientRoutedRequest(String principalId) {
560            //before altering this method it is used in checkRouteLogAuthentication
561            //don't break that method
562            if (principalId == null || "".equals(principalId)) {
563                    return false;
564            }
565    
566            boolean isRecipientInGraph = false;
567            if (isReviewerUser()) {
568                            isRecipientInGraph = getPrincipalId().equals(principalId);
569            } else if (isGroupRequest()) {
570                    Group group = getGroup();
571                            if (group == null){
572                                    LOG.error("Was unable to retrieve workgroup " + getGroupId());
573                            }
574                    isRecipientInGraph = KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, group.getId());
575            }
576    
577    
578            for (ActionRequestValue childRequest : getChildrenRequests())
579            {
580                isRecipientInGraph = isRecipientInGraph || childRequest.isRecipientRoutedRequest(principalId);
581            }
582    
583            return isRecipientInGraph;
584        }
585    
586        public boolean isRecipientRoutedRequest(Recipient recipient) {
587            //before altering this method it is used in checkRouteLogAuthentication
588            //don't break that method
589            if (recipient == null) {
590                    return false;
591            }
592    
593            boolean isRecipientInGraph = false;
594            if (isReviewerUser()) {
595                    if (recipient instanceof KimPrincipalRecipient) {
596                            isRecipientInGraph = getPrincipalId().equals(((KimPrincipalRecipient) recipient).getPrincipalId());
597                    } else if (recipient instanceof KimGroupRecipient){
598                            isRecipientInGraph = KimApiServiceLocator.getGroupService().isMemberOfGroup(getPrincipalId(), ((KimGroupRecipient)recipient).getGroup().getId());
599                    }
600    
601            } else if (isGroupRequest()) {
602                    Group group = getGroup();
603                            if (group == null){
604                                    LOG.error("Was unable to retrieve workgroup " + getGroupId());
605                            }
606                    if (recipient instanceof KimPrincipalRecipient) {
607                            KimPrincipalRecipient principalRecipient = (KimPrincipalRecipient)recipient;
608                            isRecipientInGraph = KimApiServiceLocator.getGroupService().isMemberOfGroup(principalRecipient.getPrincipalId(), group.getId());
609                    } else if (recipient instanceof KimGroupRecipient) {
610                            isRecipientInGraph = ((KimGroupRecipient) recipient).getGroup().getId().equals(group.getId());
611                    }
612            }
613    
614    
615            for (ActionRequestValue childRequest : getChildrenRequests())
616            {
617                isRecipientInGraph = isRecipientInGraph || childRequest.isRecipientRoutedRequest(recipient);
618            }
619    
620            return isRecipientInGraph;
621        }
622    
623        public boolean isGroupRequest(){
624            return RecipientType.GROUP.getCode().equals(getRecipientTypeCd());
625        }
626    
627        public boolean isRoleRequest() {
628            return RecipientType.ROLE.getCode().equals(getRecipientTypeCd());
629        }
630    
631        public boolean isAcknowledgeRequest() {
632            return KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ.equals(getActionRequested());
633        }
634    
635        public boolean isApproveRequest() {
636            return KewApiConstants.ACTION_REQUEST_APPROVE_REQ.equals(getActionRequested());
637        }
638    
639        public boolean isCompleteRequst() {
640            return KewApiConstants.ACTION_REQUEST_COMPLETE_REQ.equals(getActionRequested());
641        }
642    
643        public boolean isFYIRequest() {
644            return KewApiConstants.ACTION_REQUEST_FYI_REQ.equals(getActionRequested());
645        }
646    
647        /**
648         * Allows comparison of action requests to see which is greater responsibility. -1 : indicates code 1 is lesser responsibility than code 2 0 : indicates the same responsibility 1 : indicates code1 is greater responsibility than code 2 The priority of action requests is as follows: fyi < acknowledge < (approve == complete)
649         *
650         * @param code1
651         * @param code2
652         * @param completeAndApproveTheSame
653         * @return -1 if less than, 0 if equal, 1 if greater than
654         */
655        public static int compareActionCode(String code1, String code2, boolean completeAndApproveTheSame) {
656            int cutoff = Integer.MAX_VALUE;
657            if (completeAndApproveTheSame) {
658                    // hacked so that APPROVE and COMPLETE are equal
659                    cutoff = ACTION_CODE_RANK.length() - 3;
660            }
661            Integer code1Index = Math.min(ACTION_CODE_RANK.indexOf(code1), cutoff);
662            Integer code2Index = Math.min(ACTION_CODE_RANK.indexOf(code2), cutoff);
663            return code1Index.compareTo(code2Index);
664        }
665    
666        /**
667         * Allows comparison of action requests to see which is greater responsibility. -1 : indicates type 1 is lesser responsibility than type 2 0 : indicates the same responsibility 1 : indicates type1 is greater responsibility than type 2
668         *
669         * @param type1
670         * @param type2
671         * @return -1 if less than, 0 if equal, 1 if greater than
672         */
673        public static int compareRecipientType(String type1, String type2) {
674            Integer type1Index = RECIPIENT_TYPE_RANK.indexOf(type1);
675            Integer type2Index = RECIPIENT_TYPE_RANK.indexOf(type2);
676            return type1Index.compareTo(type2Index);
677        }
678    
679        public static int compareDelegationType(DelegationType type1, DelegationType type2) {
680            Integer type1Index = DELEGATION_TYPE_RANK.indexOf(type1);
681            Integer type2Index = DELEGATION_TYPE_RANK.indexOf(type2);
682            return type1Index.compareTo(type2Index);
683        }
684    
685        public List<ActionItem> getActionItems() {
686            if (this.simulatedActionItems == null || this.simulatedActionItems.isEmpty()) {
687                    return (List<ActionItem>) KEWServiceLocator.getActionListService().findByActionRequestId(actionRequestId);
688            } else {
689                    return this.simulatedActionItems;
690            }
691        }
692    
693        public List<ActionItem> getSimulatedActionItems() {
694            if (this.simulatedActionItems == null) {
695                    this.simulatedActionItems = new ArrayList<ActionItem>();
696            }
697                    return this.simulatedActionItems;
698            }
699    
700            public void setSimulatedActionItems(List<ActionItem> simulatedActionItems) {
701                    this.simulatedActionItems = simulatedActionItems;
702            }
703    
704            public Boolean getCurrentIndicator() {
705            return currentIndicator;
706        }
707    
708        public void setCurrentIndicator(Boolean currentIndicator) {
709            this.currentIndicator = currentIndicator;
710        }
711    
712        public String getParentActionRequestId() {
713            return parentActionRequestId;
714        }
715    
716        public void setParentActionRequestId(String parentActionRequestId) {
717            this.parentActionRequestId = parentActionRequestId;
718        }
719    
720        public ActionRequestValue getParentActionRequest() {
721            return parentActionRequest;
722        }
723    
724        public void setParentActionRequest(ActionRequestValue parentActionRequest) {
725            this.parentActionRequest = parentActionRequest;
726        }
727    
728        public List<ActionRequestValue> getChildrenRequests() {
729            return childrenRequests;
730        }
731    
732        public void setChildrenRequests(List<ActionRequestValue> childrenRequests) {
733            this.childrenRequests = childrenRequests;
734        }
735    
736        public String getQualifiedRoleName() {
737            return qualifiedRoleName;
738        }
739    
740        public void setQualifiedRoleName(String roleName) {
741            this.qualifiedRoleName = roleName;
742        }
743    
744        public DelegationType getDelegationType() {
745            return DelegationType.fromCode(delegationTypeCode);
746        }
747    
748        public void setDelegationType(DelegationType delegationPolicy) {
749            this.delegationTypeCode = delegationPolicy == null ? null : delegationPolicy.getCode();
750        }
751    
752    
753        public String getDelegationTypeCode() {
754            return delegationTypeCode;
755        }
756    
757        public void setDelegationTypeCode(String delegationTypeCode) {
758            this.delegationTypeCode = delegationTypeCode;
759        }
760    
761        public String getRoleName() {
762            return roleName;
763        }
764    
765        public void setRoleName(String roleName) {
766            this.roleName = roleName;
767        }
768    
769        public String getApprovePolicy() {
770            return approvePolicy;
771        }
772    
773        public void setApprovePolicy(String requestType) {
774            this.approvePolicy = requestType;
775        }
776    
777        public boolean getHasApprovePolicy() {
778            return getApprovePolicy() != null;
779        }
780    
781        public boolean isDeactivated() {
782            return ActionRequestStatus.DONE.getCode().equals(getStatus());
783        }
784    
785        public boolean hasParent() {
786            return getParentActionRequest() != null;
787        }
788    
789        public boolean hasChild(ActionRequestValue actionRequest) {
790            if (actionRequest == null)
791                return false;
792            String actionRequestId = actionRequest.getActionRequestId();
793            for (Iterator<ActionRequestValue> iter = getChildrenRequests().iterator(); iter.hasNext();) {
794                ActionRequestValue childRequest = iter.next();
795                if (childRequest.equals(actionRequest) || (actionRequestId != null && actionRequestId.equals(childRequest.getActionRequestId()))) {
796                    return true;
797                }
798            }
799            return false;
800        }
801    
802        public String getDisplayStatus() {
803            return displayStatus;
804        }
805    
806        public void setDisplayStatus(String displayStatus) {
807            this.displayStatus = displayStatus;
808        }
809    
810        public String getQualifiedRoleNameLabel() {
811            return qualifiedRoleNameLabel;
812        }
813    
814        public void setQualifiedRoleNameLabel(String qualifiedRoleNameLabel) {
815            this.qualifiedRoleNameLabel = qualifiedRoleNameLabel;
816        }
817    
818        public String getCreateDateString() {
819            if (createDateString == null || createDateString.trim().equals("")) {
820                return RiceConstants.getDefaultDateFormat().format(getCreateDate());
821            } else {
822                return createDateString;
823            }
824        }
825    
826        public void setCreateDateString(String createDateString) {
827            this.createDateString = createDateString;
828        }
829    
830        public RouteNodeInstance getNodeInstance() {
831                    return nodeInstance;
832            }
833    
834        public String getPotentialNodeName() {
835            return (getNodeInstance() == null ? "" : getNodeInstance().getName());
836        }
837    
838            public void setNodeInstance(RouteNodeInstance nodeInstance) {
839                    this.nodeInstance = nodeInstance;
840            }
841    
842            public String getRecipientTypeLabel() {
843                    return RecipientType.fromCode(getRecipientTypeCd()).getLabel();
844        }
845    
846        public RuleBaseValues getRuleBaseValues(){
847            if(ruleBaseValuesId != null){
848                return getRuleService().findRuleBaseValuesById(ruleBaseValuesId);
849            }
850            return null;
851        }
852        public String getRuleBaseValuesId() {
853            return ruleBaseValuesId;
854        }
855    
856        public void setRuleBaseValuesId(String ruleBaseValuesId) {
857            this.ruleBaseValuesId = ruleBaseValuesId;
858        }
859        
860            private RuleServiceInternal getRuleService() {
861            return (RuleServiceInternal) KEWServiceLocator.getService(KEWServiceLocator.RULE_SERVICE);
862        }
863    
864        public boolean isPrimaryDelegator() {
865            boolean primaryDelegator = false;
866            for (Iterator<ActionRequestValue> iter = childrenRequests.iterator(); iter.hasNext();) {
867                ActionRequestValue childRequest = iter.next();
868                primaryDelegator = DelegationType.PRIMARY.equals(childRequest.getDelegationType()) || primaryDelegator;
869            }
870            return primaryDelegator;
871        }
872    
873        /**
874         * Used to get primary delegate names on route log in the 'Requested Of' section so primary delegate requests
875         * list the delegate and not the delegator as having the request 'IN ACTION LIST'.  This method doesn't recurse
876         * and therefore assume an AR structure.
877         *
878         * @return primary delgate requests
879         */
880        public List<ActionRequestValue> getPrimaryDelegateRequests() {
881            List<ActionRequestValue> primaryDelegateRequests = new ArrayList<ActionRequestValue>();
882            for (ActionRequestValue childRequest : childrenRequests)
883            {
884                if (DelegationType.PRIMARY.equals(childRequest.getDelegationType()))
885                {
886                    if (childRequest.isRoleRequest())
887                    {
888                        for (ActionRequestValue actionRequestValue : childRequest.getChildrenRequests())
889                        {
890                            primaryDelegateRequests.add(actionRequestValue);
891                        }
892                    } else
893                    {
894                            primaryDelegateRequests.add(childRequest);
895                    }
896                }
897            }
898            return primaryDelegateRequests;
899        }
900    
901        public boolean isAdHocRequest() {                                          
902            return KewApiConstants.ADHOC_REQUEST_RESPONSIBILITY_ID.equals(getResponsibilityId());
903        }
904    
905        public boolean isGeneratedRequest() {
906            return KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID.equals(getResponsibilityId());
907        }
908    
909        public boolean isExceptionRequest() {
910            return KewApiConstants.EXCEPTION_REQUEST_RESPONSIBILITY_ID.equals(getResponsibilityId());
911        }
912    
913        public boolean isRouteModuleRequest() {
914            // FIXME: KULRICE-5201 switched rsp_id to a varchar, so the comparison below is no longer valid
915    //      return getResponsibilityId() > 0;
916            // TODO: KULRICE-5329 Verify that this code below makes sense 
917            return getResponsibilityId() != null && !KewApiConstants.SPECIAL_RESPONSIBILITY_ID_SET.contains(getResponsibilityId());
918        }
919    
920        public String toString() {
921            return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
922                .append("actionRequestId", actionRequestId)
923                .append("actionRequested", actionRequested)
924                .append("documentId", documentId)
925                .append("status", status)
926                .append("responsibilityId", responsibilityId)
927                .append("groupId", groupId)
928                .append("recipientTypeCd", recipientTypeCd)
929                .append("priority", priority)
930                .append("routeLevel", routeLevel)
931                .append("actionTakenId", actionTakenId)
932                .append("docVersion", docVersion)
933                .append("createDate", createDate)
934                .append("responsibilityDesc", responsibilityDesc)
935                .append("annotation", annotation)
936                .append("jrfVerNbr", jrfVerNbr)
937                .append("principalId", principalId)
938                .append("forceAction", forceAction)
939                .append("parentActionRequestId", parentActionRequestId)
940                .append("qualifiedRoleName", qualifiedRoleName)
941                .append("roleName", roleName)
942                .append("qualifiedRoleNameLabel", qualifiedRoleNameLabel)
943                .append("displayStatus", displayStatus)
944                .append("ruleBaseValuesId", ruleBaseValuesId)
945                .append("delegationType", delegationTypeCode)
946                .append("approvePolicy", approvePolicy)
947                .append("actionTaken", actionTaken)
948                .append("currentIndicator", currentIndicator)
949                .append("createDateString", createDateString)
950                .append("nodeInstance", nodeInstance).toString();
951        }
952    
953            public String getRequestLabel() {
954                    return this.requestLabel;
955            }
956    
957            public void setRequestLabel(String requestLabel) {
958                    this.requestLabel = requestLabel;
959            }
960    
961        public String getGroupName() {
962            return KimApiServiceLocator.getGroupService().getGroup(this.groupId).getName();
963        }
964    
965            /**
966             * @return the resolveResponsibility
967             */
968            public boolean getResolveResponsibility() {
969                    return this.resolveResponsibility;
970            }
971    
972            /**
973             * @param resolveResponsibility the resolveResponsibility to set
974             */
975            public void setResolveResponsibility(boolean resolveResponsibility) {
976                    this.resolveResponsibility = resolveResponsibility;
977            }
978    
979            public DocumentRouteHeaderValue getRouteHeader() {
980                    if (this.routeHeader == null && this.documentId != null) {
981                            this.routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(this.documentId);
982                    }
983                    return this.routeHeader;
984            }
985    
986            public void setRouteHeader(DocumentRouteHeaderValue routeHeader) {
987                    this.routeHeader = routeHeader;
988            }
989            
990            public static ActionRequest to(ActionRequestValue actionRequestBo) {
991                    if (actionRequestBo == null) {
992                            return null;
993                    }
994                    return createActionRequestBuilder(actionRequestBo).build();
995            }
996            
997            private static ActionRequest.Builder createActionRequestBuilder(ActionRequestValue actionRequestBo) {
998                    ActionRequest.Builder builder = ActionRequest.Builder.create(actionRequestBo.getActionRequestId(),
999                                    ActionRequestType.fromCode(actionRequestBo.getActionRequested()),
1000                                    ActionRequestStatus.fromCode(actionRequestBo.getStatus()),
1001                                    actionRequestBo.getResponsibilityId(),
1002                                    actionRequestBo.getDocumentId(),
1003                                    RecipientType.fromCode(actionRequestBo.getRecipientTypeCd()));
1004                    if (actionRequestBo.getActionTaken() != null) {
1005                            builder.setActionTaken(ActionTaken.Builder.create(ActionTakenValue.to(actionRequestBo.getActionTaken())));
1006                    }
1007                    builder.setAnnotation(actionRequestBo.getAnnotation());
1008                    builder.setCurrent(actionRequestBo.getCurrentIndicator().booleanValue());
1009                    builder.setDateCreated(new DateTime(actionRequestBo.getCreateDate().getTime()));
1010                    if (actionRequestBo.getDelegationType() != null) {
1011                            builder.setDelegationType(actionRequestBo.getDelegationType());
1012                    }
1013                    builder.setForceAction(actionRequestBo.getForceAction().booleanValue());
1014                    builder.setGroupId(actionRequestBo.getGroupId());
1015                    builder.setNodeName(actionRequestBo.getPotentialNodeName());
1016                    if (actionRequestBo.getParentActionRequestId() != null) {
1017                            builder.setParentActionRequestId(actionRequestBo.getParentActionRequestId());
1018                    }
1019                    builder.setPrincipalId(actionRequestBo.getPrincipalId());
1020                    if (actionRequestBo.getPriority() == null) {
1021                            builder.setPriority(KewApiConstants.ACTION_REQUEST_DEFAULT_PRIORITY);
1022                    } else {
1023                builder.setPriority(actionRequestBo.getPriority().intValue());
1024            }
1025            if (actionRequestBo.getRouteLevel() == null ) {
1026                builder.setRouteLevel(0);
1027            } else {
1028                builder.setRouteLevel(actionRequestBo.getRouteLevel().intValue());
1029            }
1030                    builder.setQualifiedRoleName(actionRequestBo.getQualifiedRoleName());
1031                    builder.setQualifiedRoleNameLabel(actionRequestBo.getQualifiedRoleNameLabel());
1032                    builder.setRequestLabel(actionRequestBo.getRequestLabel());
1033                    if (!StringUtils.isBlank(actionRequestBo.getApprovePolicy())) {
1034                            builder.setRequestPolicy(ActionRequestPolicy.fromCode(actionRequestBo.getApprovePolicy()));
1035                    }
1036                    builder.setResponsibilityDescription(actionRequestBo.getResponsibilityDesc());
1037                    builder.setRoleName(actionRequestBo.getRoleName());
1038                    if (actionRequestBo.getNodeInstance() != null) {
1039                            builder.setRouteNodeInstanceId(actionRequestBo.getNodeInstance().getRouteNodeInstanceId());
1040                    }
1041                    
1042                    List<ActionRequest.Builder> childRequests = new ArrayList<ActionRequest.Builder>();
1043                    if (actionRequestBo.getChildrenRequests() != null) {
1044                            for (ActionRequestValue childActionRequestBo : actionRequestBo.getChildrenRequests()) {
1045                                    childRequests.add(createActionRequestBuilder(childActionRequestBo));
1046                            }
1047                    }
1048                    builder.setChildRequests(childRequests);
1049                    return builder;
1050            }
1051            
1052        /**
1053         * TODO - this javadoc copied from DTOConverter, needs to be updated!
1054         * 
1055         * Converts an ActionRequestVO to an ActionRequest. The ActionRequestDTO passed in must be the root action request in the
1056         * graph, otherwise an IllegalArgumentException is thrown. This is to avoid potentially sticky issues with circular
1057         * references in the conversion. NOTE: This method's primary purpose is to convert ActionRequestVOs returned from a
1058         * RouteModule. Incidentally, the DTO's returned from the route module will be lacking some information (like the node
1059         * instance) so no attempts are made to convert this data since further initialization is handled by a higher level
1060         * component (namely ActionRequestService.initializeActionRequestGraph).
1061         */
1062        public static ActionRequestValue from(ActionRequest actionRequest) {
1063            return ActionRequestValue.from(actionRequest, null);
1064        }
1065        
1066        /**
1067         * Converts an ActionRequestVO to an ActionRequest. The ActionRequestDTO passed in must be the root action request in the
1068         * graph, otherwise an IllegalArgumentException is thrown. This is to avoid potentially sticky issues with circular
1069         * references in the conversion. 
1070         * @param routeNodeInstanceLoader a service that will provide routeNodeInstanceS based on their IDs.
1071         */
1072        public static ActionRequestValue from(ActionRequest actionRequest, 
1073                RouteNodeInstanceLoader routeNodeInstanceLoader) {
1074            return convertActionRequest(actionRequest, null, routeNodeInstanceLoader);
1075        }
1076    
1077        private static ActionRequestValue convertActionRequest(ActionRequest actionRequest, ActionRequestValue parentActionRequestBo,
1078                RouteNodeInstanceLoader routeNodeInstanceLoader) {
1079            if (actionRequest == null) {
1080                return null;
1081            }
1082            ActionRequestValue actionRequestBo = new ActionRequestFactory().createBlankActionRequest();
1083            populateActionRequest(actionRequestBo, actionRequest, routeNodeInstanceLoader);
1084            if (parentActionRequestBo != null) {
1085                actionRequestBo.setParentActionRequest(parentActionRequestBo);
1086                actionRequestBo.setParentActionRequestId(parentActionRequestBo.getActionRequestId());
1087            }
1088            if (actionRequest.getChildRequests() != null) {
1089                for (ActionRequest childRequest : actionRequest.getChildRequests()) {
1090                    actionRequestBo.getChildrenRequests().add(ActionRequestValue.convertActionRequest(childRequest, actionRequestBo, routeNodeInstanceLoader));
1091                }
1092            }
1093            return actionRequestBo;
1094        }
1095    
1096        /**
1097         * This method converts everything except for the parent and child requests
1098         */
1099        private static void populateActionRequest(ActionRequestValue actionRequestBo, ActionRequest actionRequest, 
1100                RouteNodeInstanceLoader routeNodeInstanceLoader) {
1101    
1102            actionRequestBo.setActionRequested(actionRequest.getActionRequested().getCode());
1103            if (!StringUtils.isBlank(actionRequest.getId())) {
1104                actionRequestBo.setActionRequestId(actionRequest.getId());
1105            }
1106            
1107            if (actionRequest.getActionTaken() != null) {
1108                // actionRequestBo.setActionTaken(ActionTakenValue.from(actionRequest.getActionTaken()));
1109                if (!StringUtils.isBlank(actionRequest.getActionTaken().getId())) {
1110                    actionRequestBo.setActionTakenId(actionRequest.getActionTaken().getId());
1111                }
1112            }
1113            actionRequestBo.setAnnotation(actionRequest.getAnnotation());
1114            if (actionRequest.getRequestPolicy() != null) {
1115                actionRequestBo.setApprovePolicy(actionRequest.getRequestPolicy().getCode());
1116            }
1117            actionRequestBo.setCreateDate(new Timestamp(actionRequest.getDateCreated().getMillis()));
1118            actionRequestBo.setCurrentIndicator(actionRequest.isCurrent());
1119            if (actionRequest.getDelegationType() != null) {
1120                actionRequestBo.setDelegationType(actionRequest.getDelegationType());
1121            }
1122            //actionRequestBo.setDocVersion(actionRequest.?);
1123            actionRequestBo.setForceAction(actionRequest.isForceAction());
1124            actionRequestBo.setPriority(actionRequest.getPriority());
1125            actionRequestBo.setRouteLevel(actionRequest.getRouteLevel());
1126            actionRequestBo.setQualifiedRoleName(actionRequest.getQualifiedRoleName());
1127            actionRequestBo.setQualifiedRoleNameLabel(actionRequest.getQualifiedRoleNameLabel());
1128            actionRequestBo.setRecipientTypeCd(actionRequest.getRecipientType().getCode());
1129            actionRequestBo.setResponsibilityDesc(actionRequest.getResponsibilityDescription());
1130            if (!StringUtils.isBlank(actionRequest.getResponsibilityId())) {
1131                actionRequestBo.setResponsibilityId(actionRequest.getResponsibilityId());
1132            }
1133            actionRequestBo.setRoleName(actionRequest.getRoleName());
1134            String documentId = actionRequest.getDocumentId();
1135            if (documentId != null) {
1136                actionRequestBo.setDocumentId(documentId);
1137                actionRequestBo.setRouteHeader(KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId));
1138            }
1139    
1140            actionRequestBo.setStatus(actionRequest.getStatus().getCode());
1141            actionRequestBo.setPrincipalId(actionRequest.getPrincipalId());
1142            actionRequestBo.setGroupId(actionRequest.getGroupId());
1143            
1144            if (routeNodeInstanceLoader != null && !StringUtils.isBlank(actionRequest.getRouteNodeInstanceId())) {
1145                actionRequestBo.setNodeInstance(routeNodeInstanceLoader.load(actionRequest.getRouteNodeInstanceId()));
1146            }
1147        }
1148        
1149    }