• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 10946298164

19 Sep 2024 05:33PM UTC coverage: 63.759% (+0.09%) from 63.671%
10946298164

push

github

mogoodrich
TRUNK-6265: Bugs in Concept.getPreferredName(Locale) method (#4749)

(cherry picked from commit bc725f242)

14 of 16 new or added lines in 1 file covered. (87.5%)

12 existing lines in 9 files now uncovered.

21692 of 34022 relevant lines covered (63.76%)

0.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.37
/api/src/main/java/org/openmrs/api/impl/ConceptServiceImpl.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.api.impl;
11

12
import static org.apache.commons.lang3.StringUtils.contains;
13

14
import java.lang.reflect.InvocationTargetException;
15
import java.util.ArrayList;
16
import java.util.Collection;
17
import java.util.Collections;
18
import java.util.Date;
19
import java.util.HashMap;
20
import java.util.HashSet;
21
import java.util.Iterator;
22
import java.util.List;
23
import java.util.Locale;
24
import java.util.Map;
25
import java.util.Set;
26
import java.util.UUID;
27

28
import org.apache.commons.beanutils.BeanUtils;
29
import org.apache.commons.collections.CollectionUtils;
30
import org.hibernate.Hibernate;
31
import org.openmrs.Concept;
32
import org.openmrs.ConceptAnswer;
33
import org.openmrs.ConceptAttribute;
34
import org.openmrs.ConceptAttributeType;
35
import org.openmrs.ConceptClass;
36
import org.openmrs.ConceptComplex;
37
import org.openmrs.ConceptDatatype;
38
import org.openmrs.ConceptDescription;
39
import org.openmrs.ConceptMap;
40
import org.openmrs.ConceptMapType;
41
import org.openmrs.ConceptName;
42
import org.openmrs.ConceptNameTag;
43
import org.openmrs.ConceptNumeric;
44
import org.openmrs.ConceptProposal;
45
import org.openmrs.ConceptReferenceTerm;
46
import org.openmrs.ConceptReferenceTermMap;
47
import org.openmrs.ConceptSearchResult;
48
import org.openmrs.ConceptSet;
49
import org.openmrs.ConceptSource;
50
import org.openmrs.ConceptStopWord;
51
import org.openmrs.Drug;
52
import org.openmrs.DrugIngredient;
53
import org.openmrs.Obs;
54
import org.openmrs.api.APIException;
55
import org.openmrs.api.AdministrationService;
56
import org.openmrs.api.ConceptInUseException;
57
import org.openmrs.api.ConceptNameInUseException;
58
import org.openmrs.api.ConceptService;
59
import org.openmrs.api.ConceptStopWordException;
60
import org.openmrs.api.ConceptsLockedException;
61
import org.openmrs.api.context.Context;
62
import org.openmrs.api.db.ConceptDAO;
63
import org.openmrs.api.db.DAOException;
64
import org.openmrs.customdatatype.CustomDatatypeUtil;
65
import org.openmrs.util.OpenmrsConstants;
66
import org.openmrs.util.OpenmrsUtil;
67
import org.openmrs.validator.ValidateUtil;
68
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
70
import org.springframework.cache.annotation.CacheEvict;
71
import org.springframework.cache.annotation.Cacheable;
72
import org.springframework.transaction.annotation.Transactional;
73
import org.springframework.util.StringUtils;
74

75
/**
76
 * Default Implementation of ConceptService service layer classes
77
 * 
78
 * @see org.openmrs.api.ConceptService to access these methods
79
 */
80
@Transactional
81
public class ConceptServiceImpl extends BaseOpenmrsService implements ConceptService {
1✔
82
        
83
        private static final Logger log = LoggerFactory.getLogger(ConceptServiceImpl.class);
1✔
84
        
85
        private ConceptDAO dao;
86
        
87
        private static Concept trueConcept;
88
        
89
        private static Concept falseConcept;
90
        
91
        private static Concept unknownConcept;
92

93
        private static final String ERROR_MESSAGE = "Error generated";
94

95
        private static final String CONCEPT_IDS_BY_MAPPING_CACHE_NAME = "conceptIdsByMapping";
96

97
        /**
98
         * @see org.openmrs.api.ConceptService#setConceptDAO(org.openmrs.api.db.ConceptDAO)
99
         */
100
        @Override
101
        public void setConceptDAO(ConceptDAO dao) {
102
                this.dao = dao;
1✔
103
        }
1✔
104

105
        /**
106
         * @see org.openmrs.api.ConceptService#saveConcept(org.openmrs.Concept)
107
         * <strong>Should</strong> return the concept with new conceptID if creating new concept
108
         * <strong>Should</strong> return the concept with same conceptID if updating existing concept
109
         * <strong>Should</strong> leave preferred name preferred if set
110
         * <strong>Should</strong> set default preferred name to fully specified first
111
         * <strong>Should</strong> not set default preferred name to short or index terms
112
     * <strong>Should</strong> force set flag if set members exist
113
         */
114
        @Override
115
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
116
        public Concept saveConcept(Concept concept) throws APIException {
117
                ensureConceptMapTypeIsSet(concept);
1✔
118

119
                CustomDatatypeUtil.saveAttributesIfNecessary(concept);
1✔
120

121
                // make sure the administrator hasn't turned off concept editing
122
                checkIfLocked();
1✔
123
                checkIfDatatypeCanBeChanged(concept);
1✔
124
                
125
                List<ConceptName> changedConceptNames = null;
1✔
126
                Map<String, ConceptName> uuidClonedConceptNameMap = null;
1✔
127
                
128
                if (concept.getConceptId() != null) {
1✔
129
                        uuidClonedConceptNameMap = new HashMap<>();
1✔
130
                        for (ConceptName conceptName : concept.getNames()) {
1✔
131
                                // ignore newly added names
132
                                if (conceptName.getConceptNameId() != null) {
1✔
133
                                        ConceptName clone = cloneConceptName(conceptName);
1✔
134
                                        clone.setConceptNameId(null);
1✔
135
                                        uuidClonedConceptNameMap.put(conceptName.getUuid(), clone);
1✔
136
                                        
137
                                        if (hasNameChanged(conceptName)) {
1✔
138
                                                if (changedConceptNames == null) {
1✔
139
                                                        changedConceptNames = new ArrayList<>();
1✔
140
                                                }
141
                                                changedConceptNames.add(conceptName);
1✔
142
                                        } else {
143
                                                // put back the concept name id
144
                                                clone.setConceptNameId(conceptName.getConceptNameId());
1✔
145
                                                // Use the cloned version
146
                                                try {
147
                                                        BeanUtils.copyProperties(conceptName, clone);
1✔
148
                                                }
149
                                                catch (IllegalAccessException | InvocationTargetException e) {
×
150
                                                        log.error(ERROR_MESSAGE, e);
×
151
                                                }
1✔
152
                                        }
153
                                }
154
                        }
1✔
155
                }
156
                
157
                if (CollectionUtils.isNotEmpty(changedConceptNames)) {
1✔
158
                        for (ConceptName changedName : changedConceptNames) {
1✔
159
                                // void old concept name
160
                                changedName.setVoided(true);
1✔
161
                                changedName.setDateVoided(new Date());
1✔
162
                                changedName.setVoidedBy(Context.getAuthenticatedUser());
1✔
163
                                changedName.setVoidReason(Context.getMessageSourceService().getMessage("Concept.name.voidReason.nameChanged"));
1✔
164

165
                                makeVoidedNameSynonym(changedName);
1✔
166
                                makeLocaleNotPreferred(changedName);
1✔
167
                                
168
                                // create a new concept name from the matching cloned
169
                                // conceptName
170
                                ConceptName clone = uuidClonedConceptNameMap.get(changedName.getUuid());
1✔
171
                                clone.setUuid(UUID.randomUUID().toString());
1✔
172
                                clone.setDateCreated(null);
1✔
173
                                clone.setCreator(null);
1✔
174
                                concept.addName(clone);
1✔
175
                        }
1✔
176
                }
177
                ensurePreferredNameForLocale(concept);
1✔
178
                logConceptChangedData(concept);
1✔
179
                
180
                // force isSet when concept has members
181
                if (!concept.getSet() && (!concept.getSetMembers().isEmpty())) {
1✔
182
                        concept.setSet(true);
1✔
183
                }
184

185
                return dao.saveConcept(concept);
1✔
186
        }
187

188
        private void ensureConceptMapTypeIsSet(Concept concept) {
189
                ConceptMapType defaultConceptMapType = null;
1✔
190
                for (ConceptMap map : concept.getConceptMappings()) {
1✔
191
                        if (map.getConceptMapType() == null) {
1✔
192
                                if (defaultConceptMapType == null) {
×
193
                                        defaultConceptMapType = Context.getConceptService().getDefaultConceptMapType();
×
194
                                }
195
                                map.setConceptMapType(defaultConceptMapType);
×
196
                        }
197
                }
1✔
198
        }
1✔
199

200
        private void makeVoidedNameSynonym(ConceptName conceptName) {
201
                // Helps to avoid having  multiple fully
202
                // specified or preferred names in a locale
203
                // in case the name is unvoided
204
                if (!conceptName.isSynonym()) {
1✔
205
                        conceptName.setConceptNameType(null);
1✔
206
                }
207
        }
1✔
208

209
        private void makeLocaleNotPreferred(ConceptName conceptName) {
210
                if (conceptName.getLocalePreferred()) {
1✔
211
                        conceptName.setLocalePreferred(false);
1✔
212
                }
213
        }
1✔
214

215
        private void ensurePreferredNameForLocale(Concept concept) {
216
                //Ensure if there's a name for a locale that at least one suitable name is marked preferred in that locale
217
                //Order of preference is:
218
                // 1) any name that concept.getPreferredName returns
219
                // 2) fully specified name
220
                // 3) any synonym
221
                // short name and index terms are never preferred.
222

223
                Set<Locale> checkedLocales = new HashSet<>();
1✔
224
                for (ConceptName n : concept.getNames()) {
1✔
225
                        Locale locale = n.getLocale();
1✔
226
                        if (checkedLocales.contains(locale)) {
1✔
227
                                continue; //we've already checked this locale
1✔
228
                        }
229

230
                        //getPreferredName(locale) returns any name marked preferred,
231
                        //or the fullySpecifiedName even if not marked preferred
232
                        ConceptName possiblePreferredName = concept.getPreferredName(locale);
1✔
233

234
                        if (possiblePreferredName != null) {
1✔
235
                                //do nothing yet, but stick around to setLocalePreferred(true)
236
                        } else if (concept.getFullySpecifiedName(locale) != null) {
1✔
237
                                possiblePreferredName = concept.getFullySpecifiedName(locale);
×
238
                        } else if (!CollectionUtils.isEmpty(concept.getSynonyms(locale))) {
1✔
239
                                concept.getSynonyms(locale).iterator().next().setLocalePreferred(true);
1✔
240
                        }
241
                        //index terms are never used as preferred name
242

243
                        if (possiblePreferredName != null) { //there may have been none
1✔
244
                                possiblePreferredName.setLocalePreferred(true);
1✔
245
                        }
246
                        checkedLocales.add(locale);
1✔
247
                }
1✔
248
        }
1✔
249

250
        private void logConceptChangedData(Concept concept) {
251
                concept.setDateChanged(new Date());
1✔
252
                concept.setChangedBy(Context.getAuthenticatedUser());
1✔
253
        }
1✔
254

255
        /**
256
         * @see org.openmrs.api.ConceptService#saveDrug(org.openmrs.Drug)
257
         */
258
        @Override
259
        public Drug saveDrug(Drug drug) throws APIException {
260
                checkIfLocked();
1✔
261
                return dao.saveDrug(drug);
1✔
262
        }
263
        
264
        /**
265
         * @see org.openmrs.api.ConceptService#purgeConcept(Concept)
266
         */
267
        @Override
268
        public void purgeConcept(Concept concept) throws APIException {
269
                checkIfLocked();
1✔
270
                
271
                if (concept.getConceptId() != null) {
1✔
272
                        for (ConceptName conceptName : concept.getNames()) {
1✔
273
                                if (hasAnyObservation(conceptName)) {
1✔
274
                                        throw new ConceptNameInUseException("Can't delete concept with id : " + concept.getConceptId()
1✔
275
                                                + " because it has a name '" + conceptName.getName()
1✔
276
                                                + "' which is being used by some observation(s)");
277
                                }
278
                        }
1✔
279
                }
280
                
281
                dao.purgeConcept(concept);
1✔
282
        }
1✔
283
        
284
        /**
285
         * @see org.openmrs.api.ConceptService#retireConcept(org.openmrs.Concept, java.lang.String)
286
         */
287
        @Override
288
        public Concept retireConcept(Concept concept, String reason) throws APIException {
289
                if (!StringUtils.hasText(reason)) {
1✔
290
                        throw new IllegalArgumentException(Context.getMessageSourceService().getMessage("general.voidReason.empty"));
1✔
291
                }
292
                
293
                // only do this if the concept isn't retired already
294
                if (!concept.getRetired()) {
1✔
295
                        checkIfLocked();
×
296
                        
297
                        concept.setRetired(true);
×
298
                        concept.setRetireReason(reason);
×
299
                        return Context.getConceptService().saveConcept(concept);
×
300
                }
301
                
302
                return concept;
1✔
303
        }
304
        
305
        /**
306
         * @see org.openmrs.api.ConceptService#retireDrug(org.openmrs.Drug, java.lang.String)
307
         * @throws APIException
308
         */
309
        @Override
310
        public Drug retireDrug(Drug drug, String reason) throws APIException {
311
                return dao.saveDrug(drug);
1✔
312
        }
313
        
314
        /**
315
         * @see org.openmrs.api.ConceptService#unretireDrug(org.openmrs.Drug)
316
         */
317
        @Override
318
        public Drug unretireDrug(Drug drug) throws APIException {
319
                return Context.getConceptService().saveDrug(drug);
1✔
320
        }
321
        
322
        /**
323
         * @see org.openmrs.api.ConceptService#purgeDrug(org.openmrs.Drug)
324
         * @throws APIException
325
         */
326
        @Override
327
        public void purgeDrug(Drug drug) throws APIException {
328
                dao.purgeDrug(drug);
1✔
329
        }
1✔
330
        
331
        /**
332
         * @see org.openmrs.api.ConceptService#getConcept(java.lang.Integer)
333
         */
334
        @Override
335
        @Transactional(readOnly = true)
336
        public Concept getConcept(Integer conceptId) throws APIException {
337
                return dao.getConcept(conceptId);
1✔
338
        }
339
        
340
        /**
341
         * @see org.openmrs.api.ConceptService#getConceptName(java.lang.Integer)
342
         */
343
        @Override
344
        @Transactional(readOnly = true)
345
        public ConceptName getConceptName(Integer conceptNameId) throws APIException {
346
                return dao.getConceptName(conceptNameId);
1✔
347
        }
348
        
349
        /**
350
         * @see org.openmrs.api.ConceptService#getConceptAnswer(java.lang.Integer)
351
         */
352
        @Override
353
        @Transactional(readOnly = true)
354
        public ConceptAnswer getConceptAnswer(Integer conceptAnswerId) throws APIException {
355
                return dao.getConceptAnswer(conceptAnswerId);
1✔
356
        }
357
        
358
        /**
359
         * @see org.openmrs.api.ConceptService#getDrug(java.lang.Integer)
360
         */
361
        @Override
362
        @Transactional(readOnly = true)
363
        public Drug getDrug(Integer drugId) throws APIException {
364
                return dao.getDrug(drugId);
1✔
365
        }
366
        
367
        /**
368
         * @see org.openmrs.api.ConceptService#getConceptNumeric(java.lang.Integer)
369
         */
370
        @Override
371
        @Transactional(readOnly = true)
372
        public ConceptNumeric getConceptNumeric(Integer conceptId) throws APIException {
373
                return dao.getConceptNumeric(conceptId);
1✔
374
        }
375
        
376
        /**
377
         * @see org.openmrs.api.ConceptService#getConceptComplex(java.lang.Integer)
378
         */
379
        @Override
380
        @Transactional(readOnly = true)
381
        public ConceptComplex getConceptComplex(Integer conceptId) {
382
                return dao.getConceptComplex(conceptId);
1✔
383
        }
384
        
385
        /**
386
         * @see org.openmrs.api.ConceptService#getAllConcepts()
387
         */
388
        @Override
389
        @Transactional(readOnly = true)
390
        public List<Concept> getAllConcepts() throws APIException {
391
                return Context.getConceptService().getAllConcepts(null, true, true);
1✔
392
        }
393
        
394
        /**
395
         * @see org.openmrs.api.ConceptService#getAllConcepts(java.lang.String, boolean, boolean)
396
         */
397
        @Override
398
        @Transactional(readOnly = true)
399
        public List<Concept> getAllConcepts(String sortBy, boolean asc, boolean includeRetired) throws APIException {
400
                String tmpSortBy = sortBy == null ? "conceptId" : sortBy;
1✔
401
                
402
                return dao.getAllConcepts(tmpSortBy, asc, includeRetired);
1✔
403
        }
404

405
        /**
406
         * @see org.openmrs.api.ConceptService#getConceptsByName(java.lang.String)
407
         */
408
        @Override
409
        @Transactional(readOnly = true)
410
        public List<Concept> getConceptsByName(String name) throws APIException {
411
                return getConcepts(name, Context.getLocale(), true, null, null);
1✔
412
        }
413
        
414
        /**
415
         * @see org.openmrs.api.ConceptService#getConceptByName(java.lang.String)
416
         */
417
        @Override
418
        @Transactional(readOnly = true)
419
        public Concept getConceptByName(String name) {
420
                if (!StringUtils.hasText(name)) {
1✔
421
                        return null;
1✔
422
                }
423
                return dao.getConceptByName(name);
1✔
424
        }
425

426
        /**
427
         * @see org.openmrs.api.ConceptService#getConcept(java.lang.String)
428
         */
429
        @Override
430
        @Transactional(readOnly = true)
431
        public Concept getConcept(String conceptIdOrName) {
432
                Concept c;
433
                Integer conceptId;
434
                try {
435
                        conceptId = Integer.valueOf(conceptIdOrName);
1✔
436
                }
437
                catch (NumberFormatException nfe) {
1✔
438
                        conceptId = null;
1✔
439
                }
1✔
440
                
441
                if (conceptId != null) {
1✔
442
                        c = Context.getConceptService().getConcept(conceptId);
1✔
443
                } else {
444
                        c = Context.getConceptService().getConceptByName(conceptIdOrName);
1✔
445
                }
446
                return c;
1✔
447
        }
448
        
449
        /**
450
         * Generic getConcepts method (used internally) to get concepts matching a on name
451
         * 
452
         * @param name
453
         * @param loc
454
         * @param searchOnPhrase
455
         * @return
456
         */
457
        private List<Concept> getConcepts(String name, Locale loc, boolean searchOnPhrase, List<ConceptClass> classes,
458
                List<ConceptDatatype> datatypes) {
459
                List<ConceptClass> tmpClasses = classes == null ? new ArrayList<>() : classes;
1✔
460
                List<ConceptDatatype> tmpDatatypes = datatypes == null ? new ArrayList<>() : datatypes;
1✔
461
                
462
                return dao.getConcepts(name, loc, searchOnPhrase, tmpClasses, tmpDatatypes);
1✔
463
        }
464
        
465
        /**
466
         * @see org.openmrs.api.ConceptService#getDrug(java.lang.String)
467
         */
468
        @Override
469
        @Transactional(readOnly = true)
470
        public Drug getDrug(String drugNameOrId) {
471
                Integer drugId;
472
                
473
                try {
474
                        drugId = Integer.valueOf(drugNameOrId);
×
475
                }
476
                catch (NumberFormatException nfe) {
1✔
477
                        drugId = null;
1✔
478
                }
×
479
                
480
                if (drugId != null) {
1✔
481
                        return Context.getConceptService().getDrug(drugId);
×
482
                } else {
483
                        List<Drug> drugs = dao.getDrugs(drugNameOrId, null, false);
1✔
484
                        if (drugs.size() > 1) {
1✔
485
                                log.warn("more than one drug name returned with name:" + drugNameOrId);
×
486
                        }
487
                        if (drugs.isEmpty()) {
1✔
488
                                return null;
1✔
489
                        }
490
                        return drugs.get(0);
1✔
491
                }
492
        }
493
        
494
        /**
495
         * @see org.openmrs.api.ConceptService#getAllDrugs()
496
         */
497
        @Override
498
        @Transactional(readOnly = true)
499
        public List<Drug> getAllDrugs() {
500
                return Context.getConceptService().getAllDrugs(true);
1✔
501
        }
502
        
503
        /**
504
         * @see org.openmrs.api.ConceptService#getAllDrugs(boolean)
505
         */
506
        @Override
507
        @Transactional(readOnly = true)
508
        public List<Drug> getAllDrugs(boolean includeRetired) {
509
                return dao.getDrugs(null, null, includeRetired);
1✔
510
        }
511
        
512
        /**
513
         * @see org.openmrs.api.ConceptService#getDrugsByConcept(org.openmrs.Concept)
514
         */
515
        @Override
516
        @Transactional(readOnly = true)
517
        public List<Drug> getDrugsByConcept(Concept concept) {
518
                return dao.getDrugs(null, concept, false);
1✔
519
        }
520
        
521
        /**
522
         * @see org.openmrs.api.ConceptService#getDrugs(java.lang.String)
523
         */
524
        @Override
525
        @Transactional(readOnly = true)
526
        public List<Drug> getDrugs(String phrase) {
527
                List<Drug> drugs = new ArrayList<>();
1✔
528
                // trying to treat search phrase as drug id
529
                try {
530
                        Integer drugId = Integer.parseInt(phrase);
1✔
531
                        Drug targetDrug = Context.getConceptService().getDrug(drugId);
1✔
532
                        // if drug was found add it to result
533
                        if (targetDrug != null) {
1✔
534
                                drugs.add(targetDrug);
1✔
535
                        }
536
                }
537
                catch (NumberFormatException e) {
1✔
538
                        // do nothing
539
                }
1✔
540
                
541
                // also try to treat search phrase as drug concept id
542
                try {
543
                        Integer conceptId = Integer.parseInt(phrase);
1✔
544
                        Concept targetConcept = Context.getConceptService().getConcept(conceptId);
1✔
545
                        if (targetConcept != null) {
1✔
546
                                drugs.addAll(Context.getConceptService().getDrugsByConcept(targetConcept));
1✔
547
                        }
548
                }
549
                catch (NumberFormatException e) {
1✔
550
                        // do nothing
551
                }
1✔
552
                
553
                drugs.addAll(dao.getDrugs(phrase));
1✔
554
                return drugs;
1✔
555
        }
556
        
557
        /**
558
         * @see org.openmrs.api.ConceptService#getConceptsByClass(org.openmrs.ConceptClass)
559
         */
560
        @Override
561
        @Transactional(readOnly = true)
562
        public List<Concept> getConceptsByClass(ConceptClass cc) {                
563
                return dao.getConceptsByClass(cc);
1✔
564
        }
565
        
566
        /**
567
         * @see org.openmrs.api.ConceptService#getAllConceptClasses(boolean)
568
         */
569
        @Override
570
        @Transactional(readOnly = true)
571
        public List<ConceptClass> getAllConceptClasses(boolean includeRetired) {
572
                return dao.getAllConceptClasses(includeRetired);
1✔
573
        }
574
        
575
        /**
576
         * @see org.openmrs.api.ConceptService#getConceptClass(java.lang.Integer)
577
         */
578
        @Override
579
        @Transactional(readOnly = true)
580
        public ConceptClass getConceptClass(Integer i) {
581
                return dao.getConceptClass(i);
1✔
582
        }
583
        
584
        /**
585
         * @see org.openmrs.api.ConceptService#getConceptClassByName(java.lang.String)
586
         */
587
        @Override
588
        @Transactional(readOnly = true)
589
        public ConceptClass getConceptClassByName(String name) {
590
                List<ConceptClass> ccList = dao.getConceptClasses(name);
1✔
591
                if (ccList.size() > 1) {
1✔
592
                        log.warn("More than one ConceptClass found with name: " + name);
×
593
                }
594
                if (ccList.size() == 1) {
1✔
595
                        return ccList.get(0);
1✔
596
                }
597
                return null;
1✔
598
        }
599
        
600
        /**
601
         * @see org.openmrs.api.ConceptService#getAllConceptClasses(boolean)
602
         */
603
        @Override
604
        @Transactional(readOnly = true)
605
        public List<ConceptClass> getAllConceptClasses() throws APIException {
606
                return Context.getConceptService().getAllConceptClasses(true);
1✔
607
        }
608
        
609
        /**
610
         * @see org.openmrs.api.ConceptService#saveConceptClass(org.openmrs.ConceptClass)
611
         */
612
        @Override
613
        public ConceptClass saveConceptClass(ConceptClass cc) throws APIException {
614
                return dao.saveConceptClass(cc);
1✔
615
        }
616
        
617
        /**
618
         * @see org.openmrs.api.ConceptService#purgeConceptClass(org.openmrs.ConceptClass)
619
         */
620
        @Override
621
        public void purgeConceptClass(ConceptClass cc) {
622
                dao.purgeConceptClass(cc);
1✔
623
        }
1✔
624
        
625
        /**
626
         * @see org.openmrs.api.ConceptService#purgeConceptNameTag(org.openmrs.ConceptNameTag)
627
         */
628
        @Override
629
        public void purgeConceptNameTag(ConceptNameTag cnt) {
630
                dao.deleteConceptNameTag(cnt);
1✔
631
        }
1✔
632
        
633
        /**
634
         * @see org.openmrs.api.ConceptService#getAllConceptDatatypes()
635
         */
636
        @Override
637
        @Transactional(readOnly = true)
638
        public List<ConceptDatatype> getAllConceptDatatypes() {
639
                return Context.getConceptService().getAllConceptDatatypes(true);
1✔
640
        }
641
        
642
        /**
643
         * @see org.openmrs.api.ConceptService#getAllConceptDatatypes(boolean)
644
         */
645
        @Override
646
        @Transactional(readOnly = true)
647
        public List<ConceptDatatype> getAllConceptDatatypes(boolean includeRetired) throws APIException {
648
                return dao.getAllConceptDatatypes(includeRetired);
1✔
649
        }
650
        
651
        /**
652
         * @see org.openmrs.api.ConceptService#getConceptDatatype(java.lang.Integer)
653
         */
654
        @Override
655
        @Transactional(readOnly = true)
656
        public ConceptDatatype getConceptDatatype(Integer i) {
657
                return dao.getConceptDatatype(i);
1✔
658
        }
659
        
660
        /**
661
         * @see org.openmrs.api.ConceptService#getConceptDatatypeByName(java.lang.String)
662
         */
663
        @Override
664
        @Transactional(readOnly = true)
665
        public ConceptDatatype getConceptDatatypeByName(String name) {
666
                return dao.getConceptDatatypeByName(name);
1✔
667
        }
668
        
669
        /**
670
         * @see org.openmrs.api.ConceptService#getConceptSetsByConcept(org.openmrs.Concept)
671
         */
672
        @Override
673
        @Transactional(readOnly = true)
674
        public List<ConceptSet> getConceptSetsByConcept(Concept concept) throws APIException {
675
                return dao.getConceptSetsByConcept(concept);
1✔
676
        }
677
        
678
        /**
679
         * @see org.openmrs.api.ConceptService#getConceptsByConceptSet(Concept)
680
         */
681
        @Override
682
        @Transactional(readOnly = true)
683
        public List<Concept> getConceptsByConceptSet(Concept c) {
684
                Set<Integer> alreadySeen = new HashSet<>();
1✔
685
                List<Concept> ret = new ArrayList<>();
1✔
686
                explodeConceptSetHelper(c, ret, alreadySeen);
1✔
687
                return ret;
1✔
688
        }
689
        
690
        /**
691
         * @see org.openmrs.api.ConceptService#getSetsContainingConcept(org.openmrs.Concept)
692
         */
693
        @Override
694
        @Transactional(readOnly = true)
695
        public List<ConceptSet> getSetsContainingConcept(Concept concept) {
696
                if (concept.getConceptId() == null) {
1✔
697
                        return Collections.emptyList();
1✔
698
                }
699
                
700
                return dao.getSetsContainingConcept(concept);
1✔
701
        }
702
        
703
        /**
704
         * @see org.openmrs.api.ConceptService#getConceptProposal(java.lang.Integer)
705
         */
706
        @Override
707
        @Transactional(readOnly = true)
708
        public ConceptProposal getConceptProposal(Integer conceptProposalId) {
709
                return dao.getConceptProposal(conceptProposalId);
1✔
710
        }
711
        
712
        /**
713
         * @see org.openmrs.api.ConceptService#getAllConceptProposals(boolean)
714
         */
715
        @Override
716
        @Transactional(readOnly = true)
717
        public List<ConceptProposal> getAllConceptProposals(boolean includeCompleted) {
718
                return dao.getAllConceptProposals(includeCompleted);
1✔
719
        }
720
        
721
        /**
722
         * @see org.openmrs.api.ConceptService#getConceptProposals(java.lang.String)
723
         */
724
        @Override
725
        @Transactional(readOnly = true)
726
        public List<ConceptProposal> getConceptProposals(String cp) {
727
                return dao.getConceptProposals(cp);
1✔
728
        }
729
        
730
        /**
731
         * @see org.openmrs.api.ConceptService#getProposedConcepts(java.lang.String)
732
         */
733
        @Override
734
        @Transactional(readOnly = true)
735
        public List<Concept> getProposedConcepts(String text) {
736
                return dao.getProposedConcepts(text);
×
737
        }
738
        
739
        /**
740
         * @see org.openmrs.api.ConceptService#saveConceptProposal(org.openmrs.ConceptProposal)
741
         */
742
        @Override
743
        public ConceptProposal saveConceptProposal(ConceptProposal conceptProposal) throws APIException {
744
                return dao.saveConceptProposal(conceptProposal);
1✔
745
        }
746
        
747
        /**
748
         * @see org.openmrs.api.ConceptService#purgeConceptProposal(org.openmrs.ConceptProposal)
749
         */
750
        @Override
751
        public void purgeConceptProposal(ConceptProposal cp) throws APIException {
752
                dao.purgeConceptProposal(cp);
1✔
753
        }
1✔
754
        
755
        /**
756
         * @see org.openmrs.api.ConceptService#mapConceptProposalToConcept(ConceptProposal, Concept, Locale)
757
         */
758
        @Override
759
        public Concept mapConceptProposalToConcept(ConceptProposal cp, Concept mappedConcept, Locale locale) throws APIException {
760
                
761
                if (cp.getState().equals(OpenmrsConstants.CONCEPT_PROPOSAL_REJECT)) {
1✔
762
                        cp.rejectConceptProposal();
1✔
763
                        Context.getConceptService().saveConceptProposal(cp);
1✔
764
                        return null;
1✔
765
                }
766
                
767
                if (mappedConcept == null) {
1✔
768
                        throw new APIException("Concept.mapped.illegal", (Object[]) null);
1✔
769
                }
770
                
771
                ConceptName conceptName = null;
1✔
772
                if (cp.getState().equals(OpenmrsConstants.CONCEPT_PROPOSAL_CONCEPT) || !StringUtils.hasText(cp.getFinalText())) {
1✔
773
                        cp.setState(OpenmrsConstants.CONCEPT_PROPOSAL_CONCEPT);
1✔
774
                        cp.setFinalText("");
1✔
775
                } else if (cp.getState().equals(OpenmrsConstants.CONCEPT_PROPOSAL_SYNONYM)) {
1✔
776
                        
777
                        checkIfLocked();
1✔
778
                        
779
                        String finalText = cp.getFinalText();
1✔
780
                        conceptName = new ConceptName(finalText, null);
1✔
781
                        conceptName.setConcept(mappedConcept);
1✔
782
                        conceptName.setLocale(locale == null ? Context.getLocale() : locale);
1✔
783
                        conceptName.setDateCreated(new Date());
1✔
784
                        conceptName.setCreator(Context.getAuthenticatedUser());
1✔
785
                        //If this is pre 1.9
786
                        if (conceptName.getUuid() == null) {
1✔
787
                                conceptName.setUuid(UUID.randomUUID().toString());
×
788
                        }
789
                        mappedConcept.addName(conceptName);
1✔
790
                        mappedConcept.setChangedBy(Context.getAuthenticatedUser());
1✔
791
                        mappedConcept.setDateChanged(new Date());
1✔
792
                        ValidateUtil.validate(mappedConcept);
1✔
793
            Context.getConceptService().saveConcept(mappedConcept);
1✔
794
                }
795
                
796
                cp.setMappedConcept(mappedConcept);
1✔
797
                
798
                if (cp.getObsConcept() != null) {
1✔
799
                        Obs ob = new Obs();
1✔
800
                        ob.setEncounter(cp.getEncounter());
1✔
801
                        ob.setConcept(cp.getObsConcept());
1✔
802
                        ob.setValueCoded(cp.getMappedConcept());
1✔
803
                        if (cp.getState().equals(OpenmrsConstants.CONCEPT_PROPOSAL_SYNONYM)) {
1✔
804
                                ob.setValueCodedName(conceptName);
1✔
805
                        }
806
                        ob.setCreator(Context.getAuthenticatedUser());
1✔
807
                        ob.setDateCreated(new Date());
1✔
808
                        ob.setObsDatetime(cp.getEncounter().getEncounterDatetime());
1✔
809
                        ob.setLocation(cp.getEncounter().getLocation());
1✔
810
                        ob.setPerson(cp.getEncounter().getPatient());
1✔
811
                        if (ob.getUuid() == null) {
1✔
812
                                ob.setUuid(UUID.randomUUID().toString());
×
813
                        }
814
            Context.getObsService().saveObs(ob, null);
1✔
815
                        cp.setObs(ob);
1✔
816
                }
817
                
818
                return mappedConcept;
1✔
819
        }
820
        
821
        /**
822
         * @see org.openmrs.api.ConceptService#mapConceptProposalToConcept(org.openmrs.ConceptProposal,
823
         *      org.openmrs.Concept)
824
         */
825
        @Override
826
        public Concept mapConceptProposalToConcept(ConceptProposal cp, Concept mappedConcept) throws APIException {
827
                return Context.getConceptService().mapConceptProposalToConcept(cp, mappedConcept, null);
1✔
828
        }
829
        
830
        /**
831
         * @see org.openmrs.api.ConceptService#getConceptsByAnswer(org.openmrs.Concept)
832
         */
833
        @Override
834
        @Transactional(readOnly = true)
835
        public List<Concept> getConceptsByAnswer(Concept concept) throws APIException {
836
                if (concept.getConceptId() == null) {
1✔
837
                        return Collections.emptyList();
1✔
838
                }
839
                
840
                return dao.getConceptsByAnswer(concept);
1✔
841
        }
842
        
843
        /**
844
         * @see org.openmrs.api.ConceptService#getPrevConcept(org.openmrs.Concept)
845
         */
846
        @Override
847
        @Transactional(readOnly = true)
848
        public Concept getPrevConcept(Concept c) {
849
                return dao.getPrevConcept(c);
1✔
850
        }
851
        
852
        /**
853
         * @see org.openmrs.api.ConceptService#getNextConcept(org.openmrs.Concept)
854
         */
855
        @Override
856
        @Transactional(readOnly = true)
857
        public Concept getNextConcept(Concept c) {
858
                return dao.getNextConcept(c);
1✔
859
        }
860
        
861
        /**
862
         * @see org.openmrs.api.ConceptService#checkIfLocked()
863
         */
864
        @Override
865
        @Transactional(readOnly = true)
866
        public void checkIfLocked() throws ConceptsLockedException {
867
                String locked = Context.getAdministrationService().getGlobalProperty(
1✔
868
                    OpenmrsConstants.GLOBAL_PROPERTY_CONCEPTS_LOCKED, "false");
869
                if ("true".equalsIgnoreCase(locked)) {
1✔
870
                        throw new ConceptsLockedException();
×
871
                }
872
        }
1✔
873
        
874
        /**
875
         * @see org.openmrs.api.ConceptService#getConceptsWithDrugsInFormulary()
876
         */
877
        @Override
878
        @Transactional(readOnly = true)
879
        public List<Concept> getConceptsWithDrugsInFormulary() {
880
                return dao.getConceptsWithDrugsInFormulary();
1✔
881
        }
882
        
883
        /**
884
         * @see ConceptService#getMaxConceptId()
885
         */
886
        @Override
887
        @Transactional(readOnly = true)
888
        public Integer getMaxConceptId() {
889
                return dao.getMaxConceptId();
1✔
890
        }
891
        
892
        /**
893
         * Utility method used by getConceptsInSet(Concept concept)
894
         * 
895
         * @param concept
896
         * @param ret
897
         * @param alreadySeen
898
         */
899
        private void explodeConceptSetHelper(Concept concept, Collection<Concept> ret, Collection<Integer> alreadySeen) {
900
                if (alreadySeen.contains(concept.getConceptId())) {
1✔
901
                        return;
×
902
                }
903
                alreadySeen.add(concept.getConceptId());
1✔
904
                List<ConceptSet> cs = getConceptSetsByConcept(concept);
1✔
905
                for (ConceptSet set : cs) {
1✔
906
                        Concept c = set.getConcept();
1✔
907
                        if (c.getSet()) {
1✔
908
                                ret.add(c);
1✔
909
                                explodeConceptSetHelper(c, ret, alreadySeen);
1✔
910
                        } else {
911
                                ret.add(c);
1✔
912
                        }
913
                }
1✔
914
        }
1✔
915
        
916
        /**
917
         * @see org.openmrs.api.ConceptService#getConceptNameTagByName(java.lang.String)
918
         */
919
        @Override
920
        @Transactional(readOnly = true)
921
        public ConceptNameTag getConceptNameTagByName(String tagName) {
922
                return dao.getConceptNameTagByName(tagName);
1✔
923
        }
924
        
925
        /**
926
         * @see org.openmrs.api.ConceptService#getLocalesOfConceptNames()
927
         */
928
        @Override
929
        @Transactional(readOnly = true)
930
        public Set<Locale> getLocalesOfConceptNames() {
931
                return dao.getLocalesOfConceptNames();
1✔
932
        }
933
        
934
        /**
935
         * @see org.openmrs.api.ConceptService#getConceptSource(java.lang.Integer)
936
         */
937
        @Override
938
        @Transactional(readOnly = true)
939
        public ConceptSource getConceptSource(Integer conceptSourceId) {
940
                return dao.getConceptSource(conceptSourceId);
1✔
941
        }
942
        
943
        /**
944
         * @see org.openmrs.api.ConceptService#getAllConceptSources(boolean)
945
         */
946
        @Override
947
        @Transactional(readOnly = true)
948
        public List<ConceptSource> getAllConceptSources(boolean includeRetired) {
949
                return dao.getAllConceptSources(includeRetired);
1✔
950
        }
951
        
952
        /**
953
         * @see org.openmrs.api.ConceptService#purgeConceptSource(org.openmrs.ConceptSource)
954
         */
955
        @Override
956
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
957
        public ConceptSource purgeConceptSource(ConceptSource cs) throws APIException {
958
                return dao.deleteConceptSource(cs);
1✔
959
        }
960
        
961
        /**
962
         * @see org.openmrs.api.ConceptService#retireConceptSource(org.openmrs.ConceptSource, String)
963
         */
964
        @Override
965
        public ConceptSource retireConceptSource(ConceptSource cs, String reason) throws APIException {
966
                // retireReason is automatically set in BaseRetireHandler
967
                return Context.getConceptService().saveConceptSource(cs);
1✔
968
        }
969
        
970
        /**
971
         * @see org.openmrs.api.ConceptService#saveConceptSource(org.openmrs.ConceptSource)
972
         */
973
        @Override
974
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
975
        public ConceptSource saveConceptSource(ConceptSource conceptSource) throws APIException {
976
                return dao.saveConceptSource(conceptSource);
1✔
977
        }
978
        
979
        /**
980
         * @see org.openmrs.api.ConceptService#saveConceptNameTag(org.openmrs.ConceptNameTag)
981
         */
982
        @Override
983
        public ConceptNameTag saveConceptNameTag(ConceptNameTag nameTag) {
984
                checkIfLocked();
1✔
985
                
986
                return dao.saveConceptNameTag(nameTag);
1✔
987
        }
988
        
989
        /**
990
         * @see org.openmrs.api.ConceptService#conceptIterator()
991
         */
992
        @Override
993
        @Transactional(readOnly = true)
994
        public Iterator<Concept> conceptIterator() {
995
                return dao.conceptIterator();
1✔
996
        }
997
        
998
        /**
999
         * @see org.openmrs.api.ConceptService#getConceptByUuid(java.lang.String)
1000
         */
1001
        @Override
1002
        @Transactional(readOnly = true)
1003
        public Concept getConceptByUuid(String uuid) {
1004
                return dao.getConceptByUuid(uuid);
1✔
1005
        }
1006
        
1007
        /**
1008
         * @see org.openmrs.api.ConceptService#getConceptClassByUuid(java.lang.String)
1009
         */
1010
        @Override
1011
        @Transactional(readOnly = true)
1012
        public ConceptClass getConceptClassByUuid(String uuid) {
1013
                return dao.getConceptClassByUuid(uuid);
1✔
1014
        }
1015
        
1016
        @Override
1017
        @Transactional(readOnly = true)
1018
        public ConceptAnswer getConceptAnswerByUuid(String uuid) {
1019
                return dao.getConceptAnswerByUuid(uuid);
1✔
1020
        }
1021
        
1022
        @Override
1023
        @Transactional(readOnly = true)
1024
        public ConceptName getConceptNameByUuid(String uuid) {
1025
                return dao.getConceptNameByUuid(uuid);
1✔
1026
        }
1027
        
1028
        @Override
1029
        public ConceptSet getConceptSetByUuid(String uuid) {
1030
                return dao.getConceptSetByUuid(uuid);
1✔
1031
        }
1032
        
1033
        @Override
1034
        @Transactional(readOnly = true)
1035
        public ConceptSource getConceptSourceByUuid(String uuid) {
1036
                return dao.getConceptSourceByUuid(uuid);
1✔
1037
        }
1038
        
1039
        /**
1040
         * @see org.openmrs.api.ConceptService#getConceptDatatypeByUuid(java.lang.String)
1041
         */
1042
        @Override
1043
        @Transactional(readOnly = true)
1044
        public ConceptDatatype getConceptDatatypeByUuid(String uuid) {
1045
                return dao.getConceptDatatypeByUuid(uuid);
1✔
1046
        }
1047
        
1048
        /**
1049
         * @see org.openmrs.api.ConceptService#getConceptNumericByUuid(java.lang.String)
1050
         */
1051
        @Override
1052
        @Transactional(readOnly = true)
1053
        public ConceptNumeric getConceptNumericByUuid(String uuid) {
1054
                return dao.getConceptNumericByUuid(uuid);
1✔
1055
        }
1056
        
1057
        /**
1058
         * @see org.openmrs.api.ConceptService#getConceptProposalByUuid(java.lang.String)
1059
         */
1060
        @Override
1061
        @Transactional(readOnly = true)
1062
        public ConceptProposal getConceptProposalByUuid(String uuid) {
1063
                return dao.getConceptProposalByUuid(uuid);
1✔
1064
        }
1065
        
1066
        /**
1067
         * @see org.openmrs.api.ConceptService#getDrugByUuid(java.lang.String)
1068
         */
1069
        @Override
1070
        @Transactional(readOnly = true)
1071
        public Drug getDrugByUuid(String uuid) {
1072
                return dao.getDrugByUuid(uuid);
1✔
1073
        }
1074
        
1075
        /**
1076
         * @see org.openmrs.api.ConceptService#getDrugIngredientByUuid(java.lang.String)
1077
         */
1078
        @Override
1079
        @Transactional(readOnly = true)
1080
        public DrugIngredient getDrugIngredientByUuid(String uuid) {
1081
                return dao.getDrugIngredientByUuid(uuid);
1✔
1082
        }
1083
        
1084
        /**
1085
         * @see org.openmrs.api.ConceptService#getConceptDescriptionByUuid(java.lang.String)
1086
         */
1087
        @Override
1088
        @Transactional(readOnly = true)
1089
        public ConceptDescription getConceptDescriptionByUuid(String uuid) {
1090
                return dao.getConceptDescriptionByUuid(uuid);
1✔
1091
        }
1092
        
1093
        /**
1094
         * @see org.openmrs.api.ConceptService#getConceptNameTagByUuid(java.lang.String)
1095
         */
1096
        @Override
1097
        @Transactional(readOnly = true)
1098
        public ConceptNameTag getConceptNameTagByUuid(String uuid) {
1099
                return dao.getConceptNameTagByUuid(uuid);
1✔
1100
        }
1101
        
1102
        /**
1103
         * @see org.openmrs.api.ConceptService#getAllConceptNameTags()
1104
         */
1105
        @Override
1106
        @Transactional(readOnly = true)
1107
        public List<ConceptNameTag> getAllConceptNameTags() {
1108
                return dao.getAllConceptNameTags();
1✔
1109
        }
1110
        
1111
        /**
1112
         * @see org.openmrs.api.ConceptService#getConceptNameTag(java.lang.Integer)
1113
         */
1114
        @Override
1115
        @Transactional(readOnly = true)
1116
        public ConceptNameTag getConceptNameTag(Integer id) {
1117
                return dao.getConceptNameTag(id);
1✔
1118
        }
1119
        
1120
        /**
1121
         * @see org.openmrs.api.ConceptService#getConceptByMapping(java.lang.String, java.lang.String)
1122
         */
1123
        @Override
1124
        @Transactional(readOnly = true)
1125
        public Concept getConceptByMapping(String code, String sourceName) throws APIException {
1126
                return Context.getConceptService().getConceptByMapping(code, sourceName, true);
1✔
1127
        }
1128
        
1129
        /**
1130
         * @see org.openmrs.api.ConceptService#getConceptByMapping(java.lang.String, java.lang.String,
1131
         *      java.lang.Boolean)
1132
         */
1133
        @Override
1134
        @Transactional(readOnly = true)
1135
        public Concept getConceptByMapping(String code, String sourceName, Boolean includeRetired) throws APIException {
1136
                List<Concept> concepts = Context.getConceptService().getConceptsByMapping(code, sourceName, includeRetired);
1✔
1137
                
1138
                if (concepts.isEmpty()) {
1✔
1139
                        return null;
1✔
1140
                }
1141
                // we want to throw an exception if there is more than one non-retired concept; 
1142
                // since the getConceptByMapping DAO method returns a list with all non-retired concept
1143
                // sorted to the front of the list, we can test if there is more than one retired concept
1144
                // by testing if the second concept in the list is retired or not
1145
                else if (concepts.size() > 1 && !concepts.get(1).getRetired()) {
1✔
1146
                        throw new APIException("Concept.error.multiple.non.retired", new Object[] { code, sourceName });
1✔
1147
                } else {
1148
                        return concepts.get(0);
1✔
1149
                }
1150
        }
1151
        
1152
        /**
1153
         * @see org.openmrs.api.ConceptService#getConceptsByMapping(java.lang.String, java.lang.String)
1154
         */
1155
        @Override
1156
        @Transactional(readOnly = true)
1157
        public List<Concept> getConceptsByMapping(String code, String sourceName) throws APIException {
1158
                return Context.getConceptService().getConceptsByMapping(code, sourceName, true);
1✔
1159
        }
1160
        
1161
        /**
1162
         * @see org.openmrs.api.ConceptService#getConceptsByMapping(java.lang.String, java.lang.String, boolean)
1163
         */
1164
        @Override
1165
        @Transactional(readOnly = true)
1166
        public List<Concept> getConceptsByMapping(String code, String sourceName, boolean includeRetired) throws APIException {
1167
                List<Concept> concepts = new ArrayList<>();
1✔
1168
                for (Integer conceptId : Context.getConceptService().getConceptIdsByMapping(code, sourceName, includeRetired)) {
1✔
1169
                        concepts.add(getConcept(conceptId));
1✔
1170
                }
1✔
1171
                return concepts;
1✔
1172
        }
1173

1174
        /**
1175
         * @see org.openmrs.api.ConceptService#getConceptIdsByMapping(java.lang.String, java.lang.String, boolean)
1176
         */
1177
        @Override
1178
        @Transactional(readOnly = true)
1179
        @Cacheable(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME)
1180
        public List<Integer> getConceptIdsByMapping(String code, String sourceName, boolean includeRetired) throws APIException {
1181
                return dao.getConceptIdsByMapping(code, sourceName, includeRetired);
1✔
1182
        }
1183
        
1184
        /**
1185
         * @see org.openmrs.api.ConceptService#getFalseConcept()
1186
         */
1187
        @Override
1188
        @Transactional(readOnly = true)
1189
        public Concept getFalseConcept() {
1190
                if (falseConcept == null) {
1✔
UNCOV
1191
                        setBooleanConcepts();
×
1192
                }
1193
                
1194
                return falseConcept;
1✔
1195
        }
1196
        
1197
        /**
1198
         * @see org.openmrs.api.ConceptService#getTrueConcept()
1199
         */
1200
        @Override
1201
        @Transactional(readOnly = true)
1202
        public Concept getTrueConcept() {
1203
                if (trueConcept == null) {
1✔
1204
                        setBooleanConcepts();
1✔
1205
                }
1206
                
1207
                return trueConcept;
1✔
1208
        }
1209
        
1210
        /**
1211
         * @see org.openmrs.api.ConceptService#getUnknownConcept()
1212
         */
1213
        @Override
1214
        @Transactional(readOnly = true)
1215
        public Concept getUnknownConcept() {
1216
                if (unknownConcept == null) {
1✔
1217
                        try {
1218
                                Concept unknownConcept = Context.getConceptService().getConcept(
1✔
1219
                                        Integer.parseInt(Context.getAdministrationService().getGlobalProperty(
1✔
1220
                                                OpenmrsConstants.GLOBAL_PROPERTY_UNKNOWN_CONCEPT)));
1221
                                initializeLazyPropertiesForConcept(unknownConcept);
1✔
1222
                                
1223
                                ConceptServiceImpl.setStaticUnknownConcept(unknownConcept);
1✔
1224
                        }
1225
                        catch (NumberFormatException e) {
×
1226
                                log.warn("Concept id for unknown concept should be a number");
×
1227
                        }
1✔
1228
                }
1229
                
1230
                return unknownConcept;
1✔
1231
        }
1232
        
1233
        /**
1234
         * Sets unknownConcept using static method
1235
         *
1236
         * @param currentUnknownConcept
1237
         */
1238
        private static void setStaticUnknownConcept(Concept currentUnknownConcept) {
1239
                ConceptServiceImpl.unknownConcept = currentUnknownConcept;
1✔
1240
        }
1✔
1241
        
1242
        /**
1243
         * Sets the TRUE and FALSE concepts by reading their ids from the global_property table
1244
         */
1245
        private void setBooleanConcepts() {
1246
                
1247
                try {
1248
                        trueConcept = Context.getConceptService().getConcept(
1✔
1249
                            Integer.parseInt(Context.getAdministrationService().getGlobalProperty(
1✔
1250
                                OpenmrsConstants.GLOBAL_PROPERTY_TRUE_CONCEPT)));
1251
                        initializeLazyPropertiesForConcept(trueConcept);
1✔
1252
                        
1253
                        falseConcept = Context.getConceptService().getConcept(
1✔
1254
                            Integer.parseInt(Context.getAdministrationService().getGlobalProperty(
1✔
1255
                                OpenmrsConstants.GLOBAL_PROPERTY_FALSE_CONCEPT)));
1256
                        initializeLazyPropertiesForConcept(falseConcept);
1✔
1257
                }
1258
                catch (NumberFormatException e) {
×
1259
                        log.warn("Concept ids for boolean concepts should be numbers");
×
1260
                }
1✔
1261
        }
1✔
1262

1263
        private void initializeLazyPropertiesForConcept(Concept concept) {
1264
                Hibernate.initialize(concept.getRetiredBy());
1✔
1265
                Hibernate.initialize(concept.getCreator());
1✔
1266
                Hibernate.initialize(concept.getChangedBy());
1✔
1267
                Hibernate.initialize(concept.getNames());
1✔
1268
                Hibernate.initialize(concept.getAnswers());
1✔
1269
                Hibernate.initialize(concept.getConceptSets());
1✔
1270
                Hibernate.initialize(concept.getDescriptions());
1✔
1271
                Hibernate.initialize(concept.getConceptMappings());
1✔
1272
                Hibernate.initialize(concept.getAttributes());
1✔
1273
        }
1✔
1274

1275
        /**
1276
         * @see org.openmrs.api.ConceptService#getConceptSourceByName(java.lang.String)
1277
         */
1278
        @Override
1279
        @Transactional(readOnly = true)
1280
        public ConceptSource getConceptSourceByName(String conceptSourceName) throws APIException {
1281
                return dao.getConceptSourceByName(conceptSourceName);
1✔
1282
        }
1283

1284
        /**
1285
         * @see org.openmrs.api.ConceptService#getConceptSourceByUniqueId(java.lang.String)
1286
         */
1287
        @Override
1288
        @Transactional(readOnly = true)
1289
        public ConceptSource getConceptSourceByUniqueId(String uniqueId) throws APIException {
1290
                if (uniqueId == null) {
1✔
1291
                        throw new IllegalArgumentException("uniqueId is required");
1✔
1292
                }
1293
                return dao.getConceptSourceByUniqueId(uniqueId);
1✔
1294
        }
1295

1296
        /**
1297
         * @see org.openmrs.api.ConceptService#getConceptSourceByHL7Code(java.lang.String)
1298
         */
1299
        @Override
1300
        @Transactional(readOnly = true)
1301
        public ConceptSource getConceptSourceByHL7Code(String hl7Code) throws APIException {
1302
                if (hl7Code == null) {
1✔
1303
                        throw new IllegalArgumentException("hl7Code is required");
1✔
1304
                }
1305
                return dao.getConceptSourceByHL7Code(hl7Code);
1✔
1306
        }
1307

1308
        /**
1309
         * Utility method to check if the concept is already attached to an observation (including
1310
         * voided ones) and if the datatype of the concept has changed, an exception indicating that the
1311
         * datatype cannot be modified will be reported if the concept is attached to an observation.
1312
         * This method will only allow changing boolean concepts to coded.
1313
         * 
1314
         * @param concept
1315
         * @throws ConceptInUseException
1316
         */
1317
        private void checkIfDatatypeCanBeChanged(Concept concept) {
1318
                if (concept.getId() != null && hasAnyObservation(concept) && hasDatatypeChanged(concept)) {
1✔
1319
                        // allow boolean concepts to be converted to coded
1320
                        if (!(dao.getSavedConceptDatatype(concept).isBoolean() && concept.getDatatype().isCoded())) {
1✔
1321
                                throw new ConceptInUseException();
1✔
1322
                        }
1323
                        log.debug("Converting datatype of concept with id {} from Boolean to coded", concept.getConceptId());
1✔
1324
                }
1325
        }
1✔
1326
        
1327
        /**
1328
         * Utility method which loads the previous version of a concept to check if the datatype has
1329
         * changed.
1330
         * 
1331
         * @param concept to be modified
1332
         * @return boolean indicating change in the datatype
1333
         */
1334
        private boolean hasDatatypeChanged(Concept concept) {
1335
                ConceptDatatype oldConceptDatatype = dao.getSavedConceptDatatype(concept);
1✔
1336
                return !oldConceptDatatype.equals(concept.getDatatype());
1✔
1337
        }
1338
        
1339
        /**
1340
         * @see org.openmrs.api.ConceptService#hasAnyObservation(org.openmrs.Concept)
1341
         */
1342
        @Override
1343
        @Transactional(readOnly = true)
1344
        public boolean hasAnyObservation(Concept concept) {
1345
                List<Concept> concepts = new ArrayList<>();
1✔
1346
                concepts.add(concept);
1✔
1347
                Integer count = Context.getObsService().getObservationCount(null, null, concepts, null, null, null, null, null,
1✔
1348
                    null, true);
1349
                return count > 0;
1✔
1350
        }
1351
        
1352
        /**
1353
         * @see org.openmrs.api.ConceptService#convertBooleanConceptToCoded(org.openmrs.Concept)
1354
         */
1355
        @Override
1356
        public void convertBooleanConceptToCoded(Concept conceptToChange) throws APIException {
1357
                if (conceptToChange != null) {
1✔
1358
                        if (!conceptToChange.getDatatype().isBoolean()) {
1✔
1359
                                throw new APIException("Concept.datatype.invalid", (Object[]) null);
1✔
1360
                        }
1361
                        
1362
                        conceptToChange.setDatatype(getConceptDatatypeByName("Coded"));
1✔
1363
                        conceptToChange.addAnswer(new ConceptAnswer(getTrueConcept()));
1✔
1364
                        conceptToChange.addAnswer(new ConceptAnswer(getFalseConcept()));
1✔
1365
                        Context.getConceptService().saveConcept(conceptToChange);
1✔
1366
                }
1367
        }
1✔
1368
        
1369
        /**
1370
         * @see org.openmrs.api.ConceptService#hasAnyObservation(org.openmrs.ConceptName)
1371
         */
1372
        @Override
1373
        @Transactional(readOnly = true)
1374
        public boolean hasAnyObservation(ConceptName conceptName) throws APIException {
1375
                List<ConceptName> conceptNames = new ArrayList<>();
1✔
1376
                conceptNames.add(conceptName);
1✔
1377
                Integer count = Context.getObsService().getObservationCount(conceptNames, true);
1✔
1378
                return count > 0;
1✔
1379
        }
1380
        
1381
        /**
1382
         * Utility method which loads the previous version of a conceptName to check if the name
1383
         * property of the given conceptName has changed.
1384
         * 
1385
         * @param conceptName to be modified
1386
         * @return boolean indicating change in the name property
1387
         */
1388
        private boolean hasNameChanged(ConceptName conceptName) {
1389
                String newName = conceptName.getName();
1✔
1390
                String oldName = dao.getSavedConceptName(conceptName).getName();
1✔
1391
                return !oldName.equalsIgnoreCase(newName);
1✔
1392
        }
1393
        
1394
        /**
1395
         * Creates a copy of a conceptName
1396
         * 
1397
         * @param conceptName the conceptName to be cloned
1398
         * @return the cloned conceptName
1399
         */
1400
        private ConceptName cloneConceptName(ConceptName conceptName) {
1401
                ConceptName copy = new ConceptName();
1✔
1402
                try {
1403
                        copy = (ConceptName) BeanUtils.cloneBean(conceptName);
1✔
1404
                }
1405
                catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException e) {
×
1406
                        
1407
                        log.warn(ERROR_MESSAGE, e);
×
1408
                }
1✔
1409
                return copy;
1✔
1410
        }
1411
        
1412
        /**
1413
         * @see ConceptService#findConceptAnswers(String, Locale, Concept)
1414
         */
1415
        @Override
1416
        @Transactional(readOnly = true)
1417
        public List<ConceptSearchResult> findConceptAnswers(String phrase, Locale locale, Concept concept) throws APIException {
1418

1419
                return getConcepts(phrase, Collections.singletonList(locale), false, null, null, null, null,
1✔
1420
                    concept, null, null);
1421
        }
1422
        
1423
        /**
1424
         * @see org.openmrs.api.ConceptService#getConceptStopWords(java.util.Locale)
1425
         */
1426
        @Override
1427
        @Transactional(readOnly = true)
1428
        public List<String> getConceptStopWords(Locale locale) {
1429
                return dao.getConceptStopWords(locale);
1✔
1430
        }
1431
        
1432
        /**
1433
         * @see org.openmrs.api.ConceptService#saveConceptStopWord(org.openmrs.ConceptStopWord)
1434
         */
1435
        @Override
1436
        public ConceptStopWord saveConceptStopWord(ConceptStopWord conceptStopWord) throws APIException {
1437
                try {
1438
                        return dao.saveConceptStopWord(conceptStopWord);
1✔
1439
                }
1440
                catch (DAOException e) {
1✔
1441
                        if ("Duplicate ConceptStopWord Entry".equalsIgnoreCase(e.getMessage())) {
1✔
1442
                                throw new ConceptStopWordException("ConceptStopWord.duplicated", e);
1✔
1443
                        }
1444
                        throw new ConceptStopWordException("ConceptStopWord.notSaved", e);
×
1445
                }
1446
        }
1447
        
1448
        /**
1449
         * @see org.openmrs.api.ConceptService#deleteConceptStopWord(Integer)
1450
         */
1451
        @Override
1452
        public void deleteConceptStopWord(Integer conceptStopWordId) throws APIException {
1453
                try {
1454
                        dao.deleteConceptStopWord(conceptStopWordId);
1✔
1455
                }
1456
                catch (DAOException e) {
×
1457
                        if (contains(e.getMessage(), "Concept Stop Word not found or already deleted")) {
×
1458
                                throw new ConceptStopWordException("ConceptStopWord.error.notfound", e);
×
1459
                        }
1460
                        throw new ConceptStopWordException("general.cannot.delete", e);
×
1461
                }
1✔
1462
        }
1✔
1463
        
1464
        /**
1465
         * @see org.openmrs.api.ConceptService#getAllConceptStopWords()
1466
         */
1467
        @Override
1468
        @Transactional(readOnly = true)
1469
        public List<ConceptStopWord> getAllConceptStopWords() {
1470
                return dao.getAllConceptStopWords();
1✔
1471
        }
1472
        
1473
        /**
1474
         * @see ConceptService#getConcepts(String, List, boolean, List, List, List, List, Concept,
1475
         *      Integer, Integer)
1476
         */
1477
        @Override
1478
        @Transactional(readOnly = true)
1479
        public List<ConceptSearchResult> getConcepts(String phrase, List<Locale> locales, boolean includeRetired,
1480
                List<ConceptClass> requireClasses, List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1481
                List<ConceptDatatype> excludeDatatypes, Concept answersToConcept, Integer start, Integer size)
1482
                throws APIException {
1483

1484
                List<ConceptClass> tmpRequireClasses = requireClasses == null ? new ArrayList<>() : requireClasses;
1✔
1485
                List<ConceptClass> tmpExcludeClasses = excludeClasses == null ? new ArrayList<>() : excludeClasses;
1✔
1486
                List<ConceptDatatype> tmpRequireDatatypes = requireDatatypes == null ? new ArrayList<>() : requireDatatypes;
1✔
1487
                List<ConceptDatatype> tmpExcludeDatatypes = excludeDatatypes == null ? new ArrayList<>() : excludeDatatypes;
1✔
1488
                
1489
                return dao.getConcepts(phrase, locales, includeRetired, tmpRequireClasses, tmpExcludeClasses, tmpRequireDatatypes,
1✔
1490
                    tmpExcludeDatatypes, answersToConcept, start, size);
1491
                
1492
        }
1493
        
1494
        /**
1495
         * @see ConceptService#updateConceptIndex(Concept)
1496
         */
1497
        @Override
1498
        public void updateConceptIndex(Concept concept) throws APIException {
1499
                Context.updateSearchIndexForObject(concept);
×
1500
        }
×
1501
        
1502
        /**
1503
         * @see ConceptService#updateConceptIndexes()
1504
         */
1505
        @Override
1506
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
1507
        public void updateConceptIndexes() throws APIException {
1508
                Context.updateSearchIndexForType(ConceptName.class);
×
1509
        }
×
1510
        
1511
        /**
1512
         * @see ConceptService#getCountOfConcepts(String, List, boolean, List, List, List, List,
1513
         *      Concept)
1514
         */
1515
        @Override
1516
        @Transactional(readOnly = true)
1517
        public Integer getCountOfConcepts(String phrase, List<Locale> locales, boolean includeRetired,
1518
                List<ConceptClass> requireClasses, List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1519
                List<ConceptDatatype> excludeDatatypes, Concept answersToConcept) {
1520

1521
                List<ConceptClass> tmpRequireClasses = requireClasses == null ? new ArrayList<>() : requireClasses;
1✔
1522
                List<ConceptClass> tmpExcludeClasses = excludeClasses == null ? new ArrayList<>() : excludeClasses;
1✔
1523
                List<ConceptDatatype> tmpRequireDatatypes = requireDatatypes == null ? new ArrayList<>() : requireDatatypes;
1✔
1524
                List<ConceptDatatype> tmpExcludeDatatypes = excludeDatatypes == null ? new ArrayList<>() : excludeDatatypes;
1✔
1525
                
1526
                return dao.getCountOfConcepts(phrase, locales, includeRetired, tmpRequireClasses, tmpExcludeClasses, tmpRequireDatatypes,
1✔
1527
                    tmpExcludeDatatypes, answersToConcept);
1528
        }
1529
        
1530
        /**
1531
         * @see ConceptService#getCountOfDrugs(String, Concept, boolean, boolean, boolean)
1532
         */
1533
        @Override
1534
        @Transactional(readOnly = true)
1535
        public Integer getCountOfDrugs(String drugName, Concept concept, boolean searchOnPhrase, boolean searchDrugConceptNames,
1536
                boolean includeRetired) throws APIException {
1537
                return OpenmrsUtil.convertToInteger(dao.getCountOfDrugs(drugName, concept, searchOnPhrase, searchDrugConceptNames,
1✔
1538
                    includeRetired));
1539
        }
1540
        
1541
        /**
1542
         * @see ConceptService#getDrugs(String, Concept, boolean, boolean, boolean, Integer, Integer)
1543
         */
1544
        @Override
1545
        @Transactional(readOnly = true)
1546
        public List<Drug> getDrugs(String drugName, Concept concept, boolean searchOnPhrase, boolean searchDrugConceptNames,
1547
                boolean includeRetired, Integer start, Integer length) throws APIException {
1548
                return dao.getDrugs(drugName, concept, searchOnPhrase, searchDrugConceptNames, includeRetired, start, length);
1✔
1549
        }
1550
        
1551
        /**
1552
         * @see ConceptService#getConcepts(String, Locale, boolean)
1553
         */
1554
        @Override
1555
        @Transactional(readOnly = true)
1556
        public List<ConceptSearchResult> getConcepts(String phrase, Locale locale, boolean includeRetired) throws APIException {
1557
                List<Locale> locales = new ArrayList<>();
1✔
1558
                if (locale != null) {
1✔
1559
                        locales.add(locale);
1✔
1560
                }
1561
                
1562
                return Context.getConceptService().getConcepts(phrase, locales, includeRetired, null, null, null, null, null, null,
1✔
1563
                    null);
1564
        }
1565
        
1566
        /**
1567
         * @see org.openmrs.api.ConceptService#getDrugsByIngredient(org.openmrs.Concept)
1568
         */
1569
        @Override
1570
        @Transactional(readOnly = true)
1571
        public List<Drug> getDrugsByIngredient(Concept ingredient) throws APIException {
1572
                if (ingredient == null) {
1✔
1573
                        throw new IllegalArgumentException("ingredient is required");
1✔
1574
                }
1575
                
1576
                return dao.getDrugsByIngredient(ingredient);
1✔
1577
        }
1578
        
1579
        /**
1580
         * @see ConceptService#getConceptMappingsToSource(ConceptSource)
1581
         */
1582
        @Override
1583
        @Transactional(readOnly = true)
1584
        public List<ConceptMap> getConceptMappingsToSource(ConceptSource conceptSource) throws APIException {
1585
                return dao.getConceptMapsBySource(conceptSource);
1✔
1586
        }
1587
        
1588
        /**
1589
         * @see ConceptService#getActiveConceptMapTypes()
1590
         */
1591
        @Override
1592
        @Transactional(readOnly = true)
1593
        public List<ConceptMapType> getActiveConceptMapTypes() throws APIException {
1594
                return Context.getConceptService().getConceptMapTypes(true, false);
1✔
1595
        }
1596
        
1597
        /**
1598
         * @see ConceptService#getConceptMapTypes(boolean, boolean)
1599
         */
1600
        @Override
1601
        @Transactional(readOnly = true)
1602
        public List<ConceptMapType> getConceptMapTypes(boolean includeRetired, boolean includeHidden) throws APIException {
1603
                return dao.getConceptMapTypes(includeRetired, includeHidden);
1✔
1604
        }
1605
        
1606
        /**
1607
         * @see ConceptService#getConceptMapType(Integer)
1608
         */
1609
        @Override
1610
        @Transactional(readOnly = true)
1611
        public ConceptMapType getConceptMapType(Integer conceptMapTypeId) throws APIException {
1612
                return dao.getConceptMapType(conceptMapTypeId);
1✔
1613
        }
1614
        
1615
        /**
1616
         * @see ConceptService#getConceptMapTypeByUuid(String)
1617
         */
1618
        @Override
1619
        @Transactional(readOnly = true)
1620
        public ConceptMapType getConceptMapTypeByUuid(String uuid) throws APIException {
1621
                return dao.getConceptMapTypeByUuid(uuid);
1✔
1622
        }
1623
        
1624
        /**
1625
         * @see org.openmrs.api.ConceptService#getConceptMapTypeByName(java.lang.String)
1626
         */
1627
        @Override
1628
        @Transactional(readOnly = true)
1629
        public ConceptMapType getConceptMapTypeByName(String name) throws APIException {
1630
                return dao.getConceptMapTypeByName(name);
1✔
1631
        }
1632
        
1633
        /**
1634
         * @see org.openmrs.api.ConceptService#saveConceptMapType(org.openmrs.ConceptMapType)
1635
         */
1636
        @Override
1637
        public ConceptMapType saveConceptMapType(ConceptMapType conceptMapType) throws APIException {
1638
                return dao.saveConceptMapType(conceptMapType);
1✔
1639
        }
1640
        
1641
        /**
1642
         * @see org.openmrs.api.ConceptService#retireConceptMapType(org.openmrs.ConceptMapType,
1643
         *      java.lang.String)
1644
         */
1645
        @Override
1646
        public ConceptMapType retireConceptMapType(ConceptMapType conceptMapType, String retireReason) throws APIException {
1647
                String tmpRetireReason = retireReason;
1✔
1648
                if (!StringUtils.hasText(tmpRetireReason)) {
1✔
1649
                        tmpRetireReason = Context.getMessageSourceService().getMessage("general.default.retireReason");
1✔
1650
                }
1651
                conceptMapType.setRetireReason(tmpRetireReason);
1✔
1652
                return dao.saveConceptMapType(conceptMapType);
1✔
1653
        }
1654
        
1655
        /**
1656
         * @see org.openmrs.api.ConceptService#unretireConceptMapType(org.openmrs.ConceptMapType)
1657
         */
1658
        @Override
1659
        public ConceptMapType unretireConceptMapType(ConceptMapType conceptMapType) throws APIException {
1660
                return Context.getConceptService().saveConceptMapType(conceptMapType);
1✔
1661
        }
1662
        
1663
        /**
1664
         * @see org.openmrs.api.ConceptService#purgeConceptMapType(org.openmrs.ConceptMapType)
1665
         */
1666
        @Override
1667
        public void purgeConceptMapType(ConceptMapType conceptMapType) throws APIException {
1668
                if (dao.isConceptMapTypeInUse(conceptMapType)) {
1✔
1669
                        throw new APIException("ConceptMapType.inUse", (Object[]) null);
×
1670
                }
1671
                dao.deleteConceptMapType(conceptMapType);
1✔
1672
        }
1✔
1673
        
1674
        /**
1675
         * @see org.openmrs.api.ConceptService#getAllConceptReferenceTerms()
1676
         */
1677
        @Override
1678
        @Transactional(readOnly = true)
1679
        public List<ConceptReferenceTerm> getAllConceptReferenceTerms() throws APIException {
1680
                return Context.getConceptService().getConceptReferenceTerms(true);
1✔
1681
        }
1682
        
1683
        /**
1684
         * @see ConceptService#getConceptReferenceTerms(boolean)
1685
         */
1686
        @Override
1687
        @Transactional(readOnly = true)
1688
        public List<ConceptReferenceTerm> getConceptReferenceTerms(boolean includeRetired) throws APIException {
1689
                return dao.getConceptReferenceTerms(includeRetired);
1✔
1690
        }
1691
        
1692
        /**
1693
         * @see org.openmrs.api.ConceptService#getConceptReferenceTerm(java.lang.Integer)
1694
         */
1695
        @Override
1696
        @Transactional(readOnly = true)
1697
        public ConceptReferenceTerm getConceptReferenceTerm(Integer conceptReferenceTermId) throws APIException {
1698
                return dao.getConceptReferenceTerm(conceptReferenceTermId);
1✔
1699
        }
1700
        
1701
        /**
1702
         * @see org.openmrs.api.ConceptService#getConceptReferenceTermByUuid(java.lang.String)
1703
         */
1704
        @Override
1705
        @Transactional(readOnly = true)
1706
        public ConceptReferenceTerm getConceptReferenceTermByUuid(String uuid) throws APIException {
1707
                return dao.getConceptReferenceTermByUuid(uuid);
1✔
1708
        }
1709
        
1710
        /**
1711
         * @see org.openmrs.api.ConceptService#getConceptReferenceTermByName(java.lang.String,
1712
         *      org.openmrs.ConceptSource)
1713
         */
1714
        @Override
1715
        @Transactional(readOnly = true)
1716
        public ConceptReferenceTerm getConceptReferenceTermByName(String name, ConceptSource conceptSource) throws APIException {
1717
                //On addition of extra attributes to concept maps, terms that were generated from existing maps have 
1718
                //empty string values for the name property, ignore the search when name is an empty string but allow 
1719
                //white space characters
1720
                if (!StringUtils.hasLength(name)) {
1✔
1721
                        return null;
1✔
1722
                }
1723
                return dao.getConceptReferenceTermByName(name, conceptSource);
1✔
1724
        }
1725
        
1726
        /**
1727
         * @see org.openmrs.api.ConceptService#getConceptReferenceTermByCode(java.lang.String,
1728
         *      org.openmrs.ConceptSource)
1729
         */
1730
        @Override
1731
        @Transactional(readOnly = true)
1732
        public ConceptReferenceTerm getConceptReferenceTermByCode(String code, ConceptSource conceptSource) throws APIException {
1733
                return dao.getConceptReferenceTermByCode(code, conceptSource);
1✔
1734
        }
1735
        
1736
        /**
1737
         * @see org.openmrs.api.ConceptService#saveConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1738
         */
1739
        @Override
1740
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
1741
        public ConceptReferenceTerm saveConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws APIException {
1742
                return dao.saveConceptReferenceTerm(conceptReferenceTerm);
1✔
1743
        }
1744
        
1745
        /**
1746
         * @see org.openmrs.api.ConceptService#retireConceptReferenceTerm(ConceptReferenceTerm, String)
1747
         */
1748
        @Override
1749
        public ConceptReferenceTerm retireConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm, String retireReason)
