001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.kew.engine.node.dao.impl; 017 018import java.sql.Connection; 019import java.sql.PreparedStatement; 020import java.sql.ResultSet; 021import java.sql.SQLException; 022import java.util.ArrayList; 023import java.util.Iterator; 024import java.util.List; 025 026import javax.sql.DataSource; 027 028import org.apache.ojb.broker.query.Criteria; 029import org.apache.ojb.broker.query.QueryByCriteria; 030import org.apache.ojb.broker.query.QueryFactory; 031import org.apache.ojb.broker.query.ReportQueryByCriteria; 032import org.kuali.rice.kew.engine.node.Branch; 033import org.kuali.rice.kew.engine.node.NodeState; 034import org.kuali.rice.kew.engine.node.RouteNode; 035import org.kuali.rice.kew.engine.node.RouteNodeInstance; 036import org.kuali.rice.kew.engine.node.dao.RouteNodeDAO; 037import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 038import org.kuali.rice.kew.service.KEWServiceLocator; 039import org.springframework.dao.DataAccessException; 040import org.springframework.jdbc.core.JdbcTemplate; 041import org.springframework.jdbc.core.PreparedStatementCallback; 042import org.springframework.jdbc.core.PreparedStatementCreator; 043import org.springmodules.orm.ojb.support.PersistenceBrokerDaoSupport; 044 045 046public class RouteNodeDAOOjbImpl extends PersistenceBrokerDaoSupport implements RouteNodeDAO { 047 048 private static final String ROUTE_NODE_ID = "routeNodeId"; 049 private static final String ROUTE_NODE_INSTANCE_ID = "routeNodeInstanceId"; 050 private static final String NODE_INSTANCE_ID = "nodeInstanceId"; 051 private static final String DOCUMENT_ID = "documentId"; 052 private static final String ROUTE_NODE_NAME = "routeNodeName"; 053 private static final String DOCUMENT_TYPE_ID = "documentTypeId"; 054 private static final String PROCESS_ID = "processId"; 055 private static final String ACTIVE = "active"; 056 private static final String COMPLETE = "complete"; 057 private static final String FINAL_APPROVAL = "finalApprovalInd"; 058 private static final String KEY = "key"; 059 private static final String Route_Node_State_ID = "nodeStateId"; 060 061 public void save(RouteNode node) { 062 getPersistenceBrokerTemplate().store(node); 063 } 064 065 public void save(RouteNodeInstance nodeInstance) { 066 // this is because the branch table relates to the node instance table - both through their keys - and 067 // ojb can't automatically do this bi-directional relationship 068 getPersistenceBrokerTemplate().store(nodeInstance.getBranch()); 069 getPersistenceBrokerTemplate().store(nodeInstance); 070 } 071 072 public void save(NodeState nodeState) { 073 getPersistenceBrokerTemplate().store(nodeState); 074 } 075 076 public void save(Branch branch) { 077 getPersistenceBrokerTemplate().store(branch); 078 } 079 080 public RouteNode findRouteNodeById(String nodeId) { 081 Criteria criteria = new Criteria(); 082 criteria.addEqualTo(ROUTE_NODE_ID, nodeId); 083 return (RouteNode) getPersistenceBrokerTemplate().getObjectByQuery(new QueryByCriteria(RouteNode.class, criteria)); 084 } 085 086 public RouteNodeInstance findRouteNodeInstanceById(String nodeInstanceId) { 087 Criteria criteria = new Criteria(); 088 criteria.addEqualTo(ROUTE_NODE_INSTANCE_ID, nodeInstanceId); 089 return (RouteNodeInstance) getPersistenceBrokerTemplate().getObjectByQuery( 090 new QueryByCriteria(RouteNodeInstance.class, criteria)); 091 } 092 093 @SuppressWarnings(value = "unchecked") 094 public List<RouteNodeInstance> getActiveNodeInstances(String documentId) { 095 Criteria criteria = new Criteria(); 096 criteria.addEqualTo(DOCUMENT_ID, documentId); 097 criteria.addEqualTo(ACTIVE, Boolean.TRUE); 098 return (List<RouteNodeInstance>) getPersistenceBrokerTemplate().getCollectionByQuery( 099 new QueryByCriteria(RouteNodeInstance.class, criteria)); 100 } 101 102 private static final String CURRENT_ROUTE_NODE_NAMES_SQL = "SELECT rn.nm" + 103 " FROM krew_rte_node_t rn," + 104 " krew_rte_node_instn_t rni" + 105 " LEFT JOIN krew_rte_node_instn_lnk_t rnl" + 106 " ON rnl.from_rte_node_instn_id = rni.rte_node_instn_id" + 107 " WHERE rn.rte_node_id = rni.rte_node_id AND" + 108 " rni.doc_hdr_id = ? AND" + 109 " rnl.from_rte_node_instn_id IS NULL"; 110 111 @Override 112 public List<String> getCurrentRouteNodeNames(final String documentId) { 113 final DataSource dataSource = KEWServiceLocator.getDataSource(); 114 JdbcTemplate template = new JdbcTemplate(dataSource); 115 List<String> names = template.execute(new PreparedStatementCreator() { 116 public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 117 return connection.prepareStatement(CURRENT_ROUTE_NODE_NAMES_SQL); 118 } 119 }, new PreparedStatementCallback<List<String>>() { 120 public List<String> doInPreparedStatement( 121 PreparedStatement statement) throws SQLException, DataAccessException { 122 List<String> routeNodeNames = new ArrayList<String>(); 123 statement.setString(1, documentId); 124 ResultSet rs = statement.executeQuery(); 125 try { 126 while (rs.next()) { 127 String name = rs.getString("nm"); 128 routeNodeNames.add(name); 129 } 130 } finally { 131 if (rs != null) { 132 rs.close(); 133 } 134 } 135 return routeNodeNames; 136 } 137 } 138 ); 139 return names; 140 } 141 142 @Override 143 public List<String> getActiveRouteNodeNames(final String documentId) { 144 final DataSource dataSource = KEWServiceLocator.getDataSource(); 145 JdbcTemplate template = new JdbcTemplate(dataSource); 146 List<String> names = template.execute( 147 new PreparedStatementCreator() { 148 public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 149 PreparedStatement statement = connection.prepareStatement( 150 "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 = ?"); 151 return statement; 152 } 153 }, 154 new PreparedStatementCallback<List<String>>() { 155 public List<String> doInPreparedStatement(PreparedStatement statement) throws SQLException, DataAccessException { 156 List<String> routeNodeNames = new ArrayList<String>(); 157 statement.setString(1, documentId); 158 statement.setBoolean(2, Boolean.TRUE); 159 ResultSet rs = statement.executeQuery(); 160 try { 161 while(rs.next()) { 162 String name = rs.getString("nm"); 163 routeNodeNames.add(name); 164 } 165 } finally { 166 if(rs != null) { 167 rs.close(); 168 } 169 } 170 return routeNodeNames; 171 } 172 }); 173 return names; 174 } 175 176 @Override 177 public List<String> getTerminalRouteNodeNames(final String documentId) { 178 final DataSource dataSource = KEWServiceLocator.getDataSource(); 179 JdbcTemplate template = new JdbcTemplate(dataSource); 180 List<String> names = template.execute( 181 new PreparedStatementCreator() { 182 public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 183 PreparedStatement statement = connection.prepareStatement( 184 "SELECT rn.nm" + 185 " FROM krew_rte_node_t rn," + 186 " krew_rte_node_instn_t rni" + 187 " LEFT JOIN krew_rte_node_instn_lnk_t rnl" + 188 " ON rnl.from_rte_node_instn_id = rni.rte_node_instn_id" + 189 " WHERE rn.rte_node_id = rni.rte_node_id AND" + 190 " rni.doc_hdr_id = ? AND" + 191 " rni.actv_ind = ? AND" + 192 " rni.cmplt_ind = ? AND" + 193 " rnl.from_rte_node_instn_id IS NULL"); 194 return statement; 195 } 196 }, 197 new PreparedStatementCallback<List<String>>() { 198 public List<String> doInPreparedStatement(PreparedStatement statement) throws SQLException, DataAccessException { 199 List<String> routeNodeNames = new ArrayList<String>(); 200 statement.setString(1, documentId); 201 statement.setBoolean(2, Boolean.FALSE); 202 statement.setBoolean(3, Boolean.TRUE); 203 ResultSet rs = statement.executeQuery(); 204 try { 205 while(rs.next()) { 206 String name = rs.getString("nm"); 207 routeNodeNames.add(name); 208 } 209 } finally { 210 if(rs != null) { 211 rs.close(); 212 } 213 } 214 return routeNodeNames; 215 } 216 }); 217 return names; 218 } 219 220 @SuppressWarnings("unchecked") 221 public List<RouteNodeInstance> getTerminalNodeInstances(String documentId) { 222 Criteria criteria = new Criteria(); 223 criteria.addEqualTo(DOCUMENT_ID, documentId); 224 criteria.addEqualTo(ACTIVE, Boolean.FALSE); 225 criteria.addEqualTo(COMPLETE, Boolean.TRUE); 226// criteria.addIsNull("nextNodeInstances.routeNodeInstanceId"); 227// QueryByCriteria query = new QueryByCriteria(RouteNodeInstance.class, criteria); 228// // we need to outer join here because we are looking for nodes with no nextNodeInstances 229// query.setPathOuterJoin("nextNodeInstances"); 230// return (List) getPersistenceBrokerTemplate().getCollectionByQuery(query); 231 232 //forced to do this programmatically, for some reason the above code stopped working 233 List<RouteNodeInstance> terminalNodes = new ArrayList<RouteNodeInstance>(); 234 List<RouteNodeInstance> routeNodeInstances = (List<RouteNodeInstance>) getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(RouteNodeInstance.class, criteria)); 235 for (RouteNodeInstance routeNodeInstance : routeNodeInstances) { 236 if (routeNodeInstance.getNextNodeInstances().isEmpty()) { 237 terminalNodes.add(routeNodeInstance); 238 } 239 } 240 return terminalNodes; 241 } 242 243 public List getInitialNodeInstances(String documentId) { 244 Criteria criteria = new Criteria(); 245 criteria.addEqualTo("initialDocumentRouteHeaderValues." + DOCUMENT_ID, documentId); 246 return (List) getPersistenceBrokerTemplate().getCollectionByQuery( 247 new QueryByCriteria(RouteNodeInstance.class, criteria)); 248 } 249 250 public NodeState findNodeState(Long nodeInstanceId, String key) { 251 Criteria criteria = new Criteria(); 252 criteria.addEqualTo(NODE_INSTANCE_ID, nodeInstanceId); 253 criteria.addEqualTo(KEY, key); 254 return (NodeState) getPersistenceBrokerTemplate().getObjectByQuery(new QueryByCriteria(NodeState.class, criteria)); 255 } 256 257 public RouteNode findRouteNodeByName(String documentTypeId, String name) { 258 Criteria criteria = new Criteria(); 259 criteria.addEqualTo(ROUTE_NODE_NAME, name); 260 criteria.addEqualTo(DOCUMENT_TYPE_ID, documentTypeId); 261 return (RouteNode) getPersistenceBrokerTemplate().getObjectByQuery(new QueryByCriteria(RouteNode.class, criteria)); 262 } 263 264 public List<RouteNode> findFinalApprovalRouteNodes(String documentTypeId) { 265 Criteria criteria = new Criteria(); 266 criteria.addEqualTo(DOCUMENT_TYPE_ID, documentTypeId); 267 criteria.addEqualTo(FINAL_APPROVAL, Boolean.TRUE); 268 return new ArrayList<RouteNode>(getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(RouteNode.class, criteria))); 269 } 270 271 public List findProcessNodeInstances(RouteNodeInstance process) { 272 Criteria crit = new Criteria(); 273 crit.addEqualTo(PROCESS_ID, process.getRouteNodeInstanceId()); 274 return (List) getPersistenceBrokerTemplate() 275 .getCollectionByQuery(new QueryByCriteria(RouteNodeInstance.class, crit)); 276 } 277 278 public List findRouteNodeInstances(String documentId) { 279 Criteria criteria = new Criteria(); 280 criteria.addEqualTo(DOCUMENT_ID, documentId); 281 return (List) getPersistenceBrokerTemplate().getCollectionByQuery( 282 new QueryByCriteria(RouteNodeInstance.class, criteria)); 283 } 284 285 public void deleteLinksToPreNodeInstances(RouteNodeInstance routeNodeInstance) { 286 List<RouteNodeInstance> preNodeInstances = routeNodeInstance.getPreviousNodeInstances(); 287 for (Iterator<RouteNodeInstance> preNodeInstanceIter = preNodeInstances.iterator(); preNodeInstanceIter.hasNext();) { 288 RouteNodeInstance preNodeInstance = (RouteNodeInstance) preNodeInstanceIter.next(); 289 List<RouteNodeInstance> nextInstances = preNodeInstance.getNextNodeInstances(); 290 nextInstances.remove(routeNodeInstance); 291 save(preNodeInstance); 292 } 293 } 294 295 public void deleteRouteNodeInstancesHereAfter(RouteNodeInstance routeNodeInstance) { 296 this.getPersistenceBrokerTemplate().delete(routeNodeInstance); 297 } 298 299 public void deleteNodeStateById(Long nodeStateId) { 300 Criteria criteria = new Criteria(); 301 criteria.addEqualTo(Route_Node_State_ID, nodeStateId); 302 NodeState nodeState = (NodeState) getPersistenceBrokerTemplate().getObjectByQuery( 303 new QueryByCriteria(NodeState.class, criteria)); 304 getPersistenceBrokerTemplate().delete(nodeState); 305 } 306 307 public void deleteNodeStates(List statesToBeDeleted) { 308 for (Iterator stateToBeDeletedIter = statesToBeDeleted.iterator(); stateToBeDeletedIter.hasNext();) { 309 Long stateId = (Long) stateToBeDeletedIter.next(); 310 deleteNodeStateById(stateId); 311 } 312 } 313 314}