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

openmrs / openmrs-core / 16206128513

10 Jul 2025 09:12PM UTC coverage: 65.359% (+0.002%) from 65.357%
16206128513

push

github

web-flow
maven(deps): bump org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0 (#5126)

Bumps org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-lang3
  dependency-version: 3.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

23547 of 36027 relevant lines covered (65.36%)

0.65 hits per line

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

92.87
/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 java.lang.reflect.Field;
13
import java.lang.reflect.InvocationTargetException;
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.Date;
18
import java.util.HashMap;
19
import java.util.HashSet;
20
import java.util.Iterator;
21
import java.util.List;
22
import java.util.Locale;
23
import java.util.Map;
24
import java.util.Set;
25
import java.util.UUID;
26

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

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

97
        private static final String ERROR_MESSAGE = "Error generated";
98

99
        private static final String CONCEPT_IDS_BY_MAPPING_CACHE_NAME = "conceptIdsByMapping";
100

101
        /**
102
         * @see org.openmrs.api.ConceptService#setConceptDAO(org.openmrs.api.db.ConceptDAO)
103
         */
104
        @Override
105
        public void setConceptDAO(ConceptDAO dao) {
106
                this.dao = dao;
1✔
107
        }
1✔
108

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

123
                CustomDatatypeUtil.saveAttributesIfNecessary(concept);
1✔
124

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

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

189
                return dao.saveConcept(concept);
1✔
190
        }
191

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

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

213
        private void makeLocaleNotPreferred(ConceptName conceptName) {
214
                if (conceptName.getLocalePreferred()) {
1✔
215
                        conceptName.setLocalePreferred(false);
1✔
216
                }
217
        }
1✔
218

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

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

234
                        //getPreferredName(locale) returns any name marked preferred,
235
                        //or the fullySpecifiedName even if not marked preferred
236
                        ConceptName possiblePreferredName = concept.getPreferredName(locale);
1✔
237

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

247
                        if (possiblePreferredName != null) { //there may have been none
1✔
248
                                possiblePreferredName.setLocalePreferred(true);
1✔
249
                        }
250
                        checkedLocales.add(locale);
1✔
251
                }
1✔
252
        }
1✔
253

254
        private void logConceptChangedData(Concept concept) {
255
                concept.setDateChanged(new Date());
1✔
256
                concept.setChangedBy(Context.getAuthenticatedUser());
1✔
257
        }
1✔
258

259
        /**
260
         * @see org.openmrs.api.ConceptService#saveDrug(org.openmrs.Drug)
261
         */
262
        @Override
263
        public Drug saveDrug(Drug drug) throws APIException {
264
                checkIfLocked();
1✔
265
                return dao.saveDrug(drug);
1✔
266
        }
267
        
268
        /**
269
         * @see org.openmrs.api.ConceptService#purgeConcept(Concept)
270
         */
271
        @Override
272
        public void purgeConcept(Concept concept) throws APIException {
273
                checkIfLocked();
1✔
274
                
275
                if (concept.getConceptId() != null) {
1✔
276
                        for (ConceptName conceptName : concept.getNames()) {
1✔
277
                                if (hasAnyObservation(conceptName)) {
1✔
278
                                        throw new ConceptNameInUseException("Can't delete concept with id : " + concept.getConceptId()
1✔
279
                                                + " because it has a name '" + conceptName.getName()
1✔
280
                                                + "' which is being used by some observation(s)");
281
                                }
282
                        }
1✔
283
                }
284
                
285
                dao.purgeConcept(concept);
1✔
286
        }
1✔
287
        
288
        /**
289
         * @see org.openmrs.api.ConceptService#retireConcept(org.openmrs.Concept, java.lang.String)
290
         */
291
        @Override
292
        public Concept retireConcept(Concept concept, String reason) throws APIException {
293
                if (StringUtils.isBlank(reason)) {
1✔
294
                        throw new IllegalArgumentException(Context.getMessageSourceService().getMessage("general.voidReason.empty"));
1✔
295
                }
296
                
297
                // only do this if the concept isn't retired already
298
                if (!concept.getRetired()) {
1✔
299
                        checkIfLocked();
×
300
                        
301
                        concept.setRetired(true);
×
302
                        concept.setRetireReason(reason);
×
303
                        return Context.getConceptService().saveConcept(concept);
×
304
                }
305
                
306
                return concept;
1✔
307
        }
308
        
309
        /**
310
         * @see org.openmrs.api.ConceptService#retireDrug(org.openmrs.Drug, java.lang.String)
311
         * @throws APIException
312
         */
313
        @Override
314
        public Drug retireDrug(Drug drug, String reason) throws APIException {
315
                return dao.saveDrug(drug);
1✔
316
        }
317
        
318
        /**
319
         * @see org.openmrs.api.ConceptService#unretireDrug(org.openmrs.Drug)
320
         */
321
        @Override
322
        public Drug unretireDrug(Drug drug) throws APIException {
323
                return Context.getConceptService().saveDrug(drug);
1✔
324
        }
325
        
326
        /**
327
         * @see org.openmrs.api.ConceptService#purgeDrug(org.openmrs.Drug)
328
         * @throws APIException
329
         */
330
        @Override
331
        public void purgeDrug(Drug drug) throws APIException {
332
                dao.purgeDrug(drug);
1✔
333
        }
1✔
334
        
335
        /**
336
         * @see org.openmrs.api.ConceptService#getConcept(java.lang.Integer)
337
         */
338
        @Override
339
        @Transactional(readOnly = true)
340
        public Concept getConcept(Integer conceptId) throws APIException {
341
                return dao.getConcept(conceptId);
1✔
342
        }
343

344
        /**
345
         * @see org.openmrs.api.ConceptService#getConceptByReference(String conceptRef)
346
         */
347
        @Override
348
        @Transactional(readOnly = true)
349
        public Concept getConceptByReference(String conceptRef) {
350
                if (StringUtils.isBlank(conceptRef)) {
1✔
351
                        return null;
1✔
352
                }
353
                Concept cpt = null;
1✔
354
                //check if input is a valid Uuid
355
                if (isValidUuidFormat(conceptRef)) {
1✔
356
                        cpt = Context.getConceptService().getConceptByUuid(conceptRef);
1✔
357
                        if (cpt != null) {
1✔
358
                                return cpt;
1✔
359
                        }
360
                }
361
                //handle mapping
362
                int idx = conceptRef.indexOf(":");
1✔
363
                if (idx >= 0 && idx < conceptRef.length() - 1) {
1✔
364
                        String conceptSource = conceptRef.substring(0, idx);
1✔
365
                        String conceptCode = conceptRef.substring(idx + 1);
1✔
366
                        cpt = Context.getConceptService().getConceptByMapping(conceptCode, conceptSource);
1✔
367
                        if (cpt != null) {
1✔
368
                                return cpt;
1✔
369
                        }
370
                }
371
                //handle id
372
                int conceptId = NumberUtils.toInt(conceptRef, -1);
1✔
373
                if (conceptId >= 0) {
1✔
374
                        cpt = Context.getConceptService().getConcept(conceptId);
1✔
375
                        if (cpt != null) {
1✔
376
                                return cpt;
1✔
377
                        }
378
                } else {
379
                        //handle name
380
                        cpt = Context.getConceptService().getConceptByName(conceptRef);
1✔
381
                        if (cpt != null) {
1✔
382
                                return cpt;
1✔
383
                        }
384
                }
385
                //handle static constant
386
                if (conceptRef.contains(".")) {
1✔
387
                        try {
388
                                return getConceptByReference(evaluateStaticConstant(conceptRef));
1✔
389
                        }
390
                        catch (APIException e) {
×
391
                                log.warn("Unable to translate '{}' into a concept", conceptRef, e);
×
392
                        }
393
                }
394
                return cpt == null ? null : cpt;
1✔
395
        }
