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

openmrs / openmrs-core / 36456271610

28 Sep 2026 04:53PM UTC coverage: 66.105% (+1.2%) from 64.906%
36456271610

push

github

ibacher
Clear leaked outbox rows before OutboxEventServiceTest tests (#6596)

Global property saves committed by earlier tests in the shared context
are persisted as outbox events via TestTransactionalEventAggregator.
When more than 100 are pending, getProcessingAndPendingEvents (ordered
by id, limit 100) no longer returns the test's own events, so the test
failed whenever the module tests ran before it, as on Linux CI.


Claude-Session: https://claude.ai/code/session_015sv8E9mrTQK5LBCaS5zqCn

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

25547 of 38646 relevant lines covered (66.11%)

0.66 hits per line

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

37.3
/web/src/main/java/org/openmrs/web/filter/initialization/InitializationFilter.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.web.filter.initialization;
11

12
import java.io.File;
13
import java.io.FileInputStream;
14
import java.io.FileOutputStream;
15
import java.io.IOException;
16
import java.io.InputStream;
17
import java.io.PrintWriter;
18
import java.net.URI;
19
import java.nio.charset.StandardCharsets;
20
import java.sql.Connection;
21
import java.sql.DriverManager;
22
import java.sql.SQLException;
23
import java.sql.Statement;
24
import java.util.ArrayList;
25
import java.util.Arrays;
26
import java.util.Base64;
27
import java.util.Base64.Encoder;
28
import java.util.HashMap;
29
import java.util.HashSet;
30
import java.util.List;
31
import java.util.Locale;
32
import java.util.Map;
33
import java.util.Properties;
34
import java.util.Random;
35
import java.util.Set;
36
import java.util.concurrent.ExecutionException;
37
import java.util.concurrent.Future;
38
import java.util.zip.ZipInputStream;
39
import javax.servlet.FilterChain;
40
import javax.servlet.FilterConfig;
41
import javax.servlet.ServletException;
42
import javax.servlet.ServletRequest;
43
import javax.servlet.ServletResponse;
44
import javax.servlet.http.HttpServletRequest;
45
import javax.servlet.http.HttpServletResponse;
46

47
import liquibase.changelog.ChangeSet;
48
import org.apache.commons.io.IOUtils;
49
import org.openmrs.ImplementationId;
50
import org.openmrs.api.APIAuthenticationException;
51
import org.openmrs.api.PasswordException;
52
import org.openmrs.api.UserService;
53
import org.openmrs.api.context.Context;
54
import org.openmrs.api.context.ContextAuthenticationException;
55
import org.openmrs.api.context.UsernamePasswordCredentials;
56
import org.openmrs.liquibase.ChangeLogDetective;
57
import org.openmrs.liquibase.ChangeLogVersionFinder;
58
import org.openmrs.module.MandatoryModuleException;
59
import org.openmrs.module.web.WebModuleUtil;
60
import org.openmrs.util.DatabaseUpdateException;
61
import org.openmrs.util.DatabaseUpdater;
62
import org.openmrs.liquibase.ChangeSetExecutorCallback;
63
import org.openmrs.util.DatabaseUpdaterLiquibaseProvider;
64
import org.openmrs.util.DatabaseUtil;
65
import org.openmrs.util.InputRequiredException;
66
import org.openmrs.util.OpenmrsConstants;
67
import org.openmrs.util.OpenmrsThreadPoolHolder;
68
import org.openmrs.util.OpenmrsUtil;
69
import org.openmrs.util.PrivilegeConstants;
70
import org.openmrs.util.Security;
71
import org.openmrs.web.Listener;
72
import org.openmrs.web.WebConstants;
73
import org.openmrs.web.WebDaemon;
74
import org.openmrs.web.filter.StartupFilter;
75
import org.openmrs.web.filter.update.UpdateFilter;
76
import org.openmrs.web.filter.util.CustomResourceLoader;
77
import org.openmrs.web.filter.util.ErrorMessageConstants;
78
import org.openmrs.web.filter.util.FilterUtil;
79
import org.openmrs.web.filter.util.SessionModelUtils;
80
import org.slf4j.LoggerFactory;
81
import org.springframework.util.StringUtils;
82
import org.springframework.web.context.ContextLoader;
83

84
import static org.openmrs.util.PrivilegeConstants.GET_GLOBAL_PROPERTIES;
85
import static org.openmrs.web.filter.initialization.InitializationWizardModel.DEFAULT_MYSQL_CONNECTION;
86
import static org.openmrs.web.filter.initialization.InitializationWizardModel.DEFAULT_POSTGRESQL_CONNECTION;
87

88
/**
89
 * This is the first filter that is processed. It is only active when starting OpenMRS for the very
90
 * first time. It will redirect all requests to the {@link WebConstants#SETUP_PAGE_URL} if the
91
 * {@link Listener} wasn't able to find any runtime properties
92
 */
93
public class InitializationFilter extends StartupFilter {
1 ✔
94
        
95
        private static final org.slf4j.Logger log = LoggerFactory.getLogger(InitializationFilter.class);
1 ✔
96
        
97
        private static final String DATABASE_POSTGRESQL = "postgresql";
98
        
99
        private static final String DATABASE_MYSQL = "mysql";
100
        
101
        private static final String DATABASE_SQLSERVER = "sqlserver";
102
        
103
        private static final String DATABASE_H2 = "h2";
104

105
        private static final String DATABASE_MARIADB = "mariadb";
106
        
107
        /**
108
         * The very first page of wizard, that asks user for select his preferred language
109
         */
110
        private static final String CHOOSE_LANG = "chooselang.vm";
111
        
112
        /**
113
         * The second page of the wizard that asks for simple or advanced installation.
114
         */
115
        private static final String INSTALL_METHOD = "installmethod.vm";
116
        
117
        /**
118
         * The simple installation setup page.
119
         */
120
        private static final String SIMPLE_SETUP = "simplesetup.vm";
121
        
122
        /**
123
         * The first page of the advanced installation of the wizard that asks for a current or past
124
         * database
125
         */
126
        private static final String DATABASE_SETUP = "databasesetup.vm";
127
        
128
        /**
129
         * The page from where the user specifies the url to a remote system, username and password
130
         */
131
        private static final String TESTING_REMOTE_DETAILS_SETUP = "remotedetails.vm";
132
        
133
        /**
134
         * The velocity macro page to redirect to if an error occurs or on initial startup
135
         */
136
        private static final String DEFAULT_PAGE = CHOOSE_LANG;
137
        
138
        /**
139
         * This page asks whether database tables/demo data should be inserted and what the
140
         * username/password that will be put into the runtime properties is
141
         */
142
        private static final String DATABASE_TABLES_AND_USER = "databasetablesanduser.vm";
143
        
144
        /**
145
         * This page lets the user define the admin user
146
         */
147
        private static final String ADMIN_USER_SETUP = "adminusersetup.vm";
148
        
149
        /**
150
         * This page lets the user pick an implementation id
151
         */
152
        private static final String IMPLEMENTATION_ID_SETUP = "implementationidsetup.vm";
153
        
154
        /**
155
         * This page asks for settings that will be put into the runtime properties files
156
         */
157
        private static final String OTHER_RUNTIME_PROPS = "otherruntimeproperties.vm";
158
        
159
        /**
160
         * A page that tells the user that everything is collected and will now be processed
161
         */
162
        private static final String WIZARD_COMPLETE = "wizardcomplete.vm";
163
        
164
        /**
165
         * A page that lists off what is happening while it is going on. This page has ajax that callst he
166
         * {@value #PROGRESS_VM_AJAXREQUEST} page
167
         */
168
        private static final String PROGRESS_VM = "progress.vm";
169
        
170
        /**
171
         * This url is called by javascript to get the status of the install
172
         */
173
        private static final String PROGRESS_VM_AJAXREQUEST = "progress.vm.ajaxRequest";
174
        
175
        public static final String RELEASE_TESTING_MODULE_PATH = "/module/releasetestinghelper/";
176
        
177
        /**
178
         * The model object that holds all the properties that the rendered templates use. All attributes on
179
         * this object are made available to all templates via reflection in the
180
         * {@link org.openmrs.web.filter.StartupFilter#renderTemplate(String, Map, HttpServletResponse)} method.
181
         */
182
        protected InitializationWizardModel wizardModel = null;
1 ✔
183
        
184
        private InitializationCompletion initJob;
185
        
186
        /**
187
         * Variable set to true as soon as the installation begins and set to false when the process ends
188
         */
189
        private static volatile boolean isInstallationStarted = false;
1 ✔
190

191
        // the actual driver loaded by the DatabaseUpdater class
192
        private String loadedDriverString;
193

194
        private static final Set<String> NON_NORMALIZED_KEYS = new HashSet<>(Arrays.asList("INSTALL_METHOD", "DATABASE_NAME",
1 ✔
195
            "HAS_CURRENT_OPENMRS_DATABASE", "CREATE_DATABASE_USER", "CREATE_TABLES", "ADD_DEMO_DATA", "MODULE_WEB_ADMIN",
196
            "AUTO_UPDATE_DATABASE", "ADMIN_USER_PASSWORD", "CREATE_DATABASE_USERNAME", "CREATE_DATABASE_PASSWORD",
197
            "CREATE_USER_USERNAME", "CREATE_USER_PASSWORD", "CONNECTION_DRIVER_CLASS", "IMPORT_TEST_DATA", "REMOTE_URL",
198
            "REMOTE_USERNAME", "REMOTE_PASSWORD", "ADMIN_PASSWORD_LOCKED"));
199

200
        /**
201
         * Variable set at the end of the wizard when spring is being restarted
202
         */
203
        private static volatile boolean initializationComplete = false;
1 ✔
204

205
        protected void setInitializationComplete(boolean complete) {
206
                initializationComplete = complete;
1 ✔
207
        }
1 ✔
208
        
209
        /**
210
         * Called by {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} on GET requests
211
         *
212
         * @param httpRequest
213
         * @param httpResponse
214
         */
215
        @Override
216
        protected void doGet(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
217
                throws IOException {
218
                log.debug("Entered initialization filter");
×
219
                
220
                SessionModelUtils.loadFromSession(httpRequest.getSession(), wizardModel);
×
221
                initializeWizardFromResolvedPropertiesIfPresent();
×
222
                
223
                // we need to save current user language in references map since it will be used when template
224
                // will be rendered
225
                if (httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE) == null) {
×
226
                        checkLocaleAttributesForFirstTime(httpRequest);
×
227
                }
228
                
229
                Map<String, Object> referenceMap = new HashMap<>();
×
230
                String page = httpRequest.getParameter("page");
×
231
                
232
                referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE, httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
×
233
                
234
                httpResponse.setHeader("Cache-Control", "no-cache");
×
235
                
236
                // if any body has already started installation and this is not an ajax request for the progress
237
                if (isInstallationStarted() && !PROGRESS_VM_AJAXREQUEST.equals(page)) {
×
238
                        referenceMap.put("isInstallationStarted", true);
×
239
                        httpResponse.setContentType("text/html");
×
240
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
×
241
                } else if (PROGRESS_VM_AJAXREQUEST.equals(page)) {
×
242
                        httpResponse.setContentType("text/json");
×
243
                        Map<String, Object> result = new HashMap<>();
×
244
                        if (initJob != null) {
×
245
                                result.put("hasErrors", initJob.hasErrors());
×
246
                                if (initJob.hasErrors()) {
×
247
                                        result.put("errorPage", initJob.getErrorPage());
×
248
                                        errors.putAll(initJob.getErrors());
×
249
                                }
250
                                
251
                                result.put("initializationComplete", isInitializationComplete());
×
252
                                result.put("message", initJob.getMessage());
×
253
                                result.put("actionCounter", initJob.getStepsComplete());
×
254
                                if (!isInitializationComplete()) {
×
255
                                        result.put("executingTask", initJob.getExecutingTask());
×
256
                                        result.put("executedTasks", initJob.getExecutedTasks());
×
257
                                        result.put("completedPercentage", initJob.getCompletedPercentage());
×
258
                                }
259

260
                                SessionModelUtils.clearWizardSessionAttributes(httpRequest.getSession());
×
261
                                addLogLinesToResponse(result);
×
262
                        }
263
                        
264
                        PrintWriter writer = httpResponse.getWriter();
×
265
                        writer.write(toJSONString(result));
×
266
                        writer.close();
×
267
                } else if (InitializationWizardModel.INSTALL_METHOD_AUTO.equals(wizardModel.installMethod)
×
268
                        || httpRequest.getServletPath().equals("/" + AUTO_RUN_OPENMRS)) {
×
269
                        autoRunOpenMRS(httpRequest);
×
270
                        referenceMap.put("isInstallationStarted", true);
×
271
                        httpResponse.setContentType("text/html");
×
272
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
×
273
                } else if (page == null) {
×
274
                        httpResponse.setContentType("text/html");// if any body has already started installation
×
275
                        
276
                        //If someone came straight here without setting the hidden page input,
277
                        // then we need to clear out all the passwords
278
                        clearPasswords();
×
279
                        
280
                        renderTemplate(DEFAULT_PAGE, referenceMap, httpResponse);
×
281
                } else if (INSTALL_METHOD.equals(page)) {
×
282
                        // get props and render the second page
283
                        File runtimeProperties = getRuntimePropertiesFile();
×
284
                        
285
                        if (!runtimeProperties.exists()) {
×
286
                                try {
287
                                        runtimeProperties.createNewFile();
×
288
                                        // reset the error objects in case of refresh
289
                                        wizardModel.canCreate = true;
×
290
                                        wizardModel.cannotCreateErrorMessage = "";
×
291
                                }
292
                                catch (IOException io) {
×
293
                                        wizardModel.canCreate = false;
×
294
                                        wizardModel.cannotCreateErrorMessage = io.getMessage();
×
295
                                }
×
296
                                
297
                                // check this before deleting the file again
298
                                wizardModel.canWrite = runtimeProperties.canWrite();
×
299
                                
300
                                // delete the file again after testing the create/write
301
                                // so that if the user stops the webapp before finishing
302
                                // this wizard, they can still get back into it
303
                                runtimeProperties.delete();
×
304
                                
305
                        } else {
306
                                wizardModel.canWrite = runtimeProperties.canWrite();
×
307
                                
308
                                wizardModel.databaseConnection = Context.getRuntimeProperties().getProperty("connection.url",
×
309
                                        wizardModel.databaseConnection);
310
                                
311
                                wizardModel.currentDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username",
×
312
                                        wizardModel.currentDatabaseUsername);
313
                                
314
                                wizardModel.currentDatabasePassword = Context.getRuntimeProperties().getProperty("connection.password",
×
315
                                        wizardModel.currentDatabasePassword);
316
                        }
317
                        
318
                        wizardModel.runtimePropertiesPath = runtimeProperties.getAbsolutePath();
×
319
                        
320
                        // do step one of the wizard
321
                        httpResponse.setContentType("text/html");
×
322
                        renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
×
323
                }
324
        }
×
325

326
        /**
327
         * Initializes the setup wizard model by resolving configuration properties from multiple sources.
328
         * <p>
329
         * Properties are loaded and prioritized from system properties, environment variables (normalized),
330
         * and the installation script file. Resolved values are then applied to the corresponding fields
331
         * of the {@link InitializationWizardModel}.
332
         */
333
        protected void initializeWizardFromResolvedPropertiesIfPresent() {
334
                Properties script = new Properties();
1 ✔
335

336
                Properties installScript = getInstallationScript();
1 ✔
337
                script.putAll(installScript);
1 ✔
338

339
                getEnvironmentVariables().forEach((key, value) -> {
1 ✔
340
                        String normalizedKey = normalizeEnvVariableKey(key);
1 ✔
341
                        script.setProperty(normalizedKey, value);
1 ✔
342
                });
1 ✔
343

344
                System.getProperties().forEach((key, value) -> script.setProperty(key.toString(), value.toString()));
1 ✔
345

346
                if (log.isDebugEnabled()) {
1 ✔
347
                        for (String key : script.stringPropertyNames()) {
×
348
                                String value = script.getProperty(key);
×
349
                                log.debug("{} = {}", key, key.toLowerCase().contains("password") ? "*******" : value);
×
350
                        }
×
351
                }
352
                
353
                if (!script.isEmpty()) {
1 ✔
354
                        wizardModel.installMethod = script.getProperty("install_method", wizardModel.installMethod);
1 ✔
355
                        
356
                        wizardModel.databaseConnection = script.getProperty("connection.url", wizardModel.databaseConnection);
1 ✔
357
                        wizardModel.databaseDriver = script.getProperty("connection.driver_class",
1 ✔
358
                            script.getProperty("connection_driver_class", wizardModel.databaseDriver));
1 ✔
359
                        wizardModel.databaseName = script.getProperty("database_name", wizardModel.databaseName);
1 ✔
360
                        wizardModel.currentDatabaseUsername = script.getProperty("connection.username",
1 ✔
361
                                wizardModel.currentDatabaseUsername);
362
                        wizardModel.currentDatabasePassword = script.getProperty("connection.password",
1 ✔
363
                                wizardModel.currentDatabasePassword);
364
                        
365
                        String hasCurrentOpenmrsDatabase = script.getProperty("has_current_openmrs_database");
1 ✔
366
                        if (hasCurrentOpenmrsDatabase != null) {
1 ✔
367
                                wizardModel.hasCurrentOpenmrsDatabase = Boolean.parseBoolean(hasCurrentOpenmrsDatabase);
1 ✔
368
                        }
369
                        wizardModel.createDatabaseUsername = script.getProperty("create_database_username",
1 ✔
370
                                wizardModel.createDatabaseUsername);
371
                        wizardModel.createDatabasePassword = script.getProperty("create_database_password",
1 ✔
372
                                wizardModel.createDatabasePassword);
373
                        
374
                        String createTables = script.getProperty("create_tables");
1 ✔
375
                        if (createTables != null) {
1 ✔
376
                                wizardModel.createTables = Boolean.parseBoolean(createTables);
1 ✔
377
                        }
378
                        
379
                        String createDatabaseUser = script.getProperty("create_database_user");
1 ✔
380
                        if (createDatabaseUser != null) {
1 ✔
381
                                wizardModel.createDatabaseUser = Boolean.parseBoolean(createDatabaseUser);
1 ✔
382
                        }
383
                        wizardModel.createUserUsername = script.getProperty("create_user_username", wizardModel.createUserUsername);
1 ✔
384
                        wizardModel.createUserPassword = script.getProperty("create_user_password", wizardModel.createUserPassword);
1 ✔
385
                        
386
                        String moduleWebAdmin = script.getProperty("module_web_admin");
1 ✔
387
                        if (moduleWebAdmin != null) {
1 ✔
388
                                wizardModel.moduleWebAdmin = Boolean.parseBoolean(moduleWebAdmin);
1 ✔
389
                        }
390
                        
391
                        String autoUpdateDatabase = script.getProperty("auto_update_database");
1 ✔
392
                        if (autoUpdateDatabase != null) {
1 ✔
393
                                wizardModel.autoUpdateDatabase = Boolean.parseBoolean(autoUpdateDatabase);
1 ✔
394
                        }
395
                        
396
                        wizardModel.adminUserPassword = script.getProperty("admin_user_password", wizardModel.adminUserPassword);
1 ✔
397

398
                        String importTestData = script.getProperty("import_test_data", script.getProperty("add_demo_data"));
1 ✔
399
                        if (importTestData != null) {
1 ✔
400
                                wizardModel.importTestData = Boolean.parseBoolean(importTestData);
1 ✔
401
                        }
402

403
                        wizardModel.remoteUrl = script.getProperty("remote_url", wizardModel.remoteUrl);
1 ✔
404
                        wizardModel.remoteUsername = script.getProperty("remote_username", wizardModel.remoteUsername);
1 ✔
405
                        wizardModel.remotePassword = script.getProperty("remote_password", wizardModel.remotePassword);
1 ✔
406

407
                        for (Map.Entry<Object, Object> entry : script.entrySet()) {
1 ✔
408
                                if (entry.getKey() instanceof String && ((String) entry.getKey()).startsWith("property.")) {
1 ✔
409
                                        wizardModel.additionalPropertiesFromInstallationScript.put(((String) entry.getKey()).substring(9), entry.getValue());
1 ✔
410
                                }
411
                        }
1 ✔
412

413
                        String adminPasswordLocked = script.getProperty("admin_password_locked",
1 ✔
414
                            script.getProperty("admin.password.locked"));
1 ✔
415
                        if (adminPasswordLocked != null) {
1 ✔
416
                                wizardModel.additionalPropertiesFromInstallationScript.put("admin.password.locked", adminPasswordLocked);
1 ✔
417
                        }
418
                }
419
        }
1 ✔
420
        
421
        private void clearPasswords() {
422
                wizardModel.databaseRootPassword = "";
×
423
                wizardModel.createDatabasePassword = "";
×
424
                wizardModel.createUserPassword = "";
×
425
                wizardModel.currentDatabasePassword = "";
×
426
                wizardModel.remotePassword = "";
×
427
        }
×
428
        
429
        /**
430
         * Called by {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} on POST requests
431
         *
432
         * @param httpRequest
433
         * @param httpResponse
434
         */
435
        @Override
436
        protected void doPost(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
437
                throws IOException, ServletException {
438
                String page = httpRequest.getParameter("page");
1 ✔
439
                Map<String, Object> referenceMap = new HashMap<>();
1 ✔
440
                // we need to save current user language in references map since it will be used when template
441
                // will be rendered
442
                if (httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE) != null) {
1 ✔
443
                        referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE,
×
444
                                httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
×
445
                }
446
                
447
                // if any body has already started installation
448
                if (isInstallationStarted()) {
1 ✔
449
                        referenceMap.put("isInstallationStarted", true);
1 ✔
450
                        httpResponse.setContentType("text/html");
1 ✔
451
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
1 ✔
452
                        return;
1 ✔
453
                }
454
                if (DEFAULT_PAGE.equals(page)) {
1 ✔
455
                        // get props and render the first page
456
                        File runtimeProperties = getRuntimePropertiesFile();
1 ✔
457
                        if (!runtimeProperties.exists()) {
1 ✔
458
                                try {
459
                                        runtimeProperties.createNewFile();
1 ✔
460
                                        // reset the error objects in case of refresh
461
                                        wizardModel.canCreate = true;
1 ✔
462
                                        wizardModel.cannotCreateErrorMessage = "";
1 ✔
463
                                }
464
                                catch (IOException io) {
×
465
                                        wizardModel.canCreate = false;
×
466
                                        wizardModel.cannotCreateErrorMessage = io.getMessage();
×
467
                                }
1 ✔
468
                                // check this before deleting the file again
469
                                wizardModel.canWrite = runtimeProperties.canWrite();
1 ✔
470
                                
471
                                // delete the file again after testing the create/write
472
                                // so that if the user stops the webapp before finishing
473
                                // this wizard, they can still get back into it
474
                                runtimeProperties.delete();
1 ✔
475
                        } else {
476
                                wizardModel.canWrite = runtimeProperties.canWrite();
×
477
                                
478
                                wizardModel.databaseConnection = Context.getRuntimeProperties().getProperty("connection.url",
×
479
                                        wizardModel.databaseConnection);
480
                                
481
                                wizardModel.currentDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username",
×
482
                                        wizardModel.currentDatabaseUsername);
483
                                
484
                                wizardModel.currentDatabasePassword = Context.getRuntimeProperties().getProperty("connection.password",
×
485
                                        wizardModel.currentDatabasePassword);
486
                        }
487
                        
488
                        wizardModel.runtimePropertiesPath = runtimeProperties.getAbsolutePath();
1 ✔
489
                        
490
                        checkLocaleAttributes(httpRequest);
1 ✔
491
                        referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE,
1 ✔
492
                                httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
1 ✔
493
                        log.info("Locale stored in session is " + httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
1 ✔
494
                        
495
                        httpResponse.setContentType("text/html");
1 ✔
496
                        // otherwise do step one of the wizard
497
                        renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
1 ✔
498
                } else if (INSTALL_METHOD.equals(page)) {
1 ✔
499
                        if (goBack(httpRequest)) {
1 ✔
500
                                referenceMap.put(FilterUtil.REMEMBER_ATTRIBUTE,
1 ✔
501
                                        httpRequest.getSession().getAttribute(FilterUtil.REMEMBER_ATTRIBUTE) != null);
1 ✔
502
                                referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE,
1 ✔
503
                                        httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
1 ✔
504
                                renderTemplate(CHOOSE_LANG, referenceMap, httpResponse);
1 ✔
505
                                return;
1 ✔
506
                        }
507
                        wizardModel.installMethod = httpRequest.getParameter("install_method");
1 ✔
508
                        if (InitializationWizardModel.INSTALL_METHOD_SIMPLE.equals(wizardModel.installMethod)) {
1 ✔
509
                                page = SIMPLE_SETUP;
1 ✔
510
                        } else if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
1 ✔
511
                                page = TESTING_REMOTE_DETAILS_SETUP;
1 ✔
512
                                wizardModel.currentStepNumber = 1;
1 ✔
513
                                wizardModel.numberOfSteps = skipDatabaseSetupPage() ? 1 : 3;
1 ✔
514
                        } else {
515
                                page = DATABASE_SETUP;
1 ✔
516
                                wizardModel.currentStepNumber = 1;
1 ✔
517
                                wizardModel.numberOfSteps = 5;
1 ✔
518
                        }
519
                        renderTemplate(page, referenceMap, httpResponse);
1 ✔
520
                } // simple method
521
                else if (SIMPLE_SETUP.equals(page)) {
1 ✔
522
                        if (goBack(httpRequest)) {
1 ✔
523
                                renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
1 ✔
524
                                return;
1 ✔
525
                        }
526
                        
527
                        String databaseType = httpRequest.getParameter("database_type");
1 ✔
528
                        if (databaseType != null) {
1 ✔
529
                                wizardModel.databaseType = databaseType;
1 ✔
530
                                if (DATABASE_POSTGRESQL.equals(databaseType)) {
1 ✔
531
                                        wizardModel.databaseConnection = DEFAULT_POSTGRESQL_CONNECTION;
1 ✔
532
                                        String postgresUsername = httpRequest.getParameter("create_database_username");
1 ✔
533
                                        wizardModel.createDatabaseUsername = StringUtils.hasText(postgresUsername) ? 
1 ✔
534
                                                postgresUsername : Context.getRuntimeProperties().getProperty("connection.username", "postgres");
1 ✔
535
                                } else {
1 ✔
536
                                        wizardModel.databaseConnection = DEFAULT_MYSQL_CONNECTION;
1 ✔
537
                                        wizardModel.createDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username", 
1 ✔
538
                                                wizardModel.createDatabaseUsername);
539
                                }
540
                        }
541

542
                        wizardModel.databaseRootPassword = httpRequest.getParameter("database_root_password");
1 ✔
543
                        checkForEmptyValue(wizardModel.databaseRootPassword, errors, ErrorMessageConstants.ERROR_DB_PSDW_REQ);
1 ✔
544
                        wizardModel.createUserUsername = wizardModel.createDatabaseUsername;
1 ✔
545
                        wizardModel.hasCurrentOpenmrsDatabase = false;
1 ✔
546
                        wizardModel.createTables = true;
1 ✔
547
                        // default wizardModel.databaseName is openmrs
548
                        // default wizardModel.createDatabaseUsername is root
549
                        wizardModel.createDatabasePassword = wizardModel.databaseRootPassword;
1 ✔
550
                        wizardModel.hasCurrentDatabaseUser = false;
1 ✔
551
                        wizardModel.createDatabaseUser = true;
1 ✔
552
                        // default wizardModel.createUserUsername is root
553
                        wizardModel.createUserPassword = wizardModel.databaseRootPassword;
1 ✔
554
                        
555
                        wizardModel.moduleWebAdmin = true;
1 ✔
556
                        wizardModel.autoUpdateDatabase = false;
1 ✔
557
                        
558
                        wizardModel.adminUserPassword = InitializationWizardModel.ADMIN_DEFAULT_PASSWORD;
1 ✔
559
                        
560
                        createSimpleSetup(httpRequest.getParameter("database_root_password"));
1 ✔
561
                        
562
                        try {
563
                                loadedDriverString = DatabaseUtil.loadDatabaseDriver(wizardModel.databaseConnection,
1 ✔
564
                                        wizardModel.databaseDriver);
565
                        }
566
                        catch (ClassNotFoundException e) {
×
567
                                errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
×
568
                                renderTemplate(page, referenceMap, httpResponse);
×
569
                                return;
×
570
                        }
1 ✔
571
                        
572
                        if (errors.isEmpty()) {
1 ✔
573
                                page = WIZARD_COMPLETE;
1 ✔
574
                        }
575
                        renderTemplate(page, referenceMap, httpResponse);
1 ✔
576
                } // step one
