001 /**
002 * Copyright 2005-2012 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.engine.node;
017
018 import java.io.Serializable;
019 import java.util.ArrayList;
020 import java.util.Iterator;
021 import java.util.List;
022
023 import javax.persistence.CascadeType;
024 import javax.persistence.Column;
025 import javax.persistence.Entity;
026 import javax.persistence.FetchType;
027 import javax.persistence.GeneratedValue;
028 import javax.persistence.Id;
029 import javax.persistence.JoinColumn;
030 import javax.persistence.JoinTable;
031 import javax.persistence.ManyToMany;
032 import javax.persistence.ManyToOne;
033 import javax.persistence.NamedQueries;
034 import javax.persistence.NamedQuery;
035 import javax.persistence.OneToMany;
036 import javax.persistence.OneToOne;
037 import javax.persistence.Table;
038 import javax.persistence.Version;
039
040 import org.apache.commons.lang.builder.ToStringBuilder;
041 import org.hibernate.annotations.Fetch;
042 import org.hibernate.annotations.FetchMode;
043 import org.hibernate.annotations.GenericGenerator;
044 import org.hibernate.annotations.Parameter;
045 import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
046 import org.kuali.rice.kew.api.document.node.RouteNodeInstanceState;
047 import org.kuali.rice.kew.doctype.bo.DocumentType;
048 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
049 import org.kuali.rice.kew.service.KEWServiceLocator;
050
051
052 /**
053 * Represents a materialized instance of a {@link RouteNode} definition on a {@link DocumentRouteHeaderValue}. Node instances
054 * are generated by the engine using the {@link RouteNode} as a prototype and connected as a
055 * Directed Acyclic Graph.
056 *
057 * @author Kuali Rice Team (rice.collab@kuali.org)
058 */
059 @Entity
060 @Table(name="KREW_RTE_NODE_INSTN_T")
061 //@Sequence(name="KREW_RTE_NODE_S",property="routeNodeInstanceId")
062 @NamedQueries({
063 @NamedQuery(name="RouteNodeInstance.FindByRouteNodeInstanceId",query="select r from RouteNodeInstance r where r.routeNodeInstanceId = :routeNodeInstanceId"),
064 @NamedQuery(name="RouteNodeInstance.FindActiveNodeInstances",query="select r from RouteNodeInstance r where r.documentId = :documentId and r.active = true"),
065 @NamedQuery(name="RouteNodeInstance.FindTerminalNodeInstances",query="select r from RouteNodeInstance r where r.documentId = :documentId and r.active = false and r.complete = true"),
066 @NamedQuery(name="RouteNodeInstance.FindInitialNodeInstances",query="select d.initialRouteNodeInstances from DocumentRouteHeaderValue d where d.documentId = :documentId"),
067 @NamedQuery(name="RouteNodeInstance.FindProcessNodeInstances", query="select r from RouteNodeInstance r where r.process.routeNodeInstanceId = :processId"),
068 @NamedQuery(name="RouteNodeInstance.FindRouteNodeInstances", query="select r from RouteNodeInstance r where r.documentId = :documentId")
069 })
070 public class RouteNodeInstance implements Serializable {
071
072 private static final long serialVersionUID = 7183670062805580420L;
073
074 @Id
075 @GeneratedValue(generator="KREW_RTE_NODE_S")
076 @GenericGenerator(name="KREW_RTE_NODE_S",strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",parameters={
077 @Parameter(name="sequence_name",value="KREW_RTE_NODE_S"),
078 @Parameter(name="value_column",value="id")
079 })
080 @Column(name="RTE_NODE_INSTN_ID")
081 private String routeNodeInstanceId;
082 @Column(name="DOC_HDR_ID")
083 private String documentId;
084 @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
085 @JoinColumn(name="BRCH_ID")
086 private Branch branch;
087 @OneToOne(fetch=FetchType.EAGER)
088 @JoinColumn(name="RTE_NODE_ID")
089 private RouteNode routeNode;
090 @Column(name="ACTV_IND")
091 private boolean active = false;
092 @Column(name="CMPLT_IND")
093 private boolean complete = false;
094 @Column(name="INIT_IND")
095 private boolean initial = true;
096 @OneToOne(fetch=FetchType.EAGER,cascade={CascadeType.PERSIST, CascadeType.MERGE})
097 @JoinColumn(name="PROC_RTE_NODE_INSTN_ID")
098 private RouteNodeInstance process;
099
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 public boolean isActive() {
119 return active;
120 }
121 public void setActive(boolean active) {
122 this.active = active;
123 }
124
125 public boolean isComplete() {
126 return complete;
127 }
128 public void setComplete(boolean complete) {
129 this.complete = complete;
130 }
131 public Branch getBranch() {
132 return branch;
133 }
134 public void setBranch(Branch branch) {
135 this.branch = branch;
136 }
137 public RouteNode getRouteNode() {
138 return routeNode;
139 }
140 public void setRouteNode(RouteNode node) {
141 this.routeNode = node;
142 }
143 public String getRouteNodeInstanceId() {
144 return routeNodeInstanceId;
145 }
146 public void setRouteNodeInstanceId(String routeNodeInstanceId) {
147 this.routeNodeInstanceId = routeNodeInstanceId;
148 }
149 public String getDocumentId() {
150 return documentId;
151 }
152 public void setDocumentId(String documentId) {
153 this.documentId = documentId;
154 }
155 public List<RouteNodeInstance> getNextNodeInstances() {
156 return nextNodeInstances;
157 }
158 public RouteNodeInstance getNextNodeInstance(int index) {
159 while (getNextNodeInstances().size() <= index) {
160 nextNodeInstances.add(new RouteNodeInstance());
161 }
162 return (RouteNodeInstance) getNextNodeInstances().get(index);
163 }
164 public void setNextNodeInstances(List<RouteNodeInstance> nextNodeInstances) {
165 this.nextNodeInstances = nextNodeInstances;
166 }
167 public List<RouteNodeInstance> getPreviousNodeInstances() {
168 return previousNodeInstances;
169 }
170 public RouteNodeInstance getPreviousNodeInstance(int index) {
171 while (previousNodeInstances.size() <= index) {
172 previousNodeInstances.add(new RouteNodeInstance());
173 }
174 return (RouteNodeInstance) getPreviousNodeInstances().get(index);
175 }
176 public void setPreviousNodeInstances(List<RouteNodeInstance> previousNodeInstances) {
177 this.previousNodeInstances = previousNodeInstances;
178 }
179 public boolean isInitial() {
180 return initial;
181 }
182 public void setInitial(boolean initial) {
183 this.initial = initial;
184 }
185 public List<NodeState> getState() {
186 return state;
187 }
188 public void setState(List<NodeState> state) {
189 this.state.clear();
190 this.state.addAll(state);
191 //this.state = state;
192 }
193 public RouteNodeInstance getProcess() {
194 return process;
195 }
196 public void setProcess(RouteNodeInstance process) {
197 this.process = process;
198 }
199 public Integer getLockVerNbr() {
200 return lockVerNbr;
201 }
202 public void setLockVerNbr(Integer lockVerNbr) {
203 this.lockVerNbr = lockVerNbr;
204 }
205
206 public NodeState getNodeState(String key) {
207 for (Iterator iter = getState().iterator(); iter.hasNext();) {
208 NodeState nodeState = (NodeState) iter.next();
209 if (nodeState.getKey().equals(key)) {
210 return nodeState;
211 }
212 }
213 return null;
214 }
215
216 public void addNodeState(NodeState state) {
217 this.state.add(state);
218 state.setNodeInstance(this);
219 }
220
221 public void removeNodeState(String key) {
222 for (Iterator iter = getState().iterator(); iter.hasNext();) {
223 NodeState nodeState = (NodeState) iter.next();
224 if (nodeState.getKey().equals(key)) {
225 iter.remove();
226 break;
227 }
228 }
229 }
230
231 public void addNextNodeInstance(RouteNodeInstance nextNodeInstance) {
232 nextNodeInstances.add(nextNodeInstance);
233 nextNodeInstance.getPreviousNodeInstances().add(this);
234 }
235
236 public void removeNextNodeInstance(RouteNodeInstance nextNodeInstance) {
237 nextNodeInstances.remove(nextNodeInstance);
238 nextNodeInstance.getPreviousNodeInstances().remove(this);
239 }
240
241 public void clearNextNodeInstances() {
242 for (Iterator iterator = nextNodeInstances.iterator(); iterator.hasNext();) {
243 RouteNodeInstance nextNodeInstance = (RouteNodeInstance) iterator.next();
244 iterator.remove();
245 nextNodeInstance.getPreviousNodeInstances().remove(this);
246 }
247 }
248
249 public String getName() {
250 return (getRouteNode() == null ? null : getRouteNode().getRouteNodeName());
251 }
252
253 public boolean isInProcess() {
254 return getProcess() != null;
255 }
256
257 public DocumentType getDocumentType() {
258 return KEWServiceLocator.getDocumentTypeService().findByDocumentId(getDocumentId());
259 }
260
261 /*
262 * methods used to display route node instances' data on documentoperation.jsp
263 */
264
265 public NodeState getNodeStateByIndex(int index){
266 while (state.size() <= index) {
267 state.add(new NodeState());
268 }
269 return (NodeState) getState().get(index);
270 }
271
272 public void populateState(List<NodeState> state) {
273 this.state.addAll(state);
274 }
275
276 public String toString() {
277 return new ToStringBuilder(this)
278 .append("routeNodeInstanceId", routeNodeInstanceId)
279 .append("documentId", documentId)
280 .append("branch", branch == null ? null : branch.getBranchId())
281 .append("routeNode", routeNode == null ? null : routeNode.getRouteNodeName())
282 .append("active", active)
283 .append("complete", complete)
284 .append("initial", initial)
285 .append("process", process)
286 .append("state", state == null ? null : state.size())
287 .toString();
288 }
289
290 //@PrePersist
291 public void beforeInsert(){
292 OrmUtils.populateAutoIncValue(this, KEWServiceLocator.getEntityManagerFactory().createEntityManager());
293 }
294
295
296 public static org.kuali.rice.kew.api.document.node.RouteNodeInstance to(RouteNodeInstance routeNodeInstance) {
297 if (routeNodeInstance == null) {
298 return null;
299 }
300 org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder builder = org.kuali.rice.kew.api.document.node
301 .RouteNodeInstance.Builder.create();
302 builder.setActive(routeNodeInstance.isActive());
303 builder.setBranchId(routeNodeInstance.getBranch().getBranchId());
304 builder.setComplete(routeNodeInstance.isComplete());
305 builder.setDocumentId(routeNodeInstance.getDocumentId());
306 builder.setId(routeNodeInstance.getRouteNodeInstanceId());
307 builder.setInitial(routeNodeInstance.isInitial());
308 builder.setName(routeNodeInstance.getName());
309 if (routeNodeInstance.getProcess() != null) {
310 builder.setProcessId(routeNodeInstance.getProcess().getRouteNodeInstanceId());
311 }
312 builder.setRouteNodeId(routeNodeInstance.getRouteNode().getRouteNodeId());
313 List<RouteNodeInstanceState.Builder> states = new ArrayList<RouteNodeInstanceState.Builder>();
314 for (NodeState stateBo : routeNodeInstance.getState()) {
315 RouteNodeInstanceState.Builder stateBuilder = RouteNodeInstanceState.Builder.create();
316 stateBuilder.setId(stateBo.getStateId());
317 stateBuilder.setKey(stateBo.getKey());
318 stateBuilder.setValue(stateBo.getValue());
319 states.add(stateBuilder);
320 }
321 builder.setState(states);
322
323 List<org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder> nextNodes = new ArrayList<org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder>();
324 if (routeNodeInstance.getNextNodeInstances() != null) {
325 for (RouteNodeInstance next : routeNodeInstance.getNextNodeInstances()) {
326 // will this make things blow up?
327 nextNodes.add(org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder.create(RouteNodeInstance.to(next)));
328 }
329 }
330 builder.setNextNodeInstances(nextNodes);
331
332 return builder.build();
333
334
335
336 }
337
338 }
339