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