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

openmrs / openmrs-core / 20784346756

07 Jan 2026 02:13PM UTC coverage: 63.283%. First build
20784346756

push

github

web-flow
TRUNK-6418 Run liquibase checks and data imports only when version of core or modules changes (#5603)

* TRUNK-6418: Run liquibase checks and data imports only when version of core or modules changes

(cherry picked from commit 4723e71c3)

* TRUNK-6418: Follow up adjustments

---------

Co-authored-by: IamMujuziMoses <mujuzimoses@gmail.com>

49 of 112 new or added lines in 9 files covered. (43.75%)

23080 of 36471 relevant lines covered (63.28%)

0.63 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 org.aopalliance.aop.Advice;
13
import org.apache.commons.lang3.StringUtils;
14
import org.openmrs.Allergen;
15
import org.openmrs.GlobalProperty;
16
import org.openmrs.OpenmrsObject;
17
import org.openmrs.PersonName;
18
import org.openmrs.Privilege;
19
import org.openmrs.Role;
20
import org.openmrs.User;
21
import org.openmrs.api.APIException;
22
import org.openmrs.api.AdministrationService;
23
import org.openmrs.api.CohortService;
24
import org.openmrs.api.ConceptService;
25
import org.openmrs.api.ConditionService;
26
import org.openmrs.api.DatatypeService;
27
import org.openmrs.api.DiagnosisService;
28
import org.openmrs.api.EncounterService;
29
import org.openmrs.api.FormService;
30
import org.openmrs.api.LocationService;
31
import org.openmrs.api.MedicationDispenseService;
32
import org.openmrs.api.ObsService;
33
import org.openmrs.api.OpenmrsService;
34
import org.openmrs.api.OrderService;
35
import org.openmrs.api.OrderSetService;
36
import org.openmrs.api.PatientService;
37
import org.openmrs.api.PersonService;
38
import org.openmrs.api.ProgramWorkflowService;
39
import org.openmrs.api.ProviderService;
40
import org.openmrs.api.SerializationService;
41
import org.openmrs.api.UserService;
42
import org.openmrs.api.VisitService;
43
import org.openmrs.api.db.ContextDAO;
44
import org.openmrs.hl7.HL7Service;
45
import org.openmrs.logic.LogicService;
46
import org.openmrs.messagesource.MessageSourceService;
47
import org.openmrs.module.ModuleMustStartException;
48
import org.openmrs.module.ModuleUtil;
49
import org.openmrs.notification.AlertService;
50
import org.openmrs.notification.MessageException;
51
import org.openmrs.notification.MessagePreparator;
52
import org.openmrs.notification.MessageSender;
53
import org.openmrs.notification.MessageService;
54
import org.openmrs.notification.mail.MailMessageSender;
55
import org.openmrs.notification.mail.velocity.VelocityMessagePreparator;
56
import org.openmrs.scheduler.SchedulerService;
57
import org.openmrs.scheduler.SchedulerUtil;
58
import org.openmrs.util.ConfigUtil;
59
import org.openmrs.util.DatabaseUpdateException;
60
import org.openmrs.util.DatabaseUpdater;
61
import org.openmrs.util.InputRequiredException;
62
import org.openmrs.util.LocaleUtility;
63
import org.openmrs.util.OpenmrsClassLoader;
64
import org.openmrs.util.OpenmrsConstants;
65
import org.openmrs.util.OpenmrsUtil;
66
import org.openmrs.util.PrivilegeConstants;
67
import org.openmrs.validator.ValidateUtil;
68
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
70
import org.springframework.aop.Advisor;
71
import org.springframework.beans.BeansException;
72
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
73
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
74

75
import javax.mail.Authenticator;
76
import javax.mail.PasswordAuthentication;
77
import javax.mail.Session;
78
import java.sql.Connection;
79
import java.text.SimpleDateFormat;
80
import java.util.Arrays;
81
import java.util.HashMap;
82
import java.util.HashSet;
83
import java.util.List;
84
import java.util.Locale;
85
import java.util.Map;
86
import java.util.Properties;
87
import java.util.Set;
88
import java.util.concurrent.Future;
89

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

138

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

142
        private static Session mailSession;
143

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

148
        private static volatile ServiceContext serviceContext;
149

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

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

154
        private static AuthenticationScheme authenticationScheme;
155

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

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

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

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

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

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

194
                authenticationScheme = new UsernamePasswordAuthenticationScheme();
1✔
195

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

697
        /**
698
         * logs out the "active" (authenticated) user within context
699
         *
700
         * @see #authenticate
701
         * <strong>Should</strong> not fail if session hasn't been opened yet
702
         */
703
        public static void logout() {
704
                if (!isSessionOpen()) {
1✔
705
                        return; // fail early if there isn't even a session open
1✔
706
                }
707
                log.debug("Logging out : {}", getAuthenticatedUser());
1✔
708

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1066
                startup(properties);
×
1067

1068
                // start the scheduled tasks
1069
                SchedulerUtil.startup(properties);
×
1070

1071
                closeSession();
×
1072
        }
×
1073

1074
        /**
1075
         * Stops the OpenMRS System Should be called after all activity has ended and application is
1076
         * closing
1077
         */
1078
        public static void shutdown() {
1079
                log.debug("Shutting down the scheduler");
×
1080
                try {
1081
                        // Needs to be shutdown before Hibernate
1082
                        SchedulerUtil.shutdown();
×
1083
                }
1084
                catch (Exception e) {
×
1085
                        log.warn("Error while shutting down scheduler service", e);
×
1086
                }
×
1087

1088
                log.debug("Shutting down the modules");
×
1089
                try {
1090
                        ModuleUtil.shutdown();
×
1091
                }
1092
                catch (Exception e) {
×
1093
                        log.warn("Error while shutting down module system", e);
×
1094
                }
×
1095

1096
                log.debug("Shutting down the context");
×
1097
                try {
1098
                        ContextDAO dao = null;
×
1099
                        try {
1100
                                dao = getContextDAO();
×
1101
                        }
1102
                        catch (APIException e) {
×
1103
                                // pass
1104
                        }
×
1105
                        if (dao != null) {
×
1106
                                dao.shutdown();
×
1107
                        }
1108
                }
1109
                catch (Exception e) {
×
1110
                        log.warn("Error while shutting down context dao", e);
×
1111
                }
×
1112
        }
×
1113

1114
        /**
1115
         * Used for getting services not in the previous get*Service() calls
1116
         *
1117
         * @param cls The Class of the service to get
1118
         * @return The requested Service
1119
         * <strong>Should</strong> return the same object when called multiple times for the same class
1120
         */
1121
        public static <T> T getService(Class<? extends T> cls) {
1122
                return getServiceContext().getService(cls);
1✔
1123
        }
1124

1125
        /**
1126
         * Adds an AOP advisor around the given Class <code>cls</code>
1127
         * <p>
1128
         * Advisors can wrap around a method and effect the method before or after
1129
         *
1130
         * @param cls
1131
         * @param advisor
1132
         */
1133
        public static void addAdvisor(Class cls, Advisor advisor) {
1134
                getServiceContext().addAdvisor(cls, advisor);
×
1135
        }
×
1136

1137
        /**
1138
         * Adds an AOP advice object around the given Class <code>cls</code>
1139
         * <p>
1140
         * Advice comes in the form of before or afterReturning methods
1141
         *
1142
         * @param cls
1143
         * @param advice
1144
         */
1145
        public static void addAdvice(Class cls, Advice advice) {
1146
                getServiceContext().addAdvice(cls, advice);
×
1147
        }
×
1148

1149
        /**
1150
         * Removes the given AOP advisor from Class <code>cls</code>
1151
         *
1152
         * @param cls
1153
         * @param advisor
1154
         */
1155
        public static void removeAdvisor(Class cls, Advisor advisor) {
1156
                getServiceContext().removeAdvisor(cls, advisor);
×
1157
        }
×
1158

1159
        /**
1160
         * Removes the given AOP advice object from Class <code>cls</code>
1161
         *
1162
         * @param cls
1163
         * @param advice
1164
         */
1165
        public static void removeAdvice(Class cls, Advice advice) {
1166
                getServiceContext().removeAdvice(cls, advice);
×
1167
        }
×
1168

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

1199
                // setting core privileges
1200
                try {
1201
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_PRIVILEGES);
×
1202
                        Set<String> currentPrivilegeNames = new HashSet<>();
×
1203
                        for (Privilege privilege : Context.getUserService().getAllPrivileges()) {
×
1204
                                currentPrivilegeNames.add(privilege.getPrivilege().toUpperCase());
×
1205
                        }
×
1206
                        Map<String, String> map = OpenmrsUtil.getCorePrivileges();
×
1207
                        for (Map.Entry<String, String> entry : map.entrySet()) {
×
1208
                                String privilegeName = entry.getKey();
×
1209
                                if (!currentPrivilegeNames.contains(privilegeName.toUpperCase())) {
×
1210
                                        Privilege p = new Privilege();
×
1211
                                        p.setPrivilege(privilegeName);
×
1212
                                        p.setDescription(entry.getValue());
×
1213
                                        Context.getUserService().savePrivilege(p);
×
1214
                                }
1215
                        }
×
1216
                }
