001 /** 002 * Copyright 2005-2013 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.dao.impl; 017 018 import java.sql.Connection; 019 import java.sql.PreparedStatement; 020 import java.sql.ResultSet; 021 import java.sql.SQLException; 022 import java.util.ArrayList; 023 import java.util.Iterator; 024 import java.util.List; 025 026 import javax.persistence.EntityManager; 027 import javax.persistence.PersistenceContext; 028 import javax.persistence.Query; 029 import javax.sql.DataSource; 030 031 import org.kuali.rice.core.framework.persistence.jpa.OrmUtils; 032 import org.kuali.rice.kew.api.KEWPropertyConstants; 033 import org.kuali.rice.kew.engine.node.Branch; 034 import org.kuali.rice.kew.engine.node.NodeState; 035 import org.kuali.rice.kew.engine.node.RouteNode; 036 import org.kuali.rice.kew.engine.node.RouteNodeInstance; 037 import org.kuali.rice.kew.engine.node.dao.RouteNodeDAO; 038 import org.kuali.rice.kew.service.KEWServiceLocator; 039 import org.springframework.dao.DataAccessException; 040 import org.springframework.jdbc.core.JdbcTemplate; 041 import org.springframework.jdbc.core.PreparedStatementCallback; 042 import org.springframework.jdbc.core.PreparedStatementCreator; 043 044 public class RouteNodeDAOJpaImpl implements RouteNodeDAO { 045 046 @PersistenceContext(unitName="kew-unit") 047 EntityManager entityManager; 048 049 /** 050 * @return the entityManager 051 */ 052 public EntityManager getEntityManager() { 053 return this.entityManager; 054 } 055 056 /** 057 * @param entityManager the entityManager to set 058 */ 059 public void setEntityManager(EntityManager entityManager) { 060 this.entityManager = entityManager; 061 } 062 063 public void save(RouteNode node) { 064 if (node.getRouteNodeId() == null){ 065 entityManager.persist(node); 066 } else { 067 OrmUtils.merge(entityManager, node); 068 } 069 } 070 071 public void save(RouteNodeInstance nodeInstance) { 072 if (nodeInstance.getRouteNodeInstanceId() == null){ 073 entityManager.persist(nodeInstance); 074 } else { 075 OrmUtils.merge(entityManager, nodeInstance); 076 } 077 } 078 079 public void save(NodeState nodeState) { 080 if (nodeState.getNodeStateId() == null){ 081 entityManager.persist(nodeState); 082 } else { 083 OrmUtils.merge(entityManager, nodeState); 084 } 085 } 086 087 public void save(Branch branch) { 088 if (branch.getBranchId() == null){ 089 entityManager.persist(branch); 090 } else { 091 OrmUtils.merge(entityManager, branch); 092 } 093 } 094 095 public RouteNode findRouteNodeById(String nodeId) { 096 Query query = entityManager.createNamedQuery("RouteNode.FindByRouteNodeId"); 097 query.setParameter(KEWPropertyConstants.ROUTE_NODE_ID, nodeId); 098 return (RouteNode) query.getSingleResult(); 099 } 100 101 public RouteNodeInstance findRouteNodeInstanceById(String nodeInstanceId) { 102 Query query = entityManager.createNamedQuery("RouteNodeInstance.FindByRouteNodeInstanceId"); 103 query.setParameter(KEWPropertyConstants.ROUTE_NODE_INSTANCE_ID, nodeInstanceId); 104 105 return (RouteNodeInstance) query.getSingleResult(); 106 } 107 108 @SuppressWarnings("unchecked") 109 public List<RouteNodeInstance> getActiveNodeInstances(String documentId) { 110 Query query = entityManager.createNamedQuery("RouteNodeInstance.FindActiveNodeInstances"); 111 query.setParameter(KEWPropertyConstants.DOCUMENT_ID, documentId); 112 return (List<RouteNodeInstance>)query.getResultList(); 113 } 114 115 private static final String CURRENT_ROUTE_NODE_NAMES_SQL = "SELECT rn.nm" + 116 " FROM krew_rte_node_t rn," + 117 " krew_rte_node_instn_t rni" + 118 " LEFT JOIN krew_rte_node_instn_lnk_t rnl" + 119 " ON rnl.from_rte_node_instn_id = rni.rte_node_instn_id" + 120 " WHERE rn.rte_node_id = rni.rte_node_id AND" + 121 " rni.doc_hdr_id = ? AND" + 122 " rnl.from_rte_node_instn_id IS NULL"; 123 124 @Override 125 public List<String> getCurrentRouteNodeNames(final String documentId) { 126 final DataSource dataSource = KEWServiceLocator.getDataSource(); 127 JdbcTemplate template = new JdbcTemplate(dataSource); 128 List<String> names = template.execute(new PreparedStatementCreator() { 129 public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 130 return connection.prepareStatement(CURRENT_ROUTE_NODE_NAMES_SQL); 131 } 132 }, new PreparedStatementCallback<List<String>>() { 133 public List<String> doInPreparedStatement( 134 PreparedStatement statement) throws SQLException, DataAccessException { 135 List<String> routeNodeNames = new ArrayList<String>(); 136 statement.setString(1, documentId); 137 ResultSet rs = statement.executeQuery(); 138 try { 139 while (rs.next()) { 140 String name = rs.getString("nm"); 141 routeNodeNames.add(name); 142 } 143 } finally { 144 if (rs != null) { 145 rs.close(); 146 } 147 } 148 return routeNodeNames; 149 } 150 } 151 ); 152 return names; 153 } 154 155 @Override 156 public List<String> getActiveRouteNodeNames(final String documentId) { 157 final DataSource dataSource = KEWServiceLocator.getDataSource(); 158 JdbcTemplate template = new JdbcTemplate(dataSource); 159 List<String> names = template.execute( 160 new PreparedStatementCreator() { 161 public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 162 PreparedStatement statement = connection.prepareStatement( 163 "SELECT rn.nm FROM krew_rte_node_t rn, krew_rte_node_instn_t rni WHERE rn.rte_node_id = rni.rte_node_id AND rni.doc_hdr_id = ? AND rni.actv_ind = ?"); 164 return statement; 165 } 166 }, 167 new PreparedStatementCallback<List<String>>() { 168 public List<String> doInPreparedStatement(PreparedStatement statement) throws SQLException, DataAccessException { 169 List<String> routeNodeNames = new ArrayList<String>(); 170 statement.setString(1, documentId); 171 statement.setBoolean(2, Boolean.TRUE); 172 ResultSet rs = statement.executeQuery(); 173 try { 174 while(rs.next()) { 175 String name = rs.getString("nm"); 176 routeNodeNames.add(name); 177 } 178 } finally { 179 if(rs != null) { 180 rs.close(); 181 } 182 } 183 return routeNodeNames; 184 } 185 }); 186 return names; 187 } 188 189 @SuppressWarnings("unchecked") 190 public List<RouteNodeInstance> getTerminalNodeInstances(String documentId) { 191 Query query = entityManager.createNamedQuery("RouteNodeInstance.FindTerminalNodeInstances"); 192 query.setParameter(KEWPropertyConstants.DOCUMENT_ID, documentId); 193 194 //FIXME: Can we do this better using just the JPQL query? 195 List<RouteNodeInstance> terminalNodes = new ArrayList<RouteNodeInstance>(); 196 List<RouteNodeInstance> routeNodeInstances = (List<RouteNodeInstance>) query.getResultList(); 197 for (RouteNodeInstance routeNodeInstance : routeNodeInstances) { 198 if (routeNodeInstance.getNextNodeInstances().isEmpty()) { 199 terminalNodes.add(routeNodeInstance); 200 } 201 } 202 return terminalNodes; 203 } 204 205 @Override 206 public List<String> getTerminalRouteNodeNames(final String documentId) { 207 final DataSource dataSource = KEWServiceLocator.getDataSource(); 208 JdbcTemplate template = new JdbcTemplate(dataSource); 209 List<String> names = template.execute(new PreparedStatementCreator() { 210 public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 211 PreparedStatement statement = connection.prepareStatement("SELECT rn.nm" + 212 " FROM krew_rte_node_t rn," + 213 " krew_rte_node_instn_t rni" + 214 " LEFT JOIN krew_rte_node_instn_lnk_t rnl" + 215 " ON rnl.from_rte_node_instn_id = rni.rte_node_instn_id" + 216 " WHERE rn.rte_node_id = rni.rte_node_id AND" + 217 " rni.doc_hdr_id = ? AND" + 218 " rni.actv_ind = ? AND" + 219 " rni.cmplt_ind = ? AND" + 220 " rnl.from_rte_node_instn_id IS NULL"); 221 return statement; 222 } 223 }, new PreparedStatementCallback<List<String>>() { 224 public List<String> doInPreparedStatement( 225 PreparedStatement statement) throws SQLException, DataAccessException { 226 List<String> routeNodeNames = new ArrayList<String>(); 227 statement.setString(1, documentId); 228 statement.setBoolean(2, Boolean.FALSE); 229 statement.setBoolean(3, Boolean.TRUE); 230 ResultSet rs = statement.executeQuery(); 231 try { 232 while (rs.next()) { 233 String name = rs.getString("nm"); 234 routeNodeNames.add(name); 235 } 236 } finally { 237 if (rs != null) { 238 rs.close(); 239 } 240 } 241 return routeNodeNames; 242 } 243 } 244 ); 245 return names; 246 } 247 248 public List getInitialNodeInstances(String documentId) { 249 //FIXME: Not sure this query is returning what it needs to 250 Query query = entityManager.createNamedQuery("RouteNodeInstance.FindInitialNodeInstances"); 251 query.setParameter(KEWPropertyConstants.DOCUMENT_ID, documentId); 252 return (List)query.getResultList(); 253 } 254 255 public NodeState findNodeState(Long nodeInstanceId, String key) { 256 Query query = entityManager.createNamedQuery("NodeState.FindNodeState"); 257 query.setParameter(KEWPropertyConstants.NODE_INSTANCE_ID, nodeInstanceId); 258 query.setParameter(KEWPropertyConstants.KEY, key); 259 return (NodeState) query.getSingleResult(); 260 } 261 262 public RouteNode findRouteNodeByName(String documentTypeId, String name) { 263 Query query = entityManager.createNamedQuery("RouteNode.FindRouteNodeByName"); 264 query.setParameter(KEWPropertyConstants.DOCUMENT_TYPE_ID, documentTypeId); 265 query.setParameter(KEWPropertyConstants.ROUTE_NODE_NAME, name); 266 return (RouteNode)query.getSingleResult(); 267 } 268 269 public List<RouteNode> findFinalApprovalRouteNodes(String documentTypeId) { 270 Query query = entityManager.createNamedQuery("RouteNode.FindApprovalRouteNodes"); 271 query.setParameter(KEWPropertyConstants.DOCUMENT_TYPE_ID, documentTypeId); 272 query.setParameter(KEWPropertyConstants.FINAL_APPROVAL, Boolean.TRUE); 273 return new ArrayList<RouteNode>(query.getResultList()); 274 } 275 276 public List findProcessNodeInstances(RouteNodeInstance process) { 277 Query query = entityManager.createNamedQuery("RouteNodeInstance.FindProcessNodeInstances"); 278 query.setParameter(KEWPropertyConstants.PROCESS_ID, process.getRouteNodeInstanceId()); 279 return (List) query.getResultList(); 280 } 281 282 public List findRouteNodeInstances(String documentId) { 283 Query query = entityManager.createNamedQuery("RouteNodeInstance.FindRouteNodeInstances"); 284 query.setParameter(KEWPropertyConstants.DOCUMENT_ID, documentId); 285 return (List) query.getResultList(); 286 } 287 288 public void deleteLinksToPreNodeInstances(RouteNodeInstance routeNodeInstance) { 289 List<RouteNodeInstance> preNodeInstances = routeNodeInstance.getPreviousNodeInstances(); 290 for (Iterator<RouteNodeInstance> preNodeInstanceIter = preNodeInstances.iterator(); preNodeInstanceIter.hasNext();) { 291 RouteNodeInstance preNodeInstance = (RouteNodeInstance) preNodeInstanceIter.next(); 292 List<RouteNodeInstance> nextInstances = preNodeInstance.getNextNodeInstances(); 293 nextInstances.remove(routeNodeInstance); 294 entityManager.merge(preNodeInstance); 295 } 296 } 297 298 public void deleteRouteNodeInstancesHereAfter(RouteNodeInstance routeNodeInstance) { 299 RouteNodeInstance rnInstance = findRouteNodeInstanceById(routeNodeInstance.getRouteNodeInstanceId()); 300 entityManager.remove(rnInstance); 301 } 302 303 public void deleteNodeStateById(Long nodeStateId) { 304 Query query = entityManager.createNamedQuery("RouteNode.FindNodeStateById"); 305 query.setParameter(KEWPropertyConstants.ROUTE_NODE_STATE_ID, nodeStateId); 306 NodeState nodeState = (NodeState) query.getSingleResult(); 307 entityManager.remove(nodeState); 308 } 309 310 public void deleteNodeStates(List statesToBeDeleted) { 311 for (Iterator stateToBeDeletedIter = statesToBeDeleted.iterator(); stateToBeDeletedIter.hasNext();) { 312 Long stateId = (Long) stateToBeDeletedIter.next(); 313 deleteNodeStateById(stateId); 314 } 315 } 316 317 }