There's an issue I've experienced this day. I have an interceptor that begins and commits a Hibernate transaction and it may throw an exception on commit (org.hibernate.StaleObjectStateException
for instance). That is, it can throw an exception but exception doesn't get to the handler. I thought there's an issue in my code. But then I wrote a simple test and here it is
Package definition in struts.xml
:
<package name="basicstruts2" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="dummy" class="test.TestInterceptor"/>
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="dummy" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
<global-results>
<result name="exception" type="chain">exceptionHandler</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="exception" />
</global-exception-mappings>
<action name="test" class="test.TestAction">
<result>result.jsp</result>
</action>
<action name="exceptionHandler" class="test.ExceptionHandler">
<result>DebugErrorPage.jsp</result>
</action>
</package>
TestAction.java
:
package test;
public class TestAction extends ActionSupport {
private BusinessLogic logic = new BusinessLogic();
public String execute() {
logic.test();
return SUCCESS;
}
}
TestInterceptor.java
:
package test;
public class TestInterceptor implements Interceptor {
@Override
public String intercept(ActionInvocation arg0) throws Exception {
String result = null;
try {
result = arg0.invoke();
boolean flag = true;
if (flag) throw new RuntimeException("qwerty");
} catch (Exception e) {
System.out.println("exception catched in interceptor, rethrowing " + e);
throw e;
}
return result;
}
}
ExceptionHandler.java
:
package test;
public class ExceptionHandler extends ActionSupport {
private Exception exception;
public void setException(Exception e) {
exception = e;
System.out.println("setting exception");
}
public String execute() {
System.out.println("exeption in handler " + exception);
return SUCCESS;
}
}
BusinessLogic.java
:
package test;
public class BusinessLogic {
public void test() {
System.out.println("test logic");
// boolean flag = true;
// if (flag) throw new RuntimeException("qwerty");
}
}
So, console output :
test logic
exception catched in interceptor, rethrowing java.lang.RuntimeException: qwerty
BUT if an exception is thrown by BusinnesLogic, we can uncomment code:
BusinessLogic.java
:
package test;
public class BusinessLogic {
public void test() {
System.out.println("test logic");
boolean flag = true;
if (flag) throw new RuntimeException("qwerty");
}
}
and comment out code in interceptor:
@Override
public String intercept(ActionInvocation arg0) throws Exception {
String result = null;
try {
result = arg0.invoke();
// boolean flag = true;
// if (flag) throw new RuntimeException("qwerty");
} catch (Exception e) {
System.out.println("exception catched in interceptor, rethrowing " + e);
throw e;
}
return result;
}
output will be:
test logic
exception catched in interceptor, rethrowing java.lang.RuntimeException: qwerty
setting exception
exeption in handler java.lang.RuntimeException: qwerty
And we will see the error page.
So, can anybody give a good explanation of this behavior? What's the point of putting the exception interceptor at the top of the default struts stack if it can't handle exceptions that was thrown by other interceptors? and why?? I would really appreciate for a good answer.
EDIT: There is a code I have a problem with:
public String intercept(ActionInvocation arg0) throws Exception {
String result = null;
try {
sf.getCurrentSession().beginTransaction();
result = arg0.invoke();
sf.getCurrentSession().getTransaction().commit();
} catch (StaleObjectStateException staleEx) {
if (sf.getCurrentSession().getTransaction().isActive()) {
sf.getCurrentSession().getTransaction().rollback();
}
throw staleEx;
} catch (Exception ex) {
ex.printStackTrace();
try {
if (sf.getCurrentSession().getTransaction().isActive()) {
sf.getCurrentSession().getTransaction().rollback();
}
} catch (Throwable rbEx) {
}
// Let others handle it... maybe another interceptor for exceptions?
throw new ServletException(ex);
}
return result;
}
What should be done if I want handle exceptions thrown on commit()
?