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

openmrs / openmrs-core / 30399801741

28 Jul 2026 09:13PM UTC coverage: 64.333% (+0.2%) from 64.136%
30399801741

push

github

web-flow
Fix Mockito inline mocks on JDK 8 and 11 (#6403)

24619 of 38268 relevant lines covered (64.33%)

0.64 hits per line

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

50.27
/api/src/main/java/org/openmrs/api/context/Context.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 javax.mail.Authenticator;
13
import javax.mail.PasswordAuthentication;
14
import javax.mail.Session;
15
import java.sql.Connection;
16
import java.text.SimpleDateFormat;
17
import java.util.Arrays;
18
import java.util.HashMap;
19
import java.util.HashSet;
20
import java.util.List;
21
import java.util.Locale;
22
import java.util.Map;
23
import java.util.Properties;
24
import java.util.Set;
25
import java.util.concurrent.Future;
26

27
import org.aopalliance.aop.Advice;
28
import org.apache.commons.lang3.StringUtils;
29
import org.openmrs.Allergen;
30
import org.openmrs.GlobalProperty;
31
import org.openmrs.OpenmrsObject;
32
import org.openmrs.PersonName;
33
import org.openmrs.Privilege;
34
import org.openmrs.Role;
35
import org.openmrs.User;
36
import org.openmrs.api.APIException;
37
import org.openmrs.api.AdministrationService;
38
import org.openmrs.api.CohortService;
39
import org.openmrs.api.ConceptService;
40
import org.openmrs.api.ConditionService;
41
import org.openmrs.api.DatatypeService;
42
import org.openmrs.api.DiagnosisService;
43
import org.openmrs.api.EncounterService;
44
import org.openmrs.api.FormService;
45
import org.openmrs.api.LocationService;
46
import org.openmrs.api.MedicationDispenseService;
47
import org.openmrs.api.ObsService;
48
import org.openmrs.api.OpenmrsService;
49
import org.openmrs.api.OrderService;
50
import org.openmrs.api.OrderSetService;
51
import org.openmrs.api.PatientService;
52
import org.openmrs.api.PersonService;
53
import org.openmrs.api.ProgramWorkflowService;
54
import org.openmrs.api.ProviderService;
55
import org.openmrs.api.SerializationService;
56
import org.openmrs.api.UserService;
57
import org.openmrs.api.VisitService;
58
import org.openmrs.api.db.ContextDAO;
59
import org.openmrs.hl7.HL7Service;
60
import org.openmrs.logic.LogicService;
61
import org.openmrs.messagesource.MessageSourceService;
62
import org.openmrs.module.ModuleMustStartException;
63
import org.openmrs.module.ModuleUtil;
64
import org.openmrs.notification.AlertService;
65
import org.openmrs.notification.MessageException;
66
import org.openmrs.notification.MessagePreparator;
67
import org.openmrs.notification.MessageSender;
68
import org.openmrs.notification.MessageService;
69
import org.openmrs.notification.mail.MailMessageSender;
70
import org.openmrs.notification.mail.velocity.VelocityMessagePreparator;
71
import org.openmrs.scheduler.SchedulerService;
72
import org.openmrs.util.ConfigUtil;
73
import org.openmrs.util.DatabaseUpdateException;
74
import org.openmrs.util.DatabaseUpdater;
75
import org.openmrs.util.InputRequiredException;
76
import org.openmrs.util.LocaleUtility;
77
import org.openmrs.util.OpenmrsClassLoader;
78
import org.openmrs.util.OpenmrsConstants;
79
import org.openmrs.util.OpenmrsUtil;
80
import org.openmrs.util.PrivilegeConstants;
81
import org.openmrs.validator.ValidateUtil;
82
import org.slf4j.Logger;
83
import org.slf4j.LoggerFactory;
84
import org.springframework.aop.Advisor;
85
import org.springframework.beans.BeansException;
86
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
87
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
88

89
/**
90
 * Represents an OpenMRS <code>Context</code>, which may be used to authenticate to the database and
91
 * obtain services in order to interact with the system.<br>
92
 * <br>
93
 * The Context is split into a {@link UserContext} and {@link ServiceContext}. The UserContext is
94
 * lightweight and there is an instance for every user logged into the system. The ServiceContext is
95
 * heavier and it contains each service class. This is more static and there is only one ServiceContext
96
 * per OpenMRS instance. <br>
97
 * <br>
98
 * Both the {@link UserContext} and the {@link ServiceContext} should not be used directly. This
99
 * context class has methods to pass through to the currently defined UserContext for the thread and
100
 * the currently defined ServiceContext. <br>
101
 * <br>
102
 * To use the OpenMRS api there are four things that have to be done:
103
 * <ol>
104
 * <li>Call {@link Context#startup(String, String, String, Properties)} to let the Context contact
105
 * the database</li>
106
 * <li>Call {@link Context#openSession()} to start a "unit of work".</li>
107
 * <li>Call {@link Context#authenticate(String, String)} to authenticate the current user on the
108
 * current thread</li>
109
 * <li>Call {@link Context#closeSession()} to end your "unit of work" and commit all changes to the
110
 * database.</li>
111
 * </ol>
112
 * <br>
113
 * Example usage:
114
 *
115
 * <pre>
116
 *         public static void main(String[] args) {
117
 *                 Context.startup("jdbc:mysql://localhost:3306/db-name?autoReconnect=true", "openmrs-db-user", "3jknfjkn33ijt", new Properties());
118
 *                 try {
119
 *                         Context.openSession();
120
 *                         Context.authenticate("admin", "test");
121
 *                         List&lt;Patients&gt; patients = Context.getPatientService().getPatientsByName("Fred");
122
 *                         patients.get(0).setBirthdate(new Date());
123
 *                         Context.getPatientService().savePatient(patients.get(0));
124
 *                         ...
125
 *        }
126
 *                 finally {
127
 *                         Context.closeSession();
128
 *        }
129
 *    }
130
 * </pre>
131
 *
132
 * @see org.openmrs.api.context.UserContext
133
 * @see org.openmrs.api.context.ServiceContext
134
 */
135
public class Context {
136

137

138
        // Global resources
139
        private static ContextDAO contextDAO;
140

141
        private static volatile Session mailSession;
142

143
        // Using "wrapper" (Object array) around UserContext to avoid ThreadLocal
144
        // bug in Java 1.5
145
        private static final ThreadLocal<Object[] /* UserContext */> userContextHolder = new ThreadLocal<>();
1✔
146

147
        private static volatile ServiceContext serviceContext;
148

149
        private static Properties runtimeProperties = new Properties();
1✔
150

151
        private static Properties configProperties = new Properties();
1✔
152

153
        private static AuthenticationScheme authenticationScheme;
154

155
        private static final Logger log = LoggerFactory.getLogger(Context.class);
1✔
156

157
        /**
158
         * Default public constructor
159
         */
160
        public Context() {
1✔
161
        }
1✔
162

163
        /**
164
         * Gets the context's data access object
165
         *
166
         * @return ContextDAO
167
         */
168
        static ContextDAO getContextDAO() {
169
                if (contextDAO == null) {
1✔
170
                        throw new APIException("error.context.null", (Object[]) null);
×
171
                }
172
                return contextDAO;
1✔
173
        }
174

175
        /**
176
         * Used to set the context's DAO for the application.
177
         *
178
         * @param dao ContextDAO to set
179
         */
180
        public void setContextDAO(ContextDAO dao) {
181
                setDAO(dao);
1✔
182
        }
1✔
183

184
        public static void setDAO(ContextDAO dao) {
185
                contextDAO = dao;
1✔
186
        }
1✔
187

188
        /**
189
         * Spring init method that sets the authentication scheme.
190
         */
191
        private static void setAuthenticationScheme() {
192

193
                authenticationScheme = new UsernamePasswordAuthenticationScheme();
1✔
194

195
                try {
196
                        authenticationScheme = Context.getServiceContext().getApplicationContext().getBean(AuthenticationScheme.class); // manual autowiring (from a module)
×
197
                        log.info("An authentication scheme override was provided. Using this one in place of the OpenMRS default authentication scheme.");
×
198
                }
199
                catch(NoUniqueBeanDefinitionException e) {
×
200
                        log.error("Multiple authentication schemes overrides are being provided, this is currently not supported. Sticking to OpenMRS default authentication scheme.");
×
201
                }
202
                catch(NoSuchBeanDefinitionException e) {
1✔
203
                        log.debug("No authentication scheme override was provided. Sticking to OpenMRS default authentication scheme.");
1✔
204
                }
205
                catch(BeansException e){
×
206
                        log.error("Fatal error encountered when injecting the authentication scheme override. Sticking to OpenMRS default authentication scheme.");
×
207
                }
1✔
208
        }
1✔
209

210
        /**
211
         * Loads a class with an instance of the OpenmrsClassLoader. Convenience method equivalent to
212
         * OpenmrsClassLoader.getInstance().loadClass(className);
213
         *
214
         * @param className the class to load
215
         * @return the class that was loaded
216
         * @throws ClassNotFoundException
217
         * <strong>Should</strong> load class with the OpenmrsClassLoader
218
         */
219
        public static Class<?> loadClass(String className) throws ClassNotFoundException {
220
                return OpenmrsClassLoader.getInstance().loadClass(className);
1✔
221
        }
222

223
        /**
224
         * Sets the user context on the thread local so that the service layer can perform
225
         * authentication/authorization checks.<br>
226
         * <br>
227
         * This is thread safe since it stores the given user context in ThreadLocal.
228
         *
229
         * @param ctx UserContext to set
230
         */
231
        public static void setUserContext(UserContext ctx) {
232
                log.trace("Setting user context {}", ctx);
1✔
233

234
                Object[] arr = new Object[] { ctx };
1✔
235
                userContextHolder.set(arr);
1✔
236
        }
1✔
237

238
        /**
239
         * Clears the user context from the threadlocal.
240
         */
241
        public static void clearUserContext() {
242
                log.trace("Clearing user context {}", Arrays.toString(userContextHolder.get()));
1✔
243

244
                userContextHolder.remove();
1✔
245
        }
1✔
246

247
        /**
248
         * Gets the user context from the thread local. This might be accessed by several threads at the
249
         * same time.
250
         *
251
         * @return The current UserContext for this thread.
252
         * <strong>Should</strong> fail if session hasn't been opened
253
         */
254
        public static UserContext getUserContext() {
255
                Object[] arr = userContextHolder.get();
1✔
256
                log.trace("Getting user context {} from userContextHolder {}", Arrays.toString(arr), userContextHolder);
1✔
257

258
                if (arr == null) {
1✔
259
                        log.trace("userContext is null.");
1✔
260
                        throw new APIException(
1✔
261
                                        "A user context must first be passed to setUserContext()...use Context.openSession() (and closeSession() to prevent memory leaks!) before using the API");
262
                }
263
                return (UserContext) userContextHolder.get()[0];
1✔
264
        }
265

266
        /**
267
         * Gets the currently defined service context. If one is not defined, one will be created and
268
         * then returned.
269
         *
270
         * @return the current ServiceContext
271
         */
272
        static ServiceContext getServiceContext() {
273
                if (serviceContext == null) {
1✔
274
                        synchronized (Context.class) {
×
275
                                if (serviceContext == null) {
×
276
                                        serviceContext = ServiceContext.getInstance();
×
277
                                }
278
                        }
×
279
                }
280
                return ServiceContext.getInstance();
1✔
281
        }
282

283
        /**
284
         * Sets the service context.
285
         *
286
         * @param ctx
287
         */
288
        public void setServiceContext(ServiceContext ctx) {
289
                setContext(ctx);
1✔
290
        }
1✔
291

292
        public static void setContext(ServiceContext ctx) {
293
                serviceContext = ctx;
1✔
294
        }
1✔
295

296
        /**
297
         * OpenMRS provides its default authentication scheme that authenticates via DAO with OpenMRS usernames and passwords.
298
         * 
299
         * Any module can provide an authentication scheme override by Spring wiring a custom implementation of {@link AuthenticationScheme}.
300
         * This method would return Core's default authentication scheme unless a Spring override is provided somewhere else.
301
         * 
302
         * @return The enforced authentication scheme.
303
         */
304
        public static AuthenticationScheme getAuthenticationScheme() {
305
                return authenticationScheme;
1✔
306
        }
307

308
        /**
309
         * @deprecated as of 2.3.0, replaced by {@link #authenticate(Credentials)}
310
         * 
311
         * Used to authenticate user within the context
312
         *
313
         * @param username user's identifier token for login
314
         * @param password user's password for authenticating to context
315
         * @throws ContextAuthenticationException
316
         * <strong>Should</strong> not authenticate with null username and password
317
         * <strong>Should</strong> not authenticate with null password
318
         * <strong>Should</strong> not authenticate with null username
319
         * <strong>Should</strong> not authenticate with null password and proper username
320
         * <strong>Should</strong> not authenticate with null password and proper system id
321
         */
322
        @Deprecated
323
        public static void authenticate(String username, String password) throws ContextAuthenticationException {
324
                authenticate(new UsernamePasswordCredentials(username, password));
1✔
325
        }
1✔
326

327
        /**
328
         * @param credentials
329
         * @throws ContextAuthenticationException
330
         * 
331
         * @since 2.3.0
332
         */
333
        public static Authenticated authenticate(Credentials credentials) throws ContextAuthenticationException {
334

335
                if (Daemon.isDaemonThread()) {
1✔
336
                        log.error("Authentication attempted while operating on a "
×
337
                                        + "daemon thread, authenticating is not necessary or allowed");
338
                        return new BasicAuthenticated(Daemon.getDaemonThreadUser(), "No auth scheme used by Context - Daemon user is always authenticated.");
×
339
                }
340

341
                if (credentials == null) {
1✔
342
                        throw new ContextAuthenticationException("Context cannot authenticate with null credentials.");
×
343
                }
344

345
                return getUserContext().authenticate(credentials);
1✔
346
        }
347

348
        /**
349
         * Refresh the authenticated user object in the current UserContext. This should be used when
350
         * updating information in the database about the current user and it needs to be reflecting in
351
         * the (cached) {@link #getAuthenticatedUser()} User object.
352
         *
353
         * @since 1.5
354
         * <strong>Should</strong> get fresh values from the database
355
         */
356
        public static void refreshAuthenticatedUser() {
357
                if (Daemon.isDaemonThread()) {
1✔
358
                        return;
×
359
                }
360
                log.debug("Refreshing authenticated user");
1✔
361

362
                getUserContext().refreshAuthenticatedUser();
1✔
363
        }
1✔
364

365
        /**
366
         * Become a different user. (You should only be able to do this as a superuser.)
367
         *
368
         * @param systemId
369
         * @throws ContextAuthenticationException
370
         * <strong>Should</strong> change locale when become another user
371
         */
372
        public static void becomeUser(String systemId) throws ContextAuthenticationException {
373
                log.info("systemId: {}", systemId);
1✔
374

375
                getUserContext().becomeUser(systemId);
1✔
376
        }
1✔
377

378
        /**
379
         * Get the runtime properties that this OpenMRS instance was started with
380
         *
381
         * @return copy of the runtime properties
382
         */
383
        public static Properties getRuntimeProperties() {
384
                Properties props = new Properties();
1✔
385
                if( runtimeProperties != null ) {
1✔
386
                        props.putAll(runtimeProperties);
1✔
387
                }
388
                return props;
1✔
389
        }
390

391
        /**
392
         * Set the runtime properties to be used by this OpenMRS instance
393
         *
394
         * @param props runtime properties
395
         */
396
        public static void setRuntimeProperties(Properties props) {
397
                runtimeProperties = props;
1✔
398
        }
1✔
399

400
        /**
401
         * @return concept dictionary-related services
402
         */
403
        public static ConceptService getConceptService() {
404
                return getServiceContext().getConceptService();
1✔
405
        }
406

407
        /**
408
         * @return encounter-related services
409
         */
410
        public static EncounterService getEncounterService() {
411
                return getServiceContext().getEncounterService();
1✔
412
        }
413

414
        /**
415
         * @return location services
416
         */
417
        public static LocationService getLocationService() {
418
                return getServiceContext().getLocationService();
1✔
419
        }
420

421
        /**
422
         * @return observation services
423
         */
424
        public static ObsService getObsService() {
425
                return getServiceContext().getObsService();
1✔
426
        }
427

428
        /**
429
         * @return patient-related services
430
         */
431
        public static PatientService getPatientService() {
432
                return getServiceContext().getPatientService();
1✔
433
        }
434

435
        public static CohortService getCohortService() {
436
                return getServiceContext().getCohortService();
1✔
437
        }
438

439
        /**
440
         * @return person-related services
441
         */
442
        public static PersonService getPersonService() {
443
                return getServiceContext().getPersonService();
1✔
444
        }
445

446
        /**
447
         * @return condition-related services
448
         * 
449
         * @since 2.2
450
         */
451
        public static ConditionService getConditionService(){
452
                return getServiceContext().getConditionService();
1✔
453
        }
454

455
        /**
456
         * @return diagnosis-related services
457
         *
458
         * @since 2.2
459
         */
460
        public static DiagnosisService getDiagnosisService(){
461
                return getServiceContext().getDiagnosisService();
1✔
462
        }
463

464
        /**
465
         * @return MedicationDispense-related service
466
         * @since 2.6.0
467
         */
468
        public static MedicationDispenseService getMedicationDispenseService(){
469
                return getServiceContext().getMedicationDispenseService();
1✔
470
        }
471

472
        /**
473
         * @return Returns the hl7Service.
474
         */
475
        public static HL7Service getHL7Service() {
476
                return getServiceContext().getHL7Service();
1✔
477
        }
478

479
        /**
480
         * @return user-related services
481
         */
482
        public static UserService getUserService() {
483
                return getServiceContext().getUserService();
1✔
484
        }
485

486
        /**
487
         * @return order service
488
         */
489
        public static OrderService getOrderService() {
490
                return getServiceContext().getOrderService();
1✔
491
        }
492

493
        /**
494
         * @return orderSet service
495
         * @since 1.12
496
         */
497
        public static OrderSetService getOrderSetService() {
498
                return getServiceContext().getOrderSetService();
1✔
499
        }
500

501
        /**
502
         * @return form service
503
         */
504
        public static FormService getFormService() {
505
                return getServiceContext().getFormService();
1✔
506
        }
507

508
        /**
509
         * @return serialization service
510
         * @since 1.5
511
         */
512
        public static SerializationService getSerializationService() {
513
                return getServiceContext().getSerializationService();
1✔
514
        }
515

516
        /**
517
         * @return logic service
518
         */
519
        public static LogicService getLogicService() {
520
                return getServiceContext().getLogicService();
×
521
        }
522

523
        /**
524
         * @return admin-related services
525
         */
526
        public static AdministrationService getAdministrationService() {
527
                return getServiceContext().getAdministrationService();
1✔
528
        }
529

530
        /**
531
         * @return MessageSourceService
532
         */
533
        public static MessageSourceService getMessageSourceService() {
534
                return getServiceContext().getMessageSourceService();
1✔
535
        }
536

537
        /**
538
         * @return scheduler service
539
         */
540
        public static SchedulerService getSchedulerService() {
541
                return getServiceContext().getSchedulerService();
×
542
        }
543

544
        /**
545
         * @return alert service
546
         */
547
        public static AlertService getAlertService() {
548
                return getServiceContext().getAlertService();
1✔
549
        }
550

551
        /**
552
         * @return program- and workflow-related services
553
         */
554
        public static ProgramWorkflowService getProgramWorkflowService() {
555
                return getServiceContext().getProgramWorkflowService();
1✔
556
        }
557
        
558
        /**
559
         * Get the message service.
560
         *
561
         * @return message service
562
         */
563
        public static MessageService getMessageService() {
564
                MessageService ms = getServiceContext().getMessageService();
1✔
565
                try {
566
                        // Message service dependencies
567
                        if (ms.getMessagePreparator() == null) {
1✔
568
                                ms.setMessagePreparator(getMessagePreparator());
1✔
569
                        }
570

571
                        if (ms.getMessageSender() == null) {
1✔
572
                                ms.setMessageSender(getMessageSender());
1✔
573
                        }
574

575
                }
576
                catch (Exception e) {
×
577
                        log.error("Unable to create message service due", e);
×
578
                }
1✔
579
                return ms;
1✔
580
        }
581

582
        /**
583
         * @return all of the configured properties that are used to configure the Mail Session in the Message Service
584
         * These properties are defined as all properties that are prefixed with "mail." and this will return all such
585
         * properties as defined in global properties, runtime properties, and/or system properties, with 
586
         * system properties overriding runtime properties overriding global properties.
587
         */
588
        public static Properties getMailProperties() {
589
                Properties p = new Properties();
1✔
590
                String prefix = "mail.";
1✔
591
                for (GlobalProperty gp : getAdministrationService().getGlobalPropertiesByPrefix(prefix)) {
1✔
592
                        // Historically, some mail properties defined with underscores, support these for legacy compatibility
593
                        if (gp.getProperty().equals("mail.transport_protocol")) {
×
594
                                p.setProperty("mail.transport.protocol", gp.getPropertyValue());
×
595
                        }
596
                        else if (gp.getProperty().equals("mail.smtp_host")) {
×
597
                                p.setProperty("mail.smtp.host", gp.getPropertyValue());
×
598
                        }
599
                        else if (gp.getProperty().equals("mail.smtp_port")) {
×
600
                                p.setProperty("mail.smtp.port", gp.getPropertyValue());
×
601
                        }
602
                        else if (gp.getProperty().equals("mail.smtp_auth")) {
×
603
                                p.setProperty("mail.smtp.auth", gp.getPropertyValue());
×
604
                        }
605
                        else {
606
                                p.setProperty(gp.getProperty(), gp.getPropertyValue());
×
607
                        }
608
                }
×
609
                for (String runtimeProperty : runtimeProperties.stringPropertyNames()) {
1✔
610
                        if (runtimeProperty.startsWith(prefix)) {
1✔
611
                                p.setProperty(runtimeProperty, runtimeProperties.getProperty(runtimeProperty));
×
612
                        }
613
                }
1✔
614
                for (String systemProperty : System.getProperties().stringPropertyNames()) {
1✔
615
                        if (systemProperty.startsWith(prefix)) {
1✔
616
                                p.setProperty(systemProperty, System.getProperty(systemProperty));
×
617
                        }
618
                }
1✔
619
                return p;
1✔
620
        }
621

622
        /**
623
         * Gets the mail session required by the mail message service. This function forces
624
         * authentication via the getAdministrationService() method call
625
         *
626
         * @return a java mail session
627
         */
628
        private static Session getMailSession() {
629
                if (mailSession == null) {
1✔
630
                        synchronized (Context.class) {
1✔
631
                                if (mailSession == null) {
1✔
632
                                        Authenticator auth = new Authenticator() {
1✔
633

634
                                                @Override
635
                                                public PasswordAuthentication getPasswordAuthentication() {
636
                                                        return new PasswordAuthentication(
×
637
                                                                ConfigUtil.getProperty("mail.user"),
×
638
                                                                ConfigUtil.getProperty("mail.password")
×
639
                                                        );
640
                                                }
641
                                        };
642
                                        mailSession = Session.getInstance(getMailProperties(), auth);
1✔
643
                                }
644
                        }
1✔
645
                }
646
                return mailSession;
1✔
647
        }
648

649
        /**
650
         * Convenience method to allow us to change the configuration more easily. TODO Ideally, we
651
         * would be using Spring's method injection to set the dependencies for the message service.
652
         *
653
         * @return the ServiceContext
654
         */
655
        private static MessageSender getMessageSender() {
656
                return new MailMessageSender(getMailSession());
1✔
657
        }
658

659
        /**
660
         * Convenience method to allow us to change the configuration more easily. TODO See todo for
661
         * message sender.
662
         *
663
         * @return
664
         */
665
        private static MessagePreparator getMessagePreparator() throws MessageException {
666
                return new VelocityMessagePreparator();
1✔
667
        }
668

669
        /**
670
         * @return "active" user who has been authenticated, otherwise <code>null</code>
671
         */
672
        public static User getAuthenticatedUser() {
673
                if (Daemon.isDaemonThread()) {
1✔
674
                        return Daemon.getDaemonThreadUser();
1✔
675
                }
676

677
                return getUserContext().getAuthenticatedUser();
1✔
678
        }
679

680
        /**
681
         * @return true if user has been authenticated in this context
682
         */
683
        public static boolean isAuthenticated() {
684
                if (Daemon.isDaemonThread()) {
1✔
685
                        return true;
×
686
                } else {
687
                        try {
688
                                return getAuthenticatedUser() != null;
1✔
689
                        } catch (APIException e) {
×
690
                                log.info("Could not get authenticated user inside called to isAuthenticated(), assuming no user context has been defined", e);
×
691
                                return false;
×
692
                        }
693
                }
694
        }
695

696
        /**
697
         * Used by {@link org.openmrs.aop.AuthorizationAdvice} to give access for unauthenticated users when
698
         * running initialization code with proxy privileges. See e.g.
699
         * {@link org.openmrs.event.outbox.tasks.OutboxTaskSchedulerInitializer#schedule()}.
700
         *
701
         * @return true if there are any proxy privileges
702
         * @since 2.9.0
703
         */
704
        public static boolean hasProxyPrivileges() {
705
                return getUserContext().hasProxyPrivileges();
1✔
706
        }
707

708
        /**
709
         * logs out the "active" (authenticated) user within context
710
         *
711
         * @see #authenticate
712
         * <strong>Should</strong> not fail if session hasn't been opened yet
713
         */
714
        public static void logout() {
715
                if (!isSessionOpen()) {
1✔
716
                        return; // fail early if there isn't even a session open
1✔
717
                }
718
                log.debug("Logging out : {}", getAuthenticatedUser());
1✔
719

720
                getUserContext().logout();
1✔
721

722
                // reset the UserContext object (usually cleared out by closeSession()
723
                // soon after this)
724
                setUserContext(new UserContext(getAuthenticationScheme()));
1✔
725
        }
1✔
726

727
        /**
728
         * Convenience method. Passes through to userContext.getAllRoles(User)
729
         */
730
        public static Set<Role> getAllRoles(User user) throws Exception {
731
                return getUserContext().getAllRoles();
×
732
        }
733

734
        /**
735
         * Tests whether the currently authenticated user has a particular privilege
736
         */
737
        public static boolean hasPrivilege(String privilege) {
738
                // the daemon threads have access to all things
739
                if (Daemon.isDaemonThread()) {
1✔
740
                        return true;
1✔
741
                }
742

743
                return getUserContext().hasPrivilege(privilege);
1✔
744
        }
745

746
        /**
747
         * Tests whether the currently authenticated user has a particular privilege, optionally excluding
748
         * proxy privileges. Passing <code>false</code> checks only the user's granted roles (and the
749
         * anonymous and authenticated roles), so a proxy privilege added merely to invoke a service method
750
         * cannot satisfy a per-resource access check.
751
         *
752
         * @param privilege the privilege to check
753
         * @param includeProxyPrivileges whether proxy privileges may satisfy the check
754
         * @return true if the current user has the given privilege
755
         * @see UserContext#hasPrivilege(String, boolean)
756
         * @since 3.0.0, 2.9.0, 2.8.9
757
         */
758
        public static boolean hasPrivilege(String privilege, boolean includeProxyPrivileges) {
759
                // the daemon threads have access to all things
760
                if (Daemon.isDaemonThread()) {
1✔
761
                        return true;
×
762
                }
763

764
                return getUserContext().hasPrivilege(privilege, includeProxyPrivileges);
1✔
765
        }
766

767
        /**
768
         * Throws an exception if the currently authenticated user does not have the specified
769
         * privilege.
770
         *
771
         * @param privilege
772
         * @throws ContextAuthenticationException
773
         */
774
        public static void requirePrivilege(String privilege) throws ContextAuthenticationException {
775
                if (!hasPrivilege(privilege)) {
1✔
776
                        String errorMessage;
777
                        if (StringUtils.isNotBlank(privilege)) {
×
778
                                errorMessage = Context.getMessageSourceService().getMessage("error.privilegesRequired",
×
779
                                                new Object[] { privilege }, null);
780
                        } else {
781
                                //Should we even be here if the privilege is blank?
782
                                errorMessage = Context.getMessageSourceService().getMessage("error.privilegesRequiredNoArgs");
×
783
                        }
784

785
                        throw new ContextAuthenticationException(errorMessage);
×
786
                }
787
        }
1✔
788
        
789
        /**
790
         * Adds one or more privileges to the list of privileges that that {@link #hasPrivilege(String)} will
791
         * regard as available regardless of whether the user would otherwise have the privilege.
792
         * <p/>
793
         * This is useful for situations where a system process may need access to some piece of data that the
794
         * user would not otherwise have access to, like a GlobalProperty. <strong>This facility should not be
795
         * used to return data to the user that they otherwise would be unable to see.</strong>
796
         * <p/>
797
         * The expected usage is:
798
         * <p/>
799
         * <pre>{@code
800
         * try {
801
         *   Context.addProxyPrivilege(&quot;AAA&quot;);
802
         *   Context.get*Service().methodRequiringAAAPrivilege();
803
         * }
804
         * finally {
805
         *   Context.removeProxyPrivilege(&quot;AAA&quot;);
806
         * }}
807
         * </pre>
808
         * <p/>
809
         *
810
         * @param privilege privileges to add in string form
811
         * @see #hasPrivilege(String)
812
         * @see #removeProxyPrivilege(String)
813
         */
814
        public static void addProxyPrivilege(String privilege) {
815
                getUserContext().addProxyPrivilege(privilege);
1✔
816
        }
1✔
817
        
818
        /**
819
         * Adds one or more privileges to the list of privileges that that {@link #hasPrivilege(String)} will
820
         * regard as available regardless of whether the user would otherwise have the privilege.
821
         * <p/>
822
         * This is useful for situations where a system process may need access to some piece of data that the
823
         * user would not otherwise have access to, like a GlobalProperty. <strong>This facility should not be
824
         * used to return data to the user that they otherwise would be unable to see.</strong>
825
         * <p/>
826
         * The expected usage is:
827
         * <p/>
828
         * <pre>{@code
829
         * try {
830
         *   Context.addProxyPrivilege(&quot;AAA&quot;);
831
         *   Context.get*Service().methodRequiringAAAPrivilege();
832
         * }
833
         * finally {
834
         *   Context.removeProxyPrivilege(&quot;AAA&quot;);
835
         * }}
836
         * </pre>
837
         * <p/>
838
         *
839
         * @param privileges privileges to add in string form
840
         * @see #hasPrivilege(String)
841
         * @see #removeProxyPrivilege(String...)
842
         * @since 3.0.0, 2.8.2, 2.7.8
843
         */
844
        public static void addProxyPrivilege(String... privileges) {
845
                getUserContext().addProxyPrivilege(privileges);
1✔
846
        }
1✔
847

848
        /**
849
         * Removes one or more privileges from the list of privileges that that {@link #hasPrivilege(String)} will
850
         * regard as available regardless of whether the user would otherwise have the privilege.
851
         * <p/>
852
         * This is the compliment for {@link #addProxyPrivilege(String...)} to clean-up the context.
853
         * <p/>
854
         *
855
         * @param privilege privileges to remove in string form
856
         * @see #hasPrivilege(String)
857
         * @see #addProxyPrivilege(String)
858
         */
859
        public static void removeProxyPrivilege(String privilege) {
860
                getUserContext().removeProxyPrivilege(privilege);
1✔
861
        }
1✔
862

863
        /**
864
         * Removes a privilege from the list of privileges that that {@link #hasPrivilege(String)} will
865
         * regard as available regardless of whether the user would otherwise have the privilege.
866
         * <p/>
867
         * This is the compliment for {@link #addProxyPrivilege(String...)} to clean-up the context.
868
         * <p/>
869
         *
870
         * @param privileges privileges to remove in string form
871
         * @see #hasPrivilege(String)
872
         * @see #addProxyPrivilege(String...)
873
         * * @since 3.0.0, 2.8.2, 2.7.8
874
         */
875
        public static void removeProxyPrivilege(String... privileges) {
876
                getUserContext().removeProxyPrivilege(privileges);
1✔
877
        }
1✔
878

879
        /**
880
         * Convenience method. Passes through to {@link UserContext#setLocale(Locale)}
881
         */
882
        public static void setLocale(Locale locale) {
883
                getUserContext().setLocale(locale);
1✔
884
        }
1✔
885

886
        /**
887
         * Convenience method. Passes through to {@link UserContext#getLocale()}
888
         *
889
         * <strong>Should</strong> not fail if session hasn't been opened
890
         */
891
        public static Locale getLocale() {
892
                // if a session hasn't been opened, just fetch the default
893
                if (!isSessionOpen()) {
1✔
894
                        return LocaleUtility.getDefaultLocale();
1✔
895
                }
896

897
                return getUserContext().getLocale();
1✔
898
        }
899

900
        /**
901
         * Used to define a unit of work. All "units of work" should be surrounded by openSession and
902
         * closeSession calls.
903
         */
904
        public static void openSession() {
905
                log.trace("opening session");
1✔
906
                setUserContext(new UserContext(getAuthenticationScheme())); // must be cleared out in
1✔
907
                // closeSession()
908
                getContextDAO().openSession();
1✔
909
        }
1✔
910

911
        /**
912
         * Used to define a unit of work. All "units of work" should be surrounded by openSession and
913
         * closeSession calls.
914
         */
915
        public static void closeSession() {
916
                log.trace("closing session");
1✔
917
                clearUserContext(); // because we set a UserContext on the current
1✔
918
                // thread in openSession()
919
                getContextDAO().closeSession();
1✔
920
        }
1✔
921

922
        /**
923
         * Used to define a unit of work which does not require clearing out the currently authenticated
924
         * user. Remember to call closeSessionWithCurrentUser in a, preferably, finally block after this
925
         * work.
926
         *
927
         * @since 1.10
928
         */
929
        public static void openSessionWithCurrentUser() {
930
                getContextDAO().openSession();
×
931
        }
×
932

933
        /**
934
         * Used when the a unit of work which started with a call for openSessionWithCurrentUser has
935
         * finished. This should be in a, preferably, finally block.
936
         *
937
         * @since 1.10
938
         */
939
        public static void closeSessionWithCurrentUser() {
940
                getContextDAO().closeSession();
×
941
        }
×
942

943
        /**
944
         * Clears cached changes made so far during this unit of work without writing them to the
945
         * database. If you call this method, and later call closeSession() or flushSession() your
946
         * changes are still lost.
947
         */
948
        public static void clearSession() {
949
                log.trace("clearing session");
1✔
950
                getContextDAO().clearSession();
1✔
951
        }
1✔
952

953
        /**
954
         * Forces any changes made so far in this unit of work to be written to the database
955
         *
956
         * @since 1.6
957
         */
958
        public static void flushSession() {
959
                log.trace("flushing session");
1✔
960
                getContextDAO().flushSession();
1✔
961
        }
1✔
962

963
        /**
964
         * This method tells whether {@link #openSession()} has been called or not already. If it hasn't
965
         * been called, some methods won't work correctly because a {@link UserContext} isn't available.
966
         *
967
         * @return true if {@link #openSession()} has been called already.
968
         * @since 1.5
969
         * <strong>Should</strong> return true if session is closed
970
         */
971
        public static boolean isSessionOpen() {
972
                return userContextHolder.get() != null;
1✔
973
        }
974

975
        /**
976
         * Used to re-read the state of the given instance from the underlying database.
977
         * @since 2.0
978
         * @param obj The object to refresh from the database in the session
979
         */
980
        public static void refreshEntity(Object obj) {
981
                log.trace("refreshing object: {}", obj);
1✔
982
                getContextDAO().refreshEntity(obj);
1✔
983
        }
1✔
984

985
        /**
986
         * Used to clear a cached object out of a session in the middle of a unit of work. Future
987
         * updates to this object will not be saved. Future gets of this object will not fetch this
988
         * cached copy
989
         *
990
         * @param obj The object to evict/remove from the session
991
         */
992
        public static void evictFromSession(Object obj) {
993
                log.trace("clearing session");
1✔
994
                getContextDAO().evictFromSession(obj);
1✔
995
        }
1✔
996

997
        /**
998
         * Evicts the entity data for a particular entity instance.
999
         *
1000
         * @param object entity instance to evict from the DB cache
1001
         */
1002
        public static void evictEntity(OpenmrsObject object) {
1003
                log.debug("Clearing DB cache for entity: {} with id: {}", object.getClass(), object.getId());
1✔
1004
                getContextDAO().evictEntity(object);
1✔
1005
        }
1✔
1006
        
1007
        /**
1008
         * Evicts all entity data of a particular class from the given region.
1009
         * 
1010
         * @param entityClass entity class to evict from the DB cache
1011
         */
1012
        public static void evictAllEntities(Class<?> entityClass) {
1013
                log.debug("Clearing DB cache for entities of type: {}", entityClass);
1✔
1014
                getContextDAO().evictAllEntities(entityClass);
1✔
1015
        }
1✔
1016
        
1017
        /**
1018
         * Evicts data from both DB and API cache.
1019
         */
1020
        public static void clearEntireCache() {
1021
                log.debug("Clearing DB cache");
1✔
1022
                getContextDAO().clearEntireCache();
1✔
1023
                log.debug("Clearing API cache");
1✔
1024
                getServiceContext().clearEntireApiCache();
1✔
1025
        }
1✔
1026
        
1027
        /**
1028
         * Starts the OpenMRS System Should be called prior to any kind of activity
1029
         *
1030
         * @param props Runtime properties to use for startup
1031
         * @throws InputRequiredException if the {@link DatabaseUpdater} has determined that updates
1032
         *             cannot continue without input from the user
1033
         * @throws DatabaseUpdateException if database updates are required, see
1034
         *             {@link DatabaseUpdater#executeChangelog()}
1035
         * @throws ModuleMustStartException if a module that should be started is not able to
1036
         * @see InputRequiredException#getRequiredInput() InputRequiredException#getRequiredInput() for
1037
         *      the required question/datatypes
1038
         */
1039
        public static synchronized void startup(Properties props) throws DatabaseUpdateException, InputRequiredException,
1040
        ModuleMustStartException {
1041
                // do any context database specific startup
1042
                getContextDAO().startup(props);
×
1043

1044
                if (getAdministrationService().isCoreSetupOnVersionChangeNeeded()) {
×
1045
                        log.info("Detected core version change. Running core setup hooks and Liquibase.");
×
1046
                        getAdministrationService().runCoreSetupOnVersionChange();
×
1047
                }
1048

1049
                // this should be first in the startup routines so that the application
1050
                // data directory can be set from the runtime properties
1051
                OpenmrsUtil.startup(props);
×
1052
                
1053
                openSession();
×
1054
                clearSession();
×
1055

1056
                // add any privileges/roles that /must/ exist for openmrs to work
1057
                // correctly.
1058
                checkCoreDataset();
×
1059
                
1060
                getContextDAO().setupSearchIndex();
×
1061

1062
                // Loop over each module and startup each with these custom properties
1063
                ModuleUtil.startup(props);
×
1064
        }
×
1065

1066
        /**
1067
         * Starts the OpenMRS System in a _non-webapp_ environment<br>
1068
         * <br>
1069
         * <b>Note:</b> This method calls {@link Context#openSession()}, so you must call
1070
         * {@link Context#closeSession()} somewhere on the same thread of this application so as to not
1071
         * leak memory.
1072
         *
1073
         * @param url database url like "jdbc:mysql://localhost:3306/openmrs?autoReconnect=true"
1074
         * @param username Connection username
1075
         * @param password Connection password
1076
         * @param properties Other startup properties
1077
         * @throws InputRequiredException if the {@link DatabaseUpdater} has determined that updates
1078
         *             cannot continue without input from the user
1079
         * @throws DatabaseUpdateException if the database must be updated. See {@link DatabaseUpdater}
1080
         * @throws ModuleMustStartException if a module that should start is not able to
1081
         * @see #startup(Properties)
1082
         * @see InputRequiredException#getRequiredInput() InputRequiredException#getRequiredInput() for
1083
         *      the required question/datatypes
1084
         */
1085
        public static synchronized void startup(String url, String username, String password, Properties properties)
1086
                        throws DatabaseUpdateException, InputRequiredException, ModuleMustStartException {
1087
                if (properties == null) {
×
1088
                        properties = new Properties();
×
1089
                }
1090

1091
                properties.put("connection.url", url);
×
1092
                properties.put("connection.username", username);
×
1093
                properties.put("connection.password", password);
×
1094
                setRuntimeProperties(properties);
×
1095

1096
                openSession(); // so that the startup method can use proxyPrivileges
×
1097

1098
                startup(properties);
×
1099
                
1100
                Context.getSchedulerService().onStartup();
×
1101
                
1102
                closeSession();
×
1103
        }
×
1104

1105
        /**
1106
         * Stops the OpenMRS System Should be called after all activity has ended and application is
1107
         * closing
1108
         */
1109
        public static void shutdown() {
1110
                log.debug("Shutting down the modules");
×
1111
                try {
1112
                        ModuleUtil.shutdown();
×
1113
                }
1114
                catch (Exception e) {
×
1115
                        log.warn("Error while shutting down module system", e);
×
1116
                }
×
1117

1118
                log.debug("Shutting down the context");
×
1119
                try {
1120
                        ContextDAO dao = null;
×
1121
                        try {
1122
                                dao = getContextDAO();
×
1123
                        }
1124
                        catch (APIException e) {
×
1125
                                // pass
1126
                        }
×
1127
                        if (dao != null) {
×
1128
                                dao.shutdown();
×
1129
                        }
1130
                }
1131
                catch (Exception e) {
×
1132
                        log.warn("Error while shutting down context dao", e);
×
1133
                }
×
1134
        }
×
1135

1136
        /**
1137
         * Used for getting services not in the previous get*Service() calls
1138
         *
1139
         * @param cls The Class of the service to get
1140
         * @return The requested Service
1141
         * <strong>Should</strong> return the same object when called multiple times for the same class
1142
         */
1143
        public static <T> T getService(Class<? extends T> cls) {
1144
                return getServiceContext().getService(cls);
1✔
1145
        }
1146

1147
        /**
1148
         * Adds an AOP advisor around the given Class <code>cls</code>
1149
         * <p>
1150
         * Advisors can wrap around a method and effect the method before or after
1151
         *
1152
         * @param cls
1153
         * @param advisor
1154
         */
1155
        public static void addAdvisor(Class cls, Advisor advisor) {
1156
                getServiceContext().addAdvisor(cls, advisor);
×
1157
        }
×
1158

1159
        /**
1160
         * Adds an AOP advice object around the given Class <code>cls</code>
1161
         * <p>
1162
         * Advice comes in the form of before or afterReturning methods
1163
         *
1164
         * @param cls
1165
         * @param advice
1166
         */
1167
        public static void addAdvice(Class cls, Advice advice) {
1168
                getServiceContext().addAdvice(cls, advice);
×
1169
        }
×
1170

1171
        /**
1172
         * Removes the given AOP advisor from Class <code>cls</code>
1173
         *
1174
         * @param cls
1175
         * @param advisor
1176
         */
1177
        public static void removeAdvisor(Class cls, Advisor advisor) {
1178
                getServiceContext().removeAdvisor(cls, advisor);
×
1179
        }
×
1180

1181
        /**
1182
         * Removes the given AOP advice object from Class <code>cls</code>
1183
         *
1184
         * @param cls
1185
         * @param advice
1186
         */
1187
        public static void removeAdvice(Class cls, Advice advice) {
1188
                getServiceContext().removeAdvice(cls, advice);
×
1189
        }
×
1190

1191
        /**
1192
         * Runs through the core data (e.g. privileges, roles, and global properties) and adds them if
1193
         * necessary.
1194
         */
1195
        public static void checkCoreDataset() {
1196
                // setting core roles
1197
                try {
1198
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_ROLES);
×
1199
                        Set<String> currentRoleNames = new HashSet<>();
×
1200
                        for (Role role : Context.getUserService().getAllRoles()) {
×
1201
                                currentRoleNames.add(role.getRole().toUpperCase());
×
1202
                        }
×
1203
                        Map<String, String> map = OpenmrsUtil.getCoreRoles();
×
1204
                        for (Map.Entry<String, String> entry : map.entrySet()) {
×
1205
                                String roleName = entry.getKey();
×
1206
                                if (!currentRoleNames.contains(roleName.toUpperCase())) {
×
1207
                                        Role role = new Role();
×
1208
                                        role.setRole(roleName);
×
1209
                                        role.setDescription(entry.getValue());
×
1210
                                        Context.getUserService().saveRole(role);
×
1211
                                }
1212
                        }
×
1213
                }
1214
                catch (Exception e) {
×
1215
                        log.error("Error while setting core roles for openmrs system", e);
×
1216
                }
1217
                finally {
1218
                        Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_ROLES);
×
1219
                }
1220

1221
                // setting core privileges
1222
                try {
1223
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_PRIVILEGES);
×
1224
                        Set<String> currentPrivilegeNames = new HashSet<>();
×
1225
                        for (Privilege privilege : Context.getUserService().getAllPrivileges()) {
×
1226
                                currentPrivilegeNames.add(privilege.getPrivilege().toUpperCase());
×
1227
                        }
×
1228
                        Map<String, String> map = OpenmrsUtil.getCorePrivileges();
×
1229
                        for (Map.Entry<String, String> entry : map.entrySet()) {
×
1230
                                String privilegeName = entry.getKey();
×
1231
                                if (!currentPrivilegeNames.contains(privilegeName.toUpperCase())) {
×
1232
                                        Privilege p = new Privilege();
×
1233
                                        p.setPrivilege(privilegeName);
×
1234
                                        p.setDescription(entry.getValue());
×
1235
                                        Context.getUserService().savePrivilege(p);
×
1236
                                }
1237
                        }
×
1238
                }