1 ✔
577
                else if (DATABASE_SETUP.equals(page)) {
1 ✔
578
                        if (goBack(httpRequest)) {
1 ✔
579
                                wizardModel.currentStepNumber -= 1;
1 ✔
580
                                if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
1 ✔
581
                                        renderTemplate(TESTING_REMOTE_DETAILS_SETUP, referenceMap, httpResponse);
1 ✔
582
                                } else {
583
                                        renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
1 ✔
584
                                }
585
                                return;
1 ✔
586
                        }
587
                        
588
                        wizardModel.databaseConnection = httpRequest.getParameter("database_connection");
1 ✔
589
                        checkForEmptyValue(wizardModel.databaseConnection, errors, ErrorMessageConstants.ERROR_DB_CONN_REQ);
1 ✔
590
                        
591
                        wizardModel.databaseDriver = httpRequest.getParameter("database_driver");
1 ✔
592
                        checkForEmptyValue(wizardModel.databaseConnection, errors, ErrorMessageConstants.ERROR_DB_DRIVER_REQ);
1 ✔
593
                        
594
                        loadedDriverString = loadDriver(wizardModel.databaseConnection, wizardModel.databaseDriver);
1 ✔
595
                        if (!StringUtils.hasText(loadedDriverString)) {
1 ✔
596
                                errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
1 ✔
597
                                renderTemplate(page, referenceMap, httpResponse);
1 ✔
598
                                return;
1 ✔
599
                        }
