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}