1750
                throws APIException {
1751
                String tmpRetireReason = retireReason;
1✔
1752
                if (!StringUtils.hasText(tmpRetireReason)) {
1✔
1753
                        tmpRetireReason = Context.getMessageSourceService().getMessage("general.default.retireReason");
1✔
1754
                }
1755
                conceptReferenceTerm.setRetireReason(tmpRetireReason);
1✔
1756
                return Context.getConceptService().saveConceptReferenceTerm(conceptReferenceTerm);
1✔
1757
        }
1758
        
1759
        /**
1760
         * @see org.openmrs.api.ConceptService#unretireConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1761
         */
1762
        @Override
1763
        public ConceptReferenceTerm unretireConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws APIException {
1764
                return Context.getConceptService().saveConceptReferenceTerm(conceptReferenceTerm);
1✔
1765
        }
1766
        
1767
        /**
1768
         * @see org.openmrs.api.ConceptService#purgeConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1769
         */
1770
        @Override
1771
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
1772
        public void purgeConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws APIException {
1773
                if (dao.isConceptReferenceTermInUse(conceptReferenceTerm)) {
1✔
1774
                        throw new APIException("ConceptRefereceTerm.inUse", (Object[]) null);
1✔
1775
                }
1776
                dao.deleteConceptReferenceTerm(conceptReferenceTerm);
1✔
1777
        }