600
                        
601
                        //TODO make each bit of page logic a (unit testable) method
602
                        
603
                        // asked the user for their desired database name
604
                        
605
                        if ("yes".equals(httpRequest.getParameter("current_openmrs_database"))) {
1 ✔
606
                                wizardModel.databaseName = httpRequest.getParameter("openmrs_current_database_name");
1 ✔
607
                                checkForEmptyValue(wizardModel.databaseName, errors, ErrorMessageConstants.ERROR_DB_CURR_NAME_REQ);
1 ✔
608
                                wizardModel.hasCurrentOpenmrsDatabase = true;
1 ✔
609
                                // TODO check to see if this is an active database
610
                                
611
                        } else {
612
                                // mark this wizard as a "to create database" (done at the end)
613
                                wizardModel.hasCurrentOpenmrsDatabase = false;
1 ✔
614
                                
615
                                wizardModel.createTables = true;
1 ✔
616
                                
617
                                wizardModel.databaseName = httpRequest.getParameter("openmrs_new_database_name");
1 ✔
618
                                checkForEmptyValue(wizardModel.databaseName, errors, ErrorMessageConstants.ERROR_DB_NEW_NAME_REQ);
1 ✔
619
                                // TODO create database now to check if its possible?
620
                                
621
                                wizardModel.createDatabaseUsername = httpRequest.getParameter("create_database_username");
1 ✔
622
                                checkForEmptyValue(wizardModel.createDatabaseUsername, errors, ErrorMessageConstants.ERROR_DB_USER_NAME_REQ);
1 ✔
623
                                wizardModel.createDatabasePassword = httpRequest.getParameter("create_database_password");
1 ✔
624
                                checkForEmptyValue(wizardModel.createDatabasePassword, errors, ErrorMessageConstants.ERROR_DB_USER_PSWD_REQ);
1 ✔
625
                        }
626
                        
627
                        if (errors.isEmpty()) {
1 ✔
628
                                page = DATABASE_TABLES_AND_USER;
1 ✔
629
                                
630
                                if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
1 ✔
631
                                        wizardModel.currentStepNumber = 3;
1 ✔
632
                                } else {
633
                                        wizardModel.currentStepNumber = 2;
1 ✔
634
                                }
635
                        }
636
                        
637
                        renderTemplate(page, referenceMap, httpResponse);
1 ✔
638
                        
639
                } // step two
640
                else if (DATABASE_TABLES_AND_USER.equals(page)) {
1 ✔
641
                        
642
                        if (goBack(httpRequest)) {
1 ✔
643
                                wizardModel.currentStepNumber -= 1;
1 ✔
644
                                renderTemplate(DATABASE_SETUP, referenceMap, httpResponse);
1 ✔
645
                                return;
1 ✔
646
                        }
647
                        
648
                        if (wizardModel.hasCurrentOpenmrsDatabase) {
1 ✔
649
                                wizardModel.createTables = "yes".equals(httpRequest.getParameter("create_tables"));
1 ✔
650
                        }
651
                        
652
                        if ("yes".equals(httpRequest.getParameter("current_database_user"))) {
1 ✔
653
                                wizardModel.currentDatabaseUsername = httpRequest.getParameter("current_database_username");
1 ✔
654
                                checkForEmptyValue(wizardModel.currentDatabaseUsername, errors,
1 ✔
655
                                        ErrorMessageConstants.ERROR_DB_CUR_USER_NAME_REQ);
656
                                wizardModel.currentDatabasePassword = httpRequest.getParameter("current_database_password");
1 ✔
657
                                checkForEmptyValue(wizardModel.currentDatabasePassword, errors,
1 ✔
658
                                        ErrorMessageConstants.ERROR_DB_CUR_USER_PSWD_REQ);
659
                                wizardModel.hasCurrentDatabaseUser = true;
1 ✔
660
                                wizardModel.createDatabaseUser = false;
1 ✔
661
                        } else {
662
                                wizardModel.hasCurrentDatabaseUser = false;
1 ✔
663
                                wizardModel.createDatabaseUser = true;
1 ✔
664
                                // asked for the root mysql username/password
665
                                wizardModel.createUserUsername = httpRequest.getParameter("create_user_username");
1 ✔
666
                                checkForEmptyValue(wizardModel.createUserUsername, errors, ErrorMessageConstants.ERROR_DB_USER_NAME_REQ);
1 ✔
667
                                wizardModel.createUserPassword = httpRequest.getParameter("create_user_password");
1 ✔
668
                                checkForEmptyValue(wizardModel.createUserPassword, errors, ErrorMessageConstants.ERROR_DB_USER_PSWD_REQ);
1 ✔
669
                        }
670
                        
671
                        if (errors.isEmpty()) { // go to next page
1 ✔
672
                                page = InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod) ? WIZARD_COMPLETE
1 ✔
673
                                        : OTHER_RUNTIME_PROPS;
674
                        }
675
                        
676
                        renderTemplate(page, referenceMap, httpResponse);
1 ✔
677
                } // step three
678
                else if (OTHER_RUNTIME_PROPS.equals(page)) {
1 ✔
679
                        
680
                        if (goBack(httpRequest)) {
1 ✔
681
                                renderTemplate(DATABASE_TABLES_AND_USER, referenceMap, httpResponse);
1 ✔
682
                                return;
1 ✔
683
                        }
684
                        
685
                        wizardModel.moduleWebAdmin = "yes".equals(httpRequest.getParameter("module_web_admin"));
1 ✔
686
                        wizardModel.autoUpdateDatabase = "yes".equals(httpRequest.getParameter("auto_update_database"));
1 ✔
687
                        
688
                        if (wizardModel.createTables) { // go to next page if they are creating tables
1 ✔
689
                                page = ADMIN_USER_SETUP;
1 ✔
690
                        } else { // skip a page
691
                                page = IMPLEMENTATION_ID_SETUP;
1 ✔
692
                        }
693
                        
694
                        renderTemplate(page, referenceMap, httpResponse);
1 ✔
695
                        
696
                } // optional step four
697
                else if (ADMIN_USER_SETUP.equals(page)) {
1 ✔
698
                        
699
                        if (goBack(httpRequest)) {
1 ✔
700
                                renderTemplate(OTHER_RUNTIME_PROPS, referenceMap, httpResponse);
1 ✔
701
                                return;
1 ✔
702
                        }
703
                        
704
                        wizardModel.adminUserPassword = httpRequest.getParameter("new_admin_password");
1 ✔
705
                        String adminUserConfirm = httpRequest.getParameter("new_admin_password_confirm");
1 ✔
706
                        
707
                        // throw back to admin user if passwords don't match
708
                        if (!wizardModel.adminUserPassword.equals(adminUserConfirm)) {
1 ✔
709
                                errors.put(ErrorMessageConstants.ERROR_DB_ADM_PSWDS_MATCH, null);
1 ✔
710
                                renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
1 ✔
711
                                return;
1 ✔
712
                        }
713
                        
714
                        // throw back if the user didn't put in a password
715
                        if ("".equals(wizardModel.adminUserPassword)) {
1 ✔
716
                                errors.put(ErrorMessageConstants.ERROR_DB_ADM_PSDW_EMPTY, null);
1 ✔
717
                                renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
1 ✔
718
                                return;
1 ✔
719
                        }
720
                        
721
                        try {
722
                                OpenmrsUtil.validatePassword("admin", wizardModel.adminUserPassword, "admin");
1 ✔
723
                        }
724
                        catch (PasswordException p) {
1 ✔
725
                                errors.put(ErrorMessageConstants.ERROR_DB_ADM_PSDW_WEAK, null);
1 ✔
726
                                renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
1 ✔
727
                                return;
1 ✔
728
                        }
1 ✔
729
                        
730
                        if (errors.isEmpty()) { // go to next page
1 ✔
731
                                page = IMPLEMENTATION_ID_SETUP;
1 ✔
732
                        }
733
                        
734
                        renderTemplate(page, referenceMap, httpResponse);
1 ✔
735
                        
736
                } // optional step five
