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

openmrs / openmrs-core / 8606329231

08 Apr 2024 08:37PM CUT coverage: 64.712% (+0.03%) from 64.68%
8606329231

push

github

web-flow
github-actions(deps): bump actions/upload-artifact from 3 to 4 (#4615)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

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

22772 of 35190 relevant lines covered (64.71%)

0.65 hits per line

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

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

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

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

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

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

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

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

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

119
                CustomDatatypeUtil.saveAttributesIfNecessary(concept);
1✔
120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1917
                if (conceptSource == null) {
1✔
1918
                        throw new APIException("ConceptSource.is.required", (Object[]) null);
1✔
1919
                }
1920

1921
                return dao.getDrugsByMapping(code, conceptSource, tmpWithAnyOfTheseTypes, includeRetired);
1✔
1922
        }
1923
        
1924
        /**
1925
         * @see org.openmrs.api.ConceptService#getDrugByMapping(String, org.openmrs.ConceptSource, java.util.Collection)
1926
         */
1927
        @Override
1928
        @Transactional(readOnly = true)
1929
        public Drug getDrugByMapping(String code, ConceptSource conceptSource,
1930
                Collection<ConceptMapType> withAnyOfTheseTypesOrOrderOfPreference) throws APIException {
1931
                Collection<ConceptMapType> tmpWithAnyOfTheseTypesOrOrderOfPreference = withAnyOfTheseTypesOrOrderOfPreference == null
1✔
1932
                                ? Collections.emptyList() : withAnyOfTheseTypesOrOrderOfPreference;
1✔
1933

1934
                if (conceptSource == null) {
1✔
1935
                        throw new APIException("ConceptSource.is.required", (Object[]) null);
1✔
1936
                }
1937

1938
                return dao.getDrugByMapping(code, conceptSource, tmpWithAnyOfTheseTypesOrOrderOfPreference);
1✔
1939
        }
1940
        
1941
        /**
1942
         * @see org.openmrs.api.ConceptService#getOrderableConcepts(String, java.util.List, boolean,
1943
         *      Integer, Integer)
1944
         */
1945
        @Override
1946
        @Transactional(readOnly = true)
1947
        public List<ConceptSearchResult> getOrderableConcepts(String phrase, List<Locale> locales, boolean includeRetired,
1948
                Integer start, Integer length) {
1949
                List<ConceptClass> mappedClasses = getConceptClassesOfOrderTypes();
1✔
1950
                if (mappedClasses.isEmpty()) {
1✔
1951
                        return Collections.emptyList();
×
1952
                }
1953
                List<Locale> tmpLocales = locales;
1✔
1954
                if (tmpLocales == null) {
1✔
1955
                        tmpLocales = new ArrayList<>();
1✔
1956
                        tmpLocales.add(Context.getLocale());
1✔
1957
                }
1958
                return dao.getConcepts(phrase, tmpLocales, false, mappedClasses, Collections.emptyList(), Collections.emptyList(),
1✔
1959
                    Collections.emptyList(), null, start, length);
1✔
1960
        }
1961

1962
        /**
1963
         * @see ConceptService#getAllConceptAttributeTypes()
1964
         */
1965
        @Override
1966
        @Transactional(readOnly = true)
1967
        public List<ConceptAttributeType> getAllConceptAttributeTypes() {
1968
                return dao.getAllConceptAttributeTypes();
1✔
1969
        }
1970

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

1979
        /**
1980
         * @see org.openmrs.api.ConceptService#getConceptAttributeType(Integer)
1981
         */
1982
        @Override
1983
        @Transactional(readOnly = true)
1984
        public ConceptAttributeType getConceptAttributeType(Integer id) {
1985
                return dao.getConceptAttributeType(id);
1✔
1986
        }
1987

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

1997
        /**
1998
         * @see org.openmrs.api.ConceptService#purgeConceptAttributeType(ConceptAttributeType)
1999
         */
2000
        @Override
2001
        public void purgeConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2002
                dao.deleteConceptAttributeType(conceptAttributeType);
1✔
2003

2004
        }
1✔
2005

2006
        /**
2007
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypes(String)
2008
         */
2009
        @Override
2010
        @Transactional(readOnly = true)
2011
        public List<ConceptAttributeType> getConceptAttributeTypes(String name) throws APIException {
2012
                return dao.getConceptAttributeTypes(name);
1✔
2013
        }
2014

2015
        /**
2016
         * @see org.openmrs.api.ConceptService#getConceptAttributeTypeByName(String)
2017
         */
2018
        @Override
2019
        @Transactional(readOnly = true)
2020
        public ConceptAttributeType getConceptAttributeTypeByName(String exactName) {
2021
                return dao.getConceptAttributeTypeByName(exactName);
1✔
2022
        }
2023

2024
        /**
2025
         * @see org.openmrs.api.ConceptService#retireConceptAttributeType(ConceptAttributeType, String)
2026
         */
2027
        @Override
2028
        public ConceptAttributeType retireConceptAttributeType(ConceptAttributeType conceptAttributeType, String reason) {
2029
                return dao.saveConceptAttributeType(conceptAttributeType);
1✔
2030
        }
2031

2032
        /**
2033
         * @see org.openmrs.api.ConceptService#unretireConceptAttributeType(ConceptAttributeType)
2034
         */
2035
        @Override
2036
        public ConceptAttributeType unretireConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2037
                return Context.getConceptService().saveConceptAttributeType(conceptAttributeType);
1✔
2038
        }
2039

2040
        /**
2041
         * @see org.openmrs.api.ConceptService#getConceptAttributeByUuid(String)
2042
         */
2043
        @Override
2044
        @Transactional(readOnly = true)
2045
        public ConceptAttribute getConceptAttributeByUuid(String uuid) {
2046
                return dao.getConceptAttributeByUuid(uuid);
1✔
2047
        }
2048

2049
        /**
2050
         * @see org.openmrs.api.ConceptService#hasAnyConceptAttribute(ConceptAttributeType)
2051
         */
2052
        @Override
2053
        @Transactional(readOnly = true)
2054
        public boolean hasAnyConceptAttribute(ConceptAttributeType conceptAttributeType) {
2055
                return dao.getConceptAttributeCount(conceptAttributeType) > 0;
1✔
2056
        }
2057

2058
        /***
2059
         * Determines if the passed string is in valid uuid format By OpenMRS standards, a uuid must be 36
2060
         * characters in length and not contain whitespace, but we do not enforce that a uuid be in the
2061
         * "canonical" form, with alphanumerics seperated by dashes, since the MVP dictionary does not use
2062
         * this format (We also are being slightly lenient and accepting uuids that are 37 or 38 characters
2063
         * in length, since the uuid data field is 38 characters long)
2064
         */
2065
        public static boolean isValidUuidFormat(String uuid) {
2066
                if (uuid.length() < 36 || uuid.length() > 38 || uuid.contains(" ") || uuid.contains(".")) {
1✔
2067
                        return false;
1✔
2068
                }
2069
                return true;
1✔
2070
        }
2071

2072
        /**
2073
         * Evaluates the specified Java constant using reflection: if input is org.openmrs.CLASS_NAME.CONSTANT_NAME
2074
         * then, output will be CONSTANT_NAME
2075
         * @param fqn the fully qualified name of the constant
2076
         * @return the constant value or null
2077
         */
2078
        private static String evaluateStaticConstant(String fqn) {
2079
                int lastPeriod = fqn.lastIndexOf(".");
1✔
2080
                String clazzName = fqn.substring(0, lastPeriod);
1✔
2081
                String constantName = fqn.substring(lastPeriod + 1);
1✔
2082
                try {
2083
                        Class<?> clazz = Context.loadClass(clazzName);
1✔
2084
                        Field constantField = clazz.getDeclaredField(constantName);
1✔
2085
                        constantField.setAccessible(true);
1✔
2086
                        Object val = constantField.get(null);
1✔
2087
                        return val != null ? String.valueOf(val) : null;
1✔
2088
                }
2089
                catch (Exception ex) {
×
2090
                        throw new APIException("Error while evaluating " + fqn + " as a constant" , ex);
×
2091
                }
2092
        }
2093
        
2094
        private List<ConceptClass> getConceptClassesOfOrderTypes() {
2095
                List<ConceptClass> mappedClasses = new ArrayList<>();
1✔
2096
                AdministrationService administrationService = Context.getAdministrationService();
1✔
2097
                List<List<Object>> result = administrationService.executeSQL(
1✔
2098
                    "SELECT DISTINCT concept_class_id FROM order_type_class_map", true);
2099
                for (List<Object> temp : result) {
1✔
2100
                        for (Object value : temp) {
1✔
2101
                                if (value != null) {
1✔
2102
                                        mappedClasses.add(this.getConceptClass((Integer) value));
1✔
2103
                                }
2104
                        }
1✔
2105
                }
1✔
2106
                return mappedClasses;
1✔
2107
        }
2108
}
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

© 2025 Coveralls, Inc