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    }