1 ✔
737
                else if (IMPLEMENTATION_ID_SETUP.equals(page)) {
1 ✔
738
                        
739
                        if (goBack(httpRequest)) {
1 ✔
740
                                if (wizardModel.createTables) {
1 ✔
741
                                        renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
1 ✔
742
                                } else {
743
                                        renderTemplate(OTHER_RUNTIME_PROPS, referenceMap, httpResponse);
1 ✔
744
                                }
745
                                return;
1 ✔
746
                        }
747
                        
748
                        wizardModel.implementationIdName = httpRequest.getParameter("implementation_name");
1 ✔
749
                        wizardModel.implementationId = httpRequest.getParameter("implementation_id");
1 ✔
750
                        wizardModel.implementationIdPassPhrase = httpRequest.getParameter("pass_phrase");
1 ✔
751
                        wizardModel.implementationIdDescription = httpRequest.getParameter("description");
1 ✔
752
                        
753
                        // throw back if the user-specified ID is invalid (contains ^ or |).
754
                        if (wizardModel.implementationId.indexOf('^') != -1 || wizardModel.implementationId.indexOf('|') != -1) {
1 ✔
755
                                errors.put(ErrorMessageConstants.ERROR_DB_IMPL_ID_REQ, null);
1 ✔
756
                                renderTemplate(IMPLEMENTATION_ID_SETUP, referenceMap, httpResponse);
1 ✔
757
                                return;
1 ✔
758
                        }
759
                        
760
                        if (errors.isEmpty()) { // go to next page
1 ✔
761
                                page = WIZARD_COMPLETE;
1 ✔
762
                        }
763
                        
764
                        renderTemplate(page, referenceMap, httpResponse);
1 ✔
765
                } else if (WIZARD_COMPLETE.equals(page)) {
1 ✔
766
                        
767
                        if (goBack(httpRequest)) {
1 ✔
768
                                
769
                                if (InitializationWizardModel.INSTALL_METHOD_SIMPLE.equals(wizardModel.installMethod)) {
1 ✔
770
                                        page = SIMPLE_SETUP;
1 ✔
771
                                } else if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
1 ✔
772
                                        if (skipDatabaseSetupPage()) {
×
773
                                                page = TESTING_REMOTE_DETAILS_SETUP;
×
774
                                        } else {
775
                                                page = DATABASE_TABLES_AND_USER;
×
776
                                        }
777
                                } else {
778
                                        page = IMPLEMENTATION_ID_SETUP;
1 ✔
779
                                }
780
                                renderTemplate(page, referenceMap, httpResponse);
1 ✔
781
                                return;
1 ✔
782
                        }
783
                        
784
                        wizardModel.tasksToExecute = new ArrayList<>();
1 ✔
785
                        createDatabaseTask();
1 ✔
786
                        if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
1 ✔
787
                                wizardModel.importTestData = true;
1 ✔
788
                                wizardModel.createTables = false;
1 ✔
789
                                //if we have a runtime properties file
790
                                if (skipDatabaseSetupPage()) {
1 ✔
791
                                        wizardModel.hasCurrentOpenmrsDatabase = false;
×
792
                                        wizardModel.hasCurrentDatabaseUser = true;
×
793
                                        wizardModel.createDatabaseUser = false;
×
794
                                        Properties props = OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME);
×
795
                                        wizardModel.currentDatabaseUsername = props.getProperty("connection.username");
×
796
                                        wizardModel.currentDatabasePassword = props.getProperty("connection.password");
×
797
                                        wizardModel.createDatabaseUsername = wizardModel.currentDatabaseUsername;
×
798
                                        wizardModel.createDatabasePassword = wizardModel.currentDatabasePassword;
×
799
                                }
800
                                
801
                                wizardModel.tasksToExecute.add(WizardTask.IMPORT_TEST_DATA);
1 ✔
802
                                wizardModel.tasksToExecute.add(WizardTask.ADD_MODULES);
1 ✔
803
                        } else {
804
                                createTablesTask();
1 ✔
805
                        }
806
                        wizardModel.tasksToExecute.add(WizardTask.UPDATE_TO_LATEST);
1 ✔
807
                        
808
                        referenceMap.put("tasksToExecute", wizardModel.tasksToExecute);
1 ✔
809
                        startInstallation();
1 ✔
810
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
1 ✔
811
                } else if (TESTING_REMOTE_DETAILS_SETUP.equals(page)) {
×
812
                        if (goBack(httpRequest)) {
×
813
                                wizardModel.currentStepNumber -= 1;
×
814
                                renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
×
815
                                return;
×
816
                        }
817
                        
818
                        wizardModel.remoteUrl = httpRequest.getParameter("remoteUrl");
×
819
                        checkForEmptyValue(wizardModel.remoteUrl, errors, "install.testing.remote.url.required");
×
820
                        if (errors.isEmpty()) {
×
821
                                //Check if the remote system is running
822
                                if (TestInstallUtil.testConnection(wizardModel.remoteUrl)) {
×
823
                                        //Check if the test module is installed by connecting to its setting page
824
                                        if (TestInstallUtil
×
825
                                                .testConnection(wizardModel.remoteUrl.concat(RELEASE_TESTING_MODULE_PATH + "settings.htm"))) {
×
826
                                                
827
                                                wizardModel.remoteUsername = httpRequest.getParameter("username");
×
828
                                                wizardModel.remotePassword = httpRequest.getParameter("password");
×
829
                                                checkForEmptyValue(wizardModel.remoteUsername, errors, "install.testing.username.required");
×
830
                                                checkForEmptyValue(wizardModel.remotePassword, errors, "install.testing.password.required");
×
831
                                                
832
                                                if (errors.isEmpty()) {
×
833
                                                        //check if the username and password are valid
834
                                                        try {
835
                                                                TestInstallUtil.getResourceInputStream(
×
836
                                                                        wizardModel.remoteUrl + RELEASE_TESTING_MODULE_PATH + "verifycredentials.htm",
837
                                                                        wizardModel.remoteUsername, wizardModel.remotePassword);
838
                                                        }
839
                                                        catch (APIAuthenticationException e) {
×
840
                                                                log.debug("Error generated: ", e);
×
841
                                                                page = TESTING_REMOTE_DETAILS_SETUP;
×
842
                                                                errors.put(ErrorMessageConstants.UPDATE_ERROR_UNABLE_AUTHENTICATE, null);
×
843
                                                                renderTemplate(page, referenceMap, httpResponse);
×
844
                                                                return;
×
845
                                                        }
×
846
                                                        
847
                                                        //If we have a runtime properties file, get the database setup details from it
848
                                                        if (skipDatabaseSetupPage()) {
×
849
                                                                Properties props = OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME);
×
850
                                                                wizardModel.databaseConnection = props.getProperty("connection.url");
×
851
                                                                loadedDriverString = loadDriver(wizardModel.databaseConnection, wizardModel.databaseDriver);
×
852
                                                                if (!StringUtils.hasText(loadedDriverString)) {
×
853
                                                                        page = TESTING_REMOTE_DETAILS_SETUP;
×
854
                                                                        errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
×
855
                                                                        renderTemplate(page, referenceMap, httpResponse);
×
856
                                                                        return;
×
857
                                                                }
858
                                                                
859
                                                                wizardModel.databaseName = InitializationWizardModel.DEFAULT_DATABASE_NAME;
×
860
                                                                page = WIZARD_COMPLETE;
×
861
                                                        } else {
×
862
                                                                page = DATABASE_SETUP;
×
863
                                                                wizardModel.currentStepNumber = 2;
×
864
                                                        }
865
                                                        msgs.put("install.testing.testingModuleFound", null);
×
866
                                                } else {
867
                                                        renderTemplate(page, referenceMap, httpResponse);
×
868
                                                        return;
×
869
                                                }
870
                                        } else {
871
                                                errors.put("install.testing.noTestingModule", null);
×
872
                                        }
873
                                } else {
874
                                        errors.put("install.testing.invalidProductionUrl", new Object[] { wizardModel.remoteUrl });
×
875
                                }
876
                        }
877
                        
878
                        SessionModelUtils.saveToSession(httpRequest.getSession(), wizardModel);
×
879
                        renderTemplate(page, referenceMap, httpResponse);
×
880
                }
881
        }
1 ✔
882
        
883
        protected void startInstallation() {
884
                //if no one has run any installation
885
                if (!isInstallationStarted()) {
×
886
                        initJob = new InitializationCompletion();
×
887
                        setInstallationStarted(true);
×
888
                        initJob.start();
×
889
                }
890
        }
×
891
        
892
        private void createTablesTask() {
893
                if (wizardModel.createTables) {
1 ✔
894
                        wizardModel.tasksToExecute.add(WizardTask.CREATE_TABLES);
1 ✔
895
                        wizardModel.tasksToExecute.add(WizardTask.ADD_CORE_DATA);
1 ✔
896
                }
897
        }
1 ✔
898
        
899
        private void createDatabaseTask() {
900
                if (!wizardModel.hasCurrentOpenmrsDatabase) {
1 ✔
901
                        wizardModel.tasksToExecute.add(WizardTask.CREATE_SCHEMA);
1 ✔
902
                }
903
                if (wizardModel.createDatabaseUser) {
1 ✔
904
                        wizardModel.tasksToExecute.add(WizardTask.CREATE_DB_USER);
1 ✔
905
                }
906
        }
1 ✔
907
        
908
        private void createSimpleSetup(String databaseRootPassword) {
909
                setDatabaseNameIfInTestMode();
1 ✔
910
                wizardModel.databaseConnection = Context.getRuntimeProperties().getProperty("connection.url",
1 ✔
911
                        wizardModel.databaseConnection);
912
                
913
                wizardModel.createDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username",
1 ✔
914
                        wizardModel.createDatabaseUsername);
915
                
916
                wizardModel.createUserUsername = wizardModel.createDatabaseUsername;
1 ✔
917
                
918
                wizardModel.databaseRootPassword = databaseRootPassword;
1 ✔
919
                checkForEmptyValue(wizardModel.databaseRootPassword, errors, ErrorMessageConstants.ERROR_DB_PSDW_REQ);
1 ✔
920
                
921
                wizardModel.hasCurrentOpenmrsDatabase = false;
1 ✔
922
                wizardModel.createTables = true;
1 ✔
923
                // default wizardModel.databaseName is openmrs
924
                // default wizardModel.createDatabaseUsername is root
925
                wizardModel.createDatabasePassword = wizardModel.databaseRootPassword;
1 ✔
926
                wizardModel.hasCurrentDatabaseUser = false;
1 ✔
927
                wizardModel.createDatabaseUser = true;
1 ✔
928
                // default wizardModel.createUserUsername is root
929
                wizardModel.createUserPassword = wizardModel.databaseRootPassword;
1 ✔
930
                
931
                wizardModel.moduleWebAdmin = true;
1 ✔
932
                wizardModel.autoUpdateDatabase = false;
1 ✔
933
                
934
                wizardModel.adminUserPassword = InitializationWizardModel.ADMIN_DEFAULT_PASSWORD;
1 ✔
935
        }
1 ✔
936
        
937
        private void setDatabaseNameIfInTestMode() {
938
                if (OpenmrsUtil.isTestMode()) {
1 ✔
939
                        wizardModel.databaseName = OpenmrsUtil.getOpenMRSVersionInTestMode();
×
940
                }
941
        }
1 ✔
942
        
943
        private void autoRunOpenMRS(HttpServletRequest httpRequest) {
944
                File runtimeProperties = getRuntimePropertiesFile();
×
945
                wizardModel.runtimePropertiesPath = runtimeProperties.getAbsolutePath();
×
946
                
947
                if (!InitializationWizardModel.INSTALL_METHOD_AUTO.equals(wizardModel.installMethod)) {
×
948
                        if (httpRequest.getParameter("database_user_name") != null) {
×
949
                                wizardModel.createDatabaseUsername = httpRequest.getParameter("database_user_name");
×
950
                        }
951
                        
952
                        createSimpleSetup(httpRequest.getParameter("database_root_password"));
×
953
                }
954
                
955
                checkLocaleAttributes(httpRequest);
×
956
                try {
957
                        loadedDriverString = DatabaseUtil.loadDatabaseDriver(wizardModel.databaseConnection, wizardModel.databaseDriver);
×
958
                }
959
                catch (ClassNotFoundException e) {
×
960
                        errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
×
961
                        return;
×
962
                }
×
963
                wizardModel.tasksToExecute = new ArrayList<>();
×
964
                createDatabaseTask();
×
965
                createTablesTask();
×
966
                if (wizardModel.importTestData) {
×
967
                        wizardModel.tasksToExecute.add(WizardTask.IMPORT_TEST_DATA);
×
968
                        wizardModel.tasksToExecute.add(WizardTask.ADD_MODULES);
×
969
                }
970
                wizardModel.tasksToExecute.add(WizardTask.UPDATE_TO_LATEST);
×
971
                startInstallation();
×
972
        }
×
973
        
