View Javadoc

1   /*
2    * Copyright 2013 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 1.0 (the
5    * "License"); you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl1.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package org.kuali.student.enrollment.class2.courseoffering.service.search;
17  
18  import org.kuali.student.enrollment.class1.lui.dao.LuiLuiRelationDao;
19  import org.kuali.student.enrollment.class2.courseoffering.model.ActivityOfferingClusterEntity;
20  import org.kuali.student.enrollment.class2.courseoffering.model.ActivityOfferingSetEntity;
21  import org.kuali.student.r2.common.dto.ContextInfo;
22  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
23  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
24  import org.kuali.student.r2.common.exceptions.MissingParameterException;
25  import org.kuali.student.r2.common.exceptions.OperationFailedException;
26  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
27  import org.kuali.student.r2.common.util.RichTextHelper;
28  import org.kuali.student.r2.common.util.constants.CourseOfferingServiceConstants;
29  import org.kuali.student.r2.common.util.constants.LuiServiceConstants;
30  import org.kuali.student.r2.common.util.date.DateFormatters;
31  import org.kuali.student.r2.core.class1.type.dto.TypeInfo;
32  import org.kuali.student.r2.core.search.dto.SearchParamInfo;
33  import org.kuali.student.r2.core.search.dto.SearchRequestInfo;
34  import org.kuali.student.r2.core.search.dto.SearchResultCellInfo;
35  import org.kuali.student.r2.core.search.dto.SearchResultInfo;
36  import org.kuali.student.r2.core.search.dto.SearchResultRowInfo;
37  import org.kuali.student.r2.core.search.dto.SortDirection;
38  import org.kuali.student.r2.core.search.service.SearchService;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  import javax.annotation.Resource;
43  import javax.jws.WebParam;
44  import javax.persistence.EntityManager;
45  import javax.persistence.Query;
46  import javax.persistence.TypedQuery;
47  import java.util.ArrayList;
48  import java.util.Arrays;
49  import java.util.HashSet;
50  import java.util.List;
51  import java.util.Set;
52  
53  
54  /**
55   *
56   * @author Kuali Student Team 
57   *
58   */
59  public class CourseOfferingServiceAutogenCountSearchServiceImpl implements SearchService {
60      private static final Logger log = LoggerFactory
61              .getLogger(CourseOfferingServiceAutogenCountSearchServiceImpl.class);
62  
63      @Resource
64      private EntityManager entityManager;
65      
66      private LuiLuiRelationDao luiLuiRelationDao;
67      
68      /**
69       * 
70       */
71      public CourseOfferingServiceAutogenCountSearchServiceImpl() {
72          // TODO Auto-generated constructor stub
73      }
74  
75      /**
76       *
77       * @param typeKey
78       * @param typeName
79       * @param effectiveDate
80       * @return
81       */
82      private static TypeInfo initializeTypeInfo (String typeKey, String typeName, String effectiveDate) {
83          TypeInfo info = new TypeInfo();
84          info.setKey(typeKey);
85          info.setName(typeName);
86          info.setDescr(new RichTextHelper().fromPlain(typeName));
87  
88          try {
89              info.setEffectiveDate(DateFormatters.MONTH_DAY_YEAR_DATE_FORMATTER.parse(effectiveDate));
90          } catch (IllegalArgumentException ex) {
91              throw new RuntimeException("parsing["+ effectiveDate +"] is not possible", ex);
92          } catch (UnsupportedOperationException ex){
93              throw new RuntimeException("parsing["+ effectiveDate +"] is not supported", ex);
94          }
95  
96          return info;
97      }
98      
99      /*
100      * TODO: turn these into real types and use the TypeService to resolve them.
101      */
102     private static TypeInfo BY_CO_TYPE = initializeTypeInfo(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_CO, "Autogen Counts by CO", "02/28/2013");
103     private static TypeInfo BY_FO_TYPE = initializeTypeInfo(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_FO, "Autogen Counts by FO", "02/28/2013");
104     private static TypeInfo BY_AOC_TYPE =  initializeTypeInfo(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_AOC, "Autogen Counts by AOC", "02/28/2013");
105     
106     /* (non-Javadoc)
107      * @see org.kuali.student.r2.core.search.service.SearchService#getSearchTypes(org.kuali.student.r2.common.dto.ContextInfo)
108      */
109     @Override
110     public List<TypeInfo> getSearchTypes(
111             @WebParam(name = "contextInfo") ContextInfo contextInfo)
112             throws InvalidParameterException, MissingParameterException,
113             OperationFailedException {
114         return Arrays.asList(new TypeInfo[] {BY_CO_TYPE, BY_FO_TYPE, BY_AOC_TYPE});
115     }
116 
117     /* (non-Javadoc)
118      * @see org.kuali.student.r2.core.search.service.SearchService#getSearchType(java.lang.String, org.kuali.student.r2.common.dto.ContextInfo)
119      */
120     @Override
121     public TypeInfo getSearchType(
122             @WebParam(name = "searchTypeKey") String searchTypeKey,
123             @WebParam(name = "contextInfo") ContextInfo contextInfo)
124             throws DoesNotExistException, InvalidParameterException,
125             MissingParameterException, OperationFailedException {
126         
127         if (searchTypeKey.equals(BY_CO_TYPE.getKey()))
128                 return new TypeInfo(BY_CO_TYPE);
129         else if (searchTypeKey.equals(BY_FO_TYPE.getKey()))
130             return new TypeInfo(BY_FO_TYPE);
131         else if (searchTypeKey.equals(BY_AOC_TYPE.getKey()))
132             return new TypeInfo(BY_AOC_TYPE);
133         else
134             throw new DoesNotExistException(String.format ("No key of type %s", searchTypeKey));
135     }
136 
137     /*
138      * Extract the expected parameter from the search request throwing errors if there is not one value for the expected key.
139      */
140     private String extractSearchParameter (String expectedParameterName, SearchRequestInfo searchRequestInfo) throws MissingParameterException, InvalidParameterException {
141         if (searchRequestInfo.getParams().size() != 1)
142             throw new MissingParameterException("Missing Search Parameter for what to search for");
143         
144         SearchParamInfo p = searchRequestInfo.getParams().get(0);
145         
146         if (!p.getKey().equals(expectedParameterName))
147             throw new InvalidParameterException(String.format("Expected parameter of name(%s) but was (%s)", expectedParameterName, p.getKey()));
148         
149         int numberOfValues = p.getValues().size();
150         
151         if (numberOfValues != 1)
152             throw new InvalidParameterException(String.format("Expected one parameter value for key(%s) not %d values", expectedParameterName, numberOfValues));
153         
154         return p.getValues().get(0);
155         
156     }
157     /* (non-Javadoc)
158      * @see org.kuali.student.r2.core.search.service.SearchService#search(org.kuali.student.r2.core.search.dto.SearchRequestInfo, org.kuali.student.r2.common.dto.ContextInfo)
159      */
160     @Override
161     public SearchResultInfo search(SearchRequestInfo searchRequestInfo,
162             @WebParam(name = "contextInfo") ContextInfo contextInfo)
163             throws MissingParameterException, InvalidParameterException,
164             OperationFailedException, PermissionDeniedException {
165         
166         String searchKey = searchRequestInfo.getSearchKey();
167         
168         if (searchKey.equals(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_CO)) {
169             String searchParameter = extractSearchParameter(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_CO_ID_PARAM, searchRequestInfo);
170             return searchAutogenCountsByCO(searchParameter, contextInfo);
171         }
172         else if (searchKey.equals(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_FO)) {
173             
174             String searchParameter = extractSearchParameter(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_FO_ID_PARAM, searchRequestInfo);
175             return searchAutogenCountsByFO(searchParameter, contextInfo);
176         }
177         if (searchKey.equals(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_AOC)) {
178             String searchParameter = extractSearchParameter(CourseOfferingServiceConstants.AUTOGEN_COUNTS_BY_AOC_ID_PARAM, searchRequestInfo);
179             return searchAutogenCountsByAOC(searchParameter, contextInfo);
180         }
181         else {
182             SearchResultInfo results = new SearchResultInfo();
183             results.setRows(new ArrayList<SearchResultRowInfo>());
184             results.setStartAt(0);
185             results.setTotalResults(0);
186             return results;
187         
188     }
189     
190     
191 }
192 
193     /*
194      * Find the number of AO's and RG's defined in a specified AOC.
195      */
196     private SearchResultInfo searchAutogenCountsByAOC(String activityOfferingClusterId,
197             ContextInfo contextInfo) {
198         
199         List<SearchResultCellInfo> cellData = new ArrayList<SearchResultCellInfo>();
200         
201         TypedQuery<ActivityOfferingClusterEntity> q = entityManager.createNamedQuery("ActivityOfferingClusterENR.getAOCsByIds", ActivityOfferingClusterEntity.class);
202         
203         q.setParameter("aocIds", Arrays.asList(new String[] {activityOfferingClusterId}));
204         
205         List<ActivityOfferingClusterEntity>aocs = q.getResultList();
206         
207         if (aocs.size() == 0) {
208             // doesn't match so return zero's
209           SearchResultInfo results = new SearchResultInfo();
210           results.setRows(new ArrayList<SearchResultRowInfo>());
211           results.setStartAt(0);
212           results.setTotalResults(0);
213           return results;
214         }
215         
216         loadDataFromAoc (aocs, cellData);
217         
218         SearchResultInfo results = new SearchResultInfo();
219         
220         SearchResultRowInfo data = new SearchResultRowInfo();
221        
222         data.setCells(cellData);
223         
224         results.setRows(Arrays.asList(new SearchResultRowInfo [] {data}));
225         results.setStartAt(0);
226         results.setTotalResults(1);
227         results.setSortDirection(SortDirection.DESC);
228         
229         return results;
230     }
231 
232     /*
233      * Load the count of AO's and Reg Groups from the list of AOC's passed in
234      */
235     private void loadDataFromAoc(List<ActivityOfferingClusterEntity> aocs,
236             List<SearchResultCellInfo> cellData) {
237         
238         cellData.add(new SearchResultCellInfo(CourseOfferingServiceConstants.AUTOGEN_COUNTS_TOTAL_AOCS, String.valueOf(aocs.size())));
239         
240         Set<String>aoIds = new HashSet<String>();
241         
242         /*
243          * Accumulate AO's in all of the AOC's
244          */
245         for (ActivityOfferingClusterEntity clusterEntity : aocs) {
246 
247             Set<ActivityOfferingSetEntity> aoSets = clusterEntity.getAoSets();
248 
249             for (ActivityOfferingSetEntity activityOfferingSetEntity : aoSets) {
250                 // accumulate ao ids.
251                 aoIds.addAll(activityOfferingSetEntity.getAoIds());
252             }
253 
254         }
255 
256         // count ao's in the identified aoc's
257         cellData.add(new SearchResultCellInfo(CourseOfferingServiceConstants.AUTOGEN_COUNTS_TOTAL_AOS, String.valueOf(aoIds.size())));
258         
259         // load all of the reg groups in all of these ao's
260        loadRegGroupCounts (aoIds, cellData);
261     }
262 
263     /*
264      * Find the total reg groups for the AO's given and then the subset that are invalid and record the counts into the cellData list provided.
265      */
266     private void loadRegGroupCounts(Set<String> aoIds,
267             List<SearchResultCellInfo> cellData) {
268        
269         // special bulk query to load all of the rg id's and state key for the ao id's given.
270         Query q = entityManager.createNamedQuery("LuiLuiRelationENR.getLuiIdsAndStateByRelatedLuisAndRelationType");
271 
272         q.setParameter("luiIds", aoIds);
273         q.setParameter("luiLuiRelationTypeKey", LuiServiceConstants.LUI_LUI_RELATION_REGISTERED_FOR_VIA_RG_TO_AO_TYPE_KEY);
274         
275         List<Object[]> rgData =  (List<Object[]>)q.getResultList();
276         
277         cellData.add(new SearchResultCellInfo(CourseOfferingServiceConstants.AUTOGEN_COUNTS_TOTAL_RGS, String.valueOf (rgData.size())));
278         
279         int invalidRegGroups = 0;
280         
281         for (Object[] row : rgData) {
282             String rgId = (String)row[0];
283             String stateKey = (String)row[1];
284             
285             if (stateKey.equals(LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY)) {
286                 invalidRegGroups++;
287             }
288         }
289         
290         cellData.add(new SearchResultCellInfo(CourseOfferingServiceConstants.AUTOGEN_COUNTS_TOTAL_INVALID_RGS, String.valueOf (invalidRegGroups)));
291         
292     }
293 
294     private SearchResultInfo searchAutogenCountsByFO(String formatOfferingId,
295             ContextInfo contextInfo) {
296         
297         TypedQuery<ActivityOfferingClusterEntity> q = entityManager.createNamedQuery("ActivityOfferingClusterENR.getAOCsByFormatOfferingIds", ActivityOfferingClusterEntity.class);
298         
299         q.setParameter("foIds", Arrays.asList(new String[] {formatOfferingId}));
300         
301         List<ActivityOfferingClusterEntity> aocs = q.getResultList();
302         
303         if (aocs.size() == 0) {
304             // doesn't match so return zero's
305           SearchResultInfo results = new SearchResultInfo();
306           results.setRows(new ArrayList<SearchResultRowInfo>());
307           results.setStartAt(0);
308           results.setTotalResults(0);
309           return results;
310         }
311         
312         List<SearchResultCellInfo> cellData = new ArrayList<SearchResultCellInfo>();
313         
314         loadDataFromAoc (aocs, cellData);
315         
316         SearchResultInfo results = new SearchResultInfo();
317         
318         SearchResultRowInfo data = new SearchResultRowInfo();
319        
320         data.setCells(cellData);
321         
322         results.setRows(Arrays.asList(new SearchResultRowInfo [] {data}));
323         results.setStartAt(0);
324         results.setTotalResults(1);
325         results.setSortDirection(SortDirection.DESC);
326         
327         return results;
328     }
329 
330     private SearchResultInfo searchAutogenCountsByCO(String courseOfferingId,
331             ContextInfo contextInfo) {
332         
333         // first get the list of format ids for this course offering
334         
335         Query queryFormatOfferingIds = entityManager.createNamedQuery("LuiLuiRelationENR.getRelatedLuiIdsByLuiIdAndRelationType");
336 
337         queryFormatOfferingIds.setParameter("luiId", courseOfferingId);
338         
339         queryFormatOfferingIds.setParameter("luiLuiRelationTypeKey", LuiServiceConstants.LUI_LUI_RELATION_DELIVERED_VIA_CO_TO_FO_TYPE_KEY);
340         
341         List<String> formatOfferingIds = queryFormatOfferingIds.getResultList();
342         
343         TypedQuery<ActivityOfferingClusterEntity> queryAOCs = entityManager.createNamedQuery("ActivityOfferingClusterENR.getAOCsByFormatOfferingIds", ActivityOfferingClusterEntity.class);
344         
345         queryAOCs.setParameter("foIds", formatOfferingIds);
346         
347         List<ActivityOfferingClusterEntity> aocs = queryAOCs.getResultList();
348         
349         if (aocs.size() == 0) {
350             // doesn't match so return zero's
351           SearchResultInfo results = new SearchResultInfo();
352           results.setRows(new ArrayList<SearchResultRowInfo>());
353           results.setStartAt(0);
354           results.setTotalResults(0);
355           return results;
356         }
357         
358         List<SearchResultCellInfo> cellData = new ArrayList<SearchResultCellInfo>();
359         
360         loadDataFromAoc (aocs, cellData);
361         
362         SearchResultInfo results = new SearchResultInfo();
363         
364         SearchResultRowInfo data = new SearchResultRowInfo();
365        
366         data.setCells(cellData);
367         
368         results.setRows(Arrays.asList(new SearchResultRowInfo [] {data}));
369         results.setStartAt(0);
370         results.setTotalResults(1);
371         results.setSortDirection(SortDirection.DESC);
372         
373         return results;
374     }
375     
376 }