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