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.kns.lookup;
17  
18  import org.apache.commons.codec.binary.Base64;
19  import org.kuali.rice.core.api.CoreApiServiceLocator;
20  import org.kuali.rice.kns.web.ui.ResultRow;
21  import org.kuali.rice.krad.bo.BusinessObject;
22  import org.kuali.rice.krad.dao.PersistedLookupMetadataDao;
23  import org.kuali.rice.krad.exception.AuthorizationException;
24  import org.kuali.rice.krad.service.BusinessObjectService;
25  import org.kuali.rice.krad.util.KRADConstants;
26  import org.kuali.rice.krad.util.ObjectUtils;
27  
28  import java.sql.Timestamp;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.HashMap;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Set;
35  
36  public class LookupResultsServiceImpl implements LookupResultsService {
37      private BusinessObjectService businessObjectService;
38      private PersistedLookupMetadataDao persistedLookupMetadataDao;
39      private LookupResultsSupportStrategyService persistableBusinessObjectSupportStrategy;
40      private LookupResultsSupportStrategyService dataDictionarySupportStrategy;
41      
42      /**
43       * @see org.kuali.rice.krad.lookup.LookupResultsService#persistResultsTable(java.lang.String, java.util.List, java.lang.String)
44       */
45      public void persistResultsTable(String lookupResultsSequenceNumber, List<ResultRow> resultTable, String personId) throws Exception {
46          String resultTableString = new String(Base64.encodeBase64(ObjectUtils.toByteArray(resultTable)));
47          
48          Timestamp now = CoreApiServiceLocator.getDateTimeService().getCurrentTimestamp();
49          
50          LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
51          if (lookupResults == null) {
52              lookupResults = new LookupResults();
53              lookupResults.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
54          }
55          lookupResults.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
56          lookupResults.setLookupPersonId(personId);
57          lookupResults.setSerializedLookupResults(resultTableString);
58          lookupResults.setLookupDate(now);
59          businessObjectService.save(lookupResults);
60      }
61  
62      /**
63       * @see org.kuali.rice.krad.lookup.LookupResultsService#persistSelectedObjectIds(java.lang.String, java.util.Set, java.lang.String)
64       */
65      public void persistSelectedObjectIds(String lookupResultsSequenceNumber, Set<String> selectedObjectIds, String personId) throws Exception {
66          SelectedObjectIds selectedObjectIdsBO = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
67          if (selectedObjectIdsBO == null) {
68              selectedObjectIdsBO = new SelectedObjectIds();
69              selectedObjectIdsBO.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
70          }
71          selectedObjectIdsBO.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
72          selectedObjectIdsBO.setLookupPersonId(personId);
73          selectedObjectIdsBO.setSelectedObjectIds(
74                  LookupUtils.convertSetOfObjectIdsToString(selectedObjectIds));
75          selectedObjectIdsBO.setLookupDate(CoreApiServiceLocator.getDateTimeService().getCurrentTimestamp());
76          businessObjectService.save(selectedObjectIdsBO);
77      }
78  
79      /**
80       * Retrieves the LookupResults BO with the given sequence number.  Does not check authentication.
81       * @param lookupResultsSequenceNumber
82       * @return
83       * @throws Exception
84       */
85      protected LookupResults retrieveLookupResults(String lookupResultsSequenceNumber) throws Exception {
86          Map<String, String> queryCriteria = new HashMap<String, String>();
87          queryCriteria.put(KRADConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER, lookupResultsSequenceNumber);
88          LookupResults lookupResults = (LookupResults) businessObjectService.findByPrimaryKey(LookupResults.class, queryCriteria);
89          
90          return lookupResults;
91      }
92  
93      /**
94       * Retrieves the SelectedObjectIds BO with the given sequence number.  Does not check authentication.
95       * @param lookupResultsSequenceNumber
96       * @return
97       * @throws Exception
98       */
99      protected SelectedObjectIds retrieveSelectedObjectIds(String lookupResultsSequenceNumber) throws Exception {
100         Map<String, String> queryCriteria = new HashMap<String, String>();
101         queryCriteria.put(KRADConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER, lookupResultsSequenceNumber);
102         SelectedObjectIds selectedObjectIds = (SelectedObjectIds) businessObjectService.findByPrimaryKey(SelectedObjectIds.class, queryCriteria);
103         
104         return selectedObjectIds;
105     }
106 
107     /**
108      * @see org.kuali.rice.krad.lookup.LookupResultsService#isAuthorizedToAccessLookupResults(java.lang.String, java.lang.String)
109      */
110     public boolean isAuthorizedToAccessLookupResults(String lookupResultsSequenceNumber, String personId) {
111         try {
112             LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
113             return isAuthorizedToAccessLookupResults(lookupResults, personId);
114         }
115         catch (Exception e) {
116             return false;
117         }
118     }
119 
120     /**
121      * Returns whether the user ID parameter is allowed to view the results.
122      * 
123      * @param lookupResults
124      * @param personId
125      * @return
126      */
127     protected boolean isAuthorizedToAccessLookupResults(LookupResults lookupResults, String personId) {
128         return isAuthorizedToAccessMultipleValueLookupMetadata(lookupResults, personId);
129     }
130 
131     /**
132      * @see org.kuali.rice.krad.lookup.LookupResultsService#isAuthorizedToAccessSelectedObjectIds(java.lang.String, java.lang.String)
133      */
134     public boolean isAuthorizedToAccessSelectedObjectIds(String lookupResultsSequenceNumber, String personId) {
135         try {
136             SelectedObjectIds selectedObjectIds = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
137             return isAuthorizedToAccessSelectedObjectIds(selectedObjectIds, personId);
138         }
139         catch (Exception e) {
140             return false;
141         }
142     }
143 
144     /**
145      * Returns whether the user ID parameter is allowed to view the selected object IDs
146      * 
147      * @param selectedObjectIds
148      * @param personId
149      * @return
150      */
151     protected boolean isAuthorizedToAccessSelectedObjectIds(SelectedObjectIds selectedObjectIds, String personId) {
152         return isAuthorizedToAccessMultipleValueLookupMetadata(selectedObjectIds, personId);
153     }
154     
155 
156     /**
157      * @see org.kuali.rice.krad.lookup.LookupResultsService#retrieveResultsTable(java.lang.String, java.lang.String)
158      */
159     public List<ResultRow> retrieveResultsTable(String lookupResultsSequenceNumber, String personId) throws Exception {
160         LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
161         if (!isAuthorizedToAccessLookupResults(lookupResults, personId)) {
162             // TODO: use the other identifier
163             throw new AuthorizationException(personId, "retrieve lookup results", "lookup sequence number " + lookupResultsSequenceNumber);
164         }
165         List<ResultRow> resultTable = (List<ResultRow>) ObjectUtils.fromByteArray(Base64.decodeBase64(lookupResults.getSerializedLookupResults().getBytes()));
166         return resultTable;
167     }
168 
169     /**
170      * Figures out which support strategy to defer to and uses that service to retrieve the results; if the bo class doesn't qualify with any support strategy, an exception is thrown.  A nasty one, too.
171      * 
172      * @see org.kuali.rice.krad.lookup.LookupResultsService#retrieveSelectedResultBOs(java.lang.String, java.lang.Class, java.lang.String)
173      */
174     public <T extends BusinessObject> Collection<T> retrieveSelectedResultBOs(String lookupResultsSequenceNumber, Class<T> boClass, String personId) throws Exception {
175     	final LookupResultsSupportStrategyService supportService = getQualifingSupportStrategy(boClass);
176     	if (supportService == null) {
177     		throw new RuntimeException("BusinessObject class "+boClass.getName()+" cannot be used within a multiple value lookup; it either needs to be a PersistableBusinessObject or have both its primary keys and a lookupable defined in its data dictionary entry");
178     	}
179     	
180     	SelectedObjectIds selectedObjectIds = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
181         
182         if (!isAuthorizedToAccessSelectedObjectIds(selectedObjectIds, personId)) {
183             // TODO: use the other identifier
184             throw new AuthorizationException(personId, "retrieve lookup results", "lookup sequence number " + lookupResultsSequenceNumber);
185         }
186         
187         Set<String> setOfSelectedObjIds = LookupUtils
188                 .convertStringOfObjectIdsToSet(selectedObjectIds.getSelectedObjectIds());
189         
190         if (setOfSelectedObjIds.isEmpty()) {
191             // OJB throws exception if querying on empty set
192             return new ArrayList<T>();
193         }
194     	
195     	return supportService.retrieveSelectedResultBOs(boClass, setOfSelectedObjIds);
196     }
197     
198     /**
199      * Given the business object class, determines the best qualifying LookupResultsSupportStrategyService to use
200      * 
201      * @param boClass a business object class
202      * @return an LookupResultsSupportStrategyService implementation, or null if no qualifying strategies could be found
203      */
204     protected LookupResultsSupportStrategyService getQualifingSupportStrategy(Class boClass) {
205     	if (getPersistableBusinessObjectSupportStrategy().qualifiesForStrategy(boClass)) {
206     		return getPersistableBusinessObjectSupportStrategy();
207     	} else if (getDataDictionarySupportStrategy().qualifiesForStrategy(boClass)) {
208     		return getDataDictionarySupportStrategy();
209     	}
210     	return null;
211     }
212     
213     /**
214      * @see org.kuali.rice.krad.lookup.LookupResultsService#clearPersistedLookupResults(java.lang.String)
215      */
216     public void clearPersistedLookupResults(String lookupResultsSequenceNumber) throws Exception {
217         LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
218         if (lookupResults != null) {
219             businessObjectService.delete(lookupResults);
220         }
221     }
222     
223     /**
224      * @see org.kuali.rice.krad.lookup.LookupResultsService#clearPersistedSelectedObjectIds(java.lang.String)
225      */
226     public void clearPersistedSelectedObjectIds(String lookupResultsSequenceNumber) throws Exception {
227         SelectedObjectIds selectedObjectIds = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
228         if (selectedObjectIds != null) {
229             businessObjectService.delete(selectedObjectIds);
230         }
231     }
232     
233     /**
234 	 * Figures out which LookupResultsServiceSupportStrategy to defer to, and uses that to get the lookup id
235 	 * @see org.kuali.rice.krad.lookup.LookupResultsService#getLookupId(org.kuali.rice.krad.bo.BusinessObject)
236 	 */
237 	public String getLookupId(BusinessObject businessObject) {
238 		final LookupResultsSupportStrategyService supportService = getQualifingSupportStrategy(businessObject.getClass());
239 		if (supportService == null) {
240 			return null; // this may happen quite often, so let's just return null - no exception here
241 		}
242 		return supportService.getLookupIdForBusinessObject(businessObject);
243 	}
244 
245 	public BusinessObjectService getBusinessObjectService() {
246         return businessObjectService;
247     }
248 
249     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
250         this.businessObjectService = businessObjectService;
251     }
252     
253     /**
254      * Determines whether the passed in user ID is allowed to view the lookup metadata (object IDs or results table)
255      * @param mvlm
256      * @param personId
257      * @return
258      */
259     protected boolean isAuthorizedToAccessMultipleValueLookupMetadata(MultipleValueLookupMetadata mvlm, String personId) {
260         return personId.equals(mvlm.getLookupPersonId());
261     }
262 
263     
264     public void deleteOldLookupResults(Timestamp expirationDate) {
265         persistedLookupMetadataDao.deleteOldLookupResults(expirationDate);
266         
267     }
268 
269     public void deleteOldSelectedObjectIds(Timestamp expirationDate) {
270         persistedLookupMetadataDao.deleteOldSelectedObjectIds(expirationDate);
271     }
272 
273     public PersistedLookupMetadataDao getPersistedLookupMetadataDao() {
274         return persistedLookupMetadataDao;
275     }
276 
277     public void setPersistedLookupMetadataDao(PersistedLookupMetadataDao persistedLookupMetadataDao) {
278         this.persistedLookupMetadataDao = persistedLookupMetadataDao;
279     }
280 
281 	/**
282 	 * @return the persistableBusinessObjectSupportStrategy
283 	 */
284 	public LookupResultsSupportStrategyService getPersistableBusinessObjectSupportStrategy() {
285 		return this.persistableBusinessObjectSupportStrategy;
286 	}
287 
288 	/**
289 	 * @return the dataDictionarySupportStrategy
290 	 */
291 	public LookupResultsSupportStrategyService getDataDictionarySupportStrategy() {
292 		return this.dataDictionarySupportStrategy;
293 	}
294 
295 	/**
296 	 * @param persistableBusinessObjectSupportStrategy the persistableBusinessObjectSupportStrategy to set
297 	 */
298 	public void setPersistableBusinessObjectSupportStrategy(
299 			LookupResultsSupportStrategyService persistableBusinessObjectSupportStrategy) {
300 		this.persistableBusinessObjectSupportStrategy = persistableBusinessObjectSupportStrategy;
301 	}
302 
303 	/**
304 	 * @param dataDictionarySupportStrategy the dataDictionarySupportStrategy to set
305 	 */
306 	public void setDataDictionarySupportStrategy(
307 			LookupResultsSupportStrategyService dataDictionarySupportStrategy) {
308 		this.dataDictionarySupportStrategy = dataDictionarySupportStrategy;
309 	}
310     
311 }
312