1✔
1778
        
1779
        /**
1780
         * @see org.openmrs.api.ConceptService#getConceptReferenceTerms(java.lang.String,
1781
         *      org.openmrs.ConceptSource, java.lang.Integer, java.lang.Integer, boolean)
1782
         */
1783
        @Override
1784
        @Transactional(readOnly = true)
1785
        public List<ConceptReferenceTerm> getConceptReferenceTerms(String query, ConceptSource conceptSource, Integer start,
1786
                Integer length, boolean includeRetired) throws APIException {
1787
                Integer tmpLength = length;
1✔
1788
                if (tmpLength == null) {
1✔
1789
                        tmpLength = 10000;
1✔
1790
                }
1791
                return dao.getConceptReferenceTerms(query, conceptSource, start, tmpLength, includeRetired);
1✔
1792
        }
1793
        
1794
        /**
1795
         * @see org.openmrs.api.ConceptService#getCountOfConceptReferenceTerms(String, ConceptSource,
1796
         *      boolean)
1797
         */
1798
        @Override
1799
        @Transactional(readOnly = true)
1800
        public Integer getCountOfConceptReferenceTerms(String query, ConceptSource conceptSource, boolean includeRetired) {
1801
                return OpenmrsUtil.convertToInteger(dao.getCountOfConceptReferenceTerms(query, conceptSource, includeRetired));
1✔
1802
        }
