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.routeheader.dao.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
020import org.kuali.rice.core.api.util.RiceConstants;
021import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
022import org.kuali.rice.core.framework.persistence.jpa.criteria.Criteria;
023import org.kuali.rice.core.framework.persistence.jpa.criteria.QueryByCriteria;
024import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
025import org.kuali.rice.kew.actionitem.ActionItem;
026import org.kuali.rice.kew.actionlist.service.ActionListService;
027import org.kuali.rice.kew.api.WorkflowRuntimeException;
028import org.kuali.rice.kew.api.action.ActionRequestStatus;
029import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
030import org.kuali.rice.kew.api.exception.LockingException;
031import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
032import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
033import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO;
034import org.kuali.rice.kew.service.KEWServiceLocator;
035
036import javax.persistence.EntityManager;
037import javax.persistence.EntityNotFoundException;
038import javax.persistence.PersistenceContext;
039import javax.persistence.Query;
040import java.math.BigDecimal;
041import java.util.ArrayList;
042import java.util.Collection;
043import java.util.Iterator;
044import java.util.List;
045import java.util.Set;
046
047
048public class DocumentRouteHeaderDAOJpaImpl implements DocumentRouteHeaderDAO {
049
050        @PersistenceContext(unitName="kew-unit")
051        private EntityManager entityManager;
052    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentRouteHeaderDAOJpaImpl.class);
053
054    
055    /**
056         * @return the entityManager
057         */
058        public EntityManager getEntityManager() {
059                return this.entityManager;
060        }
061
062        /**
063         * @param entityManager the entityManager to set
064         */
065        public void setEntityManager(EntityManager entityManager) {
066                this.entityManager = entityManager;
067        }
068
069        public void saveRouteHeader(DocumentRouteHeaderValue routeHeader) {     
070        DocumentRouteHeaderValueContent documentContent = routeHeader.getDocumentContent();     
071//      List<SearchableAttributeValue> searchableAttributes = routeHeader.getSearchableAttributeValues();
072        
073        if (routeHeader.getDocumentId() == null){
074                entityManager.persist(routeHeader);
075        } else {
076                OrmUtils.merge(entityManager, routeHeader);
077        }
078        
079        //Save document content (document content retrieved via a service call)
080        documentContent.setDocumentId(routeHeader.getDocumentId());
081        entityManager.merge(documentContent);
082        
083        /*
084        //Save searchable attributes
085        for (SearchableAttributeValue searchableAttributeValue:searchableAttributes){
086                searchableAttributeValue.setDocumentId(routeHeader.getDocumentId());
087                if (searchableAttributeValue.getSearchableAttributeValueId() == null){
088                        entityManager.persist(searchableAttributeValue);
089                } else {
090                        entityManager.merge(searchableAttributeValue);
091                }
092        }
093        */
094    }
095
096    public DocumentRouteHeaderValueContent getContent(String documentId) {
097        Query query = entityManager.createNamedQuery("DocumentRouteHeaderValueContent.FindByDocumentId");
098        query.setParameter("documentId", documentId);
099        return (DocumentRouteHeaderValueContent)query.getSingleResult();
100    }
101
102    public void clearRouteHeaderSearchValues(String documentId) {
103        Collection<SearchableAttributeValue> searchableAttributeValues = findSearchableAttributeValues(documentId);
104        for (SearchableAttributeValue searchableAttributeValue:searchableAttributeValues){
105                entityManager.remove(searchableAttributeValue);
106        }
107    }
108   
109    public Collection<SearchableAttributeValue> findSearchableAttributeValues(String documentId){
110        List<SearchableAttributeValue> searchableAttributeValues = new ArrayList<SearchableAttributeValue>();
111        
112        for (int i=1;i<=4; i++){
113                String namedQuery = "";
114                switch (i) {
115                                case 1: namedQuery = "SearchableAttributeFloatValue.FindByDocumentId"; break;
116                                case 2: namedQuery = "SearchableAttributeDateTimeValue.FindByDocumentId"; break;
117                                case 3: namedQuery = "SearchableAttributeLongValue.FindByDocumentId";break;
118                                case 4: namedQuery = "SearchableAttributeStringValue.FindByDocumentId"; break;
119                }
120                Query query = entityManager.createNamedQuery(namedQuery);
121                query.setParameter("documentId", documentId);           
122                searchableAttributeValues.addAll(query.getResultList());
123        }       
124
125        return searchableAttributeValues;
126    }
127
128    public void lockRouteHeader(final String documentId, final boolean wait) {
129        String sql = getPlatform().getLockRouteHeaderQuerySQL(documentId, wait);
130        try{
131                Query query = entityManager.createNativeQuery(sql);
132                query.setParameter(1, documentId);
133                query.getSingleResult();
134        } catch (Exception e){
135                //FIXME: Should this check for hibernate LockAcquisitionException
136                throw new LockingException("Could not aquire lock on document, documentId=" + documentId, e);
137        }
138    }
139
140    public DocumentRouteHeaderValue findRouteHeader(String documentId) {
141        return findRouteHeader(documentId, false);
142    }
143
144    public DocumentRouteHeaderValue findRouteHeader(String documentId, boolean clearCache) {
145        Query query = entityManager.createNamedQuery("DocumentRouteHeaderValue.FindByDocumentId");
146        query.setParameter("documentId", documentId);
147
148        //TODO: What cache do we clear when using JPA
149        if (clearCache) {
150                //this.getPersistenceBrokerTemplate().clearCache();
151        }
152        
153            DocumentRouteHeaderValue routeHeader = (DocumentRouteHeaderValue) query.getSingleResult(); 
154//          routeHeader.setSearchableAttributeValues(findSearchableAttributeValues(documentId));
155            return routeHeader;
156    }
157
158    public Collection<DocumentRouteHeaderValue> findRouteHeaders(Collection<String> documentIds) {
159        return findRouteHeaders(documentIds, false);
160    }
161    
162    public Collection<DocumentRouteHeaderValue> findRouteHeaders(Collection<String> documentIds, boolean clearCache) {
163        if (documentIds == null || documentIds.isEmpty()) {
164                return null;
165        }
166        Criteria crit = new Criteria(DocumentRouteHeaderValue.class.getName());
167        crit.in("documentId", documentIds);
168        
169        //TODO: What cache do we clear when using JPA
170        if (clearCache) {
171                //this.getPersistenceBrokerTemplate().clearCache();
172        }
173        
174        return new QueryByCriteria(entityManager, crit).toQuery().getResultList();
175    }
176    
177    public void deleteRouteHeader(DocumentRouteHeaderValue routeHeader) {
178        DocumentRouteHeaderValue attachedRouteHeader = findRouteHeader(routeHeader.getDocumentId());
179        entityManager.remove(attachedRouteHeader);
180    }
181
182    public String getNextDocumentId() {
183        Long nextDocumentId = getPlatform().getNextValSQL("KREW_DOC_HDR_S", entityManager);
184        return nextDocumentId.toString();
185    }
186    
187    protected DatabasePlatform getPlatform() {
188        return (DatabasePlatform) GlobalResourceLoader.getService(RiceConstants.DB_PLATFORM);
189    }
190
191    @Override
192    public Collection<String> findPendingByResponsibilityIds(Set<String> responsibilityIds) {
193
194        if (responsibilityIds.isEmpty()) {
195            return new ArrayList();
196        }
197
198        String respIds = "('";
199        int index = 0;
200        for (String responsibilityId : responsibilityIds) {
201            respIds += responsibilityId + (index == responsibilityIds.size()-1 ? "" : "','");
202        }
203        respIds += "')";
204
205        String query = "SELECT DISTINCT(doc_hdr_id) FROM KREW_ACTN_RQST_T "+
206                "WHERE (STAT_CD='" +
207                ActionRequestStatus.INITIALIZED.getCode()+
208                "' OR STAT_CD='"+
209                ActionRequestStatus.ACTIVATED.getCode()+
210                "') AND RSP_ID IN "+respIds;
211
212        LOG.debug("Query to find pending documents for requeue: " + query);
213        
214        List<String> idList = new ArrayList<String>();
215        for (Object tempId : entityManager.createNativeQuery(query).getResultList()) {
216                idList.add(((String) tempId));
217        }
218
219        return idList; //(List<Long>)entityManager.createNativeQuery(query).getResultList();
220    }
221
222    public boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue) {
223        return hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeDateTimeValue.FindByKey")
224                || hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeStringValue.FindByKey")
225                || hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeLongValue.FindByKey")
226                || hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeFloatValue.FindByKey");
227    }
228    
229    private boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue, String namedQuery) {
230        Query query = entityManager.createNamedQuery(namedQuery);
231        query.setParameter("documentId", documentId);
232        query.setParameter("searchableAttributeKey", searchableAttributeKey);
233        Collection results = query.getResultList();
234        if (!results.isEmpty()) {
235            for (Iterator iterator = results.iterator(); iterator.hasNext();) {
236                SearchableAttributeValue attribute = (SearchableAttributeValue) iterator.next();
237                if (StringUtils.equals(attribute.getSearchableAttributeDisplayValue(), searchableAttributeValue)) {
238                    return true;
239                }
240            }
241        }
242        return false;           
243    }
244
245    public String getApplicationIdByDocumentId(String documentId) {
246        if (documentId == null) {
247                throw new IllegalArgumentException("Encountered a null document ID.");
248        }
249        
250        String applicationId = null;
251        
252        try {
253            String sql = "SELECT DT.APPL_ID FROM KREW_DOC_TYP_T DT, KREW_DOC_HDR_T DH "+
254                "WHERE DH.DOC_TYP_ID=DT.DOC_TYP_ID AND "+
255                "DH.DOC_HDR_ID=?";
256                
257            Query query = entityManager.createNativeQuery(sql);
258            query.setParameter(1, documentId);
259            
260            applicationId = (String)query.getSingleResult();
261        } catch (EntityNotFoundException enfe) {
262                throw new WorkflowRuntimeException(enfe.getMessage());
263                }
264        
265        return applicationId;
266    }
267
268    public String getDocumentStatus(String documentId) {
269        DocumentRouteHeaderValue document = findRouteHeader(documentId);
270
271                return document.getDocRouteStatus();
272    }
273    
274    public String getAppDocId(String documentId) {
275        Query query = entityManager.createNamedQuery("DocumentRouteHeaderValue.GetAppDocId");
276        query.setParameter("documentId", documentId);
277        return (String) query.getSingleResult(); 
278         }
279
280    public String getAppDocStatus(String documentId) {
281        Query query = entityManager.createNamedQuery("DocumentRouteHeaderValue.GetAppDocStatus");
282        query.setParameter("documentId", documentId);
283        return (String) query.getSingleResult();
284    }
285
286    public void save(SearchableAttributeValue searchableAttributeValue) {       
287        if (searchableAttributeValue.getSearchableAttributeValueId() == null){
288                entityManager.persist(searchableAttributeValue);
289        } else {
290                entityManager.merge(searchableAttributeValue);
291        }
292    }
293
294        public Collection findByDocTypeAndAppId(String documentTypeName,
295                        String appId) {
296        try {
297            String sql = 
298                        "SELECT DISTINCT " +
299                        "    (docHdr.doc_hdr_id) " +
300                        "FROM " +
301                        "    KREW_DOC_HDR_T docHdr, " +
302                        "    KREW_DOC_TYP_T docTyp " +
303                        "WHERE " +
304                        "    docHdr.APP_DOC_ID     = ? " +
305                        "    AND docHdr.DOC_TYP_ID = docTyp.DOC_TYP_ID " +
306                        "    AND docTyp.DOC_TYP_NM = ?";
307                
308            Query query = entityManager.createNativeQuery(sql);
309            query.setParameter(1, appId);
310            query.setParameter(2, documentTypeName);
311            Collection<Long> idCollection = new ArrayList<Long>();
312            for (Object tempId : query.getResultList()) {
313                idCollection.add(((BigDecimal)tempId).longValueExact());
314            }
315            return idCollection;
316        } catch (EntityNotFoundException enfe) {
317                throw new WorkflowRuntimeException(enfe.getMessage());
318                }
319        }
320
321
322}