Skip to content

Commit

Permalink
#37 : handle errors and timeouts tbc
Browse files Browse the repository at this point in the history
  • Loading branch information
vankeisb committed Jan 13, 2016
1 parent 8fac7da commit 26fcaa4
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,26 @@ public void cancelled() {
};
}

@DontValidate
public Resolution asyncEventThatTimeouts() {
return new AsyncResolution() {
public void execute(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
getAsyncContext().setTimeout(1000);
getAsyncContext().getResponse().getWriter().write("OK");
// never call complete/dispatch...
}
};
}

@DontValidate
public Resolution asyncEventThatThrows() {
return new AsyncResolution() {
public void execute(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
throw new RuntimeException("WTF");
}
};
}

private void dispatch(CloseableHttpAsyncClient asyncClient, AsyncContext c) {
try {
asyncClient.close();
Expand Down
8 changes: 8 additions & 0 deletions examples/src/main/webapp/WEB-INF/async/async.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
<s:param name="someProp" value="foobar"/>
I'm an async event
</s:link>
<br/>
<s:link beanclass="<%=AsyncActionBean.class%>" event="asyncEventThatTimeouts">
I'm an async event that timeouts
</s:link>
<br/>
<s:link beanclass="<%=AsyncActionBean.class%>" event="asyncEventThatThrows">
I'm an async event that throws an Exception
</s:link>
<hr/>
<s:errors/>
<s:form beanclass="<%=AsyncActionBean.class%>">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,36 +188,52 @@ protected void service(final HttpServletRequest request, final HttpServletRespon
final PageContext pc = pageContext;
// register listener for finalizing the async processing
asyncContext.addListener(new AsyncListener() {
// TODO factor out and make sure this finalizations are needed...
public void onComplete(AsyncEvent event) throws IOException {
if (pc != null) {
JspFactory.getDefaultFactory().releasePageContext(pc);
DispatcherHelper.setPageContext(null);

private boolean completed = false;

private void doComplete() {
if (!completed) {
completed = true;
if (pc != null) {
JspFactory.getDefaultFactory().releasePageContext(pc);
DispatcherHelper.setPageContext(null);
}
requestComplete(ctx);
restoreActionBean(request);
}
requestComplete(ctx);
restoreActionBean(request);
}

public void onComplete(AsyncEvent event) throws IOException {
log.debug("Async context completed=", event.getAsyncContext());
doComplete();
}

// TODO i18n, use stripes exception handlers
public void onTimeout(AsyncEvent event) throws IOException {
if (pc != null) {
JspFactory.getDefaultFactory().releasePageContext(pc);
DispatcherHelper.setPageContext(null);
}
requestComplete(ctx);
restoreActionBean(request);
log.error("Async context timeout after ", event.getAsyncContext().getTimeout(), "ms, ctx=", event.getAsyncContext());
HttpServletResponse response = (HttpServletResponse)event.getSuppliedResponse();
response.sendError(500, "Operation timed out");

// TODO understand why we need to call this
// if we don't then dispatcher is called twice (probably
// because of server side dispatch)
event.getAsyncContext().complete();
}

public void onError(AsyncEvent event) throws IOException {
if (pc != null) {
JspFactory.getDefaultFactory().releasePageContext(pc);
DispatcherHelper.setPageContext(null);
}
requestComplete(ctx);
restoreActionBean(request);
log.error("Async context error=", event.getAsyncContext());
HttpServletResponse response = (HttpServletResponse)event.getSuppliedResponse();
Throwable err = event.getThrowable();
String msg = err != null ? err.getMessage() : "";
response.sendError(500, msg);
doComplete();
}

// this one is not called because we register the listener after starting the async context...
public void onStartAsync(AsyncEvent event) throws IOException {

log.debug("Async context started=", event.getAsyncContext(),
"request=", event.getSuppliedRequest(),
"response=", event.getSuppliedResponse());
}
});
AsyncResolution asyncResolution = (AsyncResolution)resolution;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.sourceforge.stripes.mock;

/**
* Created by vankeisb on 13/01/16.
*/
public class MockAsyncContext {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.sourceforge.stripes.mock;

import net.sourceforge.stripes.FilterEnabledTestBase;
import net.sourceforge.stripes.action.*;
import org.testng.Assert;
import org.testng.annotations.Test;

import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestMockAsync extends FilterEnabledTestBase {

@Test(groups="fast")
public void testDefaultEvent() throws Exception {
MockRoundtrip trip = new MockRoundtrip(getMockServletContext(), AsyncActionBean.class);
trip.execute();

AsyncActionBean bean = trip.getActionBean(AsyncActionBean.class);
Assert.assertNotNull(bean);
}


@UrlBinding("/async")
public static class AsyncActionBean implements ActionBean {

private boolean completed = false;
private ActionBeanContext context;

public ActionBeanContext getContext() {
return context;
}

public void setContext(ActionBeanContext context) {
this.context = context;
}

@DefaultHandler
public Resolution doAsync() {
return new AsyncResolution() {
public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
Thread.sleep(5000);
AsyncContext asyncContext = getAsyncContext();
asyncContext.getResponse().getWriter().write("DONE");
asyncContext.complete();
}
};
}


}


}

0 comments on commit 26fcaa4

Please sign in to comment.