001 /**
002 * Copyright 2005-2012 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.kns.lookup;
017
018 import org.apache.commons.codec.binary.Base64;
019 import org.kuali.rice.core.api.CoreApiServiceLocator;
020 import org.kuali.rice.kns.web.ui.ResultRow;
021 import org.kuali.rice.krad.bo.BusinessObject;
022 import org.kuali.rice.krad.bo.LookupResults;
023 import org.kuali.rice.krad.bo.MultipleValueLookupMetadata;
024 import org.kuali.rice.krad.bo.SelectedObjectIds;
025 import org.kuali.rice.krad.dao.PersistedLookupMetadataDao;
026 import org.kuali.rice.krad.exception.AuthorizationException;
027 import org.kuali.rice.krad.service.BusinessObjectService;
028 import org.kuali.rice.krad.util.KRADConstants;
029 import org.kuali.rice.krad.util.ObjectUtils;
030
031 import java.sql.Timestamp;
032 import java.util.ArrayList;
033 import java.util.Collection;
034 import java.util.HashMap;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.Set;
038
039 public class LookupResultsServiceImpl implements LookupResultsService {
040 private BusinessObjectService businessObjectService;
041 private PersistedLookupMetadataDao persistedLookupMetadataDao;
042 private LookupResultsSupportStrategyService persistableBusinessObjectSupportStrategy;
043 private LookupResultsSupportStrategyService dataDictionarySupportStrategy;
044
045 /**
046 * @see org.kuali.rice.krad.lookup.LookupResultsService#persistResultsTable(java.lang.String, java.util.List, java.lang.String)
047 */
048 public void persistResultsTable(String lookupResultsSequenceNumber, List<ResultRow> resultTable, String personId) throws Exception {
049 String resultTableString = new String(Base64.encodeBase64(ObjectUtils.toByteArray(resultTable)));
050
051 Timestamp now = CoreApiServiceLocator.getDateTimeService().getCurrentTimestamp();
052
053 LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
054 if (lookupResults == null) {
055 lookupResults = new LookupResults();
056 lookupResults.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
057 }
058 lookupResults.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
059 lookupResults.setLookupPersonId(personId);
060 lookupResults.setSerializedLookupResults(resultTableString);
061 lookupResults.setLookupDate(now);
062 businessObjectService.save(lookupResults);
063 }
064
065 /**
066 * @see org.kuali.rice.krad.lookup.LookupResultsService#persistSelectedObjectIds(java.lang.String, java.util.Set, java.lang.String)
067 */
068 public void persistSelectedObjectIds(String lookupResultsSequenceNumber, Set<String> selectedObjectIds, String personId) throws Exception {
069 SelectedObjectIds selectedObjectIdsBO = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
070 if (selectedObjectIdsBO == null) {
071 selectedObjectIdsBO = new SelectedObjectIds();
072 selectedObjectIdsBO.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
073 }
074 selectedObjectIdsBO.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
075 selectedObjectIdsBO.setLookupPersonId(personId);
076 selectedObjectIdsBO.setSelectedObjectIds(
077 LookupUtils.convertSetOfObjectIdsToString(selectedObjectIds));
078 selectedObjectIdsBO.setLookupDate(CoreApiServiceLocator.getDateTimeService().getCurrentTimestamp());
079 businessObjectService.save(selectedObjectIdsBO);
080 }
081
082 /**
083 * Retrieves the LookupResults BO with the given sequence number. Does not check authentication.
084 * @param lookupResultsSequenceNumber
085 * @return
086 * @throws Exception
087 */
088 protected LookupResults retrieveLookupResults(String lookupResultsSequenceNumber) throws Exception {
089 Map<String, String> queryCriteria = new HashMap<String, String>();
090 queryCriteria.put(KRADConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER, lookupResultsSequenceNumber);
091 LookupResults lookupResults = (LookupResults) businessObjectService.findByPrimaryKey(LookupResults.class, queryCriteria);
092
093 return lookupResults;
094 }
095
096 /**
097 * Retrieves the SelectedObjectIds BO with the given sequence number. Does not check authentication.
098 * @param lookupResultsSequenceNumber
099 * @return
100 * @throws Exception
101 */
102 protected SelectedObjectIds retrieveSelectedObjectIds(String lookupResultsSequenceNumber) throws Exception {
103 Map<String, String> queryCriteria = new HashMap<String, String>();
104 queryCriteria.put(KRADConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER, lookupResultsSequenceNumber);
105 SelectedObjectIds selectedObjectIds = (SelectedObjectIds) businessObjectService.findByPrimaryKey(SelectedObjectIds.class, queryCriteria);
106
107 return selectedObjectIds;
108 }
109
110 /**
111 * @see org.kuali.rice.krad.lookup.LookupResultsService#isAuthorizedToAccessLookupResults(java.lang.String, java.lang.String)
112 */
113 public boolean isAuthorizedToAccessLookupResults(String lookupResultsSequenceNumber, String personId) {
114 try {
115 LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
116 return isAuthorizedToAccessLookupResults(lookupResults, personId);
117 }
118 catch (Exception e) {
119 return false;
120 }
121 }
122
123 /**
124 * Returns whether the user ID parameter is allowed to view the results.
125 *
126 * @param lookupResults
127 * @param personId
128 * @return
129 */
130 protected boolean isAuthorizedToAccessLookupResults(LookupResults lookupResults, String personId) {
131 return isAuthorizedToAccessMultipleValueLookupMetadata(lookupResults, personId);
132 }
133
134 /**
135 * @see org.kuali.rice.krad.lookup.LookupResultsService#isAuthorizedToAccessSelectedObjectIds(java.lang.String, java.lang.String)
136 */
137 public boolean isAuthorizedToAccessSelectedObjectIds(String lookupResultsSequenceNumber, String personId) {
138 try {
139 SelectedObjectIds selectedObjectIds = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
140 return isAuthorizedToAccessSelectedObjectIds(selectedObjectIds, personId);
141 }
142 catch (Exception e) {
143 return false;
144 }
145 }
146
147 /**
148 * Returns whether the user ID parameter is allowed to view the selected object IDs
149 *
150 * @param selectedObjectIds
151 * @param personId
152 * @return
153 */
154 protected boolean isAuthorizedToAccessSelectedObjectIds(SelectedObjectIds selectedObjectIds, String personId) {
155 return isAuthorizedToAccessMultipleValueLookupMetadata(selectedObjectIds, personId);
156 }
157
158
159 /**
160 * @see org.kuali.rice.krad.lookup.LookupResultsService#retrieveResultsTable(java.lang.String, java.lang.String)
161 */
162 public List<ResultRow> retrieveResultsTable(String lookupResultsSequenceNumber, String personId) throws Exception {
163 LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
164 if (!isAuthorizedToAccessLookupResults(lookupResults, personId)) {
165 // TODO: use the other identifier
166 throw new AuthorizationException(personId, "retrieve lookup results", "lookup sequence number " + lookupResultsSequenceNumber);
167 }
168 List<ResultRow> resultTable = (List<ResultRow>) ObjectUtils.fromByteArray(Base64.decodeBase64(lookupResults.getSerializedLookupResults().getBytes()));
169 return resultTable;
170 }
171
172 /**
173 * 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.
174 *
175 * @see org.kuali.rice.krad.lookup.LookupResultsService#retrieveSelectedResultBOs(java.lang.String, java.lang.Class, java.lang.String)
176 */
177 public <T extends BusinessObject> Collection<T> retrieveSelectedResultBOs(String lookupResultsSequenceNumber, Class<T> boClass, String personId) throws Exception {
178 final LookupResultsSupportStrategyService supportService = getQualifingSupportStrategy(boClass);
179 if (supportService == null) {
180 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");
181 }
182
183 SelectedObjectIds selectedObjectIds = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
184
185 if (!isAuthorizedToAccessSelectedObjectIds(selectedObjectIds, personId)) {
186 // TODO: use the other identifier
187 throw new AuthorizationException(personId, "retrieve lookup results", "lookup sequence number " + lookupResultsSequenceNumber);
188 }
189
190 Set<String> setOfSelectedObjIds = LookupUtils
191 .convertStringOfObjectIdsToSet(selectedObjectIds.getSelectedObjectIds());
192
193 if (setOfSelectedObjIds.isEmpty()) {
194 // OJB throws exception if querying on empty set
195 return new ArrayList<T>();
196 }
197
198 return supportService.retrieveSelectedResultBOs(boClass, setOfSelectedObjIds);
199 }
200
201 /**
202 * Given the business object class, determines the best qualifying LookupResultsSupportStrategyService to use
203 *
204 * @param boClass a business object class
205 * @return an LookupResultsSupportStrategyService implementation, or null if no qualifying strategies could be found
206 */
207 protected LookupResultsSupportStrategyService getQualifingSupportStrategy(Class boClass) {
208 if (getPersistableBusinessObjectSupportStrategy().qualifiesForStrategy(boClass)) {
209 return getPersistableBusinessObjectSupportStrategy();
210 } else if (getDataDictionarySupportStrategy().qualifiesForStrategy(boClass)) {
211 return getDataDictionarySupportStrategy();
212 }
213 return null;
214 }
215
216 /**
217 * @see org.kuali.rice.krad.lookup.LookupResultsService#clearPersistedLookupResults(java.lang.String)
218 */
219 public void clearPersistedLookupResults(String lookupResultsSequenceNumber) throws Exception {
220 LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber);
221 if (lookupResults != null) {
222 businessObjectService.delete(lookupResults);
223 }
224 }
225
226 /**
227 * @see org.kuali.rice.krad.lookup.LookupResultsService#clearPersistedSelectedObjectIds(java.lang.String)
228 */
229 public void clearPersistedSelectedObjectIds(String lookupResultsSequenceNumber) throws Exception {
230 SelectedObjectIds selectedObjectIds = retrieveSelectedObjectIds(lookupResultsSequenceNumber);
231 if (selectedObjectIds != null) {
232 businessObjectService.delete(selectedObjectIds);
233 }
234 }
235
236 /**
237 * Figures out which LookupResultsServiceSupportStrategy to defer to, and uses that to get the lookup id
238 * @see org.kuali.rice.krad.lookup.LookupResultsService#getLookupId(org.kuali.rice.krad.bo.BusinessObject)
239 */
240 public String getLookupId(BusinessObject businessObject) {
241 final LookupResultsSupportStrategyService supportService = getQualifingSupportStrategy(businessObject.getClass());
242 if (supportService == null) {
243 return null; // this may happen quite often, so let's just return null - no exception here
244 }
245 return supportService.getLookupIdForBusinessObject(businessObject);
246 }
247
248 public BusinessObjectService getBusinessObjectService() {
249 return businessObjectService;
250 }
251
252 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
253 this.businessObjectService = businessObjectService;
254 }
255
256 /**
257 * Determines whether the passed in user ID is allowed to view the lookup metadata (object IDs or results table)
258 * @param mvlm
259 * @param personId
260 * @return
261 */
262 protected boolean isAuthorizedToAccessMultipleValueLookupMetadata(MultipleValueLookupMetadata mvlm, String personId) {
263 return personId.equals(mvlm.getLookupPersonId());
264 }
265
266
267 public void deleteOldLookupResults(Timestamp expirationDate) {
268 persistedLookupMetadataDao.deleteOldLookupResults(expirationDate);
269
270 }
271
272 public void deleteOldSelectedObjectIds(Timestamp expirationDate) {
273 persistedLookupMetadataDao.deleteOldSelectedObjectIds(expirationDate);
274 }
275
276 public PersistedLookupMetadataDao getPersistedLookupMetadataDao() {
277 return persistedLookupMetadataDao;
278 }
279
280 public void setPersistedLookupMetadataDao(PersistedLookupMetadataDao persistedLookupMetadataDao) {
281 this.persistedLookupMetadataDao = persistedLookupMetadataDao;
282 }
283
284 /**
285 * @return the persistableBusinessObjectSupportStrategy
286 */
287 public LookupResultsSupportStrategyService getPersistableBusinessObjectSupportStrategy() {
288 return this.persistableBusinessObjectSupportStrategy;
289 }
290
291 /**
292 * @return the dataDictionarySupportStrategy
293 */
294 public LookupResultsSupportStrategyService getDataDictionarySupportStrategy() {
295 return this.dataDictionarySupportStrategy;
296 }
297
298 /**
299 * @param persistableBusinessObjectSupportStrategy the persistableBusinessObjectSupportStrategy to set
300 */
301 public void setPersistableBusinessObjectSupportStrategy(
302 LookupResultsSupportStrategyService persistableBusinessObjectSupportStrategy) {
303 this.persistableBusinessObjectSupportStrategy = persistableBusinessObjectSupportStrategy;
304 }
305
306 /**
307 * @param dataDictionarySupportStrategy the dataDictionarySupportStrategy to set
308 */
309 public void setDataDictionarySupportStrategy(
310 LookupResultsSupportStrategyService dataDictionarySupportStrategy) {
311 this.dataDictionarySupportStrategy = dataDictionarySupportStrategy;
312 }
313
314 }
315