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

openmrs / openmrs-core / 21724477650

05 Feb 2026 06:57PM UTC coverage: 63.772% (+0.1%) from 63.633%
21724477650

push

github

ibacher
Fix some serious errors in the ThreadSafeCircularFifoQueue (#5746)

6 of 6 new or added lines in 1 file covered. (100.0%)

770 existing lines in 12 files now uncovered.

21870 of 34294 relevant lines covered (63.77%)

0.64 hits per line

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

0.0
/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.Base64;
26
import java.util.Base64.Encoder;
27
import java.util.HashMap;
28
import java.util.HashSet;
29
import java.util.List;
30
import java.util.Locale;
31
import java.util.Map;
32
import java.util.Properties;
33
import java.util.Random;
34
import java.util.Set;
35
import java.util.zip.ZipInputStream;
36
import javax.servlet.FilterChain;
37
import javax.servlet.FilterConfig;
38
import javax.servlet.ServletException;
39
import javax.servlet.ServletRequest;
40
import javax.servlet.ServletResponse;
41
import javax.servlet.http.HttpServletRequest;
42
import javax.servlet.http.HttpServletResponse;
43

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

80
/**
81
 * This is the first filter that is processed. It is only active when starting OpenMRS for the very
82
 * first time. It will redirect all requests to the {@link WebConstants#SETUP_PAGE_URL} if the
83
 * {@link Listener} wasn't able to find any runtime properties
84
 */
UNCOV
85
public class InitializationFilter extends StartupFilter {
×
86
        
UNCOV
87
        private static final org.slf4j.Logger log = LoggerFactory.getLogger(InitializationFilter.class);
×
88
        
89
        private static final String DATABASE_POSTGRESQL = "postgresql";
90
        
91
        private static final String DATABASE_MYSQL = "mysql";
92
        
93
        private static final String DATABASE_SQLSERVER = "sqlserver";
94
        
95
        private static final String DATABASE_H2 = "h2";
96
        
97
        private static final String LIQUIBASE_DEMO_DATA = "liquibase-demo-data.xml";
98
        
99
        /**
100
         * The very first page of wizard, that asks user for select his preferred language
101
         */
102
        private static final String CHOOSE_LANG = "chooselang.vm";
103
        
104
        /**
105
         * The second page of the wizard that asks for simple or advanced installation.
106
         */
107
        private static final String INSTALL_METHOD = "installmethod.vm";
108
        
109
        /**
110
         * The simple installation setup page.
111
         */
112
        private static final String SIMPLE_SETUP = "simplesetup.vm";
113
        
114
        /**
115
         * The first page of the advanced installation of the wizard that asks for a current or past
116
         * database
117
         */
118
        private static final String DATABASE_SETUP = "databasesetup.vm";
119
        
120
        /**
121
         * The page from where the user specifies the url to a remote system, username and password
122
         */
123
        private static final String TESTING_REMOTE_DETAILS_SETUP = "remotedetails.vm";
124
        
125
        /**
126
         * The velocity macro page to redirect to if an error occurs or on initial startup
127
         */
128
        private static final String DEFAULT_PAGE = CHOOSE_LANG;
129
        
130
        /**
131
         * This page asks whether database tables/demo data should be inserted and what the
132
         * username/password that will be put into the runtime properties is
133
         */
134
        private static final String DATABASE_TABLES_AND_USER = "databasetablesanduser.vm";
135
        
136
        /**
137
         * This page lets the user define the admin user
138
         */
139
        private static final String ADMIN_USER_SETUP = "adminusersetup.vm";
140
        
141
        /**
142
         * This page lets the user pick an implementation id
143
         */
144
        private static final String IMPLEMENTATION_ID_SETUP = "implementationidsetup.vm";
145
        
146
        /**
147
         * This page asks for settings that will be put into the runtime properties files
148
         */
149
        private static final String OTHER_RUNTIME_PROPS = "otherruntimeproperties.vm";
150
        
151
        /**
152
         * A page that tells the user that everything is collected and will now be processed
153
         */
154
        private static final String WIZARD_COMPLETE = "wizardcomplete.vm";
155
        
156
        /**
157
         * A page that lists off what is happening while it is going on. This page has ajax that callst he
158
         * {@value #PROGRESS_VM_AJAXREQUEST} page
159
         */
160
        private static final String PROGRESS_VM = "progress.vm";
161
        
162
        /**
163
         * This url is called by javascript to get the status of the install
164
         */
165
        private static final String PROGRESS_VM_AJAXREQUEST = "progress.vm.ajaxRequest";
166
        
167
        public static final String RELEASE_TESTING_MODULE_PATH = "/module/releasetestinghelper/";
168

169
        /**
170
         * This tracks the properties that we use in the installation wizard. Properties not defined here will be copied
171
         * to the runtime properties, allowing us to pre-define certain runtime settings.
172
         */
173
        private static final Set<String> INSTALLATION_WIZARD_PROPERTIES;
174
        static {
UNCOV
175
                INSTALLATION_WIZARD_PROPERTIES = new HashSet<>();
×
UNCOV
176
                INSTALLATION_WIZARD_PROPERTIES.add("install_method");
×
UNCOV
177
                INSTALLATION_WIZARD_PROPERTIES.add("connection.url");
×
UNCOV
178
                INSTALLATION_WIZARD_PROPERTIES.add("connection.driver_class");
×
UNCOV
179
                INSTALLATION_WIZARD_PROPERTIES.add("connection.username");
×
UNCOV
180
                INSTALLATION_WIZARD_PROPERTIES.add("connection.password");
×
181
                INSTALLATION_WIZARD_PROPERTIES.add("has_current_openmrs_database");
×
UNCOV
182
                INSTALLATION_WIZARD_PROPERTIES.add("create_database_username");
×
UNCOV
183
                INSTALLATION_WIZARD_PROPERTIES.add("create_database_password");
×
UNCOV
184
                INSTALLATION_WIZARD_PROPERTIES.add("create_tables");
×
UNCOV
185
                INSTALLATION_WIZARD_PROPERTIES.add("add_demo_data");
×
UNCOV
186
                INSTALLATION_WIZARD_PROPERTIES.add("module_web_admin");
×
UNCOV
187
                INSTALLATION_WIZARD_PROPERTIES.add("auto_update_database");
×
UNCOV
188
                INSTALLATION_WIZARD_PROPERTIES.add("admin_user_password");
×
189
        }
190
        
191
        /**
192
         * The model object that holds all the properties that the rendered templates use. All attributes on
193
         * this object are made available to all templates via reflection in the
194
         * {@link org.openmrs.web.filter.StartupFilter#renderTemplate(String, Map, HttpServletResponse)} method.
195
         */
UNCOV
196
        private InitializationWizardModel wizardModel = null;
×
197
        
198
        private InitializationCompletion initJob;
199
        
200
        /**
201
         * Variable set to true as soon as the installation begins and set to false when the process ends
202
         * This thread should only be accesses through the synchronized method.
203
         */
204
        private static boolean isInstallationStarted = false;
×
205
        
206
        // the actual driver loaded by the DatabaseUpdater class
207
        private String loadedDriverString;
208
        
209
        /**
210
         * Variable set at the end of the wizard when spring is being restarted
211
         */
212
        private static boolean initializationComplete = false;
×
213
        
214
        protected synchronized void setInitializationComplete(boolean initializationComplete) {
215
                InitializationFilter.initializationComplete = initializationComplete;
×
UNCOV
216
        }
×
217
        
218
        /**
219
         * Called by {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} on GET requests
220
         *
221
         * @param httpRequest
222
         * @param httpResponse
223
         */
224
        @Override
225
        protected void doGet(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
226
                throws IOException, ServletException {
227
                loadInstallationScriptIfPresent();
×
228
                
229
                // we need to save current user language in references map since it will be used when template
230
                // will be rendered
231
                if (httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE) == null) {
×
UNCOV
232
                        checkLocaleAttributesForFirstTime(httpRequest);
×
233
                }
234
                
235
                Map<String, Object> referenceMap = new HashMap<>();
×
236
                String page = httpRequest.getParameter("page");
×
237
                
238
                referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE, httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
×
239
                
240
                httpResponse.setHeader("Cache-Control", "no-cache");
×
241
                
242
                // if any body has already started installation and this is not an ajax request for the progress
243
                if (isInstallationStarted() && !PROGRESS_VM_AJAXREQUEST.equals(page)) {
×
UNCOV
244
                        referenceMap.put("isInstallationStarted", true);
×
UNCOV
245
                        httpResponse.setContentType("text/html");
×
246
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
×
247
                } else if (PROGRESS_VM_AJAXREQUEST.equals(page)) {
×
248
                        httpResponse.setContentType("text/json");
×
249
                        Map<String, Object> result = new HashMap<>();
×
250
                        if (initJob != null) {
×
251
                                result.put("hasErrors", initJob.hasErrors());
×
252
                                if (initJob.hasErrors()) {
×
253
                                        result.put("errorPage", initJob.getErrorPage());
×
254
                                        errors.putAll(initJob.getErrors());
×
255
                                }
256
                                
UNCOV
257
                                result.put("initializationComplete", isInitializationComplete());
×
UNCOV
258
                                result.put("message", initJob.getMessage());
×
UNCOV
259
                                result.put("actionCounter", initJob.getStepsComplete());
×
260
                                if (!isInitializationComplete()) {
×
UNCOV
261
                                        result.put("executingTask", initJob.getExecutingTask());
×
262
                                        result.put("executedTasks", initJob.getExecutedTasks());
×
263
                                        result.put("completedPercentage", initJob.getCompletedPercentage());
×
264
                                }
265
                                
UNCOV
266
                                addLogLinesToResponse(result);
×
267
                        }
268
                        
269
                        PrintWriter writer = httpResponse.getWriter();
×
UNCOV
270
                        writer.write(toJSONString(result));
×
271
                        writer.close();
×
272
                } else if (InitializationWizardModel.INSTALL_METHOD_AUTO.equals(wizardModel.installMethod)
×
UNCOV
273
                        || httpRequest.getServletPath().equals("/" + AUTO_RUN_OPENMRS)) {
×
274
                        autoRunOpenMRS(httpRequest);
×
275
                        referenceMap.put("isInstallationStarted", true);
×
276
                        httpResponse.setContentType("text/html");
×
277
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
×
UNCOV
278
                } else if (page == null) {
×
UNCOV
279
                        httpResponse.setContentType("text/html");// if any body has already started installation
×
280
                        
281
                        //If someone came straight here without setting the hidden page input,
282
                        // then we need to clear out all the passwords
UNCOV
283
                        clearPasswords();
×
284
                        
285
                        renderTemplate(DEFAULT_PAGE, referenceMap, httpResponse);
×
UNCOV
286
                } else if (INSTALL_METHOD.equals(page)) {
×
287
                        // get props and render the second page
288
                        File runtimeProperties = getRuntimePropertiesFile();
×
289
                        
290
                        if (!runtimeProperties.exists()) {
×
291
                                try {
UNCOV
292
                                        runtimeProperties.createNewFile();
×
293
                                        // reset the error objects in case of refresh
UNCOV
294
                                        wizardModel.canCreate = true;
×
UNCOV
295
                                        wizardModel.cannotCreateErrorMessage = "";
×
296
                                }
UNCOV
297
                                catch (IOException io) {
×
UNCOV
298
                                        wizardModel.canCreate = false;
×
UNCOV
299
                                        wizardModel.cannotCreateErrorMessage = io.getMessage();
×
300
                                }
×
301
                                
302
                                // check this before deleting the file again
303
                                wizardModel.canWrite = runtimeProperties.canWrite();
×
304
                                
305
                                // delete the file again after testing the create/write
306
                                // so that if the user stops the webapp before finishing
307
                                // this wizard, they can still get back into it
UNCOV
308
                                runtimeProperties.delete();
×
309
                                
310
                        } else {
311
                                wizardModel.canWrite = runtimeProperties.canWrite();
×
312
                                
313
                                wizardModel.databaseConnection = Context.getRuntimeProperties().getProperty("connection.url",
×
314
                                        wizardModel.databaseConnection);
315
                                
UNCOV
316
                                wizardModel.currentDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username",
×
317
                                        wizardModel.currentDatabaseUsername);
318
                                
UNCOV
319
                                wizardModel.currentDatabasePassword = Context.getRuntimeProperties().getProperty("connection.password",
×
320
                                        wizardModel.currentDatabasePassword);
321
                        }
322
                        
UNCOV
323
                        wizardModel.runtimePropertiesPath = runtimeProperties.getAbsolutePath();
×
324
                        
325
                        // do step one of the wizard
326
                        httpResponse.setContentType("text/html");
×
UNCOV
327
                        renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
×
328
                }
329
        }
×
330
        
331
        private void loadInstallationScriptIfPresent() {
UNCOV
332
                Properties script = getInstallationScript();
×
UNCOV
333
                if (!script.isEmpty()) {
×
334
                        wizardModel.installMethod = script.getProperty("install_method", wizardModel.installMethod);
×
335
                        
336
                        wizardModel.databaseConnection = script.getProperty("connection.url", wizardModel.databaseConnection);
×
UNCOV
337
                        wizardModel.databaseDriver = script.getProperty("connection.driver_class", wizardModel.databaseDriver);
×
338
                        wizardModel.currentDatabaseUsername = script.getProperty("connection.username",
×
339
                                wizardModel.currentDatabaseUsername);
UNCOV
340
                        wizardModel.currentDatabasePassword = script.getProperty("connection.password",
×
341
                                wizardModel.currentDatabasePassword);
342
                        
343
                        String hasCurrentOpenmrsDatabase = script.getProperty("has_current_openmrs_database");
×
UNCOV
344
                        if (hasCurrentOpenmrsDatabase != null) {
×
UNCOV
345
                                wizardModel.hasCurrentOpenmrsDatabase = Boolean.parseBoolean(hasCurrentOpenmrsDatabase);
×
346
                        }
347
                        wizardModel.createDatabaseUsername = script.getProperty("create_database_username",
×
348
                                wizardModel.createDatabaseUsername);
UNCOV
349
                        wizardModel.createDatabasePassword = script.getProperty("create_database_password",
×
350
                                wizardModel.createDatabasePassword);
351
                        
352
                        String createTables = script.getProperty("create_tables");
×
353
                        if (createTables != null) {
×
UNCOV
354
                                wizardModel.createTables = Boolean.parseBoolean(createTables);
×
355
                        }
356
                        
UNCOV
357
                        String createDatabaseUser = script.getProperty("create_database_user");
×
358
                        if (createDatabaseUser != null) {
×
UNCOV
359
                                wizardModel.createDatabaseUser = Boolean.parseBoolean(createDatabaseUser);
×
360
                        }
361
                        wizardModel.createUserUsername = script.getProperty("create_user_username", wizardModel.createUserUsername);
×
362
                        wizardModel.createUserPassword = script.getProperty("create_user_password", wizardModel.createUserPassword);
×
363
                        
364
                        String addDemoData = script.getProperty("add_demo_data");
×
365
                        if (addDemoData != null) {
×
366
                                wizardModel.addDemoData = Boolean.parseBoolean(addDemoData);
×
367
                        }
368
                        
UNCOV
369
                        String moduleWebAdmin = script.getProperty("module_web_admin");
×
UNCOV
370
                        if (moduleWebAdmin != null) {
×
UNCOV
371
                                wizardModel.moduleWebAdmin = Boolean.parseBoolean(moduleWebAdmin);
×
372
                        }
373
                        
UNCOV
374
                        String autoUpdateDatabase = script.getProperty("auto_update_database");
×
UNCOV
375
                        if (autoUpdateDatabase != null) {
×
UNCOV
376
                                wizardModel.autoUpdateDatabase = Boolean.parseBoolean(autoUpdateDatabase);
×
377
                        }
378
                        
UNCOV
379
                        wizardModel.adminUserPassword = script.getProperty("admin_user_password", wizardModel.adminUserPassword);
×
380
                        
381
                        for (Map.Entry<Object, Object> entry : script.entrySet()) {
×
382
                                if (!INSTALLATION_WIZARD_PROPERTIES.contains(entry.getKey())) {
×
383
                                        wizardModel.additionalPropertiesFromInstallationScript.put(entry.getKey(), entry.getValue());
×
384
                                }
UNCOV
385
                        }
×
386
                }
387
        }
×
388
        
389
        private void clearPasswords() {
390
                wizardModel.databaseRootPassword = "";
×
391
                wizardModel.createDatabasePassword = "";
×
UNCOV
392
                wizardModel.createUserPassword = "";
×
393
                wizardModel.currentDatabasePassword = "";
×
UNCOV
394
                wizardModel.remotePassword = "";
×
395
        }
×
396
        
397
        /**
398
         * Called by {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} on POST requests
399
         *
400
         * @param httpRequest
401
         * @param httpResponse
402
         */
403
        @Override
404
        protected void doPost(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
405
                throws IOException, ServletException {
406
                String page = httpRequest.getParameter("page");
×
UNCOV
407
                Map<String, Object> referenceMap = new HashMap<>();
×
408
                // we need to save current user language in references map since it will be used when template
409
                // will be rendered
UNCOV
410
                if (httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE) != null) {
×
UNCOV
411
                        referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE,
×
UNCOV
412
                                httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
×
413
                }
414
                
415
                // if any body has already started installation
UNCOV
416
                if (isInstallationStarted()) {
×
417
                        referenceMap.put("isInstallationStarted", true);
×
UNCOV
418
                        httpResponse.setContentType("text/html");
×
UNCOV
419
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
×
420
                        return;
×
421
                }
UNCOV
422
                if (DEFAULT_PAGE.equals(page)) {
×
423
                        // get props and render the first page
UNCOV
424
                        File runtimeProperties = getRuntimePropertiesFile();
×
UNCOV
425
                        if (!runtimeProperties.exists()) {
×
426
                                try {
427
                                        runtimeProperties.createNewFile();
×
428
                                        // reset the error objects in case of refresh
429
                                        wizardModel.canCreate = true;
×
430
                                        wizardModel.cannotCreateErrorMessage = "";
×
431
                                }
432
                                catch (IOException io) {
×
UNCOV
433
                                        wizardModel.canCreate = false;
×
434
                                        wizardModel.cannotCreateErrorMessage = io.getMessage();
×
UNCOV
435
                                }
×
436
                                // check this before deleting the file again
437
                                wizardModel.canWrite = runtimeProperties.canWrite();
×
438
                                
439
                                // delete the file again after testing the create/write
440
                                // so that if the user stops the webapp before finishing
441
                                // this wizard, they can still get back into it
442
                                runtimeProperties.delete();
×
443
                        } else {
444
                                wizardModel.canWrite = runtimeProperties.canWrite();
×
445
                                
446
                                wizardModel.databaseConnection = Context.getRuntimeProperties().getProperty("connection.url",
×
447
                                        wizardModel.databaseConnection);
448
                                
449
                                wizardModel.currentDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username",
×
450
                                        wizardModel.currentDatabaseUsername);
451
                                
452
                                wizardModel.currentDatabasePassword = Context.getRuntimeProperties().getProperty("connection.password",
×
453
                                        wizardModel.currentDatabasePassword);
454
                        }
455
                        
456
                        wizardModel.runtimePropertiesPath = runtimeProperties.getAbsolutePath();
×
457
                        
458
                        checkLocaleAttributes(httpRequest);
×
UNCOV
459
                        referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE,
×
460
                                httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
×
461
                        log.info("Locale stored in session is " + httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
×
462
                        
463
                        httpResponse.setContentType("text/html");
×
464
                        // otherwise do step one of the wizard
465
                        renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
×
UNCOV
466
                } else if (INSTALL_METHOD.equals(page)) {
×
UNCOV
467
                        if (goBack(httpRequest)) {
×
468
                                referenceMap.put(FilterUtil.REMEMBER_ATTRIBUTE,
×
UNCOV
469
                                        httpRequest.getSession().getAttribute(FilterUtil.REMEMBER_ATTRIBUTE) != null);
×
UNCOV
470
                                referenceMap.put(FilterUtil.LOCALE_ATTRIBUTE,
×
471
                                        httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE));
×
UNCOV
472
                                renderTemplate(CHOOSE_LANG, referenceMap, httpResponse);
×
473
                                return;
×
474
                        }
UNCOV
475
                        wizardModel.installMethod = httpRequest.getParameter("install_method");
×
476
                        if (InitializationWizardModel.INSTALL_METHOD_SIMPLE.equals(wizardModel.installMethod)) {
×
477
                                page = SIMPLE_SETUP;
×
UNCOV
478
                        } else if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
×
UNCOV
479
                                page = TESTING_REMOTE_DETAILS_SETUP;
×
480
                                wizardModel.currentStepNumber = 1;
×
481
                                wizardModel.numberOfSteps = skipDatabaseSetupPage() ? 1 : 3;
×
482
                        } else {
483
                                page = DATABASE_SETUP;
×
484
                                wizardModel.currentStepNumber = 1;
×
UNCOV
485
                                wizardModel.numberOfSteps = 5;
×
486
                        }
UNCOV
487
                        renderTemplate(page, referenceMap, httpResponse);
×
488
                } // simple method