1803
        
1804
        /**
1805
         * @see org.openmrs.api.ConceptService#getReferenceTermMappingsTo(ConceptReferenceTerm)
1806
         */
1807
        @Override
1808
        @Transactional(readOnly = true)
1809
        public List<ConceptReferenceTermMap> getReferenceTermMappingsTo(ConceptReferenceTerm term) throws APIException {
1810
                return dao.getReferenceTermMappingsTo(term);
1✔
1811
        }
1812
        
1813
        /**
1814
         * @see org.openmrs.api.ConceptService#getConceptsByName(java.lang.String, java.util.Locale,
1815
         *      java.lang.Boolean)
1816
         */
1817
        @Override
1818
        @Transactional(readOnly = true)
1819
        public List<Concept> getConceptsByName(String name, Locale locale, Boolean exactLocale) throws APIException {
1820
                return dao.getConceptsByName(name, locale, exactLocale);
1✔
1821
        }
1822
        
1823
        /**
1824
         * @see org.openmrs.api.ConceptService#getDefaultConceptMapType()
1825
         */
1826
        @Override
1827
        @Transactional(readOnly = true)
1828
        public ConceptMapType getDefaultConceptMapType() throws APIException {
1829
                //We need to fetch it in DAO since it must be done in the MANUAL fush mode to prevent pre-mature flushes.
1830
                return dao.getDefaultConceptMapType();
1✔
1831
        }
