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 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 // will this make things blow up?
337 nextNodes.add(org.kuali.rice.kew.api.document.node.RouteNodeInstance.Builder.create(RouteNodeInstance.to(next)));
338 }
339 }
340 builder.setNextNodeInstances(nextNodes);
341
342 return builder.build();
343
344
345
346 }
347
348 }
349