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

openmrs / openmrs-core / 17991776982

24 Sep 2025 10:53PM UTC coverage: 64.928% (-0.05%) from 64.977%
17991776982

push

github

dkayiwa
TRUNK-6433 add isObsValueCodedAnswer method

7 of 10 new or added lines in 1 file covered. (70.0%)

21 existing lines in 9 files now uncovered.

23421 of 36072 relevant lines covered (64.93%)

0.65 hits per line

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

74.56
/api/src/main/java/org/openmrs/api/context/ServiceContext.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.context;
11

12
import java.util.ArrayList;
13
import java.util.Collections;
14
import java.util.HashMap;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Map.Entry;
19
import java.util.Set;
20

21
import org.aopalliance.aop.Advice;
22
import org.openmrs.api.APIException;
23
import org.openmrs.api.AdministrationService;
24
import org.openmrs.api.CohortService;
25
import org.openmrs.api.ConceptService;
26
import org.openmrs.api.ConditionService;
27
import org.openmrs.api.DatatypeService;
28
import org.openmrs.api.DiagnosisService;
29
import org.openmrs.api.EncounterService;
30
import org.openmrs.api.FormService;
31
import org.openmrs.api.LocationService;
32
import org.openmrs.api.MedicationDispenseService;
33
import org.openmrs.api.ObsService;
34
import org.openmrs.api.OpenmrsService;
35
import org.openmrs.api.OrderService;
36
import org.openmrs.api.OrderSetService;
37
import org.openmrs.api.PatientService;
38
import org.openmrs.api.PersonService;
39
import org.openmrs.api.ProgramWorkflowService;
40
import org.openmrs.api.ProviderService;
41
import org.openmrs.api.SerializationService;
42
import org.openmrs.api.ServiceNotFoundException;
43
import org.openmrs.api.UserService;
44
import org.openmrs.api.VisitService;
45
import org.openmrs.hl7.HL7Service;
46
import org.openmrs.logic.LogicService;
47
import org.openmrs.messagesource.MessageSourceService;
48
import org.openmrs.messagesource.impl.DefaultMessageSourceServiceImpl;
49
import org.openmrs.notification.AlertService;
50
import org.openmrs.notification.MessageService;
51
import org.openmrs.scheduler.SchedulerService;
52
import org.openmrs.util.OpenmrsClassLoader;
53
import org.openmrs.util.OpenmrsThreadPoolHolder;
54
import org.slf4j.Logger;
55
import org.slf4j.LoggerFactory;
56
import org.springframework.aop.Advisor;
57
import org.springframework.aop.framework.Advised;
58
import org.springframework.aop.framework.ProxyFactory;
59
import org.springframework.beans.BeansException;
60
import org.springframework.context.ApplicationContext;
61
import org.springframework.context.ApplicationContextAware;
62

63
/**
64
 * Represents an OpenMRS <code>Service Context</code>, which returns the services represented
65
 * throughout the system. <br>
66
 * <br>
67
 * This class should not be access directly, but rather used through the <code>Context</code> class. <br>
68
 * <br>
69
 * This class is essentially static and only one instance is kept because this is fairly
70
 * heavy-weight. Spring takes care of filling in the actual service implementations via dependency
71
 * injection. See the /metadata/api/spring/applicationContext-service.xml file. <br>
72
 * <br>
73
 * Module services are also accessed through this class. See {@link #getService(Class)}
74
 *
75
 * @see org.openmrs.api.context.Context
76
 */