1217
                catch (Exception e) {
×
1218
                        log.error("Error while setting core privileges", e);
×
1219
                }
1220
                finally {
1221
                        Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_PRIVILEGES);
×
1222
                }
1223

1224
                // setting core global properties
1225
                try {
1226
                        Context.addProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
1227
                        Context.addProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES);
×
1228
                        Set<String> currentPropNames = new HashSet<>();
×
1229
                        Map<String, GlobalProperty> propsMissingDescription = new HashMap<>();
×
1230
                        Map<String, GlobalProperty> propsMissingDatatype = new HashMap<>();
×
1231
                        for (GlobalProperty prop : Context.getAdministrationService().getAllGlobalProperties()) {
×
1232
                                currentPropNames.add(prop.getProperty().toUpperCase());
×
1233
                                if (prop.getDescription() == null) {
×
1234
                                        propsMissingDescription.put(prop.getProperty().toUpperCase(), prop);
×
1235
                                }
1236
                                if (prop.getDatatypeClassname() == null) {
×
1237
                                        propsMissingDatatype.put(prop.getProperty().toUpperCase(), prop);
×
1238
                                }
1239
                        }
×
1240

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

1275
                // setting default validation rule
1276
                AdministrationService as = Context.getAdministrationService();
×
1277
                Boolean disableValidation = Boolean.valueOf(as.getGlobalProperty(OpenmrsConstants.GP_DISABLE_VALIDATION, "false"));