974
        /**
975
         * This method should be called after the user has left wizard's first page (i.e. choose language).
976
         * It checks if user has changed any of locale related parameters and makes appropriate corrections
977
         * with filter's model or/and with locale attribute inside user's session.
978
         *
979
         * @param httpRequest the http request object
980
         */
981
        private void checkLocaleAttributes(HttpServletRequest httpRequest) {
982
                String localeParameter = httpRequest.getParameter(FilterUtil.LOCALE_ATTRIBUTE);
1 ✔
983
                Boolean rememberLocale = false;
1 ✔
984
                // we need to check if user wants that system will remember his selection of language
985
                if (httpRequest.getParameter(FilterUtil.REMEMBER_ATTRIBUTE) != null) {
1 ✔
986
                        rememberLocale = true;
×
987
                }
988
                if (localeParameter != null) {
1 ✔
989
                        String storedLocale = null;
1 ✔
990
                        if (httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE) != null) {
1 ✔
991
                                storedLocale = httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE).toString();
×
992
                        }
993
                        // if user has changed locale parameter to new one
994
                        // or chooses it parameter at first page loading
995
                        if (storedLocale == null || !storedLocale.equals(localeParameter)) {
1 ✔
996
                                log.info("Stored locale parameter to session " + localeParameter);
1 ✔
997
                                httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, localeParameter);
1 ✔
998
                        }
999
                        if (rememberLocale) {
1 ✔
1000
                                httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, localeParameter);
×
1001
                                httpRequest.getSession().setAttribute(FilterUtil.REMEMBER_ATTRIBUTE, true);
×
1002
                                wizardModel.localeToSave = localeParameter;
×
1003
                        } else {
1004
                                // we need to reset it if it was set before
1005
                                httpRequest.getSession().setAttribute(FilterUtil.REMEMBER_ATTRIBUTE, null);
1 ✔
1006
                                wizardModel.localeToSave = null;
1 ✔
1007
                        }
1008
                }
1009
        }
1 ✔
1010
        
1011
        /**
1012
         * It sets locale parameter for current session when user is making first GET http request to
1013
         * application. It retrieves user locale from request object and checks if this locale is supported
1014
         * by application. If not, it uses {@link Locale#ENGLISH} by default
1015
         *
1016
         * @param httpRequest the http request object
1017
         */
1018
        public void checkLocaleAttributesForFirstTime(HttpServletRequest httpRequest) {
1019
                Locale locale = httpRequest.getLocale();
×
1020
                if (CustomResourceLoader.getInstance(httpRequest).getAvailablelocales().contains(locale)) {
×
1021
                        httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, locale.toString());
×
1022
                } else {
1023
                        httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, Locale.ENGLISH.toString());
×
1024
                }
1025
        }
×
1026
        
1027
        /**
1028
         * Verify the database connection works.
1029
         *
1030
         * @param connectionUsername
1031
         * @param connectionPassword
1032
         * @param databaseConnectionFinalUrl
1033
         * @return true/false whether it was verified or not
1034
         */
1035
        private boolean verifyConnection(String connectionUsername, String connectionPassword,
1036
                String databaseConnectionFinalUrl) {
1037
                try {
1038
                        // verify connection
1039
                        DatabaseUtil.loadDatabaseDriver(databaseConnectionFinalUrl, loadedDriverString);
×
1040
                        try (Connection ignored = DriverManager.getConnection(databaseConnectionFinalUrl, connectionUsername, connectionPassword)) {
×
1041
                                return true;
×
1042
                        }
1043
                }
1044
                catch (Exception e) {
×
1045
                        errors.put("User account " + connectionUsername + " does not work. " + e.getMessage()
×
1046
                                        + " See the error log for more details",
1047
                                null); // TODO internationalize this
1048
                        log.warn("Error while checking the connection user account", e);
×
1049
                        return false;
×
1050
                }
1051
        }
1052
        
1053
        /**
1054
         * Convenience method to load the runtime properties file.
1055
         *
1056
         * @return the runtime properties file.
1057
         */
1058
        private File getRuntimePropertiesFile() {
1059
                File file;
1060
                
1061
                String pathName = OpenmrsUtil.getRuntimePropertiesFilePathName(WebConstants.WEBAPP_NAME);
1 ✔
1062
                if (pathName != null) {
1 ✔
1063
                        file = new File(pathName);
×
1064
                } else {
1065
                        file = new File(OpenmrsUtil.getApplicationDataDirectory(), getRuntimePropertiesFileName());
1 ✔
1066
                }
1067
                
1068
                log.debug("Using file: " + file.getAbsolutePath());
1 ✔
1069
                
1070
                return file;
1 ✔
1071
        }
1072
        
1073
        private String getRuntimePropertiesFileName() {
1074
                String fileName = OpenmrsUtil.getRuntimePropertiesFileNameInTestMode();
1 ✔
1075
                if (fileName == null) {
1 ✔
1076
                        fileName = WebConstants.WEBAPP_NAME + "-runtime.properties";
1 ✔
1077
                }
1078
                return fileName;
1 ✔
1079
        }
1080
        
1081
        /**
1082
         * @see org.openmrs.web.filter.StartupFilter#getTemplatePrefix()
1083
         */
1084
        @Override
1085
        protected String getTemplatePrefix() {
1086
                return "org/openmrs/web/filter/initialization/";
×
1087
        }
1088
        
1089
        /**
1090
         * @see org.openmrs.web.filter.StartupFilter#getUpdateFilterModel()
1091
         */
1092
        @Override
1093
        protected Object getUpdateFilterModel() {
1094
                return wizardModel;
×
1095
        }
1096
        
1097
        /**
1098
         * @see org.openmrs.web.filter.StartupFilter#skipFilter(HttpServletRequest)
1099
         */
1100
        @Override
1101
        public boolean skipFilter(HttpServletRequest httpRequest) {
1102
                if (initializationRequired()) {
1 ✔
1103
                        return false;
1 ✔
1104
                }
1105
                // Once initialization completes, only the progress page's final poll still needs this filter; without it
1106
                // progress.vm never leaves the wizard. Check the servlet path first so other requests aren't parsed.
1107
                if (!("/" + WebConstants.SETUP_PAGE_URL).equals(httpRequest.getServletPath())) {
1 ✔
1108
                        return true;
1 ✔
1109
                }
1110
                return !PROGRESS_VM_AJAXREQUEST.equals(httpRequest.getParameter("page"));
1 ✔
1111
        }
1112
        
1113
        /**
1114
         * Public method that returns true if database+runtime properties initialization is required
1115
         *
1116
         * @return true if this initialization wizard needs to run
1117
         */
1118
        public static boolean initializationRequired() {
1119
                return !isInitializationComplete();
1 ✔
1120
        }
1121
        
1122
        /**
1123
         * @param isInstallationStarted the value to set
1124
         */
1125
        protected static void setInstallationStarted(boolean isInstallationStarted) {
1126
                InitializationFilter.isInstallationStarted = isInstallationStarted;
1 ✔
1127
        }
1 ✔
1128
        
1129
        /**
1130
         * @return true if installation has been started
1131
         */
1132
        public static boolean isInstallationStarted() {
1133
                return isInstallationStarted;
1 ✔
1134
        }
1135
        
1136
        /**
1137
         * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
1138
         */
1139
        @Override
1140
        public void init(FilterConfig filterConfig) throws ServletException {
1141
                super.init(filterConfig);
×
1142
                wizardModel = new InitializationWizardModel();
×
1143
                DatabaseDetective databaseDetective = new DatabaseDetective();
×
1144
                //set whether need to do initialization work
1145
                if (databaseDetective.isDatabaseEmpty(OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME))) {
×
1146
                        //if runtime-properties file doesn't exist, have to do initialization work
1147
                        setInitializationComplete(false);
×
1148
                } else {
1149
                        //if database is not empty, then let UpdaterFilter to judge whether need database update
1150
                        setInitializationComplete(true);
×
1151
                }
1152
        }
×
1153
        
1154
        private void importTestDataSet(InputStream in, String connectionUrl, String connectionUsername,
1155
                String connectionPassword) throws IOException {
1156
                File tempFile = null;
×
1157
                FileOutputStream fileOut = null;
×
1158
                try {
1159
                        ZipInputStream zipIn = new ZipInputStream(in);
×
1160
                        zipIn.getNextEntry();
×
1161
                        
1162
                        tempFile = File.createTempFile("testDataSet", "dump");
×
1163
                        fileOut = new FileOutputStream(tempFile);
×
1164
                        
1165
                        IOUtils.copy(zipIn, fileOut);
×
1166
                        
1167
                        fileOut.close();
×
1168
                        zipIn.close();
×
1169
                        
1170
                        //Cater for the stand-alone connection url with has :mxj:
1171
                        if (connectionUrl.contains(":mxj:")) {
×
1172
                                connectionUrl = connectionUrl.replace(":mxj:", ":");
×
1173
                        }
1174
                        
1175
                        URI uri = URI.create(connectionUrl.substring(5)); //remove 'jdbc:' prefix to conform to the URI format
×
1176
                        String host = uri.getHost();
×
1177
                        int port = uri.getPort();
×
1178
                        
1179
                        TestInstallUtil.addTestData(host, port, wizardModel.databaseName, connectionUsername, connectionPassword,
×
1180
                                tempFile.getAbsolutePath());
×
1181
                }
1182
                finally {
1183
                        IOUtils.closeQuietly(in);
×
1184
                        IOUtils.closeQuietly(fileOut);
×
1185
                        
1186
                        if (tempFile != null) {
×
1187
                                tempFile.delete();
×
1188
                        }
1189
                }
1190
        }
×
1191
        
1192
        protected boolean isCurrentDatabase(String database) {
1193
                return wizardModel.databaseConnection.contains(database);
1 ✔
1194
        }
1195
        
1196
        /**
1197
         * @param silent if this statement fails do not display stack trace or record an error in the wizard
1198
         *            object.
1199
         * @param user username to connect with
1200
         * @param pw password to connect with
1201
         * @param sql String containing sql and question marks
1202
         * @param args the strings to fill into the question marks in the given sql
1203
         * @return result of executeUpdate or -1 for error
1204
         */
1205
        private int executeStatement(boolean silent, String user, String pw, String sql, String... args) {
1206
                
1207
                Connection connection = null;
×
1208
                Statement statement = null;
×
1209
                try {
1210
                        String replacedSql = sql;
×
1211
                        
1212
                        // TODO how to get the driver for the other dbs...
1213
                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1214
                                Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
×
1215
                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1216
                                Class.forName("org.postgresql.Driver").newInstance();
×
1217
                                replacedSql = replacedSql.replaceAll("`", "\"");
×
1218
                        } else {
1219
                                replacedSql = replacedSql.replaceAll("`", "\"");
×
1220
                        }
1221
                        
1222
                        String tempDatabaseConnection;
1223
                        if (sql.contains("create database")) {
×
1224
                                tempDatabaseConnection = wizardModel.databaseConnection.replace("@DBNAME@",
×
1225
                                        ""); // make this dbname agnostic so we can create the db
1226
                        } else {
1227
                                tempDatabaseConnection = wizardModel.databaseConnection.replace("@DBNAME@", wizardModel.databaseName);
×
1228
                        }
1229
                        
1230
                        connection = DriverManager.getConnection(tempDatabaseConnection, user, pw);
×
1231
                        
1232
                        for (String arg : args) {
×
1233
                                arg = arg.replace(";", "&#094"); // to prevent any sql injection
×
1234
                                replacedSql = replacedSql.replaceFirst("\\?", arg);
×
1235
                        }
1236
                        
1237
                        // run the sql statement
1238
                        statement = connection.createStatement();
×
1239
                        
1240
                        return statement.executeUpdate(replacedSql);
×
1241
                        
1242
                }
1243
                catch (SQLException sqlex) {
×
1244
                        if (!silent) {
×
1245
                                // log and add error
1246
                                log.warn("error executing sql: " + sql, sqlex);
×
1247
                                errors.put("Error executing sql: " + sql + " - " + sqlex.getMessage(), null);
×
1248
                        }
1249
                }
1250
                catch (InstantiationException | ClassNotFoundException | IllegalAccessException e) {
×
1251
                        log.error("Error generated", e);
×
1252
                }
1253
                finally {
1254
                        try {
1255
                                if (statement != null) {
×
1256
                                        statement.close();
×
1257
                                }
1258
                        }
1259
                        catch (SQLException e) {
×
1260
                                log.warn("Error while closing statement");
×
1261
                        }
×
1262
                        try {
1263
                                
1264
                                if (connection != null) {
×
1265
                                        connection.close();
×
1266
                                }
1267
                        }
1268
                        catch (Exception e) {
×
1269
                                log.warn("Error while closing connection", e);
×
1270
                        }
×
1271
                }
1272
                
1273
                return -1;
×
1274
        }
1275
        