1832
        
1833
        /**
1834
         * @see org.openmrs.api.ConceptService#isConceptNameDuplicate(org.openmrs.ConceptName)
1835
         */
1836
        @Override
1837
        public boolean isConceptNameDuplicate(ConceptName name) {
1838
                return dao.isConceptNameDuplicate(name);
1✔
1839
        }
1840
        
1841
        /**
1842
         * @see ConceptService#getDrugs(String, java.util.Locale, boolean, boolean)
1843
         */
1844
        @Override
1845
        @Transactional(readOnly = true)
1846
        public List<Drug> getDrugs(String searchPhrase, Locale locale, boolean exactLocale, boolean includeRetired)
1847
                throws APIException {
1848
                if (searchPhrase == null) {
1✔
1849
                        throw new IllegalArgumentException("searchPhrase is required");
1✔
1850
                }
1851
                return dao.getDrugs(searchPhrase, locale, exactLocale, includeRetired);
1✔
1852
        }
1853
        
1854
        /**
1855
         * @see org.openmrs.api.ConceptService#getDrugsByMapping(String, ConceptSource, Collection,
1856
         *      boolean)
1857
         */
1858
        @Override
1859
        @Transactional(readOnly = true)
1860
        public List<Drug> getDrugsByMapping(String code, ConceptSource conceptSource,
1861
                Collection<ConceptMapType> withAnyOfTheseTypes, boolean includeRetired) throws APIException {
1862
                Collection<ConceptMapType> tmpWithAnyOfTheseTypes = withAnyOfTheseTypes == null ? Collections.emptyList() : withAnyOfTheseTypes;
1✔
1863

1864
                if (conceptSource == null) {
1✔
1865
                        throw new APIException("ConceptSource.is.required", (Object[]) null);
1✔
1866
                }
1867

1868
                return dao.getDrugsByMapping(code, conceptSource, tmpWithAnyOfTheseTypes, includeRetired);
1✔
1869
        }
1870
        
1871
        /**
1872
         * @see org.openmrs.api.ConceptService#getDrugByMapping(String, org.openmrs.ConceptSource, java.util.Collection)
1873
         */
1874
        @Override
1875
        @Transactional(readOnly = true)
1876
        public Drug getDrugByMapping(String code, ConceptSource conceptSource,
1877
                Collection<ConceptMapType> withAnyOfTheseTypesOrOrderOfPreference) throws APIException {
1878
                Collection<ConceptMapType> tmpWithAnyOfTheseTypesOrOrderOfPreference = withAnyOfTheseTypesOrOrderOfPreference == null
1✔
1879
                                ? Collections.emptyList() : withAnyOfTheseTypesOrOrderOfPreference;
1✔
1880

1881
                if (conceptSource == null) {
1✔
1882
                        throw new APIException("ConceptSource.is.required", (Object[]) null);
1✔
1883
                }
1884

1885
                return dao.getDrugByMapping(code, conceptSource, tmpWithAnyOfTheseTypesOrOrderOfPreference);
1✔
1886
        }
1887
        
1888
        /**
1889
         * @see org.openmrs.api.ConceptService#getOrderableConcepts(String, java.util.List, boolean,
1890
         *      Integer, Integer)
1891
         */
1892
        @Override
1893
        @Transactional(readOnly = true)
1894
        public List<ConceptSearchResult> getOrderableConcepts(String phrase, List<Locale> locales, boolean includeRetired,
1895
                Integer start, Integer length) {
1896
                List<ConceptClass> mappedClasses = getConceptClassesOfOrderTypes();
1✔
1897
                if (mappedClasses.isEmpty()) {
1✔
1898
                        return Collections.emptyList();
×
1899
                }
1900
                List<Locale> tmpLocales = locales;
1✔
1901
                if (tmpLocales == null) {
1✔
1902
                        tmpLocales = new ArrayList<>();
1✔
1903
                        tmpLocales.add(Context.getLocale());
1✔
1904
                }
1905
                return dao.getConcepts(phrase, tmpLocales, false, mappedClasses, Collections.emptyList(), Collections.emptyList(),
1✔
1906
                    Collections.emptyList(), null, start, length);
1✔
1907
        }
1908

1909
        /**
1910
         * @see ConceptService#getAllConceptAttributeTypes()
1911
         */
1912
        @Override
1913
        @Transactional(readOnly = true)
1914
        public List<ConceptAttributeType> getAllConceptAttributeTypes() {
1915
                return dao.getAllConceptAttributeTypes();
1✔
1916
        }
1917

1918
        /**
1919
         * @see org.openmrs.api.ConceptService#saveConceptAttributeType(ConceptAttributeType)
1920
         */
