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