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

openmrs / openmrs-core / 24803983538

22 Apr 2026 09:33PM UTC coverage: 63.689% (-0.04%) from 63.73%
24803983538

push

github

ibacher
Fix issues with Javadocs

21841 of 34293 relevant lines covered (63.69%)

0.64 hits per line

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

74.31
/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.ObsService;
33
import org.openmrs.api.OpenmrsService;
34
import org.openmrs.api.OrderService;
35
import org.openmrs.api.OrderSetService;
36
import org.openmrs.api.PatientService;
37
import org.openmrs.api.PersonService;
38
import org.openmrs.api.ProgramWorkflowService;
39
import org.openmrs.api.ProviderService;
40
import org.openmrs.api.SerializationService;
41
import org.openmrs.api.ServiceNotFoundException;
42
import org.openmrs.api.UserService;
43
import org.openmrs.api.VisitService;
44
import org.openmrs.hl7.HL7Service;
45
import org.openmrs.logic.LogicService;
46
import org.openmrs.messagesource.MessageSourceService;
47
import org.openmrs.messagesource.impl.DefaultMessageSourceServiceImpl;
48
import org.openmrs.notification.AlertService;
49
import org.openmrs.notification.MessageService;
50
import org.openmrs.scheduler.SchedulerService;
51
import org.openmrs.util.OpenmrsClassLoader;
52
import org.slf4j.Logger;
53
import org.slf4j.LoggerFactory;
54
import org.springframework.aop.Advisor;
55
import org.springframework.aop.framework.Advised;
56
import org.springframework.aop.framework.ProxyFactory;
57
import org.springframework.beans.BeansException;
58
import org.springframework.context.ApplicationContext;
59
import org.springframework.context.ApplicationContextAware;
60

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

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

119
                private ServiceContextHolder() {
120
                }
121

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

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

232
        /**
233
         * @param diagnosisService diagnosis related service
234
         *
235
         * @since 2.2
236
         */
237
        public void setDiagnosisService(DiagnosisService diagnosisService) {
238
                setService(DiagnosisService.class, diagnosisService);
1✔
239
        }
1✔
240
        
241
        /**
242
         * @return cohort related service
243
         */
244
        public CohortService getCohortService() {
245
                return getService(CohortService.class);
1✔
246
        }
247
        
248
        /**
249
         * @param cs cohort related service
250
         */
251
        public void setCohortService(CohortService cs) {
252
                setService(CohortService.class, cs);
1✔
253
        }
1✔
254
        
255
        /**
256
         * @return order set service
257
         */
258
        public OrderSetService getOrderSetService() {
259
                return getService(OrderSetService.class);
1✔
260
        }
261
        
262
        /**
263
         * @return order service
264
         */
265
        public OrderService getOrderService() {
266
                return getService(OrderService.class);
1✔
267
        }
268
        
269
        /**
270
         * @return form service
271
         */
272
        public FormService getFormService() {
273
                return getService(FormService.class);
1✔
274
        }
275
        
276
        /**
277
         * @return serialization service
278
         */
279
        public SerializationService getSerializationService() {
280
                return getService(SerializationService.class);
1✔
281
        }
282
        
283
        /**
284
         * @return admin-related services
285
         */
286
        public AdministrationService getAdministrationService() {
287
                return getService(AdministrationService.class);
1✔
288
        }
289
        
290
        /**
291
         * @return programWorkflowService
292
         */
293
        public ProgramWorkflowService getProgramWorkflowService() {
294
                return getService(ProgramWorkflowService.class);
1✔
295
        }
296

297
        /**
298
         * @return logicService
299
         */
300
        public LogicService getLogicService() {
301
                return getService(LogicService.class);
×
302
        }
303
        
304
        /**
305
         * @return scheduler service
306
         */
307
        public SchedulerService getSchedulerService() {
308
                return getService(SchedulerService.class);
1✔
309
        }
310
        
311
        /**
312
         * Set the scheduler service.
313
         *
314
         * @param schedulerService
315
         */
316
        public void setSchedulerService(SchedulerService schedulerService) {
317
                setService(SchedulerService.class, schedulerService);
1✔
318
        }
1✔
319
        
320
        /**
321
         * @return alert service
322
         */
323
        public AlertService getAlertService() {
324
                return getService(AlertService.class);
1✔
325
        }
326
        
327
        /**
328
         * @param alertService
329
         */
330
        public void setAlertService(AlertService alertService) {
331
                setService(AlertService.class, alertService);
1✔
332
        }
1✔
333
        
334
        /**
335
         * @param programWorkflowService
336
         */
337
        public void setProgramWorkflowService(ProgramWorkflowService programWorkflowService) {
338
                setService(ProgramWorkflowService.class, programWorkflowService);
1✔
339
        }
1✔
340

341
        /**
342
         * @param logicService
343
         */
344
        public void setLogicService(LogicService logicService) {
345
                setService(LogicService.class, logicService);
×
346
        }
×
347
        