1239
                catch (Exception e) {
×
1240
                        log.error("Error while setting core privileges", e);
×
1241
                }
1242
                finally {
1243
                        Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_PRIVILEGES);
×
1244
                }
1245

1246
                // setting core global properties
1247
                try {
1248
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
1249
                        Context.addProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES);
×
1250
                        Set<String> currentPropNames = new HashSet<>();
×
1251
                        Map<String, GlobalProperty> propsMissingDescription = new HashMap<>();
×
1252
                        Map<String, GlobalProperty> propsMissingDatatype = new HashMap<>();
×
1253
                        for (GlobalProperty prop : Context.getAdministrationService().getAllGlobalProperties()) {
×
1254
                                currentPropNames.add(prop.getProperty().toUpperCase());
×
1255
                                if (prop.getDescription() == null) {
×
1256
                                        propsMissingDescription.put(prop.getProperty().toUpperCase(), prop);
×
1257
                                }
1258
                                if (prop.getDatatypeClassname() == null) {
×
1259
                                        propsMissingDatatype.put(prop.getProperty().toUpperCase(), prop);
×
1260
                                }
1261
                        }
×
1262

1263
                        for (GlobalProperty coreProp : OpenmrsConstants.CORE_GLOBAL_PROPERTIES()) {
×
1264
                                String corePropName = coreProp.getProperty().toUpperCase();
×
1265
                                // if the prop doesn't exist, save it
1266
                                if (!currentPropNames.contains(corePropName)) {
×
1267
                                        Context.getAdministrationService().saveGlobalProperty(coreProp);
×
1268
                                        currentPropNames.add(corePropName); // add to list in case
×
1269
                                        // of duplicates
1270
                                } else {
1271
                                        // if the prop is missing its description, update it
1272
                                        GlobalProperty propToUpdate = propsMissingDescription.get(corePropName);
×
1273
                                        if (propToUpdate != null) {
×
1274
                                                propToUpdate.setDescription(coreProp.getDescription());
×
1275
                                                Context.getAdministrationService().saveGlobalProperty(propToUpdate);
×
1276
                                        }
1277
                                        // set missing datatypes
1278
                                        propToUpdate = propsMissingDatatype.get(corePropName);
×
1279
                                        if (propToUpdate != null && coreProp.getDatatypeClassname() != null) {
×
1280
                                                propToUpdate.setDatatypeClassname(coreProp.getDatatypeClassname());
×
1281
                                                propToUpdate.setDatatypeConfig(coreProp.getDatatypeConfig());
×
1282
                                                propToUpdate.setPreferredHandlerClassname(coreProp.getPreferredHandlerClassname());
×
1283
                                                propToUpdate.setHandlerConfig(coreProp.getHandlerConfig());
×
1284
                                                Context.getAdministrationService().saveGlobalProperty(propToUpdate);
×
1285
                                        }
1286
                                }
1287
                        }
×
1288
                }
1289
                catch (Exception e) {
×
1290
                        log.error("Error while setting core global properties", e);
×
1291
                }
1292
                finally {
1293
                        Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
1294
                        Context.removeProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES);
×
1295
                }
1296

1297
                // setting default validation rule
1298
                AdministrationService as = Context.getAdministrationService();
×
1299
                Boolean disableValidation = Boolean.valueOf(as.getGlobalProperty(OpenmrsConstants.GP_DISABLE_VALIDATION, "false"));
×
1300
                ValidateUtil.setDisableValidation(disableValidation);
×
1301

1302
                PersonName.setFormat(Context.getAdministrationService().getGlobalProperty(
×
1303
                                OpenmrsConstants.GLOBAL_PROPERTY_LAYOUT_NAME_FORMAT));
1304

1305
                Allergen.setOtherNonCodedConceptUuid(Context.getAdministrationService().getGlobalProperty(
×
1306
                                OpenmrsConstants.GP_ALLERGEN_OTHER_NON_CODED_UUID));
1307
        }
×
1308

1309
        /**
1310
         * Updates the openmrs database to the latest. This is only needed if using the API alone. <br>
1311
         * <br>
1312
         * The typical use-case would be: Try to {@link #startup(String, String, String, Properties)},
1313
         * if that fails, call this method to get the database up to speed.
1314
         *
1315
         * @param userInput (can be null) responses from the user about needed input
1316
         * @throws DatabaseUpdateException if an error occurred while updating
1317
         * @since 1.5
1318
         * @deprecated as of 2.4
1319
         * 
1320
         */
1321
        @Deprecated
1322
        public static void updateDatabase(Map<String, Object> userInput) throws DatabaseUpdateException {
1323
                throw new UnsupportedOperationException("As of 2.4, this method is not longer implemented");
×
1324
        }
1325

1326
        /**
1327
         * Gets the simple date format for the current user's locale. The format will be similar in size
1328
         * to mm/dd/yyyy
1329
         *
1330
         * @return SimpleDateFormat for the user's current locale
1331
         * @see org.openmrs.util.OpenmrsUtil#getDateFormat(Locale)
1332
         * <strong>Should</strong> return a pattern with four y characters in it
1333
         */
1334
        public static SimpleDateFormat getDateFormat() {
1335
                return OpenmrsUtil.getDateFormat(getLocale());
1✔
1336
        }
1337

1338
        /**
1339
         * Gets the simple time format for the current user's locale. The format will be similar to
1340
         * hh:mm a
1341
         *
1342
         * @return SimpleDateFormat for the user's current locale
1343
         * @see org.openmrs.util.OpenmrsUtil#getTimeFormat(Locale)
1344
         * <strong>Should</strong> return a pattern with two h characters in it
1345
         */
1346
        public static SimpleDateFormat getTimeFormat() {
1347
                return OpenmrsUtil.getTimeFormat(getLocale());
×
1348
        }
1349

1350
        /**
1351
         * Gets the simple datetime format for the current user's locale. The format will be similar to
1352
         * mm/dd/yyyy hh:mm a
1353
         *
1354
         * @return SimpleDateFormat for the user's current locale
1355
         * @see org.openmrs.util.OpenmrsUtil#getDateTimeFormat(Locale)
1356
         * <strong>Should</strong> return a pattern with four y characters and two h characters in it
1357
         */
1358
        public static SimpleDateFormat getDateTimeFormat() {
1359
                return OpenmrsUtil.getDateTimeFormat(getLocale());
1✔
1360
        }
1361

1362
        /**
1363
         * @return true/false whether the service context is currently being refreshed
1364
         * @see org.openmrs.api.context.ServiceContext#isRefreshingContext()
1365
         */
1366
        public static boolean isRefreshingContext() {
1367
                return getServiceContext().isRefreshingContext();
1✔
1368
        }
1369

1370
        /**
1371
         * @since 1.5
1372
         * @see ServiceContext#getRegisteredComponents(Class)
1373
         */
1374
        public static <T> List<T> getRegisteredComponents(Class<T> type) {
1375
                return getServiceContext().getRegisteredComponents(type);
1✔
1376
        }
1377

1378
        /**
1379
         * @see ServiceContext#getRegisteredComponent(String, Class)
1380
         * @since 1.9.4
1381
         */
1382
        public static <T> T getRegisteredComponent(String beanName, Class<T> type) throws APIException {
1383
                return getServiceContext().getRegisteredComponent(beanName, type);
1✔
1384
        }
1385

1386
        /**
1387
         * @see ServiceContext#getModuleOpenmrsServices(String)
1388
         * @since 1.9
1389
         */
1390
        public static List<OpenmrsService> getModuleOpenmrsServices(String modulePackage) {
1391
                return getServiceContext().getModuleOpenmrsServices(modulePackage);
1✔
1392
        }
1393

1394
        /**
1395
         * @since 1.9
1396
         * @see ServiceContext#getVisitService()
1397
         */
1398
        public static VisitService getVisitService() {
1399
                return getServiceContext().getVisitService();
1✔
1400
        }
1401

1402
        /**
1403
         * @since 1.9
1404
         * @see ServiceContext#getProviderService()
1405
         */
1406
        public static ProviderService getProviderService() {
1407
                return getServiceContext().getProviderService();
1✔
1408
        }
1409

1410
        /**
1411
         * @since 1.9
1412
         * @see ServiceContext#getDatatypeService()
1413
         */
1414
        public static DatatypeService getDatatypeService() {
1415
                return getServiceContext().getDatatypeService();
1✔
1416
        }
1417

1418
        /**
1419
         * Add or replace a property in the config properties list
1420
         *
1421
         * @param key name of the property
1422
         * @param value value of the property
1423
         * @since 1.9
1424
         */
1425
        public static void addConfigProperty(Object key, Object value) {
1426
                configProperties.put(key, value);
×
1427
        }
×
1428

1429
        /**
1430
         * Remove a property from the list of config properties
1431
         *
1432
         * @param key name of the property
1433
         * @since 1.9
1434
         */
1435
        public static void removeConfigProperty(Object key) {
1436
                configProperties.remove(key);
×
1437
        }
×
1438

1439
        /**
1440
         * Get the config properties that have been added to this OpenMRS instance
1441
         *
1442
         * @return copy of the module properties
1443
         * @since 1.9
1444
         */
1445
        public static Properties getConfigProperties() {
1446
                Properties props = new Properties();
1✔
1447
                props.putAll(configProperties);
1✔
1448
                return props;
1✔
1449
        }
1450

1451
        /**
1452
         * Updates the search index. It is a blocking operation, which may take even a few minutes
1453
         * depending on the index size.
1454
         * <p>
1455
         * There is no need to call this method in normal usage since the index is automatically updated
1456
         * whenever DB transactions are committed.
1457
         * <p>
1458
         * The method is designated to be used in tests, which rollback transactions. Note that if the
1459
         * transaction is rolled back, changes to the index will not be reverted.
1460
         *
1461
         * @since 1.11
1462
         */
1463
        public static void updateSearchIndex() {
1464
                getContextDAO().updateSearchIndex();
×
1465
        }
×
1466

1467
        /**
1468
         * Updates the search index. It is an asynchronous operation.
1469
         * <p>
1470
         * There is no need to call this method in normal usage since the index is automatically updated
1471
         * whenever DB transactions are committed.
1472
         * <p>
1473
         *
1474
         * @return object representing the result of the started asynchronous operation
1475
         */
1476
        public static Future<?> updateSearchIndexAsync() {
1477
                return getContextDAO().updateSearchIndexAsync();
×
1478
        }
1479

1480
        /**
1481
         * It should be used <b>IN TESTS ONLY</b>. See {@link #updateSearchIndex(Class[])} for normal use.
1482
         * <p>
1483
         * Updates the search index for objects of the given type.
1484
         *
1485
         * @see #updateSearchIndex()
1486
         * @see #updateSearchIndex(Class[]) 
1487
         * @param type
1488
         * @since 1.11
1489
         */
1490
        public static void updateSearchIndexForType(Class<?> type) {
1491
                getContextDAO().updateSearchIndexForType(type);
1✔
1492
        }
1✔
1493

1494
        /**
1495
         * Updates the search index for objects of the given types using mass indexer.
1496
         * 
1497
         * @see #updateSearchIndex() 
1498
         * @param types
1499
         * @since 2.8.0
1500
         */
1501
        public static void updateSearchIndex(Class<?>... types) {
1502
                getContextDAO().updateSearchIndex(types);
×
1503
        }
×
1504

1505
        /**
1506
         * Updates the search index for the given object.
1507
         *
1508
         * @see #updateSearchIndex()
1509
         * @param object
1510
         * @since 1.11
1511
         */
1512
        public static void updateSearchIndexForObject(Object object) {
1513
                getContextDAO().updateSearchIndexForObject(object);
×
1514
        }
×
1515

1516
        /**
1517
         * @see org.openmrs.api.context.ServiceContext#setUseSystemClassLoader(boolean)
1518
         * @since 1.10
1519
         */
1520
        public static void setUseSystemClassLoader(boolean useSystemClassLoader) {
1521
                getServiceContext().setUseSystemClassLoader(useSystemClassLoader);
1✔
1522
        }
1✔
1523

1524
        /**
1525
         * @see org.openmrs.api.context.ServiceContext#isUseSystemClassLoader()
1526
         * @since 1.10
1527
         */
1528
        public static boolean isUseSystemClassLoader() {
1529
                return getServiceContext().isUseSystemClassLoader();
×
1530
        }
1531

1532
        /**
1533
         * @return a Connection from the OpenMRS database connection pool
1534
         * @since 2.5.7
1535
         */
1536
        public static Connection getDatabaseConnection() {
1537
                return getContextDAO().getDatabaseConnection();
×
1538
        }
1539

1540
        /**
1541
         * It is used to shorten startup time by e.g. not running Liquibase checks, if versions did not change or 
1542
         * re-using expanded jars between restarts. If you want to force a standard startup
1543
         * procedure without optimization, please set the <code>optimized.startup</code> runtime property to <code>false</code>.
1544
         * (<code>true</code> by default) 
1545
         * <p>
1546
         * See <a href="https://issues.openmrs.org/browse/TRUNK-6417">TRUNK-6417</a>
1547
         * 
1548
         * @return <code>true</code> (default) or <code>false</code>
1549
         * @since 2.9.0
1550
         */
1551
        public static boolean isOptimizedStartup() {
1552
                return Boolean.parseBoolean(Context.getRuntimeProperties().getProperty("optimized.startup", "true"));
1✔
1553
        }
1554
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc