package net.sourceforge.stripes.mock; import net.sourceforge.stripes.util.Log; import javax.servlet.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class MockAsyncContext implements AsyncContext { private static final Log log = Log.getInstance(MockAsyncContext.class); private final ServletRequest request; private final ServletResponse response; private final List<AsyncListener> listeners = new ArrayList<AsyncListener>(); private boolean completed = false; private boolean timedOut = false; private long timeout = 10000; private long startedOn; public MockAsyncContext(ServletRequest request, ServletResponse response) { this.startedOn = System.currentTimeMillis(); this.request = request; this.response = response; log.info("async started, request=", request, ", response=", response); } @Override public ServletRequest getRequest() { return request; } @Override public ServletResponse getResponse() { return response; } @Override public boolean hasOriginalRequestAndResponse() { return request != null && response != null; } private void checkNotCompleted() { if (completed) { throw new IllegalStateException("already dispatched or completed !"); } } @Override public void dispatch() { complete(); } @Override public void dispatch(String path) { dispatch(); } @Override public void dispatch(ServletContext context, String path) { dispatch(); } @Override public void complete() { checkNotCompleted(); completed = true; AsyncEvent evt = new AsyncEvent(this, request, response); for (AsyncListener l : listeners) { try { l.onComplete(evt); } catch (IOException e) { throw new RuntimeException(e); } } } @Override public void start(Runnable run) { throw new UnsupportedOperationException("TODO"); } @Override public void addListener(AsyncListener listener) { listeners.add(listener); } @Override public void addListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) { listeners.add(listener); } @Override public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException { try { return clazz.newInstance(); } catch (Exception e) { throw new ServletException(e); } } @Override public void setTimeout(long timeout) { this.timeout = timeout; } @Override public long getTimeout() { return timeout; } public void waitForCompletion() throws Exception { log.debug("Waiting for completion..."); while(true) { long elapsed = System.currentTimeMillis() - startedOn; if (elapsed > timeout) { timedOut = true; // invoke listeners timeout AsyncEvent timeoutEvent = new AsyncEvent(MockAsyncContext.this, request, response); for (AsyncListener l : listeners) { try { l.onTimeout(timeoutEvent); } catch (Exception e) { log.warn("listener onTimeout threw exception", e); } } log.error("Operation timed out, will throw exception"); throw new RuntimeException("Operation timed out (elapsed=" + elapsed + ", timeout=" + timeout + ")"); } else if (completed) { log.debug("...Completed in ", elapsed, "ms"); break; } Thread.sleep(200); } } public long getStartedOn() { return startedOn; } public boolean isTimedOut() { return timedOut; } public boolean isCompleted() { return completed; } }