348
        /**
349
         * @return message service
350
         */
351
        public MessageService getMessageService() {
352
                return getService(MessageService.class);
1✔
353
        }
354
        
355
        /**
356
         * Sets the message service.
357
         *
358
         * @param messageService
359
         */
360
        public void setMessageService(MessageService messageService) {
361
                setService(MessageService.class, messageService);
1✔
362
        }
1✔
363
        
364
        /**
365
         * @return the hl7Service
366
         */
367
        public HL7Service getHL7Service() {
368
                return getService(HL7Service.class);
1✔
369
        }
370
        
371
        /**
372
         * @param hl7Service the hl7Service to set
373
         */
374
        public void setHl7Service(HL7Service hl7Service) {
375
                setService(HL7Service.class, hl7Service);
1✔
376
        }
1✔
377
        
378
        /**
379
         * @param administrationService the administrationService to set
380
         */
381
        public void setAdministrationService(AdministrationService administrationService) {
382
                setService(AdministrationService.class, administrationService);
1✔
383
        }
1✔
384
        
385
        /**
386
         * @param encounterService the encounterService to set
387
         */
388
        public void setEncounterService(EncounterService encounterService) {
389
                setService(EncounterService.class, encounterService);
1✔
390
        }
1✔
391
        
392
        /**
393
         * @param locationService the LocationService to set
394
         */
395
        public void setLocationService(LocationService locationService) {
396
                setService(LocationService.class, locationService);
1✔
397
        }
1✔
398
        
399
        /**
400
         * @param formService the formService to set
401
         */
402
        public void setFormService(FormService formService) {
403
                setService(FormService.class, formService);
1✔
404
        }
1✔
405
        
406
        /**
407
         * @param obsService the obsService to set
408
         */
409
        public void setObsService(ObsService obsService) {
410
                setService(ObsService.class, obsService);
1✔
411
        }
1✔
412

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

948
                                                refreshingContextLock.wait();
×
949

950
                                                log.debug("Finished waiting to get service {} while the context was being refreshed", classString);
×
951
                                        }
952
                                }
1✔
953

954
                                Daemon.runStartupForService(openmrsService);
1✔
955
                        }
956
                        catch (InterruptedException e) {
×
957
                                log.warn("Refresh lock was interrupted while waiting to run OpenmrsService.onStartup() for "
×
958
                                        + classString, e);
959
                        }
1✔
960
                }).start();
1✔
961
        }
1✔
962
        
963
        /**
964
         * Gets a list of services implementing the {@link OpenmrsService} interface, for a given
965
         * module.
966
         *
967
         * @param modulePackage the module's package name.
968
         * @return the list of service instances.
969
         * @since 1.9
970
         */
971
        public List<OpenmrsService> getModuleOpenmrsServices(String modulePackage) {
972
                List<OpenmrsService> openmrsServices = new ArrayList<>();
1✔
973
                
974
                for (Entry<String, OpenmrsService> entry : moduleOpenmrsServices.entrySet()) {
1✔
975
                        if (entry.getKey().startsWith(modulePackage)) {
1✔
976
                                openmrsServices.add(entry.getValue());
1✔
977
                        }
978
                }
1✔
979
                
980
                return openmrsServices;
1✔
981
        }
982
        
983
        /**
984
         * Gets the visit service.
985
         *
986
         * @return visit service.
987
         * @since 1.9
988
         **/
989
        public VisitService getVisitService() {
990
                return getService(VisitService.class);
1✔
991
        }
992
        
993
        /**
994
         * Sets the visit service.
995
         *
996
         * @param visitService the visitService to set
997
         * @since 1.9
998
         **/
999
        public void setVisitService(VisitService visitService) {
1000
                setService(VisitService.class, visitService);
1✔
1001
        }
1✔
1002
        
1003
        /**
1004
         * Gets the provider service.
1005
         *
1006
         * @return provider service.
1007
         * @since 1.9
1008
         **/
1009
        
1010
        public ProviderService getProviderService() {
1011
                return getService(ProviderService.class);
1✔
1012
        }
1013
        
1014
        /**
1015
         * Sets the provider service.
1016
         *
1017
         * @param providerService the providerService to set
1018
         * @since 1.9
1019
         **/
1020
        public void setProviderService(ProviderService providerService) {
1021
                setService(ProviderService.class, providerService);
1✔
1022
        }
1✔
1023
        
1024
        /**
1025
         * Gets the datatype service
1026
         *
1027
         * @return custom datatype service
1028
         * @since 1.9
1029
         */
1030
        public DatatypeService getDatatypeService() {
1031
                return getService(DatatypeService.class);
1✔
1032
        }
1033
        
1034
        /**
1035
         * Sets the datatype service
1036
         *
1037
         * @param datatypeService the datatypeService to set
1038
         * @since 1.9
1039
         */
1040
        public void setDatatypeService(DatatypeService datatypeService) {
1041
                setService(DatatypeService.class, datatypeService);
1✔
1042
        }
1✔
1043
}
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