View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * 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/ecl2.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,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.impl.repository;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.criteria.QueryByCriteria;
20  import org.kuali.rice.core.api.criteria.QueryResults;
21  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
22  import org.kuali.rice.krad.data.DataObjectService;
23  import org.kuali.rice.krad.data.PersistenceOption;
24  import org.kuali.rice.krms.api.repository.term.TermDefinition;
25  import org.kuali.rice.krms.api.repository.term.TermResolverDefinition;
26  import org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition;
27  import org.kuali.rice.krms.impl.util.KrmsImplConstants;
28  import org.springframework.util.CollectionUtils;
29  
30  import java.util.ArrayList;
31  import java.util.Collections;
32  import java.util.HashMap;
33  import java.util.List;
34  import java.util.Map;
35  
36  import static org.kuali.rice.krms.impl.repository.BusinessObjectServiceMigrationUtils.findMatching;
37  import static org.kuali.rice.krms.impl.repository.BusinessObjectServiceMigrationUtils.findSingleMatching;
38  
39  /**
40   * Implementation of {@link TermBoService}
41   *
42   * @author Kuali Rice Team (rice.collab@kuali.org)
43   */
44  public class TermBoServiceImpl implements TermBoService {
45  
46      private DataObjectService dataObjectService;
47  
48      /**
49       * @param dataObjectService the dataObjectService to set
50       */
51      public void setDataObjectService(DataObjectService dataObjectService) {
52          this.dataObjectService = dataObjectService;
53      }
54  
55      /**
56       * @see org.kuali.rice.krms.impl.repository.TermBoService#getTermSpecificationById(java.lang.String)
57       */
58      @Override
59      public TermSpecificationDefinition getTermSpecificationById(String id) {
60          TermSpecificationDefinition result = null;
61  
62          if (StringUtils.isBlank(id)) {
63              throw new RiceIllegalArgumentException("id must not be blank or null");
64          }
65  
66          TermSpecificationBo termSpecificationBo = dataObjectService.find(TermSpecificationBo.class, id);
67  
68          if (termSpecificationBo != null) {
69              List<ContextValidTermBo> contextValidTermBos =
70                      findMatching(dataObjectService, ContextValidTermBo.class,
71                              Collections.singletonMap("termSpecification.id", termSpecificationBo.getId()));
72  
73              if (contextValidTermBos != null) for (ContextValidTermBo contextValidTerm : contextValidTermBos) {
74                  termSpecificationBo.getContextIds().add(contextValidTerm.getContextId());
75              }
76  
77              result = TermSpecificationDefinition.Builder.create(termSpecificationBo).build();
78          }
79  
80          return result;
81      }
82  
83      /**
84       * @see org.kuali.rice.krms.impl.repository.TermBoService#createTermSpecification(org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition)
85       */
86      @Override
87      public TermSpecificationDefinition createTermSpecification(TermSpecificationDefinition termSpec) {
88          if (!StringUtils.isBlank(termSpec.getId())) {
89              throw new RiceIllegalArgumentException("for creation, TermSpecification.id must be null");
90          }
91  
92          TermSpecificationBo termSpecBo = TermSpecificationBo.from(termSpec);
93  
94          // save relations to the contexts on the BO
95          if (!CollectionUtils.isEmpty(termSpec.getContextIds())) {
96              for (String contextId : termSpec.getContextIds()) {
97                  ContextValidTermBo contextValidTerm = new ContextValidTermBo();
98                  contextValidTerm.setContextId(contextId);
99                  contextValidTerm.setTermSpecification(termSpecBo);
100 
101                 termSpecBo.getContextValidTerms().add(contextValidTerm);
102             }
103         }
104 
105         termSpecBo = dataObjectService.save(termSpecBo, PersistenceOption.FLUSH);
106 
107         return TermSpecificationBo.to(termSpecBo);
108     }
109 
110     @Override
111     public void updateTermSpecification(TermSpecificationDefinition termSpec) throws RiceIllegalArgumentException {
112         if (termSpec == null) {
113             throw new IllegalArgumentException("term specification is null");
114         }
115 
116         // must already exist to be able to update
117         final String termSpecificationId = termSpec.getId();
118         final TermSpecificationBo existing = dataObjectService.find(TermSpecificationBo.class, termSpecificationId);
119 
120         if (existing == null) {
121             throw new IllegalStateException("the term specification does not exist: " + termSpec);
122         }
123 
124         final TermSpecificationDefinition toUpdate;
125 
126         if (!existing.getId().equals(termSpec.getId())) {
127             // if passed in id does not match existing id, correct it
128             final TermSpecificationDefinition.Builder builder = TermSpecificationDefinition.Builder.create(termSpec);
129             builder.setId(existing.getId());
130             toUpdate = builder.build();
131         } else {
132             toUpdate = termSpec;
133         }
134 
135         // copy all updateable fields to bo
136         TermSpecificationBo boToUpdate = TermSpecificationBo.from(toUpdate);
137         reconcileContextValidTerms(existing, boToUpdate);
138 
139         // update the rule and create new attributes
140         dataObjectService.save(boToUpdate, PersistenceOption.FLUSH);
141 
142     }
143 
144     /**
145      * Transfer any ContextValidTermBos that still apply from existing to boToUpdate, and create new ContextValidTermBos
146      * for any new context IDs that are found in boToUpdate.
147      *
148      * <p>This method is side effecting, it makes modifications to boToUpdate.contextValidTerms. </p>
149      *
150      * @param existing the TermSpecificationBo which has been fetched from the database
151      * @param boToUpdate the new TermSpecificationBo which will (later) be persisted
152      */
153     private void reconcileContextValidTerms(TermSpecificationBo existing,
154             TermSpecificationBo boToUpdate) {
155 
156         // add all contextValidTerms that still apply
157         for (ContextValidTermBo contextValidTerm : existing.getContextValidTerms()) {
158             if (boToUpdate.getContextIds().contains(contextValidTerm.getContextId())) {
159                 boToUpdate.getContextValidTerms().add(contextValidTerm);
160             }
161         }
162 
163         // add new contextValidTerms for new context IDs
164         for (String contextId : boToUpdate.getContextIds()) {
165             boolean alreadyInContextValidTerms = false;
166 
167             for (ContextValidTermBo contextValidTerm : boToUpdate.getContextValidTerms()) {
168                 if (contextId.equals(contextValidTerm.getContextId())) {
169                     alreadyInContextValidTerms = true;
170                     break;
171                 }
172             }
173 
174             if (!alreadyInContextValidTerms) {
175                 ContextValidTermBo contextValidTerm = new ContextValidTermBo();
176                 contextValidTerm.setContextId(contextId);
177                 contextValidTerm.setTermSpecification(boToUpdate);
178 
179                 boToUpdate.getContextValidTerms().add(contextValidTerm);
180             }
181         }
182     }
183 
184     @Override
185     public void deleteTermSpecification(String id) throws RiceIllegalArgumentException {
186         if (id == null) {
187             throw new RiceIllegalArgumentException("agendaId is null");
188         }
189 
190         final TermSpecificationBo existing = dataObjectService.find(TermSpecificationBo.class, id);
191 
192         if (existing == null) {
193             throw new IllegalStateException("the TermSpecification to delete does not exists: " + id);
194         }
195 
196         dataObjectService.delete(existing);
197     }
198 
199     /**
200      * @see org.kuali.rice.krms.impl.repository.TermBoService#createTerm(org.kuali.rice.krms.api.repository.term.TermDefinition)
201      */
202     @Override
203     public TermDefinition createTerm(TermDefinition termDef) {
204         if (!StringUtils.isBlank(termDef.getId())) {
205             throw new RiceIllegalArgumentException("for creation, TermDefinition.id must be null");
206         }
207 
208         TermBo termBo = TermBo.from(termDef);
209         termBo = dataObjectService.save(termBo, PersistenceOption.FLUSH);
210 
211         return TermBo.to(termBo);
212     }
213 
214     @Override
215     public void updateTerm(TermDefinition term) throws RiceIllegalArgumentException {
216         if (term == null) {
217             throw new IllegalArgumentException("term is null");
218         }
219 
220         // must already exist to be able to update
221         final String termId = term.getId();
222         final TermBo existing = dataObjectService.find(TermBo.class, termId);
223 
224         if (existing == null) {
225             throw new IllegalStateException("the term resolver does not exist: " + term);
226         }
227 
228         final TermDefinition toUpdate;
229 
230         if (!existing.getId().equals(term.getId())) {
231             // if passed in id does not match existing id, correct it
232             final TermDefinition.Builder builder = TermDefinition.Builder.create(term);
233             builder.setId(existing.getId());
234             toUpdate = builder.build();
235         } else {
236             toUpdate = term;
237         }
238 
239         // copy all updateable fields to bo
240         TermBo boToUpdate = TermBo.from(toUpdate);
241 
242         // update the rule and create new attributes
243         dataObjectService.save(boToUpdate, PersistenceOption.FLUSH);
244     }
245 
246     @Override
247     public void deleteTerm(String id) throws RiceIllegalArgumentException {
248         if (id == null) {
249             throw new RiceIllegalArgumentException("termId is null");
250         }
251 
252         TermBo existing = dataObjectService.find(TermBo.class, id);
253 
254         if (existing == null) {
255             throw new IllegalStateException("the term to delete does not exists: " + id);
256         }
257 
258         dataObjectService.delete(existing);
259     }
260 
261     /**
262      * @see org.kuali.rice.krms.impl.repository.TermBoService#createTermResolver(org.kuali.rice.krms.api.repository.term.TermResolverDefinition)
263      */
264     @Override
265     public TermResolverDefinition createTermResolver(TermResolverDefinition termResolver) {
266         if (!StringUtils.isBlank(termResolver.getId())) {
267             throw new RiceIllegalArgumentException("for creation, TermResolverDefinition.id must be null");
268         }
269 
270         TermResolverBo termResolverBo = TermResolverBo.from(termResolver);
271 
272         termResolverBo = (TermResolverBo) dataObjectService.save(termResolverBo, PersistenceOption.FLUSH);
273 
274         return TermResolverBo.to(termResolverBo);
275     }
276 
277     @Override
278     public void updateTermResolver(TermResolverDefinition termResolver) throws RiceIllegalArgumentException {
279         if (termResolver == null) {
280             throw new IllegalArgumentException("term resolver is null");
281         }
282 
283         // must already exist to be able to update
284         final String termResolverId = termResolver.getId();
285         final TermResolverBo existing = dataObjectService.find(TermResolverBo.class, termResolverId);
286 
287         if (existing == null) {
288             throw new IllegalStateException("the term resolver does not exist: " + termResolver);
289         }
290 
291         final TermResolverDefinition toUpdate;
292 
293         if (!existing.getId().equals(termResolver.getId())) {
294             // if passed in id does not match existing id, correct it
295             final TermResolverDefinition.Builder builder = TermResolverDefinition.Builder.create(termResolver);
296             builder.setId(existing.getId());
297             toUpdate = builder.build();
298         } else {
299             toUpdate = termResolver;
300         }
301 
302         // copy all updateable fields to bo
303         TermResolverBo boToUpdate = TermResolverBo.from(toUpdate);
304 
305         // delete any old, existing attributes
306         QueryByCriteria crit =
307                 QueryByCriteria.Builder.forAttribute(KrmsImplConstants.PropertyNames.TermResolver.TERM_RESOLVER_ID, toUpdate.getId()).build();
308 
309         dataObjectService.deleteMatching(TermResolverAttributeBo.class, crit);
310 
311         // update the rule and create new attributes
312         dataObjectService.save(boToUpdate, PersistenceOption.FLUSH);
313     }
314 
315     @Override
316     public void deleteTermResolver(String id) throws RiceIllegalArgumentException {
317         if (id == null) {
318             throw new RiceIllegalArgumentException("agendaId is null");
319         }
320 
321         TermSpecificationBo existing = dataObjectService.find(TermSpecificationBo.class, id);
322 
323         if (existing == null) {
324             throw new IllegalStateException("the TermResolver to delete does not exists: " + id);
325         }
326 
327         dataObjectService.delete(existing);
328     }
329 
330     /**
331      * @see org.kuali.rice.krms.impl.repository.TermBoService#getTerm(java.lang.String)
332      */
333     @Override
334     public TermDefinition getTerm(String id) {
335         TermDefinition result = null;
336 
337         if (StringUtils.isBlank(id)) {
338             throw new RiceIllegalArgumentException("id must not be blank or null");
339         }
340 
341         TermBo termBo = dataObjectService.find(TermBo.class, id);
342 
343         if (termBo != null) {
344             result = TermBo.to(termBo);
345         }
346 
347         return result;
348     }
349 
350     /**
351      * @see org.kuali.rice.krms.impl.repository.TermBoService#getTermResolverById(java.lang.String)
352      */
353     @Override
354     public TermResolverDefinition getTermResolverById(String id) {
355         TermResolverDefinition result = null;
356 
357         if (StringUtils.isBlank(id)) {
358             throw new RiceIllegalArgumentException("id must not be blank or null");
359         }
360 
361         TermResolverBo termResolverBo = dataObjectService.find(TermResolverBo.class, id);
362 
363         if (termResolverBo != null) {
364             result = TermResolverBo.to(termResolverBo);
365         }
366 
367         return result;
368     }
369 
370     @Override
371     public List<TermResolverDefinition> findTermResolversByOutputId(String id, String namespace) {
372         List<TermResolverDefinition> results = null;
373 
374         if (StringUtils.isBlank(id)) {
375             throw new RiceIllegalArgumentException("id must not be blank or null");
376         }
377 
378         if (StringUtils.isBlank(namespace)) {
379             throw new RiceIllegalArgumentException("namespace must not be blank or null");
380         }
381 
382         Map<String, String> critMap = new HashMap<String, String>(2);
383 
384         critMap.put("outputId", id);
385         critMap.put("namespace", namespace);
386 
387         QueryByCriteria crit = QueryByCriteria.Builder.andAttributes(critMap).build();
388 
389         QueryResults<TermResolverBo> termResolverBos = dataObjectService.findMatching(TermResolverBo.class, crit);
390 
391         if (!CollectionUtils.isEmpty(termResolverBos.getResults())) {
392             results = new ArrayList<TermResolverDefinition>(termResolverBos.getResults().size());
393 
394             for (TermResolverBo termResolverBo : termResolverBos.getResults()) {
395                 results.add(TermResolverBo.to(termResolverBo));
396             }
397         } else {
398             results = Collections.emptyList();
399         }
400 
401         return results;
402     }
403 
404     @Override
405     public List<TermResolverDefinition> findTermResolversByNamespace(String namespace) {
406         List<TermResolverDefinition> results = null;
407 
408         if (StringUtils.isBlank(namespace)) {
409             throw new RiceIllegalArgumentException("namespace must not be blank or null");
410         }
411 
412         QueryByCriteria crit = QueryByCriteria.Builder.forAttribute("namespace", namespace).build();
413 
414         QueryResults<TermResolverBo> termResolverBos = dataObjectService.findMatching(TermResolverBo.class, crit);
415 
416         if (!CollectionUtils.isEmpty(termResolverBos.getResults())) {
417             results = new ArrayList<TermResolverDefinition>(termResolverBos.getResults().size());
418 
419             for (TermResolverBo termResolverBo : termResolverBos.getResults()) {
420                 if (termResolverBo != null) {
421                     results.add(TermResolverBo.to(termResolverBo));
422                 }
423             }
424         } else {
425             results = Collections.emptyList();
426         }
427 
428         return results;
429     }
430 
431     @Override
432     public TermResolverDefinition getTermResolverByNameAndNamespace(String name,
433             String namespace) throws RiceIllegalArgumentException {
434         if (StringUtils.isBlank(name)) {
435             throw new IllegalArgumentException("name is null or blank");
436         }
437 
438         if (StringUtils.isBlank(namespace)) {
439             throw new IllegalArgumentException("namespace is null or blank");
440         }
441 
442         final Map<String, Object> map = new HashMap<String, Object>();
443         map.put("name", name);
444         map.put("namespace", namespace);
445         TermResolverBo bo = dataObjectService.find(TermResolverBo.class, map);
446 
447         return TermResolverBo.to(bo);
448     }
449 
450     @Override
451     public TermSpecificationDefinition getTermSpecificationByNameAndNamespace(String name,
452             String namespace) throws RiceIllegalArgumentException {
453         if (StringUtils.isBlank(name)) {
454             throw new IllegalArgumentException("name is null or blank");
455         }
456 
457         if (StringUtils.isBlank(namespace)) {
458             throw new IllegalArgumentException("namespace is null or blank");
459         }
460 
461         final Map<String, Object> map = new HashMap<String, Object>();
462         map.put("name", name);
463         map.put("namespace", namespace);
464         TermSpecificationBo bo = findSingleMatching(dataObjectService, TermSpecificationBo.class, map);
465 
466         return TermSpecificationBo.to(bo);
467     }
468 
469     @Override
470     public List<TermSpecificationDefinition> findAllTermSpecificationsByContextId(String contextId) {
471         List<TermSpecificationDefinition> results = null;
472 
473         if (StringUtils.isBlank(contextId)) {
474             throw new RiceIllegalArgumentException("contextId must not be blank or null");
475         }
476 
477         QueryByCriteria crit = QueryByCriteria.Builder.forAttribute("contextId", contextId).build();
478 
479         QueryResults<ContextValidTermBo> contextValidTerms =
480                 dataObjectService.findMatching(ContextValidTermBo.class, crit);
481 
482         if (!CollectionUtils.isEmpty(contextValidTerms.getResults())) {
483             results = new ArrayList<TermSpecificationDefinition>(contextValidTerms.getResults().size());
484 
485             for (ContextValidTermBo validTerm : contextValidTerms.getResults()) {
486                 results.add(TermSpecificationBo.to(validTerm.getTermSpecification()));
487             }
488         } else {
489             results = Collections.emptyList();
490         }
491 
492         return results;
493     }
494 }