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

openmrs / openmrs-core / 14177712917

31 Mar 2025 05:35PM UTC coverage: 65.083% (+0.003%) from 65.08%
14177712917

push

github

ibacher
Restore debugging when using JDKs newer than 8

With JDK 9, Java's debugging shifted so that it's possible to specify not only the port, but also the IP address that the debugger should listen on. This adapts things to fit the new syntax that reflects this, but only if we're running JDK 9 or newer.

Theoretically, it would be possible to somehow calculate this at image build time, but this is pretty limited use-case.

23407 of 35965 relevant lines covered (65.08%)

0.65 hits per line

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

93.55
/api/src/main/java/org/openmrs/validator/PatientProgramValidator.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.validator;
11

12
import java.util.Date;
13
import java.util.HashSet;
14
import java.util.Set;
15

16
import org.openmrs.PatientProgram;
17
import org.openmrs.PatientState;
18
import org.openmrs.ProgramWorkflow;
19
import org.openmrs.annotation.Handler;
20
import org.openmrs.api.context.Context;
21
import org.openmrs.messagesource.MessageSourceService;
22
import org.openmrs.util.OpenmrsUtil;
23
import org.slf4j.Logger;
24
import org.slf4j.LoggerFactory;
25
import org.springframework.validation.Errors;
26
import org.springframework.validation.ValidationUtils;
27
import org.springframework.validation.Validator;
28

29
/**
30
 * This class validates a {@link PatientProgram} object
31
 *
32
 * @since 1.9
33
 */
34
@Handler(supports = { PatientProgram.class }, order = 50)
35
public class PatientProgramValidator implements Validator {
1✔
36
        
37
        private static final Logger log = LoggerFactory.getLogger(PatientProgramValidator.class);
1✔
38
        
39
        /**
40
         * @see org.springframework.validation.Validator#supports(java.lang.Class)
41
         */
42
        @Override
43
        public boolean supports(Class<?> c) {
44
                return PatientProgram.class.isAssignableFrom(c);
1✔
45
        }
46
        
47
        /**
48
         * Validates the given PatientProgram.
49
         *
50
         * @param obj The patient program to validate.
51
         * @param errors Errors
52
         * @see org.springframework.validation.Validator#validate(java.lang.Object,
53
         *      org.springframework.validation.Errors)
54
         * <strong>Should</strong> fail validation if obj is null
55
         * <strong>Should</strong> fail if the patient field is blank
56
         * <strong>Should</strong> fail if there is more than one patientState with the same states and startDates
57
         * <strong>Should</strong> fail if there is more than one state with a null start date in the same workflow
58
         * <strong>Should</strong> pass if the start date of the first patient state in the work flow is null
59
         * <strong>Should</strong> fail if any patient state has an end date before its start date
60
         * <strong>Should</strong> fail if the program property is null
61
         * <strong>Should</strong> fail if any patient states overlap each other in the same work flow
62
         * <strong>Should</strong> fail if a patientState has an invalid work flow state
63
         * <strong>Should</strong> fail if a patient program has duplicate states in the same work flow
64
         * <strong>Should</strong> fail if a patient is in multiple states in the same work flow
65
         * <strong>Should</strong> fail if a enrolled date is in future at the date it set
66
         * <strong>Should</strong> fail if a completion date is in future at the date it set
67
         * <strong>Should</strong> fail if a patient program has an enroll date after its completion
68
         * <strong>Should</strong> pass if a patient is in multiple states in different work flows
69
         * <strong>Should</strong> pass for a valid program
70
         * <strong>Should</strong> pass for patient states that have the same start dates in the same work flow
71
         * <strong>Should</strong> pass validation if field lengths are correct
72
         * <strong>Should</strong> fail validation if field lengths are not correct
73
         */
74
        @Override
75
        public void validate(Object obj, Errors errors) {
76
                log.debug("{}.validate...", this.getClass().getName());
1✔
77
                
78
                if (obj == null) {
1✔
79
                        throw new IllegalArgumentException("The parameter obj should not be null");
1✔
80
                }
81
                MessageSourceService mss = Context.getMessageSourceService();
1✔
82
                PatientProgram patientProgram = (PatientProgram) obj;
1✔
83
                ValidationUtils.rejectIfEmpty(errors, "patient", "error.required",
1✔
84
                    new Object[] { mss.getMessage("general.patient") });
1✔
85
                ValidationUtils.rejectIfEmpty(errors, "program", "error.required",
1✔
86
                    new Object[] { mss.getMessage("Program.program") });
1✔
87
                
88
                if (errors.hasErrors()) {
1✔
89
                        return;
1✔
90
                }
91
                
92
                ValidationUtils.rejectIfEmpty(errors, "dateEnrolled", "error.patientProgram.enrolledDateEmpty");
1✔
93
                
94
                Date today = new Date();
1✔
95
                if (patientProgram.getDateEnrolled() != null && today.before(patientProgram.getDateEnrolled())) {
1✔
96
                        errors.rejectValue("dateEnrolled", "error.patientProgram.enrolledDateDateCannotBeInFuture");
1✔
97
                }
98
                
99
                if (patientProgram.getDateCompleted() != null && today.before(patientProgram.getDateCompleted())) {
1✔
100
                        errors.rejectValue("dateCompleted", "error.patientProgram.completionDateCannotBeInFuture");
1✔
101
                }
102
                
103
                // if enrollment or complete date of program is in future or complete date has come before enroll date we should throw error
104
                if (patientProgram.getDateEnrolled() != null
1✔
105
                        && OpenmrsUtil.compareWithNullAsLatest(patientProgram.getDateCompleted(), patientProgram.getDateEnrolled()) < 0) {
1✔
106
                        errors.rejectValue("dateCompleted", "error.patientProgram.enrolledDateShouldBeBeforecompletionDate");
1✔
107
                }
108
                
109
                Set<ProgramWorkflow> workFlows = patientProgram.getProgram().getWorkflows();
1✔
110
                //Patient state validation is specific to a work flow
111
                for (ProgramWorkflow workFlow : workFlows) {
1✔
112
                        Set<PatientState> patientStates = patientProgram.getStates();
1✔
113
                        if (patientStates != null) {
1✔
114
                                //Set to store to keep track of unique valid state and start date combinations
115
                                Set<String> statesAndStartDates = new HashSet<>();
1✔
116
                                PatientState latestState = null;
1✔
117
                                boolean foundCurrentPatientState = false;
1✔
118
                                boolean foundStateWithNullStartDate = false;
1✔
119
                                for (PatientState patientState : patientStates) {
1✔
120
                                        if (patientState.getVoided()) {
1✔
121
                                                continue;
1✔
122
                                        }
123
                                        
124
                                        String missingRequiredFieldCode = null;
1✔
125
                                        //only the initial state can have a null start date
126
                                        if (patientState.getStartDate() == null) {
1✔
127
                                                if (foundStateWithNullStartDate) {
1✔
128
                                                        missingRequiredFieldCode = "general.dateStart";
1✔
129
                                                } else {
130
                                                        foundStateWithNullStartDate = true;
1✔
131
                                                }
132
                                        } else if (patientState.getState() == null) {
1✔
133
                                                missingRequiredFieldCode = "State.state";
1✔
134
                                        }
135
                                        
136
                                        if (missingRequiredFieldCode != null) {
1✔
137
                                                errors.rejectValue("states", "PatientState.error.requiredField", new Object[] { mss
1✔
138
                                                        .getMessage(missingRequiredFieldCode) }, null);
1✔
139
                                                return;
1✔
140
                                        }
141
                                        
142
                                        //state should belong to one of the workflows in the program
143
                                        // note that we are iterating over getAllWorkflows() here because we want to include
144
                                        // retired workflows, and the workflows variable does not include retired workflows
145
                                        boolean isValidPatientState = false;
1✔
146
                                        for (ProgramWorkflow wf : patientProgram.getProgram().getAllWorkflows()) {
1✔
147
                                                if (wf.getStates().contains(patientState.getState())) {
1✔
148
                                                        isValidPatientState = true;
1✔
149
                                                        break;
1✔
150
                                                }
151
                                        }
1✔
152
                                        
153
                                        if (!isValidPatientState) {
1✔
154
                                                errors.rejectValue("states", "PatientState.error.invalidPatientState",
1✔
155
                                                    new Object[] { patientState }, null);
156
                                                return;
1✔
157
                                        }
158
                                        
159
                                        //will validate it with other states in its workflow
160
                                        if (!patientState.getState().getProgramWorkflow().equals(workFlow)) {
1✔
161
                                                continue;
1✔
162
                                        }
163
                                        
164
                                        if (OpenmrsUtil.compareWithNullAsLatest(patientState.getEndDate(), patientState.getStartDate()) < 0) {
1✔
165
                                                errors.rejectValue("states", "PatientState.error.endDateCannotBeBeforeStartDate");
1✔
166
                                                return;
1✔
167
                                        } else if (statesAndStartDates.contains(patientState.getState().getUuid() + ""
1✔
168
                                                + patientState.getStartDate())) {
1✔
169
                                                // we already have a patient state with the same work flow state and start date
170
                                                errors.rejectValue("states", "PatientState.error.duplicatePatientStates");
1✔
171
                                                return;
1✔
172
                                        }
173
                                        
174
                                        //Ensure that the patient is only in one state at a given time
175
                                        if (!foundCurrentPatientState && patientState.getEndDate() == null) {
1✔
176
                                                foundCurrentPatientState = true;
1✔
177
                                        } else if (foundCurrentPatientState && patientState.getEndDate() == null) {
1✔
178
                                                errors.rejectValue("states", "PatientProgram.error.cannotBeInMultipleStates");
1✔
179
                                                return;
1✔
180
                                        }
181
                                        
182
                                        if (latestState == null) {
1✔
183
                                                latestState = patientState;
1✔
184
                                        } else {
185
                                                if (patientState.compareTo(latestState) > 0) {
1✔
186
                                                        //patient should have already left this state since it is older
187
                                                        if (latestState.getEndDate() == null) {
1✔
188
                                                                errors.rejectValue("states", "PatientProgram.error.cannotBeInMultipleStates");
×
189
                                                                return;
×
190
                                                        } else if (OpenmrsUtil.compareWithNullAsEarliest(patientState.getStartDate(), latestState
1✔
191
                                                                .getEndDate()) < 0) {
1✔
192
                                                                //current state was started before a previous state was ended
193
                                                                errors.rejectValue("states", "PatientProgram.error.foundOverlappingStates", new Object[] {
1✔
194
                                                                        patientState.getStartDate(), latestState.getEndDate() }, null);
1✔
195
                                                                return;
1✔
196
                                                        }
197
                                                        latestState = patientState;
1✔
198
                                                } else if (patientState.compareTo(latestState) < 0) {
1✔
199
                                                        //patient should have already left this state since it is older
200
                                                        if (patientState.getEndDate() == null) {
1✔
201
                                                                errors.rejectValue("states", "PatientProgram.error.cannotBeInMultipleStates");
×
202
                                                                return;
×
203
                                                        } else if (OpenmrsUtil.compareWithNullAsEarliest(latestState.getStartDate(), patientState
1✔
204
                                                                .getEndDate()) < 0) {
1✔
205
                                                                //latest state was started before a previous state was ended
206
                                                                errors.rejectValue("states", "PatientProgram.error.foundOverlappingStates");
×
207
                                                                return;
×
208
                                                        }
209
                                                }
210
                                        }
211
                                        
212
                                        statesAndStartDates.add(patientState.getState().getUuid() + "" + patientState.getStartDate());
1✔
213
                                }
1✔
214
                        }
215
                }
1✔
216
                ValidateUtil.validateFieldLengths(errors, obj.getClass(), "voidReason");
1✔
217
                //
218
        }
1✔
219
}
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