001 /**
002 * Copyright 2005-2014 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 }