001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.kns.lookup; 017 018import org.apache.commons.codec.binary.Base64; 019import org.kuali.rice.core.api.CoreApiServiceLocator; 020import org.kuali.rice.kns.web.ui.ResultRow; 021import org.kuali.rice.krad.bo.BusinessObject; 022import org.kuali.rice.krad.dao.PersistedLookupMetadataDao; 023import org.kuali.rice.krad.exception.AuthorizationException; 024import org.kuali.rice.krad.service.BusinessObjectService; 025import org.kuali.rice.krad.util.KRADConstants; 026import org.kuali.rice.krad.util.ObjectUtils; 027 028import java.sql.Timestamp; 029import java.util.ArrayList; 030import java.util.Collection; 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; 034import java.util.Set; 035 036public class LookupResultsServiceImpl implements LookupResultsService { 037 private BusinessObjectService businessObjectService; 038 private PersistedLookupMetadataDao persistedLookupMetadataDao; 039 private LookupResultsSupportStrategyService persistableBusinessObjectSupportStrategy; 040 private LookupResultsSupportStrategyService dataDictionarySupportStrategy; 041 042 /** 043 * @see org.kuali.rice.krad.lookup.LookupResultsService#persistResultsTable(java.lang.String, java.util.List, java.lang.String) 044 */ 045 public void persistResultsTable(String lookupResultsSequenceNumber, List<ResultRow> resultTable, String personId) throws Exception { 046 String resultTableString = new String(Base64.encodeBase64(ObjectUtils.toByteArray(resultTable))); 047 048 Timestamp now = CoreApiServiceLocator.getDateTimeService().getCurrentTimestamp(); 049 050 LookupResults lookupResults = retrieveLookupResults(lookupResultsSequenceNumber); 051 if (lookupResults == null) { 052 lookupResults = new LookupResults(); 053 lookupResults.setLookupResultsSequenceNumber(lookupResultsSequenceNumber); 054 } 055 lookupResults.setLookupResultsSequenceNumber(lookupResultsSequenceNumber); 056 lookupResults.setLookupPersonId(personId); 057 lookupResults.setSerializedLookupResults(resultTableString); 058 lookupResults.setLookupDate(now); 059 businessObjectService.save(lookupResults); 060 } 061 062 /** 063 * @see org.kuali.rice.krad.lookup.LookupResultsService#persistSelectedObjectIds(java.lang.String, java.util.Set, java.lang.String) 064 */ 065 public void persistSelectedObjectIds(String lookupResultsSequenceNumber, Set<String> selectedObjectIds, String personId) throws Exception { 066 SelectedObjectIds selectedObjectIdsBO = retrieveSelectedObjectIds(lookupResultsSequenceNumber); 067 if (selectedObjectIdsBO == null) { 068 selectedObjectIdsBO = new SelectedObjectIds(); 069 selectedObjectIdsBO.setLookupResultsSequenceNumber(lookupResultsSequenceNumber); 070 } 071 selectedObjectIdsBO.setLookupResultsSequenceNumber(lookupResultsSequenceNumber); 072 selectedObjectIdsBO.setLookupPersonId(personId); 073 selectedObjectIdsBO.setSelectedObjectIds( 074 LookupUtils.convertSetOfObjectIdsToString(selectedObjectIds)); 075 selectedObjectIdsBO.setLookupDate(CoreApiServiceLocator.getDateTimeService().getCurrentTimestamp()); 076 businessObjectService.save(selectedObjectIdsBO); 077 } 078 079 /** 080 * Retrieves the LookupResults BO with the given sequence number. Does not check authentication. 081 * @param lookupResultsSequenceNumber 082 * @return 083 * @throws Exception 084 */ 085 protected LookupResults retrieveLookupResults(String lookupResultsSequenceNumber) throws Exception { 086 Map<String, String> queryCriteria = new HashMap<String, String>(); 087 queryCriteria.put(KRADConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER, lookupResultsSequenceNumber); 088 LookupResults lookupResults = (LookupResults) businessObjectService.findByPrimaryKey(LookupResults.class, queryCriteria); 089 090 return lookupResults; 091 } 092 093 /** 094 * Retrieves the SelectedObjectIds BO with the given sequence number. Does not check authentication. 095 * @param lookupResultsSequenceNumber 096 * @return 097 * @throws Exception 098 */ 099 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