396
        
397
        /**
398
         * @see org.openmrs.api.ConceptService#getConceptName(java.lang.Integer)
399
         */
400
        @Override
401
        @Transactional(readOnly = true)
402
        public ConceptName getConceptName(Integer conceptNameId) throws APIException {
403
                return dao.getConceptName(conceptNameId);
1✔
404
        }
405
        
406
        /**
407
         * @see org.openmrs.api.ConceptService#getConceptAnswer(java.lang.Integer)
408
         */
409
        @Override
410
        @Transactional(readOnly = true)
411
        public ConceptAnswer getConceptAnswer(Integer conceptAnswerId) throws APIException {
412
                return dao.getConceptAnswer(conceptAnswerId);
1✔
413
        }
414
        
415
        /**
416
         * @see org.openmrs.api.ConceptService#getDrug(java.lang.Integer)
417
         */
418
        @Override
419
        @Transactional(readOnly = true)
420
        public Drug getDrug(Integer drugId) throws APIException {
421
                return dao.getDrug(drugId);
1✔
422
        }
423
        
424
        /**
425
         * @see org.openmrs.api.ConceptService#getConceptNumeric(java.lang.Integer)
426
         */
427
        @Override
428
        @Transactional(readOnly = true)
429
        public ConceptNumeric getConceptNumeric(Integer conceptId) throws APIException {
430
                return dao.getConceptNumeric(conceptId);
1✔
431
        }
432
        
433
        /**
434
         * @see org.openmrs.api.ConceptService#getConceptComplex(java.lang.Integer)
435
         */
436
        @Override
437
        @Transactional(readOnly = true)
438
        public ConceptComplex getConceptComplex(Integer conceptId) {
439
                return dao.getConceptComplex(conceptId);
1✔
440
        }
441
        
442
        /**
443
         * @see org.openmrs.api.ConceptService#getAllConcepts()
444
         */
445
        @Override
446
        @Transactional(readOnly = true)
447
        public List<Concept> getAllConcepts() throws APIException {
448
                return Context.getConceptService().getAllConcepts(null, true, true);
1✔
449
        }
450
        
451
        /**
452
         * @see org.openmrs.api.ConceptService#getAllConcepts(java.lang.String, boolean, boolean)
453
         */
454
        @Override
455
        @Transactional(readOnly = true)
456
        public List<Concept> getAllConcepts(String sortBy, boolean asc, boolean includeRetired) throws APIException {
457
                String tmpSortBy = sortBy == null ? "conceptId" : sortBy;
1✔
458
                
459
                return dao.getAllConcepts(tmpSortBy, asc, includeRetired);
1✔
460
        }
461

462
        /**
463
         * @see org.openmrs.api.ConceptService#getConceptsByName(java.lang.String)
464
         */
465
        @Override
466
        @Transactional(readOnly = true)
467
        public List<Concept> getConceptsByName(String name) throws APIException {
468
                return getConcepts(name, Context.getLocale(), true, null, null);
1✔
469
        }
470
        
471
        /**
472
         * @see org.openmrs.api.ConceptService#getConceptByName(java.lang.String)
473
         */
474
        @Override
475
        @Transactional(readOnly = true)
476
        public Concept getConceptByName(String name) {
477
                if (StringUtils.isBlank(name)) {
1✔
478
                        return null;
1✔
479
                }
480
                return dao.getConceptByName(name);
1✔
481
        }
482

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

1231
        /**
1232
         * @see org.openmrs.api.ConceptService#getConceptIdsByMapping(java.lang.String, java.lang.String, boolean)
1233
         */
1234
        @Override
1235
        @Transactional(readOnly = true)
1236
        @Cacheable(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME)
1237
        public List<Integer> getConceptIdsByMapping(String code, String sourceName, boolean includeRetired) throws APIException {
1238
                return dao.getConceptIdsByMapping(code, sourceName, includeRetired);
1✔
1239
        }
1240
        
1241
        /**
1242
         * @see org.openmrs.api.ConceptService#getFalseConcept()
1243
         */
1244
        @Override
1245
        @Transactional(readOnly = true)
1246
        public Concept getFalseConcept() {
1247
                if (falseConcept == null) {
1✔
1248
                        setBooleanConcepts();
1✔
1249
                }
1250
                
1251
                return falseConcept;
1✔
1252
        }
1253
        
1254
        /**
1255
         * @see org.openmrs.api.ConceptService#getTrueConcept()
1256
         */
1257
        @Override
1258
        @Transactional(readOnly = true)
1259
        public Concept getTrueConcept() {
1260
                if (trueConcept == null) {
1✔
1261
                        setBooleanConcepts();
×
1262
                }
1263
                
1264
                return trueConcept;
1✔
1265
        }
1266
        
1267
        /**
1268
         * @see org.openmrs.api.ConceptService#getUnknownConcept()
1269
         */
1270
        @Override
1271
        @Transactional(readOnly = true)
1272
        public Concept getUnknownConcept() {
1273
                if (unknownConcept == null) {
1✔
1274
                        try {
1275
                                Concept unknownConcept = Context.getConceptService().getConcept(
1✔
1276
                                        Integer.parseInt(Context.getAdministrationService().getGlobalProperty(
1✔
1277
                                                OpenmrsConstants.GLOBAL_PROPERTY_UNKNOWN_CONCEPT)));
1278
                                initializeLazyPropertiesForConcept(unknownConcept);
1✔
1279
                                
1280
                                ConceptServiceImpl.setStaticUnknownConcept(unknownConcept);
1✔
1281
                        }
1282
                        catch (NumberFormatException e) {
×
1283
                                log.warn("Concept id for unknown concept should be a number");
×
1284
                        }
1✔
1285
                }
1286
                
1287
                return unknownConcept;
1✔
1288
        }
1289
        
1290
        /**
1291
         * Sets unknownConcept using static method
1292
         *
1293
         * @param currentUnknownConcept
1294
         */
1295
        private static void setStaticUnknownConcept(Concept currentUnknownConcept) {
1296
                ConceptServiceImpl.unknownConcept = currentUnknownConcept;
1✔
1297
        }
1✔
1298
        
1299
        /**
1300
         * Sets the TRUE and FALSE concepts by reading their ids from the global_property table
1301
         */
1302
        private void setBooleanConcepts() {
1303
                
1304
                try {
1305
                        trueConcept = Context.getConceptService().getConcept(
1✔
1306
                            Integer.parseInt(Context.getAdministrationService().getGlobalProperty(
1✔
1307
                                OpenmrsConstants.GLOBAL_PROPERTY_TRUE_CONCEPT)));
1308
                        initializeLazyPropertiesForConcept(trueConcept);
1✔
1309
                        
1310
                        falseConcept = Context.getConceptService().getConcept(
1✔
1311
                            Integer.parseInt(Context.getAdministrationService().getGlobalProperty(
1✔
1312
                                OpenmrsConstants.GLOBAL_PROPERTY_FALSE_CONCEPT)));
1313
                        initializeLazyPropertiesForConcept(falseConcept);
1✔
1314
                }
1315
                catch (NumberFormatException e) {
×
1316
                        log.warn("Concept ids for boolean concepts should be numbers");
×
1317
                }
1✔
1318
        }
1✔
1319

1320
        private void initializeLazyPropertiesForConcept(Concept concept) {
1321
                Hibernate.initialize(concept.getRetiredBy());
1✔
1322
                Hibernate.initialize(concept.getCreator());
1✔
1323
                Hibernate.initialize(concept.getChangedBy());
1✔
1324
                Hibernate.initialize(concept.getNames());
1✔
1325
                Hibernate.initialize(concept.getAnswers());
1✔
1326
                Hibernate.initialize(concept.getConceptSets());
1✔
1327
                Hibernate.initialize(concept.getDescriptions());
1✔
1328
                Hibernate.initialize(concept.getConceptMappings());
1✔
1329
                Hibernate.initialize(concept.getAttributes());
1✔
1330
        }
1✔
1331

1332
        /**
1333
         * @see org.openmrs.api.ConceptService#getConceptSourceByName(java.lang.String)
1334
         */
1335
        @Override
1336
        @Transactional(readOnly = true)
1337
        public ConceptSource getConceptSourceByName(String conceptSourceName) throws APIException {
1338
                return dao.getConceptSourceByName(conceptSourceName);
1✔
1339
        }
1340

1341
        /**
1342
         * @see org.openmrs.api.ConceptService#getConceptSourceByUniqueId(java.lang.String)
1343
         */
1344
        @Override
1345
        @Transactional(readOnly = true)
1346
        public ConceptSource getConceptSourceByUniqueId(String uniqueId) throws APIException {
1347
                if (uniqueId == null) {
1✔
1348
                        throw new IllegalArgumentException("uniqueId is required");
1✔
1349
                }
1350
                return dao.getConceptSourceByUniqueId(uniqueId);
1✔
1351
        }
1352

1353
        /**
1354
         * @see org.openmrs.api.ConceptService#getConceptSourceByHL7Code(java.lang.String)
1355
         */
1356
        @Override
1357
        @Transactional(readOnly = true)
1358
        public ConceptSource getConceptSourceByHL7Code(String hl7Code) throws APIException {
1359
                if (hl7Code == null) {
1✔
1360
                        throw new IllegalArgumentException("hl7Code is required");
1✔
1361
                }
1362
                return dao.getConceptSourceByHL7Code(hl7Code);
1✔
1363
        }
1364

1365
        /**
1366
         * Utility method to check if the concept is already attached to an observation (including
1367
         * voided ones) and if the datatype of the concept has changed, an exception indicating that the
1368
         * datatype cannot be modified will be reported if the concept is attached to an observation.
1369
         * This method will only allow changing boolean concepts to coded.
1370
         * 
1371
         * @param concept
1372
         * @throws ConceptInUseException
1373
         */
1374
        private void checkIfDatatypeCanBeChanged(Concept concept) {
1375
                if (concept.getId() != null && hasAnyObservation(concept) && hasDatatypeChanged(concept)) {
1✔
1376
                        // allow boolean concepts to be converted to coded
1377
                        if (!(dao.getSavedConceptDatatype(concept).isBoolean() && concept.getDatatype().isCoded())) {
1✔
1378
                                throw new ConceptInUseException();
1✔
1379
                        }
1380
                        log.debug("Converting datatype of concept with id {} from Boolean to coded", concept.getConceptId());
1✔
1381
                }
1382
        }
1✔
1383
        
1384
        /**
1385
         * Utility method which loads the previous version of a concept to check if the datatype has
1386
         * changed.
1387
         * 
1388
         * @param concept to be modified
1389
         * @return boolean indicating change in the datatype
1390
         */
1391
        private boolean hasDatatypeChanged(Concept concept) {
1392
                ConceptDatatype oldConceptDatatype = dao.getSavedConceptDatatype(concept);
1✔
1393
                return !oldConceptDatatype.equals(concept.getDatatype());
1✔
1394
        }
1395
        
1396
        /**
1397
         * @see org.openmrs.api.ConceptService#hasAnyObservation(org.openmrs.Concept)
1398
         */
1399
        @Override
1400
        @Transactional(readOnly = true)
1401
        public boolean hasAnyObservation(Concept concept) {
1402
                List<Concept> concepts = new ArrayList<>();
1✔
1403
                concepts.add(concept);
1✔
1404
                Integer count = Context.getObsService().getObservationCount(null, null, concepts, null, null, null, null, null,
1✔
1405
                    null, true);
1406
                return count > 0;
1✔
1407
        }
1408
        
1409
        /**
1410
         * @see org.openmrs.api.ConceptService#convertBooleanConceptToCoded(org.openmrs.Concept)
1411
         */
1412
        @Override
1413
        public void convertBooleanConceptToCoded(Concept conceptToChange) throws APIException {
1414
                if (conceptToChange != null) {
1✔
1415
                        if (!conceptToChange.getDatatype().isBoolean()) {
1✔
1416
                                throw new APIException("Concept.datatype.invalid", (Object[]) null);
1✔
1417
                        }
1418
                        
1419
                        conceptToChange.setDatatype(getConceptDatatypeByName("Coded"));
1✔
1420
                        conceptToChange.addAnswer(new ConceptAnswer(getTrueConcept()));
1✔
1421
                        conceptToChange.addAnswer(new ConceptAnswer(getFalseConcept()));
1✔
1422
                        Context.getConceptService().saveConcept(conceptToChange);
1✔
1423
                }
1424
        }
1✔
1425
        
1426
        /**
1427
         * @see org.openmrs.api.ConceptService#hasAnyObservation(org.openmrs.ConceptName)
1428
         */
1429
        @Override
1430
        @Transactional(readOnly = true)
1431
        public boolean hasAnyObservation(ConceptName conceptName) throws APIException {
1432
                List<ConceptName> conceptNames = new ArrayList<>();
1✔
1433
                conceptNames.add(conceptName);
1✔
1434
                Integer count = Context.getObsService().getObservationCount(conceptNames, true);
1✔
1435
                return count > 0;
1✔
1436
        }