1276
        /**
1277
         * Convenience variable to know if this wizard has completed successfully and that this wizard does
1278
         * not need to be executed again
1279
         *
1280
         * @return true if this has been run already
1281
         */
1282
        private static boolean isInitializationComplete() {
1283
                return initializationComplete;
1 ✔
1284
        }
1285
        
1286
        /**
1287
         * Checks if the given string value is empty or contains only whitespace. 
1288
         * If it is, an error is added to the provided errors map with the specified error message code.
1289
         *
1290
         * @param value            the string to check
1291
         * @param errors           the list of errors to append the errorMessage to if value is empty
1292
         * @param errorMessageCode the string with code of error message translation to append if value is
1293
         *                         empty
1294
         */
1295
        private void checkForEmptyValue(String value, Map<String, Object[]> errors, String errorMessageCode) {
1296
                if (!StringUtils.hasText(value)) {
1 ✔
1297
                        errors.put(errorMessageCode, null);
1 ✔
1298
                }
1299
        }
1 ✔
1300
        
1301
        /**
1302
         * Separate thread that will run through all tasks to complete the initialization. The database is
1303
         * created, user's created, etc here
1304
         */
1305
        private class InitializationCompletion {
1306
                
1307
                private final Future<Void> future;
1308
                
1309
                private int steps = 0;
×
1310
                
1311
                private String message = "";
×
1312
                
1313
                private Map<String, Object[]> errors = new HashMap<>();
×
1314
                
1315
                private String errorPage = null;
×
1316
                
1317
                private boolean erroneous = false;
×
1318
                
1319
                private int completedPercentage = 0;
×
1320
                
1321
                private WizardTask executingTask;
1322
                
1323
                private List<WizardTask> executedTasks = new ArrayList<>();
×
1324
                
1325
                public synchronized void reportError(String error, String errorPage, Object... params) {
1326
                        errors.put(error, params);
×
1327
                        this.errorPage = errorPage;
×
1328
                        erroneous = true;
×
1329
                }
×
1330
                
1331
                public synchronized boolean hasErrors() {
1332
                        return erroneous;
×
1333
                }
1334
                
1335
                public synchronized String getErrorPage() {
1336
                        return errorPage;
×
1337
                }
1338
                
1339
                public synchronized Map<String, Object[]> getErrors() {
1340
                        return errors;
×
1341
                }
1342
                
1343
                /**
1344
                 * Start the completion stage. This fires up the thread to do all the work.
1345
                 */
1346
                public void start() {
1347
                        setStepsComplete(0);
×
1348
                        setInitializationComplete(false);
×
1349
                }
×
1350
                
1351
                public void waitForCompletion() {
1352
                        try {
1353
                                future.get();
×
1354
                        } catch (InterruptedException | ExecutionException e) {
×
1355
                                throw new RuntimeException(e);
×
1356
                        }
×
1357
                }
×
1358
                
1359
                protected synchronized void setStepsComplete(int steps) {
1360
                        this.steps = steps;
×
1361
                }
×
1362
                
1363
                protected synchronized int getStepsComplete() {
1364
                        return steps;
×
1365
                }
1366
                
1367
                public synchronized String getMessage() {
1368
                        return message;
×
1369
                }
1370
                
1371
                public synchronized void setMessage(String message) {
1372
                        log.debug(message);
×
1373
                        this.message = message;
×
1374
                        setStepsComplete(getStepsComplete() + 1);
×
1375
                }
×
1376
                
1377
                /**
1378
                 * @return the executingTask
1379
                 */
1380
                protected synchronized WizardTask getExecutingTask() {
1381
                        return executingTask;
×
1382
                }
1383
                
1384
                /**
1385
                 * @return the completedPercentage
1386
                 */
1387
                protected synchronized int getCompletedPercentage() {
1388
                        return completedPercentage;
×
1389
                }
1390
                
1391
                /**
1392
                 * @param completedPercentage the completedPercentage to set
1393
                 */
1394
                protected synchronized void setCompletedPercentage(int completedPercentage) {
1395
                        this.completedPercentage = completedPercentage;
×
1396
                }
×
1397
                
1398
                /**
1399
                 * Adds a task that has been completed to the list of executed tasks
1400
                 *
1401
                 * @param task
1402
                 */
1403
                protected synchronized void addExecutedTask(WizardTask task) {
1404
                        this.executedTasks.add(task);
×
1405
                }
×
1406
                
1407
                /**
1408
                 * @param executingTask the executingTask to set
1409
                 */
1410
                protected synchronized void setExecutingTask(WizardTask executingTask) {
1411
                        this.executingTask = executingTask;
×
1412
                }
×
1413
                
1414
                /**
1415
                 * @return the executedTasks
1416
                 */
1417
                protected synchronized List<WizardTask> getExecutedTasks() {
1418
                        return this.executedTasks;
×
1419
                }
1420
                
1421
                /**
1422
                 * This class does all the work of creating the desired database, user, updates, etc
1423
                 */
1424
                public InitializationCompletion() {
×
1425
                        Runnable r = new Runnable() {
×
1426
                                
1427
                                /**
1428
                                 * TODO split this up into multiple testable methods
1429
                                 *
1430
                                 * @see java.lang.Runnable#run()
1431
                                 */
1432
                                @Override
1433
                                public void run() {
1434
                                        try {
1435
                                                String connectionUsername;
1436
                                                StringBuilder connectionPassword = new StringBuilder();
×
1437
                                                ChangeLogDetective changeLogDetective = ChangeLogDetective.getInstance();
×
1438
                                                ChangeLogVersionFinder changeLogVersionFinder = new ChangeLogVersionFinder();
×
1439
                                                
1440
                                                if (!wizardModel.hasCurrentOpenmrsDatabase) {
×
1441
                                                        setMessage("Create database");
×
1442
                                                        setExecutingTask(WizardTask.CREATE_SCHEMA);
×
1443
                                                        // connect via jdbc and create a database
1444
                                                        String sql;
1445
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1446
                                                                sql = "create database if not exists `?` default character set utf8";
×
1447
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1448
                                                                sql = "create database `?` encoding 'utf8'";
×
1449
                                                        } else if (isCurrentDatabase(DATABASE_H2)) {
×
1450
                                                                sql = null;
×
1451
                                                        } else {
1452
                                                                sql = "create database `?`";
×
1453
                                                        }
1454
                                                        
1455
                                                        int result;
1456
                                                        if (sql != null) {
×
1457
                                                                result = executeStatement(false, wizardModel.createDatabaseUsername,
×
1458
                                                                        wizardModel.createDatabasePassword, sql, wizardModel.databaseName);
1459
                                                        } else {
1460
                                                                result = 1;
×
1461
                                                        }
1462
                                                        // throw the user back to the main screen if this error occurs
1463
                                                        if (result < 0) {
×
1464
                                                                reportError(ErrorMessageConstants.ERROR_DB_CREATE_NEW, DEFAULT_PAGE);
×
1465
                                                                return;
×
1466
                                                        } else {
1467
                                                                wizardModel.workLog.add("Created database " + wizardModel.databaseName);
×
1468
                                                        }
1469
                                                        
1470
                                                        addExecutedTask(WizardTask.CREATE_SCHEMA);
×
1471
                                                }
1472
                                                
1473
                                                if (wizardModel.createDatabaseUser) {
×
1474
                                                        setMessage("Create database user");
×
1475
                                                        setExecutingTask(WizardTask.CREATE_DB_USER);
×
1476
                                                        connectionUsername = wizardModel.databaseName + "_user";
×
1477
                                                        if (connectionUsername.length() > 16) {
×
1478
                                                                connectionUsername = wizardModel.databaseName.substring(0, 11)
×
1479
                                                                        + "_user"; // trim off enough to leave space for _user at the end
1480
                                                        }
1481
                                                        
1482
                                                        connectionPassword.append("");
×
1483
                                                        // generate random password from this subset of alphabet
1484
                                                        // intentionally left out these characters: ufsb$() to prevent certain words forming randomly
1485
                                                        String chars = "acdeghijklmnopqrtvwxyzACDEGHIJKLMNOPQRTVWXYZ0123456789.|~@#^&";
×
1486
                                                        Random r = new Random();
×
1487
                                                        StringBuilder randomStr = new StringBuilder("");
×
1488
                                                        for (int x = 0; x < 12; x++) {
×
1489
                                                                randomStr.append(chars.charAt(r.nextInt(chars.length())));
×
1490
                                                        }
1491
                                                        connectionPassword.append(randomStr);
×
1492
                                                        
1493
                                                        // connect via jdbc with root user and create an openmrs user
1494
                                                        String host = "'%'";
×
1495
                                                        if (wizardModel.databaseConnection.contains("localhost")
×
1496
                                                                || wizardModel.databaseConnection.contains("127.0.0.1")) {
×
1497
                                                                host = "'localhost'";
×
1498
                                                        }
1499
                                                        
1500
                                                        String sql = "";
×
1501
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1502
                                                                sql = "drop user '?'@" + host;
×
1503
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1504
                                                                sql = "drop user `?`";
×
1505
                                                        }
1506
                                                        
1507
                                                        executeStatement(true, wizardModel.createUserUsername, wizardModel.createUserPassword, sql,
×
1508
                                                                connectionUsername);
1509
                                                        
1510
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1511
                                                                sql = "create user '?'@" + host + " identified by '?'";
×
1512
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1513
                                                                sql = "create user `?` with password '?'";
×
1514
                                                        }
1515
                                                        
1516
                                                        if (-1 != executeStatement(false, wizardModel.createUserUsername, wizardModel.createUserPassword,
×
1517
                                                                sql, connectionUsername, connectionPassword.toString())) {
×
1518
                                                                wizardModel.workLog.add("Created user " + connectionUsername);
×
1519
                                                        } else {
1520
                                                                // if error occurs stop
1521
                                                                reportError(ErrorMessageConstants.ERROR_DB_CREATE_DB_USER, DEFAULT_PAGE);
×
1522
                                                                return;
×
1523
                                                        }
1524
                                                        
1525
                                                        // grant the roles
1526
                                                        int result = 1;
×
1527
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1528
                                                                sql = "GRANT ALL ON `?`.* TO '?'@" + host;
×
1529
                                                                result = executeStatement(false, wizardModel.createUserUsername,
×
1530
                                                                        wizardModel.createUserPassword, sql, wizardModel.databaseName, connectionUsername);
1531
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1532
                                                                sql = "ALTER USER `?` WITH SUPERUSER";
×
1533
                                                                result = executeStatement(false, wizardModel.createUserUsername,
×
1534
                                                                        wizardModel.createUserPassword, sql, connectionUsername);
1535
                                                        }
1536
                                                        
1537
                                                        // throw the user back to the main screen if this error occurs
1538
                                                        if (result < 0) {
×
1539
                                                                reportError(ErrorMessageConstants.ERROR_DB_GRANT_PRIV, DEFAULT_PAGE);
×
1540
                                                                return;
×
1541
                                                        } else {
1542
                                                                wizardModel.workLog.add("Granted user " + connectionUsername + " all privileges to database "
×
1543
                                                                        + wizardModel.databaseName);
1544
                                                        }
1545
                                                        
1546
                                                        addExecutedTask(WizardTask.CREATE_DB_USER);
×
1547
                                                } else {
×
1548
                                                        connectionUsername = wizardModel.currentDatabaseUsername;
×
1549
                                                        connectionPassword.setLength(0);
×
1550
                                                        connectionPassword.append(wizardModel.currentDatabasePassword);
×
1551
                                                }
1552
                                                
1553
                                                String finalDatabaseConnectionString = wizardModel.databaseConnection.replace("@DBNAME@",
×
1554
                                                        wizardModel.databaseName);
1555
                                                
1556
                                                finalDatabaseConnectionString = finalDatabaseConnectionString.replace("@APPLICATIONDATADIR@",
×
1557
                                                        OpenmrsUtil.getApplicationDataDirectory().replace("\\", "/"));
×
1558
                                                
1559
                                                // verify that the database connection works
1560
                                                if (!verifyConnection(connectionUsername, connectionPassword.toString(),
×
1561
                                                        finalDatabaseConnectionString)) {
1562
                                                        setMessage("Verify that the database connection works");
×
1563
                                                        // redirect to setup page if we got an error
1564
                                                        reportError("Unable to connect to database", DEFAULT_PAGE);
×
1565
                                                        return;
×
1566
                                                }
1567
                                                
1568
                                                // save the properties for startup purposes
1569
                                                Properties runtimeProperties = new Properties();
×
1570
                                                
1571
                                                runtimeProperties.put("connection.url", finalDatabaseConnectionString);
×
1572
                                                runtimeProperties.put("connection.username", connectionUsername);
×
1573
                                                runtimeProperties.put("connection.password", connectionPassword.toString());
×
1574
                                                if (StringUtils.hasText(wizardModel.databaseDriver)) {
×
1575
                                                        runtimeProperties.put("connection.driver_class", wizardModel.databaseDriver);
×
1576
                                                }
1577
                                                if (finalDatabaseConnectionString.contains(DATABASE_POSTGRESQL)) {
×
1578
                                                        runtimeProperties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL82Dialect");
×
1579
                                                }
1580
                                                if (finalDatabaseConnectionString.contains(DATABASE_SQLSERVER)) {
×
1581
                                                        runtimeProperties.put("hibernate.dialect", "org.hibernate.dialect.SQLServerDialect");
×
1582
                                                }
1583
                                                if (finalDatabaseConnectionString.contains(DATABASE_H2)) {
×
1584
                                                        runtimeProperties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
×
1585
                                                }
1586
                                                if (finalDatabaseConnectionString.contains(DATABASE_MARIADB)) {
×
1587
                                                        runtimeProperties.put("hibernate.dialect", "org.hibernate.dialect.MariaDBDialect");
×
1588
                                                }
1589
                                                runtimeProperties.put("module.allow_web_admin", "" + wizardModel.moduleWebAdmin);
×
1590
                                                runtimeProperties.put("auto_update_database", "" + wizardModel.autoUpdateDatabase);
×
1591
                                                final Encoder base64 = Base64.getEncoder();
×
1592
                                                runtimeProperties.put(OpenmrsConstants.ENCRYPTION_VECTOR_RUNTIME_PROPERTY,
×
1593
                                                        new String(base64.encode(Security.generateNewInitVector()), StandardCharsets.UTF_8));
×
1594
                                                runtimeProperties.put(OpenmrsConstants.ENCRYPTION_KEY_RUNTIME_PROPERTY,
×
1595
                                                        new String(base64.encode(Security.generateNewSecretKey()), StandardCharsets.UTF_8));
×
1596
                                                
1597
                                                runtimeProperties.putAll(wizardModel.additionalPropertiesFromInstallationScript);
×
1598
                                                
1599
                                                Properties properties = Context.getRuntimeProperties();
×
1600
                                                properties.putAll(runtimeProperties);
×
1601
                                                runtimeProperties = properties;
×
1602

1603
                                                Context.setRuntimeProperties(runtimeProperties);
×
1604
                                                
1605
                                                /**
1606
                                                 * A callback class that prints out info about liquibase changesets
1607
                                                 */
1608
                                                class PrintingChangeSetExecutorCallback implements ChangeSetExecutorCallback {
1609
                                                        
1610
                                                        private int i = 1;
×
1611
                                                        
1612
                                                        private String message;
1613
                                                        
1614
                                                        public PrintingChangeSetExecutorCallback(String message) {
×
1615
                                                                this.message = message;
×
1616
                                                        }
×
1617
                                                        
1618
                                                        /**
1619
                                                         * @see ChangeSetExecutorCallback#executing(liquibase.changelog.ChangeSet, int)
1620
                                                         */
1621
                                                        @Override
1622
                                                        public void executing(ChangeSet changeSet, int numChangeSetsToRun) {
1623
                                                                setMessage(message + " (" + i++ + "/" + numChangeSetsToRun + "): Author: "
×
1624
                                                                        + changeSet.getAuthor() + " Comments: " + changeSet.getComments() + " Description: "
×
1625
                                                                        + changeSet.getDescription());
×
1626
                                                                float numChangeSetsToRunFloat = (float) numChangeSetsToRun;
×
1627
                                                                float j = (float) i;
×
1628
                                                                setCompletedPercentage(Math.round(j * 100 / numChangeSetsToRunFloat));
×
1629
                                                        }
×
1630
                                                        
1631
                                                }
1632
                                                
1633
                                                if (wizardModel.createTables) {
×
1634
                                                        log.debug("Creating tables");
×
1635
                                                        // use liquibase to create core data + tables
1636
                                                        try {
1637
                                                                String liquibaseSchemaFileName = changeLogVersionFinder.getLatestSchemaSnapshotFilename()
×
1638
                                                                        .get();
×
1639
                                                                String liquibaseCoreDataFileName = changeLogVersionFinder.getLatestCoreDataSnapshotFilename()
×
1640
                                                                        .get();
×
1641
                                                                
1642
                                                                setMessage("Executing " + liquibaseSchemaFileName);
×
1643
                                                                setExecutingTask(WizardTask.CREATE_TABLES);
×
1644
                                                                
1645
                                                                log.debug("executing Liquibase file '{}' ", liquibaseSchemaFileName);
×
1646
                                                                
1647
                                                                DatabaseUpdater.executeChangelog(liquibaseSchemaFileName,
×
1648
                                                                        new PrintingChangeSetExecutorCallback("OpenMRS schema file"));
1649
                                                                addExecutedTask(WizardTask.CREATE_TABLES);
×
1650
                                                                
1651
                                                                //reset for this task
1652
                                                                setCompletedPercentage(0);
×
1653
                                                                setExecutingTask(WizardTask.ADD_CORE_DATA);
×
1654
                                                                
1655
                                                                log.debug("executing Liquibase file '{}' ", liquibaseCoreDataFileName);
×
1656
                                                                
1657
                                                                DatabaseUpdater.executeChangelog(liquibaseCoreDataFileName,
×
1658
                                                                        new PrintingChangeSetExecutorCallback("OpenMRS core data file"));
1659
                                                                wizardModel.workLog.add("Created database tables and added core data");
×
1660
                                                                addExecutedTask(WizardTask.ADD_CORE_DATA);
×
1661
                                                                
1662
                                                        }
1663
                                                        catch (Exception e) {
×
1664
                                                                reportError(ErrorMessageConstants.ERROR_DB_CREATE_TABLES_OR_ADD_DEMO_DATA, DEFAULT_PAGE,
×
1665
                                                                        e.getMessage());
×
1666
                                                                log.warn("Error while trying to create tables and demo data", e);
×
1667
                                                        }
×
1668
                                                }
1669
                                                
1670
                                                if (wizardModel.importTestData) {
×
1671
                                                        try {
1672
                                                                setMessage("Importing test data");
×
1673
                                                                setExecutingTask(WizardTask.IMPORT_TEST_DATA);
×
1674
                                                                setCompletedPercentage(0);
×
1675
                                                                
1676
                                                                try {
1677
                                                                        InputStream inData = TestInstallUtil.getResourceInputStream(
×
1678
                                                                                wizardModel.remoteUrl + RELEASE_TESTING_MODULE_PATH + "generateTestDataSet.form",
1679
                                                                                wizardModel.remoteUsername, wizardModel.remotePassword);
1680
                                                                        
1681
                                                                        setCompletedPercentage(40);
×
1682
                                                                        setMessage("Loading imported test data...");
×
1683
                                                                        importTestDataSet(inData, finalDatabaseConnectionString, connectionUsername,
×
1684
                                                                                connectionPassword.toString());
×
1685
                                                                        wizardModel.workLog.add("Imported test data");
×
1686
                                                                        addExecutedTask(WizardTask.IMPORT_TEST_DATA);
×
1687
                                                                        
1688
                                                                        //reset the progress for the next task
1689
                                                                        setCompletedPercentage(0);
×
1690
                                                                        setMessage("Importing modules from remote server...");
×
1691
                                                                        setExecutingTask(WizardTask.ADD_MODULES);
×
1692
                                                                        
1693
                                                                        InputStream inModules = TestInstallUtil.getResourceInputStream(
×
1694
                                                                                wizardModel.remoteUrl + RELEASE_TESTING_MODULE_PATH + "getModules.htm",
1695
                                                                                wizardModel.remoteUsername, wizardModel.remotePassword);
1696
                                                                        
1697
                                                                        setCompletedPercentage(90);
×
1698
                                                                        setMessage("Adding imported modules...");
×
1699
                                                                        if (!TestInstallUtil.addZippedTestModules(inModules)) {
×
1700
                                                                                reportError(ErrorMessageConstants.ERROR_DB_UNABLE_TO_ADD_MODULES, DEFAULT_PAGE, "");
×
1701
                                                                                return;
×
1702
                                                                        } else {
1703
                                                                                wizardModel.workLog.add("Added Modules");
×
1704
                                                                                addExecutedTask(WizardTask.ADD_MODULES);
×
1705
                                                                        }
1706
                                                                }
1707
                                                                catch (APIAuthenticationException e) {
×
1708
                                                                        log.warn("Unable to authenticate as a User with the System Developer role");
×
1709
                                                                        reportError(ErrorMessageConstants.UPDATE_ERROR_UNABLE_AUTHENTICATE,
×
1710
                                                                                TESTING_REMOTE_DETAILS_SETUP, "");
1711
                                                                        return;
×
1712
                                                                }
×
1713
                                                        }
1714
                                                        catch (Exception e) {
×
1715
                                                                reportError(ErrorMessageConstants.ERROR_DB_IMPORT_TEST_DATA, DEFAULT_PAGE, e.getMessage());
×
1716
                                                                log.warn("Error while trying to import test data", e);
×
1717
                                                                return;
×
1718
                                                        }
×
1719
                                                }
1720
                                                
1721
                                                // update the database to the latest version
1722
                                                try {
1723
                                                        setMessage("Updating the database to the latest version");
×
1724
                                                        setCompletedPercentage(0);
×
1725
                                                        setExecutingTask(WizardTask.UPDATE_TO_LATEST);
×
1726
                                                        
1727
                                                        String version = null;
×
1728
                                                        
1729
                                                        if (wizardModel.createTables) {
×
1730
                                                                version = changeLogVersionFinder.getLatestSnapshotVersion().get();
×
1731
                                                        } else {
1732
                                                                version = changeLogDetective.getInitialLiquibaseSnapshotVersion(DatabaseUpdater.CONTEXT,
×
1733
                                                                        new DatabaseUpdaterLiquibaseProvider());
1734
                                                        }
1735
                                                        
1736
                                                        log.debug(
×
1737
                                                                "updating the database with versions of liquibase-update-to-latest files greater than '{}'",
1738
                                                                version);
1739
                                                        
1740
                                                        List<String> changelogs = changeLogVersionFinder
×
1741
                                                                .getUpdateFileNames(changeLogVersionFinder.getUpdateVersionsGreaterThan(version));
×
1742
                                                        
1743
                                                        for (String changelog : changelogs) {
×
1744
                                                                log.debug("applying Liquibase changelog '{}'", changelog);
×
1745
                                                                
1746
                                                                DatabaseUpdater.executeChangelog(changelog,
×
1747
                                                                        new PrintingChangeSetExecutorCallback("executing Liquibase changelog " + changelog));
1748
                                                        }
×
1749
                                                        addExecutedTask(WizardTask.UPDATE_TO_LATEST);
×
1750
                                                }
1751
                                                catch (Exception e) {
×
1752
                                                        reportError(ErrorMessageConstants.ERROR_DB_UPDATE_TO_LATEST, DEFAULT_PAGE, e.getMessage());
×
1753
                                                        log.warn("Error while trying to update to the latest database version", e);
×
1754
                                                        return;
×
1755
                                                }
×
1756
                                                
1757
                                                setExecutingTask(null);
×
1758
                                                setMessage("Starting OpenMRS");
×
1759
                                                
1760
                                                // start spring
1761
                                                // after this point, all errors need to also call: contextLoader.closeWebApplicationContext(event.getServletContext())
1762
                                                // logic copied from org.springframework.web.context.ContextLoaderListener
1763
                                                log.debug("Initializing WAC");
×
1764
                                                ContextLoader contextLoader = new ContextLoader();
×
1765
                                                contextLoader.initWebApplicationContext(filterConfig.getServletContext());
×
1766
                                                log.debug("Done initializing WAC");
×
1767
                                                
1768
                                                // output properties to the openmrs runtime properties file so that this wizard is not run again
1769
                                                FileOutputStream fos = null;
×
1770
                                                try {
1771
                                                        fos = new FileOutputStream(getRuntimePropertiesFile());
×
1772
                                                        OpenmrsUtil.storeProperties(runtimeProperties, fos,
×
1773
                                                                "Auto generated by OpenMRS initialization wizard");
1774
                                                        wizardModel.workLog.add("Saved runtime properties file " + getRuntimePropertiesFile());
×
1775
                                                        
1776
                                                        /*
1777
                                                         * Fix file readability permissions:
1778
                                                         * first revoke read permission from everyone, then set read permissions for only the user
1779
                                                         * there is no function to set specific readability for only one user
1780
                                                         * and revoke everyone else's, therefore this is the only way to accomplish this.
1781
                                                         */
1782
                                                        wizardModel.workLog.add("Adjusting file posix properties to user readonly");
×
1783
                                                        if (getRuntimePropertiesFile().setReadable(false, false)
×
1784
                                                                && getRuntimePropertiesFile().setReadable(true)) {
×
1785
                                                                wizardModel.workLog
×
1786
                                                                        .add("Successfully adjusted RuntimePropertiesFile to disallow world to read it");
×
1787
                                                        } else {
1788
                                                                wizardModel.workLog
×
1789
                                                                        .add("Unable to adjust RuntimePropertiesFile to disallow world to read it");
×
1790
                                                        }
1791
                                                        // don't need to catch errors here because we tested it at the beginning of the wizard
1792
                                                }
1793
                                                finally {
1794
                                                        if (fos != null) {
×
1795
                                                                fos.close();
×
1796
                                                        }
1797
                                                }
1798
                                                
1799
                                                Context.openSession();
×
1800
                                                
1801
                                                if (!"".equals(wizardModel.implementationId)) {
×
1802
                                                        try {
1803
                                                                Context.addProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
1804
                                                                Context.addProxyPrivilege(GET_GLOBAL_PROPERTIES);
×
1805
                                                                Context.addProxyPrivilege(PrivilegeConstants.MANAGE_CONCEPT_SOURCES);
×
1806
                                                                Context.addProxyPrivilege(PrivilegeConstants.GET_CONCEPT_SOURCES);
×
1807
                                                                Context.addProxyPrivilege(PrivilegeConstants.MANAGE_IMPLEMENTATION_ID);
×
1808
                                                                
1809
                                                                ImplementationId implId = new ImplementationId();
×
1810
                                                                implId.setName(wizardModel.implementationIdName);
×
1811
                                                                implId.setImplementationId(wizardModel.implementationId);
×
1812
                                                                implId.setPassphrase(wizardModel.implementationIdPassPhrase);
×
1813
                                                                implId.setDescription(wizardModel.implementationIdDescription);
×
1814
                                                                
1815
                                                                Context.getAdministrationService().setImplementationId(implId);
×
1816
                                                        }
1817
                                                        catch (Exception e) {
×
1818
                                                                reportError(ErrorMessageConstants.ERROR_SET_INPL_ID, DEFAULT_PAGE, e.getMessage());
×
1819
                                                                log.warn("Implementation ID could not be set.", e);
×
1820
                                                                Context.shutdown();
×
1821
                                                                WebModuleUtil.shutdownModules(filterConfig.getServletContext());
×
1822
                                                                contextLoader.closeWebApplicationContext(filterConfig.getServletContext());
×
1823
                                                                return;
×
1824
                                                        }
1825
                                                        finally {
1826
                                                                Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
1827
                                                                Context.removeProxyPrivilege(GET_GLOBAL_PROPERTIES);
×
1828
                                                                Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_CONCEPT_SOURCES);
×
1829
                                                                Context.removeProxyPrivilege(PrivilegeConstants.GET_CONCEPT_SOURCES);
×
1830
                                                                Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_IMPLEMENTATION_ID);
×
1831
                                                        }
1832
                                                }
1833
                                                
1834
                                                try {
1835
                                                        // change the admin user password from "test" to what they input above
1836
                                                        if (wizardModel.createTables) {
×
1837
                                                                try {
1838
                                                                        Context.addProxyPrivilege(GET_GLOBAL_PROPERTIES);
×
1839
                                                                        Context.authenticate(new UsernamePasswordCredentials("admin", "test"));
×
1840
                                                                        
1841
                                                                        Properties props = Context.getRuntimeProperties();
×
1842
                                                                        String initValue = props.getProperty(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY);
×
1843
                                                                        props.setProperty(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY, "false");
×
1844
                                                                        Context.setRuntimeProperties(props);
×
1845
                                                                        
1846
                                                                        Context.getUserService().changePassword("test", wizardModel.adminUserPassword);
×
1847
                                                                        
1848
                                                                        if (initValue == null) {
×
1849
                                                                                props.remove(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY);
×
1850
                                                                        } else {
1851
                                                                                props.setProperty(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY, initValue);
×
1852
                                                                        }
1853
                                                                        Context.setRuntimeProperties(props);
×
1854
                                                                        Context.logout();
×
1855
                                                                }
1856
                                                                catch (ContextAuthenticationException ex) {
×
1857
                                                                        log.info("No need to change admin password.", ex);
×
1858
                                                                }
1859
                                                                finally {
1860
                                                                        Context.removeProxyPrivilege(GET_GLOBAL_PROPERTIES);
×
1861
                                                                }
1862
                                                        }
1863
                                                }
1864
                                                catch (Exception e) {
×
1865
                                                        Context.shutdown();
×
1866
                                                        WebModuleUtil.shutdownModules(filterConfig.getServletContext());
×
1867
                                                        contextLoader.closeWebApplicationContext(filterConfig.getServletContext());
×
1868
                                                        reportError(ErrorMessageConstants.ERROR_COMPLETE_STARTUP, DEFAULT_PAGE, e.getMessage());
×
1869
                                                        log.warn("Unable to complete the startup.", e);
×
1870
                                                        return;
×
1871
                                                }
×
1872
                                                
1873
                                                try {
1874
                                                        // Update PostgreSQL Sequences after insertion of core data
1875
                                                        Context.getAdministrationService().updatePostgresSequence();
×
1876
                                                }
1877
                                                catch (Exception e) {
×
1878
                                                        log.warn("Not able to update PostgreSQL sequence. Startup failed for PostgreSQL", e);
×
1879
                                                        reportError(ErrorMessageConstants.ERROR_COMPLETE_STARTUP, DEFAULT_PAGE, e.getMessage());
×
1880
                                                        return;
×
1881
                                                }
×
1882
                                                
1883
                                                // set this so that the wizard isn't run again on next page load
1884
                                                Context.closeSession();
×
1885
                                                
1886
                                                // start openmrs
1887
                                                try {
1888
                                                        UpdateFilter.setUpdatesRequired(false);
×
1889
                                                        WebDaemon.startOpenmrs(filterConfig.getServletContext());
×
1890
                                                }
1891
                                                catch (DatabaseUpdateException updateEx) {
×
1892
                                                        log.warn("Error while running the database update file", updateEx);
×
1893
                                                        reportError(ErrorMessageConstants.ERROR_DB_UPDATE, DEFAULT_PAGE, updateEx.getMessage());
×
1894
                                                        return;
×
1895
                                                }
1896
                                                catch (InputRequiredException inputRequiredEx) {
×
1897
                                                        // TODO display a page looping over the required input and ask the user for each.
1898
                                                        //                 When done and the user and put in their say, call DatabaseUpdater.update(Map);
1899
                                                        //                with the user's question/answer pairs
1900
                                                        log.warn(
×
1901
                                                                "Unable to continue because user input is required for the db updates and we cannot do anything about that right now");
1902
                                                        reportError(ErrorMessageConstants.ERROR_INPUT_REQ, DEFAULT_PAGE);
×
1903
                                                        return;
×
1904
                                                }
1905
                                                catch (MandatoryModuleException mandatoryModEx) {
×
1906
                                                        log.warn(
×
1907
                                                                "A mandatory module failed to start. Fix the error or unmark it as mandatory to continue.",
1908
                                                                mandatoryModEx);
1909
                                                        reportError(ErrorMessageConstants.ERROR_MANDATORY_MOD_REQ, DEFAULT_PAGE,
×
1910
                                                                mandatoryModEx.getMessage());
×
1911
                                                        return;
×
1912
                                                }
×
1913
                                                
1914
                                                // TODO catch openmrs errors here and drop the user back out to the setup screen
1915
                                                
1916
                                        }
1917
                                        catch (IOException e) {
×
1918
                                                reportError(ErrorMessageConstants.ERROR_COMPLETE_STARTUP, DEFAULT_PAGE, e.getMessage());
×
1919
                                        }
1920
                                        finally {
1921
                                                if (!hasErrors()) {
×
1922
                                                        // set this so that the wizard isn't run again on next page load
1923
                                                        setInitializationComplete(true);
×
1924
                                                        // we should also try to store selected by user language
1925
                                                        // if user wants to system will do it for him 
1926
                                                        FilterUtil.storeLocale(wizardModel.localeToSave);
×
1927
                                                }
1928
                                                setInstallationStarted(false);
×
1929
                                        }
1930
                                }
×
1931
                        };
1932
                        
1933
                        future = OpenmrsThreadPoolHolder.threadExecutor.submit(() -> { r.run(); return null; });
×
1934
                }
×
1935
        }
1936
        
1937
        /**
1938
         * Convenience method that loads the database driver
1939
         *
1940
         * @param connection the database connection string
1941
         * @param databaseDriver the database driver class name to load
1942
         * @return the loaded driver string
1943
         */
1944
        public static String loadDriver(String connection, String databaseDriver) {
1945
                String loadedDriverString = null;
1 ✔
1946
                try {
1947
                        loadedDriverString = DatabaseUtil.loadDatabaseDriver(connection, databaseDriver);
1 ✔
1948
                        log.info("using database driver :" + loadedDriverString);
1 ✔
1949
                }
1950
                catch (ClassNotFoundException e) {
×
1951
                        log.error("The given database driver class was not found. "
×
1952
                                + "Please ensure that the database driver jar file is on the class path "
1953
                                + "(like in the webapp's lib folder)");
1954
                }
1 ✔
1955
                
1956
                return loadedDriverString;
1 ✔
1957
        }
1958
        
1959
        /**
1960
         * Utility method that checks if there is a runtime properties file containing database connection
1961
         * credentials
1962
         *
1963
         * @return
1964
         */
1965
        private static boolean skipDatabaseSetupPage() {
1966
                Properties props = OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME);
1 ✔
1967
                return (props != null && StringUtils.hasText(props.getProperty("connection.url"))
1 ✔
1968
                        && StringUtils.hasText(props.getProperty("connection.username"))
×
1969
                        && StringUtils.hasText(props.getProperty("connection.password")));
1 ✔
1970
        }
1971
        
1972
        /**
1973
         * Utility methods that checks if the user clicked the back image
1974
         *
1975
         * @param httpRequest
1976
         * @return
1977
         */
1978
        private static boolean goBack(HttpServletRequest httpRequest) {
1979
                return "Back".equals(httpRequest.getParameter("back"))
1 ✔
1980
                        || (httpRequest.getParameter("back.x") != null && httpRequest.getParameter("back.y") != null);
1 ✔
1981
        }
1982
        
1983
        private String normalizeEnvVariableKey(String envVarKey) {
1984
                if (NON_NORMALIZED_KEYS.contains(envVarKey)) {
1 ✔
1985
                        return envVarKey.toLowerCase();
1 ✔
1986
                }
1987
                return envVarKey.toLowerCase().replace('_', '.');
1 ✔
1988
        }
1989

1990
        protected Map<String, String> getEnvironmentVariables() {
1991
                return System.getenv();
1 ✔
1992
        }
1993

1994
        /**
1995
         * Convenience method to get custom installation script
1996
         *
1997
         * @return Properties from custom installation script or empty if none specified
1998
         * @throws RuntimeException if path to installation script is invalid
1999
         */
2000
        protected Properties getInstallationScript() {
2001
                Properties prop = new Properties();
1 ✔
2002
                
2003
                String fileName = System.getProperty("OPENMRS_INSTALLATION_SCRIPT");
1 ✔
2004
                if (fileName == null) {
1 ✔
2005
                        return prop;
×
2006
                }
2007
                if (fileName.startsWith("classpath:")) {
1 ✔
2008
                        fileName = fileName.substring(10);
×
2009
                        InputStream input = null;
×
2010
                        try {
2011
                                input = getClass().getClassLoader().getResourceAsStream(fileName);
×
2012
                                if (input == null) {
×
2013
                                        return null;
×
2014
                                }
2015
                                prop.load(input);
×
2016
                                log.info("Using installation script from classpath: {}", fileName);
×
2017
                                
2018
                                input.close();
×
2019
                        }
2020
                        catch (IOException ex) {
×
2021
                                log.error("Failed to load installation script from classpath: {}", fileName, ex);
×
2022
                                throw new RuntimeException(ex);
×
2023
                        }
2024
                        finally {
2025
                                IOUtils.closeQuietly(input);
×
2026
                        }
2027
                } else {
×
2028
                        File file = new File(fileName);
1 ✔
2029
                        if (file.exists()) {
1 ✔
2030
                                InputStream input = null;
1 ✔
2031
                                try {
2032
                                        input = new FileInputStream(fileName);
1 ✔
2033
                                        prop.load(input);
1 ✔
2034
                                        log.info("Using installation script from absolute path: {}", file.getAbsolutePath());
1 ✔
2035
                                        
2036
                                        input.close();
1 ✔
2037
                                }
2038
                                catch (IOException ex) {
×
2039
                                        log.error("Failed to load installation script from absolute path: {}", file.getAbsolutePath(), ex);
×
2040
                                        throw new RuntimeException(ex);
×
2041
                                }
2042
                                finally {
2043
                                        IOUtils.closeQuietly(input);
1 ✔
2044
                                }
2045
                        }
2046
                }
2047
                return prop;
1 ✔
2048
        }
2049

2050
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc