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