View Javadoc
1   /**
2    * Copyright 2005-2016 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.Iterator;
21  import java.util.List;
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.Version;
39  
40  import org.apache.commons.lang.builder.ToStringBuilder;
41  import org.hibernate.annotations.Fetch;
42  import org.hibernate.annotations.FetchMode;
43  import org.hibernate.annotations.GenericGenerator;
44  import org.hibernate.annotations.Parameter;
45  import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
46  import org.kuali.rice.kew.api.document.node.RouteNodeInstanceState;
47  import org.kuali.rice.kew.doctype.bo.DocumentType;
48  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
49  import org.kuali.rice.kew.service.KEWServiceLocator;
50  
51  
52  /**
53   * Represents a materialized instance of a {@link RouteNode} definition on a {@link DocumentRouteHeaderValue}.  Node instances
54   * are generated by the engine using the {@link RouteNode} as a prototype and connected as a 
55   * Directed Acyclic Graph.
56   *
57   * @author Kuali Rice Team (rice.collab@kuali.org)
58   */
59  @Entity
60  @Table(name="KREW_RTE_NODE_INSTN_T")
61  //@Sequence(name="KREW_RTE_NODE_S",property="routeNodeInstanceId")
62  @NamedQueries({
63  	@NamedQuery(name="RouteNodeInstance.FindByRouteNodeInstanceId",query="select r from RouteNodeInstance r where r.routeNodeInstanceId = :routeNodeInstanceId"),
64  	@NamedQuery(name="RouteNodeInstance.FindActiveNodeInstances",query="select r from RouteNodeInstance r where r.documentId = :documentId and r.active = true"),
65  	@NamedQuery(name="RouteNodeInstance.FindTerminalNodeInstances",query="select r from RouteNodeInstance r where r.documentId = :documentId and r.active = false and r.complete = true"),
66  	@NamedQuery(name="RouteNodeInstance.FindInitialNodeInstances",query="select d.initialRouteNodeInstances from DocumentRouteHeaderValue d where d.documentId = :documentId"),
67  	@NamedQuery(name="RouteNodeInstance.FindProcessNodeInstances", query="select r from RouteNodeInstance r where r.process.routeNodeInstanceId = :processId"),
68  	@NamedQuery(name="RouteNodeInstance.FindRouteNodeInstances", query="select r from RouteNodeInstance r where r.documentId = :documentId")
69  })
70  public class RouteNodeInstance implements Serializable {
71      
72  	private static final long serialVersionUID = 7183670062805580420L;
73  	
74  	@Id
75  	@GeneratedValue(generator="KREW_RTE_NODE_S")
76  	@GenericGenerator(name="KREW_RTE_NODE_S",strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",parameters={
77  			@Parameter(name="sequence_name",value="KREW_RTE_NODE_S"),
78  			@Parameter(name="value_column",value="id")
79  	})
80  	@Column(name="RTE_NODE_INSTN_ID")
81  	private String routeNodeInstanceId;
82      @Column(name="DOC_HDR_ID")
83  	private String documentId;
84      @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
85  	@JoinColumn(name="BRCH_ID")
86  	private Branch branch;
87      @OneToOne(fetch=FetchType.EAGER)
88  	@JoinColumn(name="RTE_NODE_ID")
89      private RouteNode routeNode;
90      @Column(name="ACTV_IND")
91      private boolean active = false;
92      @Column(name="CMPLT_IND")
93      private boolean complete = false;
94      @Column(name="INIT_IND")
95      private boolean initial = true;
96      @OneToOne(fetch=FetchType.EAGER,cascade={CascadeType.PERSIST, CascadeType.MERGE})
97  	@JoinColumn(name="PROC_RTE_NODE_INSTN_ID")
98  	private RouteNodeInstance process;
99      
100     @ManyToMany(fetch=FetchType.EAGER,cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
101     @JoinTable(name = "KREW_RTE_NODE_INSTN_LNK_T", joinColumns = @JoinColumn(name = "FROM_RTE_NODE_INSTN_ID"), inverseJoinColumns = @JoinColumn(name = "TO_RTE_NODE_INSTN_ID"))
102     @Fetch(value = FetchMode.SELECT)
103     private List<RouteNodeInstance> nextNodeInstances = new ArrayList<RouteNodeInstance>();
104     
105     @ManyToMany(fetch=FetchType.EAGER, mappedBy="nextNodeInstances")
106     @Fetch(value = FetchMode.SELECT)
107     //@JoinTable(name = "KREW_RTE_NODE_INSTN_LNK_T", joinColumns = @JoinColumn(name = "TO_RTE_NODE_INSTN_ID"), inverseJoinColumns = @JoinColumn(name = "FROM_RTE_NODE_INSTN_ID"))
108     private List<RouteNodeInstance> previousNodeInstances = new ArrayList<RouteNodeInstance>();
109 
110     @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE}, mappedBy="nodeInstance", orphanRemoval=true)    
111     @Fetch(value = FetchMode.SELECT)
112     private List<NodeState> state = new ArrayList<NodeState>();
113     	
114     @Version
115 	@Column(name="VER_NBR")
116 	private Integer lockVerNbr;
117     
118     private List<DocumentRouteHeaderValue> initialDocumentRouteHeaderValues = new ArrayList<DocumentRouteHeaderValue>();
119 
120     public boolean isActive() {
121         return active;
122     }
123     public void setActive(boolean active) {
124         this.active = active;
125     }
126     
127     public boolean isComplete() {
128         return complete;
129     }
130     public void setComplete(boolean complete) {
131         this.complete = complete;
132     }
133     public Branch getBranch() {
134         return branch;
135     }
136     public void setBranch(Branch branch) {
137         this.branch = branch;
138     }
139     public RouteNode getRouteNode() {
140         return routeNode;
141     }
142     public void setRouteNode(RouteNode node) {
143         this.routeNode = node;
144     }
145     public String getRouteNodeInstanceId() {
146         return routeNodeInstanceId;
147     }
148     public void setRouteNodeInstanceId(String routeNodeInstanceId) {
149         this.routeNodeInstanceId = routeNodeInstanceId;
150     }
151     public String getDocumentId() {
152         return documentId;
153     }
154     public void setDocumentId(String documentId) {
155         this.documentId = documentId;
156     }
157     public List<RouteNodeInstance> getNextNodeInstances() {
158         return nextNodeInstances;
159     }
160     public RouteNodeInstance getNextNodeInstance(int index) {
161     	while (getNextNodeInstances().size() <= index) {
162     		nextNodeInstances.add(new RouteNodeInstance());
163     	}
164     	return (RouteNodeInstance) getNextNodeInstances().get(index);
165     }
166     public void setNextNodeInstances(List<RouteNodeInstance> nextNodeInstances) {
167         this.nextNodeInstances = nextNodeInstances;
168     }
169     public List<RouteNodeInstance> getPreviousNodeInstances() {
170         return previousNodeInstances;
171     }
172     public RouteNodeInstance getPreviousNodeInstance(int index) {
173     	while (previousNodeInstances.size() <= index) {
174     		previousNodeInstances.add(new RouteNodeInstance());
175     	}
176     	return (RouteNodeInstance) getPreviousNodeInstances().get(index);
177     }
178     public void setPreviousNodeInstances(List<RouteNodeInstance> previousNodeInstances) {
179         this.previousNodeInstances = previousNodeInstances;
180     }
181     public boolean isInitial() {
182         return initial;
183     }
184     public void setInitial(boolean initial) {
185         this.initial = initial;
186     }
187     public List<NodeState> getState() {
188         return state;
189     }
190     public void setState(List<NodeState> state) {
191         this.state.clear();
192     	this.state.addAll(state);
193         //this.state = state;
194     }
195     public RouteNodeInstance getProcess() {
196 		return process;
197 	}
198 	public void setProcess(RouteNodeInstance process) {
199 		this.process = process;
200 	}
201 	public Integer getLockVerNbr() {
202         return lockVerNbr;
203     }
204     public void setLockVerNbr(Integer lockVerNbr) {
205         this.lockVerNbr = lockVerNbr;
206     }
207     
208     public NodeState getNodeState(String key) {
209         for (Iterator iter = getState().iterator(); iter.hasNext();) {
210             NodeState nodeState = (NodeState) iter.next();
211             if (nodeState.getKey().equals(key)) {
212                 return nodeState;
213             }
214         }
215         return null;
216     }
217     
218     public void addNodeState(NodeState state) {
219         this.state.add(state);
220         state.setNodeInstance(this);
221     }
222     
223     public void removeNodeState(String key) {
224         for (Iterator iter = getState().iterator(); iter.hasNext();) {
225             NodeState nodeState = (NodeState) iter.next();
226             if (nodeState.getKey().equals(key)) {
227                 iter.remove();
228                 break;
229             }
230         }
231     }
232     
233     public void addNextNodeInstance(RouteNodeInstance nextNodeInstance) {
234         nextNodeInstances.add(nextNodeInstance);
235         nextNodeInstance.getPreviousNodeInstances().add(this);
236     }
237     
238     public void removeNextNodeInstance(RouteNodeInstance nextNodeInstance) {
239         nextNodeInstances.remove(nextNodeInstance);
240         nextNodeInstance.getPreviousNodeInstances().remove(this);
241     }
242     
243     public void clearNextNodeInstances() {
244         for (Iterator iterator = nextNodeInstances.iterator(); iterator.hasNext();) {
245             RouteNodeInstance nextNodeInstance = (RouteNodeInstance) iterator.next();
246             iterator.remove();
247             nextNodeInstance.getPreviousNodeInstances().remove(this);
248         }
249     }
250     
251     public String getName() {
252         return (getRouteNode() == null ? null : getRouteNode().getRouteNodeName());
253     }
254     
255     public boolean isInProcess() {
256         return getProcess() != null;
257     }
258     
259     public DocumentType getDocumentType() {
260         return KEWServiceLocator.getDocumentTypeService().findByDocumentId(getDocumentId());
261     }
262     
263     /*
264      * methods used to display route node instances' data on documentoperation.jsp
265      */
266     
267     public NodeState getNodeStateByIndex(int index){
268     	while (state.size() <= index) {
269             state.add(new NodeState());
270         }
271         return (NodeState) getState().get(index);
272     }   
273 
274     public void populateState(List<NodeState> state) {
275         this.state.addAll(state);
276      }
277 
278     public List<DocumentRouteHeaderValue> getInitialDocumentRouteHeaderValues() {
279         return initialDocumentRouteHeaderValues;
280     }
281 
282     public void setInitialDocumentRouteHeaderValues(List<DocumentRouteHeaderValue> initialDocumentRouteHeaderValues) {
283         this.initialDocumentRouteHeaderValues = initialDocumentRouteHeaderValues;
284     }
285     
286     public String toString() {
287         return new ToStringBuilder(this)
288             .append("routeNodeInstanceId", routeNodeInstanceId)
289             .append("documentId", documentId)
290             .append("branch", branch == null ? null : branch.getBranchId())
291             .append("routeNode", routeNode == null ? null : routeNode.getRouteNodeName())
292             .append("active", active)
293             .append("complete", complete)
294             .append("initial", initial)
295             .append("process", process)
296             .append("state", state == null ? null : state.size())
297             .toString();
298     }
299     
300 	//@PrePersist
301 	public void beforeInsert(){
302 		OrmUtils.populateAutoIncValue(this, KEWServiceLocator.getEntityManagerFactory().createEntityManager());
303 	}
304 
305 
306 	public static org.kuali.rice.kew.api.document.node.RouteNodeInstance to(RouteNodeInstance routeNodeInstance) {
307 		if (routeNodeInstance == null) {
308 			return null;
309 		}
310 		org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder builder = org.kuali.rice.kew.api.document.node
311                 .RouteNodeInstance.Builder.create();
312 		builder.setActive(routeNodeInstance.isActive());
313 		builder.setBranchId(routeNodeInstance.getBranch().getBranchId());
314 		builder.setComplete(routeNodeInstance.isComplete());
315 		builder.setDocumentId(routeNodeInstance.getDocumentId());
316 		builder.setId(routeNodeInstance.getRouteNodeInstanceId());
317 		builder.setInitial(routeNodeInstance.isInitial());
318 		builder.setName(routeNodeInstance.getName());
319 		if (routeNodeInstance.getProcess() != null) {
320 			builder.setProcessId(routeNodeInstance.getProcess().getRouteNodeInstanceId());
321 		}
322 		builder.setRouteNodeId(routeNodeInstance.getRouteNode().getRouteNodeId());
323 		List<RouteNodeInstanceState.Builder> states = new ArrayList<RouteNodeInstanceState.Builder>();
324 		for (NodeState stateBo : routeNodeInstance.getState()) {
325 			RouteNodeInstanceState.Builder stateBuilder = RouteNodeInstanceState.Builder.create();
326 			stateBuilder.setId(stateBo.getStateId());
327 			stateBuilder.setKey(stateBo.getKey());
328 			stateBuilder.setValue(stateBo.getValue());
329 			states.add(stateBuilder);
330 		}
331 		builder.setState(states);
332 
333         List<org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder> nextNodes = new ArrayList<org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder>();
334         if (routeNodeInstance.getNextNodeInstances() != null) {
335             for (RouteNodeInstance next : routeNodeInstance.getNextNodeInstances()) {
336                 // KULRICE-8152 - During load testing, sometimes routeNodeInstance.getNextNodeInstances() returns an
337                 // arraylist with size = 1 but all elements are null, which causes a "contract was null" error when the
338                 // create is called.  This check to see if next is not null prevents the error from occurring.
339                 if (next != null) {
340                     // will this make things blow up?
341                     nextNodes.add(org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder.create(RouteNodeInstance.to(next)));
342                 }
343             }
344         }
345         builder.setNextNodeInstances(nextNodes);
346 
347 		return builder.build();
348 
349 
350 
351 	}
352     
353 }
354