The code is bad not only because the magic numbers, but because it coalesces several meanings in the return code, hiding inside of its meaning an error, a warning, a permission to create a session or a combination of the three, which makes it a bad input for decision making.
I would suggest the following refactoring: returning an enum with the possible results (as suggested in other answers), but adding to the enum an attribute indicating whether it is a denial, a waiver (I'll let you pass this last time) or if it is OK (PASS):
public LoginResult processLogin(HttpServletRequest request, HttpServletResponse response,
int pwChangeDays, ServletContext ServContext) {
}
==> LoginResult.java <==
public enum LoginResult {
NOT_LOGGED_IN(Severity.DENIAL),
ALREADY_LOGGED_IN(Severity.PASS),
INACTIVE_USER(Severity.DENIAL),
VALID_USER(Severity.PASS),
NEEDS_PASSWORD_CHANGE(Severity.WAIVER),
INVALID_APP_USER(Severity.DENIAL),
INVALID_NETWORK_USER(Severity.DENIAL),
NON_APPROVED_ADDRESS(Severity.DENIAL),
ACCOUNT_LOCKED(Severity.DENIAL),
ACCOUNT_WILL_BE_LOCKED(Severity.WAIVER);
private Severity severity;
private LoginResult(Severity severity) {
this.severity = severity;
}
public Severity getSeverity() {
return this.severity;
}
}
==> Severity.java <==
public enum Severity {
PASS,
WAIVER,
DENIAL;
}
==> Test.java <==
public class Test {
public static void main(String[] args) {
for (LoginResult r: LoginResult.values()){
System.out.println(r + " " +r.getSeverity());
}
}
}
Output for Test.java showing the severity for each LoginResult:
NOT_LOGGED_IN : DENIAL
ALREADY_LOGGED_IN : PASS
INACTIVE_USER : DENIAL
VALID_USER : PASS
NEEDS_PASSWORD_CHANGE : WAIVER
INVALID_APP_USER : DENIAL
INVALID_NETWORK_USER : DENIAL
NON_APPROVED_ADDRESS : DENIAL
ACCOUNT_LOCKED : DENIAL
ACCOUNT_WILL_BE_LOCKED : WAIVER
Based on both the enum value and its severity, you can decide whether creation of session proceeds or not.
EDIT:
As a response to @T.Sar's comment, I changed the severity's possible values to PASS,WAIVER and DENIAL instead of (OK,WARNING and ERROR). That way it is clear that a DENIAL (previously ERROR) is not an error per se and shouldn't necessarily translate into throwing an exception. The caller examines the object and decides whether or not to throw an exception, but DENIAL is a valid result status resulting from calling processLogin(...)
.
- PASS: go ahead, create a session if one doesn't already exist
- WAIVER: go ahead this time, but next time user you may not be allowed to pass
- DENIAL: sorry, user cannot pass, don't create a session