• 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

65.06
/api/src/main/java/org/openmrs/api/impl/AdministrationServiceImpl.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.impl;
11

12
import java.io.UnsupportedEncodingException;
13
import java.net.InetAddress;
14
import java.net.UnknownHostException;
15
import java.text.SimpleDateFormat;
16
import java.util.ArrayList;
17
import java.util.Arrays;
18
import java.util.Calendar;
19
import java.util.Collection;
20
import java.util.HashMap;
21
import java.util.HashSet;
22
import java.util.Iterator;
23
import java.util.LinkedHashMap;
24
import java.util.LinkedHashSet;
25
import java.util.List;
26
import java.util.Locale;
27
import java.util.Map;
28
import java.util.Objects;
29
import java.util.Properties;
30
import java.util.Set;
31
import java.util.SortedMap;
32
import java.util.TreeMap;
33

34
import org.apache.commons.lang3.StringUtils;
35
import org.openmrs.ConceptSource;
36
import org.openmrs.GlobalProperty;
37
import org.openmrs.ImplementationId;
38
import org.openmrs.OpenmrsData;
39
import org.openmrs.OpenmrsMetadata;
40
import org.openmrs.OpenmrsObject;
41
import org.openmrs.Privilege;
42
import org.openmrs.User;
43
import org.openmrs.api.APIException;
44
import org.openmrs.api.AdministrationService;
45
import org.openmrs.api.EventListeners;
46
import org.openmrs.api.GlobalPropertyListener;
47
import org.openmrs.api.context.Context;
48
import org.openmrs.api.db.AdministrationDAO;
49
import org.openmrs.customdatatype.CustomDatatype;
50
import org.openmrs.customdatatype.CustomDatatypeUtil;
51
import org.openmrs.customdatatype.CustomValueDescriptor;
52
import org.openmrs.customdatatype.Customizable;
53
import org.openmrs.customdatatype.SingleCustomValue;
54
import org.openmrs.layout.LayoutSupport;
55
import org.openmrs.layout.LayoutTemplate;
56
import org.openmrs.messagesource.PresentationMessage;
57
import org.openmrs.module.Module;
58
import org.openmrs.module.ModuleFactory;
59
import org.openmrs.module.ModuleUtil;
60
import org.openmrs.obs.ComplexData;
61
import org.openmrs.person.PersonMergeLogData;
62
import org.openmrs.util.DatabaseUpdateException;
63
import org.openmrs.util.DatabaseUpdater;
64
import org.openmrs.util.HttpClient;
65
import org.openmrs.util.LocaleUtility;
66
import org.openmrs.util.OpenmrsConstants;
67
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
69
import org.springframework.cache.annotation.CacheEvict;
70
import org.springframework.cache.annotation.Cacheable;
71
import org.springframework.transaction.annotation.Transactional;
72
import org.springframework.validation.Errors;
73

74
/**
75
 * Default implementation of the administration services. This class should not be used on its own.
76
 * The current OpenMRS implementation should be fetched from the Context
77
 * 
78
 * @see org.openmrs.api.AdministrationService
79
 * @see org.openmrs.api.context.Context
80
 */
81
@Transactional
82
public class AdministrationServiceImpl extends BaseOpenmrsService implements AdministrationService, GlobalPropertyListener {
83
        
84
        private static final Logger log = LoggerFactory.getLogger(AdministrationServiceImpl.class);
1✔
85

86
        protected AdministrationDAO dao;
87
        
88
        private EventListeners eventListeners;
89
        
90
        /**
91
         * An always up-to-date collection of the allowed locales.
92
         */
93
        private GlobalLocaleList globalLocaleList;
94
        
95
        private HttpClient implementationIdHttpClient;
96
        
97
        /**
98
         * Default empty constructor
99
         */
100
        public AdministrationServiceImpl() {
1✔
101
        }
1✔
102
        
103
        /**
104
         * @see org.openmrs.api.AdministrationService#setAdministrationDAO(org.openmrs.api.db.AdministrationDAO)
105
         */
106
        @Override
107
        public void setAdministrationDAO(AdministrationDAO dao) {
108
                this.dao = dao;
1✔
109
        }
1✔
110
        
111
        public void setEventListeners(EventListeners eventListeners) {
112
                this.eventListeners = eventListeners;
1✔
113
        }
1✔
114
                
115
        /**
116
         * Static-ish variable used to cache the system variables. This is not static so that every time
117
         * a module is loaded or removed the variable is destroyed (along with the administration
118
         * service) and recreated the next time it is called
119
         */
120
        protected SortedMap<String, String> systemVariables = null;
1✔
121
        
122
        /**
123
         * Set of locales which can be used to present messages in the user interface. Created lazily as
124
         * needed by {@link #getAllowedLocales()}.
125
         */
126
        private Set<Locale> presentationLocales;
127
        
128
        /**
129
         * @see org.openmrs.api.AdministrationService#getSystemVariables()
130
         */
131
        @Override
132
        @Transactional(readOnly = true)
133
        public SortedMap<String, String> getSystemVariables() throws APIException {
134
                if (systemVariables == null) {
1✔
135
                        systemVariables = new TreeMap<>();
1✔
136
                        
137
                        // Added the server's fully qualified domain name
138
                        try {
139
                                systemVariables.put("OPENMRS_HOSTNAME", InetAddress.getLocalHost().getCanonicalHostName());
1✔
140
                        }
141
                        catch (UnknownHostException e) {
×
142
                                systemVariables.put("OPENMRS_HOSTNAME", "Unknown host: " + e.getMessage());
×
143
                        }
1✔
144
                        systemVariables.put("OPENMRS_VERSION", String.valueOf(OpenmrsConstants.OPENMRS_VERSION));
1✔
145
                        systemVariables.put("DATABASE_NAME", OpenmrsConstants.DATABASE_NAME);
1✔
146
                        systemVariables.put("DATABASE_BUSINESS_NAME", OpenmrsConstants.DATABASE_BUSINESS_NAME);
1✔
147
                        systemVariables.put("OBSCURE_PATIENTS", String.valueOf(OpenmrsConstants.OBSCURE_PATIENTS));
1✔
148
                        systemVariables.put("OBSCURE_PATIENTS_FAMILY_NAME", OpenmrsConstants.OBSCURE_PATIENTS_FAMILY_NAME);
1✔
149
                        systemVariables.put("OBSCURE_PATIENTS_GIVEN_NAME", OpenmrsConstants.OBSCURE_PATIENTS_GIVEN_NAME);
1✔
150
                        systemVariables.put("OBSCURE_PATIENTS_MIDDLE_NAME", OpenmrsConstants.OBSCURE_PATIENTS_MIDDLE_NAME);
1✔
151
                        systemVariables.put("MODULE_REPOSITORY_PATH", ModuleUtil.getModuleRepository().getAbsolutePath());
1✔
152
                        systemVariables.put("OPERATING_SYSTEM_KEY", String.valueOf(OpenmrsConstants.OPERATING_SYSTEM_KEY));
1✔
153
                        systemVariables.put("OPERATING_SYSTEM", String.valueOf(OpenmrsConstants.OPERATING_SYSTEM));
1✔
154
                }
155
                
156
                return systemVariables;
1✔
157
        }
158
        
159
        /**
160
         * @see org.openmrs.api.AdministrationService#getGlobalProperty(java.lang.String)
161
         */
162
        @Override
163
        @Transactional(readOnly = true)
164
        public String getGlobalProperty(String propertyName) throws APIException {
165
                // This method should not have any authorization check
166
                if (propertyName == null) {
1✔
167
                        return null;
1✔
168
                }
169
                
170
                GlobalProperty gp = dao.getGlobalPropertyObject(propertyName);
1✔
171
                if (gp != null) {
1✔
172
                        if (canViewGlobalProperty(gp)) {
1✔
173
                                return gp.getPropertyValue();
1✔
174
                        } else {
175
                                throw new APIException("GlobalProperty.error.privilege.required.view", new Object[] {
×
176
                                        gp.getViewPrivilege().getPrivilege(), propertyName });
×
177
                        }
178
                } else {
179
                        return null;
1✔
180
                }
181
        }
182
        
183
        private boolean canViewGlobalProperty(GlobalProperty property) {
184
                if (property.getViewPrivilege() == null) {
1✔
185
                        return true;
1✔
186
                }
187
                
188
                return Context.getAuthenticatedUser().hasPrivilege(property.getViewPrivilege().getPrivilege());
1✔
189
        }
190
        
191
        private boolean canDeleteGlobalProperty(GlobalProperty property) {
192
                if (property.getDeletePrivilege() == null) {
1✔
193
                        return true;
1✔
194
                }
195
                
196
                return Context.getAuthenticatedUser().hasPrivilege(property.getDeletePrivilege().getPrivilege());
1✔
197
        }
198
        
199
        private boolean canEditGlobalProperty(GlobalProperty property) {
200
                if (property.getEditPrivilege() == null) {
1✔
201
                        return true;
1✔
202
                }
203
                
204
                return Context.getAuthenticatedUser().hasPrivilege(property.getEditPrivilege().getPrivilege());
1✔
205
        }
206
        
207
        private List<GlobalProperty> filterGlobalPropertiesByViewPrivilege(List<GlobalProperty> properties) {
208
                if (properties != null) {
1✔
209
                        for (Iterator<GlobalProperty> iterator = properties.iterator(); iterator.hasNext();) {
1✔
210
                                GlobalProperty property = iterator.next();
1✔
211
                                Privilege vp = property.getViewPrivilege();
1✔
212
                                if (vp != null && !Context.getAuthenticatedUser().hasPrivilege(vp.getPrivilege())) {
1✔
213
                                        iterator.remove();
1✔
214
                                }
215
                        }
1✔
216
                }
217
                return properties;
1✔
218
        }
219
        
220
        /**
221
         * @see org.openmrs.api.AdministrationService#getGlobalProperty(java.lang.String,
222
         *      java.lang.String)
223
         */
224
        @Override
225
        @Transactional(readOnly = true)
226
        public String getGlobalProperty(String propertyName, String defaultValue) throws APIException {
227
                String s = Context.getAdministrationService().getGlobalProperty(propertyName);
1✔
228
                if (s == null) {
1✔
229
                        return defaultValue;
1✔
230
                }
231
                return s;
1✔
232
        }
233
        
234
        /**
235
         * @see org.openmrs.api.AdministrationService#getGlobalPropertyObject(java.lang.String)
236
         */
237
        @Override
238
        @Transactional(readOnly = true)
239
        public GlobalProperty getGlobalPropertyObject(String propertyName) {
240
                GlobalProperty gp = dao.getGlobalPropertyObject(propertyName);
1✔
241
                if (gp != null) {
1✔
242
                        if (canViewGlobalProperty(gp)) {
1✔
243
                                return gp;
1✔
244
                        } else {
245
                                throw new APIException("GlobalProperty.error.privilege.required.view", new Object[] {
×
246
                                        gp.getViewPrivilege().getPrivilege(), propertyName });
×
247
                        }
248
                } else {
249
                        return null;
1✔
250
                }
251
        }
252
        
253
        /**
254
         * @see org.openmrs.api.AdministrationService#setGlobalProperty(java.lang.String,
255
         *      java.lang.String)
256
         */
257
        @Override
258
        public void setGlobalProperty(String propertyName, String propertyValue) throws APIException {
259
                GlobalProperty gp = Context.getAdministrationService().getGlobalPropertyObject(propertyName);
1✔
260
                if (gp == null) {
1✔
261
                        gp = new GlobalProperty();
1✔
262
                        gp.setProperty(propertyName);
1✔
263
                }
264
                gp.setPropertyValue(propertyValue);
1✔
265
                Context.getAdministrationService().saveGlobalProperty(gp);
1✔
266
        }
1✔
267
        
268
        /**
269
         * @see org.openmrs.api.AdministrationService#updateGlobalProperty(java.lang.String,
270
         *      java.lang.String)
271
         */
272
        @Override
273
        public void updateGlobalProperty(String propertyName, String propertyValue) throws IllegalStateException {
274
                GlobalProperty gp = Context.getAdministrationService().getGlobalPropertyObject(propertyName);
1✔
275
                if (gp == null) {
1✔
276
                        throw new IllegalStateException("Global property with the given propertyName does not exist" + propertyName);
1✔
277
                }
278
                
279
                if (!canEditGlobalProperty(gp)) {
1✔
280
                        throw new APIException("GlobalProperty.error.privilege.required.edit", new Object[] {
×
281
                                gp.getEditPrivilege().getPrivilege(), propertyName });
×
282
                }
283
                
284
                gp.setPropertyValue(propertyValue);
1✔
285
                dao.saveGlobalProperty(gp);
1✔
286
        }
1✔
287
        
288
        /**
289
         * @see org.openmrs.api.AdministrationService#getAllGlobalProperties()
290
         */
291
        @Override
292
        @Transactional(readOnly = true)
293
        public List<GlobalProperty> getAllGlobalProperties() throws APIException {
294
                return filterGlobalPropertiesByViewPrivilege(dao.getAllGlobalProperties());
1✔
295
        }
296
        
297
        /**
298
         * @see org.openmrs.api.AdministrationService#getGlobalPropertiesByPrefix(java.lang.String)
299
         */
300
        @Override
301
        @Transactional(readOnly = true)
302
        public List<GlobalProperty> getGlobalPropertiesByPrefix(String prefix) {
303
                return filterGlobalPropertiesByViewPrivilege(dao.getGlobalPropertiesByPrefix(prefix));
1✔
304
        }
305
        
306
        /**
307
         * @see org.openmrs.api.AdministrationService#getGlobalPropertiesBySuffix(java.lang.String)
308
         */
309
        @Override
310
        @Transactional(readOnly = true)
311
        public List<GlobalProperty> getGlobalPropertiesBySuffix(String suffix) {
312
                return filterGlobalPropertiesByViewPrivilege(dao.getGlobalPropertiesBySuffix(suffix));
1✔
313
        }
314
        
315
        /**
316
         * @see org.openmrs.api.AdministrationService#purgeGlobalProperty(org.openmrs.GlobalProperty)
317
         */
318
        @Override
319
        public void purgeGlobalProperty(GlobalProperty globalProperty) throws APIException {
320
                if (!canDeleteGlobalProperty(globalProperty)) {
1✔
321
                        throw new APIException("GlobalProperty.error.privilege.required.purge", new Object[] {
1✔
322
                                globalProperty.getDeletePrivilege().getPrivilege(), globalProperty.getProperty() });
1✔
323
                }
324
                
325
                notifyGlobalPropertyDelete(globalProperty.getProperty());
1✔
326
                dao.deleteGlobalProperty(globalProperty);
1✔
327
        }
1✔
328
        
329
        /**
330
         * @see org.openmrs.api.AdministrationService#saveGlobalProperties(java.util.List)
331
         */
332
        @Override
333
        @CacheEvict(value = "userSearchLocales", allEntries = true)
334
        public List<GlobalProperty> saveGlobalProperties(List<GlobalProperty> props) throws APIException {
335
                log.debug("saving a list of global properties");
1✔
336
                
337
                // add all of the new properties
338
                for (GlobalProperty prop : props) {
1✔
339
                        if (prop.getProperty() != null && prop.getProperty().length() > 0) {
1✔
340
                                Context.getAdministrationService().saveGlobalProperty(prop);
1✔
341
                        }
342
                }
1✔
343
                
344
                return props;
1✔
345
        }
346
        
347
        /**
348
         * @see org.openmrs.api.AdministrationService#saveGlobalProperty(org.openmrs.GlobalProperty)
349
         */
350
        @Override
351
        @CacheEvict(value = "userSearchLocales", allEntries = true)
352
        public GlobalProperty saveGlobalProperty(GlobalProperty gp) throws APIException {
353

354
                if (!canEditGlobalProperty(gp)) {
1✔
355
                        throw new APIException("GlobalProperty.error.privilege.required.edit", new Object[] {
1✔
356
                                gp.getEditPrivilege().getPrivilege(), gp.getProperty() });
1✔
357
                }
358
                
359
                // only try to save it if the global property has a key
360
                if (gp.getProperty() != null && gp.getProperty().length() > 0) {
1✔
361
                        if (gp.getProperty().equals(OpenmrsConstants.GLOBAL_PROPERTY_LOCALE_ALLOWED_LIST)) {
1✔
362
                                if (gp.getPropertyValue() != null) {
1✔
363
                                        List<Locale> localeList = new ArrayList<>();
1✔
364
                                        
365
                                        for (String localeString : gp.getPropertyValue().split(",")) {
1✔
366
                                                localeList.add(LocaleUtility.fromSpecification(localeString.trim()));
1✔
367
                                        }
368
                                        if (!localeList.contains(LocaleUtility.getDefaultLocale())) {
1✔
369
                                                gp.setPropertyValue(StringUtils.join(getAllowedLocales(), ", "));
1✔
370
                                                throw new APIException(Context.getMessageSourceService().getMessage(
1✔
371
                                                    "general.locale.localeListNotIncludingDefaultLocale",
372
                                                    new Object[] { LocaleUtility.getDefaultLocale() }, null));
1✔
373
                                        }
374
                                }
1✔
375
                        } else if (gp.getProperty().equals(OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_LOCALE)
1✔
376
                                                && gp.getPropertyValue() != null) {
1✔
377
                        
378
                                        List<Locale> localeList = getAllowedLocales();
1✔
379
                                        
380
                                        if (!localeList.contains(LocaleUtility.fromSpecification(gp.getPropertyValue().trim()))) {
1✔
381
                                                String value = gp.getPropertyValue();
1✔
382
                                                gp.setPropertyValue(LocaleUtility.getDefaultLocale().toString());
1✔
383
                                                throw new APIException((Context.getMessageSourceService().getMessage(
1✔
384
                                                    "general.locale.defaultNotInAllowedLocalesList", new Object[] { value }, null)));
385
                                        }
386
                        }
387
                        
388
                        CustomDatatypeUtil.saveIfDirty(gp);
1✔
389
                        dao.saveGlobalProperty(gp);
1✔
390
                        notifyGlobalPropertyChange(gp);
1✔
391
                        return gp;
1✔
392
                }
393
                
394
                return gp;
×
395
        }
396
        
397
        /**
398
         * @see org.openmrs.api.AdministrationService#executeSQL(java.lang.String, boolean)
399
         */
400
        @Override
401
        public List<List<Object>> executeSQL(String sql, boolean selectOnly) throws APIException {
402
                if (sql == null || "".equals(sql.trim())) {
1✔
403
                        return null;
1✔
404
                }
405
                
406
                return dao.executeSQL(sql, selectOnly);
1✔
407
        }
408
        
409
        /**
410
         * @see org.openmrs.api.AdministrationService#addGlobalPropertyListener(GlobalPropertyListener)
411
         */
412
        @Override
413
        public void addGlobalPropertyListener(GlobalPropertyListener listener) {
414
                eventListeners.getGlobalPropertyListeners().add(listener);
1✔
415
        }
1✔
416
        
417
        /**
418
         * @see org.openmrs.api.AdministrationService#removeGlobalPropertyListener(GlobalPropertyListener)
419
         */
420
        @Override
421
        public void removeGlobalPropertyListener(GlobalPropertyListener listener) {
422
                eventListeners.getGlobalPropertyListeners().remove(listener);
1✔
423
        }
1✔
424
        
425
        /**
426
         * Calls global property listeners registered for this create/change
427
         * 
428
         * @param gp
429
         */
430
        private void notifyGlobalPropertyChange(GlobalProperty gp) {
431
                for (GlobalPropertyListener listener : eventListeners.getGlobalPropertyListeners()) {
1✔
432
                        if (listener.supportsPropertyName(gp.getProperty())) {
1✔
433
                                listener.globalPropertyChanged(gp);
1✔
434
                        }
435
                }
1✔
436
        }
1✔
437
        
438
        /**
439
         * Calls global property listeners registered for this delete
440
         * 
441
         * @param propertyName
442
         */
443
        private void notifyGlobalPropertyDelete(String propertyName) {
444
                for (GlobalPropertyListener listener : eventListeners.getGlobalPropertyListeners()) {
1✔
445
                        if (listener.supportsPropertyName(propertyName)) {
1✔
446
                                listener.globalPropertyDeleted(propertyName);
1✔
447
                        }
448
                }
1✔
449
        }
1✔
450
        
451
        /**
452
         * @see org.openmrs.api.AdministrationService#getImplementationId()
453
         */
454
        @Override
455
        @Transactional(readOnly = true)
456
        public ImplementationId getImplementationId() throws APIException {
457
                String property = Context.getAdministrationService().getGlobalProperty(
1✔
458
                    OpenmrsConstants.GLOBAL_PROPERTY_IMPLEMENTATION_ID);
459
                
460
                // fail early if no gp has been defined yet
461
                if (property == null) {
1✔
462
                        return null;
1✔
463
                }
464
                
465
                try {
466
                        return Context.getSerializationService().getDefaultSerializer().deserialize(property, ImplementationId.class);
×
467
                }
468
                catch (Exception e) {
×
469
                        log.debug("Error while getting implementation id", e);
×
470
                }
471
                
472
                return null;
×
473
        }
474
        
475
        /**
476
         * @see org.openmrs.api.AdministrationService#setImplementationId(org.openmrs.ImplementationId)
477
         */
478
        @Override
479
        public void setImplementationId(ImplementationId implementationId) throws APIException {
480
                
481
                if (implementationId == null) {
1✔
482
                        return;
1✔
483
                }
484
                
485
                // check the validity of this implementation id with the server
486
                String description = implementationId.getDescription();
1✔
487
                try {
488
                        // check that source id is valid
489
                        description = checkImplementationIdValidity(implementationId.getImplementationId(), description,
1✔
490
                            implementationId.getPassphrase());
1✔
491
                        
492
                        // save the server's description back to this concept source object
493
                        implementationId.setDescription(description);
×
494
                        
495
                        boolean foundMatchingSource = false;
×
496
                        // loop over the concept sources to make sure one exists for this hl7Code/implementationId
497
                        List<ConceptSource> sources = Context.getConceptService().getAllConceptSources(false);
×
498
                        if (sources != null) {
×
499
                                for (ConceptSource source : sources) {
×
500
                                        if (implementationId.getImplementationId().equals(source.getHl7Code())) {
×
501
                                                foundMatchingSource = true;
×
502
                                        }
503
                                }
×
504
                        }
505
                        
506
                        // if no ConceptSource currently exists with this implementationId, save this implId
507
                        // as a new ConceptSource
508
                        if (!foundMatchingSource) {
×
509
                                ConceptSource newConceptSource = new ConceptSource();
×
510
                                newConceptSource.setName(implementationId.getName());
×
511
                                newConceptSource.setDescription(implementationId.getDescription());
×
512
                                newConceptSource.setHl7Code(implementationId.getImplementationId());
×
513
                                if (Context.getAuthenticatedUser() == null) {
×
514
                                        // (hackish)
515
                                        newConceptSource.setCreator(new User(1)); // fake the user because no one is logged in
×
516
                                }
517
                                Context.getConceptService().saveConceptSource(newConceptSource);
×
518
                        }
519
                        
520
                        // serialize and save the ImplementationId to the global properties table
521
                        String value = Context.getSerializationService().getDefaultSerializer().serialize(implementationId);
×
522
                        Context.getAdministrationService().saveGlobalProperty(
×
523
                            new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_IMPLEMENTATION_ID, value));
524
                }
525
                catch (APIException e) {
1✔
526
                        throw e;
1✔
527
                }
528
                catch (Exception e) {
1✔
529
                        // pass any other exceptions on up the train
530
                        throw new APIException(e);
1✔
531
                }
532
                finally {
1✔
533
                        // save an empty concept source to the database when something fails?
534
                }
1✔
535
        }
×
536
        
537
        /**
538
         * Checks the remote server for this exact implementation id. Returns the description if 1)
539
         * there is no implementation id or 2) there is a implementation id and this passphrase matches
540
         * it. In the case of 1), this implementation id and passphrase are saved to the remote server's
541
         * database
542
         * 
543
         * @param implementationId
544
         * @param description
545
         * @param passphrase
546
         * @return the stored description on the remote server
547
         * @throws APIException
548
         * @throws UnsupportedEncodingException
549
         */
550
        private String checkImplementationIdValidity(String implementationId, String description, String passphrase)
551
                throws APIException {
552
                
553
                if (StringUtils.isEmpty(implementationId)) {
1✔
554
                        throw new APIException("cannot.be.empty", new Object[] { "implementationid" });
1✔
555
                }
556
                if (StringUtils.isEmpty(description)) {
1✔
557
                        throw new APIException("cannot.be.empty", new Object[] { "description" });
×
558
                }
559
                if (StringUtils.isEmpty(passphrase)) {
1✔
560
                        throw new APIException("cannot.be.empty", new Object[] { "passphrase" });
×
561
                }
562
                
563
                // set up the data map to post to the openmrs server
564
                Map<String, String> data = new HashMap<>();
1✔
565
                data.put("implementationId", implementationId);
1✔
566
                data.put("description", description);
1✔
567
                data.put("passphrase", passphrase);
1✔
568
                
569
                String response = implementationIdHttpClient.post(data);
1✔
570
                response = response.trim();
×
571
                
572
                if ("".equals(response)) {
×
573
                        String ms = Context.getMessageSourceService().getMessage("ImplementationId.connectionError",
×
574
                            new String[] { implementationId }, Context.getLocale());
×
575
                        throw new APIException(ms);
×
576
                }
577
                
578
                log.debug("Response: {}", response);
×
579
                
580
                if (response.startsWith("Success")) {
×
581
                        response = response.replace("Success", "");
×
582
                        return response.trim();
×
583
                }
584
                
585
                String ms = Context.getMessageSourceService().getMessage("ImplementationId.invalidIdorPassphrase",
×
586
                    new String[] { description }, Context.getLocale());
×
587
                throw new APIException(ms);
×
588
        }
589
        
590
        /**
591
         * @see org.openmrs.api.AdministrationService#getAllowedLocales()
592
         */
593
        @Override
594
        @Transactional(readOnly = true)
595
        public List<Locale> getAllowedLocales() {
596
                // lazy-load the global locale list and initialize with current global property value
597
                if (globalLocaleList == null) {
1✔
598
                        globalLocaleList = new GlobalLocaleList();
×
599
                        Context.getAdministrationService().addGlobalPropertyListener(globalLocaleList);
×
600
                }
601
                
602
                Set<Locale> allowedLocales = globalLocaleList.getAllowedLocales();
1✔
603
                
604
                // update the GlobalLocaleList.allowedLocales by faking a global property change
605
                if (allowedLocales == null) {
1✔
606
                        // use a default language of "english" if they have cleared this GP for some reason
607
                        String currentPropertyValue = Context.getAdministrationService().getGlobalProperty(
1✔
608
                            OpenmrsConstants.GLOBAL_PROPERTY_LOCALE_ALLOWED_LIST, LocaleUtility.getDefaultLocale().toString());
1✔
609
                        GlobalProperty allowedLocalesProperty = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_LOCALE_ALLOWED_LIST,
1✔
610
                                currentPropertyValue);
611
                        globalLocaleList.globalPropertyChanged(allowedLocalesProperty);
1✔
612
                        allowedLocales = globalLocaleList.getAllowedLocales();
1✔
613
                }
614
                
615
                // allowedLocales is guaranteed to not be null at this point
616
                return new ArrayList<>(allowedLocales);
1✔
617
        }
618
        
619
        /**
620
         * Used by spring to set the GlobalLocaleList on this implementation
621
         * 
622
         * @param gll the GlobalLocaleList object that is registered to the GlobalPropertyListeners as
623
         *            well
624
         */
625
        public void setGlobalLocaleList(GlobalLocaleList gll) {
626
                globalLocaleList = gll;
1✔
627
        }
1✔
628
        
629
        /**
630
         * @see org.openmrs.api.AdministrationService#getPresentationLocales()
631
         */
632
        @Override
633
        @Transactional(readOnly = true)
634
        public Set<Locale> getPresentationLocales() {
635
                if (presentationLocales == null) {
1✔
636
                        presentationLocales = new LinkedHashSet<>();
1✔
637
                        Collection<Locale> messageLocales = Context.getMessageSourceService().getLocales();
1✔
638
                        List<Locale> allowedLocales = getAllowedLocales();
1✔
639
                        
640
                        for (Locale locale : allowedLocales) {
1✔
641
                                // if no country is specified all countries with this language will be added
642
                                if (StringUtils.isEmpty(locale.getCountry())) {
1✔
643
                                        List<Locale> localsWithSameLanguage = new ArrayList<>();
1✔
644
                                        for (Locale possibleLocale : messageLocales) {
1✔
645
                                                if (locale.getLanguage().equals(possibleLocale.getLanguage())
1✔
646
                                                        && !StringUtils.isEmpty(possibleLocale.getCountry())) {
1✔
647
                                                        localsWithSameLanguage.add(possibleLocale);
1✔
648
                                                }
649
                                        }
1✔
650
                                        
651
                                        // if there are country locales we add those only
652
                                        if (!localsWithSameLanguage.isEmpty()) {
1✔
653
                                                presentationLocales.addAll(localsWithSameLanguage);
1✔
654
                                        } else {
655
                                                // if there are no country locales we add possibleLocale which has country as ""
656
                                                // e.g: if 'es' locale has no country based entries es_CL etc. we show default 'es'
657
                                                if (messageLocales.contains(locale)) {
1✔
658
                                                        presentationLocales.add(locale);
1✔
659
                                                }
660
                                        }
661
                                } else {
1✔
662
                                        // if locales list contains exact <language,country> pair add it
663
                                        if (messageLocales.contains(locale)) {
1✔
664
                                                presentationLocales.add(locale);
1✔
665
                                        } else {
666
                                                // if no such entry add possibleLocale with country ""
667
                                                // e.g: we specify es_CL but it is not in list so we add es locale here
668
                                                for (Locale possibleLocale : messageLocales) {
1✔
669
                                                        if (locale.getLanguage().equals(possibleLocale.getLanguage())
1✔
670
                                                                && StringUtils.isEmpty(possibleLocale.getCountry())) {
1✔
671
                                                                presentationLocales.add(possibleLocale);
1✔
672
                                                        }
673
                                                }
1✔
674
                                        }
675
                                }
676
                        }
1✔
677
                }
678
                return presentationLocales;
1✔
679
        }
680
        
681
        /**
682
         * @see org.openmrs.api.GlobalPropertyListener#globalPropertyChanged(org.openmrs.GlobalProperty)
683
         */
684
        @Override
685
        public void globalPropertyChanged(GlobalProperty newValue) {
686
                if (newValue.getProperty().equals(OpenmrsConstants.GLOBAL_PROPERTY_LOCALE_ALLOWED_LIST)) {
1✔
687
                        // reset the calculated locale values
688
                        presentationLocales = null;
1✔
689
                }
690
        }
1✔
691
        
692
        /**
693
         * @see org.openmrs.api.GlobalPropertyListener#globalPropertyDeleted(java.lang.String)
694
         */
695
        @Override
696
        public void globalPropertyDeleted(String propertyName) {
697
                // TODO Auto-generated method stub
698
                
699
        }
1✔
700
        
701
        /**
702
         * @see org.openmrs.api.GlobalPropertyListener#supportsPropertyName(java.lang.String)
703
         */
704
        @Override
705
        public boolean supportsPropertyName(String propertyName) {
706
                return propertyName.equals(OpenmrsConstants.GLOBAL_PROPERTY_LOCALE_ALLOWED_LIST);
1✔
707
        }
708
        
709
        /**
710
         * @see org.openmrs.api.AdministrationService#getGlobalPropertyByUuid(java.lang.String)
711
         */
712
        @Override
713
        @Transactional(readOnly = true)
714
        public GlobalProperty getGlobalPropertyByUuid(String uuid) {
715
                GlobalProperty gp =  dao.getGlobalPropertyByUuid(uuid);
1✔
716
                if (gp == null) {
1✔
717
                        return null;
1✔
718
                } else if (canViewGlobalProperty(gp)) {
1✔
719
                        return gp;
1✔
720
                } else {
721
                        throw new APIException("GlobalProperty.error.privilege.required.view", new Object[] {
×
722
                                gp.getViewPrivilege().getPrivilege(), gp.getProperty() });
×
723
                }
724
        }
725
        
726
        /**
727
         * @see org.openmrs.api.AdministrationService#getGlobalPropertyValue(java.lang.String,
728
         *      java.lang.Object)
729
         */
730
        @Override
731
        @SuppressWarnings("unchecked")
732
        public <T> T getGlobalPropertyValue(String propertyName, T defaultValue) throws APIException {
733
                if (defaultValue == null) {
1✔
734
                        throw new IllegalArgumentException("The defaultValue argument cannot be null");
1✔
735
                }
736
                
737
                String propVal = Context.getAdministrationService().getGlobalProperty(propertyName);
1✔
738
                if (StringUtils.isEmpty(propVal)) {
1✔
739
                        return defaultValue;
1✔
740
                }
741
                
742
                try {
743
                        return (T) defaultValue.getClass().getDeclaredConstructor(String.class).newInstance(propVal);
1✔
744
                }
745
                catch (InstantiationException e) {
×
746
                        throw new APIException("is.not.able.instantiated", new Object[] { defaultValue.getClass().getName(), propVal },
×
747
                                e);
748
                }
749
                catch (NoSuchMethodException e) {
×
750
                        throw new APIException("does.not.have.string.constructor", new Object[] { defaultValue.getClass().getName() }, e);
×
751
                }
752
                catch (Exception e) {
×
753
                        log.error("Unable to turn value '" + propVal + "' into type " + defaultValue.getClass().getName(), e);
×
754
                        return defaultValue;
×
755
                }
756
        }
757
        
758
        /**
759
         * @see org.openmrs.api.AdministrationService#getSystemInformation()
760
         */
761
        @Override
762
        @Transactional(readOnly = true)
763
        public Map<String, Map<String, String>> getSystemInformation() throws APIException {
764
                Map<String, Map<String, String>> systemInfoMap = new LinkedHashMap<>();
×
765
                
766
                systemInfoMap.put("SystemInfo.title.openmrsInformation", new LinkedHashMap<String, String>() {
×
767
                        
768
                        private static final long serialVersionUID = 1L;
769
                        
770
                        {
771
                                put("SystemInfo.OpenMRSInstallation.systemDate", new SimpleDateFormat("yyyy-MM-dd").format(Calendar
×
772
                                        .getInstance().getTime()));
×
773
                                put("SystemInfo.OpenMRSInstallation.systemTime", new SimpleDateFormat("HH:mm:ss").format(Calendar
×
774
                                        .getInstance().getTime()));
×
775
                                put("SystemInfo.OpenMRSInstallation.openmrsVersion", OpenmrsConstants.OPENMRS_VERSION);
×
776
                                try {
777
                                        put("SystemInfo.hostname", InetAddress.getLocalHost().getCanonicalHostName());
×
778
                                }
779
                                catch (UnknownHostException e) {
×
780
                                        put("SystemInfo.hostname", "Unknown host: " + e.getMessage());
×
781
                                }
×
782
                        }
×
783
                });
784
                
785
                systemInfoMap.put("SystemInfo.title.javaRuntimeEnvironmentInformation", new LinkedHashMap<String, String>() {
×
786
                        
787
                        Properties properties = System.getProperties();
×
788
                        
789
                        private static final long serialVersionUID = 1L;
790
                        
791
                        {
792
                                put("SystemInfo.JavaRuntimeEnv.operatingSystem", properties.getProperty("os.name"));
×
793
                                put("SystemInfo.JavaRuntimeEnv.operatingSystemArch", properties.getProperty("os.arch"));
×
794
                                put("SystemInfo.JavaRuntimeEnv.operatingSystemVersion", properties.getProperty("os.version"));
×
795
                                put("SystemInfo.JavaRuntimeEnv.javaVersion", properties.getProperty("java.version"));
×
796
                                put("SystemInfo.JavaRuntimeEnv.javaVendor", properties.getProperty("java.vendor"));
×
797
                                put("SystemInfo.JavaRuntimeEnv.jvmVersion", properties.getProperty("java.vm.version"));
×
798
                                put("SystemInfo.JavaRuntimeEnv.jvmVendor", properties.getProperty("java.vm.vendor"));
×
799
                                put("SystemInfo.JavaRuntimeEnv.javaRuntimeName", properties.getProperty("java.runtime.name"));
×
800
                                put("SystemInfo.JavaRuntimeEnv.javaRuntimeVersion", properties.getProperty("java.runtime.version"));
×
801
                                put("SystemInfo.JavaRuntimeEnv.userName", properties.getProperty("user.name"));
×
802
                                put("SystemInfo.JavaRuntimeEnv.systemLanguage", properties.getProperty("user.language"));
×
803
                                put("SystemInfo.JavaRuntimeEnv.systemTimezone", properties.getProperty("user.timezone"));
×
804
                                put("SystemInfo.JavaRuntimeEnv.fileSystemEncoding", properties.getProperty("sun.jnu.encoding"));
×
805
                                put("SystemInfo.JavaRuntimeEnv.userDirectory", properties.getProperty("user.dir"));
×
806
                                put("SystemInfo.JavaRuntimeEnv.tempDirectory", properties.getProperty("java.io.tmpdir"));
×
807
                        }
×
808
                });
809
                
810
                systemInfoMap.put("SystemInfo.title.memoryInformation", new LinkedHashMap<String, String>() {
×
811
                        
812
                        private static final long serialVersionUID = 1L;
813
                        
814
                        Runtime runtime = Runtime.getRuntime();
×
815
                        
816
                        {
817
                                put("SystemInfo.Memory.totalMemory", convertToMegaBytes(runtime.totalMemory()));
×
818
                                put("SystemInfo.Memory.freeMemory", convertToMegaBytes(runtime.freeMemory()));
×
819
                                put("SystemInfo.Memory.maximumHeapSize", convertToMegaBytes(runtime.maxMemory()));
×
820
                                
821
                        }
×
822
                });
823
                
824
                systemInfoMap.put("SystemInfo.title.dataBaseInformation", new LinkedHashMap<String, String>() {
×
825
                        
826
                        Properties properties = Context.getRuntimeProperties();
×
827
                        
828
                        private static final long serialVersionUID = 1L;
829
                        
830
                        {
831
                                put("SystemInfo.Database.name", OpenmrsConstants.DATABASE_NAME);
×
832
                                put("SystemInfo.Database.connectionURL", properties.getProperty("connection.url"));
×
833
                                put("SystemInfo.Database.userName", properties.getProperty("connection.username"));
×
834
                                put("SystemInfo.Database.driver", properties.getProperty("hibernate.connection.driver_class"));
×
835
                                put("SystemInfo.Database.dialect", properties.getProperty("hibernate.dialect"));
×
836
                                
837
                        }
×
838
                });
839
                
840
                systemInfoMap.put("SystemInfo.title.moduleInformation", new LinkedHashMap<String, String>() {
×
841
                        
842
                        private static final long serialVersionUID = 1L;
843
                        
844
                        {
845
                                put("SystemInfo.Module.repositoryPath", ModuleUtil.getModuleRepository().getAbsolutePath());
×
846
                                Collection<Module> loadedModules = ModuleFactory.getLoadedModules();
×
847
                                for (Module module : loadedModules) {
×
848
                                        String moduleInfo = module.getVersion() + " "
×
849
                                                + (module.isStarted() ? "" : Context.getMessageSourceService().getMessage("Module.notStarted"));
×
850
                                        put(module.getName(), moduleInfo);
×
851
                                }
×
852
                        }
×
853
                });
854
                
855
                return systemInfoMap;
×
856
        }
857
        
858
        /**
859
         * @param bytes to be converted into mega bytes
860
         * @return memory in mega bytes
861
         */
862
        private String convertToMegaBytes(long bytes) {
863
                final int ONE_KILO_BYTE = 1024;
×
864
                return String.valueOf(bytes / ONE_KILO_BYTE / ONE_KILO_BYTE) + " MB";
×
865
        }
866
        
867
        /**
868
         * @see org.openmrs.api.AdministrationService#purgeGlobalProperties(java.util.List)
869
         */
870
        @Override
871
        public void purgeGlobalProperties(List<GlobalProperty> globalProperties) throws APIException {
872
                for (GlobalProperty globalProperty : globalProperties) {
1✔
873
                        Context.getAdministrationService().purgeGlobalProperty(globalProperty);
1✔
874
                }
1✔
875
        }
1✔
876
        
877
        /**
878
         * @see AdministrationService#getMaximumPropertyLength(Class, String)
879
         */
880
        @Override
881
        @Transactional(readOnly = true)
882
        public int getMaximumPropertyLength(Class<? extends OpenmrsObject> aClass, String fieldName) {
883
                return dao.getMaximumPropertyLength(aClass, fieldName);
1✔
884
        }
885
        
886
        /**
887
         * @see org.openmrs.api.AdministrationService#validate(java.lang.Object, Errors)
888
         */
889
        @Override
890
        @Transactional(readOnly = true)
891
        public void validate(Object object, Errors errors) throws APIException {
892
                if (object == null) {
1✔
893
                        throw new APIException("error.null", (Object[]) null);
1✔
894
                }
895

896
                dao.validate(object, errors);
1✔
897
        }
1✔
898

899
        @Override
900
        @Cacheable(value = "userSearchLocales")
901
        public List<Locale> getSearchLocales(Locale currentLocale, User user) throws APIException {
902
                Set<Locale> locales = new LinkedHashSet<>();
1✔
903
                locales.add(currentLocale); //the currently used full locale
1✔
904
                locales.add(new Locale(currentLocale.getLanguage()));
1✔
905

906
                if (user != null) {
1✔
907
                        List<Locale> proficientLocales = user.getProficientLocales();
1✔
908
                        if (proficientLocales != null) {
1✔
909
                                locales.addAll(proficientLocales);
1✔
910
                        }
911
                }
912
                
913
                //limit locales to only allowed locales
914
                List<Locale> allowedLocales = Context.getAdministrationService().getAllowedLocales();
1✔
915
                if (allowedLocales != null) {
1✔
916
                        Set<Locale> retainLocales = new HashSet<>();
1✔
917
                        
918
                        for (Locale allowedLocale : allowedLocales) {
1✔
919
                                retainLocales.add(allowedLocale);
1✔
920
                                retainLocales.add(new Locale(allowedLocale.getLanguage()));
1✔
921
                        }
1✔
922
                        
923
                        locales.retainAll(retainLocales);
1✔
924
                }
925
                
926
                return new ArrayList<>(locales);
1✔
927
        }
928

929
        /**
930
         * @see AdministrationService#getSearchLocales()
931
         */
932
        @Override
933
        @Transactional(readOnly = true)
934
        public List<Locale> getSearchLocales(){
935
                //call it via interface, so cache interceptor is invoked
936
                return Context.getAdministrationService().getSearchLocales(Context.getLocale(), Context.getAuthenticatedUser());
1✔
937
        }
938
        
939
        @Override
940
        public void setImplementationIdHttpClient(HttpClient implementationIdHttpClient) {
941
                this.implementationIdHttpClient = implementationIdHttpClient;
1✔
942
        }
1✔
943
        
944
        /**
945
         * @see org.openmrs.api.AdministrationService#isDatabaseStringComparisonCaseSensitive()
946
         */
947
        @Override
948
        public boolean isDatabaseStringComparisonCaseSensitive() {
949
                return dao.isDatabaseStringComparisonCaseSensitive();
1✔
950
        }
951
        
952
        /**
953
         * @see org.openmrs.api.AdministrationService#updatePostgresSequence()
954
         */
955
        @Override
956
        public void updatePostgresSequence() {
957
                dao.updatePostgresSequence();
×
958
        }
×
959

960
        @Override
961
        public List<String> getSerializerWhitelistTypes() {
962
                List<String> whitelistTypes = new ArrayList<>();
1✔
963
                List<Class<?>> hierarchyTypes = getSerializerDefaultWhitelistHierarchyTypes();
1✔
964
                for (Class<?> hierarchyType: hierarchyTypes) {
1✔
965
                        whitelistTypes.add(GP_SERIALIZER_WHITELIST_HIERARCHY_TYPES_PREFIX + hierarchyType.getName());
1✔
966
                }
1✔
967

968
                List<GlobalProperty> gpTypes = getGlobalPropertiesBySuffix(
1✔
969
                        AdministrationService.GP_SUFFIX_SERIALIZER_WHITELIST_TYPES);
970
                for (GlobalProperty gpType: gpTypes) {
1✔
971
                        String[] types = gpType.getPropertyValue().split(",");
1✔
972
                        for (String type: types) {
1✔
973
                                if(!StringUtils.isBlank(type)) {
1✔
974
                                        whitelistTypes.add(type.trim());
1✔
975
                                }
976
                        }
977
                }
1✔
978

979
                return whitelistTypes;
1✔
980
        }
981
        public static List<Class<?>> getSerializerDefaultWhitelistHierarchyTypes() {
982
                List<Class<?>> types = Arrays.asList(OpenmrsObject.class, OpenmrsMetadata.class, OpenmrsData.class, 
1✔
983
                        CustomDatatype.class, SingleCustomValue.class, CustomValueDescriptor.class, Customizable.class,
984
                        LayoutTemplate.class, LayoutSupport.class, ComplexData.class, PresentationMessage.class,
985
                        PersonMergeLogData.class);
986
                return types;
1✔
987
        }
988
        
989
        /**
990
         * @see org.openmrs.api.AdministrationService#isCoreSetupOnVersionChangeNeeded() 
991
         */
992
        @Override
993
        public boolean isCoreSetupOnVersionChangeNeeded() {
994
                boolean forceSetup = Boolean.parseBoolean(Context.getRuntimeProperties().getProperty("force.setup", "false"));
1✔
995
                if (forceSetup) {
1✔
NEW
996
                        return true;
×
997
                }
998
                
999
                String stored = getStoredCoreVersion();
1✔
1000
                String current = OpenmrsConstants.OPENMRS_VERSION_SHORT;
1✔
1001
                return !Objects.equals(stored, current);
1✔
1002
        }
1003

1004
        /**
1005
         * @see org.openmrs.api.AdministrationService#isModuleSetupOnVersionChangeNeeded(String)
1006
         */
1007
        @Override
1008
        public boolean isModuleSetupOnVersionChangeNeeded(String moduleId) {
1009
                Module module = ModuleFactory.getModuleById(moduleId);
1✔
1010
                if (module == null) {
1✔
NEW
1011
                        log.info("{} module is no longer installed, skipping setup", moduleId);
×
NEW
1012
                        return false;
×
1013
                }
1014
                
1015
                if (isCoreSetupOnVersionChangeNeeded()) {
1✔
1016
                        return true;
1✔
1017
                }
1018
                
NEW
1019
                String stored = getStoredModuleVersion(moduleId);
×
NEW
1020
                String current = module.getVersion();
×
NEW
1021
                if (!Objects.equals(stored, current)) {
×
NEW
1022
                        return true;
×
1023
                } else {
NEW
1024
                        log.info("{} module did not change, skipping setup", moduleId);
×
NEW
1025
                        return false;
×
1026
                }
1027
        }
1028

1029
        /**
1030
         * @see org.openmrs.api.AdministrationService#runCoreSetupOnVersionChange() 
1031
         */
1032
        @Override
1033
        @Transactional
1034
        public void runCoreSetupOnVersionChange() throws DatabaseUpdateException {
NEW
1035
                if (!ModuleFactory.getLoadedModules().isEmpty()) {
×
NEW
1036
                        String prevCoreVersion = getStoredCoreVersion();
×
1037
                        
NEW
1038
                        for (Module module : ModuleFactory.getLoadedModules()) {
×
NEW
1039
                                String prevModuleVersion = getStoredModuleVersion(module.getModuleId());
×
1040
                                
NEW
1041
                                module.getModuleActivator().setupOnVersionChangeBeforeSchemaChanges(prevCoreVersion, prevModuleVersion);
×
NEW
1042
                        }
×
1043
                }
1044
                
1045
                boolean updatesRequired;
1046
                try {
NEW
1047
                        updatesRequired = DatabaseUpdater.updatesRequired();
×
1048
                }
NEW
1049
                catch (Exception e) {
×
NEW
1050
                        throw new DatabaseUpdateException("Unable to check if database updates are required", e);
×
NEW
1051
                }
×
1052

1053
                // this must be the first thing run in case it changes database mappings
NEW
1054
                if (updatesRequired) {
×
NEW
1055
                        if (!DatabaseUpdater.allowAutoUpdate()) {
×
NEW
1056
                                throw new DatabaseUpdateException(
×
1057
                                        "Database updates are required. Call Context.updateDatabase() before .startup() to continue.");
1058
                        }
1059
                }
1060
                
NEW
1061
                DatabaseUpdater.executeChangelog();
×
1062
                
NEW
1063
                storeCoreVersion();
×
NEW
1064
        }
×
1065

1066
        /**
1067
         * @see org.openmrs.api.AdministrationService#runModuleSetupOnVersionChange(Module)
1068
         */
1069
        @Override
1070
        @Transactional
1071
        public void runModuleSetupOnVersionChange(Module module) {
1072
                if (module == null) {
1✔
NEW
1073
                        return;
×
1074
                }
1075

1076
                String moduleId = module.getModuleId();
1✔
1077
                String prevCoreVersion = getStoredCoreVersion();
1✔
1078
                String prevModuleVersion = getStoredModuleVersion(moduleId);
1✔
1079
                
1080
                ModuleFactory.runLiquibaseForModule(module);
1✔
1081
                module.getModuleActivator().setupOnVersionChange(prevCoreVersion, prevModuleVersion);
1✔
1082
                
1083
                storeModuleVersion(moduleId, module.getVersion());
1✔
1084
        }
1✔
1085

1086
        protected String getStoredCoreVersion() {
1087
                return dao.getGlobalProperty("core.version");
1✔
1088
        }
1089

1090
        protected String getStoredModuleVersion(String moduleId) {
1091
                return dao.getGlobalProperty("module." + moduleId + ".version");
1✔
1092
        }
1093

1094
        protected void storeCoreVersion() {
NEW
1095
                String propertyName = "core.version";
×
NEW
1096
                GlobalProperty gp = new GlobalProperty(propertyName, OpenmrsConstants.OPENMRS_VERSION_SHORT, 
×
1097
                        "Saved core version for future restarts");
NEW
1098
                dao.saveGlobalProperty(gp);
×
NEW
1099
        }
×
1100

1101
        protected void storeModuleVersion(String moduleId, String version) {
1102
                String propertyName = "module." + moduleId + ".version";
1✔
1103
                GlobalProperty gp = new GlobalProperty(propertyName, version, "Saved module version for future restarts");
1✔
1104
                dao.saveGlobalProperty(gp);
1✔
1105
        }
1✔
1106
}
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