77
public class ServiceContext implements ApplicationContextAware {
78
        
79
        private static final Logger log = LoggerFactory.getLogger(ServiceContext.class);
1✔
80

81
        private ApplicationContext applicationContext;
82
        
83
        private static boolean refreshingContext = false;
1✔
84
        
85
        private static final Object refreshingContextLock = new Object();
1✔
86
        
87
        /**
88
         * Static variable holding whether or not to use the system classloader. By default this is
89
         * false so the openmrs classloader is used instead
90
         */
91
        private boolean useSystemClassLoader = false;
1✔
92
        
93
        // Cached service objects
94
        Map<Class, Object> services = new HashMap<>();
1✔
95
        
96
        // Advisors added to services by this service
97
        Map<Class, Set<Advisor>> addedAdvisors = new HashMap<>();
1✔
98
        
99
        // Advice added to services by this service
100
        Map<Class, Set<Advice>> addedAdvice = new HashMap<>();
1✔
101
        
102
        /**
103
         * Services implementing the OpenmrsService interface for each module. The map is keyed by the
104
         * full class name including package.
105
         *
106
         * @since 1.9
107
         */
108
        Map<String, OpenmrsService> moduleOpenmrsServices = new HashMap<>();
1✔
109
        
110
        /**
111
         * The default constructor is private so as to keep only one instance per java vm.
112
         *
113
         * @see ServiceContext#getInstance()
114
         */
115
        private ServiceContext() {
1✔
116
                log.debug("Instantiating service context");
1✔
117
        }
1✔
118
        
119
        private static class ServiceContextHolder {
120

121
                private ServiceContextHolder() {
122
                }
123

124
                private static ServiceContext instance = null;
1✔
125
        }
126
        
127
        /**
128
         * There should only be one ServiceContext per openmrs (java virtual machine). This method
129
         * should be used when wanting to fetch the service context Note: The ServiceContext shouldn't
130
         * be used independently. All calls should go through the Context
131
         *
132
         * @return This VM's current ServiceContext.
133
         * @see org.openmrs.api.context.Context
134
         */
135
        public static ServiceContext getInstance() {
136
                if (ServiceContextHolder.instance == null) {
1✔
137
                        ServiceContextHolder.instance = new ServiceContext();
1✔
138
                }
139
                
140
                return ServiceContextHolder.instance;
1✔
141
        }
142
        
143
        /**
144
         * Null out the current instance of the ServiceContext. This should be used when modules are
145
         * refreshing (being added/removed) and/or openmrs is shutting down
146
         */
147
        public static void destroyInstance() {
148
                if (ServiceContextHolder.instance != null && ServiceContextHolder.instance.services != null) {
1✔
149
                        for (Map.Entry<Class, Object> entry : ServiceContextHolder.instance.services.entrySet()) {
1✔
150
                                log.debug("Service - {} : {}", entry.getKey().getName(), entry.getValue());
1✔
151
                        }
1✔
152
                        
153
                        // Remove advice and advisors that this service added
154
                        for (Class serviceClass : ServiceContextHolder.instance.services.keySet()) {
1✔
155
                                ServiceContextHolder.instance.removeAddedAOP(serviceClass);
1✔
156
                        }
1✔
157
                        
158
                        if (ServiceContextHolder.instance.services != null) {
1✔
159
                                ServiceContextHolder.instance.services.clear();
1✔
160
                                ServiceContextHolder.instance.services = null;
1✔
161
                        }
162
                        
163
                        if (ServiceContextHolder.instance.addedAdvisors != null) {
1✔
164
                                ServiceContextHolder.instance.addedAdvisors.clear();
1✔
165
                                ServiceContextHolder.instance.addedAdvisors = null;
1✔
166
                        }
167
                        
168
                        if (ServiceContextHolder.instance.addedAdvice != null) {
1✔
169
                                ServiceContextHolder.instance.addedAdvice.clear();
1✔
170
                                ServiceContextHolder.instance.addedAdvice = null;
1✔
171
                        }
172
                }
173
                
174
                if (ServiceContextHolder.instance != null) {
1✔
175
                        ServiceContextHolder.instance.applicationContext = null;
1✔
176
                        
177
                        if (ServiceContextHolder.instance.moduleOpenmrsServices != null) {
1✔
178
                                ServiceContextHolder.instance.moduleOpenmrsServices.clear();
1✔
179
                                ServiceContextHolder.instance.moduleOpenmrsServices = null;
1✔
180
                        }
181
                }
182
                log.debug("Destroying ServiceContext instance: {}", ServiceContextHolder.instance);
1✔
183
                ServiceContextHolder.instance = null;
1✔
184
        }
1✔
185
        
186
        /**
187
         * @return encounter-related services
188
         */
189
        public EncounterService getEncounterService() {
190
                return getService(EncounterService.class);
1✔
191
        }
192
        
193
        /**
194
         * @return location services
195
         */
196
        public LocationService getLocationService() {
197
                return getService(LocationService.class);
1✔
198
        }
199
        
200
        /**
201
         * @return observation services
202
         */
203
        public ObsService getObsService() {
204
                return getService(ObsService.class);
1✔
205
        }
206
        
207
        /**
208
         * @return condition related service
209
         * 
210
         * @since 2.2
211
         */
212
        public ConditionService getConditionService() {
213
                return getService(ConditionService.class);
1✔
214
        }
215
        
216
        /**
217
         * @param conditionService condition related service
218
         *            
219
         * @since 2.2   
220
         */
221
        public void setConditionService(ConditionService conditionService) {
222
                setService(ConditionService.class, conditionService);
1✔
223
        }
1✔
224

225
        /**
226
         * @return diagnosis related service
227
         *
228
         * @since 2.2
229
         */
230
        public DiagnosisService getDiagnosisService() {
231
                return getService(DiagnosisService.class);
1✔
232
        }
233

234
        /**
235
         * @param diagnosisService diagnosis related service
236
         *
237
         * @since 2.2
238
         */
239
        public void setDiagnosisService(DiagnosisService diagnosisService) {
240
                setService(DiagnosisService.class, diagnosisService);
1✔
241
        }
1✔
242

243
        /**
244
         * @return MedicationDispense related service
245
         * @since 2.6.0
246
         */
247
        public MedicationDispenseService getMedicationDispenseService() {
248
                return getService(MedicationDispenseService.class);
×
249
        }
250

251
        /**
252
         * @param medicationDispenseService MedicationDispense related service
253
         * @since 2.6.0
254
         */
255
        public void setMedicationDispenseService(MedicationDispenseService medicationDispenseService) {
256
                setService(MedicationDispenseService.class, medicationDispenseService);
1✔
257
        }
1✔
258
        
259
        /**
260
         * @return cohort related service
261
         */
262
        public CohortService getCohortService() {
263
                return getService(CohortService.class);
1✔
264
        }
265
        
266
        /**
267
         * @param cs cohort related service
268
         */
269
        public void setCohortService(CohortService cs) {
270
                setService(CohortService.class, cs);
1✔
271
        }
1✔
272
        
273
        /**
274
         * @return order set service
275
         */
276
        public OrderSetService getOrderSetService() {
277
                return getService(OrderSetService.class);
1✔
278
        }
279
        
280
        /**
281
         * @return order service
282
         */
283
        public OrderService getOrderService() {
284
                return getService(OrderService.class);
1✔
285
        }
286
        
287
        /**
288
         * @return form service
289
         */
290
        public FormService getFormService() {
291
                return getService(FormService.class);
1✔
292
        }
293
        
294
        /**
295
         * @return serialization service
296
         */
297
        public SerializationService getSerializationService() {
298
                return getService(SerializationService.class);
1✔
299
        }
300
        
301
        /**
302
         * @return admin-related services
303
         */
304
        public AdministrationService getAdministrationService() {
305
                return getService(AdministrationService.class);
1✔
306
        }
307
        
308
        /**
309
         * @return programWorkflowService
310
         */
311
        public ProgramWorkflowService getProgramWorkflowService() {
312
                return getService(ProgramWorkflowService.class);
1✔
313
        }
314

315
        /**
316
         * @return logicService
317
         */
318
        public LogicService getLogicService() {
319
                return getService(LogicService.class);
×
320
        }
321
        
322
        /**
323
         * @return scheduler service
324
         */
325
        public SchedulerService getSchedulerService() {
326
                return getService(SchedulerService.class);
1✔
327
        }
328
        
329
        /**
330
         * Set the scheduler service.
331
         *
332
         * @param schedulerService
333
         */
334
        public void setSchedulerService(SchedulerService schedulerService) {
335
                setService(SchedulerService.class, schedulerService);
1✔
336
        }
1✔
337
        
338
        /**
339
         * @return alert service
340
         */
341
        public AlertService getAlertService() {
342
                return getService(AlertService.class);
1✔
343
        }
344
        
345
        /**
346
         * @param alertService
347
         */
348
        public void setAlertService(AlertService alertService) {
349
                setService(AlertService.class, alertService);
1✔
350
        }
1✔
351
        
352
        /**
353
         * @param programWorkflowService
354
         */
355
        public void setProgramWorkflowService(ProgramWorkflowService programWorkflowService) {
356
                setService(ProgramWorkflowService.class, programWorkflowService);
1✔
357
        }
1✔
358

359
        /**
360
         * @param logicService
361
         */
362
        public void setLogicService(LogicService logicService) {
363
                setService(LogicService.class, logicService);
×
364
        }
×
365
        
366
        /**
367
         * @return message service
368
         */
369
        public MessageService getMessageService() {
370
                return getService(MessageService.class);
1✔
371
        }
372
        
373
        /**
374
         * Sets the message service.
375
         *
376
         * @param messageService
377
         */
378
        public void setMessageService(MessageService messageService) {
379
                setService(MessageService.class, messageService);
1✔
380
        }
1✔
381
        
382
        /**
383
         * @return the hl7Service
384
         */
385
        public HL7Service getHL7Service() {
386
                return getService(HL7Service.class);
1✔
387
        }
388
        
389
        /**
390
         * @param hl7Service the hl7Service to set
391
         */
392
        public void setHl7Service(HL7Service hl7Service) {
393
                setService(HL7Service.class, hl7Service);
1✔
394
        }
1✔
395
        
396
        /**
397
         * @param administrationService the administrationService to set
398
         */
399
        public void setAdministrationService(AdministrationService administrationService) {
400
                setService(AdministrationService.class, administrationService);
1✔
401
        }
1✔
402
        
403
        /**
404
         * @param encounterService the encounterService to set
405
         */
406
        public void setEncounterService(EncounterService encounterService) {
407
                setService(EncounterService.class, encounterService);
1✔
408
        }
1✔
409
        
410
        /**
411
         * @param locationService the LocationService to set
412
         */
413
        public void setLocationService(LocationService locationService) {
414
                setService(LocationService.class, locationService);
1✔
415
        }
1✔
416
        
417
        /**
418
         * @param formService the formService to set
419
         */
420
        public void setFormService(FormService formService) {
421
                setService(FormService.class, formService);
1✔
422
        }
1✔
423
        
424
        /**
425
         * @param obsService the obsService to set
426
         */
427
        public void setObsService(ObsService obsService) {
428
                setService(ObsService.class, obsService);
1✔
429
        }
1✔
430

431
        /**
432
         * @param orderService the orderService to set
433
         */
434
        public void setOrderService(OrderService orderService) {
435
                setService(OrderService.class, orderService);
1✔
436
        }
1✔
437
        
438
        /**
439
         * @param orderSetService the orderSetService to set
440
         */
441
        public void setOrderSetService(OrderSetService orderSetService) {
442
                setService(OrderSetService.class, orderSetService);
1✔
443
        }
1✔
444
        
445
        /**
446
         * @param serializationService
447
         */
448
        public void setSerializationService(SerializationService serializationService) {
449
                setService(SerializationService.class, serializationService);
1✔
450
        }
1✔
451
        
452
        /**
453
         * @return patient related services
454
         */
455
        public PatientService getPatientService() {
456
                return getService(PatientService.class);
1✔
457
        }
458
        
459
        /**
460
         * @param patientService the patientService to set
461
         */
462
        public void setPatientService(PatientService patientService) {
463
                setService(PatientService.class, patientService);
1✔
464
        }
1✔
465
        
466
        /**
467
         * @return person related services
468
         */
469
        public PersonService getPersonService() {
470
                return getService(PersonService.class);
1✔
471
        }
472
        
473
        /**
474
         * @param personService the personService to set
475
         */
476
        public void setPersonService(PersonService personService) {
477
                setService(PersonService.class, personService);
1✔
478
        }
1✔
479
        
480
        /**
481
         * @return concept related services
482
         */
483
        public ConceptService getConceptService() {
484
                return getService(ConceptService.class);
1✔
485
        }
486
        
487
        /**
488
         * @param conceptService the conceptService to set
489
         */
490
        public void setConceptService(ConceptService conceptService) {
491
                setService(ConceptService.class, conceptService);
1✔
492
        }
1✔
493
        
494
        /**
495
         * @return user-related services
496
         */
497
        public UserService getUserService() {
498
                return getService(UserService.class);
1✔
499
        }
500
        
501
        /**
502
         * @param userService the userService to set
503
         */
504
        public void setUserService(UserService userService) {
505
                setService(UserService.class, userService);
1✔
506
        }
1✔
507
        
508
        /**
509
         * Gets the MessageSourceService used in the context.
510
         *
511
         * @return MessageSourceService
512
         */
513
        public MessageSourceService getMessageSourceService() {
514
                try {
515
                        return getService(MessageSourceService.class);
1✔
516
                }
UNCOV
517
                catch (APIException ex) {
×
518
                        //must be a service not found exception because of spring not being started
UNCOV
519
                        return DefaultMessageSourceServiceImpl.getInstance();
×
520
                }
521
        }
522
        
523
        /**
524
         * Sets the MessageSourceService used in the context.
525
         *
526
         * @param messageSourceService the MessageSourceService to use
527
         */
528
        public void setMessageSourceService(MessageSourceService messageSourceService) {
529
                setService(MessageSourceService.class, messageSourceService);
1✔
530
        }
1✔
531
        
532
        /**
533
         * @param cls
534
         * @param advisor
535
         */
536
        public void addAdvisor(Class cls, Advisor advisor) {
537
                Advised advisedService = (Advised) services.get(cls);
×
538
                if (advisedService.indexOf(advisor) < 0) {
×
539
                        advisedService.addAdvisor(advisor);
×
540
                }
541
                addedAdvisors.computeIfAbsent(cls, k -> new HashSet<>());
×
542
                getAddedAdvisors(cls).add(advisor);
×
543
        }
×
544
        
545
        /**
546
         * @param cls
547
         * @param advice
548
         */
549
        public void addAdvice(Class cls, Advice advice) {
550
                Advised advisedService = (Advised) services.get(cls);
×
551
                if (advisedService.indexOf(advice) < 0) {
×
552
                        advisedService.addAdvice(advice);
×
553
                }
554
                addedAdvice.computeIfAbsent(cls, k -> new HashSet<>());
×
555
                getAddedAdvice(cls).add(advice);
×
556
        }
×
557
        
558
        /**
559
         * @param cls
560
         * @param advisor
561
         */
562
        public void removeAdvisor(Class cls, Advisor advisor) {
563
                Advised advisedService = (Advised) services.get(cls);
×
564
                advisedService.removeAdvisor(advisor);
×
565
                getAddedAdvisors(cls).remove(advisor);
×
566
        }
×
567
        
568
        /**
569
         * @param cls
570
         * @param advice
571
         */
572
        public void removeAdvice(Class cls, Advice advice) {
573
                Advised advisedService = (Advised) services.get(cls);
×
574
                advisedService.removeAdvice(advice);
×
575
                getAddedAdvice(cls).remove(advice);
×
576
        }
×
577
        
578
        /**
579
         * Moves advisors and advice added by ServiceContext from the source service to the target one.
580
         *
581
         * @param source the existing service
582
         * @param target the new service
583
         */
584
        private void moveAddedAOP(Advised source, Advised target) {
585
                Class serviceClass = source.getClass();
1✔
586
                Set<Advisor> existingAdvisors = getAddedAdvisors(serviceClass);
1✔
587
                for (Advisor advisor : existingAdvisors) {
1✔
588
                        target.addAdvisor(advisor);
×
589
                        source.removeAdvisor(advisor);
×
590
                }
×
591
                
592
                Set<Advice> existingAdvice = getAddedAdvice(serviceClass);
1✔
593
                for (Advice advice : existingAdvice) {
1✔
594
                        target.addAdvice(advice);
×
595
                        source.removeAdvice(advice);
×
596
                }
×
597
        }
1✔
598
        
599
        /**
600
         * Removes all advice and advisors added by ServiceContext.
601
         *
602
         * @param cls the class of the cached service to cleanup
603
         */
604
        private void removeAddedAOP(Class cls) {
605
                removeAddedAdvisors(cls);
1✔
606
                removeAddedAdvice(cls);
1✔
607
        }
1✔
608
        
609
        /**
610
         * Removes all the advisors added by ServiceContext.
611
         *
612
         * @param cls the class of the cached service to cleanup
613
         */
614
        private void removeAddedAdvisors(Class cls) {
615
                Advised advisedService = (Advised) services.get(cls);
1✔
616
                Set<Advisor> advisorsToRemove = addedAdvisors.get(cls);
1✔
617
                if (advisedService != null && advisorsToRemove != null) {
1✔
618
                        for (Advisor advisor : advisorsToRemove.toArray(new Advisor[] {})) {
×
619
                                removeAdvisor(cls, advisor);
×
620
                        }
621
                }
622
        }
1✔
623
        
624
        /**
625
         * Returns the set of advisors added by ServiceContext.
626
         *
627
         * @param cls the class of the cached service
628
         * @return the set of advisors or an empty set
629
         */
630
        @SuppressWarnings("unchecked")
631
        private Set<Advisor> getAddedAdvisors(Class cls) {
632
                Set<Advisor> result = addedAdvisors.get(cls);
1✔
633
                return (Set<Advisor>) (result == null ? Collections.emptySet() : result);
1✔
634
        }
635
        
636
        /**
637
         * Removes all the advice added by the ServiceContext.
638
         *
639
         * @param cls the class of the caches service to cleanup
640
         */
641
        private void removeAddedAdvice(Class cls) {
642
                Advised advisedService = (Advised) services.get(cls);
1✔
643
                Set<Advice> adviceToRemove = addedAdvice.get(cls);
1✔
644
                if (advisedService != null && adviceToRemove != null) {
1✔
645
                        for (Advice advice : adviceToRemove.toArray(new Advice[] {})) {
×
646
                                removeAdvice(cls, advice);
×
647
                        }
648
                }
649
        }
1✔
650
        
651
        /**
652
         * Returns the set of advice added by ServiceContext.
653
         *
654
         * @param cls the class of the cached service
655
         * @return the set of advice or an empty set
656
         */
657
        @SuppressWarnings("unchecked")
658
        private Set<Advice> getAddedAdvice(Class cls) {
659
                Set<Advice> result = addedAdvice.get(cls);
1✔
660
                return (Set<Advice>) (result == null ? Collections.emptySet() : result);
1✔
661
        }
662
        
663
        /**
664
         * Returns the current proxy that is stored for the Class <code>cls</code>
665
         *
666
         * @param cls
667
         * @return Object that is a proxy for the <code>cls</code> class
668
         */
669
        @SuppressWarnings("unchecked")
670
        public <T> T getService(Class<? extends T> cls) {
671
                if (log.isTraceEnabled()) {
1✔
672
                        log.trace("Getting service: " + cls);
×
673
                }
674
                
675
                // if the context is refreshing, wait until it is
676
                // done -- otherwise a null service might be returned
677
                synchronized (refreshingContextLock) {
1✔
678
                        try {
679
                                while (refreshingContext) {
1✔
680
                                        log.debug("Waiting to get service: {} while the context is being refreshed", cls);
×
681
                                        
682
                                        refreshingContextLock.wait();
×
683
                                        
684
                                        log.debug("Finished waiting to get service {} while the context was being refreshed", cls);
×
685
                                }
686
                                
687
                        }
688
                        catch (InterruptedException e) {
×
689
                                log.warn("Refresh lock was interrupted", e);
×
690
                        }
1✔
691
                }
1✔
692
                
693
                Object service = services.get(cls);
1✔
694
                if (service == null) {
1✔
695
                        throw new ServiceNotFoundException(cls);
1✔
696
                }
697
                
698
                return (T) service;
1✔
699
        }
700
        
701
        /**
702
         * Allow other services to be added to our service layer
703
         *
704
         * @param cls Interface to proxy
705
         * @param classInstance the actual instance of the <code>cls</code> interface
706
         */
707
        public void setService(Class<?> cls, Object classInstance) {
708
                log.debug("Setting service: {}", cls);
1✔
709
                
710
                if (cls != null && classInstance != null) {
1✔
711
                        try {
712
                                Advised cachedService = (Advised) services.get(cls);
1✔
713
                                boolean noExistingService = cachedService == null;
1✔
714
                                boolean replacingService = cachedService != null && cachedService != classInstance;
1✔
715
                                boolean serviceAdvised = classInstance instanceof Advised;
1✔
716
                                
717
                                if (noExistingService || replacingService) {
1✔
718
                                        
719
                                        Advised advisedService;
720
                                        
721
                                        if (!serviceAdvised) {
1✔
722
                                                // Adding a bare service, wrap with AOP proxy
723
                                                Class[] interfaces = { cls };
1✔
724
                                                ProxyFactory factory = new ProxyFactory(interfaces);
1✔
725
                                                factory.setTarget(classInstance);
1✔
726
                                                advisedService = (Advised) factory.getProxy(OpenmrsClassLoader.getInstance());
1✔
727
                                        } else {
1✔
728
                                                advisedService = (Advised) classInstance;
1✔
729
                                        }
730
                                        
731
                                        if (replacingService) {
1✔
732
                                                moveAddedAOP(cachedService, advisedService);
1✔
733
                                        }
734
                                        
735
                                        services.put(cls, advisedService);
1✔
736
                                }
737
                                log.debug("Service: {} set successfully", cls);
1✔
738
                        }
739
                        catch (Exception e) {
×
740
                                throw new APIException("service.unable.create.proxy.factory", new Object[] { classInstance.getClass()
×
741
                                        .getName() }, e);
×
742
                        }
1✔
743
                        
744
                }
745
        }
1✔
746
        
747
        /**
748
         * Allow other services to be added to our service layer <br>
749
         * <br>
750
         * Classes will be found/loaded with the ModuleClassLoader <br>
751
         * <br>
752
         * <code>params</code>[0] = string representing the service interface<br>
753
         * <code>params</code>[1] = service instance
754
         *
755
         * @param params list of parameters
756
         */
757
        public void setModuleService(List<Object> params) {
758
                String classString = (String) params.get(0);
1✔
759
                Object classInstance = params.get(1);
1✔
760
                
761
                if (classString == null || classInstance == null) {
1✔
762
                        throw new APIException(
1✔
763
                                String.format("Unable to find service as unexpected null value found for class [%s] or instance [%s]",
1✔
764
                                    classString, classInstance));
765
                }
766
                
767
                Class cls = null;
1✔
768
                
769
                // load the given 'classString' class from either the openmrs class
770
                // loader or the system class loader depending on if we're in a testing
771
                // environment or not (system == testing, openmrs == normal)
772
                try {
773
                        if (!useSystemClassLoader) {
1✔
774
                                cls = OpenmrsClassLoader.getInstance().loadClass(classString);
1✔
775
                                
776
                                if (cls != null && log.isDebugEnabled()) {
1✔
777
                                        try {
778
                                                log.debug("cls classloader: {} uid: {}", cls.getClass().getClassLoader(),
×
779
                                                    cls.getClass().getClassLoader().hashCode());
×
780
                                        }
781
                                        catch (Exception e) { /*pass*/}
×
782
                                }
783
                        } else if (useSystemClassLoader) {
×
784
                                try {
785
                                        cls = Class.forName(classString);
×
786
                                        log.debug("cls2 classloader: {} uid: {}", cls.getClass().getClassLoader(),
×
787
                                            cls.getClass().getClassLoader().hashCode());
×
788
                                        //pay attention that here, cls = Class.forName(classString), the system class loader and
789
                                        //cls2 is the openmrs class loader, like above.
790
                                        log.debug("cls==cls2: {}",
×
791
                                            String.valueOf(cls == OpenmrsClassLoader.getInstance().loadClass(classString)));
×
792
                                }
793
                                catch (Exception e) { /*pass*/}
×
794
                        }
795
                }
796
                catch (ClassNotFoundException e) {
1✔
797
                        throw new APIException("Unable to find service as class not found: " + classString, e);
1✔
798
                }
1✔
799
                
800
                // add this module service to the normal list of services
801
                setService(cls, classInstance);
1✔
802
                
803
                //Run onStartup for all services implementing the OpenmrsService interface.
804
                if (OpenmrsService.class.isAssignableFrom(classInstance.getClass())) {
1✔
805
                        moduleOpenmrsServices.put(classString, (OpenmrsService) classInstance);
1✔
806
                        runOpenmrsServiceOnStartup((OpenmrsService) classInstance, classString);
1✔
807
                }
808
        }
1✔
809
        
810
        /**
811
         * Set this service context to use the system class loader if the
812
         * <code>useSystemClassLoader</code> is set to true. If false, the openmrs class loader is used
813
         * to load module services
814
         *
815
         * @param useSystemClassLoader true/false whether to use the system class loader
816
         */
817
        public void setUseSystemClassLoader(boolean useSystemClassLoader) {
818
                this.useSystemClassLoader = useSystemClassLoader;
1✔
819
        }
1✔
820
        
821
        /**
822
         * Checks if we are using the system class loader.
823
         *
824
         * @return true if using the system class loader, else false.
825
         */
826
        public boolean isUseSystemClassLoader() {
827
                return useSystemClassLoader;
1✔
828
        }
829
        
830
        public static void setRefreshingContext(boolean refreshingContext) {
831
                ServiceContext.refreshingContext = refreshingContext;
×
832
        }
×
833
        
834
        /**
835
         * Should be called <b>right before</b> any spring context refresh This forces all calls to
836
         * getService to wait until <code>doneRefreshingContext</code> is called
837
         */
838
        public void startRefreshingContext() {
839
                synchronized (refreshingContextLock) {
×
840
                        log.info("Refreshing Context");
×
841
                        setRefreshingContext(true);
×
842
                }
×
843
        }
×
844
        
845
        /**
846
         * Should be called <b>right after</b> any spring context refresh This wakes up all calls to
847
         * getService that were waiting because <code>startRefreshingContext</code> was called
848
         */
849
        public void doneRefreshingContext() {
850
                synchronized (refreshingContextLock) {
×
851
                        log.info("Done refreshing Context");
×
852
                        setRefreshingContext(false);
×
853
                        refreshingContextLock.notifyAll();
×
854
                }
×
855
        }
×
856
        
857
        /**
858
         * Returns true/false whether startRefreshingContext() has been called without a subsequent call
859
         * to doneRefreshingContext() yet. All methods involved in starting/stopping a module should
860
         * call this if a service method is needed -- otherwise a deadlock will occur.
861
         *
862
         * @return true/false whether the services are currently blocking waiting for a call to
863
         *         doneRefreshingContext()
864
         */
865
        public boolean isRefreshingContext() {
866
                synchronized (refreshingContextLock) {
1✔
867
                        return refreshingContext;
1✔
868
                }
869
        }
870
        
871
        /**
872
         * Retrieves all Beans which have been registered in the Spring {@link ApplicationContext} that
873
         * match the given object type (including subclasses).
874
         * <p>
875
         * <b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i> check nested
876
         * beans which might match the specified type as well.
877
         *
878
         * @see ApplicationContext#getBeansOfType(Class)
879
         * @param type the type of Bean to retrieve from the Spring {@link ApplicationContext}
880
         * @return a List of all registered Beans that are valid instances of the passed type
881
         * @since 1.5
882
         * <strong>Should</strong> return a list of all registered beans of the passed type
883
         * <strong>Should</strong> return beans registered in a module
884
         * <strong>Should</strong> return an empty list if no beans have been registered of the passed type
885
         */
886
        
887
        public <T> List<T> getRegisteredComponents(Class<T> type) {
888
                Map<String, T> m = getRegisteredComponents(applicationContext, type);
1✔
889
                log.trace("getRegisteredComponents({}) = {}", type, m);
1✔
890
                return new ArrayList<>(m.values());
1✔
891
        }
892
        
893
        /**
894
         * Retrieves a bean that match the given type (including subclasses) and name.
895
         *
896
         * @param beanName the name of registered bean to retrieve
897
         * @param type the type of bean to retrieve 
898
         * @return bean of passed type
899
         *
900
         * @since 1.9.4
901
         */
902
        public <T> T getRegisteredComponent(String beanName, Class<T> type) throws APIException {
903
                try {
904
                        return applicationContext.getBean(beanName, type);
1✔
905
                }
906
                catch (BeansException beanException) {
1✔
907
                        throw new APIException("Error during getting registered component", beanException);
1✔
908
                }
909
        }
910
        
911
        /**
912
         * Private method which returns all components registered in a Spring applicationContext of a
913
         * given type This method recurses through each parent ApplicationContext
914
         *
915
         * @param context - The applicationContext to check
916
         * @param type - The type of component to retrieve
917
         * @return all components registered in a Spring applicationContext of a given type
918
         */
919
        private <T> Map<String, T> getRegisteredComponents(ApplicationContext context, Class<T> type) {
920
                Map<String, T> registeredComponents = context.getBeansOfType(type);
1✔
921
                log.trace("getRegisteredComponents({}, {}) = {}", context, type, registeredComponents);
1✔
922
                Map<String, T> components = new HashMap<>(registeredComponents);
1✔
923
                if (context.getParent() != null) {
1✔
924
                        components.putAll(getRegisteredComponents(context.getParent(), type));
1✔
925
                }
926
                return components;
1✔
927
        }
928
        
929
        /**
930
         * @param applicationContext the applicationContext to set
931
         */
932
        @Override
933
        public void setApplicationContext(ApplicationContext applicationContext) {
934
                this.applicationContext = applicationContext;
1✔
935
        }
1✔
936
        
937
        public ApplicationContext getApplicationContext() {
938
                return applicationContext;
1✔
939
        }
940
        
941
        /**
942
         * Calls the {@link OpenmrsService#onStartup()} method for an instance implementing the
943
         * {@link OpenmrsService} interface.
944
         *
945
         * @param openmrsService instance implementing the {@link OpenmrsService} interface.
946
         * @param classString the full instance class name including the package name.
947
         * @since 1.9
948
         */
949
        private void runOpenmrsServiceOnStartup(final OpenmrsService openmrsService, final String classString) {
950
                OpenmrsThreadPoolHolder.threadExecutor.execute(() -> {
1✔
951
                        try {
952
                                synchronized (refreshingContextLock) {
1✔
953
                                        //Need to wait for application context to finish refreshing otherwise we get into trouble.
954
                                        while (refreshingContext) {
1✔
955
                                                log.debug("Waiting to get service: {} while the context is being refreshed", classString);
×
956
        
957
                                                refreshingContextLock.wait();
×
958
        
959
                                                log.debug("Finished waiting to get service {} while the context was being refreshed", classString);
×
960
                                        }
961
                                }
1✔
962
        
963
                                Daemon.runStartupForService(openmrsService);
1✔
964
                        }
965
                                catch (InterruptedException e) {
×
966
                                log.warn("Refresh lock was interrupted while waiting to run OpenmrsService.onStartup() for "
×
967
                                        + classString, e);
968
                        }
1✔
969
                });
1✔
970
        }
1✔
971
        
972
        /**
973
         * Gets a list of services implementing the {@link OpenmrsService} interface, for a given
974
         * module.
975
         *
976
         * @param modulePackage the module's package name.
977
         * @return the list of service instances.
978
         * @since 1.9
979
         */
980
        public List<OpenmrsService> getModuleOpenmrsServices(String modulePackage) {
981
                List<OpenmrsService> openmrsServices = new ArrayList<>();
1✔
982
                
983
                for (Entry<String, OpenmrsService> entry : moduleOpenmrsServices.entrySet()) {
1✔
984
                        if (entry.getKey().startsWith(modulePackage)) {
1✔
985
                                openmrsServices.add(entry.getValue());
1✔
986
                        }
987
                }
1✔
988
                
989
                return openmrsServices;
1✔
990
        }
991
        
992
        /**
993
         * Gets the visit service.
994
         *
995
         * @return visit service.
996
         * @since 1.9
997
         **/
998
        public VisitService getVisitService() {
999
                return getService(VisitService.class);
1✔
1000
        }
1001
        
1002
        /**
1003
         * Sets the visit service.
1004
         *
1005
         * @param visitService the visitService to set
1006
         * @since 1.9
1007
         **/
1008
        public void setVisitService(VisitService visitService) {
1009
                setService(VisitService.class, visitService);
1✔
1010
        }
1✔
1011
        
1012
        /**
1013
         * Gets the provider service.
1014
         *
1015
         * @return provider service.
1016
         * @since 1.9
1017
         **/
1018
        
1019
        public ProviderService getProviderService() {
1020
                return getService(ProviderService.class);
1✔
1021
        }
1022
        
1023
        /**
1024
         * Sets the provider service.
1025
         *
1026
         * @param providerService the providerService to set
1027
         * @since 1.9
1028
         **/
1029
        public void setProviderService(ProviderService providerService) {
1030
                setService(ProviderService.class, providerService);
1✔
1031
        }
1✔
1032
        
1033
        /**
1034
         * Gets the datatype service
1035
         *
1036
         * @return custom datatype service
1037
         * @since 1.9
1038
         */
1039
        public DatatypeService getDatatypeService() {
1040
                return getService(DatatypeService.class);
1✔
1041
        }
1042
        
1043
        /**
1044
         * Sets the datatype service
1045
         *
1046
         * @param datatypeService the datatypeService to set
1047
         * @since 1.9
1048
         */
1049
        public void setDatatypeService(DatatypeService datatypeService) {
1050
                setService(DatatypeService.class, datatypeService);
1✔
1051
        }
1✔
1052
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc