View Javadoc
1   /**
2    * Copyright 2005-2016 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.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.commons.lang.exception.ExceptionUtils;
20  import org.kuali.rice.kew.api.KewApiConstants;
21  import org.kuali.rice.kew.api.action.ActionItem;
22  import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
23  import org.kuali.rice.kew.docsearch.dao.SearchableAttributeDAO;
24  import org.kuali.rice.kew.doctype.bo.DocumentType;
25  import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
26  import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
27  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
28  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
29  import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO;
30  import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
31  import org.kuali.rice.kew.service.KEWServiceLocator;
32  import org.kuali.rice.kim.api.identity.principal.Principal;
33  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
34  import org.kuali.rice.krad.data.DataObjectService;
35  import org.kuali.rice.krad.data.PersistenceOption;
36  import org.springframework.beans.factory.annotation.Required;
37  
38  import javax.persistence.OptimisticLockException;
39  import java.math.BigDecimal;
40  import java.sql.Timestamp;
41  import java.util.ArrayList;
42  import java.util.Collection;
43  import java.util.HashMap;
44  import java.util.HashSet;
45  import java.util.List;
46  import java.util.Map;
47  import java.util.Set;
48  
49  public class RouteHeaderServiceImpl implements RouteHeaderService {
50  
51      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RouteHeaderServiceImpl.class);
52  
53      private DocumentRouteHeaderDAO routeHeaderDAO;
54      private SearchableAttributeDAO searchableAttributeDAO;
55  
56      private DataObjectService dataObjectService;
57  
58      public DocumentRouteHeaderValue getRouteHeader(String documentId) {
59          return getDataObjectService().find(DocumentRouteHeaderValue.class, documentId);
60      }
61  
62      public DocumentRouteHeaderValue getRouteHeader(String documentId, boolean clearCache) {
63      	return getRouteHeaderDAO().findRouteHeader(documentId, clearCache);
64      }
65  
66      public Collection<DocumentRouteHeaderValue> getRouteHeaders(Collection<String> documentIds) {
67           return getRouteHeaderDAO().findRouteHeaders(documentIds);
68      }
69      
70      public Collection<DocumentRouteHeaderValue> getRouteHeaders(Collection<String> documentIds, boolean clearCache) {
71      	return getRouteHeaderDAO().findRouteHeaders(documentIds, clearCache);
72      }
73      
74      public Map<String,DocumentRouteHeaderValue> getRouteHeadersForActionItems(Collection<ActionItem> actionItems) {
75      	Map<String,DocumentRouteHeaderValue> routeHeaders = new HashMap<String,DocumentRouteHeaderValue>();
76      	List<String> documentIds = new ArrayList<String>(actionItems.size());
77      	for (ActionItem actionItem : actionItems) {
78      		documentIds.add(actionItem.getDocumentId());
79      	}
80      	Collection<DocumentRouteHeaderValue> actionItemRouteHeaders = getRouteHeaders(documentIds);
81      	if (actionItemRouteHeaders != null) {
82      		for (DocumentRouteHeaderValue routeHeader : actionItemRouteHeaders) {
83      			routeHeaders.put(routeHeader.getDocumentId(), routeHeader);
84      		}
85      	}
86      	return routeHeaders;
87      }
88      
89      public void lockRouteHeader(String documentId) {
90          getRouteHeaderDAO().lockRouteHeader(documentId);
91          LOG.debug("Successfully locked document [docId=" + documentId + "]");
92      }
93  
94      public DocumentRouteHeaderValue saveRouteHeader(DocumentRouteHeaderValue routeHeader) {
95          if ( LOG.isDebugEnabled() ) {
96              LOG.debug( "About to Save the route Header: " + routeHeader.getDocumentId() + " / version="
97                      + routeHeader.getVersionNumber() );
98              DocumentRouteHeaderValue currHeader = getDataObjectService().find(DocumentRouteHeaderValue.class,
99                      routeHeader.getDocumentId());
100             if ( currHeader != null ) {
101                 LOG.debug( "Current Header Version: " + currHeader.getVersionNumber() );
102             } else {
103                 LOG.debug( "Current Header: null" );
104             }
105             LOG.debug( ExceptionUtils.getStackTrace(new Throwable()) );
106         }
107         try {
108             // before saving, copy off the document content, since it's transient it will get erased during a JPA merge
109             DocumentRouteHeaderValueContent content = routeHeader.getDocumentContent();
110             DocumentRouteHeaderValue drvPersisted = dataObjectService.save(routeHeader, PersistenceOption.FLUSH);
111             // now let's save the content and reattach it to our document
112             content.setDocumentId(drvPersisted.getDocumentId());
113             content = dataObjectService.save(content);
114             drvPersisted.setDocumentContent(content);
115             return drvPersisted;
116         } catch ( RuntimeException ex ) {
117             if ( ex.getCause() instanceof OptimisticLockException) {
118                 LOG.error( "Optimistic Locking Exception saving document header or content. Offending object: "
119                         + ex.getCause()
120                         + "; DocumentId = " + routeHeader.getDocumentId() + " ;  Version Number = "
121                         + routeHeader.getVersionNumber());
122             }
123             LOG.error( "Unable to save document header or content. Route Header: " + routeHeader, ex );
124             throw ex;
125         }
126     }
127 
128     public void deleteRouteHeader(DocumentRouteHeaderValue routeHeader) {
129         dataObjectService.delete(routeHeader);
130     }
131 
132     public String getNextDocumentId() {
133         return getRouteHeaderDAO().getNextDocumentId();
134     }
135 
136     public Collection findPendingByResponsibilityIds(Set responsibilityIds) {
137         return getRouteHeaderDAO().findPendingByResponsibilityIds(responsibilityIds);
138     }
139 
140     public void clearRouteHeaderSearchValues(String documentId) {
141         getRouteHeaderDAO().clearRouteHeaderSearchValues(documentId);
142     }
143     
144     public void updateRouteHeaderSearchValues(String documentId, List<SearchableAttributeValue> searchAttributes) {
145         getRouteHeaderDAO().clearRouteHeaderSearchValues(documentId);
146         HashSet<String> dupedSet = new HashSet<String>();
147         //"de-dupe" for value,key,and doc header id
148         for (SearchableAttributeValue searchAttribute : searchAttributes) {
149             if(searchAttribute != null){
150                 String fakeKey = searchAttribute.getSearchableAttributeKey() + "-" + searchAttribute.getSearchableAttributeValue();
151                 if(!dupedSet.contains(fakeKey)){
152                     getRouteHeaderDAO().save(searchAttribute);
153                     dupedSet.add(fakeKey);
154                 }
155             }
156         }
157         LOG.warn("Deduplication adjusted incoming SearchableAttributeValue list from original: " + searchAttributes.size() + " entries into : "  + (searchAttributes.size() - dupedSet.size()) + " entries.");
158     }
159 
160     public void validateRouteHeader(DocumentRouteHeaderValue routeHeader){
161         LOG.debug("Enter validateRouteHeader(..)");
162         List errors = new ArrayList();
163 
164         if (routeHeader.getDocRouteStatus() == null || routeHeader.getDocRouteStatus().trim().equals("")) {
165             errors.add(new WorkflowServiceErrorImpl("RouteHeader route status null.", "routeheader.routestatus.empty"));
166         } else if (!KewApiConstants.DOCUMENT_STATUSES.containsKey(routeHeader.getDocRouteStatus())){
167             errors.add(new WorkflowServiceErrorImpl("RouteHeader route status invalid.", "routeheader.routestatus.invalid"));
168         }
169 
170         if(routeHeader.getDocRouteLevel() == null || routeHeader.getDocRouteLevel().intValue() < 0){
171             errors.add(new WorkflowServiceErrorImpl("RouteHeader route level invalid.", "routeheader.routelevel.invalid"));
172         }
173 
174         if(routeHeader.getDateLastModified() == null){
175             errors.add(new WorkflowServiceErrorImpl("RouteHeader status modification date empty.", "routeheader.statusmoddate.empty"));
176         }
177 
178         if(routeHeader.getCreateDate() == null){
179             errors.add(new WorkflowServiceErrorImpl("RouteHeader status create date empty.", "routeheader.createdate.empty"));
180         }
181         if(routeHeader.getDocVersion() == null || routeHeader.getDocVersion().intValue() < 0){
182             errors.add(new WorkflowServiceErrorImpl("RouteHeader doc version invalid.", "routeheader.docversion.invalid"));
183         }
184 
185         if (routeHeader.getInitiatorWorkflowId () == null || routeHeader.getInitiatorWorkflowId().trim().equals("")) {
186             errors.add(new WorkflowServiceErrorImpl("RouteHeader initiator null.", "routeheader.initiator.empty"));
187         }
188         else
189         {
190            	Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(routeHeader.getInitiatorWorkflowId());
191             if(principal == null)
192             {
193                	errors.add(new WorkflowServiceErrorImpl("RouteHeader initiator id invalid.", "routeheader.initiator.invalid"));
194             }
195         }
196 
197         if(!StringUtils.isBlank(routeHeader.getDocumentTypeId())){
198             DocumentType docType = KEWServiceLocator.getDocumentTypeService().findById(routeHeader.getDocumentTypeId());
199             if(docType == null){
200                 errors.add(new WorkflowServiceErrorImpl("RouteHeader document type id invalid.", "routeheader.doctypeid.invalid"));
201             }
202         }
203 
204         LOG.debug("Exit validateRouteHeader(..) ");
205         if (!errors.isEmpty()) {
206             throw new WorkflowServiceErrorException("RouteHeader Validation Error", errors);
207         }
208     }
209 
210     public String getApplicationIdByDocumentId(String documentId) {
211     	return getRouteHeaderDAO().getApplicationIdByDocumentId(documentId);
212     }
213 
214     public DocumentRouteHeaderValueContent getContent(String documentId) {
215     	if (documentId == null) {
216     		return new DocumentRouteHeaderValueContent();
217     	}
218         DocumentRouteHeaderValueContent content = getRouteHeaderDAO().getContent(documentId);
219     	if (content == null) {
220     		content = new DocumentRouteHeaderValueContent(documentId);
221     	}
222     	return content;
223     }
224 
225     public boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue) {
226 	return getRouteHeaderDAO().hasSearchableAttributeValue(documentId, searchableAttributeKey, searchableAttributeValue);
227     }
228 
229     public String getDocumentStatus(String documentId) {
230     	return getRouteHeaderDAO().getDocumentStatus(documentId);
231     }
232     
233     public String getAppDocId(String documentId) {
234  	 	if (documentId == null) {
235  	 		return null;
236  	 	}
237  	 	return getRouteHeaderDAO().getAppDocId(documentId);
238     }
239 
240     public String getAppDocStatus(String documentId) {
241         if (documentId == null) {
242             return null;
243         }
244         return getRouteHeaderDAO().getAppDocStatus(documentId);
245     }
246 
247     public DocumentRouteHeaderDAO getRouteHeaderDAO() {
248         return routeHeaderDAO;
249     }
250 
251     public void setRouteHeaderDAO(DocumentRouteHeaderDAO routeHeaderDAO) {
252         this.routeHeaderDAO = routeHeaderDAO;
253     }
254 
255 	public List<Timestamp> getSearchableAttributeDateTimeValuesByKey(
256 			String documentId, String key) {
257 		return getSearchableAttributeDAO().getSearchableAttributeDateTimeValuesByKey(documentId, key);
258 	}
259 
260 	public List<BigDecimal> getSearchableAttributeFloatValuesByKey(
261 			String documentId, String key) {
262 		return getSearchableAttributeDAO().getSearchableAttributeFloatValuesByKey(documentId, key);
263 	}
264 
265 	public List<Long> getSearchableAttributeLongValuesByKey(String documentId,
266 			String key) {
267 		return getSearchableAttributeDAO().getSearchableAttributeLongValuesByKey(documentId, key);
268 	}
269 
270 	public List<String> getSearchableAttributeStringValuesByKey(
271 			String documentId, String key) {
272 
273 		return getSearchableAttributeDAO().getSearchableAttributeStringValuesByKey(documentId, key);
274 	}
275 
276 	public void setSearchableAttributeDAO(SearchableAttributeDAO searchableAttributeDAO) {
277 		this.searchableAttributeDAO = searchableAttributeDAO;
278 	}
279 
280 	public SearchableAttributeDAO getSearchableAttributeDAO() {
281 		return searchableAttributeDAO;
282 	}
283 
284 	public Collection findByDocTypeAndAppId(String documentTypeName,
285 			String appId) {
286 		return getRouteHeaderDAO().findByDocTypeAndAppId(documentTypeName, appId);
287 	}
288 
289     public DataObjectService getDataObjectService(){
290         return dataObjectService;
291     }
292 
293     @Required
294     public void setDataObjectService(DataObjectService dataObjectService) {
295         this.dataObjectService = dataObjectService;
296     }
297 }