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

openmrs / openmrs-core / 22629535597

03 Mar 2026 03:16PM UTC coverage: 65.387% (-0.007%) from 65.394%
22629535597

push

github

ibacher
TRUNK-6512: Introduce ConceptReferenceRangeContext API (#5880)

Co-authored-by: Binayak490-cyber <binayak490@gmail.com>

104 of 129 new or added lines in 4 files covered. (80.62%)

4 existing lines in 4 files now uncovered.

23838 of 36457 relevant lines covered (65.39%)

0.65 hits per line

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

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

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

100
        private static final String ERROR_MESSAGE = "Error generated";
101

102
        private static final String CONCEPT_IDS_BY_MAPPING_CACHE_NAME = "conceptIdsByMapping";
103

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

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

126
                CustomDatatypeUtil.saveAttributesIfNecessary(concept);
1✔
127

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

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

192
                return dao.saveConcept(concept);
1✔
193
        }
194

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

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

216
        private void makeLocaleNotPreferred(ConceptName conceptName) {
217
                if (conceptName.getLocalePreferred()) {
1✔
218
                        conceptName.setLocalePreferred(false);
1✔
219
                }
220
        }
1✔
221

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

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

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

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

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

257
        private void logConceptChangedData(Concept concept) {
258
                concept.setDateChanged(new Date());
1✔
259
                concept.setChangedBy(Context.getAuthenticatedUser());
1✔
260
        }
1✔
261

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2017
        }
1✔
2018

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

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

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

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

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

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

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

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

2088
        @Override
2089
        public ConceptReferenceRange getConceptReferenceRangeByUuid(String uuid) {
2090
                return dao.getConceptReferenceRangeByUuid(uuid);
1✔
2091
        }
2092
        
2093
        @Override
2094
        public ConceptReferenceRange getConceptReferenceRange(Person person, Concept concept) {
2095
                if (person == null || concept == null) {
1✔
2096
                        return null;
1✔
2097
                }
2098
                return Context.getConceptService().getConceptReferenceRange(
1✔
2099
                        new ConceptReferenceRangeContext(person, concept, null));
2100
        }
2101

2102
        @Override
2103
        public ConceptReferenceRange getConceptReferenceRange(ConceptReferenceRangeContext context) {
2104
                if (context == null) {
1✔
2105
                        throw new IllegalArgumentException("ConceptReferenceRangeContext must not be null");
1✔
2106
                }
2107

2108
                Concept concept = HibernateUtil.getRealObjectFromProxy(context.getConcept());
1✔
2109
                if (!(concept instanceof ConceptNumeric) || concept.getDatatype() == null || !concept.getDatatype().isNumeric()) {
1✔
2110
                        return null;
1✔
2111
                }
2112
                ConceptNumeric conceptNumeric = (ConceptNumeric) concept;
1✔
2113

2114
                List<ConceptReferenceRange> referenceRanges =
2115
                        Context.getConceptService().getConceptReferenceRangesByConceptId(concept.getConceptId());
1✔
2116

2117
                if (referenceRanges.isEmpty()) {
1✔
2118
                        return getDefaultReferenceRange(conceptNumeric);
1✔
2119
                }
2120

2121
                ConceptReferenceRangeUtility referenceRangeUtility = new ConceptReferenceRangeUtility();
1✔
2122
                List<ConceptReferenceRange> validRanges = new ArrayList<>();
1✔
2123

2124
                for (ConceptReferenceRange referenceRange : referenceRanges) {
1✔
2125
                        if (referenceRangeUtility.evaluateCriteria(
1✔
2126
                                        StringEscapeUtils.unescapeHtml4(referenceRange.getCriteria()), context)) {
1✔
2127
                                validRanges.add(referenceRange);
1✔
2128
                        }
2129
                }
1✔
2130

2131
                if (validRanges.isEmpty()) {
1✔
2132
                        ConceptReferenceRange defaultReferenceRange = getDefaultReferenceRange(conceptNumeric);
1✔
2133
                        if (defaultReferenceRange != null) {
1✔
2134
                                return defaultReferenceRange;
1✔
2135
                        }
NEW
2136
                        return null;
×
2137
                }
2138

2139
                return findStrictestReferenceRange(validRanges);
1✔
2140
        }
