Skip to content

Commit 294a884

Browse files
committed
TRUNK-6418: Follow up adjustments
1 parent 485c431 commit 294a884

File tree

21 files changed

+291
-208
lines changed

21 files changed

+291
-208
lines changed

api/src/main/java/org/openmrs/api/AdministrationService.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -426,29 +426,33 @@ public interface AdministrationService extends OpenmrsService {
426426
/**
427427
* Checks whether a core setup needs to be run due to a version change.
428428
*
429+
* @since 2.9.0
429430
* @return true if core setup should be executed because of a version change, false otherwise
430431
*/
431-
public boolean isCoreSetupOnVersionChangeNeeded();
432+
boolean isCoreSetupOnVersionChangeNeeded();
432433

433434
/**
434435
* Checks whether a module setup needs to be run due to a version change.
435436
*
437+
* @since 2.9.0
436438
* @param moduleId the identifier of the module to check
437439
* @return true if the module setup should be executed because of a version change, false otherwise
438440
*/
439-
public boolean isModuleSetupOnVersionChangeNeeded(String moduleId);
441+
boolean isModuleSetupOnVersionChangeNeeded(String moduleId);
440442

441443
/**
442444
* Executes the core setup procedures required after a core version change.
443445
*
444-
* @throws DatabaseUpdateException
446+
* @since 2.9.0
447+
* @throws DatabaseUpdateException if the core setup fails
445448
*/
446-
public void runCoreSetupOnVersionChange() throws DatabaseUpdateException;
449+
void runCoreSetupOnVersionChange() throws DatabaseUpdateException;
447450

448451
/**
449452
* Executes the setup procedures required for a module after a module version change.
450453
*
454+
* @since 2.9.0
451455
* @param module the module for which the setup should be executed
452456
*/
453-
public void runModuleSetupOnVersionChange(Module module);
457+
void runModuleSetupOnVersionChange(Module module);
454458
}

api/src/main/java/org/openmrs/api/context/Context.java

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,20 +1009,22 @@ public static synchronized void startup(Properties props) throws DatabaseUpdateE
10091009
// do any context database specific startup
10101010
getContextDAO().startup(props);
10111011

1012-
// find/set/check whether the current database version is compatible
1013-
checkForDatabaseUpdates(props);
1012+
if (getAdministrationService().isCoreSetupOnVersionChangeNeeded()) {
1013+
log.info("Detected core version change. Running core setup hooks and Liquibase.");
1014+
getAdministrationService().runCoreSetupOnVersionChange();
1015+
}
10141016

10151017
// this should be first in the startup routines so that the application
10161018
// data directory can be set from the runtime properties
10171019
OpenmrsUtil.startup(props);
1018-
1020+
10191021
openSession();
10201022
clearSession();
10211023

10221024
// add any privileges/roles that /must/ exist for openmrs to work
10231025
// correctly.
10241026
checkCoreDataset();
1025-
1027+
10261028
getContextDAO().setupSearchIndex();
10271029

10281030
// Loop over each module and startup each with these custom properties
@@ -1282,44 +1284,6 @@ public static void checkCoreDataset() {
12821284
OpenmrsConstants.GP_ALLERGEN_OTHER_NON_CODED_UUID));
12831285
}
12841286

1285-
/**
1286-
* Runs any needed updates on the current database if the user has the allow_auto_update runtime
1287-
* property set to true. If not set to true, then {@link #updateDatabase(Map)} must be called.<br>
1288-
* <br>
1289-
* If an {@link InputRequiredException} is thrown, a call to {@link #updateDatabase(Map)} is
1290-
* required with a mapping from question prompt to user answer.
1291-
*
1292-
* @param props the runtime properties
1293-
* @throws InputRequiredException if the {@link DatabaseUpdater} has determined that updates
1294-
* cannot continue without input from the user
1295-
* @see InputRequiredException#getRequiredInput() InputRequiredException#getRequiredInput() for
1296-
* the required question/datatypes
1297-
*/
1298-
private static void checkForDatabaseUpdates(Properties props) throws DatabaseUpdateException, InputRequiredException {
1299-
boolean updatesRequired;
1300-
try {
1301-
updatesRequired = DatabaseUpdater.updatesRequired();
1302-
}
1303-
catch (Exception e) {
1304-
throw new DatabaseUpdateException("Unable to check if database updates are required", e);
1305-
}
1306-
1307-
// this must be the first thing run in case it changes database mappings
1308-
if (updatesRequired) {
1309-
if (!DatabaseUpdater.allowAutoUpdate()) {
1310-
throw new DatabaseUpdateException(
1311-
"Database updates are required. Call Context.updateDatabase() before .startup() to continue.");
1312-
}
1313-
}
1314-
1315-
if (getAdministrationService().isCoreSetupOnVersionChangeNeeded()) {
1316-
log.info("Detected core version change. Running core setup hooks and Liquibase.");
1317-
getAdministrationService().runCoreSetupOnVersionChange();
1318-
}
1319-
1320-
log.info("Database update check completed.");
1321-
}
1322-
13231287
/**
13241288
* Updates the openmrs database to the latest. This is only needed if using the API alone. <br>
13251289
* <br>

api/src/main/java/org/openmrs/api/db/AdministrationDAO.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ public interface AdministrationDAO {
6060
* @see org.openmrs.api.AdministrationService#saveGlobalProperty(org.openmrs.GlobalProperty)
6161
*/
6262
public GlobalProperty saveGlobalProperty(GlobalProperty gp) throws DAOException;
63+
64+
/**
65+
* Internal method for AdministrationService to overwrite or create a new global property without fetching.
66+
* <p>
67+
* It is to go around an issue with case-sensitive session.get and non-case-sensitive primary key resulting
68+
* in multiple objects in a session with the same primary key, but different casing...
69+
*/
70+
public GlobalProperty saveGlobalProperty(String name, String value, String description) throws DAOException;
6371

6472
/**
6573
* @see org.openmrs.api.db.AdministrationDAO#executeSQL(java.lang.String, boolean)

api/src/main/java/org/openmrs/api/db/hibernate/HibernateAdministrationDAO.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,16 @@ public GlobalProperty getGlobalPropertyObject(String propertyName) {
113113

114114
query.where(condition);
115115

116-
return session.createQuery(query).uniqueResult();
117-
} else {
118-
return session.get(GlobalProperty.class, propertyName);
116+
GlobalProperty gp = session.createQuery(query).uniqueResult();
117+
if (gp != null) {
118+
// GP may be null, but the session may contain an unflushed gp so
119+
// we will do a final check with session.get below. It may happen,
120+
// if flush is set to manual and running in a larger transaction.
121+
return gp;
122+
}
119123
}
124+
125+
return session.get(GlobalProperty.class, propertyName);
120126
}
121127

122128
@Override
@@ -199,11 +205,17 @@ public GlobalProperty saveGlobalProperty(GlobalProperty gp) throws DAOException
199205
sessionFactory.getCurrentSession().update(gpObject);
200206
return gpObject;
201207
} else {
202-
sessionFactory.getCurrentSession().save(gp);
208+
sessionFactory.getCurrentSession().saveOrUpdate(gp);
203209
return gp;
204210
}
205211
}
206-
212+
213+
@Override
214+
public GlobalProperty saveGlobalProperty(String name, String value, String description) throws DAOException {
215+
GlobalProperty gp = new GlobalProperty(name, value, description);
216+
return (GlobalProperty) sessionFactory.getCurrentSession().merge(gp);
217+
}
218+
207219
/**
208220
* @see org.openmrs.api.db.AdministrationDAO#executeSQL(java.lang.String, boolean)
209221
*/

api/src/main/java/org/openmrs/api/impl/AdministrationServiceImpl.java

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
import java.util.List;
2626
import java.util.Locale;
2727
import java.util.Map;
28+
import java.util.Objects;
2829
import java.util.Properties;
2930
import java.util.Set;
3031
import java.util.SortedMap;
3132
import java.util.TreeMap;
3233

3334
import org.apache.commons.lang3.StringUtils;
35+
import org.jgroups.Global;
3436
import org.openmrs.ConceptSource;
3537
import org.openmrs.GlobalProperty;
3638
import org.openmrs.ImplementationId;
@@ -984,47 +986,46 @@ public static List<Class<?>> getSerializerDefaultWhitelistHierarchyTypes() {
984986
PersonMergeLogData.class);
985987
return types;
986988
}
987-
988-
@Override
989-
@SuppressWarnings("unchecked")
990-
public <T> T getRefByUuid(Class<T> type, String uuid) {
991-
if (GlobalProperty.class.equals(type)) {
992-
return (T) getGlobalPropertyByUuid(uuid);
993-
}
994-
throw new APIException("Unsupported type for getRefByUuid: " + type != null ? type.getName() : "null");
995-
}
996-
997-
@Override
998-
public List<Class<?>> getRefTypes() {
999-
return Arrays.asList(GlobalProperty.class);
1000-
}
1001-
989+
1002990
/**
1003991
* @see org.openmrs.api.AdministrationService#isCoreSetupOnVersionChangeNeeded()
1004992
*/
1005993
@Override
1006994
public boolean isCoreSetupOnVersionChangeNeeded() {
995+
boolean forceSetup = Boolean.parseBoolean(Context.getRuntimeProperties().getProperty("force.setup", "false"));
996+
if (forceSetup) {
997+
return true;
998+
}
999+
10071000
String stored = getStoredCoreVersion();
10081001
String current = OpenmrsConstants.OPENMRS_VERSION_SHORT;
1009-
boolean forceSetup = Boolean.parseBoolean(getGlobalProperty("force.setup", "false"));
1010-
1011-
return forceSetup || !Objects.equals(stored, current);
1002+
return !Objects.equals(stored, current);
10121003
}
10131004