1437
        
1438
        /**
1439
         * Utility method which loads the previous version of a conceptName to check if the name
1440
         * property of the given conceptName has changed.
1441
         * 
1442
         * @param conceptName to be modified
1443
         * @return boolean indicating change in the name property
1444
         */
1445
        private boolean hasNameChanged(ConceptName conceptName) {
1446
                String newName = conceptName.getName();
1✔
1447
                String oldName = dao.getSavedConceptName(conceptName).getName();
1✔
1448
                return !oldName.equalsIgnoreCase(newName);
1✔
1449
        }
1450
        
1451
        /**
1452
         * Creates a copy of a conceptName
1453
         * 
1454
         * @param conceptName the conceptName to be cloned
1455
         * @return the cloned conceptName
1456
         */
1457
        private ConceptName cloneConceptName(ConceptName conceptName) {
1458
                ConceptName copy = new ConceptName();
1✔
1459
                try {
1460
                        copy = (ConceptName) BeanUtils.cloneBean(conceptName);
1✔
1461
                }
1462
                catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException e) {
×
1463
                        
1464
                        log.warn(ERROR_MESSAGE, e);
×
1465
                }
1✔
1466
                return copy;
1✔
1467
        }
1468
        
1469
        /**
1470
         * @see ConceptService#findConceptAnswers(String, Locale, Concept)
1471
         */
1472
        @Override
1473
        @Transactional(readOnly = true)
1474
        public List<ConceptSearchResult> findConceptAnswers(String phrase, Locale locale, Concept concept) throws APIException {
1475

1476
                return getConcepts(phrase, Collections.singletonList(locale), false, null, null, null, null,
1✔
1477
                    concept, null, null);
1478
        }
1479
        
1480
        /**
1481
         * @see org.openmrs.api.ConceptService#getConceptStopWords(java.util.Locale)
1482
         */
1483
        @Override
1484
        @Transactional(readOnly = true)
1485
        public List<String> getConceptStopWords(Locale locale) {
1486
                return dao.getConceptStopWords(locale);
1✔
1487
        }
1488
        
1489
        /**
1490
         * @see org.openmrs.api.ConceptService#saveConceptStopWord(org.openmrs.ConceptStopWord)
1491
         */
1492
        @Override
1493
        public ConceptStopWord saveConceptStopWord(ConceptStopWord conceptStopWord) throws APIException {
1494
                try {
1495
                        return dao.saveConceptStopWord(conceptStopWord);
1✔
1496
                }
1497
                catch (DAOException e) {
1✔
1498
                        if ("Duplicate ConceptStopWord Entry".equalsIgnoreCase(e.getMessage())) {
1✔
1499
                                throw new ConceptStopWordException("ConceptStopWord.duplicated", e);
1✔
1500
                        }
1501
                        throw new ConceptStopWordException("ConceptStopWord.notSaved", e);
×
1502
                }
1503
        }
1504
        
1505
        /**
1506
         * @see org.openmrs.api.ConceptService#deleteConceptStopWord(Integer)
1507
         */
1508
        @Override
1509
        public void deleteConceptStopWord(Integer conceptStopWordId) throws APIException {
1510
                try {
1511
                        dao.deleteConceptStopWord(conceptStopWordId);
1✔
1512
                }
1513
                catch (DAOException e) {
×
1514
                        if (StringUtils.contains(e.getMessage(), "Concept Stop Word not found or already deleted")) {
×
1515
                                throw new ConceptStopWordException("ConceptStopWord.error.notfound", e);
×
1516
                        }
1517
                        throw new ConceptStopWordException("general.cannot.delete", e);
×
1518
                }
1✔
1519
        }
1✔
1520
        
1521
        /**
1522
         * @see org.openmrs.api.ConceptService#getAllConceptStopWords()
1523
         */
1524
        @Override
1525
        @Transactional(readOnly = true)
1526
        public List<ConceptStopWord> getAllConceptStopWords() {
1527
                return dao.getAllConceptStopWords();
1✔
1528
        }
1529
        
1530
        /**
1531
         * @see ConceptService#getConcepts(String, List, boolean, List, List, List, List, Concept,
1532
         *      Integer, Integer)
1533
         */
1534
        @Override
1535
        @Transactional(readOnly = true)
1536
        public List<ConceptSearchResult> getConcepts(String phrase, List<Locale> locales, boolean includeRetired,
1537
                List<ConceptClass> requireClasses, List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1538
                List<ConceptDatatype> excludeDatatypes, Concept answersToConcept, Integer start, Integer size)
1539
                throws APIException {
1540

1541
                List<ConceptClass> tmpRequireClasses = requireClasses == null ? new ArrayList<>() : requireClasses;
1✔
1542
                List<ConceptClass> tmpExcludeClasses = excludeClasses == null ? new ArrayList<>() : excludeClasses;
1✔
1543
                List<ConceptDatatype> tmpRequireDatatypes = requireDatatypes == null ? new ArrayList<>() : requireDatatypes;
1✔
1544
                List<ConceptDatatype> tmpExcludeDatatypes = excludeDatatypes == null ? new ArrayList<>() : excludeDatatypes;
1✔
1545
                
1546
                return dao.getConcepts(phrase, locales, includeRetired, tmpRequireClasses, tmpExcludeClasses, tmpRequireDatatypes,
1✔
1547
                    tmpExcludeDatatypes, answersToConcept, start, size);
1548
                
1549
        }
1550
        
1551
        /**
1552
         * @see ConceptService#updateConceptIndex(Concept)
1553
         */
1554
        @Override
1555
        public void updateConceptIndex(Concept concept) throws APIException {
1556
                Context.updateSearchIndexForObject(concept);
×
1557
        }
×
1558
        
1559
        /**
1560
         * @see ConceptService#updateConceptIndexes()
1561
         */
1562
        @Override
1563
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
1564
        public void updateConceptIndexes() throws APIException {
1565
                Context.updateSearchIndexForType(ConceptName.class);
1✔
1566
        }
1✔
1567
        
1568
        /**
1569
         * @see ConceptService#getCountOfConcepts(String, List, boolean, List, List, List, List,
1570
         *      Concept)
1571
         */
1572
        @Override
1573
        @Transactional(readOnly = true)
1574
        public Integer getCountOfConcepts(String phrase, List<Locale> locales, boolean includeRetired,
1575
                List<ConceptClass> requireClasses, List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1576
                List<ConceptDatatype> excludeDatatypes, Concept answersToConcept) {
1577

1578
                List<ConceptClass> tmpRequireClasses = requireClasses == null ? new ArrayList<>() : requireClasses;
1✔
1579
                List<ConceptClass> tmpExcludeClasses = excludeClasses == null ? new ArrayList<>() : excludeClasses;
1✔
1580
                List<ConceptDatatype> tmpRequireDatatypes = requireDatatypes == null ? new ArrayList<>() : requireDatatypes;
1✔
1581
                List<ConceptDatatype> tmpExcludeDatatypes = excludeDatatypes == null ? new ArrayList<>() : excludeDatatypes;
1✔
1582
                
1583
                return dao.getCountOfConcepts(phrase, locales, includeRetired, tmpRequireClasses, tmpExcludeClasses, tmpRequireDatatypes,
1✔
1584
                    tmpExcludeDatatypes, answersToConcept);
1585
        }
1586
        
1587
        /**
1588
         * @see ConceptService#getCountOfDrugs(String, Concept, boolean, boolean, boolean)
1589
         */
1590
        @Override
1591
        @Transactional(readOnly = true)
1592
        public Integer getCountOfDrugs(String drugName, Concept concept, boolean searchOnPhrase, boolean searchDrugConceptNames,
1593
                boolean includeRetired) throws APIException {
1594
                return OpenmrsUtil.convertToInteger(dao.getCountOfDrugs(drugName, concept, searchOnPhrase, searchDrugConceptNames,
1✔
1595
                    includeRetired));
1596
        }
1597
        
1598
        /**
1599
         * @see ConceptService#getDrugs(String, Concept, boolean, boolean, boolean, Integer, Integer)
1600
         */
1601
        @Override
1602
        @Transactional(readOnly = true)
1603
        public List<Drug> getDrugs(String drugName, Concept concept, boolean searchOnPhrase, boolean searchDrugConceptNames,
1604
                boolean includeRetired, Integer start, Integer length) throws APIException {
1605
                return dao.getDrugs(drugName, concept, searchOnPhrase, searchDrugConceptNames, includeRetired, start, length);
1✔
1606
        }
1607
        
1608
        /**
1609
         * @see ConceptService#getConcepts(String, Locale, boolean)
1610
         */
1611
        @Override
1612
        @Transactional(readOnly = true)
1613
        public List<ConceptSearchResult> getConcepts(String phrase, Locale locale, boolean includeRetired) throws APIException {
1614
                List<Locale> locales = new ArrayList<>();
1✔
1615
                if (locale != null) {
1✔
1616
                        locales.add(locale);
1✔
1617
                }
1618
                
1619
                return Context.getConceptService().getConcepts(phrase, locales, includeRetired, null, null, null, null, null, null,
1✔
1620
                    null);
1621
        }
1622
        
1623
        /**
1624
         * @see org.openmrs.api.ConceptService#getDrugsByIngredient(org.openmrs.Concept)
1625
         */
1626
        @Override
1627
        @Transactional(readOnly = true)
1628
        public List<Drug> getDrugsByIngredient(Concept ingredient) throws APIException {
1629
                if (ingredient == null) {
1✔
1630
                        throw new IllegalArgumentException("ingredient is required");
1✔
1631
                }
1632
                
1633
                return dao.getDrugsByIngredient(ingredient);
1✔
1634
        }
1635
        
1636
        /**
1637
         * @see ConceptService#getConceptMappingsToSource(ConceptSource)
1638
         */
1639
        @Override
1640
        @Transactional(readOnly = true)
1641
        public List<ConceptMap> getConceptMappingsToSource(ConceptSource conceptSource) throws APIException {
1642
                return dao.getConceptMapsBySource(conceptSource);
1✔
1643
        }
1644
        
1645
        /**
1646
         * @see ConceptService#getActiveConceptMapTypes()
1647
         */
1648
        @Override
1649
        @Transactional(readOnly = true)
1650
        public List<ConceptMapType> getActiveConceptMapTypes() throws APIException {
1651
                return Context.getConceptService().getConceptMapTypes(true, false);
1✔
1652
        }
1653
        
1654
        /**
1655
         * @see ConceptService#getConceptMapTypes(boolean, boolean)
1656
         */
1657
        @Override
1658
        @Transactional(readOnly = true)
1659
        public List<ConceptMapType> getConceptMapTypes(boolean includeRetired, boolean includeHidden) throws APIException {
1660
                return dao.getConceptMapTypes(includeRetired, includeHidden);
1✔
1661
        }
1662
        
1663
        /**
1664
         * @see ConceptService#getConceptMapType(Integer)
1665
         */
1666
        @Override
1667
        @Transactional(readOnly = true)
1668
        public ConceptMapType getConceptMapType(Integer conceptMapTypeId) throws APIException {
1669
                return dao.getConceptMapType(conceptMapTypeId);
1✔
1670
        }
1671
        
1672
        /**
1673
         * @see ConceptService#getConceptMapTypeByUuid(String)
1674
         */
1675
        @Override
1676
        @Transactional(readOnly = true)
1677
        public ConceptMapType getConceptMapTypeByUuid(String uuid) throws APIException {
1678
                return dao.getConceptMapTypeByUuid(uuid);
1✔
1679
        }
1680
        
1681
        /**
1682
         * @see org.openmrs.api.ConceptService#getConceptMapTypeByName(java.lang.String)
1683
         */
1684
        @Override
1685
        @Transactional(readOnly = true)
1686
        public ConceptMapType getConceptMapTypeByName(String name) throws APIException {
1687
                return dao.getConceptMapTypeByName(name);
1✔
1688
        }
1689
        
1690
        /**
1691
         * @see org.openmrs.api.ConceptService#saveConceptMapType(org.openmrs.ConceptMapType)
1692
         */
1693
        @Override
1694
        public ConceptMapType saveConceptMapType(ConceptMapType conceptMapType) throws APIException {
1695
                return dao.saveConceptMapType(conceptMapType);
1✔
1696
        }
1697
        
1698
        /**
1699
         * @see org.openmrs.api.ConceptService#retireConceptMapType(org.openmrs.ConceptMapType,
1700
         *      java.lang.String)
1701
         */
1702
        @Override
1703
        public ConceptMapType retireConceptMapType(ConceptMapType conceptMapType, String retireReason) throws APIException {
1704
                String tmpRetireReason = retireReason;
1✔
1705
                if (StringUtils.isBlank(tmpRetireReason)) {
1✔
1706
                        tmpRetireReason = Context.getMessageSourceService().getMessage("general.default.retireReason");
1✔
1707
                }
1708
                conceptMapType.setRetireReason(tmpRetireReason);
1✔
1709
                return dao.saveConceptMapType(conceptMapType);
1✔
1710
        }
1711
        
1712
        /**
1713
         * @see org.openmrs.api.ConceptService#unretireConceptMapType(org.openmrs.ConceptMapType)
1714
         */
1715
        @Override
1716
        public ConceptMapType unretireConceptMapType(ConceptMapType conceptMapType) throws APIException {
1717
                return Context.getConceptService().saveConceptMapType(conceptMapType);
1✔
1718
        }
1719
        
1720
        /**
1721
         * @see org.openmrs.api.ConceptService#purgeConceptMapType(org.openmrs.ConceptMapType)
1722
         */
1723
        @Override
1724
        public void purgeConceptMapType(ConceptMapType conceptMapType) throws APIException {
1725
                if (dao.isConceptMapTypeInUse(conceptMapType)) {
1✔
1726
                        throw new APIException("ConceptMapType.inUse", (Object[]) null);
×
1727
                }
1728
                dao.deleteConceptMapType(conceptMapType);
1✔
1729
        }
1✔
1730
        
1731
        /**
1732
         * @see org.openmrs.api.ConceptService#getAllConceptReferenceTerms()
1733
         */
1734
        @Override
1735
        @Transactional(readOnly = true)
1736
        public List<ConceptReferenceTerm> getAllConceptReferenceTerms() throws APIException {
1737
                return Context.getConceptService().getConceptReferenceTerms(true);
1✔
1738
        }
1739
        
1740
        /**
1741
         * @see ConceptService#getConceptReferenceTerms(boolean)
1742
         */
1743
        @Override
1744
        @Transactional(readOnly = true)
1745
        public List<ConceptReferenceTerm> getConceptReferenceTerms(boolean includeRetired) throws APIException {
1746
                return dao.getConceptReferenceTerms(includeRetired);
1✔
1747
        }
1748
        
1749
        /**
1750
         * @see org.openmrs.api.ConceptService#getConceptReferenceTerm(java.lang.Integer)
1751
         */
1752
        @Override
1753
        @Transactional(readOnly = true)
1754
        public ConceptReferenceTerm getConceptReferenceTerm(Integer conceptReferenceTermId) throws APIException {
1755
                return dao.getConceptReferenceTerm(conceptReferenceTermId);
1✔
1756
        }
1757
        
1758
        /**
1759
         * @see org.openmrs.api.ConceptService#getConceptReferenceTermByUuid(java.lang.String)
1760
         */
1761
        @Override
1762
        @Transactional(readOnly = true)
1763
        public ConceptReferenceTerm getConceptReferenceTermByUuid(String uuid) throws APIException {
1764
                return dao.getConceptReferenceTermByUuid(uuid);
1✔
1765
        }
1766
        
1767
        /**
1768
         * @see org.openmrs.api.ConceptService#getConceptReferenceTermByName(java.lang.String,
1769
         *      org.openmrs.ConceptSource)
1770
         */
1771
        @Override
1772
        @Transactional(readOnly = true)
1773
        public ConceptReferenceTerm getConceptReferenceTermByName(String name, ConceptSource conceptSource) throws APIException {
1774
                //On addition of extra attributes to concept maps, terms that were generated from existing maps have 
1775
                //empty string values for the name property, ignore the search when name is an empty string but allow 
1776
                //white space characters
1777
                if (StringUtils.isBlank(name)) {
1✔
1778
                        return null;
1✔
1779
                }
1780
                return dao.getConceptReferenceTermByName(name, conceptSource);
1✔
1781
        }
1782
        
1783
        /**
1784
         * @see org.openmrs.api.ConceptService#getConceptReferenceTermByCode(java.lang.String,
1785
         *      org.openmrs.ConceptSource)
1786
         */
1787
        @Override
1788
        @Transactional(readOnly = true)
1789
        public ConceptReferenceTerm getConceptReferenceTermByCode(String code, ConceptSource conceptSource) throws APIException {
1790
                return dao.getConceptReferenceTermByCode(code, conceptSource);
1✔
1791
        }
1792

1793
        @Override
1794
        @Transactional(readOnly = true)
1795
        public List<ConceptReferenceTerm> getConceptReferenceTermByCode(String code, ConceptSource conceptSource, boolean includeRetired) throws APIException {
1796
                return dao.getConceptReferenceTermByCode(code, conceptSource, includeRetired);
1✔
1797
        }
1798

1799
        /**
1800
         * @see org.openmrs.api.ConceptService#saveConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1801
         */
1802
        @Override
1803
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
1804
        public ConceptReferenceTerm saveConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws APIException {
1805
                return dao.saveConceptReferenceTerm(conceptReferenceTerm);
1✔
1806
        }
1807
        
1808
        /**
1809
         * @see org.openmrs.api.ConceptService#retireConceptReferenceTerm(ConceptReferenceTerm, String)
1810
         */
1811
        @Override
1812
        public ConceptReferenceTerm retireConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm, String retireReason)
1813
                throws APIException {
1814
                String tmpRetireReason = retireReason;
1✔
1815
                if (StringUtils.isBlank(tmpRetireReason)) {
1✔
1816
                        tmpRetireReason = Context.getMessageSourceService().getMessage("general.default.retireReason");
1✔
1817
                }
1818
                conceptReferenceTerm.setRetireReason(tmpRetireReason);
1✔
1819
                return Context.getConceptService().saveConceptReferenceTerm(conceptReferenceTerm);
1✔
1820
        }
1821
        
1822
        /**
1823
         * @see org.openmrs.api.ConceptService#unretireConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1824
         */
1825
        @Override
1826
        public ConceptReferenceTerm unretireConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws APIException {
1827
                return Context.getConceptService().saveConceptReferenceTerm(conceptReferenceTerm);
1✔
1828
        }
1829
        
1830
        /**
1831
         * @see org.openmrs.api.ConceptService#purgeConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1832
         */
1833
        @Override
1834
        @CacheEvict(value = CONCEPT_IDS_BY_MAPPING_CACHE_NAME, allEntries = true)
1835
        public void purgeConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws APIException {
1836
                if (dao.isConceptReferenceTermInUse(conceptReferenceTerm)) {
1✔
1837
                        throw new APIException("ConceptRefereceTerm.inUse", (Object[]) null);
1✔
1838
                }
1839
                dao.deleteConceptReferenceTerm(conceptReferenceTerm);
1✔
1840
        }
1✔
1841
        
1842
        /**
1843
         * @see org.openmrs.api.ConceptService#getConceptReferenceTerms(java.lang.String,
1844
         *      org.openmrs.ConceptSource, java.lang.Integer, java.lang.Integer, boolean)
1845
         */
1846
        @Override
1847
        @Transactional(readOnly = true)
1848
        public List<ConceptReferenceTerm> getConceptReferenceTerms(String query, ConceptSource conceptSource, Integer start,
1849
                Integer length, boolean includeRetired) throws APIException {
1850
                Integer tmpLength = length;
1✔
1851
                if (tmpLength == null) {
1✔
1852
                        tmpLength = 10000;
1✔
1853
                }
1854
                return dao.getConceptReferenceTerms(query, conceptSource, start, tmpLength, includeRetired);
1✔
1855
        }
1856
        
1857
        /**
1858
         * @see org.openmrs.api.ConceptService#getCountOfConceptReferenceTerms(String, ConceptSource,
1859
         *      boolean)
1860
         */
1861
        @Override
1862
        @Transactional(readOnly = true)
1863
        public Integer getCountOfConceptReferenceTerms(String query, ConceptSource conceptSource, boolean includeRetired) {
1864
                return OpenmrsUtil.convertToInteger(dao.getCountOfConceptReferenceTerms(query, conceptSource, includeRetired));
1✔
1865
        }
1866
        
1867
        /**
1868
         * @see org.openmrs.api.ConceptService#getReferenceTermMappingsTo(ConceptReferenceTerm)
1869
         */
1870
        @Override
1871
        @Transactional(readOnly = true)
1872
        public List<ConceptReferenceTermMap> getReferenceTermMappingsTo(ConceptReferenceTerm term) throws APIException {
1873
                return dao.getReferenceTermMappingsTo(term);
1✔
1874
        }
1875
        
1876
        /**
1877
         * @see org.openmrs.api.ConceptService#getConceptsByName(java.lang.String, java.util.Locale,
1878
         *      java.lang.Boolean)
1879
         */
1880
        @Override
1881
        @Transactional(readOnly = true)
1882
        public List<Concept> getConceptsByName(String name, Locale locale, Boolean exactLocale) throws APIException {
1883
                return dao.getConceptsByName(name, locale, exactLocale);
1✔
1884
        }
1885
        
1886
        /**
1887
         * @see org.openmrs.api.ConceptService#getDefaultConceptMapType()
1888
         */
1889
        @Override
1890
        @Transactional(readOnly = true)
1891
        public ConceptMapType getDefaultConceptMapType() throws APIException {
1892
                //We need to fetch it in DAO since it must be done in the MANUAL fush mode to prevent pre-mature flushes.
1893
                return dao.getDefaultConceptMapType();
1✔
1894
        }
1895
        
1896
        /**
1897
         * @see org.openmrs.api.ConceptService#isConceptNameDuplicate(org.openmrs.ConceptName)
1898
         */
1899
        @Override
1900
        public boolean isConceptNameDuplicate(ConceptName name) {
1901
                return dao.isConceptNameDuplicate(name);
1✔
1902
        }
1903
        
1904
        /**
1905
         * @see ConceptService#getDrugs(String, java.util.Locale, boolean, boolean)
1906
         */
1907
        @Override
1908
        @Transactional(readOnly = true)
1909
        public List<Drug> getDrugs(String searchPhrase, Locale locale, boolean exactLocale, boolean includeRetired)
1910
                throws APIException {
1911
                if (searchPhrase == null) {
1✔
1912
                        throw new IllegalArgumentException("searchPhrase is required");
1✔
1913
                }
1914
                return dao.getDrugs(searchPhrase, locale, exactLocale, includeRetired);
1✔
1915
        }
1916
        
1917
        /**
1918
         * @see org.openmrs.api.ConceptService#getDrugsByMapping(String, ConceptSource, Collection,
1919
         *      boolean)
1920
         */
1921
        @Override
1922
        @Transactional(readOnly = true)
1923
        public List<Drug> getDrugsByMapping(String code, ConceptSource conceptSource,
1924
                Collection<ConceptMapType> withAnyOfTheseTypes, boolean includeRetired) throws APIException {
1925
                Collection<ConceptMapType> tmpWithAnyOfTheseTypes = withAnyOfTheseTypes == null ? Collections.emptyList() : withAnyOfTheseTypes;
1✔
1926

1927
                if (conceptSource == null) {
1✔
1928
                        throw new APIException("ConceptSource.is.required", (Object[]) null);
1✔
1929
                }
1930

1931
                return dao.getDrugsByMapping(code, conceptSource, tmpWithAnyOfTheseTypes, includeRetired);
1✔
1932
        }
1933
        
1934
        /**
1935
         * @see org.openmrs.api.ConceptService#getDrugByMapping(String, org.openmrs.ConceptSource, java.util.Collection)
1936
         */
1937
        @Override
1938
        @Transactional(readOnly = true)
1939
        public Drug getDrugByMapping(String code, ConceptSource conceptSource,
1940
                Collection<ConceptMapType> withAnyOfTheseTypesOrOrderOfPreference) throws APIException {
1941
                Collection<ConceptMapType> tmpWithAnyOfTheseTypesOrOrderOfPreference = withAnyOfTheseTypesOrOrderOfPreference == null
1✔
1942
                                ? Collections.emptyList() : withAnyOfTheseTypesOrOrderOfPreference;
1✔
1943

1944
                if (conceptSource == null) {
1✔
1945
                        throw new APIException("ConceptSource.is.required", (Object[]) null);
1✔
1946
                }
1947

1948
                return dao.getDrugByMapping(code, conceptSource, tmpWithAnyOfTheseTypesOrOrderOfPreference);
1✔
1949
        }
1950
        
1951
        /**
1952
         * @see org.openmrs.api.ConceptService#getOrderableConcepts(String, java.util.List, boolean,
1953
         *      Integer, Integer)
1954
         */
1955
        @Override
1956
        @Transactional(readOnly = true)
1957
        public List<ConceptSearchResult> getOrderableConcepts(String phrase, List<Locale> locales, boolean includeRetired,
1958
                Integer start, Integer length) {
1959
                List<ConceptClass> mappedClasses = getConceptClassesOfOrderTypes();
1✔
1960
                if (mappedClasses.isEmpty()) {
1✔
1961
                        return Collections.emptyList();
×
1962
                }
1963
                List<Locale> tmpLocales = locales;
1✔
1964
                if (tmpLocales == null) {
1✔
1965
                        tmpLocales = new ArrayList<>();
1✔
1966
                        tmpLocales.add(Context.getLocale());
1✔
1967
                }
1968
                return dao.getConcepts(phrase, tmpLocales, false, mappedClasses, Collections.emptyList(), Collections.emptyList(),
1✔
1969
                    Collections.emptyList(), null, start, length);
1✔
1970
        }
1971

1972
        /**
1973
         * @see ConceptService#getAllConceptAttributeTypes()
1974
         */
1975
        @Override
1976
        @Transactional(readOnly = true)
1977
        public List<ConceptAttributeType> getAllConceptAttributeTypes() {
1978
                return dao.getAllConceptAttributeTypes();
1✔
1979
        }
1980

1981
        /**
1982
         * @see org.openmrs.api.ConceptService#saveConceptAttributeType(ConceptAttributeType)
1983
         */
1984
        @Override
1985
        public ConceptAttributeType saveConceptAttributeType(ConceptAttributeType conceptAttributeType) {
1986
                return dao.saveConceptAttributeType(conceptAttributeType);
1✔
1987
        }
1988

1989
        /**
1990
         * @see org.openmrs.api.ConceptService#getConceptAttributeType(Integer)
1991
         */
1992
        @Override
1993
        @Transactional(readOnly = true)
1994
        public ConceptAttributeType getConceptAttributeType(Integer id) {
1995
                return dao.getConceptAttributeType(id);
1✔
1996
        }
1997

1998
        /**
1999
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypeByUuid(String)
2000
         */
2001
        @Override
2002
        @Transactional(readOnly = true)
2003
        public ConceptAttributeType getConceptAttributeTypeByUuid(String uuid) {
2004
                return dao.getConceptAttributeTypeByUuid(uuid);
1✔
2005
        }
2006

2007
        /**
2008
         * @see org.openmrs.api.ConceptService#purgeConceptAttributeType(ConceptAttributeType)
2009
         */
2010
        @Override
2011
        public void purgeConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2012
                dao.deleteConceptAttributeType(conceptAttributeType);
1✔
2013

2014
        }
1✔
2015

2016
        /**
2017
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypes(String)
2018
         */
2019
        @Override
2020
        @Transactional(readOnly = true)
2021
        public List<ConceptAttributeType> getConceptAttributeTypes(String name) throws APIException {
2022
                return dao.getConceptAttributeTypes(name);
1✔
2023
        }
2024

2025
        /**
2026
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypeByName(String)
2027
         */
2028
        @Override
2029
        @Transactional(readOnly = true)
2030
        public ConceptAttributeType getConceptAttributeTypeByName(String exactName) {
2031
                return dao.getConceptAttributeTypeByName(exactName);
1✔
2032
        }
2033

2034
        /**
2035
         * @see org.openmrs.api.ConceptService#retireConceptAttributeType(ConceptAttributeType, String)
2036
         */
2037
        @Override
2038
        public ConceptAttributeType retireConceptAttributeType(ConceptAttributeType conceptAttributeType, String reason) {
2039
                return dao.saveConceptAttributeType(conceptAttributeType);
1✔
2040
        }
2041

2042
        /**
2043
         * @see org.openmrs.api.ConceptService#unretireConceptAttributeType(ConceptAttributeType)
2044
         */
2045
        @Override
2046
        public ConceptAttributeType unretireConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2047
                return Context.getConceptService().saveConceptAttributeType(conceptAttributeType);
1✔
2048
        }
2049

2050
        /**
2051
         * @see org.openmrs.api.ConceptService#getConceptAttributeByUuid(String)
2052
         */
2053
        @Override
2054
        @Transactional(readOnly = true)
2055
        public ConceptAttribute getConceptAttributeByUuid(String uuid) {
2056
                return dao.getConceptAttributeByUuid(uuid);
1✔
2057
        }
2058

2059
        /**
2060
         * @see org.openmrs.api.ConceptService#hasAnyConceptAttribute(ConceptAttributeType)
2061
         */
2062
        @Override
2063
        @Transactional(readOnly = true)
2064
        public boolean hasAnyConceptAttribute(ConceptAttributeType conceptAttributeType) {
2065
                return dao.getConceptAttributeCount(conceptAttributeType) > 0;
1✔
2066
        }
2067

2068
        /**
2069
         * @see ConceptService#saveConceptReferenceRange(ConceptReferenceRange)
2070
         */
2071
        @Override
2072
        public ConceptReferenceRange saveConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2073
                return dao.saveConceptReferenceRange(conceptReferenceRange);
1✔
2074
        }
2075

2076
        /**
2077
         * @see ConceptService#getConceptReferenceRangesByConceptId(Integer)
2078
         */
2079
        @Override
2080
        @Transactional(readOnly = true)
2081
        public List<ConceptReferenceRange> getConceptReferenceRangesByConceptId(Integer conceptId) {
2082
                return dao.getConceptReferenceRangesByConceptId(conceptId);
1✔
2083
        }
2084

2085
        @Override
2086
        public ConceptReferenceRange getConceptReferenceRangeByUuid(String uuid) {
2087
                return dao.getConceptReferenceRangeByUuid(uuid);
1✔
2088
        }
2089
        
2090
        @Override
2091
        public ConceptReferenceRange getConceptReferenceRange(Person person, Concept concept) {
2092
                Obs obs = new Obs(person, concept, null, null);
1✔
2093
                return new ObsValidator().getReferenceRange(obs);
1✔
2094
        }
2095

2096
        /***
2097
         * Determines if the passed string is in valid uuid format By OpenMRS standards, a uuid must be 36
2098
         * characters in length and not contain whitespace, but we do not enforce that a uuid be in the
2099
         * "canonical" form, with alphanumerics seperated by dashes, since the MVP dictionary does not use
2100
         * this format (We also are being slightly lenient and accepting uuids that are 37 or 38 characters
2101
         * in length, since the uuid data field is 38 characters long)
2102
         */
2103
        public static boolean isValidUuidFormat(String uuid) {
2104
                if (uuid.length() < 36 || uuid.length() > 38 || uuid.contains(" ") || uuid.contains(".")) {
1✔
2105
                        return false;
1✔
2106
                }
2107
                return true;
1✔
2108
        }
2109

2110
        /**
2111
         * Evaluates the specified Java constant using reflection: if input is org.openmrs.CLASS_NAME.CONSTANT_NAME
2112
         * then, output will be CONSTANT_NAME
2113
         * @param fqn the fully qualified name of the constant
2114
         * @return the constant value or null
2115
         */
2116
        private static String evaluateStaticConstant(String fqn) {
2117
                int lastPeriod = fqn.lastIndexOf(".");
1✔
2118
                String clazzName = fqn.substring(0, lastPeriod);
1✔
2119
                String constantName = fqn.substring(lastPeriod + 1);
1✔
2120
                try {
2121
                        Class<?> clazz = Context.loadClass(clazzName);
1✔
2122
                        Field constantField = clazz.getDeclaredField(constantName);
1✔
2123
                        constantField.setAccessible(true);
1✔
2124
                        Object val = constantField.get(null);
1✔
2125
                        return val != null ? String.valueOf(val) : null;
1✔
2126
                }
2127
                catch (Exception ex) {
×
2128
                        throw new APIException("Error while evaluating " + fqn + " as a constant" , ex);
×
2129
                }
2130
        }
2131
        
2132
        private List<ConceptClass> getConceptClassesOfOrderTypes() {
2133
                List<ConceptClass> mappedClasses = new ArrayList<>();
1✔
2134
                AdministrationService administrationService = Context.getAdministrationService();
1✔
2135
                List<List<Object>> result = administrationService.executeSQL(
1✔
2136
                    "SELECT DISTINCT concept_class_id FROM order_type_class_map", true);
2137
                for (List<Object> temp : result) {
1✔
2138
                        for (Object value : temp) {
1✔
2139
                                if (value != null) {
1✔
2140
                                        mappedClasses.add(this.getConceptClass((Integer) value));
1✔
2141
                                }
2142
                        }
1✔
2143
                }
1✔
2144
                return mappedClasses;
1✔
2145
        }
2146
        
2147
        /**
2148
         * @see org.openmrs.api.ConceptService#purgeConceptReferenceRange(ConceptReferenceRange)
2149
         */
2150
        @Override
2151
        public void purgeConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2152
                checkIfLocked();
1✔
2153
                dao.purgeConceptReferenceRange(conceptReferenceRange);
1✔
2154
        }
1✔
2155
}
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