View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.engine.node;
17  
18  import java.io.Serializable;
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.Map;
22  
23  import javax.persistence.CascadeType;
24  import javax.persistence.Column;
25  import javax.persistence.Entity;
26  import javax.persistence.FetchType;
27  import javax.persistence.GeneratedValue;
28  import javax.persistence.Id;
29  import javax.persistence.JoinColumn;
30  import javax.persistence.JoinTable;
31  import javax.persistence.ManyToMany;
32  import javax.persistence.ManyToOne;
33  import javax.persistence.NamedQueries;
34  import javax.persistence.NamedQuery;
35  import javax.persistence.OneToMany;
36  import javax.persistence.OneToOne;
37  import javax.persistence.Table;
38  import javax.persistence.Transient;
39  import javax.persistence.Version;
40  
41  import org.apache.commons.lang.StringUtils;
42  import org.apache.log4j.Logger;
43  import org.hibernate.annotations.Fetch;
44  import org.hibernate.annotations.FetchMode;
45  import org.hibernate.annotations.GenericGenerator;
46  import org.hibernate.annotations.Parameter;
47  import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
48  import org.kuali.rice.kew.api.doctype.RouteNodeConfigurationParameterContract;
49  import org.kuali.rice.kew.api.doctype.RouteNodeContract;
50  import org.kuali.rice.kew.api.exception.ResourceUnavailableException;
51  import org.kuali.rice.kew.doctype.bo.DocumentType;
52  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
53  import org.kuali.rice.kew.rule.service.RuleTemplateService;
54  import org.kuali.rice.kew.service.KEWServiceLocator;
55  import org.kuali.rice.kew.api.KewApiConstants;
56  import org.kuali.rice.kew.util.Utilities;
57  import org.kuali.rice.kim.api.group.Group;
58  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
59  
60  /**
61   * Represents the prototype definition of a node in the route path of {@link DocumentType}.
62   *
63   * @author Kuali Rice Team (rice.collab@kuali.org)
64   */
65  @Entity
66  @Table(name="KREW_RTE_NODE_T")
67  //@Sequence(name="KREW_RTE_NODE_S", property="routeNodeId")
68  @NamedQueries({
69  	@NamedQuery(name="RouteNode.FindByRouteNodeId",query="select r from RouteNode as r where r.routeNodeId = :routeNodeId"),
70  	@NamedQuery(name="RouteNode.FindRouteNodeByName", query="select r from RouteNode as r where r.routeNodeName = :routeNodeName and r.documentTypeId = :documentTypeId"),
71  	@NamedQuery(name="RouteNode.FindApprovalRouteNodes", query="select r from RouteNode as r where r.documentTypeId = :documentTypeId and r.finalApprovalInd = :finalApprovalInd")
72  })
73  public class RouteNode implements Serializable, RouteNodeContract {    
74  
75      private static final long serialVersionUID = 4891233177051752726L;
76  
77      public static final String CONTENT_FRAGMENT_CFG_KEY = "contentFragment";
78      public static final String RULE_SELECTOR_CFG_KEY = "ruleSelector";
79  
80      @Id
81      @GeneratedValue(generator="KREW_RTE_NODE_S")
82  	@GenericGenerator(name="KREW_RTE_NODE_S",strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",parameters={
83  			@Parameter(name="sequence_name",value="KREW_RTE_NODE_S"),
84  			@Parameter(name="value_column",value="id")
85  	})
86  	@Column(name="RTE_NODE_ID")
87  	private String routeNodeId;
88      @Column(name="DOC_TYP_ID",insertable=false, updatable=false)
89  	private String documentTypeId;
90      @Column(name="NM")
91  	private String routeNodeName;
92      @Column(name="RTE_MTHD_NM")
93  	private String routeMethodName;
94      @Column(name="FNL_APRVR_IND")
95  	private Boolean finalApprovalInd;
96      @Column(name="MNDTRY_RTE_IND")
97  	private Boolean mandatoryRouteInd;
98      @Column(name="GRP_ID")
99  	private String exceptionWorkgroupId;
100     @Column(name="RTE_MTHD_CD")
101 	private String routeMethodCode;
102     @Column(name="ACTVN_TYP")
103     private String activationType = ActivationTypeEnum.PARALLEL.getCode();
104     
105     /**
106      * The nextDocStatus property represents the value of the ApplicationDocumentStatus to be set 
107      * in the RouteHeader upon transitioning from this node.
108      */
109     @Column(name="NEXT_DOC_STAT")
110 	private String nextDocStatus;
111 
112     @Version
113 	@Column(name="VER_NBR")
114 	private Integer lockVerNbr;
115     @ManyToOne(fetch=FetchType.EAGER)
116 	@JoinColumn(name="DOC_TYP_ID")
117 	private DocumentType documentType;
118     @Transient
119     private String exceptionWorkgroupName;
120 
121     @Transient
122     private RuleTemplateBo ruleTemplate;
123     @Column(name="TYP")
124     private String nodeType = RequestsNode.class.getName();
125     
126     //@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}, mappedBy="nextNodes")
127     @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST}, mappedBy="nextNodes")
128     @Fetch(value = FetchMode.SELECT)
129     //@JoinTable(name = "KREW_RTE_NODE_LNK_T", joinColumns = @JoinColumn(name = "TO_RTE_NODE_ID"), inverseJoinColumns = @JoinColumn(name = "FROM_RTE_NODE_ID"))
130     private List<RouteNode> previousNodes = new ArrayList<RouteNode>();
131     //@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST})
132     @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST})
133     @Fetch(value = FetchMode.SELECT)
134     @JoinTable(name = "KREW_RTE_NODE_LNK_T", joinColumns = @JoinColumn(name = "FROM_RTE_NODE_ID"), inverseJoinColumns = @JoinColumn(name = "TO_RTE_NODE_ID"))
135     private List<RouteNode> nextNodes = new ArrayList<RouteNode>();
136     @OneToOne(fetch=FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE})
137 	@JoinColumn(name="BRCH_PROTO_ID")
138 	private BranchPrototype branch;
139     @OneToMany(fetch=FetchType.EAGER,mappedBy="routeNode",cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
140     @Fetch(value = FetchMode.SELECT)
141     private List<RouteNodeConfigParam> configParams  = new ArrayList<RouteNodeConfigParam>(0);
142 
143     /**
144      * Looks up a config parameter for this route node definition
145      * @param key the config param key 
146      * @return the RouteNodeConfigParam if present
147      */
148     protected RouteNodeConfigParam getConfigParam(String key) {
149         Map<String, RouteNodeConfigParam> configParamMap = Utilities.getKeyValueCollectionAsLookupTable(configParams);
150         return configParamMap.get(key);
151     }
152 
153     /**
154      * Sets a config parameter for this route node definition.  If the key already exists
155      * the existing RouteNodeConfigParam is modified, otherwise a new one is created
156      * @param key the key of the parameter to set
157      * @param value the value to set
158      */
159     protected void setConfigParam(String key, String value) {
160         Map<String, RouteNodeConfigParam> configParamMap = Utilities.getKeyValueCollectionAsLookupTable(configParams);
161         RouteNodeConfigParam cfCfgParam = configParamMap.get(key);
162         if (cfCfgParam == null) {
163             cfCfgParam = new RouteNodeConfigParam(this, key, value);
164             configParams.add(cfCfgParam);
165         } else {
166             cfCfgParam.setValue(value);
167         }
168     }
169 
170     public List<RouteNodeConfigParam> getConfigParams() {
171         return configParams;
172     }
173 
174     public void setConfigParams(List<RouteNodeConfigParam> configParams) {
175         this.configParams = configParams;
176     }
177 
178     /**
179      * @return the RouteNodeConfigParam value under the 'contentFragment'  key
180      */
181     public String getContentFragment() {
182         RouteNodeConfigParam cfCfgParam = getConfigParam(CONTENT_FRAGMENT_CFG_KEY);
183         if (cfCfgParam == null) return null;
184         return cfCfgParam.getValue();
185     }
186 
187     /**
188      * @param contentFragment the content fragment of the node, which will be set as a RouteNodeConfigParam under the 'contentFragment' key
189      */
190     public void setContentFragment(String contentFragment) {
191         setConfigParam(CONTENT_FRAGMENT_CFG_KEY, contentFragment);
192     }
193 
194     public String getActivationType() {
195         return activationType;
196     }
197 
198     public void setActivationType(String activationType) {
199         /* Cleanse the input.
200          * This is surely not the best way to validate the activation types;
201          * it would probably be better to use typesafe enums accross the board
202          * but that would probably entail refactoring large swaths of code, not
203          * to mention reconfiguring OJB (can typesafe enums be used?) and dealing
204          * with serialization compatibility issues (if any).
205          * So instead, let's just be sure to fail-fast.
206          */
207         ActivationTypeEnum at = ActivationTypeEnum.lookupCode(activationType);
208         this.activationType = at.getCode();
209     }
210 
211     public Group getExceptionWorkgroup() {
212     	if (!StringUtils.isBlank(exceptionWorkgroupId)) {
213     		return KimApiServiceLocator.getGroupService().getGroup(exceptionWorkgroupId);
214     	}
215     	return null;
216     }
217     
218     public boolean isExceptionGroupDefined() {
219     	return getExceptionWorkgroupId() != null;
220     }
221 
222     public String getExceptionWorkgroupId() {
223         return exceptionWorkgroupId;
224     }
225 
226     public void setExceptionWorkgroupId(String workgroupId) {
227         this.exceptionWorkgroupId = workgroupId;
228     }
229 
230     public void setFinalApprovalInd(Boolean finalApprovalInd) {
231         this.finalApprovalInd = finalApprovalInd;
232     }
233 
234     public void setMandatoryRouteInd(Boolean mandatoryRouteInd) {
235         this.mandatoryRouteInd = mandatoryRouteInd;
236     }
237 
238     public String getRouteMethodName() {
239         return routeMethodName;
240     }
241 
242     public void setRouteMethodName(String routeMethodName) {
243         this.routeMethodName = routeMethodName;
244     }
245 
246     public String getDocumentTypeId() {
247         return documentTypeId;
248     }
249 
250     public void setDocumentTypeId(String documentTypeId) {
251         this.documentTypeId = documentTypeId;
252     }
253 
254     public String getRouteNodeId() {
255         return routeNodeId;
256     }
257 
258     public void setRouteNodeId(String routeNodeId) {
259         this.routeNodeId = routeNodeId;
260     }
261 
262     public String getRouteNodeName() {
263         return routeNodeName;
264     }
265 
266     public void setRouteNodeName(String routeLevelName) {
267         this.routeNodeName = routeLevelName;
268     }
269 
270     public DocumentType getDocumentType() {
271         return documentType;
272     }
273 
274     public void setDocumentType(DocumentType documentType) {
275         this.documentType = documentType;
276     }
277 
278     public String getRouteMethodCode() {
279         return routeMethodCode;
280     }
281 
282     public void setRouteMethodCode(String routeMethodCode) {
283         this.routeMethodCode = routeMethodCode;
284     }
285 
286 	/**
287 	 * @param nextDocStatus the nextDocStatus to set
288 	 */
289 	public void setNextDocStatus(String nextDocStatus) {
290 		this.nextDocStatus = nextDocStatus;
291 	}
292 
293 	/**
294 	 * @return the nextDocStatus
295 	 */
296 	public String getNextDocStatus() {
297 		return nextDocStatus;
298 	}
299 	
300     public String getExceptionWorkgroupName() {
301     	Group exceptionGroup = getExceptionWorkgroup();
302         if (exceptionWorkgroupName == null || exceptionWorkgroupName.equals("")) {
303             if (exceptionGroup != null) {
304                 return exceptionGroup.getName();
305             }
306         }
307         return exceptionWorkgroupName;
308     }
309 
310     public void setExceptionWorkgroupName(String exceptionWorkgroupName) {
311         this.exceptionWorkgroupName = exceptionWorkgroupName;
312     }
313 
314     public Integer getLockVerNbr() {
315         return lockVerNbr;
316     }
317 
318     public void setLockVerNbr(Integer lockVerNbr) {
319         this.lockVerNbr = lockVerNbr;
320     }
321 
322     public boolean isFlexRM() {
323         return routeMethodCode != null && routeMethodCode.equals(KewApiConstants.ROUTE_LEVEL_FLEX_RM);
324     }
325 
326     public boolean isRulesEngineNode() {
327         return StringUtils.equals(routeMethodCode, KewApiConstants.ROUTE_LEVEL_RULES_ENGINE);
328     }
329 
330     public boolean isPeopleFlowNode() {
331         return StringUtils.equals(routeMethodCode, KewApiConstants.ROUTE_LEVEL_PEOPLE_FLOW);
332     }
333     
334     public boolean isRoleNode() {
335     	try {
336     		return nodeType != null && NodeType.fromNode(this).isTypeOf(NodeType.ROLE);
337     	} catch( ResourceUnavailableException ex ) {
338     		Logger.getLogger( RouteNode.class ).info( "isRoleNode(): Unable to determine node type: " + ex.getMessage() );
339     		return false;
340     	}
341     }
342 
343     public Boolean getFinalApprovalInd() {
344         return finalApprovalInd;
345     }
346 
347     public Boolean getMandatoryRouteInd() {
348         return mandatoryRouteInd;
349     }
350 
351     public void addNextNode(RouteNode nextNode) {
352         getNextNodes().add(nextNode);
353         nextNode.getPreviousNodes().add(this);
354     }
355 
356     public List<RouteNode> getNextNodes() {
357         return nextNodes;
358     }
359 
360     public void setNextNodes(List<RouteNode> nextNodes) {
361         this.nextNodes = nextNodes;
362     }
363 
364     public List<RouteNode> getPreviousNodes() {
365         return previousNodes;
366     }
367 
368     public void setPreviousNodes(List<RouteNode> parentNodes) {
369         this.previousNodes = parentNodes;
370     }
371 
372     public RuleTemplateBo getRuleTemplate() {
373         if (ruleTemplate == null) {
374             RuleTemplateService ruleTemplateService = (RuleTemplateService) KEWServiceLocator.getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
375             ruleTemplate = ruleTemplateService.findByRuleTemplateName(getRouteMethodName());
376         }
377         return ruleTemplate;
378     }
379 
380     public String getNodeType() {
381         return nodeType;
382     }
383 
384     public void setNodeType(String nodeType) {
385         this.nodeType = nodeType;
386     }
387 
388     public BranchPrototype getBranch() {
389         return branch;
390     }
391 
392     public void setBranch(BranchPrototype branch) {
393         this.branch = branch;
394     }
395 
396 	//@PrePersist
397 	public void beforeInsert(){
398 		OrmUtils.populateAutoIncValue(this, KEWServiceLocator.getEntityManagerFactory().createEntityManager());
399 	}
400 	
401 	/**
402 	 * This overridden method ...
403 	 * 
404 	 * @see java.lang.Object#toString()
405 	 */
406 	@Override
407 	public String toString() {
408 		return "RouteNode[routeNodeName="+routeNodeName+", nodeType="+nodeType+", activationType="+activationType+"]";
409 	}
410 
411     @Override
412     public Long getVersionNumber() {
413         if (lockVerNbr == null) {
414             return null;
415         }
416         return Long.valueOf(lockVerNbr.longValue());
417     }
418 
419     @Override
420     public String getId() {
421         if (routeNodeId == null) {
422             return null;
423         }
424         return routeNodeId.toString();
425     }
426 
427     @Override
428     public String getName() {
429         return getRouteNodeName();
430     }
431 
432     @Override
433     public boolean isFinalApproval() {
434         if (finalApprovalInd == null) {
435             return false;
436         }
437         return finalApprovalInd.booleanValue();
438     }
439 
440     @Override
441     public boolean isMandatory() {
442         if (mandatoryRouteInd == null) {
443             return false;
444         }
445         return mandatoryRouteInd.booleanValue();
446     }
447 
448     @Override
449     public String getExceptionGroupId() {
450         return exceptionWorkgroupId;
451     }
452 
453     @Override
454     public String getType() {
455         return nodeType;
456     }
457 
458     @Override
459     public String getBranchName() {
460         if (branch == null) {
461             return null;
462         }
463         return branch.getName();
464     }
465 
466     @Override
467     public String getNextDocumentStatus() {
468         return nextDocStatus;
469     }
470 
471     @Override
472     public List<? extends RouteNodeConfigurationParameterContract> getConfigurationParameters() {
473         return configParams;
474     }
475 
476     @Override
477     public List<String> getPreviousNodeIds() {
478         List<String> previousNodeIds = new ArrayList<String>();
479         if (previousNodes != null) {
480             for (RouteNode previousNode : previousNodes) {
481                 previousNodeIds.add(previousNode.getRouteNodeId().toString());
482             }
483         }
484         return previousNodeIds;
485     }
486 
487     @Override
488     public List<String> getNextNodeIds() {
489         List<String> nextNodeIds = new ArrayList<String>();
490         if (nextNodeIds != null) {
491             for (RouteNode nextNode : nextNodes) {
492                 nextNodeIds.add(nextNode.getRouteNodeId().toString());
493             }
494         }
495         return nextNodeIds;
496     }
497 	
498 	
499 
500 }