489
                else if (SIMPLE_SETUP.equals(page)) {
×
UNCOV
490
                        if (goBack(httpRequest)) {
×
491
                                renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
×
UNCOV
492
                                return;
×
493
                        }
UNCOV
494
                        wizardModel.databaseConnection = httpRequest.getParameter("database_connection");
×
495
                        ;
496
                        
UNCOV
497
                        wizardModel.createDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username",
×
498
                                wizardModel.createDatabaseUsername);
499
                        
500
                        wizardModel.createUserUsername = wizardModel.createDatabaseUsername;
×
501
                        
502
                        wizardModel.databaseRootPassword = httpRequest.getParameter("database_root_password");
×
503
                        checkForEmptyValue(wizardModel.databaseRootPassword, errors, ErrorMessageConstants.ERROR_DB_PSDW_REQ);
×
504
                        
505
                        wizardModel.hasCurrentOpenmrsDatabase = false;
×
506
                        wizardModel.createTables = true;
×
507
                        // default wizardModel.databaseName is openmrs
508
                        // default wizardModel.createDatabaseUsername is root
UNCOV
509
                        wizardModel.createDatabasePassword = wizardModel.databaseRootPassword;
×
510
                        wizardModel.addDemoData = "yes".equals(httpRequest.getParameter("add_demo_data"));
×
511
                        
512
                        wizardModel.hasCurrentDatabaseUser = false;
×
513
                        wizardModel.createDatabaseUser = true;
×
514
                        // default wizardModel.createUserUsername is root
UNCOV
515
                        wizardModel.createUserPassword = wizardModel.databaseRootPassword;
×
516
                        
UNCOV
517
                        wizardModel.moduleWebAdmin = true;
×
518
                        wizardModel.autoUpdateDatabase = false;
×
519
                        
UNCOV
520
                        wizardModel.adminUserPassword = InitializationWizardModel.ADMIN_DEFAULT_PASSWORD;
×
521
                        
522
                        createSimpleSetup(httpRequest.getParameter("database_root_password"), httpRequest.getParameter("add_demo_data"));
×
523
                        
524
                        try {
525
                                loadedDriverString = DatabaseUtil.loadDatabaseDriver(wizardModel.databaseConnection,
×
526
                                        wizardModel.databaseDriver);
527
                        }
528
                        catch (ClassNotFoundException e) {
×
529
                                errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
×
530
                                renderTemplate(page, referenceMap, httpResponse);
×
531
                                return;
×
UNCOV
532
                        }
×
533
                        
UNCOV
534
                        if (errors.isEmpty()) {
×
UNCOV
535
                                page = WIZARD_COMPLETE;
×
536
                        }
UNCOV
537
                        renderTemplate(page, referenceMap, httpResponse);
×
538
                } // step one
539
                else if (DATABASE_SETUP.equals(page)) {
×
540
                        if (goBack(httpRequest)) {
×
541
                                wizardModel.currentStepNumber -= 1;
×
UNCOV
542
                                if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
×
UNCOV
543
                                        renderTemplate(TESTING_REMOTE_DETAILS_SETUP, referenceMap, httpResponse);
×
544
                                } else {
UNCOV
545
                                        renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
×
546
                                }
UNCOV
547
                                return;
×
548
                        }
549
                        
550
                        wizardModel.databaseConnection = httpRequest.getParameter("database_connection");
×
551
                        checkForEmptyValue(wizardModel.databaseConnection, errors, ErrorMessageConstants.ERROR_DB_CONN_REQ);
×
552
                        
UNCOV
553
                        wizardModel.databaseDriver = httpRequest.getParameter("database_driver");
×
554
                        checkForEmptyValue(wizardModel.databaseConnection, errors, ErrorMessageConstants.ERROR_DB_DRIVER_REQ);
×
555
                        
556
                        loadedDriverString = loadDriver(wizardModel.databaseConnection, wizardModel.databaseDriver);
×
557
                        if (!StringUtils.hasText(loadedDriverString)) {
×
UNCOV
558
                                errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
×
UNCOV
559
                                renderTemplate(page, referenceMap, httpResponse);
×
560
                                return;
×
561
                        }
562
                        
563
                        //TODO make each bit of page logic a (unit testable) method
564
                        
565
                        // asked the user for their desired database name
566
                        
UNCOV
567
                        if ("yes".equals(httpRequest.getParameter("current_openmrs_database"))) {
×
UNCOV
568
                                wizardModel.databaseName = httpRequest.getParameter("openmrs_current_database_name");
×
UNCOV
569
                                checkForEmptyValue(wizardModel.databaseName, errors, ErrorMessageConstants.ERROR_DB_CURR_NAME_REQ);
×
570
                                wizardModel.hasCurrentOpenmrsDatabase = true;
×
571
                                // TODO check to see if this is an active database
572
                                
573
                        } else {
574
                                // mark this wizard as a "to create database" (done at the end)
575
                                wizardModel.hasCurrentOpenmrsDatabase = false;
×
576
                                
577
                                wizardModel.createTables = true;
×
578
                                
UNCOV
579
                                wizardModel.databaseName = httpRequest.getParameter("openmrs_new_database_name");
×
UNCOV
580
                                checkForEmptyValue(wizardModel.databaseName, errors, ErrorMessageConstants.ERROR_DB_NEW_NAME_REQ);
×
581
                                // TODO create database now to check if its possible?
582
                                
UNCOV
583
                                wizardModel.createDatabaseUsername = httpRequest.getParameter("create_database_username");
×
UNCOV
584
                                checkForEmptyValue(wizardModel.createDatabaseUsername, errors, ErrorMessageConstants.ERROR_DB_USER_NAME_REQ);
×
585
                                wizardModel.createDatabasePassword = httpRequest.getParameter("create_database_password");
×
UNCOV
586
                                checkForEmptyValue(wizardModel.createDatabasePassword, errors, ErrorMessageConstants.ERROR_DB_USER_PSWD_REQ);
×
587
                        }
588
                        
589
                        if (errors.isEmpty()) {
×
UNCOV
590
                                page = DATABASE_TABLES_AND_USER;
×
591
                                
592
                                if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
×
UNCOV
593
                                        wizardModel.currentStepNumber = 3;
×
594
                                } else {
595
                                        wizardModel.currentStepNumber = 2;
×
596
                                }
597
                        }
598
                        
UNCOV
599
                        renderTemplate(page, referenceMap, httpResponse);
×
600
                        
601
                } // step two
602
                else if (DATABASE_TABLES_AND_USER.equals(page)) {
×
603
                        
UNCOV
604
                        if (goBack(httpRequest)) {
×
UNCOV
605
                                wizardModel.currentStepNumber -= 1;
×
606
                                renderTemplate(DATABASE_SETUP, referenceMap, httpResponse);
×
607
                                return;
×
608
                        }
609
                        
UNCOV
610
                        if (wizardModel.hasCurrentOpenmrsDatabase) {
×
611
                                wizardModel.createTables = "yes".equals(httpRequest.getParameter("create_tables"));
×
612
                        }
613
                        
UNCOV
614
                        wizardModel.addDemoData = "yes".equals(httpRequest.getParameter("add_demo_data"));
×
615
                        
616
                        if ("yes".equals(httpRequest.getParameter("current_database_user"))) {
×
617
                                wizardModel.currentDatabaseUsername = httpRequest.getParameter("current_database_username");
×
UNCOV
618
                                checkForEmptyValue(wizardModel.currentDatabaseUsername, errors,
×
619
                                        ErrorMessageConstants.ERROR_DB_CUR_USER_NAME_REQ);
620
                                wizardModel.currentDatabasePassword = httpRequest.getParameter("current_database_password");
×
621
                                checkForEmptyValue(wizardModel.currentDatabasePassword, errors,
×
622
                                        ErrorMessageConstants.ERROR_DB_CUR_USER_PSWD_REQ);
623
                                wizardModel.hasCurrentDatabaseUser = true;
×
624
                                wizardModel.createDatabaseUser = false;
×
625
                        } else {
626
                                wizardModel.hasCurrentDatabaseUser = false;
×
UNCOV
627
                                wizardModel.createDatabaseUser = true;
×
628
                                // asked for the root mysql username/password
629
                                wizardModel.createUserUsername = httpRequest.getParameter("create_user_username");
×
UNCOV
630
                                checkForEmptyValue(wizardModel.createUserUsername, errors, ErrorMessageConstants.ERROR_DB_USER_NAME_REQ);
×
UNCOV
631
                                wizardModel.createUserPassword = httpRequest.getParameter("create_user_password");
×
632
                                checkForEmptyValue(wizardModel.createUserPassword, errors, ErrorMessageConstants.ERROR_DB_USER_PSWD_REQ);
×
633
                        }
634
                        
635
                        if (errors.isEmpty()) { // go to next page
×
636
                                page = InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod) ? WIZARD_COMPLETE
×
637
                                        : OTHER_RUNTIME_PROPS;
638
                        }
639
                        
640
                        renderTemplate(page, referenceMap, httpResponse);
×
641
                } // step three
UNCOV
642
                else if (OTHER_RUNTIME_PROPS.equals(page)) {
×
643
                        
644
                        if (goBack(httpRequest)) {
×
645
                                renderTemplate(DATABASE_TABLES_AND_USER, referenceMap, httpResponse);
×
646
                                return;
×
647
                        }
648
                        
UNCOV
649
                        wizardModel.moduleWebAdmin = "yes".equals(httpRequest.getParameter("module_web_admin"));
×
650
                        wizardModel.autoUpdateDatabase = "yes".equals(httpRequest.getParameter("auto_update_database"));
×
651
                        
652
                        if (wizardModel.createTables) { // go to next page if they are creating tables
×
653
                                page = ADMIN_USER_SETUP;
×
654
                        } else { // skip a page
UNCOV
655
                                page = IMPLEMENTATION_ID_SETUP;
×
656
                        }
657
                        
UNCOV
658
                        renderTemplate(page, referenceMap, httpResponse);
×
659
                        
660
                } // optional step four
661
                else if (ADMIN_USER_SETUP.equals(page)) {
×
662
                        
663
                        if (goBack(httpRequest)) {
×
UNCOV
664
                                renderTemplate(OTHER_RUNTIME_PROPS, referenceMap, httpResponse);
×
665
                                return;
×
666
                        }
667
                        
UNCOV
668
                        wizardModel.adminUserPassword = httpRequest.getParameter("new_admin_password");
×
669
                        String adminUserConfirm = httpRequest.getParameter("new_admin_password_confirm");
×
670
                        
671
                        // throw back to admin user if passwords don't match
672
                        if (!wizardModel.adminUserPassword.equals(adminUserConfirm)) {
×
UNCOV
673
                                errors.put(ErrorMessageConstants.ERROR_DB_ADM_PSWDS_MATCH, null);
×
674
                                renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
×
675
                                return;
×
676
                        }
677
                        
678
                        // throw back if the user didn't put in a password
UNCOV
679
                        if ("".equals(wizardModel.adminUserPassword)) {
×
680
                                errors.put(ErrorMessageConstants.ERROR_DB_ADM_PSDW_EMPTY, null);
×
UNCOV
681
                                renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
×
UNCOV
682
                                return;
×
683
                        }
684
                        
685
                        try {
686
                                OpenmrsUtil.validatePassword("admin", wizardModel.adminUserPassword, "admin");
×
687
                        }
UNCOV
688
                        catch (PasswordException p) {
×
689
                                errors.put(ErrorMessageConstants.ERROR_DB_ADM_PSDW_WEAK, null);
×
690
                                renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
×
691
                                return;
×
692
                        }
×
693
                        
UNCOV
694
                        if (errors.isEmpty()) { // go to next page
×
695
                                page = IMPLEMENTATION_ID_SETUP;
×
696
                        }
697
                        
UNCOV
698
                        renderTemplate(page, referenceMap, httpResponse);
×
699
                        
700
                } // optional step five
×
UNCOV
701
                else if (IMPLEMENTATION_ID_SETUP.equals(page)) {
×
702
                        
UNCOV
703
                        if (goBack(httpRequest)) {
×
704
                                if (wizardModel.createTables) {
×
705
                                        renderTemplate(ADMIN_USER_SETUP, referenceMap, httpResponse);
×
706
                                } else {
707
                                        renderTemplate(OTHER_RUNTIME_PROPS, referenceMap, httpResponse);
×
708
                                }
UNCOV
709
                                return;
×
710
                        }
711
                        
UNCOV
712
                        wizardModel.implementationIdName = httpRequest.getParameter("implementation_name");
×
713
                        wizardModel.implementationId = httpRequest.getParameter("implementation_id");
×
UNCOV
714
                        wizardModel.implementationIdPassPhrase = httpRequest.getParameter("pass_phrase");
×
715
                        wizardModel.implementationIdDescription = httpRequest.getParameter("description");
×
716
                        
717
                        // throw back if the user-specified ID is invalid (contains ^ or |).
UNCOV
718
                        if (wizardModel.implementationId.indexOf('^') != -1 || wizardModel.implementationId.indexOf('|') != -1) {
×
719
                                errors.put(ErrorMessageConstants.ERROR_DB_IMPL_ID_REQ, null);
×
720
                                renderTemplate(IMPLEMENTATION_ID_SETUP, referenceMap, httpResponse);
×
721
                                return;
×
722
                        }
723
                        
724
                        if (errors.isEmpty()) { // go to next page
×
UNCOV
725
                                page = WIZARD_COMPLETE;
×
726
                        }
727
                        
728
                        renderTemplate(page, referenceMap, httpResponse);
×
729
                } else if (WIZARD_COMPLETE.equals(page)) {
×
730
                        
731
                        if (goBack(httpRequest)) {
×
732
                                
733
                                if (InitializationWizardModel.INSTALL_METHOD_SIMPLE.equals(wizardModel.installMethod)) {
×
734
                                        page = SIMPLE_SETUP;
×
UNCOV
735
                                } else if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
×
UNCOV
736
                                        if (skipDatabaseSetupPage()) {
×
737
                                                page = TESTING_REMOTE_DETAILS_SETUP;
×
738
                                        } else {
UNCOV
739
                                                page = DATABASE_TABLES_AND_USER;
×
740
                                        }
741
                                } else {
UNCOV
742
                                        page = IMPLEMENTATION_ID_SETUP;
×
743
                                }
UNCOV
744
                                renderTemplate(page, referenceMap, httpResponse);
×
745
                                return;
×
746
                        }
747
                        
748
                        wizardModel.tasksToExecute = new ArrayList<>();
×
749
                        createDatabaseTask();
×
750
                        if (InitializationWizardModel.INSTALL_METHOD_TESTING.equals(wizardModel.installMethod)) {
×
751
                                wizardModel.importTestData = true;
×
752
                                wizardModel.createTables = false;
×
UNCOV
753
                                wizardModel.addDemoData = false;
×
754
                                //if we have a runtime properties file
755
                                if (skipDatabaseSetupPage()) {
×
756
                                        wizardModel.hasCurrentOpenmrsDatabase = false;
×
757
                                        wizardModel.hasCurrentDatabaseUser = true;
×
UNCOV
758
                                        wizardModel.createDatabaseUser = false;
×
759
                                        Properties props = OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME);
×
UNCOV
760
                                        wizardModel.currentDatabaseUsername = props.getProperty("connection.username");
×
761
                                        wizardModel.currentDatabasePassword = props.getProperty("connection.password");
×
762
                                        wizardModel.createDatabaseUsername = wizardModel.currentDatabaseUsername;
×
UNCOV
763
                                        wizardModel.createDatabasePassword = wizardModel.currentDatabasePassword;
×
764
                                }
765
                                
766
                                wizardModel.tasksToExecute.add(WizardTask.IMPORT_TEST_DATA);
×
767
                                wizardModel.tasksToExecute.add(WizardTask.ADD_MODULES);
×
768
                        } else {
769
                                createTablesTask();
×
UNCOV
770
                                createDemoDataTask();
×
771
                        }
772
                        wizardModel.tasksToExecute.add(WizardTask.UPDATE_TO_LATEST);
×
773
                        
UNCOV
774
                        referenceMap.put("tasksToExecute", wizardModel.tasksToExecute);
×
UNCOV
775
                        startInstallation();
×
776
                        renderTemplate(PROGRESS_VM, referenceMap, httpResponse);
×
777
                } else if (TESTING_REMOTE_DETAILS_SETUP.equals(page)) {
×
778
                        if (goBack(httpRequest)) {
×
779
                                wizardModel.currentStepNumber -= 1;
×
780
                                renderTemplate(INSTALL_METHOD, referenceMap, httpResponse);
×
781
                                return;
×
782
                        }
783
                        
UNCOV
784
                        wizardModel.remoteUrl = httpRequest.getParameter("remoteUrl");
×
785
                        checkForEmptyValue(wizardModel.remoteUrl, errors, "install.testing.remote.url.required");
×
786
                        if (errors.isEmpty()) {
×
787
                                //Check if the remote system is running
788
                                if (TestInstallUtil.testConnection(wizardModel.remoteUrl)) {
×
789
                                        //Check if the test module is installed by connecting to its setting page
790
                                        if (TestInstallUtil
×
791
                                                .testConnection(wizardModel.remoteUrl.concat(RELEASE_TESTING_MODULE_PATH + "settings.htm"))) {
×
792
                                                
793
                                                wizardModel.remoteUsername = httpRequest.getParameter("username");
×
UNCOV
794
                                                wizardModel.remotePassword = httpRequest.getParameter("password");
×
UNCOV
795
                                                checkForEmptyValue(wizardModel.remoteUsername, errors, "install.testing.username.required");
×
796
                                                checkForEmptyValue(wizardModel.remotePassword, errors, "install.testing.password.required");
×
797
                                                
798
                                                if (errors.isEmpty()) {
×
799
                                                        //check if the username and password are valid
800
                                                        try {
UNCOV
801
                                                                TestInstallUtil.getResourceInputStream(
×
802
                                                                        wizardModel.remoteUrl + RELEASE_TESTING_MODULE_PATH + "verifycredentials.htm",
803
                                                                        wizardModel.remoteUsername, wizardModel.remotePassword);
804
                                                        }
805
                                                        catch (APIAuthenticationException e) {
×
UNCOV
806
                                                                log.debug("Error generated: ", e);
×
UNCOV
807
                                                                page = TESTING_REMOTE_DETAILS_SETUP;
×
808
                                                                errors.put(ErrorMessageConstants.UPDATE_ERROR_UNABLE_AUTHENTICATE, null);
×
UNCOV
809
                                                                renderTemplate(page, referenceMap, httpResponse);
×
UNCOV
810
                                                                return;
×
811
                                                        }
×
812
                                                        
813
                                                        //If we have a runtime properties file, get the database setup details from it
UNCOV
814
                                                        if (skipDatabaseSetupPage()) {
×
815
                                                                Properties props = OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME);
×
UNCOV
816
                                                                wizardModel.databaseConnection = props.getProperty("connection.url");
×
817
                                                                loadedDriverString = loadDriver(wizardModel.databaseConnection, wizardModel.databaseDriver);
×
UNCOV
818
                                                                if (!StringUtils.hasText(loadedDriverString)) {
×
UNCOV
819
                                                                        page = TESTING_REMOTE_DETAILS_SETUP;
×
UNCOV
820
                                                                        errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
×
821
                                                                        renderTemplate(page, referenceMap, httpResponse);
×
822
                                                                        return;
×
823
                                                                }
824
                                                                
UNCOV
825
                                                                wizardModel.databaseName = InitializationWizardModel.DEFAULT_DATABASE_NAME;
×
826
                                                                page = WIZARD_COMPLETE;
×
UNCOV
827
                                                        } else {
×
UNCOV
828
                                                                page = DATABASE_SETUP;
×
829
                                                                wizardModel.currentStepNumber = 2;
×
830
                                                        }
UNCOV
831
                                                        msgs.put("install.testing.testingModuleFound", null);
×
832
                                                } else {
UNCOV
833
                                                        renderTemplate(page, referenceMap, httpResponse);
×
UNCOV
834
                                                        return;
×
835
                                                }
836
                                        } else {
837
                                                errors.put("install.testing.noTestingModule", null);
×
838
                                        }
839
                                } else {
UNCOV
840
                                        errors.put("install.testing.invalidProductionUrl", new Object[] { wizardModel.remoteUrl });
×
841
                                }
842
                        }
843
                        
UNCOV
844
                        renderTemplate(page, referenceMap, httpResponse);
×
845
                }
846
        }
×
847
        
848
        private void startInstallation() {
849
                //if no one has run any installation
UNCOV
850
                if (!isInstallationStarted()) {
×
851
                        initJob = new InitializationCompletion();
×
852
                        setInstallationStarted(true);
×
UNCOV
853
                        initJob.start();
×
854
                }
855
        }
×
856
        
857
        private void createDemoDataTask() {
858
                if (wizardModel.addDemoData) {
×
UNCOV
859
                        wizardModel.tasksToExecute.add(WizardTask.ADD_DEMO_DATA);
×
860
                }
861
        }
×
862
        
863
        private void createTablesTask() {
864
                if (wizardModel.createTables) {
×
UNCOV
865
                        wizardModel.tasksToExecute.add(WizardTask.CREATE_TABLES);
×
UNCOV
866
                        wizardModel.tasksToExecute.add(WizardTask.ADD_CORE_DATA);
×
867
                }
868
        }
×
869
        
870
        private void createDatabaseTask() {
871
                if (!wizardModel.hasCurrentOpenmrsDatabase) {
×
UNCOV
872
                        wizardModel.tasksToExecute.add(WizardTask.CREATE_SCHEMA);
×
873
                }
UNCOV
874
                if (wizardModel.createDatabaseUser) {
×
875
                        wizardModel.tasksToExecute.add(WizardTask.CREATE_DB_USER);
×
876
                }
UNCOV
877
        }
×
878
        
879
        private void createSimpleSetup(String databaseRootPassword, String addDemoData) {
UNCOV
880
                setDatabaseNameIfInTestMode();
×
UNCOV
881
                wizardModel.databaseConnection = Context.getRuntimeProperties().getProperty("connection.url",
×
882
                        wizardModel.databaseConnection);
883
                
UNCOV
884
                wizardModel.createDatabaseUsername = Context.getRuntimeProperties().getProperty("connection.username",
×
885
                        wizardModel.createDatabaseUsername);
886
                
UNCOV
887
                wizardModel.createUserUsername = wizardModel.createDatabaseUsername;
×
888
                
889
                wizardModel.databaseRootPassword = databaseRootPassword;
×
UNCOV
890
                checkForEmptyValue(wizardModel.databaseRootPassword, errors, ErrorMessageConstants.ERROR_DB_PSDW_REQ);
×
891
                
892
                wizardModel.hasCurrentOpenmrsDatabase = false;
×
893
                wizardModel.createTables = true;
×
894
                // default wizardModel.databaseName is openmrs
895
                // default wizardModel.createDatabaseUsername is root
896
                wizardModel.createDatabasePassword = wizardModel.databaseRootPassword;
×
UNCOV
897
                wizardModel.addDemoData = "yes".equals(addDemoData);
×
898
                
899
                wizardModel.hasCurrentDatabaseUser = false;
×
UNCOV
900
                wizardModel.createDatabaseUser = true;
×
901
                // default wizardModel.createUserUsername is root
UNCOV
902
                wizardModel.createUserPassword = wizardModel.databaseRootPassword;
×
903
                
904
                wizardModel.moduleWebAdmin = true;
×
905
                wizardModel.autoUpdateDatabase = false;
×
906
                
907
                wizardModel.adminUserPassword = InitializationWizardModel.ADMIN_DEFAULT_PASSWORD;
×
908
        }
×
909
        
910
        private void setDatabaseNameIfInTestMode() {
911
                if (OpenmrsUtil.isTestMode()) {
×
912
                        wizardModel.databaseName = OpenmrsUtil.getOpenMRSVersionInTestMode();
×
913
                }
UNCOV
914
        }
×
915
        
916
        private void autoRunOpenMRS(HttpServletRequest httpRequest) {
UNCOV
917
                File runtimeProperties = getRuntimePropertiesFile();
×
UNCOV
918
                wizardModel.runtimePropertiesPath = runtimeProperties.getAbsolutePath();
×
919
                
UNCOV
920
                if (!InitializationWizardModel.INSTALL_METHOD_AUTO.equals(wizardModel.installMethod)) {
×
UNCOV
921
                        if (httpRequest.getParameter("database_user_name") != null) {
×
UNCOV
922
                                wizardModel.createDatabaseUsername = httpRequest.getParameter("database_user_name");
×
923
                        }
924
                        
UNCOV
925
                        createSimpleSetup(httpRequest.getParameter("database_root_password"), "yes");
×
926
                }
927
                
UNCOV
928
                checkLocaleAttributes(httpRequest);
×
929
                try {
930
                        loadedDriverString = DatabaseUtil.loadDatabaseDriver(wizardModel.databaseConnection, wizardModel.databaseDriver);
×
931
                }
932
                catch (ClassNotFoundException e) {
×
UNCOV
933
                        errors.put(ErrorMessageConstants.ERROR_DB_DRIVER_CLASS_REQ, null);
×
UNCOV
934
                        return;
×
UNCOV
935
                }
×
936
                wizardModel.tasksToExecute = new ArrayList<>();
×
937
                createDatabaseTask();
×
938
                createTablesTask();
×
UNCOV
939
                createDemoDataTask();
×
940
                wizardModel.tasksToExecute.add(WizardTask.UPDATE_TO_LATEST);
×
941
                startInstallation();
×
942
        }
×
943
        
944
        /**
945
         * This method should be called after the user has left wizard's first page (i.e. choose language).
946
         * It checks if user has changed any of locale related parameters and makes appropriate corrections
947
         * with filter's model or/and with locale attribute inside user's session.
948
         *
949
         * @param httpRequest the http request object
950
         */
951
        private void checkLocaleAttributes(HttpServletRequest httpRequest) {
UNCOV
952
                String localeParameter = httpRequest.getParameter(FilterUtil.LOCALE_ATTRIBUTE);
×
UNCOV
953
                Boolean rememberLocale = false;
×
954
                // we need to check if user wants that system will remember his selection of language
UNCOV
955
                if (httpRequest.getParameter(FilterUtil.REMEMBER_ATTRIBUTE) != null) {
×
UNCOV
956
                        rememberLocale = true;
×
957
                }
UNCOV
958
                if (localeParameter != null) {
×
UNCOV
959
                        String storedLocale = null;
×
960
                        if (httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE) != null) {
×
961
                                storedLocale = httpRequest.getSession().getAttribute(FilterUtil.LOCALE_ATTRIBUTE).toString();
×
962
                        }
963
                        // if user has changed locale parameter to new one
964
                        // or chooses it parameter at first page loading
UNCOV
965
                        if (storedLocale == null || !storedLocale.equals(localeParameter)) {
×
966
                                log.info("Stored locale parameter to session " + localeParameter);
×
UNCOV
967
                                httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, localeParameter);
×
968
                        }
UNCOV
969
                        if (rememberLocale) {
×
UNCOV
970
                                httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, localeParameter);
×
UNCOV
971
                                httpRequest.getSession().setAttribute(FilterUtil.REMEMBER_ATTRIBUTE, true);
×
UNCOV
972
                                wizardModel.localeToSave = localeParameter;
×
973
                        } else {
974
                                // we need to reset it if it was set before
UNCOV
975
                                httpRequest.getSession().setAttribute(FilterUtil.REMEMBER_ATTRIBUTE, null);
×
UNCOV
976
                                wizardModel.localeToSave = null;
×
977
                        }
978
                }
UNCOV
979
        }
×
980
        
981
        /**
982
         * It sets locale parameter for current session when user is making first GET http request to
983
         * application. It retrieves user locale from request object and checks if this locale is supported
984
         * by application. If not, it uses {@link Locale#ENGLISH} by default
985
         *
986
         * @param httpRequest the http request object
987
         */
988
        public void checkLocaleAttributesForFirstTime(HttpServletRequest httpRequest) {
989
                Locale locale = httpRequest.getLocale();
×
UNCOV
990
                if (CustomResourceLoader.getInstance(httpRequest).getAvailablelocales().contains(locale)) {
×
UNCOV
991
                        httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, locale.toString());
×
992
                } else {
993
                        httpRequest.getSession().setAttribute(FilterUtil.LOCALE_ATTRIBUTE, Locale.ENGLISH.toString());
×
994
                }
UNCOV
995
        }
×
996
        
997
        /**
998
         * Verify the database connection works.
999
         *
1000
         * @param connectionUsername
1001
         * @param connectionPassword
1002
         * @param databaseConnectionFinalUrl
1003
         * @return true/false whether it was verified or not
1004
         */
1005
        private boolean verifyConnection(String connectionUsername, String connectionPassword,
1006
                String databaseConnectionFinalUrl) {
1007
                try {
1008
                        // verify connection
1009
                        //Set Database Driver using driver String
UNCOV
1010
                        Class.forName(loadedDriverString).newInstance();
×
UNCOV
1011
                        try (Connection ignored = DriverManager.getConnection(databaseConnectionFinalUrl, connectionUsername, connectionPassword)) {
×
1012
                                return true;
×
1013
                        }
1014
                }
UNCOV
1015
                catch (Exception e) {
×
UNCOV
1016
                        errors.put("User account " + connectionUsername + " does not work. " + e.getMessage()
×
1017
                                        + " See the error log for more details",
1018
                                null); // TODO internationalize this
1019
                        log.warn("Error while checking the connection user account", e);
×
1020
                        return false;
×
1021
                }
1022
        }
1023
        
1024
        /**
1025
         * Convenience method to load the runtime properties file.
1026
         *
1027
         * @return the runtime properties file.
1028
         */
1029
        private File getRuntimePropertiesFile() {
1030
                File file;
1031
                
UNCOV
1032
                String pathName = OpenmrsUtil.getRuntimePropertiesFilePathName(WebConstants.WEBAPP_NAME);
×
UNCOV
1033
                if (pathName != null) {
×
UNCOV
1034
                        file = new File(pathName);
×
1035
                } else {
UNCOV
1036
                        file = new File(OpenmrsUtil.getApplicationDataDirectory(), getRuntimePropertiesFileName());
×
1037
                }
1038
                
UNCOV
1039
                log.debug("Using file: " + file.getAbsolutePath());
×
1040
                
UNCOV
1041
                return file;
×
1042
        }
1043
        
1044
        private String getRuntimePropertiesFileName() {
UNCOV
1045
                String fileName = OpenmrsUtil.getRuntimePropertiesFileNameInTestMode();
×
UNCOV
1046
                if (fileName == null) {
×
UNCOV
1047
                        fileName = WebConstants.WEBAPP_NAME + "-runtime.properties";
×
1048
                }
1049
                return fileName;
×
1050
        }
1051
        
1052
        /**
1053
         * @see org.openmrs.web.filter.StartupFilter#getTemplatePrefix()
1054
         */
1055
        @Override
1056
        protected String getTemplatePrefix() {
UNCOV
1057
                return "org/openmrs/web/filter/initialization/";
×
1058
        }
1059
        
1060
        /**
1061
         * @see org.openmrs.web.filter.StartupFilter#getUpdateFilterModel()
1062
         */
1063
        @Override
1064
        protected Object getUpdateFilterModel() {
1065
                return wizardModel;
×
1066
        }
1067
        
1068
        /**
1069
         * @see org.openmrs.web.filter.StartupFilter#skipFilter(HttpServletRequest)
1070
         */
1071
        @Override
1072
        public boolean skipFilter(HttpServletRequest httpRequest) {
1073
                // If progress.vm makes an ajax request even immediately after initialization has completed
1074
                // let the request pass in order to let progress.vm load the start page of OpenMRS
1075
                // (otherwise progress.vm is displayed "forever")
UNCOV
1076
                return !PROGRESS_VM_AJAXREQUEST.equals(httpRequest.getParameter("page")) && !initializationRequired();
×
1077
        }
1078
        
1079
        /**
1080
         * Public method that returns true if database+runtime properties initialization is required
1081
         *
1082
         * @return true if this initialization wizard needs to run
1083
         */
1084
        public static boolean initializationRequired() {
UNCOV
1085
                return !isInitializationComplete();
×
1086
        }
1087
        
1088
        /**
1089
         * @param isInstallationStarted the value to set
1090
         */
1091
        protected static synchronized void setInstallationStarted(boolean isInstallationStarted) {
UNCOV
1092
                InitializationFilter.isInstallationStarted = isInstallationStarted;
×
UNCOV
1093
        }
×
1094
        
1095
        /**
1096
         * @return true if installation has been started
1097
         */
1098
        protected static boolean isInstallationStarted() {
1099
                return isInstallationStarted;
×
1100
        }
1101
        
1102
        /**
1103
         * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
1104
         */
1105
        @Override
1106
        public void init(FilterConfig filterConfig) throws ServletException {
1107
                super.init(filterConfig);
×
UNCOV
1108
                wizardModel = new InitializationWizardModel();
×
UNCOV
1109
                DatabaseDetective databaseDetective = new DatabaseDetective();
×
1110
                //set whether need to do initialization work
1111
                if (databaseDetective.isDatabaseEmpty(OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME))) {
×
1112
                        //if runtime-properties file doesn't exist, have to do initialization work
UNCOV
1113
                        setInitializationComplete(false);
×
1114
                } else {
1115
                        //if database is not empty, then let UpdaterFilter to judge whether need database update
1116
                        setInitializationComplete(true);
×
1117
                }
1118
        }
×
1119
        
1120
        private void importTestDataSet(InputStream in, String connectionUrl, String connectionUsername,
1121
                String connectionPassword) throws IOException {
1122
                File tempFile = null;
×
1123
                FileOutputStream fileOut = null;
×
1124
                try {
1125
                        ZipInputStream zipIn = new ZipInputStream(in);
×
1126
                        zipIn.getNextEntry();
×
1127
                        
UNCOV
1128
                        tempFile = File.createTempFile("testDataSet", "dump");
×
1129
                        fileOut = new FileOutputStream(tempFile);
×
1130
                        
UNCOV
1131
                        IOUtils.copy(zipIn, fileOut);
×
1132
                        
UNCOV
1133
                        fileOut.close();
×
UNCOV
1134
                        zipIn.close();
×
1135
                        
1136
                        //Cater for the stand-alone connection url with has :mxj:
UNCOV
1137
                        if (connectionUrl.contains(":mxj:")) {
×
UNCOV
1138
                                connectionUrl = connectionUrl.replace(":mxj:", ":");
×
1139
                        }
1140
                        
UNCOV
1141
                        URI uri = URI.create(connectionUrl.substring(5)); //remove 'jdbc:' prefix to conform to the URI format
×
UNCOV
1142
                        String host = uri.getHost();
×
UNCOV
1143
                        int port = uri.getPort();
×
1144
                        
UNCOV
1145
                        TestInstallUtil.addTestData(host, port, wizardModel.databaseName, connectionUsername, connectionPassword,
×
1146
                                tempFile.getAbsolutePath());
×
1147
                }
1148
                finally {
1149
                        IOUtils.closeQuietly(in);
×
UNCOV
1150
                        IOUtils.closeQuietly(fileOut);
×
1151
                        
1152
                        if (tempFile != null) {
×
1153
                                tempFile.delete();
×
1154
                        }
1155
                }
1156
        }
×
1157
        
1158
        private boolean isCurrentDatabase(String database) {
UNCOV
1159
                return wizardModel.databaseConnection.contains(database);
×
1160
        }
1161
        
1162
        /**
1163
         * @param silent if this statement fails do not display stack trace or record an error in the wizard
1164
         *            object.
1165
         * @param user username to connect with
1166
         * @param pw password to connect with
1167
         * @param sql String containing sql and question marks
1168
         * @param args the strings to fill into the question marks in the given sql
1169
         * @return result of executeUpdate or -1 for error
1170
         */
1171
        private int executeStatement(boolean silent, String user, String pw, String sql, String... args) {
1172
                
1173
                Connection connection = null;
×
UNCOV
1174
                Statement statement = null;
×
1175
                try {
UNCOV
1176
                        String replacedSql = sql;
×
1177
                        
1178
                        // TODO how to get the driver for the other dbs...
1179
                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
UNCOV
1180
                                Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
×
UNCOV
1181
                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1182
                                Class.forName("org.postgresql.Driver").newInstance();
×
1183
                                replacedSql = replacedSql.replaceAll("`", "\"");
×
1184
                        } else {
1185
                                replacedSql = replacedSql.replaceAll("`", "\"");
×
1186
                        }
1187
                        
1188
                        String tempDatabaseConnection;
1189
                        if (sql.contains("create database")) {
×
1190
                                tempDatabaseConnection = wizardModel.databaseConnection.replace("@DBNAME@",
×
1191
                                        ""); // make this dbname agnostic so we can create the db
1192
                        } else {
UNCOV
1193
                                tempDatabaseConnection = wizardModel.databaseConnection.replace("@DBNAME@", wizardModel.databaseName);
×
1194
                        }
1195
                        
UNCOV
1196
                        connection = DriverManager.getConnection(tempDatabaseConnection, user, pw);
×
1197
                        
1198
                        for (String arg : args) {
×
1199
                                arg = arg.replace(";", "&#094"); // to prevent any sql injection
×
1200
                                replacedSql = replacedSql.replaceFirst("\\?", arg);
×
1201
                        }
1202
                        
1203
                        // run the sql statement
1204
                        statement = connection.createStatement();
×
1205
                        
UNCOV
1206
                        return statement.executeUpdate(replacedSql);
×
1207
                        
1208
                }
1209
                catch (SQLException sqlex) {
×
UNCOV
1210
                        if (!silent) {
×
1211
                                // log and add error
1212
                                log.warn("error executing sql: " + sql, sqlex);
×
UNCOV
1213
                                errors.put("Error executing sql: " + sql + " - " + sqlex.getMessage(), null);
×
1214
                        }
1215
                }
UNCOV
1216
                catch (InstantiationException | ClassNotFoundException | IllegalAccessException e) {
×
UNCOV
1217
                        log.error("Error generated", e);
×
1218
                }
1219
                finally {
1220
                        try {
UNCOV
1221
                                if (statement != null) {
×
1222
                                        statement.close();
×
1223
                                }
1224
                        }
UNCOV
1225
                        catch (SQLException e) {
×
UNCOV
1226
                                log.warn("Error while closing statement");
×
UNCOV
1227
                        }
×
1228
                        try {
1229
                                
UNCOV
1230
                                if (connection != null) {
×
UNCOV
1231
                                        connection.close();
×
1232
                                }
1233
                        }
UNCOV
1234
                        catch (Exception e) {
×
1235
                                log.warn("Error while closing connection", e);
×
1236
                        }
×
1237
                }
1238
                
1239
                return -1;
×
1240
        }
1241
        
1242
        /**
1243
         * Convenience variable to know if this wizard has completed successfully and that this wizard does
1244
         * not need to be executed again
1245
         *
1246
         * @return true if this has been run already
1247
         */
1248
        private static synchronized boolean isInitializationComplete() {
UNCOV
1249
                return initializationComplete;
×
1250
        }
1251
        
1252
        /**
1253
         * Check if the given value is null or a zero-length String
1254
         *
1255
         * @param value the string to check
1256
         * @param errors the list of errors to append the errorMessage to if value is empty
1257
         * @param errorMessageCode the string with code of error message translation to append if value is
1258
         *            empty
1259
         * @return true if the value is non-empty
1260
         */
1261
        private boolean checkForEmptyValue(String value, Map<String, Object[]> errors, String errorMessageCode) {
UNCOV
1262
                if (!StringUtils.isEmpty(value)) {
×
UNCOV
1263
                        return true;
×
1264
                }
UNCOV
1265
                errors.put(errorMessageCode, null);
×
UNCOV
1266
                return false;
×
1267
        }
1268
        
1269
        /**
1270
         * Separate thread that will run through all tasks to complete the initialization. The database is
1271
         * created, user's created, etc here
1272
         */
1273
        private class InitializationCompletion {
1274
                
1275
                private Thread thread;
1276
                
1277
                private int steps = 0;
×
1278
                
UNCOV
1279
                private String message = "";
×
1280
                
1281
                private Map<String, Object[]> errors = new HashMap<>();
×
1282
                
UNCOV
1283
                private String errorPage = null;
×
1284
                
UNCOV
1285
                private boolean erroneous = false;
×
1286
                
UNCOV
1287
                private int completedPercentage = 0;
×
1288
                
1289
                private WizardTask executingTask;
1290
                
1291
                private List<WizardTask> executedTasks = new ArrayList<>();
×
1292
                
1293
                public synchronized void reportError(String error, String errorPage, Object... params) {
UNCOV
1294
                        errors.put(error, params);
×
1295
                        this.errorPage = errorPage;
×
UNCOV
1296
                        erroneous = true;
×
1297
                }
×
1298
                
1299
                public synchronized boolean hasErrors() {
1300
                        return erroneous;
×
1301
                }
1302
                
1303
                public synchronized String getErrorPage() {
1304
                        return errorPage;
×
1305
                }
1306
                
1307
                public synchronized Map<String, Object[]> getErrors() {
UNCOV
1308
                        return errors;
×
1309
                }
1310
                
1311
                /**
1312
                 * Start the completion stage. This fires up the thread to do all the work.
1313
                 */
1314
                public void start() {
1315
                        setStepsComplete(0);
×
1316
                        setInitializationComplete(false);
×
1317
                        thread.start();
×
UNCOV
1318
                }
×
1319
                
1320
                public void waitForCompletion() {
1321
                        try {
UNCOV
1322
                                thread.join();
×
1323
                        }
UNCOV
1324
                        catch (InterruptedException e) {
×
UNCOV
1325
                                log.error("Error generated", e);
×
UNCOV
1326
                        }
×
UNCOV
1327
                }
×
1328
                
1329
                protected synchronized void setStepsComplete(int steps) {
1330
                        this.steps = steps;
×
UNCOV
1331
                }
×
1332
                
1333
                protected synchronized int getStepsComplete() {
UNCOV
1334
                        return steps;
×
1335
                }
1336
                
1337
                public synchronized String getMessage() {
1338
                        return message;
×
1339
                }
1340
                
1341
                public synchronized void setMessage(String message) {
UNCOV
1342
                        this.message = message;
×
UNCOV
1343
                        setStepsComplete(getStepsComplete() + 1);
×
UNCOV
1344
                }
×
1345
                
1346
                /**
1347
                 * @return the executingTask
1348
                 */
1349
                protected synchronized WizardTask getExecutingTask() {
UNCOV
1350
                        return executingTask;
×
1351
                }
1352
                
1353
                /**
1354
                 * @return the completedPercentage
1355
                 */
1356
                protected synchronized int getCompletedPercentage() {
UNCOV
1357
                        return completedPercentage;
×
1358
                }
1359
                
1360
                /**
1361
                 * @param completedPercentage the completedPercentage to set
1362
                 */
1363
                protected synchronized void setCompletedPercentage(int completedPercentage) {
UNCOV
1364
                        this.completedPercentage = completedPercentage;
×
UNCOV
1365
                }
×
1366
                
1367
                /**
1368
                 * Adds a task that has been completed to the list of executed tasks
1369
                 *
1370
                 * @param task
1371
                 */
1372
                protected synchronized void addExecutedTask(WizardTask task) {
UNCOV
1373
                        this.executedTasks.add(task);
×
UNCOV
1374
                }
×
1375
                
1376
                /**
1377
                 * @param executingTask the executingTask to set
1378
                 */
1379
                protected synchronized void setExecutingTask(WizardTask executingTask) {
1380
                        this.executingTask = executingTask;
×
UNCOV
1381
                }
×
1382
                
1383
                /**
1384
                 * @return the executedTasks
1385
                 */
1386
                protected synchronized List<WizardTask> getExecutedTasks() {
1387
                        return this.executedTasks;
×
1388
                }
1389
                
1390
                /**
1391
                 * This class does all the work of creating the desired database, user, updates, etc
1392
                 */
UNCOV
1393
                public InitializationCompletion() {
×
1394
                        Runnable r = new Runnable() {
×
1395
                                
1396
                                /**
1397
                                 * TODO split this up into multiple testable methods
1398
                                 *
1399
                                 * @see java.lang.Runnable#run()
1400
                                 */
1401
                                @Override
1402
                                public void run() {
1403
                                        try {
1404
                                                String connectionUsername;
1405
                                                StringBuilder connectionPassword = new StringBuilder();
×
1406
                                                ChangeLogDetective changeLogDetective = new ChangeLogDetective();
×
1407
                                                ChangeLogVersionFinder changeLogVersionFinder = new ChangeLogVersionFinder();
×
1408
                                                
1409
                                                if (!wizardModel.hasCurrentOpenmrsDatabase) {
×
UNCOV
1410
                                                        setMessage("Create database");
×
UNCOV
1411
                                                        setExecutingTask(WizardTask.CREATE_SCHEMA);
×
1412
                                                        // connect via jdbc and create a database
1413
                                                        String sql;
UNCOV
1414
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1415
                                                                sql = "create database if not exists `?` default character set utf8";
×
1416
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1417
                                                                sql = "create database `?` encoding 'utf8'";
×
1418
                                                        } else if (isCurrentDatabase(DATABASE_H2)) {
×
1419
                                                                sql = null;
×
1420
                                                        } else {
UNCOV
1421
                                                                sql = "create database `?`";
×
1422
                                                        }
1423
                                                        
1424
                                                        int result;
UNCOV
1425
                                                        if (sql != null) {
×
UNCOV
1426
                                                                result = executeStatement(false, wizardModel.createDatabaseUsername,
×
1427
                                                                        wizardModel.createDatabasePassword, sql, wizardModel.databaseName);
×
1428
                                                        } else {
1429
                                                                result = 1;
×
1430
                                                        }
1431
                                                        // throw the user back to the main screen if this error occurs
UNCOV
1432
                                                        if (result < 0) {
×
1433
                                                                reportError(ErrorMessageConstants.ERROR_DB_CREATE_NEW, DEFAULT_PAGE);
×
UNCOV
1434
                                                                return;
×
1435
                                                        } else {
1436
                                                                wizardModel.workLog.add("Created database " + wizardModel.databaseName);
×
1437
                                                        }
1438
                                                        
1439
                                                        addExecutedTask(WizardTask.CREATE_SCHEMA);
×
1440
                                                }
1441
                                                
1442
                                                if (wizardModel.createDatabaseUser) {
×
1443
                                                        setMessage("Create database user");
×
1444
                                                        setExecutingTask(WizardTask.CREATE_DB_USER);
×
1445
                                                        connectionUsername = wizardModel.databaseName + "_user";
×
1446
                                                        if (connectionUsername.length() > 16) {
×
UNCOV
1447
                                                                connectionUsername = wizardModel.databaseName.substring(0, 11)
×
1448
                                                                        + "_user"; // trim off enough to leave space for _user at the end
1449
                                                        }
1450
                                                        
UNCOV
1451
                                                        connectionPassword.append("");
×
1452
                                                        // generate random password from this subset of alphabet
1453
                                                        // intentionally left out these characters: ufsb$() to prevent certain words forming randomly
1454
                                                        String chars = "acdeghijklmnopqrtvwxyzACDEGHIJKLMNOPQRTVWXYZ0123456789.|~@#^&";
×
1455
                                                        Random r = new Random();
×
UNCOV
1456
                                                        StringBuilder randomStr = new StringBuilder("");
×
UNCOV
1457
                                                        for (int x = 0; x < 12; x++) {
×
1458
                                                                randomStr.append(chars.charAt(r.nextInt(chars.length())));
×
1459
                                                        }
1460
                                                        connectionPassword.append(randomStr);
×
1461
                                                        
1462
                                                        // connect via jdbc with root user and create an openmrs user
1463
                                                        String host = "'%'";
×
1464
                                                        if (wizardModel.databaseConnection.contains("localhost")
×
UNCOV
1465
                                                                || wizardModel.databaseConnection.contains("127.0.0.1")) {
×
UNCOV
1466
                                                                host = "'localhost'";
×
1467
                                                        }
1468
                                                        
1469
                                                        String sql = "";
×
1470
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1471
                                                                sql = "drop user '?'@" + host;
×
1472
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1473
                                                                sql = "drop user `?`";
×
1474
                                                        }
1475
                                                        
1476
                                                        executeStatement(true, wizardModel.createUserUsername, wizardModel.createUserPassword, sql,
×
1477
                                                                connectionUsername);
1478
                                                        
UNCOV
1479
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
1480
                                                                sql = "create user '?'@" + host + " identified by '?'";
×
1481
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
1482
                                                                sql = "create user `?` with password '?'";
×
1483
                                                        }
1484
                                                        
1485
                                                        if (-1 != executeStatement(false, wizardModel.createUserUsername, wizardModel.createUserPassword,
×
UNCOV
1486
                                                                sql, connectionUsername, connectionPassword.toString())) {
×
UNCOV
1487
                                                                wizardModel.workLog.add("Created user " + connectionUsername);
×
1488
                                                        } else {
1489
                                                                // if error occurs stop
1490
                                                                reportError(ErrorMessageConstants.ERROR_DB_CREATE_DB_USER, DEFAULT_PAGE);
×
1491
                                                                return;
×
1492
                                                        }
1493
                                                        
1494
                                                        // grant the roles
1495
                                                        int result = 1;
×
1496
                                                        if (isCurrentDatabase(DATABASE_MYSQL)) {
×
UNCOV
1497
                                                                sql = "GRANT ALL ON `?`.* TO '?'@" + host;
×
1498
                                                                result = executeStatement(false, wizardModel.createUserUsername,
×
1499
                                                                        wizardModel.createUserPassword, sql, wizardModel.databaseName, connectionUsername);
×
UNCOV
1500
                                                        } else if (isCurrentDatabase(DATABASE_POSTGRESQL)) {
×
UNCOV
1501
                                                                sql = "ALTER USER `?` WITH SUPERUSER";
×
1502
                                                                result = executeStatement(false, wizardModel.createUserUsername,
×
UNCOV
1503
                                                                        wizardModel.createUserPassword, sql, connectionUsername);
×
1504
                                                        }
1505
                                                        
1506
                                                        // throw the user back to the main screen if this error occurs
1507
                                                        if (result < 0) {
×
UNCOV
1508
                                                                reportError(ErrorMessageConstants.ERROR_DB_GRANT_PRIV, DEFAULT_PAGE);
×
UNCOV
1509
                                                                return;
×
1510
                                                        } else {
1511
                                                                wizardModel.workLog.add("Granted user " + connectionUsername + " all privileges to database "
×
UNCOV
1512
                                                                        + wizardModel.databaseName);
×
1513
                                                        }
1514
                                                        
1515
                                                        addExecutedTask(WizardTask.CREATE_DB_USER);
×
1516
                                                } else {
×
1517
                                                        connectionUsername = wizardModel.currentDatabaseUsername;
×
UNCOV
1518
                                                        connectionPassword.setLength(0);
×
1519
                                                        connectionPassword.append(wizardModel.currentDatabasePassword);
×
1520
                                                }
1521
                                                
1522
                                                String finalDatabaseConnectionString = wizardModel.databaseConnection.replace("@DBNAME@",
×
1523
                                                        wizardModel.databaseName);
×
1524
                                                
1525
                                                finalDatabaseConnectionString = finalDatabaseConnectionString.replace("@APPLICATIONDATADIR@",
×
1526
                                                        OpenmrsUtil.getApplicationDataDirectory().replace("\\", "/"));
×
1527
                                                
1528
                                                // verify that the database connection works
1529
                                                if (!verifyConnection(connectionUsername, connectionPassword.toString(),
×
1530
                                                        finalDatabaseConnectionString)) {
1531
                                                        setMessage("Verify that the database connection works");
×
1532
                                                        // redirect to setup page if we got an error
1533
                                                        reportError("Unable to connect to database", DEFAULT_PAGE);
×
1534
                                                        return;
×
1535
                                                }
1536
                                                
1537
                                                // save the properties for startup purposes
1538
                                                Properties runtimeProperties = new Properties();
×
1539
                                                
UNCOV
1540
                                                runtimeProperties.put("connection.url", finalDatabaseConnectionString);
×
UNCOV
1541
                                                runtimeProperties.put("connection.username", connectionUsername);
×
UNCOV
1542
                                                runtimeProperties.put("connection.password", connectionPassword.toString());
×
UNCOV
1543
                                                if (StringUtils.hasText(wizardModel.databaseDriver)) {
×
UNCOV
1544
                                                        runtimeProperties.put("connection.driver_class", wizardModel.databaseDriver);
×
1545
                                                }
1546
                                                if (finalDatabaseConnectionString.contains(DATABASE_POSTGRESQL)) {
×
UNCOV
1547
                                                        runtimeProperties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL82Dialect");
×
1548
                                                }
UNCOV
1549
                                                if (finalDatabaseConnectionString.contains(DATABASE_SQLSERVER)) {
×
1550
                                                        runtimeProperties.put("hibernate.dialect", "org.hibernate.dialect.SQLServerDialect");
×
1551
                                                }
1552
                                                if (finalDatabaseConnectionString.contains(DATABASE_H2)) {
×
UNCOV
1553
                                                        runtimeProperties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
×
1554
                                                }
UNCOV
1555
                                                runtimeProperties.put("module.allow_web_admin", "" + wizardModel.moduleWebAdmin);
×
UNCOV
1556
                                                runtimeProperties.put("auto_update_database", "" + wizardModel.autoUpdateDatabase);
×
UNCOV
1557
                                                final Encoder base64 = Base64.getEncoder();
×
UNCOV
1558
                                                runtimeProperties.put(OpenmrsConstants.ENCRYPTION_VECTOR_RUNTIME_PROPERTY,
×
1559
                                                        new String(base64.encode(Security.generateNewInitVector()), StandardCharsets.UTF_8));
×
1560
                                                runtimeProperties.put(OpenmrsConstants.ENCRYPTION_KEY_RUNTIME_PROPERTY,
×
1561
                                                        new String(base64.encode(Security.generateNewSecretKey()), StandardCharsets.UTF_8));
×
1562
                                                
1563
                                                runtimeProperties.putAll(wizardModel.additionalPropertiesFromInstallationScript);
×
1564
                                                
1565
                                                Properties properties = Context.getRuntimeProperties();
×
UNCOV
1566
                                                properties.putAll(runtimeProperties);
×
UNCOV
1567
                                                runtimeProperties = properties;
×
UNCOV
1568
                                                Context.setRuntimeProperties(runtimeProperties);
×
1569
                                                
1570
                                                /**
1571
                                                 * A callback class that prints out info about liquibase changesets
1572
                                                 */
1573
                                                class PrintingChangeSetExecutorCallback implements ChangeSetExecutorCallback {
1574
                                                        
1575
                                                        private int i = 1;
×
1576
                                                        
1577
                                                        private String message;
1578
                                                        
UNCOV
1579
                                                        public PrintingChangeSetExecutorCallback(String message) {
×
1580
                                                                this.message = message;
×
UNCOV
1581
                                                        }
×
1582
                                                        
1583
                                                        /**
1584
                                                         * @see ChangeSetExecutorCallback#executing(liquibase.changelog.ChangeSet, int)
1585
                                                         */
1586
                                                        @Override
1587
                                                        public void executing(ChangeSet changeSet, int numChangeSetsToRun) {
1588
                                                                setMessage(message + " (" + i++ + "/" + numChangeSetsToRun + "): Author: "
×
UNCOV
1589
                                                                        + changeSet.getAuthor() + " Comments: " + changeSet.getComments() + " Description: "
×
1590
                                                                        + changeSet.getDescription());
×
UNCOV
1591
                                                                float numChangeSetsToRunFloat = (float) numChangeSetsToRun;
×
1592
                                                                float j = (float) i;
×
UNCOV
1593
                                                                setCompletedPercentage(Math.round(j * 100 / numChangeSetsToRunFloat));
×
1594
                                                        }
×
1595
                                                        
1596
                                                }
1597
                                                
1598
                                                if (wizardModel.createTables) {
×
1599
                                                        // use liquibase to create core data + tables
1600
                                                        try {
1601
                                                                String liquibaseSchemaFileName = changeLogVersionFinder.getLatestSchemaSnapshotFilename()
×
1602
                                                                        .get();
×
UNCOV
1603
                                                                String liquibaseCoreDataFileName = changeLogVersionFinder.getLatestCoreDataSnapshotFilename()
×
UNCOV
1604
                                                                        .get();
×
1605
                                                                
UNCOV
1606
                                                                setMessage("Executing " + liquibaseSchemaFileName);
×
1607
                                                                setExecutingTask(WizardTask.CREATE_TABLES);
×
1608
                                                                
1609
                                                                log.debug("executing Liquibase file '{}' ", liquibaseSchemaFileName);
×
1610
                                                                
UNCOV
1611
                                                                DatabaseUpdater.executeChangelog(liquibaseSchemaFileName,
×
1612
                                                                        new PrintingChangeSetExecutorCallback("OpenMRS schema file"));
1613
                                                                addExecutedTask(WizardTask.CREATE_TABLES);
×
1614
                                                                
1615
                                                                //reset for this task
1616
                                                                setCompletedPercentage(0);
×
1617
                                                                setExecutingTask(WizardTask.ADD_CORE_DATA);
×
1618
                                                                
1619
                                                                log.debug("executing Liquibase file '{}' ", liquibaseCoreDataFileName);
×
1620
                                                                
1621
                                                                DatabaseUpdater.executeChangelog(liquibaseCoreDataFileName,
×
1622
                                                                        new PrintingChangeSetExecutorCallback("OpenMRS core data file"));
UNCOV
1623
                                                                wizardModel.workLog.add("Created database tables and added core data");
×
1624
                                                                addExecutedTask(WizardTask.ADD_CORE_DATA);
×
1625
                                                                
1626
                                                        }
UNCOV
1627
                                                        catch (Exception e) {
×
1628
                                                                reportError(ErrorMessageConstants.ERROR_DB_CREATE_TABLES_OR_ADD_DEMO_DATA, DEFAULT_PAGE,
×
1629
                                                                        e.getMessage());
×
1630
                                                                log.warn("Error while trying to create tables and demo data", e);
×
UNCOV
1631
                                                        }
×
1632
                                                }
1633
                                                
1634
                                                if (wizardModel.importTestData) {
×
1635
                                                        try {
1636
                                                                setMessage("Importing test data");
×
UNCOV
1637
                                                                setExecutingTask(WizardTask.IMPORT_TEST_DATA);
×
1638
                                                                setCompletedPercentage(0);
×
1639
                                                                
1640
                                                                try {
UNCOV
1641
                                                                        InputStream inData = TestInstallUtil.getResourceInputStream(
×
1642
                                                                                wizardModel.remoteUrl + RELEASE_TESTING_MODULE_PATH + "generateTestDataSet.form",
×
1643
                                                                                wizardModel.remoteUsername, wizardModel.remotePassword);
×
1644
                                                                        
UNCOV
1645
                                                                        setCompletedPercentage(40);
×
1646
                                                                        setMessage("Loading imported test data...");
×
1647
                                                                        importTestDataSet(inData, finalDatabaseConnectionString, connectionUsername,
×
UNCOV
1648
                                                                                connectionPassword.toString());
×
1649
                                                                        wizardModel.workLog.add("Imported test data");
×
1650
                                                                        addExecutedTask(WizardTask.IMPORT_TEST_DATA);
×
1651
                                                                        
1652
                                                                        //reset the progress for the next task
1653
                                                                        setCompletedPercentage(0);
×
UNCOV
1654
                                                                        setMessage("Importing modules from remote server...");
×
UNCOV
1655
                                                                        setExecutingTask(WizardTask.ADD_MODULES);
×
1656
                                                                        
1657
                                                                        InputStream inModules = TestInstallUtil.getResourceInputStream(
×
UNCOV
1658
                                                                                wizardModel.remoteUrl + RELEASE_TESTING_MODULE_PATH + "getModules.htm",
×
1659
                                                                                wizardModel.remoteUsername, wizardModel.remotePassword);
×
1660
                                                                        
1661
                                                                        setCompletedPercentage(90);
×
UNCOV
1662
                                                                        setMessage("Adding imported modules...");
×
1663
                                                                        if (!TestInstallUtil.addZippedTestModules(inModules)) {
×
UNCOV
1664
                                                                                reportError(ErrorMessageConstants.ERROR_DB_UNABLE_TO_ADD_MODULES, DEFAULT_PAGE, "");
×
1665
                                                                                return;
×
1666
                                                                        } else {
1667
                                                                                wizardModel.workLog.add("Added Modules");
×
UNCOV
1668
                                                                                addExecutedTask(WizardTask.ADD_MODULES);
×
1669
                                                                        }
1670
                                                                }
1671
                                                                catch (APIAuthenticationException e) {
×
1672
                                                                        log.warn("Unable to authenticate as a User with the System Developer role");
×
1673
                                                                        reportError(ErrorMessageConstants.UPDATE_ERROR_UNABLE_AUTHENTICATE,
×
1674
                                                                                TESTING_REMOTE_DETAILS_SETUP, "");
1675
                                                                        return;
×
UNCOV
1676
                                                                }
×
1677
                                                        }
UNCOV
1678
                                                        catch (Exception e) {
×
UNCOV
1679
                                                                reportError(ErrorMessageConstants.ERROR_DB_IMPORT_TEST_DATA, DEFAULT_PAGE, e.getMessage());
×
1680
                                                                log.warn("Error while trying to import test data", e);
×
1681
                                                                return;
×
1682
                                                        }
×
1683
                                                }
1684
                                                
1685
                                                // add demo data only if creating tables fresh and user selected the option add demo data
1686
                                                if (wizardModel.createTables && wizardModel.addDemoData) {
×
1687
                                                        try {
UNCOV
1688
                                                                setMessage("Adding demo data");
×
1689
                                                                setCompletedPercentage(0);
×
UNCOV
1690
                                                                setExecutingTask(WizardTask.ADD_DEMO_DATA);
×
1691
                                                                
UNCOV
1692
                                                                log.debug("executing Liquibase file '{}' ", LIQUIBASE_DEMO_DATA);
×
1693
                                                                
UNCOV
1694
                                                                DatabaseUpdater.executeChangelog(LIQUIBASE_DEMO_DATA,
×
1695
                                                                        new PrintingChangeSetExecutorCallback("OpenMRS demo patients, users, and forms"));
UNCOV
1696
                                                                wizardModel.workLog.add("Added demo data");
×
1697
                                                                
1698
                                                                addExecutedTask(WizardTask.ADD_DEMO_DATA);
×
1699
                                                        }
1700
                                                        catch (Exception e) {
×
1701
                                                                reportError(ErrorMessageConstants.ERROR_DB_CREATE_TABLES_OR_ADD_DEMO_DATA, DEFAULT_PAGE,
×
UNCOV
1702
                                                                        e.getMessage());
×
1703
                                                                log.warn("Error while trying to add demo data", e);
×
UNCOV
1704
                                                        }
×
1705
                                                }
1706
                                                
1707
                                                // update the database to the latest version
1708
                                                try {
1709
                                                        setMessage("Updating the database to the latest version");
×
1710
                                                        setCompletedPercentage(0);
×
1711
                                                        setExecutingTask(WizardTask.UPDATE_TO_LATEST);
×
1712
                                                        
UNCOV
1713
                                                        String version = null;
×
1714
                                                        
1715
                                                        if (wizardModel.createTables) {
×
UNCOV
1716
                                                                version = changeLogVersionFinder.getLatestSnapshotVersion().get();
×
1717
                                                        } else {
UNCOV
1718
                                                                version = changeLogDetective.getInitialLiquibaseSnapshotVersion(DatabaseUpdater.CONTEXT,
×
1719
                                                                        new DatabaseUpdaterLiquibaseProvider());
1720
                                                        }
1721
                                                        
UNCOV
1722
                                                        log.debug(
×
1723
                                                                "updating the database with versions of liquibase-update-to-latest files greater than '{}'",
1724
                                                                version);
1725
                                                        
1726
                                                        List<String> changelogs = changeLogVersionFinder
×
1727
                                                                .getUpdateFileNames(changeLogVersionFinder.getUpdateVersionsGreaterThan(version));
×
1728
                                                        
1729
                                                        for (String changelog : changelogs) {
×
UNCOV
1730
                                                                log.debug("applying Liquibase changelog '{}'", changelog);
×
1731
                                                                
UNCOV
1732
                                                                DatabaseUpdater.executeChangelog(changelog,
×
1733
                                                                        new PrintingChangeSetExecutorCallback("executing Liquibase changelog " + changelog));
UNCOV
1734
                                                        }
×
UNCOV
1735
                                                        addExecutedTask(WizardTask.UPDATE_TO_LATEST);
×
1736
                                                }
1737
                                                catch (Exception e) {
×
1738
                                                        reportError(ErrorMessageConstants.ERROR_DB_UPDATE_TO_LATEST, DEFAULT_PAGE, e.getMessage());
×
1739
                                                        log.warn("Error while trying to update to the latest database version", e);
×
1740
                                                        return;
×
1741
                                                }
×
1742
                                                
1743
                                                setExecutingTask(null);
×
1744
                                                setMessage("Starting OpenMRS");
×
1745
                                                
1746
                                                // start spring
1747
                                                // after this point, all errors need to also call: contextLoader.closeWebApplicationContext(event.getServletContext())
1748
                                                // logic copied from org.springframework.web.context.ContextLoaderListener
1749
                                                ContextLoader contextLoader = new ContextLoader();
×
1750
                                                contextLoader.initWebApplicationContext(filterConfig.getServletContext());
×
1751
                                                
1752
                                                // output properties to the openmrs runtime properties file so that this wizard is not run again
UNCOV
1753
                                                FileOutputStream fos = null;
×
1754
                                                try {
UNCOV
1755
                                                        fos = new FileOutputStream(getRuntimePropertiesFile());
×
1756
                                                        OpenmrsUtil.storeProperties(runtimeProperties, fos,
×
1757
                                                                "Auto generated by OpenMRS initialization wizard");
1758
                                                        wizardModel.workLog.add("Saved runtime properties file " + getRuntimePropertiesFile());
×
1759
                                                        
1760
                                                        /*
1761
                                                         * Fix file readability permissions:
1762
                                                         * first revoke read permission from everyone, then set read permissions for only the user
1763
                                                         * there is no function to set specific readability for only one user
1764
                                                         * and revoke everyone else's, therefore this is the only way to accomplish this.
1765
                                                         */
1766
                                                        wizardModel.workLog.add("Adjusting file posix properties to user readonly");
×
1767
                                                        if (getRuntimePropertiesFile().setReadable(false, false)
×
UNCOV
1768
                                                                && getRuntimePropertiesFile().setReadable(true)) {
×
1769
                                                                wizardModel.workLog
×
UNCOV
1770
                                                                        .add("Successfully adjusted RuntimePropertiesFile to disallow world to read it");
×
1771
                                                        } else {
1772
                                                                wizardModel.workLog
×
1773
                                                                        .add("Unable to adjust RuntimePropertiesFile to disallow world to read it");
×
1774
                                                        }
1775
                                                        // don't need to catch errors here because we tested it at the beginning of the wizard
1776
                                                }
1777
                                                finally {
UNCOV
1778
                                                        if (fos != null) {
×
UNCOV
1779
                                                                fos.close();
×
1780
                                                        }
1781
                                                }
1782
                                                
1783
                                                Context.openSession();
×
1784
                                                
UNCOV
1785
                                                if (!"".equals(wizardModel.implementationId)) {
×
1786
                                                        try {
UNCOV
1787
                                                                Context.addProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
UNCOV
1788
                                                                Context.addProxyPrivilege(PrivilegeConstants.MANAGE_CONCEPT_SOURCES);
×
1789
                                                                Context.addProxyPrivilege(PrivilegeConstants.GET_CONCEPT_SOURCES);
×
UNCOV
1790
                                                                Context.addProxyPrivilege(PrivilegeConstants.MANAGE_IMPLEMENTATION_ID);
×
1791
                                                                
UNCOV
1792
                                                                ImplementationId implId = new ImplementationId();
×
1793
                                                                implId.setName(wizardModel.implementationIdName);
×
1794
                                                                implId.setImplementationId(wizardModel.implementationId);
×
1795
                                                                implId.setPassphrase(wizardModel.implementationIdPassPhrase);
×
1796
                                                                implId.setDescription(wizardModel.implementationIdDescription);
×
1797
                                                                
1798
                                                                Context.getAdministrationService().setImplementationId(implId);
×
1799
                                                        }
1800
                                                        catch (Exception e) {
×
1801
                                                                reportError(ErrorMessageConstants.ERROR_SET_INPL_ID, DEFAULT_PAGE, e.getMessage());
×
UNCOV
1802
                                                                log.warn("Implementation ID could not be set.", e);
×
1803
                                                                Context.shutdown();
×
UNCOV
1804
                                                                WebModuleUtil.shutdownModules(filterConfig.getServletContext());
×
1805
                                                                contextLoader.closeWebApplicationContext(filterConfig.getServletContext());
×
1806
                                                                return;
×
1807
                                                        }
1808
                                                        finally {
1809
                                                                Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES);
×
1810
                                                                Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_CONCEPT_SOURCES);
×
UNCOV
1811
                                                                Context.removeProxyPrivilege(PrivilegeConstants.GET_CONCEPT_SOURCES);
×
UNCOV
1812
                                                                Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_IMPLEMENTATION_ID);
×
1813
                                                        }
1814
                                                }
1815
                                                
1816
                                                try {
1817
                                                        // change the admin user password from "test" to what they input above
1818
                                                        if (wizardModel.createTables) {
×
1819
                                                                try {
1820
                                                                        Context.authenticate(new UsernamePasswordCredentials("admin", "test"));
×
1821
                                                                        
UNCOV
1822
                                                                        Properties props = Context.getRuntimeProperties();
×
UNCOV
1823
                                                                        String initValue = props.getProperty(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY);
×
1824
                                                                        props.setProperty(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY, "false");
×
UNCOV
1825
                                                                        Context.setRuntimeProperties(props);
×
1826
                                                                        
1827
                                                                        Context.getUserService().changePassword("test", wizardModel.adminUserPassword);
×
1828
                                                                        
1829
                                                                        if (initValue == null) {
×
1830
                                                                                props.remove(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY);
×
1831
                                                                        } else {
UNCOV
1832
                                                                                props.setProperty(UserService.ADMIN_PASSWORD_LOCKED_PROPERTY, initValue);
×
1833
                                                                        }
UNCOV
1834
                                                                        Context.setRuntimeProperties(props);
×
UNCOV
1835
                                                                        Context.logout();
×
1836
                                                                }
1837
                                                                catch (ContextAuthenticationException ex) {
×
1838
                                                                        log.info("No need to change admin password.", ex);
×
UNCOV
1839
                                                                }
×
1840
                                                        }
1841
                                                }
1842
                                                catch (Exception e) {
×
1843
                                                        Context.shutdown();
×
UNCOV
1844
                                                        WebModuleUtil.shutdownModules(filterConfig.getServletContext());
×
1845
                                                        contextLoader.closeWebApplicationContext(filterConfig.getServletContext());
×
UNCOV
1846
                                                        reportError(ErrorMessageConstants.ERROR_COMPLETE_STARTUP, DEFAULT_PAGE, e.getMessage());
×
UNCOV
1847
                                                        log.warn("Unable to complete the startup.", e);
×
UNCOV
1848
                                                        return;
×
1849
                                                }
×
1850
                                                
1851
                                                try {
1852
                                                        // Update PostgreSQL Sequences after insertion of core data
UNCOV
1853
                                                        Context.getAdministrationService().updatePostgresSequence();
×
1854
                                                }
1855
                                                catch (Exception e) {
×
UNCOV
1856
                                                        log.warn("Not able to update PostgreSQL sequence. Startup failed for PostgreSQL", e);
×
UNCOV
1857
                                                        reportError(ErrorMessageConstants.ERROR_COMPLETE_STARTUP, DEFAULT_PAGE, e.getMessage());
×
1858
                                                        return;
×
1859
                                                }
×
1860
                                                
1861
                                                // set this so that the wizard isn't run again on next page load
1862
                                                Context.closeSession();
×
1863
                                                
1864
                                                // start openmrs
1865
                                                try {
1866
                                                        UpdateFilter.setUpdatesRequired(false);
×
1867
                                                        WebDaemon.startOpenmrs(filterConfig.getServletContext());
×
1868
                                                }
UNCOV
1869
                                                catch (DatabaseUpdateException updateEx) {
×
UNCOV
1870
                                                        log.warn("Error while running the database update file", updateEx);
×
UNCOV
1871
                                                        reportError(ErrorMessageConstants.ERROR_DB_UPDATE, DEFAULT_PAGE, updateEx.getMessage());
×
UNCOV
1872
                                                        return;
×
1873
                                                }
1874
                                                catch (InputRequiredException inputRequiredEx) {
×
1875
                                                        // TODO display a page looping over the required input and ask the user for each.
1876
                                                        //                 When done and the user and put in their say, call DatabaseUpdater.update(Map);
1877
                                                        //                with the user's question/answer pairs
UNCOV
1878
                                                        log.warn(
×
1879
                                                                "Unable to continue because user input is required for the db updates and we cannot do anything about that right now");
UNCOV
1880
                                                        reportError(ErrorMessageConstants.ERROR_INPUT_REQ, DEFAULT_PAGE);
×
UNCOV
1881
                                                        return;
×
1882
                                                }
UNCOV
1883
                                                catch (MandatoryModuleException mandatoryModEx) {
×
1884
                                                        log.warn(
×
1885
                                                                "A mandatory module failed to start. Fix the error or unmark it as mandatory to continue.",
1886
                                                                mandatoryModEx);
UNCOV
1887
                                                        reportError(ErrorMessageConstants.ERROR_MANDATORY_MOD_REQ, DEFAULT_PAGE,
×
UNCOV
1888
                                                                mandatoryModEx.getMessage());
×
1889
                                                        return;
×
1890
                                                }
UNCOV
1891
                                                catch (OpenmrsCoreModuleException coreModEx) {
×
UNCOV
1892
                                                        log.warn(
×
1893
                                                                "A core module failed to start. Make sure that all core modules (with the required minimum versions) are installed and starting properly.",
1894
                                                                coreModEx);
UNCOV
1895
                                                        reportError(ErrorMessageConstants.ERROR_CORE_MOD_REQ, DEFAULT_PAGE, coreModEx.getMessage());
×
UNCOV
1896
                                                        return;
×
UNCOV
1897
                                                }
×
1898
                                                
1899
                                                // TODO catch openmrs errors here and drop the user back out to the setup screen
1900
                                                
1901
                                        }
UNCOV
1902
                                        catch (IOException e) {
×
1903
                                                reportError(ErrorMessageConstants.ERROR_COMPLETE_STARTUP, DEFAULT_PAGE, e.getMessage());
×
1904
                                        }
1905
                                        finally {
1906
                                                if (!hasErrors()) {
×
1907
                                                        // set this so that the wizard isn't run again on next page load
UNCOV
1908
                                                        setInitializationComplete(true);
×
1909
                                                        // we should also try to store selected by user language
1910
                                                        // if user wants to system will do it for him 
UNCOV
1911
                                                        FilterUtil.storeLocale(wizardModel.localeToSave);
×
1912
                                                }
UNCOV
1913
                                                setInstallationStarted(false);
×
1914
                                        }
UNCOV
1915
                                }
×
1916
                        };
1917
                        
UNCOV
1918
                        thread = new Thread(r);
×
UNCOV
1919
                }
×
1920
        }
1921
        
1922
        /**
1923
         * Convenience method that loads the database driver
1924
         *
1925
         * @param connection the database connection string
1926
         * @param databaseDriver the database driver class name to load
1927
         * @return the loaded driver string
1928
         */
1929
        public static String loadDriver(String connection, String databaseDriver) {
UNCOV
1930
                String loadedDriverString = null;
×
1931
                try {
UNCOV
1932
                        loadedDriverString = DatabaseUtil.loadDatabaseDriver(connection, databaseDriver);
×
UNCOV
1933
                        log.info("using database driver :" + loadedDriverString);
×
1934
                }
1935
                catch (ClassNotFoundException e) {
×
1936
                        log.error("The given database driver class was not found. "
×
1937
                                + "Please ensure that the database driver jar file is on the class path "
1938
                                + "(like in the webapp's lib folder)");
UNCOV
1939
                }
×
1940
                
UNCOV
1941
                return loadedDriverString;
×
1942
        }
1943
        
1944
        /**
1945
         * Utility method that checks if there is a runtime properties file containing database connection
1946
         * credentials
1947
         *
1948
         * @return
1949
         */
1950
        private static boolean skipDatabaseSetupPage() {
UNCOV
1951
                Properties props = OpenmrsUtil.getRuntimeProperties(WebConstants.WEBAPP_NAME);
×
1952
                return (props != null && StringUtils.hasText(props.getProperty("connection.url"))
×
1953
                        && StringUtils.hasText(props.getProperty("connection.username"))
×
1954
                        && StringUtils.hasText(props.getProperty("connection.password")));
×
1955
        }
1956
        
1957
        /**
1958
         * Utility methods that checks if the user clicked the back image
1959
         *
1960
         * @param httpRequest
1961
         * @return
1962
         */
1963
        private static boolean goBack(HttpServletRequest httpRequest) {
1964
                return "Back".equals(httpRequest.getParameter("back"))
×
UNCOV
1965
                        || (httpRequest.getParameter("back.x") != null && httpRequest.getParameter("back.y") != null);
×
1966
        }
1967
        
1968
        /**
1969
         * Convenience method to get custom installation script
1970
         *
1971
         * @return Properties from custom installation script or empty if none specified
1972
         * @throws RuntimeException if path to installation script is invalid
1973
         */
1974
        private Properties getInstallationScript() {
1975
                Properties prop = new Properties();
×
1976
                
UNCOV
1977
                String fileName = System.getProperty("OPENMRS_INSTALLATION_SCRIPT");
×
1978
                if (fileName == null) {
×
UNCOV
1979
                        return prop;
×
1980
                }
1981
                if (fileName.startsWith("classpath:")) {
×
1982
                        fileName = fileName.substring(10);
×
UNCOV
1983
                        InputStream input = null;
×
1984
                        try {
1985
                                input = getClass().getClassLoader().getResourceAsStream(fileName);
×
UNCOV
1986
                                prop.load(input);
×
UNCOV
1987
                                log.info("Using installation script from classpath: " + fileName);
×
1988
                                
1989
                                input.close();
×
1990
                        }
UNCOV
1991
                        catch (IOException ex) {
×
UNCOV
1992
                                log.error("Failed to load installation script from classpath: " + fileName, ex);
×
UNCOV
1993
                                throw new RuntimeException(ex);
×
1994
                        }
1995
                        finally {
UNCOV
1996
                                IOUtils.closeQuietly(input);
×
1997
                        }
UNCOV
1998
                } else {
×
UNCOV
1999
                        File file = new File(fileName);
×
UNCOV
2000
                        if (file.exists()) {
×
UNCOV
2001
                                InputStream input = null;
×
2002
                                try {
UNCOV
2003
                                        input = new FileInputStream(fileName);
×
UNCOV
2004
                                        prop.load(input);
×
UNCOV
2005
                                        log.info("Using installation script from absolute path: " + file.getAbsolutePath());
×
2006
                                        
UNCOV
2007
                                        input.close();
×
2008
                                }
UNCOV
2009
                                catch (IOException ex) {
×
UNCOV
2010
                                        log.error("Failed to load installation script from absolute path: " + file.getAbsolutePath(), ex);
×
UNCOV
2011
                                        throw new RuntimeException(ex);
×
2012
                                }
2013
                                finally {
UNCOV
2014
                                        IOUtils.closeQuietly(input);
×
2015
                                }
2016
                        }
2017
                }
UNCOV
2018
                return prop;
×
2019
        }
2020
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc