001    /**
002     * Copyright 2005-2011 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.routeheader.dao.impl;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
020    import org.kuali.rice.core.api.util.RiceConstants;
021    import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
022    import org.kuali.rice.core.framework.persistence.jpa.criteria.Criteria;
023    import org.kuali.rice.core.framework.persistence.jpa.criteria.QueryByCriteria;
024    import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
025    import org.kuali.rice.kew.actionitem.ActionItem;
026    import org.kuali.rice.kew.actionlist.service.ActionListService;
027    import org.kuali.rice.kew.api.WorkflowRuntimeException;
028    import org.kuali.rice.kew.api.action.ActionRequestStatus;
029    import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
030    import org.kuali.rice.kew.api.exception.LockingException;
031    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
032    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
033    import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO;
034    import org.kuali.rice.kew.service.KEWServiceLocator;
035    
036    import javax.persistence.EntityManager;
037    import javax.persistence.EntityNotFoundException;
038    import javax.persistence.PersistenceContext;
039    import javax.persistence.Query;
040    import java.math.BigDecimal;
041    import java.util.ArrayList;
042    import java.util.Collection;
043    import java.util.Iterator;
044    import java.util.List;
045    import java.util.Set;
046    
047    
048    public 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            List<SearchableAttributeValue> searchableAttributeValues = findSearchableAttributeValues(documentId);
104            for (SearchableAttributeValue searchableAttributeValue:searchableAttributeValues){
105                    entityManager.remove(searchableAttributeValue);
106            }
107        }
108       
109        private List<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            // need to clear action list cache for users who have this item in their action list
179            ActionListService actionListSrv = KEWServiceLocator.getActionListService();
180            Collection actionItems = actionListSrv.findByDocumentId(routeHeader.getDocumentId());
181            for (Iterator iter = actionItems.iterator(); iter.hasNext();) {
182                    ActionItem actionItem = (ActionItem) iter.next();
183                    try {
184                            KEWServiceLocator.getUserOptionsService().saveRefreshUserOption(actionItem.getPrincipalId());
185                    } catch (Exception e) {
186                            LOG.error("error saving refreshUserOption", e);
187                    }
188            }
189            
190            DocumentRouteHeaderValue attachedRouteHeader = findRouteHeader(routeHeader.getDocumentId());
191            entityManager.remove(attachedRouteHeader);
192        }
193    
194        public String getNextDocumentId() {
195            Long nextDocumentId = getPlatform().getNextValSQL("KREW_DOC_HDR_S", entityManager);
196            return nextDocumentId.toString();
197        }
198        
199        protected DatabasePlatform getPlatform() {
200            return (DatabasePlatform) GlobalResourceLoader.getService(RiceConstants.DB_PLATFORM);
201        }
202    
203        @Override
204        public Collection<String> findPendingByResponsibilityIds(Set<String> responsibilityIds) {
205    
206            if (responsibilityIds.isEmpty()) {
207                return new ArrayList();
208            }
209    
210            String respIds = "(";
211            int index = 0;
212            for (String responsibilityId : responsibilityIds) {
213                respIds += responsibilityId + (index == responsibilityIds.size()-1 ? "" : ",");
214            }
215            respIds += ")";
216    
217            String query = "SELECT DISTINCT(doc_hdr_id) FROM KREW_ACTN_RQST_T "+
218                    "WHERE (STAT_CD='" +
219                    ActionRequestStatus.INITIALIZED.getCode()+
220                    "' OR STAT_CD='"+
221                    ActionRequestStatus.ACTIVATED.getCode()+
222                    "') AND RSP_ID IN "+respIds;
223    
224            LOG.debug("Query to find pending documents for requeue: " + query);
225            
226            List<String> idList = new ArrayList<String>();
227            for (Object tempId : entityManager.createNativeQuery(query).getResultList()) {
228                    idList.add(((String) tempId));
229            }
230    
231            return idList; //(List<Long>)entityManager.createNativeQuery(query).getResultList();
232        }
233    
234        public boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue) {
235            return hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeDateTimeValue.FindByKey")
236                    || hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeStringValue.FindByKey")
237                    || hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeLongValue.FindByKey")
238                    || hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue, "SearchableAttributeFloatValue.FindByKey");
239        }
240        
241        private boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue, String namedQuery) {
242            Query query = entityManager.createNamedQuery(namedQuery);
243            query.setParameter("documentId", documentId);
244            query.setParameter("searchableAttributeKey", searchableAttributeKey);
245            Collection results = query.getResultList();
246            if (!results.isEmpty()) {
247                for (Iterator iterator = results.iterator(); iterator.hasNext();) {
248                    SearchableAttributeValue attribute = (SearchableAttributeValue) iterator.next();
249                    if (StringUtils.equals(attribute.getSearchableAttributeDisplayValue(), searchableAttributeValue)) {
250                        return true;
251                    }
252                }
253            }
254            return false;           
255        }
256    
257        public String getApplicationIdByDocumentId(String documentId) {
258            if (documentId == null) {
259                    throw new IllegalArgumentException("Encountered a null document ID.");
260            }
261            
262            String applicationId = null;
263            
264            try {
265                String sql = "SELECT DT.APPL_ID FROM KREW_DOC_TYP_T DT, KREW_DOC_HDR_T DH "+
266                    "WHERE DH.DOC_TYP_ID=DT.DOC_TYP_ID AND "+
267                    "DH.DOC_HDR_ID=?";
268                    
269                Query query = entityManager.createNativeQuery(sql);
270                query.setParameter(1, documentId);
271                
272                applicationId = (String)query.getSingleResult();
273            } catch (EntityNotFoundException enfe) {
274                    throw new WorkflowRuntimeException(enfe.getMessage());
275                    }
276            
277            return applicationId;
278        }
279    
280        public String getDocumentStatus(String documentId) {
281            DocumentRouteHeaderValue document = findRouteHeader(documentId);
282    
283                    return document.getDocRouteStatus();
284        }
285        
286        public String getAppDocId(String documentId) {
287            Query query = entityManager.createNamedQuery("DocumentRouteHeaderValue.GetAppDocId");
288            query.setParameter("documentId", documentId);
289            return (String) query.getSingleResult(); 
290             }
291        
292        public void save(SearchableAttributeValue searchableAttributeValue) {       
293            if (searchableAttributeValue.getSearchableAttributeValueId() == null){
294                    entityManager.persist(searchableAttributeValue);
295            } else {
296                    entityManager.merge(searchableAttributeValue);
297            }
298        }
299    
300            public Collection findByDocTypeAndAppId(String documentTypeName,
301                            String appId) {
302            try {
303                String sql = 
304                            "SELECT DISTINCT " +
305                            "    (docHdr.doc_hdr_id) " +
306                            "FROM " +
307                            "    KREW_DOC_HDR_T docHdr, " +
308                            "    KREW_DOC_TYP_T docTyp " +
309                            "WHERE " +
310                            "    docHdr.APP_DOC_ID     = ? " +
311                            "    AND docHdr.DOC_TYP_ID = docTyp.DOC_TYP_ID " +
312                            "    AND docTyp.DOC_TYP_NM = ?";
313                    
314                Query query = entityManager.createNativeQuery(sql);
315                query.setParameter(1, appId);
316                query.setParameter(2, documentTypeName);
317                Collection<Long> idCollection = new ArrayList<Long>();
318                for (Object tempId : query.getResultList()) {
319                    idCollection.add(((BigDecimal)tempId).longValueExact());
320                }
321                return idCollection;
322            } catch (EntityNotFoundException enfe) {
323                    throw new WorkflowRuntimeException(enfe.getMessage());
324                    }
325            }
326    
327    
328    }