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.persistence.EntityManager;
027import javax.persistence.PersistenceContext;
028import javax.persistence.Query;
029import javax.sql.DataSource;
030
031import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
032import org.kuali.rice.kew.api.KEWPropertyConstants;
033import org.kuali.rice.kew.engine.node.Branch;
034import org.kuali.rice.kew.engine.node.NodeState;
035import org.kuali.rice.kew.engine.node.RouteNode;
036import org.kuali.rice.kew.engine.node.RouteNodeInstance;
037import org.kuali.rice.kew.engine.node.dao.RouteNodeDAO;
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;
043
044public 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}