Repository: dropwizard/metrics
Issue: Another ClassCastException in metrics-jetty9's InstrumentedHandler

I found another ClassCastException in metrics-jetty9. Commit 622ef9b which is included in 3.0.1 doesn't seem to completly fix issue #435 that I reported earlier.

```
java.lang.ClassCastException: org.atmosphere.cpr.AtmosphereRequest cannot be cast to org.eclipse.jetty.server.Request
    at com.codahale.metrics.jetty9.InstrumentedHandler$1.onComplete(InstrumentedHandler.java:140) ~[metrics-jetty9-3.0.1.jar:3.0.1]
    at org.eclipse.jetty.server.HttpChannelState.completed(HttpChannelState.java:470) ~[jetty-server-9.0.4.v20130625.jar:9.0.4.v20130625]
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:315) ~[jetty-server-9.0.4.v20130625.jar:9.0.4.v20130625]
    at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:228) ~[jetty-server-9.0.4.v20130625.jar:9.0.4.v20130625]
    at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1143) ~[jetty-server-9.0.4.v20130625.jar:9.0.4.v20130625]
    at org.eclipse.jetty.server.HttpChannelState.complete(HttpChannelState.java:432) ~[jetty-server-9.0.4.v20130625.jar:9.0.4.v20130625]
    at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:90) ~[jetty-server-9.0.4.v20130625.jar:9.0.4.v20130625]
    at org.atmosphere.container.Servlet30CometSupport.action(Servlet30CometSupport.java:157) ~[atmosphere-runtime-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.atmosphere.container.Servlet30CometSupport.action(Servlet30CometSupport.java:79) ~[atmosphere-runtime-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.atmosphere.cpr.AtmosphereResourceImpl.resume(AtmosphereResourceImpl.java:326) ~[atmosphere-runtime-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.atmosphere.jersey.util.JerseyBroadcasterUtil.broadcast(JerseyBroadcasterUtil.java:161) ~[atmosphere-jersey-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.atmosphere.jersey.JerseyBroadcaster.invokeOnStateChange(JerseyBroadcaster.java:77) ~[atmosphere-jersey-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.atmosphere.cpr.DefaultBroadcaster.prepareInvokeOnStateChange(DefaultBroadcaster.java:1047) ~[atmosphere-runtime-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.atmosphere.cpr.DefaultBroadcaster.executeAsyncWrite(DefaultBroadcaster.java:921) ~[atmosphere-runtime-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.atmosphere.cpr.DefaultBroadcaster$3.run(DefaultBroadcaster.java:580) ~[atmosphere-runtime-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) ~[na:1.7.0_25]
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) ~[na:1.7.0_25]
    at java.util.concurrent.FutureTask.run(FutureTask.java:166) ~[na:1.7.0_25]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) ~[na:1.7.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) ~[na:1.7.0_25]
    at java.lang.Thread.run(Thread.java:724) ~[na:1.7.0_25]
```


Changed files:
metrics-jetty9-legacy/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java
metrics-jetty9/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java

