View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.routeheader.dao.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.config.property.ConfigContext;
20  import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
21  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
22  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
23  import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO;
24  import org.kuali.rice.krad.data.DataObjectService;
25  import org.kuali.rice.krad.data.platform.MaxValueIncrementerFactory;
26  import org.springframework.beans.factory.annotation.Required;
27  import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
28  
29  import javax.persistence.EntityManager;
30  import javax.persistence.LockModeType;
31  import javax.persistence.Query;
32  import javax.persistence.TypedQuery;
33  import javax.sql.DataSource;
34  import java.util.ArrayList;
35  import java.util.Collection;
36  import java.util.HashMap;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Set;
40  
41  public class DocumentRouteHeaderDAOJpa implements DocumentRouteHeaderDAO {
42  
43      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentRouteHeaderDAOJpa.class);
44  
45      private static final String LOCK_TIMEOUT_HINT = "javax.persistence.lock.timeout";
46      private static final Long DEFAULT_LOCK_TIMEOUT_SECONDS = Long.valueOf(60 * 60); // default to 1 hour
47  
48      public static final String GET_APP_DOC_ID_NAME = "DocumentRouteHeaderValue.GetAppDocId";
49      public static final String GET_APP_DOC_ID_QUERY = "SELECT d.appDocId from DocumentRouteHeaderValue "
50              + "as d where d.documentId = :documentId";
51      public static final String GET_APP_DOC_STATUS_NAME = "DocumentRouteHeaderValue.GetAppDocStatus";
52      public static final String GET_APP_DOC_STATUS_QUERY = "SELECT d.appDocStatus from "
53              + "DocumentRouteHeaderValue as d where d.documentId = :documentId";
54      public static final String GET_DOCUMENT_HEADERS_NAME = "DocumentRouteHeaderValue.GetDocumentHeaders";
55      public static final String GET_DOCUMENT_HEADERS_QUERY = "SELECT d from DocumentRouteHeaderValue "
56              + "as d where d.documentId IN :documentIds";
57      public static final String GET_DOCUMENT_STATUS_NAME = "DocumentRouteHeaderValue.GetDocumentStatus";
58      public static final String GET_DOCUMENT_STATUS_QUERY = "SELECT d.docRouteStatus from "
59              + "DocumentRouteHeaderValue as d where d.documentId = :documentId";
60      public static final String GET_DOCUMENT_ID_BY_DOC_TYPE_APP_ID_NAME =
61              "DocumentRouteHeaderValue.GetDocumentIdByDocTypeAndAppId";
62      public static final String GET_DOCUMENT_ID_BY_DOC_TYPE_APP_ID_QUERY = "SELECT "
63              + "DISTINCT(DH.documentId) FROM DocumentRouteHeaderValue DH, DocumentType DT "
64              + "WHERE DH.appDocId = :appDocId AND DH.documentTypeId = DT.documentTypeId  AND DT.name = :name";
65  
66  	private EntityManager entityManager;
67      private DataSource dataSource;
68  
69      private DataObjectService dataObjectService;
70  
71      @Override
72      public Collection<DocumentRouteHeaderValue> findRouteHeaders(Collection<String> documentIds){
73          if (documentIds.isEmpty()) {
74              return new ArrayList<DocumentRouteHeaderValue>();
75          }
76          TypedQuery<DocumentRouteHeaderValue> query = getEntityManager().
77                  createNamedQuery(GET_DOCUMENT_HEADERS_NAME, DocumentRouteHeaderValue.class);
78          query.setParameter("documentIds",documentIds);
79          return query.getResultList();
80      }
81  
82      @Override
83      public Collection<DocumentRouteHeaderValue> findRouteHeaders(Collection<String> documentIds, boolean clearCache){
84          Collection<DocumentRouteHeaderValue> documentRouteHeaderValues = findRouteHeaders(documentIds);
85          if(clearCache){
86              for(DocumentRouteHeaderValue drhv : documentRouteHeaderValues){
87                  getEntityManager().refresh(drhv);
88              }
89  
90          }
91          return documentRouteHeaderValues;
92      }
93  
94      @Override
95      public void lockRouteHeader(final String documentId) {
96          // passing a hint here on the lock timeout, this will really only work on Oracle since it supports "wait"
97          // on a SELECT ... FOR UPDATE but other databases don't
98          //
99          // one random additional piece of trivia to note, if the timeout comes back non-zero, then EclipseLink just
100         // ingores it when sending it to MySQL and issues a plain SELECT ... FOR UPDATE. However if it cames back as 0,
101         // it will try to issue a SELECT ... FOR UPDATE NOWAIT even thouh MySQL doesn't support it. This, of course,
102         // triggers an exception from the MySQL database
103         //
104         // the moral of the story? don't ever set the timeout to zero, at least not until EclipseLink fixes that bug
105         Map<String, Object> options = new HashMap<String, Object>();
106         options.put(LOCK_TIMEOUT_HINT, getTimeoutMilliseconds());
107         getEntityManager().find(DocumentRouteHeaderValue.class, documentId, LockModeType.PESSIMISTIC_WRITE, options);
108     }
109 
110     protected Long getTimeoutMilliseconds() {
111         Long secondsToWait = DEFAULT_LOCK_TIMEOUT_SECONDS;
112         String timeoutValue = ConfigContext.getCurrentContextConfig().getDocumentLockTimeout();
113         if (timeoutValue != null) {
114             try {
115                 secondsToWait = Long.parseLong(timeoutValue);
116             } catch (NumberFormatException e) {
117                 LOG.warn("Failed to parse document lock timeout as it was not a valid number: " + timeoutValue);
118             }
119         }
120         return secondsToWait * 1000;
121     }
122 
123     @Override
124     public DocumentRouteHeaderValue findRouteHeader(String documentId, boolean clearCache) {
125         DocumentRouteHeaderValue dv = getDataObjectService().find(DocumentRouteHeaderValue.class,documentId);
126         if(clearCache){
127             getEntityManager().refresh(dv);
128         }
129         return dv;
130     }
131 
132     @Override
133     public String getNextDocumentId(){
134         DataFieldMaxValueIncrementer incrementer = MaxValueIncrementerFactory.getIncrementer(
135                                         getDataSource(), "KREW_DOC_HDR_S");
136         return incrementer.nextStringValue();
137     }
138 
139     public Collection<String> findPendingByResponsibilityIds(Set<String> responsibilityIds) {
140         List<String> documentIds = new ArrayList<String>();
141         if (responsibilityIds.isEmpty()) {
142             return documentIds;
143         }
144         TypedQuery<String> query =
145                 getEntityManager().createNamedQuery("ActionRequestValue.FindPendingByResponsibilityIds", String.class);
146         query.setParameter("respIds", responsibilityIds);
147         return query.getResultList();
148     }
149 
150     public void clearRouteHeaderSearchValues(String documentId) {
151 
152         Query query = getEntityManager().
153                 createNamedQuery("SearchableAttributeValue.FindSearchableAttributesByDocumentId");
154         query.setParameter("documentId",documentId);
155         List<SearchableAttributeValue> searchableAttributeValues =
156                 (List<SearchableAttributeValue>)query.getResultList();
157         for(SearchableAttributeValue sa : searchableAttributeValues){
158             getDataObjectService().delete(sa);
159         }
160     }
161 
162     @Override
163     public Collection<SearchableAttributeValue> findSearchableAttributeValues(String documentId) {
164         Query query = getEntityManager().createNamedQuery(
165                 "SearchableAttributeValue.FindSearchableAttributesByDocumentId");
166         query.setParameter("documentId",documentId);
167         return query.getResultList();
168     }
169 
170     @Override
171     public DocumentRouteHeaderValueContent getContent(String documentId) {
172         DocumentRouteHeaderValueContent content = null;
173         Query query = getEntityManager().createNamedQuery("DocumentRouteHeaderValueContent.FindByDocumentId");
174         query.setParameter("documentId",documentId);
175         if(query.getResultList() != null && !query.getResultList().isEmpty()) {
176           content = (DocumentRouteHeaderValueContent)query.getResultList().get(0);
177         }
178         return content;
179     }
180 
181     @Override
182     public boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue) {
183         Query query = getEntityManager().createNamedQuery("SearchableAttributeValue.HasSearchableAttributeValue");
184         query.setParameter("documentId",documentId);
185         query.setParameter("searchableAttributeKey",searchableAttributeKey);
186 
187         if(query.getResultList() != null && !query.getResultList().isEmpty()){
188             for(Object ob : query.getResultList()){
189                 SearchableAttributeValue sav = (SearchableAttributeValue)ob;
190                 if (StringUtils.equals(sav.getSearchableAttributeDisplayValue(), searchableAttributeValue)) {
191                     return true;
192                 }
193             }
194         }
195         return false;
196     }
197 
198     public String getDocumentStatus(String documentId) {
199         String status = null;
200 
201         Query query = getEntityManager().createNamedQuery(GET_DOCUMENT_STATUS_NAME);
202         query.setParameter("documentId",documentId);
203         if(query.getResultList() != null && !query.getResultList().isEmpty()){
204             status = (String)query.getResultList().get(0);
205         }
206         return status;
207     }
208 
209     @Override
210     public void save(SearchableAttributeValue searchableAttribute) {
211         getDataObjectService().save(searchableAttribute);
212     }
213 
214     public String getAppDocId(String documentId) {
215         TypedQuery<String> query = getEntityManager().createNamedQuery(GET_APP_DOC_ID_NAME,String.class
216         );
217         query.setParameter("documentId",documentId);
218 
219         String applicationDocId = null;
220         if(query.getResultList() != null && !query.getResultList().isEmpty()){
221             applicationDocId = query.getResultList().get(0);
222         }
223         return applicationDocId;
224 
225     }
226 
227     public String getApplicationIdByDocumentId(String documentId) {
228         if (documentId == null) {
229             throw new IllegalArgumentException("Encountered a null document ID.");
230         }
231 
232         String applicationId = null;
233 
234         TypedQuery<String> query = getEntityManager().createNamedQuery(
235                 "DocumentType.GetAppIdByDocumentId",String.class);
236         query.setParameter("documentId",documentId);
237         if(query.getResultList() != null && !query.getResultList().isEmpty()){
238              applicationId = query.getResultList().get(0);
239         }
240         return applicationId;
241 
242     }
243 
244     public String getAppDocStatus(String documentId) {
245         String applicationDocumentStatus = null;
246 
247         TypedQuery<String> query = getEntityManager().createNamedQuery(GET_APP_DOC_STATUS_NAME,String.class);
248         query.setParameter("documentId",documentId);
249         if(query.getResultList() != null && !query.getResultList().isEmpty()){
250             applicationDocumentStatus = query.getResultList().get(0);
251         }
252         return applicationDocumentStatus;
253     }
254 
255     public Collection findByDocTypeAndAppId(String documentTypeName,
256             String appId) {
257         TypedQuery<String> query = getEntityManager().createNamedQuery(GET_DOCUMENT_ID_BY_DOC_TYPE_APP_ID_NAME,
258                 String.class);
259         query.setParameter("appDocId",appId);
260         query.setParameter("name",documentTypeName);
261         return query.getResultList();
262     }
263 
264     /**
265      * @return the entityManager
266      */
267     public EntityManager getEntityManager() {
268         return this.entityManager;
269     }
270 
271     /**
272      * @param entityManager the entityManager to set
273      */
274     public void setEntityManager(EntityManager entityManager) {
275         this.entityManager = entityManager;
276     }
277 
278     public DataSource getDataSource() {
279         return dataSource;
280     }
281 
282     public void setDataSource(DataSource dataSource) {
283         this.dataSource = dataSource;
284     }
285 
286     public DataObjectService getDataObjectService() {
287         return dataObjectService;
288     }
289 
290     @Required
291     public void setDataObjectService(DataObjectService dataObjectService) {
292         this.dataObjectService = dataObjectService;
293     }
294 
295 }