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

openmrs / openmrs-core / 23193642646

17 Mar 2026 12:13PM UTC coverage: 63.1% (-0.3%) from 63.429%
23193642646

push

github

rkorytkowski
Fixing: Fix an issue with the ModuleResourceServlet

0 of 2 new or added lines in 1 file covered. (0.0%)

925 existing lines in 17 files now uncovered.

23137 of 36667 relevant lines covered (63.1%)

0.63 hits per line

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

50.83
/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✔
UNCOV
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 {
UNCOV
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
                }
UNCOV
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
                }
UNCOV
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) {
1✔
275
                                if (serviceContext == null) {
1✔
276
                                        serviceContext = ServiceContext.getInstance();
1✔
277
                                }
278
                        }
1✔
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✔
UNCOV
336
                        log.error("Authentication attempted while operating on a "
×
337
                                        + "daemon thread, authenticating is not necessary or allowed");
UNCOV
338
                        return new BasicAuthenticated(Daemon.getDaemonThreadUser(), "No auth scheme used by Context - Daemon user is always authenticated.");
×
339
                }
340

341
                if (credentials == null) {
1✔
UNCOV
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✔
UNCOV
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(){
UNCOV
469
                return getServiceContext().getMedicationDispenseService();
×
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() {
UNCOV
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() {
UNCOV
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
                }
UNCOV
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
UNCOV
593
                        if (gp.getProperty().equals("mail.transport_protocol")) {
×
594
                                p.setProperty("mail.transport.protocol", gp.getPropertyValue());
×
595
                        }
UNCOV
596
                        else if (gp.getProperty().equals("mail.smtp_host")) {
×
597
                                p.setProperty("mail.smtp.host", gp.getPropertyValue());
×
598
                        }
UNCOV
599
                        else if (gp.getProperty().equals("mail.smtp_port")) {
×
600
                                p.setProperty("mail.smtp.port", gp.getPropertyValue());
×
601
                        }
UNCOV
602
                        else if (gp.getProperty().equals("mail.smtp_auth")) {
×
603
                                p.setProperty("mail.smtp.auth", gp.getPropertyValue());
×
604
                        }
605
                        else {
UNCOV
606
                                p.setProperty(gp.getProperty(), gp.getPropertyValue());
×
607
                        }
UNCOV
608
                }
×
609
                for (String runtimeProperty : runtimeProperties.stringPropertyNames()) {
1✔
610
                        if (runtimeProperty.startsWith(prefix)) {
1✔
UNCOV
611
                                p.setProperty(runtimeProperty, runtimeProperties.getProperty(runtimeProperty));
×
612
                        }
613
                }
1✔
614
                for (String systemProperty : System.getProperties().stringPropertyNames()) {
1✔
615
                        if (systemProperty.startsWith(prefix)) {
1✔
UNCOV
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() {
UNCOV
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✔
UNCOV
685
                        return true;
×
686
                } else {
687
                        try {
688
                                return getAuthenticatedUser() != null;
1✔
UNCOV
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
         * logs out the "active" (authenticated) user within context
698
         *
699
         * @see #authenticate
700
         * <strong>Should</strong> not fail if session hasn't been opened yet
701
         */
702
        public static void logout() {
703
                if (!isSessionOpen()) {
1✔
704
                        return; // fail early if there isn't even a session open
1✔
705
                }
706
                log.debug("Logging out : {}", getAuthenticatedUser());
1✔
707

708
                getUserContext().logout();
1✔
709

710
                // reset the UserContext object (usually cleared out by closeSession()
711
                // soon after this)
712
                setUserContext(new UserContext(getAuthenticationScheme()));
1✔
713
        }
1✔
714

715
        /**
716
         * Convenience method. Passes through to userContext.getAllRoles(User)
717
         */
718
        public static Set<Role> getAllRoles(User user) throws Exception {
UNCOV
719
                return getUserContext().getAllRoles();
×
720
        }
721

722
        /**
723
         * Tests whether the currently authenticated user has a particular privilege
724
         */
725
        public static boolean hasPrivilege(String privilege) {
726
                // the daemon threads have access to all things
727
                if (Daemon.isDaemonThread()) {
1✔
728
                        return true;
1✔
729
                }
730

731
                return getUserContext().hasPrivilege(privilege);
1✔
732
        }
733

734
        /**
735
         * Throws an exception if the currently authenticated user does not have the specified
736
         * privilege.
737
         *
738
         * @param privilege
739
         * @throws ContextAuthenticationException
740
         */
741
        public static void requirePrivilege(String privilege) throws ContextAuthenticationException {
742
                if (!hasPrivilege(privilege)) {
1✔
743
                        String errorMessage;
UNCOV
744
                        if (StringUtils.isNotBlank(privilege)) {
×
745
                                errorMessage = Context.getMessageSourceService().getMessage("error.privilegesRequired",
×
746
                                                new Object[] { privilege }, null);
747
                        } else {
748
                                //Should we even be here if the privilege is blank?
UNCOV
749
                                errorMessage = Context.getMessageSourceService().getMessage("error.privilegesRequiredNoArgs");
×
750
                        }
751

UNCOV
752
                        throw new ContextAuthenticationException(errorMessage);
×
753
                }
754
        }
1✔
755
        
756
        /**
757
         * Adds one or more privileges to the list of privileges that that {@link #hasPrivilege(String)} will
758
         * regard as available regardless of whether the user would otherwise have the privilege.
759
         * <p/>
760
         * This is useful for situations where a system process may need access to some piece of data that the
761
         * user would not otherwise have access to, like a GlobalProperty. <strong>This facility should not be
762
         * used to return data to the user that they otherwise would be unable to see.</strong>
763
         * <p/>
764
         * The expected usage is:
765
         * <p/>
766
         * <pre>{@code
767
         * try {
768
         *   Context.addProxyPrivilege(&quot;AAA&quot;);
769
         *   Context.get*Service().methodRequiringAAAPrivilege();
770
         * }
771
         * finally {
772
         *   Context.removeProxyPrivilege(&quot;AAA&quot;);
773
         * }}
774
         * </pre>
775
         * <p/>
776
         *
777
         * @param privilege privileges to add in string form
778
         * @see #hasPrivilege(String)
779
         * @see #removeProxyPrivilege(String)
780
         */
781
        public static void addProxyPrivilege(String privilege) {
782
                getUserContext().addProxyPrivilege(privilege);
1✔
783
        }
1✔
784
        
785
        /**
786
         * Adds one or more privileges to the list of privileges that that {@link #hasPrivilege(String)} will
787
         * regard as available regardless of whether the user would otherwise have the privilege.
788
         * <p/>
789
         * This is useful for situations where a system process may need access to some piece of data that the
790
         * user would not otherwise have access to, like a GlobalProperty. <strong>This facility should not be
791
         * used to return data to the user that they otherwise would be unable to see.</strong>
792
         * <p/>
793
         * The expected usage is:
794
         * <p/>
795
         * <pre>{@code
796
         * try {
797
         *   Context.addProxyPrivilege(&quot;AAA&quot;);
798
         *   Context.get*Service().methodRequiringAAAPrivilege();
799
         * }
800
         * finally {
801
         *   Context.removeProxyPrivilege(&quot;AAA&quot;);
802
         * }}
803
         * </pre>
804
         * <p/>
805
         *
806
         * @param privileges privileges to add in string form
807
         * @see #hasPrivilege(String)
808
         * @see #removeProxyPrivilege(String...)
809
         * @since 3.0.0, 2.8.2, 2.7.8
810
         */
811
        public static void addProxyPrivilege(String... privileges) {
812
                getUserContext().addProxyPrivilege(privileges);
1✔
813
        }
1✔
814

815
        /**
816
         * Removes one or more privileges from the list of privileges that that {@link #hasPrivilege(String)} will
817
         * regard as available regardless of whether the user would otherwise have the privilege.
818
         * <p/>
819
         * This is the compliment for {@link #addProxyPrivilege(String...)} to clean-up the context.
820
         * <p/>
821
         *
822
         * @param privilege privileges to remove in string form
823
         * @see #hasPrivilege(String)
824
         * @see #addProxyPrivilege(String)
825
         */
826
        public static void removeProxyPrivilege(String privilege) {
827
                getUserContext().removeProxyPrivilege(privilege);
1✔
828
        }
1✔
829

830
        /**
831
         * Removes a privilege from the list of privileges that that {@link #hasPrivilege(String)} will
832
         * regard as available regardless of whether the user would otherwise have the privilege.
833
         * <p/>
834
         * This is the compliment for {@link #addProxyPrivilege(String...)} to clean-up the context.
835
         * <p/>
836
         *
837
         * @param privileges privileges to remove in string form
838
         * @see #hasPrivilege(String)
839
         * @see #addProxyPrivilege(String...)
840
         * * @since 3.0.0, 2.8.2, 2.7.8
841
         */
842
        public static void removeProxyPrivilege(String... privileges) {
843
                getUserContext().removeProxyPrivilege(privileges);
1✔
844
        }
1✔
845

846
        /**
847
         * Convenience method. Passes through to {@link UserContext#setLocale(Locale)}
848
         */
849
        public static void setLocale(Locale locale) {
850
                getUserContext().setLocale(locale);
1✔
851
        }
1✔
852

853
        /**
854
         * Convenience method. Passes through to {@link UserContext#getLocale()}
855
         *
856
         * <strong>Should</strong> not fail if session hasn't been opened
857
         */
858
        public static Locale getLocale() {
859
                // if a session hasn't been opened, just fetch the default
860
                if (!isSessionOpen()) {
1✔
861
                        return LocaleUtility.getDefaultLocale();
1✔
862
                }
863

864
                return getUserContext().getLocale();
1✔
865
        }
866

867
        /**
868
         * Used to define a unit of work. All "units of work" should be surrounded by openSession and
869
         * closeSession calls.
870
         */
871
        public static void openSession() {
872
                log.trace("opening session");
1✔
873
                setUserContext(new UserContext(getAuthenticationScheme())); // must be cleared out in
1✔
874
                // closeSession()
875
                getContextDAO().openSession();
1✔
876
        }
1✔
877

878
        /**
879
         * Used to define a unit of work. All "units of work" should be surrounded by openSession and
880
         * closeSession calls.
881
         */
882
        public static void closeSession() {
883
                log.trace("closing session");
1✔
884
                clearUserContext(); // because we set a UserContext on the current
1✔
885
                // thread in openSession()
886
                getContextDAO().closeSession();
1✔
887
        }
1✔
888

889
        /**
890
         * Used to define a unit of work which does not require clearing out the currently authenticated
891
         * user. Remember to call closeSessionWithCurrentUser in a, preferably, finally block after this
892
         * work.
893
         *
894
         * @since 1.10
895
         */
896
        public static void openSessionWithCurrentUser() {
UNCOV
897
                getContextDAO().openSession();
×
898
        }
×
899

900
        /**
901
         * Used when the a unit of work which started with a call for openSessionWithCurrentUser has
902
         * finished. This should be in a, preferably, finally block.
903
         *
904
         * @since 1.10
905
         */
906
        public static void closeSessionWithCurrentUser() {
UNCOV
907
                getContextDAO().closeSession();
×
908
        }
×
909

910
        /**
911
         * Clears cached changes made so far during this unit of work without writing them to the
912
         * database. If you call this method, and later call closeSession() or flushSession() your
913
         * changes are still lost.
914
         */
915
        public static void clearSession() {
916
                log.trace("clearing session");
1✔
917
                getContextDAO().clearSession();
1✔
918
        }
1✔
919

920
        /**
921
         * Forces any changes made so far in this unit of work to be written to the database
922
         *
923
         * @since 1.6
924
         */
925
        public static void flushSession() {
926
                log.trace("flushing session");
1✔
927
                getContextDAO().flushSession();
1✔
928
        }
1✔
929

930
        /**
931
         * This method tells whether {@link #openSession()} has been called or not already. If it hasn't
932
         * been called, some methods won't work correctly because a {@link UserContext} isn't available.
933
         *
934
         * @return true if {@link #openSession()} has been called already.
935
         * @since 1.5
936
         * <strong>Should</strong> return true if session is closed
937
         */
938
        public static boolean isSessionOpen() {
939
                return userContextHolder.get() != null;
1✔
940
        }
941

942
        /**
943
         * Used to re-read the state of the given instance from the underlying database.
944
         * @since 2.0
945
         * @param obj The object to refresh from the database in the session
946
         */
947
        public static void refreshEntity(Object obj) {
948
                log.trace("refreshing object: {}", obj);
1✔
949
                getContextDAO().refreshEntity(obj);
1✔
950
        }
1✔
951

952
        /**
953
         * Used to clear a cached object out of a session in the middle of a unit of work. Future
954
         * updates to this object will not be saved. Future gets of this object will not fetch this
955
         * cached copy
956
         *
957
         * @param obj The object to evict/remove from the session
958
         */
959
        public static void evictFromSession(Object obj) {
960
                log.trace("clearing session");
1✔
961
                getContextDAO().evictFromSession(obj);
1✔
962
        }
1✔
963

964
        /**
965
         * Evicts the entity data for a particular entity instance.
966
         *
967
         * @param object entity instance to evict from the DB cache
968
         */
969
        public static void evictEntity(OpenmrsObject object) {
970
                log.debug("Clearing DB cache for entity: {} with id: {}", object.getClass(), object.getId());
1✔
971
                getContextDAO().evictEntity(object);
1✔
972
        }
1✔
973
        
974
        /**
975
         * Evicts all entity data of a particular class from the given region.
976
         * 
977
         * @param entityClass entity class to evict from the DB cache
978
         */
979
        public static void evictAllEntities(Class<?> entityClass) {
980
                log.debug("Clearing DB cache for entities of type: {}", entityClass);
1✔
981
                getContextDAO().evictAllEntities(entityClass);
1✔
982
        }
1✔
983
        
984
        /**
985
         * Evicts data from both DB and API cache.
986
         */
987
        public static void clearEntireCache() {
988
                log.debug("Clearing DB cache");
1✔
989
                getContextDAO().clearEntireCache();
1✔
990
                log.debug("Clearing API cache");
1✔
991
                getServiceContext().clearEntireApiCache();
1✔
992
        }
1✔
993
        
994
        /**
995
         * Starts the OpenMRS System Should be called prior to any kind of activity
996
         *
997
         * @param props Runtime properties to use for startup
998
         * @throws InputRequiredException if the {@link DatabaseUpdater} has determined that updates
999
         *             cannot continue without input from the user
1000
         * @throws DatabaseUpdateException if database updates are required, see
1001
         *             {@link DatabaseUpdater#executeChangelog()}
1002
         * @throws ModuleMustStartException if a module that should be started is not able to
1003
         * @see InputRequiredException#getRequiredInput() InputRequiredException#getRequiredInput() for
1004
         *      the required question/datatypes
1005
         */
1006
        public static synchronized void startup(Properties props) throws DatabaseUpdateException, InputRequiredException,
1007
        ModuleMustStartException {
1008
                // do any context database specific startup
UNCOV
1009
                getContextDAO().startup(props);
×
1010

UNCOV
1011
                if (getAdministrationService().isCoreSetupOnVersionChangeNeeded()) {
×
1012
                        log.info("Detected core version change. Running core setup hooks and Liquibase.");
×
1013
                        getAdministrationService().runCoreSetupOnVersionChange();
×
1014
                }
1015

1016
                // this should be first in the startup routines so that the application
1017
                // data directory can be set from the runtime properties
UNCOV
1018
                OpenmrsUtil.startup(props);
×
1019
                
UNCOV
1020
                openSession();
×
1021
                clearSession();
×
1022

1023
                // add any privileges/roles that /must/ exist for openmrs to work
1024
                // correctly.
UNCOV
1025
                checkCoreDataset();
×
1026
                
UNCOV
1027
                getContextDAO().setupSearchIndex();
×
1028

1029
                // Loop over each module and startup each with these custom properties
UNCOV
1030
                ModuleUtil.startup(props);
×
1031
        }
×
1032

1033
        /**
1034
         * Starts the OpenMRS System in a _non-webapp_ environment<br>
1035
         * <br>
1036
         * <b>Note:</b> This method calls {@link Context#openSession()}, so you must call
1037
         * {@link Context#closeSession()} somewhere on the same thread of this application so as to not
1038
         * leak memory.
1039
         *
1040
         * @param url database url like "jdbc:mysql://localhost:3306/openmrs?autoReconnect=true"
1041
         * @param username Connection username
1042
         * @param password Connection password
1043
         * @param properties Other startup properties
1044
         * @throws InputRequiredException if the {@link DatabaseUpdater} has determined that updates
1045
         *             cannot continue without input from the user
1046
         * @throws DatabaseUpdateException if the database must be updated. See {@link DatabaseUpdater}
1047
         * @throws ModuleMustStartException if a module that should start is not able to
1048
         * @see #startup(Properties)
1049
         * @see InputRequiredException#getRequiredInput() InputRequiredException#getRequiredInput() for
1050
         *      the required question/datatypes
1051
         */
1052
        public static synchronized void startup(String url, String username, String password, Properties properties)
1053
                        throws DatabaseUpdateException, InputRequiredException, ModuleMustStartException {
UNCOV
1054
                if (properties == null) {
×
1055
                        properties = new Properties();
×
1056
                }
1057

UNCOV
1058
                properties.put("connection.url", url);
×
1059
                properties.put("connection.username", username);
×
1060
                properties.put("connection.password", password);
×
1061
                setRuntimeProperties(properties);
×
1062

UNCOV
1063
                openSession(); // so that the startup method can use proxyPrivileges
×
1064

UNCOV
1065
                startup(properties);
×
1066
                
UNCOV
1067
                Context.getSchedulerService().onStartup();
×
1068
                
1069
                closeSession();
×
UNCOV
1070
        }
×
1071

1072
        /**
1073
         * Stops the OpenMRS System Should be called after all activity has ended and application is
1074
         * closing
1075
         */
1076
        public static void shutdown() {
UNCOV
1077
                log.debug("Shutting down the modules");
×
1078
                try {
1079
                        ModuleUtil.shutdown();
×
1080
                }
UNCOV
1081
                catch (Exception e) {
×
1082
                        log.warn("Error while shutting down module system", e);
×
UNCOV
1083
                }
×
1084

1085
                log.debug("Shutting down the context");
×
1086
                try {
UNCOV
1087
                        ContextDAO dao = null;
×
1088
                        try {
UNCOV
1089
                                dao = getContextDAO();
×
1090
                        }
UNCOV
1091
                        catch (APIException e) {
×
1092
                                // pass
1093
                        }
×
1094
                        if (dao != null) {
×
UNCOV
1095
                                dao.shutdown();
×
1096
                        }
1097
                }
1098
                catch (Exception e) {
×
UNCOV
1099
                        log.warn("Error while shutting down context dao", e);
×
1100
                }
×
UNCOV
1101
        }
×
1102

1103
        /**
1104
         * Used for getting services not in the previous get*Service() calls
1105
         *
1106
         * @param cls The Class of the service to get
1107
         * @return The requested Service
1108
         * <strong>Should</strong> return the same object when called multiple times for the same class
1109
         */
1110
        public static <T> T getService(Class<? extends T> cls) {
1111
                return getServiceContext().getService(cls);
1✔
1112
        }
1113

1114
        /**
1115
         * Adds an AOP advisor around the given Class <code>cls</code>
1116
         * <p>
1117
         * Advisors can wrap around a method and effect the method before or after
1118
         *
1119
         * @param cls
1120
         * @param advisor
1121
         */
1122
        public static void addAdvisor(Class cls, Advisor advisor) {
UNCOV
1123
                getServiceContext().addAdvisor(cls, advisor);
×
UNCOV
1124
        }
×
1125

1126
        /**
1127
         * Adds an AOP advice object around the given Class <code>cls</code>
1128
         * <p>
1129
         * Advice comes in the form of before or afterReturning methods
1130
         *
1131
         * @param cls
1132
         * @param advice
1133
         */
1134
        public static void addAdvice(Class cls, Advice advice) {
1135
                getServiceContext().addAdvice(cls, advice);
×
UNCOV
1136
        }
×
1137

1138
        /**
1139
         * Removes the given AOP advisor from Class <code>cls</code>
1140
         *
1141
         * @param cls
1142
         * @param advisor
1143
         */
1144
        public static void removeAdvisor(Class cls, Advisor advisor) {
UNCOV
1145
                getServiceContext().removeAdvisor(cls, advisor);
×
1146
        }
×
1147

1148
        /**
1149
         * Removes the given AOP advice object from Class <code>cls</code>
1150
         *
1151
         * @param cls
1152
         * @param advice
1153
         */
1154
        public static void removeAdvice(Class cls, Advice advice) {
UNCOV
1155
                getServiceContext().removeAdvice(cls, advice);
×
1156
        }
×
1157

1158
        /**
1159
         * Runs through the core data (e.g. privileges, roles, and global properties) and adds them if
1160
         * necessary.
1161
         */
1162
        public static void checkCoreDataset() {
1163
                // setting core roles
1164
                try {
UNCOV
1165
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_ROLES);
×
1166
                        Set<String> currentRoleNames = new HashSet<>();
×
1167
                        for (Role role : Context.getUserService().getAllRoles()) {
×
UNCOV
1168
                                currentRoleNames.add(role.getRole().toUpperCase());
×
UNCOV
1169
                        }
×
UNCOV
1170
                        Map<String, String> map = OpenmrsUtil.getCoreRoles();
×
UNCOV
1171
                        for (Map.Entry<String, String> entry : map.entrySet()) {
×
UNCOV
1172
                                String roleName = entry.getKey();
×
UNCOV
1173
                                if (!currentRoleNames.contains(roleName.toUpperCase())) {
×
UNCOV
1174
                                        Role role = new Role();
×
UNCOV
1175
                                        role.setRole(roleName);
×
1176
                                        role.setDescription(entry.getValue());
×
1177
                                        Context.getUserService().saveRole(role);
×
1178
                                }
1179
                        }
×
1180
                }
1181
                catch (Exception e) {
×
1182
                        log.error("Error while setting core roles for openmrs system", e);
×
1183
                }
1184
                finally {
1185
                        Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_ROLES);
×
1186
                }
1187

1188
                // setting core privileges
1189
                try {
1190
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_PRIVILEGES);
×
UNCOV
1191
                        Set<String> currentPrivilegeNames = new HashSet<>();
×
1192
                        for (Privilege privilege : Context.getUserService().getAllPrivileges()) {
×
1193
                                currentPrivilegeNames.add(privilege.getPrivilege().toUpperCase());
×
UNCOV
1194
                        }
×
UNCOV
1195
                        Map<String, String> map = OpenmrsUtil.getCorePrivileges();
×
1196
                        for (Map.Entry<String, String> entry : map.entrySet()) {
×
UNCOV
1197
                                String privilegeName = entry.getKey();
×
UNCOV
1198
                                if (!currentPrivilegeNames.contains(privilegeName.toUpperCase())) {
×
UNCOV
1199
                                        Privilege p = new Privilege();
×
UNCOV
1200
                                        p.setPrivilege(privilegeName);
×
1201
                                        p.setDescription(entry.getValue());
×
1202
                                        Context.getUserService().savePrivilege(p);
×
1203
                                }
1204
                        }
×
1205
                }
1206
                catch (Exception e) {
×
1207
                        log.error("Error while setting core privileges", e);
×
1208
                }
1209
                finally {
1210
                        Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_PRIVILEGES);
×
1211
                }
1212

1213
                // setting core global properties
1214
                try {
1215
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
UNCOV
1216
                        Context.addProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES);
×
1217
                        Set<String> currentPropNames = new HashSet<>();
×
1218
                        Map<String, GlobalProperty> propsMissingDescription = new HashMap<>();
×
UNCOV
1219
                        Map<String, GlobalProperty> propsMissingDatatype = new HashMap<>();
×
UNCOV
1220
                        for (GlobalProperty prop : Context.getAdministrationService().getAllGlobalProperties()) {
×
1221
                                currentPropNames.add(prop.getProperty().toUpperCase());
×
UNCOV
1222
                                if (prop.getDescription() == null) {
×
UNCOV
1223
                                        propsMissingDescription.put(prop.getProperty().toUpperCase(), prop);
×
1224
                                }
UNCOV
1225
                                if (prop.getDatatypeClassname() == null) {
×
1226
                                        propsMissingDatatype.put(prop.getProperty().toUpperCase(), prop);
×
1227
                                }
1228
                        }
×
1229

1230
                        for (GlobalProperty coreProp : OpenmrsConstants.CORE_GLOBAL_PROPERTIES()) {
×
1231
                                String corePropName = coreProp.getProperty().toUpperCase();
×
1232
                                // if the prop doesn't exist, save it
1233
                                if (!currentPropNames.contains(corePropName)) {
×
1234
                                        Context.getAdministrationService().saveGlobalProperty(coreProp);
×
UNCOV
1235
                                        currentPropNames.add(corePropName); // add to list in case
×
1236
                                        // of duplicates
1237
                                } else {
1238
                                        // if the prop is missing its description, update it
1239
                                        GlobalProperty propToUpdate = propsMissingDescription.get(corePropName);
×
UNCOV
1240
                                        if (propToUpdate != null) {
×
1241
                                                propToUpdate.setDescription(coreProp.getDescription());
×
1242
                                                Context.getAdministrationService().saveGlobalProperty(propToUpdate);
×
1243
                                        }
1244
                                        // set missing datatypes
1245
                                        propToUpdate = propsMissingDatatype.get(corePropName);
×
1246
                                        if (propToUpdate != null && coreProp.getDatatypeClassname() != null) {
×
UNCOV
1247
                                                propToUpdate.setDatatypeClassname(coreProp.getDatatypeClassname());
×
UNCOV
1248
                                                propToUpdate.setDatatypeConfig(coreProp.getDatatypeConfig());
×
UNCOV
1249
                                                propToUpdate.setPreferredHandlerClassname(coreProp.getPreferredHandlerClassname());
×
1250
                                                propToUpdate.setHandlerConfig(coreProp.getHandlerConfig());
×
1251
                                                Context.getAdministrationService().saveGlobalProperty(propToUpdate);
×
1252
                                        }
1253
                                }
UNCOV
1254
                        }
×
1255
                }
1256
                catch (Exception e) {
×
1257
                        log.error("Error while setting core global properties", e);
×
1258
                }
1259
                finally {
1260
                        Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
1261
                        Context.removeProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES);
×
1262
                }
1263

1264
                // setting default validation rule
1265
                AdministrationService as = Context.getAdministrationService();
×
UNCOV
1266
                Boolean disableValidation = Boolean.valueOf(as.getGlobalProperty(OpenmrsConstants.GP_DISABLE_VALIDATION, "false"));
×
1267
                ValidateUtil.setDisableValidation(disableValidation);
×
1268

UNCOV
1269
                PersonName.setFormat(Context.getAdministrationService().getGlobalProperty(
×
1270
                                OpenmrsConstants.GLOBAL_PROPERTY_LAYOUT_NAME_FORMAT));
1271

1272
                Allergen.setOtherNonCodedConceptUuid(Context.getAdministrationService().getGlobalProperty(
×
1273
                                OpenmrsConstants.GP_ALLERGEN_OTHER_NON_CODED_UUID));
UNCOV
1274
        }
