Here's the problem: The EJB throws this exception (from the glassfish logs):
SEVERE: Attempting to confirm previously confirmed login using confirmation UUID: b90b33ca-dc69-41c1-9c60-99152810c89b
com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException: Attempting to confirm previously confirmed login using confirmation UUID: b90b33ca-dc69-41c1-9c60-99152810c89b
at com.extremelatitudesoftware.security.auth.CredentialsController.checkForPreviousConfirmation(CredentialsController.java:244)
And on the client side of the exception stack (down at the bottom) I see this:
WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
at com.extremelatitudesoftware.accesscontrol.registration.RegistrationConfirmationBean.setChallengeQuestion(RegistrationConfirmationBean.java:61)
at com.extremelatitudesoftware.accesscontrol.registration.RegistrationConfirmationBean.fetchChallengeResponse(RegistrationConfirmationBean.java:51)
And of course in the browser I get a generic 500 exception error that says there was a null pointer exception.
I want to have a custom error page that detects the "com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException" and say something like "Oops you already confirmed this!"
Can someone point me in the right direction for getting the client/JSF layer to correctly "see" the exception so that this may be done.
This is the use case for the problem:
I have a method in the EJB layer that checks to see if a user has previously confirmed their login account. If they haven't it processes their request to confirm their new account. If they have say gone back to an old email and said, hmmmmm let's click on that again, the back end will detect that, throw the exception with the intent of it being picked up by the JSF/client layer and the user will be advised that the account is already confirmed.
Adding example code:
Method checking for condition and throwing exception if necessary. Note that the majority of the time this won't happen so I want to use this mechanism instead of making unnecessary calls every time someone confirms their account.
...
private void checkForPreviousConfirmation(Credentials cr)
throws LoginPreviouslyConfirmedException {
if (!(CredentialsStatusType.PENDING.equals(cr.getStatus()))
|| !(CredentialsDispositionType.WAITING.equals(cr.getDisposition()))) {
String msg = "Attempting to confirm previously confirmed login using "
+ "confirmation UUID: " + cr.getConfirmationUuid();
Logger.getLogger(CredentialsController.class.getName()).log(Level.INFO,
msg);
throw new LoginPreviouslyConfirmedException(msg);
}
}
The custom exception:
public class LoginPreviouslyConfirmedException extends RuntimeException {
public LoginPreviouslyConfirmedException(String msg, Throwable cause) {
super(msg, cause);
}
public LoginPreviouslyConfirmedException(String msg) {
super(msg);
}
}
This is in the ManagedBean in the JSF tier. It is called via: preRenderView
...
public void fetchChallengeResponse() {
try {
crespList = regFacade.fetchChallengeResponse(confirmUuid);
} catch (LoginPreviouslyConfirmedException ex) {
String msg = "Attempting to confirm previously confirmed login using " + "confirmation UUID: " + getConfirmUuid();
Logger.getLogger(RegistrationConfirmationBean.class.getName()).log(Level.SEVERE, msg, ex);
FacesContext facesContext = FacesContext.getCurrentInstance();
Application application = facesContext.getApplication();
NavigationHandler navigationHandler = application.getNavigationHandler();
navigationHandler.handleNavigation(facesContext, null, "faces/errorpages/already_confirmed.xhtml");
facesContext.renderResponse();
}catch (Exception ex){
String msg = "Including this to see if the previously confirmed exception was skipped over";
Logger.getLogger(RegistrationConfirmationBean.class.getName()).log(Level.SEVERE, msg, ex);
}
this.setChallengeQuestion();
}
This is what the log shows:
INFO: Attempting to confirm previously confirmed login using confirmation UUID: b90b33ca-dc69-41c1-9c60-99152810c89b
WARNING: EJB5184:A system exception occurred during an invocation on EJB CredentialsController, method: public java.util.ArrayList com.extremelatitudesoftware.security.auth.CredentialsController.fetchChallengeResponseByCredentialUuid(java.lang.String) throws com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException
WARNING: javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean
Then a couple traces down:
SEVERE: Including this to see if the previously confirmed exception was skipped over
javax.ejb.EJBTransactionRolledbackException
Per BalusC's suggestion I changed the code in the ManagedBean to this:
public void fetchChallengeResponse() throws LoginPreviouslyConfirmedException{
crespList = regFacade.fetchChallengeResponse(confirmUuid);
this.setChallengeQuestion();
}
This is in the web.xml
<error-page>
<exception-type>com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException</exception-type>
<location>/errorpages/already_confirmed.xhtml</location>
</error-page>