diff --git a/metrics-jetty9-legacy/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java b/metrics-jetty9-legacy/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java
index 56805cdc9..503e7867f 100644
--- a/metrics-jetty9-legacy/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java
+++ b/metrics-jetty9-legacy/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java
@@ -133,6 +133,8 @@ public class InstrumentedHandler extends HandlerWrapper {
         this.otherRequests = metricRegistry.timer(name(prefix, "other-requests"));
 
         this.listener = new AsyncListener() {
+            private long startTime;
+
             @Override
             public void onTimeout(AsyncEvent event) throws IOException {
                 asyncTimeouts.mark();
@@ -140,6 +142,7 @@ public class InstrumentedHandler extends HandlerWrapper {
 
             @Override
             public void onStartAsync(AsyncEvent event) throws IOException {
+                startTime = System.currentTimeMillis();
                 event.getAsyncContext().addListener(this);
             }
 
@@ -150,8 +153,9 @@ public class InstrumentedHandler extends HandlerWrapper {
             @Override
             public void onComplete(AsyncEvent event) throws IOException {
                 final AsyncContextState state = (AsyncContextState) event.getAsyncContext();
-                final Request request = (Request) state.getRequest();
-                updateResponses(request);
+                final HttpServletRequest request = (HttpServletRequest) state.getRequest();
+                final HttpServletResponse response = (HttpServletResponse) state.getResponse();
+                updateResponses(request, response, startTime);
                 if (!state.getHttpChannelState().isDispatched()) {
                     activeSuspended.dec();
                 }
@@ -197,7 +201,7 @@ public class InstrumentedHandler extends HandlerWrapper {
                 }
                 activeSuspended.inc();
             } else if (state.isInitial()) {
-                updateResponses(request);
+                updateResponses(httpRequest, httpResponse, start);
             }
             // else onCompletion will handle it.
         }
@@ -233,13 +237,13 @@ public class InstrumentedHandler extends HandlerWrapper {
         }
     }
 
-    private void updateResponses(Request request) {
-        final int response = request.getResponse().getStatus() / 100;
-        if (response >= 1 && response <= 5) {
-            responses[response - 1].mark();
+    private void updateResponses(HttpServletRequest request, HttpServletResponse response, long start) {
+        final int responseStatus = response.getStatus() / 100;
+        if (responseStatus >= 1 && responseStatus <= 5) {
+            responses[responseStatus - 1].mark();
         }
         activeRequests.dec();
-        final long elapsedTime = System.currentTimeMillis() - request.getTimeStamp();
+        final long elapsedTime = System.currentTimeMillis() - start;
         requests.update(elapsedTime, TimeUnit.MILLISECONDS);
         requestTimer(request.getMethod()).update(elapsedTime, TimeUnit.MILLISECONDS);
     }
diff --git a/metrics-jetty9/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java b/metrics-jetty9/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java
index 3c31cb66f..27b03900a 100644
--- a/metrics-jetty9/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java
+++ b/metrics-jetty9/src/main/java/com/codahale/metrics/jetty9/InstrumentedHandler.java
@@ -133,6 +133,8 @@ public class InstrumentedHandler extends HandlerWrapper {
         this.otherRequests = metricRegistry.timer(name(prefix, "other-requests"));
 
         this.listener = new AsyncListener() {
+            private long startTime;
+
             @Override
             public void onTimeout(AsyncEvent event) throws IOException {
                 asyncTimeouts.mark();
@@ -140,6 +142,7 @@ public class InstrumentedHandler extends HandlerWrapper {
 
             @Override
             public void onStartAsync(AsyncEvent event) throws IOException {
+                startTime = System.currentTimeMillis();
                 event.getAsyncContext().addListener(this);
             }
 
@@ -150,8 +153,9 @@ public class InstrumentedHandler extends HandlerWrapper {
             @Override
             public void onComplete(AsyncEvent event) throws IOException {
                 final AsyncContextState state = (AsyncContextState) event.getAsyncContext();
-                final Request request = (Request) state.getRequest();
-                updateResponses(request);
+                final HttpServletRequest request = (HttpServletRequest) state.getRequest();
+                final HttpServletResponse response = (HttpServletResponse) state.getResponse();
+                updateResponses(request, response, startTime);
                 if (state.getHttpChannelState().getState() != HttpChannelState.State.DISPATCHED) {
                     activeSuspended.dec();
                 }
@@ -197,7 +201,7 @@ public class InstrumentedHandler extends HandlerWrapper {
                 }
                 activeSuspended.inc();
             } else if (state.isInitial()) {
-                updateResponses(request);
+                updateResponses(httpRequest, httpResponse, start);
             }
             // else onCompletion will handle it.
         }
@@ -233,13 +237,13 @@ public class InstrumentedHandler extends HandlerWrapper {
         }
     }
 
-    private void updateResponses(Request request) {
-        final int response = request.getResponse().getStatus() / 100;
-        if (response >= 1 && response <= 5) {
-            responses[response - 1].mark();
+    private void updateResponses(HttpServletRequest request, HttpServletResponse response, long start) {
+        final int responseStatus = response.getStatus() / 100;
+        if (responseStatus >= 1 && responseStatus <= 5) {
+            responses[responseStatus - 1].mark();
         }
         activeRequests.dec();
-        final long elapsedTime = System.currentTimeMillis() - request.getTimeStamp();
+        final long elapsedTime = System.currentTimeMillis() - start;
         requests.update(elapsedTime, TimeUnit.MILLISECONDS);
         requestTimer(request.getMethod()).update(elapsedTime, TimeUnit.MILLISECONDS);
     }