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.krad.service.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.datetime.DateTimeService;
020import org.kuali.rice.krad.bo.BusinessObject;
021import org.kuali.rice.krad.bo.InactivatableFromTo;
022import org.kuali.rice.krad.service.DataDictionaryService;
023import org.kuali.rice.krad.service.InactivateableFromToService;
024import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
025import org.kuali.rice.krad.service.LookupService;
026import org.kuali.rice.krad.util.BeanPropertyComparator;
027import org.kuali.rice.krad.util.KRADPropertyConstants;
028import org.kuali.rice.krad.util.ObjectUtils;
029
030import java.util.ArrayList;
031import java.util.Collections;
032import java.util.Date;
033import java.util.List;
034import java.util.Map;
035
036/**
037 * Implementation of InactivateableFromToService that uses the lookup service for query implementation
038 * 
039 * @see org.kuali.rice.krad.service.InactivateableFromToService
040 */
041public class InactivateableFromToServiceImpl implements InactivateableFromToService {
042
043        protected DateTimeService dateTimeService;
044        protected LookupService lookupService;
045    protected DataDictionaryService dataDictionaryService;
046
047        /**
048         * Uses lookup service which will convert the active criteria to active begin/to field criteria
049         * 
050         * @see org.kuali.rice.krad.service.InactivateableFromToService#findMatchingActive(java.lang.Class, java.util.Map)
051         */
052        public List<InactivatableFromTo> findMatchingActive(Class<? extends InactivatableFromTo> clazz, Map fieldValues) {
053                fieldValues.put(KRADPropertyConstants.ACTIVE, "true");
054
055                return (List<InactivatableFromTo>) lookupService.findCollectionBySearchUnbounded(clazz, fieldValues);
056        }
057
058        /**
059         * Uses lookup service which will convert the active criteria to active begin/to field criteria
060         * 
061         * @see org.kuali.rice.krad.service.InactivateableFromToService#findMatchingActiveAsOfDate(java.lang.Class, java.util.Map,
062         *      java.util.Date)
063         */
064        public List<InactivatableFromTo> findMatchingActiveAsOfDate(Class<? extends InactivatableFromTo> clazz,
065                        Map fieldValues, Date activeAsOfDate) {
066                fieldValues.put(KRADPropertyConstants.ACTIVE, "true");
067                fieldValues.put(KRADPropertyConstants.ACTIVE_AS_OF_DATE, dateTimeService.toDateString(activeAsOfDate));
068
069                return (List<InactivatableFromTo>) lookupService.findCollectionBySearchUnbounded(clazz, fieldValues);
070        }
071
072        /**
073         * @see org.kuali.rice.krad.service.InactivateableFromToService#filterOutNonActive(java.util.List)
074         */
075        public List<InactivatableFromTo> filterOutNonActive(List<InactivatableFromTo> filterList) {
076                return filterOutNonActive(filterList, dateTimeService.getCurrentDate());
077        }
078
079        /**
080         * @see org.kuali.rice.krad.service.InactivateableFromToService#filterOutNonActive(java.util.List, java.util.Date)
081         */
082        public List<InactivatableFromTo> filterOutNonActive(List<InactivatableFromTo> filterList, Date activeAsOfDate) {
083                List<InactivatableFromTo> filteredList = new ArrayList<InactivatableFromTo>();
084
085                for (InactivatableFromTo inactivateable : filterList) {
086                        inactivateable.setActiveAsOfDate(new java.sql.Timestamp(activeAsOfDate.getTime()));
087                        if (inactivateable.isActive()) {
088                                filteredList.add(inactivateable);
089                        }
090                }
091
092                return filteredList;
093        }
094
095        /**
096         * Uses lookup service which will convert the active and current criteria to active begin/to field criteria
097         * 
098         * @see org.kuali.rice.krad.service.InactivateableFromToService#findMatchingCurrent(java.lang.Class, java.util.Map)
099         */
100        public List<InactivatableFromTo> findMatchingCurrent(Class<? extends InactivatableFromTo> clazz,
101                        Map fieldValues) {
102                fieldValues.put(KRADPropertyConstants.ACTIVE, "true");
103                fieldValues.put(KRADPropertyConstants.CURRENT, "true");
104
105                return (List<InactivatableFromTo>) lookupService.findCollectionBySearchUnbounded(clazz, fieldValues);
106        }
107
108        /**
109         * Uses lookup service which will convert the active and current criteria to active begin/to field criteria
110         * 
111         * @see org.kuali.rice.krad.service.InactivateableFromToService#findMatchingCurrent(java.lang.Class, java.util.Map, java.util.Date)
112         */
113        public List<InactivatableFromTo> findMatchingCurrent(Class<? extends InactivatableFromTo> clazz,
114                        Map fieldValues, Date currentAsOfDate) {
115                fieldValues.put(KRADPropertyConstants.ACTIVE, "true");
116                fieldValues.put(KRADPropertyConstants.CURRENT, "true");
117                fieldValues.put(KRADPropertyConstants.ACTIVE_AS_OF_DATE, dateTimeService.toDateString(currentAsOfDate));
118
119                return (List<InactivatableFromTo>) lookupService.findCollectionBySearchUnbounded(clazz, fieldValues);
120        }
121
122        /**
123         * @see org.kuali.rice.krad.service.InactivateableFromToService#filterOutNonCurrent(java.util.List)
124         */
125        public List<InactivatableFromTo> filterOutNonCurrent(List<InactivatableFromTo> filterList) {
126                return filterOutNonCurrent(filterList, dateTimeService.getCurrentDate());
127        }
128
129        /**
130         * @see org.kuali.rice.krad.service.InactivateableFromToService#filterOutNonCurrent(java.util.List, java.util.Date)
131         */
132        public List<InactivatableFromTo> filterOutNonCurrent(List<InactivatableFromTo> filterList, Date currentAsOfDate) {
133                List<InactivatableFromTo> activeList = filterOutNonActive(filterList, currentAsOfDate);
134
135                if (activeList.isEmpty()) {
136                        return activeList;
137                }
138
139                List<InactivatableFromTo> currentList = new ArrayList<InactivatableFromTo>();
140
141                List<String> groupByList = getDataDictionaryService().getGroupByAttributesForEffectiveDating(
142                activeList.get(0).getClass());
143                if (groupByList != null) {
144                        List<String> sortByList = new ArrayList<String>(groupByList);
145                        sortByList.add(KRADPropertyConstants.ACTIVE_FROM_DATE);
146
147                        // sort list so we get records together with same group by
148                        Collections.sort(activeList, new BeanPropertyComparator(sortByList, true));
149
150                        // reverse so we get max active begin date first within the group by
151                        Collections.reverse(activeList);
152
153                        String previousGroupByString = "";
154                        Date previousActiveFromDate = null;
155                        for (InactivatableFromTo inactivateable : activeList) {
156                                String groupByString = buildGroupByValueString((BusinessObject) inactivateable, groupByList);
157                                if (!StringUtils.equals(groupByString, previousGroupByString)) {
158                                        // always add first record of new group by since list is sorted by active begin date descending
159                                        currentList.add(inactivateable);
160                                }
161                                // active from date should not be null here since we are dealing with only active records
162                                else if (inactivateable.getActiveFromDate().equals(previousActiveFromDate)) {
163                                        // have more than one record for the group by key with same active begin date, so they both are current
164                                        currentList.add(inactivateable);
165                                }
166
167                                previousGroupByString = groupByString;
168                                previousActiveFromDate = inactivateable.getActiveFromDate();
169                        }
170                } else {
171                        currentList = activeList;
172                }
173
174                return currentList;
175        }
176
177        /**
178         * Builds a string containing the values from the given business object for the fields in the given list, concatenated together using a
179         * bar. Null values are treated as an empty string
180         * 
181         * @param businessObject
182         *            - business object instance to get values from
183         * @param groupByList
184         *            - list of fields to get values for
185         * @return String
186         */
187        protected String buildGroupByValueString(BusinessObject businessObject, List<String> groupByList) {
188                String groupByValueString = "";
189
190                for (String groupByField : groupByList) {
191                        Object fieldValue = ObjectUtils.getPropertyValue(businessObject, groupByField);
192                        groupByValueString += "|";
193                        if (fieldValue != null) {
194                                groupByValueString += fieldValue;
195                        }
196                }
197
198                return groupByValueString;
199        }
200
201        public void setDateTimeService(DateTimeService dateTimeService) {
202                this.dateTimeService = dateTimeService;
203        }
204
205        public void setLookupService(LookupService lookupService) {
206                this.lookupService = lookupService;
207        }
208
209    protected DataDictionaryService getDataDictionaryService() {
210        if (dataDictionaryService == null) {
211            this.dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
212        }
213        return dataDictionaryService;
214    }
215
216    public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
217        this.dataDictionaryService = dataDictionaryService;
218    }
219}