×
1278
                ValidateUtil.setDisableValidation(disableValidation);
×
1279

1280
                PersonName.setFormat(Context.getAdministrationService().getGlobalProperty(
×
1281
                                OpenmrsConstants.GLOBAL_PROPERTY_LAYOUT_NAME_FORMAT));
1282

1283
                Allergen.setOtherNonCodedConceptUuid(Context.getAdministrationService().getGlobalProperty(
×
1284
                                OpenmrsConstants.GP_ALLERGEN_OTHER_NON_CODED_UUID));
1285
        }
×
1286

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

1304
        /**
1305
         * Gets the simple date format for the current user's locale. The format will be similar in size
1306
         * to mm/dd/yyyy
1307
         *
1308
         * @return SimpleDateFormat for the user's current locale
1309
         * @see org.openmrs.util.OpenmrsUtil#getDateFormat(Locale)
1310
         * <strong>Should</strong> return a pattern with four y characters in it
1311
         */
1312
        public static SimpleDateFormat getDateFormat() {
1313
                return OpenmrsUtil.getDateFormat(getLocale());
1✔
1314
        }
1315

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

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

1340
        /**
1341
         * @return true/false whether the service context is currently being refreshed
1342
         * @see org.openmrs.api.context.ServiceContext#isRefreshingContext()
1343
         */
1344
        public static boolean isRefreshingContext() {
1345
                return getServiceContext().isRefreshingContext();
1✔
1346
        }
1347

1348
        /**
1349
         * @since 1.5
1350
         * @see ServiceContext#getRegisteredComponents(Class)
1351
         */
1352
        public static <T> List<T> getRegisteredComponents(Class<T> type) {
1353
                return getServiceContext().getRegisteredComponents(type);
1✔
1354
        }
1355

1356
        /**
1357
         * @see ServiceContext#getRegisteredComponent(String, Class)
1358
         * @since 1.9.4
1359
         */
1360
        public static <T> T getRegisteredComponent(String beanName, Class<T> type) throws APIException {
1361
                return getServiceContext().getRegisteredComponent(beanName, type);
1✔
1362
        }
1363

1364
        /**
1365
         * @see ServiceContext#getModuleOpenmrsServices(String)
1366
         * @since 1.9
1367
         */
1368
        public static List<OpenmrsService> getModuleOpenmrsServices(String modulePackage) {
1369
                return getServiceContext().getModuleOpenmrsServices(modulePackage);
1✔
1370
        }
1371

1372
        /**
1373
         * @since 1.9
1374
         * @see ServiceContext#getVisitService()
1375
         */
1376
        public static VisitService getVisitService() {
1377
                return getServiceContext().getVisitService();
1✔
1378
        }
1379

1380
        /**
1381
         * @since 1.9
1382
         * @see ServiceContext#getProviderService()
1383
         */
1384
        public static ProviderService getProviderService() {
1385
                return getServiceContext().getProviderService();
1✔
1386
        }
1387

1388
        /**
1389
         * @since 1.9
1390
         * @see ServiceContext#getDatatypeService()
1391
         */
1392
        public static DatatypeService getDatatypeService() {
1393
                return getServiceContext().getDatatypeService();
1✔
1394
        }
1395

1396
        /**
1397
         * Add or replace a property in the config properties list
1398
         *
1399
         * @param key name of the property
1400
         * @param value value of the property
1401
         * @since 1.9
1402
         */
1403
        public static void addConfigProperty(Object key, Object value) {
1404
                configProperties.put(key, value);
×
1405
        }
×
1406

1407
        /**
1408
         * Remove a property from the list of config properties
1409
         *
1410
         * @param key name of the property
1411
         * @since 1.9
1412
         */
1413
        public static void removeConfigProperty(Object key) {
1414
                configProperties.remove(key);
×
1415
        }
×
1416

1417
        /**
1418
         * Get the config properties that have been added to this OpenMRS instance
1419
         *
1420
         * @return copy of the module properties
1421
         * @since 1.9
1422
         */
1423
        public static Properties getConfigProperties() {
1424
                Properties props = new Properties();
1✔
1425
                props.putAll(configProperties);
1✔
1426
                return props;
1✔
1427
        }
1428

1429
        /**
1430
         * Updates the search index. It is a blocking operation, which may take even a few minutes
1431
         * depending on the index size.
1432
         * <p>
1433
         * There is no need to call this method in normal usage since the index is automatically updated
1434
         * whenever DB transactions are committed.
1435
         * <p>
1436
         * The method is designated to be used in tests, which rollback transactions. Note that if the
1437
         * transaction is rolled back, changes to the index will not be reverted.
1438
         *
1439
         * @since 1.11
1440
         */
1441
        public static void updateSearchIndex() {
1442
                getContextDAO().updateSearchIndex();
×
1443
        }
×
1444

1445
        /**
1446
         * Updates the search index. It is an asynchronous operation.
1447
         * <p>
1448
         * There is no need to call this method in normal usage since the index is automatically updated
1449
         * whenever DB transactions are committed.
1450
         * <p>
1451
         *
1452
         * @return object representing the result of the started asynchronous operation
1453
         */
1454
        public static Future<?> updateSearchIndexAsync() {
1455
                return getContextDAO().updateSearchIndexAsync();
×
1456
        }
1457

1458
        /**
1459
         * It should be used <b>IN TESTS ONLY</b>. See {@link #updateSearchIndex(Class[])} for normal use.
1460
         * <p>
1461
         * Updates the search index for objects of the given type.
1462
         *
1463
         * @see #updateSearchIndex()
1464
         * @see #updateSearchIndex(Class[]) 
1465
         * @param type
1466
         * @since 1.11
1467
         */
1468
        public static void updateSearchIndexForType(Class<?> type) {
1469
                getContextDAO().updateSearchIndexForType(type);
1✔
1470
        }
1✔
1471

1472
        /**
1473
         * Updates the search index for objects of the given types using mass indexer.
1474
         * 
1475
         * @see #updateSearchIndex() 
1476
         * @param types
1477
         * @since 2.8.0
1478
         */
1479
        public static void updateSearchIndex(Class<?>... types) {
1480
                getContextDAO().updateSearchIndex(types);
×
1481
        }
×
1482

1483
        /**
1484
         * Updates the search index for the given object.
1485
         *
1486
         * @see #updateSearchIndex()
1487
         * @param object
1488
         * @since 1.11
1489
         */
1490
        public static void updateSearchIndexForObject(Object object) {
1491
                getContextDAO().updateSearchIndexForObject(object);
×
1492
        }
×
1493

1494
        /**
1495
         * @see org.openmrs.api.context.ServiceContext#setUseSystemClassLoader(boolean)
1496
         * @since 1.10
1497
         */
1498
        public static void setUseSystemClassLoader(boolean useSystemClassLoader) {
1499
                getServiceContext().setUseSystemClassLoader(useSystemClassLoader);
1✔
1500
        }
1✔
1501

1502
        /**
1503
         * @see org.openmrs.api.context.ServiceContext#isUseSystemClassLoader()
1504
         * @since 1.10
1505
         */
1506
        public static boolean isUseSystemClassLoader() {
1507
                return getServiceContext().isUseSystemClassLoader();
×
1508
        }
1509

1510
        /**
1511
         * @return a Connection from the OpenMRS database connection pool
1512
         * @since 2.5.7
1513
         */
1514
        public static Connection getDatabaseConnection() {
1515
                return getContextDAO().getDatabaseConnection();
×
1516
        }
1517
}
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