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

openmrs / openmrs-core / 29592249542

17 Jul 2026 02:16PM UTC coverage: 66.061% (+0.09%) from 65.967%
29592249542

push

github

ibacher
TRUNK-6688: Follow-up: run Mockito's inline MockMaker on older JVMs

24319 of 36813 relevant lines covered (66.06%)

0.66 hits per line

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

74.57
/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.cache.CacheManager;
61
import org.springframework.context.ApplicationContext;
62
import org.springframework.context.ApplicationContextAware;
63

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

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

122
                private ServiceContextHolder() {
123
                }
124

125
                private static ServiceContext instance = null;
1✔
126
        }
127
        
128
        /**
129
         * There should only be one ServiceContext per openmrs (java virtual machine). This method
130
         * should be used when wanting to fetch the service context Note: The ServiceContext shouldn't
131
         * be used independently. All calls should go through the Context
132
         *
133
         * @return This VM's current ServiceContext.
134
         * @see org.openmrs.api.context.Context
135
         */
136
        public static ServiceContext getInstance() {
137
                if (ServiceContextHolder.instance == null) {
1✔
138
                        ServiceContextHolder.instance = new ServiceContext();
1✔
139
                }
140
                
141
                return ServiceContextHolder.instance;
1✔
142
        }
143
        
144
        /**
145
         * Reports whether the singleton {@link ServiceContext} has already been created, without triggering
146
         * its creation the way {@link #getInstance()} would.
147
         *
148
         * @return true if the ServiceContext singleton has been instantiated
149
         * @since 3.0.0, 2.9.0, 2.8.9
150
         */
151
        public static boolean isInstantiated() {
152
                return ServiceContextHolder.instance != null;
1✔
153
        }
154

155
        /**
156
         * Null out the current instance of the ServiceContext. This should be used when modules are
157
         * refreshing (being added/removed) and/or openmrs is shutting down
158
         */
159
        public static void destroyInstance() {
160
                if (ServiceContextHolder.instance != null && ServiceContextHolder.instance.services != null) {
1✔
161
                        for (Map.Entry<Class, Object> entry : ServiceContextHolder.instance.services.entrySet()) {
1✔
162
                                log.debug("Service - {} : {}", entry.getKey().getName(), entry.getValue());
1✔
163
                        }
1✔
164
                        
165
                        // Remove advice and advisors that this service added
166
                        for (Class serviceClass : ServiceContextHolder.instance.services.keySet()) {
1✔
167
                                ServiceContextHolder.instance.removeAddedAOP(serviceClass);
1✔
168
                        }
1✔
169
                        
170
                        if (ServiceContextHolder.instance.services != null) {
1✔
171
                                ServiceContextHolder.instance.services.clear();
1✔
172
                                ServiceContextHolder.instance.services = null;
1✔
173
                        }
174
                        
175
                        if (ServiceContextHolder.instance.addedAdvisors != null) {
1✔
176
                                ServiceContextHolder.instance.addedAdvisors.clear();
1✔
177
                                ServiceContextHolder.instance.addedAdvisors = null;
1✔
178
                        }
179
                        
180
                        if (ServiceContextHolder.instance.addedAdvice != null) {
1✔
181
                                ServiceContextHolder.instance.addedAdvice.clear();
1✔
182
                                ServiceContextHolder.instance.addedAdvice = null;
1✔
183
                        }
184
                }
185
                
186
                if (ServiceContextHolder.instance != null) {
1✔
187
                        ServiceContextHolder.instance.applicationContext = null;
1✔
188
                        
189
                        if (ServiceContextHolder.instance.moduleOpenmrsServices != null) {
1✔
190
                                ServiceContextHolder.instance.moduleOpenmrsServices.clear();
1✔
191
                                ServiceContextHolder.instance.moduleOpenmrsServices = null;
1✔
192
                        }
193
                }
194
                log.debug("Destroying ServiceContext instance: {}", ServiceContextHolder.instance);
1✔
195
                ServiceContextHolder.instance = null;
1✔
196
        }
1✔
197
        
198
        /**
199
         * @return encounter-related services
200
         */
201
        public EncounterService getEncounterService() {
202
                return getService(EncounterService.class);
1✔
203
        }
204
        
205
        /**
206
         * @return location services
207
         */
208
        public LocationService getLocationService() {
209
                return getService(LocationService.class);
1✔
210
        }
211
        
212
        /**
213
         * @return observation services
214
         */
215
        public ObsService getObsService() {
216
                return getService(ObsService.class);
1✔
217
        }
218
        
219
        /**
220
         * @return condition related service
221
         * 
222
         * @since 2.2
223
         */
224
        public ConditionService getConditionService() {
225
                return getService(ConditionService.class);
1✔
226
        }
227
        
228
        /**
229
         * @param conditionService condition related service
230
         *            
231
         * @since 2.2   
232
         */
233
        public void setConditionService(ConditionService conditionService) {
234
                setService(ConditionService.class, conditionService);
1✔
235
        }
1✔
236

237
        /**
238
         * @return diagnosis related service
239
         *
240
         * @since 2.2
241
         */
242
        public DiagnosisService getDiagnosisService() {
243
                return getService(DiagnosisService.class);
1✔
244
        }
245

246
        /**
247
         * @param diagnosisService diagnosis related service
248
         *
249
         * @since 2.2
250
         */
251
        public void setDiagnosisService(DiagnosisService diagnosisService) {
252
                setService(DiagnosisService.class, diagnosisService);
1✔
253
        }
1✔
254

255
        /**
256
         * @return MedicationDispense related service
257
         * @since 2.6.0
258
         */
259
        public MedicationDispenseService getMedicationDispenseService() {
260
                return getService(MedicationDispenseService.class);
×
261
        }
262

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

327
        /**
328
         * @return logicService
329
         */
330
        public LogicService getLogicService() {
331
                return getService(LogicService.class);
×
332
        }
333
        
334
        /**
335
         * @return scheduler service
336
         */
337
        public SchedulerService getSchedulerService() {
338
                return getService(SchedulerService.class);
1✔
339
        }
340
        
341
        /**
342
         * Set the scheduler service.
343
         *
344
         * @param schedulerService
345
         */
346
        public void setSchedulerService(SchedulerService schedulerService) {
347
                setService(SchedulerService.class, schedulerService);
1✔
348
        }
1✔
349
        
350
        /**
351
         * @return alert service
352
         */
353
        public AlertService getAlertService() {
354
                return getService(AlertService.class);
1✔
355
        }
356
        
357
        /**
358
         * @param alertService
359
         */
360
        public void setAlertService(AlertService alertService) {
361
                setService(AlertService.class, alertService);
1✔
362
        }
1✔
363
        
364
        /**
365
         * @param programWorkflowService
366
         */
367
        public void setProgramWorkflowService(ProgramWorkflowService programWorkflowService) {
368
                setService(ProgramWorkflowService.class, programWorkflowService);
1✔
369
        }
1✔
370

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

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

1065
        /**
1066
         * Clears entire API cache.
1067
         * 
1068
         * @since 2.8.0
1069
         */
1070
        public void clearEntireApiCache() {
1071
                CacheManager apiCacheManager = getRegisteredComponent("apiCacheManager", CacheManager.class);
1✔
1072
                apiCacheManager.getCacheNames().forEach(cacheName -> apiCacheManager.getCache(cacheName).invalidate());
1✔
1073
        }
1✔
1074
}
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