10141005
/**
10151006
* @see org.openmrs.api.AdministrationService#isModuleSetupOnVersionChangeNeeded(String)
10161007
*/
10171008
@Override
10181009
public boolean isModuleSetupOnVersionChangeNeeded(String moduleId) {
1019-
String stored = getStoredModuleVersion(moduleId);
10201010
Module module = ModuleFactory.getModuleById(moduleId);
10211011
if (module == null) {
1012+
log.info("{} module is no longer installed, skipping setup", moduleId);
10221013
return false;
10231014
}
1024-
String current = module.getVersion();
1015+
10251016
boolean forceSetup = Boolean.parseBoolean(getGlobalProperty("force.setup", "false"));
1017+
if (forceSetup) {
1018+
return true;
1019+
}
10261020

1027-
return forceSetup || !Objects.equals(stored, current);
1021+
String stored = getStoredModuleVersion(moduleId);
1022+
String current = module.getVersion();
1023+
if (!Objects.equals(stored, current) || isCoreSetupOnVersionChangeNeeded()) {
1024+
return true;
1025+
} else {
1026+
log.info("{} module did not change, skipping setup", moduleId);
1027+
return false;
1028+
}
10281029
}
10291030

10301031
/**
@@ -1034,7 +1035,7 @@ public boolean isModuleSetupOnVersionChangeNeeded(String moduleId) {
10341035
@Transactional
10351036
public void runCoreSetupOnVersionChange() throws DatabaseUpdateException {
10361037
if (!ModuleFactory.getLoadedModules().isEmpty()) {
1037-
String prevCoreVersion = getStoredCoreVersion() != null ? getStoredCoreVersion() : OpenmrsConstants.OPENMRS_VERSION_SHORT;
1038+
String prevCoreVersion = getStoredCoreVersion();
10381039

10391040
for (Module module : ModuleFactory.getLoadedModules()) {
10401041
String prevModuleVersion = getStoredModuleVersion(module.getModuleId());
@@ -1043,7 +1044,24 @@ public void runCoreSetupOnVersionChange() throws DatabaseUpdateException {
10431044
}
10441045
}
10451046

1047+
boolean updatesRequired;
1048+
try {
1049+
updatesRequired = DatabaseUpdater.updatesRequired();
1050+
}
1051+
catch (Exception e) {
1052+
throw new DatabaseUpdateException("Unable to check if database updates are required", e);
1053+
}
1054+
1055+
// this must be the first thing run in case it changes database mappings
1056+
if (updatesRequired) {
1057+
if (!DatabaseUpdater.allowAutoUpdate()) {
1058+
throw new DatabaseUpdateException(
1059+
"Database updates are required. Call Context.updateDatabase() before .startup() to continue.");
1060+
}
1061+
}
1062+
10461063
DatabaseUpdater.executeChangelog();
1064+
10471065
storeCoreVersion();
10481066
}
10491067

@@ -1058,7 +1076,7 @@ public void runModuleSetupOnVersionChange(Module module) {
10581076
}
10591077

10601078
String moduleId = module.getModuleId();
1061-
String prevCoreVersion = getStoredCoreVersion() != null ? getStoredCoreVersion() : OpenmrsConstants.OPENMRS_VERSION_SHORT;
1079+
String prevCoreVersion = getStoredCoreVersion();
10621080
String prevModuleVersion = getStoredModuleVersion(moduleId);
10631081

10641082
ModuleFactory.runLiquibaseForModule(module);
@@ -1068,39 +1086,23 @@ public void runModuleSetupOnVersionChange(Module module) {
10681086
}
10691087

10701088
protected String getStoredCoreVersion() {
1071-
return getGlobalProperty("core.version");
1089+
return dao.getGlobalProperty("core.version");
10721090
}
10731091

10741092
protected String getStoredModuleVersion(String moduleId) {
1075-
return getGlobalProperty("module." + moduleId + ".version");
1093+
return dao.getGlobalProperty("module." + moduleId + ".version");
10761094
}
10771095

10781096
protected void storeCoreVersion() {
1079-
saveGlobalProperty("core.version", OpenmrsConstants.OPENMRS_VERSION_SHORT, "Saved the state of this core version for future restarts");
1097+
String propertyName = "core.version";
1098+
GlobalProperty gp = new GlobalProperty(propertyName, OpenmrsConstants.OPENMRS_VERSION_SHORT,
1099+
"Saved core version for future restarts");
1100+
dao.saveGlobalProperty(gp);
10801101
}
10811102

10821103
protected void storeModuleVersion(String moduleId, String version) {
10831104
String propertyName = "module." + moduleId + ".version";
1084-
saveGlobalProperty(propertyName, version, "Saved the state of this module version for future restarts");
1085-
}
1086-
1087-
/**
1088-
* Convenience method to save a global property with the given value. Proxy privileges are added so
1089-
* that this can occur at startup.
1090-
*/
1091-
protected void saveGlobalProperty(String key, String value, String desc) {
1092-
try {
1093-
GlobalProperty gp = getGlobalPropertyObject(key);
1094-
if (gp == null) {
1095-
gp = new GlobalProperty(key, value, desc);
1096-
} else {
1097-
gp.setPropertyValue(value);
1098-
}
1099-
1100-
saveGlobalProperty(gp);
1101-
}
1102-
catch (Exception e) {
1103-
log.warn("Unable to save the global property", e);
1104-
}
1105+
GlobalProperty gp = new GlobalProperty(propertyName, version, "Saved module version for future restarts");
1106+
dao.saveGlobalProperty(gp);
11051107
}
11061108
}

api/src/main/java/org/openmrs/module/ModuleActivator.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,19 @@ public interface ModuleActivator {
5858

5959
/**
6060
* Called before Liquibase runs, but only if core or this module version changed.
61+
*
62+
* @param previousCoreVersion previous core version of <code>null</code> if first install
63+
* @param previousModuleVersion previous module version or <code>null</code> if first install
64+
* @since 2.9.0
6165
*/
6266
default void setupOnVersionChangeBeforeSchemaChanges(String previousCoreVersion, String previousModuleVersion) {}
6367

6468
/**
6569
* Called after Liquibase runs, but only if core or this module version changed.
70+
*
71+
* @param previousCoreVersion previous core version of <code>null</code> if first install
72+
* @param previousModuleVersion previous module version or <code>null</code> if first install
73+
* @since 2.9.0
6674
*/
6775
default void setupOnVersionChange(String previousCoreVersion, String previousModuleVersion) {}
6876

api/src/main/java/org/openmrs/module/ModuleFactory.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ public static Module startModuleInternal(Module module, boolean isOpenmrsStartup
692692
}
693693

694694
if (Context.getAdministrationService().isModuleSetupOnVersionChangeNeeded(module.getModuleId())) {
695-
log.info("Detected version change for module {}. Running setup hooks and module Liquibase.", module.getModuleId());
695+
log.info("Module {} changed, running setup.", module.getModuleId());
696696
Context.getAdministrationService().runModuleSetupOnVersionChange(module);
697697
}
698698

@@ -752,7 +752,7 @@ public static Module startModuleInternal(Module module, boolean isOpenmrsStartup
752752
module.clearStartupError();
753753
}
754754
catch (Exception e) {
755-
log.warn("Error while trying to start module: " + moduleId, e);
755+
log.error("Error while trying to start module: {}", moduleId, e);
756756
module.setStartupErrorMessage("Error while trying to start module", e);
757757
notifySuperUsersAboutModuleFailure(module);
758758
// undo all of the actions in startup
@@ -768,7 +768,7 @@ public static Module startModuleInternal(Module module, boolean isOpenmrsStartup
768768
catch (Exception e2) {
769769
// this will probably occur about the same place as the
770770
// error in startup
771-
log.debug("Error while stopping module: " + moduleId, e2);
771+
log.debug("Error while stopping module: {}", moduleId, e2);
772772
}
773773
}
774774

@@ -944,6 +944,7 @@ private static void runDiff(Module module, String version, String sql) {
944944

945945
/**
946946
* This is a convenience method that exposes the private {@link #runLiquibase(Module)} method.
947+
* @since 2.9.0
947948
*/
948949
public static void runLiquibaseForModule(Module module) {
949950
runLiquibase(module);

0 commit comments

Comments
 (0)