2141

2142
        /**
2143
         * Returns a reference range derived from the ConceptNumeric's own range fields.
2144
         * Used as a fallback when no ConceptReferenceRange records exist or match.
2145
         */
2146
        private static ConceptReferenceRange getDefaultReferenceRange(ConceptNumeric conceptNumeric) {
2147
                if (conceptNumeric == null || (
1✔
2148
                        conceptNumeric.getHiAbsolute() == null &&
1✔
2149
                        conceptNumeric.getHiCritical() == null &&
1✔
2150
                        conceptNumeric.getHiNormal() == null &&
1✔
2151
                        conceptNumeric.getLowAbsolute() == null &&
1✔
2152
                        conceptNumeric.getLowCritical() == null &&
1✔
2153
                        conceptNumeric.getLowNormal() == null
1✔
2154
                )) {
2155
                        return null;
1✔
2156
                }
2157

2158
                ConceptReferenceRange defaultReferenceRange = new ConceptReferenceRange();
1✔
2159
                defaultReferenceRange.setConceptNumeric(conceptNumeric);
1✔
2160
                defaultReferenceRange.setHiAbsolute(conceptNumeric.getHiAbsolute());
1✔
2161
                defaultReferenceRange.setHiCritical(conceptNumeric.getHiCritical());
1✔
2162
                defaultReferenceRange.setHiNormal(conceptNumeric.getHiNormal());
1✔
2163
                defaultReferenceRange.setLowAbsolute(conceptNumeric.getLowAbsolute());
1✔
2164
                defaultReferenceRange.setLowCritical(conceptNumeric.getLowCritical());
1✔
2165
                defaultReferenceRange.setLowNormal(conceptNumeric.getLowNormal());
1✔
2166
                return defaultReferenceRange;
1✔
2167
        }
2168

2169
        /**
2170
         * Combines multiple matching reference ranges into one by selecting the strictest bound for
2171
         * each limit. For low bounds, the highest value is strictest; for high bounds, the lowest.
2172
         * For example, ranges 80-150 and 60-140 combine to 80-140.
2173
         */
2174
        private static ConceptReferenceRange findStrictestReferenceRange(List<ConceptReferenceRange> conceptReferenceRanges) {
2175
                if (conceptReferenceRanges.size() == 1) {
1✔
2176
                        return conceptReferenceRanges.get(0);
1✔
2177
                }
2178

2179
                ConceptReferenceRange strictestRange = new ConceptReferenceRange();
1✔
2180
                strictestRange.setConceptNumeric(conceptReferenceRanges.get(0).getConceptNumeric());
1✔
2181

2182
                for (ConceptReferenceRange conceptReferenceRange : conceptReferenceRanges) {
1✔
2183
                        if (conceptReferenceRange.getLowAbsolute() != null &&
1✔
2184
                                        (strictestRange.getLowAbsolute() == null || strictestRange.getLowAbsolute() < conceptReferenceRange.getLowAbsolute())) {
1✔
2185
                                strictestRange.setLowAbsolute(conceptReferenceRange.getLowAbsolute());
1✔
2186
                        }
2187

2188
                        if (conceptReferenceRange.getLowCritical() != null &&
1✔
2189
                                        (strictestRange.getLowCritical() == null || strictestRange.getLowCritical() < conceptReferenceRange.getLowCritical())) {
1✔
2190
                                strictestRange.setLowCritical(conceptReferenceRange.getLowCritical());
1✔
2191
                        }
2192

2193
                        if (conceptReferenceRange.getLowNormal() != null &&
1✔
2194
                                        (strictestRange.getLowNormal() == null || strictestRange.getLowNormal() < conceptReferenceRange.getLowNormal())) {
1✔
2195
                                strictestRange.setLowNormal(conceptReferenceRange.getLowNormal());
1✔
2196
                        }
2197

2198
                        if (conceptReferenceRange.getHiNormal() != null &&
1✔
2199
                                        (strictestRange.getHiNormal() == null || strictestRange.getHiNormal() > conceptReferenceRange.getHiNormal())) {
1✔
2200
                                strictestRange.setHiNormal(conceptReferenceRange.getHiNormal());
1✔
2201
                        }
2202

2203
                        if (conceptReferenceRange.getHiCritical() != null &&
1✔
2204
                                        (strictestRange.getHiCritical() == null || strictestRange.getHiCritical() > conceptReferenceRange.getHiCritical())) {
1✔
2205
                                strictestRange.setHiCritical(conceptReferenceRange.getHiCritical());
1✔
2206
                        }
2207

2208
                        if (conceptReferenceRange.getHiAbsolute() != null &&
1✔
2209
                                        (strictestRange.getHiAbsolute() == null || strictestRange.getHiAbsolute() > conceptReferenceRange.getHiAbsolute())) {
1✔
2210
                                strictestRange.setHiAbsolute(conceptReferenceRange.getHiAbsolute());
1✔
2211
                        }
2212
                }
1✔
2213

2214
                return strictestRange;
1✔
2215
        }
2216

2217
        /***
2218
         * Determines if the passed string is in valid uuid format By OpenMRS standards, a uuid must be 36
2219
         * characters in length and not contain whitespace, but we do not enforce that a uuid be in the
2220
         * "canonical" form, with alphanumerics seperated by dashes, since the MVP dictionary does not use
2221
         * this format (We also are being slightly lenient and accepting uuids that are 37 or 38 characters
2222
         * in length, since the uuid data field is 38 characters long)
2223
         */
2224
        public static boolean isValidUuidFormat(String uuid) {
2225
                if (uuid.length() < 36 || uuid.length() > 38 || uuid.contains(" ") || uuid.contains(".")) {
1✔
2226
                        return false;
1✔
2227
                }
2228
                return true;
1✔
2229
        }
2230

2231
        /**
2232
         * Evaluates the specified Java constant using reflection: if input is org.openmrs.CLASS_NAME.CONSTANT_NAME
2233
         * then, output will be CONSTANT_NAME
2234
         * @param fqn the fully qualified name of the constant
2235
         * @return the constant value or null
2236
         */
2237
        private static String evaluateStaticConstant(String fqn) {
2238
                int lastPeriod = fqn.lastIndexOf(".");
1✔
2239
                String clazzName = fqn.substring(0, lastPeriod);
1✔
2240
                String constantName = fqn.substring(lastPeriod + 1);
1✔
2241
                try {
2242
                        Class<?> clazz = Context.loadClass(clazzName);
1✔
2243
                        Field constantField = clazz.getDeclaredField(constantName);
1✔
2244
                        constantField.setAccessible(true);
1✔
2245
                        Object val = constantField.get(null);
1✔
2246
                        return val != null ? String.valueOf(val) : null;
1✔
2247
                }
2248
                catch (Exception ex) {
×
2249
                        throw new APIException("Error while evaluating " + fqn + " as a constant" , ex);
×
2250
                }
2251
        }
2252
        
2253
        private List<ConceptClass> getConceptClassesOfOrderTypes() {
2254
                List<ConceptClass> mappedClasses = new ArrayList<>();
1✔
2255
                AdministrationService administrationService = Context.getAdministrationService();
1✔
2256
                List<List<Object>> result = administrationService.executeSQL(
1✔
2257
                    "SELECT DISTINCT concept_class_id FROM order_type_class_map", true);
2258
                for (List<Object> temp : result) {
1✔
2259
                        for (Object value : temp) {
1✔
2260
                                if (value != null) {
1✔
2261
                                        mappedClasses.add(this.getConceptClass((Integer) value));
1✔
2262
                                }
2263
                        }
1✔
2264
                }
1✔
2265
                return mappedClasses;
1✔
2266
        }
2267
        
2268
        /**
2269
         * @see org.openmrs.api.ConceptService#purgeConceptReferenceRange(ConceptReferenceRange)
2270
         */
2271
        @Override
2272
        public void purgeConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2273
                checkIfLocked();
1✔
2274
                dao.purgeConceptReferenceRange(conceptReferenceRange);
1✔
2275
        }
1✔
2276
}
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