1921
        @Override
1922
        public ConceptAttributeType saveConceptAttributeType(ConceptAttributeType conceptAttributeType) {
1923
                return dao.saveConceptAttributeType(conceptAttributeType);
1✔
1924
        }
1925

1926
        /**
1927
         * @see org.openmrs.api.ConceptService#getConceptAttributeType(Integer)
1928
         */
1929
        @Override
1930
        @Transactional(readOnly = true)
1931
        public ConceptAttributeType getConceptAttributeType(Integer id) {
1932
                return dao.getConceptAttributeType(id);
1✔
1933
        }
1934

1935
        /**
1936
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypeByUuid(String)
1937
         */
1938
        @Override
1939
        @Transactional(readOnly = true)
1940
        public ConceptAttributeType getConceptAttributeTypeByUuid(String uuid) {
1941
                return dao.getConceptAttributeTypeByUuid(uuid);
1✔
1942
        }
1943

1944
        /**
1945
         * @see org.openmrs.api.ConceptService#purgeConceptAttributeType(ConceptAttributeType)
1946
         */
1947
        @Override
1948
        public void purgeConceptAttributeType(ConceptAttributeType conceptAttributeType) {
1949
                dao.deleteConceptAttributeType(conceptAttributeType);
1✔
1950

1951
        }
1✔
1952

1953
        /**
1954
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypes(String)
1955
         */
1956
        @Override
1957
        @Transactional(readOnly = true)
1958
        public List<ConceptAttributeType> getConceptAttributeTypes(String name) throws APIException {
1959
                return dao.getConceptAttributeTypes(name);
1✔
1960
        }
1961

1962
        /**
1963
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypeByName(String)
1964
         */
1965
        @Override
1966
        @Transactional(readOnly = true)
1967
        public ConceptAttributeType getConceptAttributeTypeByName(String exactName) {
1968
                return dao.getConceptAttributeTypeByName(exactName);
1✔
1969
        }
1970

1971
        /**
1972
         * @see org.openmrs.api.ConceptService#retireConceptAttributeType(ConceptAttributeType, String)
1973
         */
1974
        @Override
1975
        public ConceptAttributeType retireConceptAttributeType(ConceptAttributeType conceptAttributeType, String reason) {
1976
                return dao.saveConceptAttributeType(conceptAttributeType);
1✔
1977
        }
1978

1979
        /**
1980
         * @see org.openmrs.api.ConceptService#unretireConceptAttributeType(ConceptAttributeType)
1981
         */
1982
        @Override
1983
        public ConceptAttributeType unretireConceptAttributeType(ConceptAttributeType conceptAttributeType) {
1984
                return Context.getConceptService().saveConceptAttributeType(conceptAttributeType);
1✔
1985
        }
1986

1987
        /**
1988
         * @see org.openmrs.api.ConceptService#getConceptAttributeByUuid(String)
1989
         */
1990
        @Override
1991
        @Transactional(readOnly = true)
1992
        public ConceptAttribute getConceptAttributeByUuid(String uuid) {
1993
                return dao.getConceptAttributeByUuid(uuid);
1✔
1994
        }
1995

1996
        /**
1997
         * @see org.openmrs.api.ConceptService#hasAnyConceptAttribute(ConceptAttributeType)
1998
         */
1999
        @Override
2000
        @Transactional(readOnly = true)
2001
        public boolean hasAnyConceptAttribute(ConceptAttributeType conceptAttributeType) {
2002
                return dao.getConceptAttributeCount(conceptAttributeType) > 0;
1✔
2003
        }
2004

2005
        private List<ConceptClass> getConceptClassesOfOrderTypes() {
2006
                List<ConceptClass> mappedClasses = new ArrayList<>();
1✔
2007
                AdministrationService administrationService = Context.getAdministrationService();
1✔
2008
                List<List<Object>> result = administrationService.executeSQL(
1✔
2009
                    "SELECT DISTINCT concept_class_id FROM order_type_class_map", true);
2010
                for (List<Object> temp : result) {
1✔
2011
                        for (Object value : temp) {
1✔
2012
                                if (value != null) {
1✔
2013
                                        mappedClasses.add(this.getConceptClass((Integer) value));
1✔
2014
                                }
2015
                        }
1✔
2016
                }
1✔
2017
                return mappedClasses;
1✔
2018
        }
2019
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc