First of all, my framework is Java EE 6 with JSF, managed bean, EJB and JPA. I write a simple program to query information from the database. So when I click a button, it trigger an event to a managed bean, where an event listener method will access EJB method. The EJB method will do a simple select
query to an Entity. If the database is shutdown before or during the time I select
, I get an exception
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 51,460 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago.
Error Code: 0
How do I safeguard away from this Exception? Definitely a try, catch
here, but not sure where to put it. When I do em.createNamedQuery
or em.remove
, I try to catch com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
, but I got an error said: Exception com.mysql.jdbc.exceptions.jdbc4.CommunicationsException is never thrown in body of corresponding try statement
.
Below are my codes, where would I catch the Exception?
This is my EJB
@Stateless
@LocalBean
public class DocumentSBean {
@PersistenceContext
private EntityManager em;
public List<User> listUser(){
Query query = em.createNamedQuery("User.listUser");
query.returnResultList();
}
}
This is my ManagedBean
@ManagedBean(name="document")
@ViewScoped
public class DisplayListController implements Serializable {
@EJB
DocumentSBean sBean;
List<User> users = null;
public void foo(){
users = sBean.listUser();
}
}
EDIT
I try both ways as listed below, but still return status 200 instead of 500 on firebug
<p:commandButton update="myform" actionListener="#{document.setDisplayFacility}" rendered="#{utility.admin}" value="Facilities"/>
OR
<p:commandButton update="myform" actionListener="#{document.setDisplayFacility}" rendered="#{utility.admin}" value="Facilities">
<p:ajax actionListener="#{document.setDisplayFacility}" update="myform" event="click"/>
</p:commandButton>
Here is setDisplayFacility()
public void setDisplayFacility(){
facilities = sBean.getAllFacilities(); //sBean is EJB
displayFacility = true;
}
How do I safeguard away from this Exception? Definitely a try, catch here, but not sure where to put it.
Only catch the exception there where you can handle it in a reasonable manner.
I try to catch com.mysql.jdbc.exceptions.jdbc4.CommunicationsException, but I got an error said: Exception com.mysql.jdbc.exceptions.jdbc4.CommunicationsException is never thrown in body of corresponding try statement.
The CommunicationsException
is in this case a nested exception of DatabaseException
. EclipseLink is under the covers already catching the CommunicationsException
and rethrowing it as DatabaseException
with the CommunicationsException
as root cause. Something like:
try {
// Execute query.
} catch (Exception e) {
throw new DatabaseException("Internal Exception: " + e, e);
}
In theory, you can only handle it as follows:
try {
// Let EclipseLink execute query.
} catch (DatabaseException e) {
if (e.getCause() instanceof CommunicationsException) {
// Handle.
}
}
Which is however ugly and not recommended in this particular case.
Below are my codes, where would I catch the Exception?
Depends on how you would like to handle the exception. If you want to display it in a generic error page, then you should not catch it yourself, but just let it go. The servletcontainer will then catch and handle it itself. It will lookup the best matching <error-page>
in the web.xml
and display it.
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/generic-error.xhtml</location>
</error-page>
This one will display /generic-error.xhtml
for all subclasses of java.lang.Exception
.
If you want to display it in a specific error page, then you need to declare the <exception-type>
more specific to match the actual exception type. E.g.:
<error-page>
<exception-type>org.eclipse.persistence.exceptions.DatabaseException</exception-type>
<location>/database-error.xhtml</location>
</error-page>
However, although not explicitly specified in your question, I know based on your question history that you're using JSF with PrimeFaces. You need to keep in mind that PrimeFaces will not display the error page when the initial request was made by ajax. Instead, its ajax view handler has already catched the exception itself and it will delegate to the <p:ajaxStatus>
component in the view. Try adding ajax="false"
to the PrimeFaces command component and you'll finally see the servletcontainer's default error page being displayed (or any of yours if a matching one in web.xml
is found).
If you want to display some generic JSF UI when PrimeFaces received an ajax error, then use the error
facet of <p:ajaxStatus>
. E.g.
<p:ajaxStatus>
<f:facet name="start"><h:graphicImage value="images/ajax-loader.gif" /></f:facet>
<f:facet name="success"><h:outputText value="" /></f:facet>
<f:facet name="error">
<h:panelGroup layout="block" styleClass="ui-message-error ui-widget ui-corner-all">
<h:outputText value="An error has occurred!" /><br />
<h:outputLink value="#" onclick="window.location.reload(true)"><h:outputText value="Please reload page and retry" /></h:outputLink><br />
<h:outputLink value="mailto:support@example.com?subject=Ajax%20Error"><h:outputText value="If in vain, please contact support" /></h:outputLink>
</h:panelGroup>
</f:facet>
</p:ajaxStatus>
(there's however some bug in PrimeFaces 2.2 RC1 which causes displaying the error facet to fail, it works correctly in PrimeFaces 2.1)