×
1275

1276
        /**
1277
         * Updates the openmrs database to the latest. This is only needed if using the API alone. <br>
1278
         * <br>
1279
         * The typical use-case would be: Try to {@link #startup(String, String, String, Properties)},
1280
         * if that fails, call this method to get the database up to speed.
1281
         *
1282
         * @param userInput (can be null) responses from the user about needed input
1283
         * @throws DatabaseUpdateException if an error occurred while updating
1284
         * @since 1.5
1285
         * @deprecated as of 2.4
1286
         * 
1287
         */
1288
        @Deprecated
1289
        public static void updateDatabase(Map<String, Object> userInput) throws DatabaseUpdateException {
UNCOV
1290
                throw new UnsupportedOperationException("As of 2.4, this method is not longer implemented");
×
1291
        }
1292

1293
        /**
1294
         * Gets the simple date format for the current user's locale. The format will be similar in size
1295
         * to mm/dd/yyyy
1296
         *
1297
         * @return SimpleDateFormat for the user's current locale
1298
         * @see org.openmrs.util.OpenmrsUtil#getDateFormat(Locale)
1299
         * <strong>Should</strong> return a pattern with four y characters in it
1300
         */
1301
        public static SimpleDateFormat getDateFormat() {
1302
                return OpenmrsUtil.getDateFormat(getLocale());
1✔
1303
        }
1304

1305
        /**
1306
         * Gets the simple time format for the current user's locale. The format will be similar to
1307
         * hh:mm a
1308
         *
1309
         * @return SimpleDateFormat for the user's current locale
1310
         * @see org.openmrs.util.OpenmrsUtil#getTimeFormat(Locale)
1311
         * <strong>Should</strong> return a pattern with two h characters in it
1312
         */
1313
        public static SimpleDateFormat getTimeFormat() {
UNCOV
1314
                return OpenmrsUtil.getTimeFormat(getLocale());
×
1315
        }
1316

1317
        /**
1318
         * Gets the simple datetime format for the current user's locale. The format will be similar to
1319
         * mm/dd/yyyy hh:mm a
1320
         *
1321
         * @return SimpleDateFormat for the user's current locale
1322
         * @see org.openmrs.util.OpenmrsUtil#getDateTimeFormat(Locale)
1323
         * <strong>Should</strong> return a pattern with four y characters and two h characters in it
1324
         */
1325
        public static SimpleDateFormat getDateTimeFormat() {
1326
                return OpenmrsUtil.getDateTimeFormat(getLocale());
1✔
1327
        }
1328

1329
        /**
1330
         * @return true/false whether the service context is currently being refreshed
1331
         * @see org.openmrs.api.context.ServiceContext#isRefreshingContext()
1332
         */
1333
        public static boolean isRefreshingContext() {
1334
                return getServiceContext().isRefreshingContext();
1✔
1335
        }
1336

1337
        /**
1338
         * @since 1.5
1339
         * @see ServiceContext#getRegisteredComponents(Class)
1340
         */
1341
        public static <T> List<T> getRegisteredComponents(Class<T> type) {
1342
                return getServiceContext().getRegisteredComponents(type);
1✔
1343
        }
1344

1345
        /**
1346
         * @see ServiceContext#getRegisteredComponent(String, Class)
1347
         * @since 1.9.4
1348
         */
1349
        public static <T> T getRegisteredComponent(String beanName, Class<T> type) throws APIException {
1350
                return getServiceContext().getRegisteredComponent(beanName, type);
1✔
1351
        }
1352

1353
        /**
1354
         * @see ServiceContext#getModuleOpenmrsServices(String)
1355
         * @since 1.9
1356
         */
1357
        public static List<OpenmrsService> getModuleOpenmrsServices(String modulePackage) {
1358
                return getServiceContext().getModuleOpenmrsServices(modulePackage);
1✔
1359
        }
1360

1361
        /**
1362
         * @since 1.9
1363
         * @see ServiceContext#getVisitService()
1364
         */
1365
        public static VisitService getVisitService() {
1366
                return getServiceContext().getVisitService();
1✔
1367
        }
1368

1369
        /**
1370
         * @since 1.9
1371
         * @see ServiceContext#getProviderService()
1372
         */
1373
        public static ProviderService getProviderService() {
1374
                return getServiceContext().getProviderService();
1✔
1375
        }
1376

1377
        /**
1378
         * @since 1.9
1379
         * @see ServiceContext#getDatatypeService()
1380
         */
1381
        public static DatatypeService getDatatypeService() {
1382
                return getServiceContext().getDatatypeService();
1✔
1383
        }
1384

1385
        /**
1386
         * Add or replace a property in the config properties list
1387
         *
1388
         * @param key name of the property
1389
         * @param value value of the property
1390
         * @since 1.9
1391
         */
1392
        public static void addConfigProperty(Object key, Object value) {
UNCOV
1393
                configProperties.put(key, value);
×
UNCOV
1394
        }
×
1395

1396
        /**
1397
         * Remove a property from the list of config properties
1398
         *
1399
         * @param key name of the property
1400
         * @since 1.9
1401
         */
1402
        public static void removeConfigProperty(Object key) {
UNCOV
1403
                configProperties.remove(key);
×
1404
        }
×
1405

1406
        /**
1407
         * Get the config properties that have been added to this OpenMRS instance
1408
         *
1409
         * @return copy of the module properties
1410
         * @since 1.9
1411
         */
1412
        public static Properties getConfigProperties() {
1413
                Properties props = new Properties();
1✔
1414
                props.putAll(configProperties);
1✔
1415
                return props;
1✔
1416
        }
1417

1418
        /**
1419
         * Updates the search index. It is a blocking operation, which may take even a few minutes
1420
         * depending on the index size.
1421
         * <p>
1422
         * There is no need to call this method in normal usage since the index is automatically updated
1423
         * whenever DB transactions are committed.
1424
         * <p>
1425
         * The method is designated to be used in tests, which rollback transactions. Note that if the
1426
         * transaction is rolled back, changes to the index will not be reverted.
1427
         *
1428
         * @since 1.11
1429
         */
1430
        public static void updateSearchIndex() {
UNCOV
1431
                getContextDAO().updateSearchIndex();
×
UNCOV
1432
        }
×
1433

1434
        /**
1435
         * Updates the search index. It is an asynchronous operation.
1436
         * <p>
1437
         * There is no need to call this method in normal usage since the index is automatically updated
1438
         * whenever DB transactions are committed.
1439
         * <p>
1440
         *
1441
         * @return object representing the result of the started asynchronous operation
1442
         */
1443
        public static Future<?> updateSearchIndexAsync() {
UNCOV
1444
                return getContextDAO().updateSearchIndexAsync();
×
1445
        }
1446

1447
        /**
1448
         * It should be used <b>IN TESTS ONLY</b>. See {@link #updateSearchIndex(Class[])} for normal use.
1449
         * <p>
1450
         * Updates the search index for objects of the given type.
1451
         *
1452
         * @see #updateSearchIndex()
1453
         * @see #updateSearchIndex(Class[]) 
1454
         * @param type
1455
         * @since 1.11
1456
         */
1457
        public static void updateSearchIndexForType(Class<?> type) {
1458
                getContextDAO().updateSearchIndexForType(type);
1✔
1459
        }
1✔
1460

1461
        /**
1462
         * Updates the search index for objects of the given types using mass indexer.
1463
         * 
1464
         * @see #updateSearchIndex() 
1465
         * @param types
1466
         * @since 2.8.0
1467
         */
1468
        public static void updateSearchIndex(Class<?>... types) {
UNCOV
1469
                getContextDAO().updateSearchIndex(types);
×
UNCOV
1470
        }
×
1471

1472
        /**
1473
         * Updates the search index for the given object.
1474
         *
1475
         * @see #updateSearchIndex()
1476
         * @param object
1477
         * @since 1.11
1478
         */
1479
        public static void updateSearchIndexForObject(Object object) {
1480
                getContextDAO().updateSearchIndexForObject(object);
×
1481
        }
×
1482

1483
        /**
1484
         * @see org.openmrs.api.context.ServiceContext#setUseSystemClassLoader(boolean)
1485
         * @since 1.10
1486
         */
1487
        public static void setUseSystemClassLoader(boolean useSystemClassLoader) {
1488
                getServiceContext().setUseSystemClassLoader(useSystemClassLoader);
1✔
1489
        }
1✔
1490

1491
        /**
1492
         * @see org.openmrs.api.context.ServiceContext#isUseSystemClassLoader()
1493
         * @since 1.10
1494
         */
1495
        public static boolean isUseSystemClassLoader() {
UNCOV
1496
                return getServiceContext().isUseSystemClassLoader();
×
1497
        }
1498

1499
        /**
1500
         * @return a Connection from the OpenMRS database connection pool
1501
         * @since 2.5.7
1502
         */
1503
        public static Connection getDatabaseConnection() {
UNCOV
1504
                return getContextDAO().getDatabaseConnection();
×
1505
        }
1506

1507
        /**
1508
         * It is used to shorten startup time by e.g. not running Liquibase checks, if versions did not change or 
1509
         * re-using expanded jars between restarts. If you want to force a standard startup
1510
         * procedure without optimization, please set the <code>optimized.startup</code> runtime property to <code>false</code>.
1511
         * (<code>true</code> by default) 
1512
         * <p>
1513
         * See <a href="https://issues.openmrs.org/browse/TRUNK-6417">TRUNK-6417</a>
1514
         * 
1515
         * @return <code>true</code> (default) or <code>false</code>
1516
         * @since 2.9.0
1517
         */
1518
        public static boolean isOptimizedStartup() {
1519
                return Boolean.parseBoolean(Context.getRuntimeProperties().getProperty("optimized.startup", "true"));
1✔
1520
        }
1521
}
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