15
15
*/
16
16
package org .asynchttpclient .providers .netty .request ;
17
17
18
+ import io .netty .channel .Channel ;
18
19
import io .netty .channel .ChannelProgressiveFuture ;
19
20
import io .netty .channel .ChannelProgressiveFutureListener ;
20
21
21
22
import java .nio .channels .ClosedChannelException ;
22
- import java .util .concurrent .atomic .AtomicLong ;
23
23
24
24
import org .asynchttpclient .AsyncHandler ;
25
25
import org .asynchttpclient .AsyncHttpClientConfig ;
31
31
import org .slf4j .LoggerFactory ;
32
32
33
33
public class ProgressListener implements ChannelProgressiveFutureListener {
34
-
34
+
35
35
private static final Logger LOGGER = LoggerFactory .getLogger (ProgressListener .class );
36
36
37
37
private final AsyncHttpClientConfig config ;
38
38
private final boolean notifyHeaders ;
39
39
private final AsyncHandler <?> asyncHandler ;
40
40
private final NettyResponseFuture <?> future ;
41
- private final AtomicLong lastProgress = new AtomicLong ( 0 ) ;
41
+ private long lastProgress = 0L ;
42
42
43
43
public ProgressListener (AsyncHttpClientConfig config , boolean notifyHeaders , AsyncHandler <?> asyncHandler , NettyResponseFuture <?> future ) {
44
44
this .config = config ;
@@ -47,54 +47,60 @@ public ProgressListener(AsyncHttpClientConfig config, boolean notifyHeaders, Asy
47
47
this .future = future ;
48
48
}
49
49
50
- @ Override
51
- public void operationComplete (ChannelProgressiveFuture cf ) {
52
- // The write operation failed. If the channel was cached, it means it got asynchronously closed.
53
- // Let's retry a second time.
54
- Throwable cause = cf .cause ();
50
+ private boolean abortOnThrowable (Throwable cause , Channel channel ) {
51
+
55
52
if (cause != null && future .getState () != NettyResponseFuture .STATE .NEW ) {
56
53
57
54
if (cause instanceof IllegalStateException ) {
58
55
LOGGER .debug (cause .getMessage (), cause );
59
56
try {
60
- cf . channel () .close ();
57
+ channel .close ();
61
58
} catch (RuntimeException ex ) {
62
59
LOGGER .debug (ex .getMessage (), ex );
63
60
}
64
- return ;
65
- }
66
-
67
- if (cause instanceof ClosedChannelException || NettyResponseFutures .abortOnReadCloseException (cause ) || NettyResponseFutures .abortOnWriteCloseException (cause )) {
61
+ } else if (cause instanceof ClosedChannelException || NettyResponseFutures .abortOnReadCloseException (cause ) || NettyResponseFutures .abortOnWriteCloseException (cause )) {
68
62
69
- if (LOGGER .isDebugEnabled ()) {
70
- LOGGER .debug (cf .cause () == null ? "" : cf .cause ().getMessage (), cf .cause ());
71
- }
63
+ if (LOGGER .isDebugEnabled ())
64
+ LOGGER .debug (cause .getMessage (), cause );
72
65
73
66
try {
74
- cf . channel () .close ();
67
+ channel .close ();
75
68
} catch (RuntimeException ex ) {
76
69
LOGGER .debug (ex .getMessage (), ex );
77
70
}
78
- return ;
79
71
} else {
80
72
future .abort (cause );
81
73
}
82
- return ;
74
+
75
+ return true ;
83
76
}
84
- future .touch ();
85
77
86
- /**
87
- * We need to make sure we aren't in the middle of an authorization process before publishing events as we will re-publish again the same event after the authorization,
88
- * causing unpredictable behavior.
89
- */
90
- Realm realm = future .getRequest ().getRealm () != null ? future .getRequest ().getRealm () : config .getRealm ();
91
- boolean startPublishing = future .isInAuth () || realm == null || realm .getUsePreemptiveAuth ();
78
+ return false ;
79
+ }
92
80
93
- if (startPublishing && asyncHandler instanceof ProgressAsyncHandler ) {
94
- if (notifyHeaders ) {
95
- ProgressAsyncHandler .class .cast (asyncHandler ).onHeaderWriteCompleted ();
96
- } else {
97
- ProgressAsyncHandler .class .cast (asyncHandler ).onContentWriteCompleted ();
81
+ @ Override
82
+ public void operationComplete (ChannelProgressiveFuture cf ) {
83
+ // The write operation failed. If the channel was cached, it means it got asynchronously closed.
84
+ // Let's retry a second time.
85
+
86
+ if (!abortOnThrowable (cf .cause (), cf .channel ())) {
87
+
88
+ future .touch ();
89
+
90
+ /**
91
+ * We need to make sure we aren't in the middle of an authorization process before publishing events as we will re-publish again the same event after the authorization,
92
+ * causing unpredictable behavior.
93
+ */
94
+ Realm realm = future .getRequest ().getRealm () != null ? future .getRequest ().getRealm () : config .getRealm ();
95
+ boolean startPublishing = future .isInAuth () || realm == null || realm .getUsePreemptiveAuth ();
96
+
97
+ if (startPublishing && asyncHandler instanceof ProgressAsyncHandler ) {
98
+ ProgressAsyncHandler <?> progressAsyncHandler = (ProgressAsyncHandler <?>) asyncHandler ;
99
+ if (notifyHeaders ) {
100
+ progressAsyncHandler .onHeaderWriteCompleted ();
101
+ } else {
102
+ progressAsyncHandler .onContentWriteCompleted ();
103
+ }
98
104
}
99
105
}
100
106
}
@@ -103,8 +109,9 @@ public void operationComplete(ChannelProgressiveFuture cf) {
103
109
public void operationProgressed (ChannelProgressiveFuture f , long progress , long total ) {
104
110
future .touch ();
105
111
if (!notifyHeaders && asyncHandler instanceof ProgressAsyncHandler ) {
106
- long lastProgressValue = lastProgress .getAndSet (progress );
107
- ProgressAsyncHandler .class .cast (asyncHandler ).onContentWriteProgress (progress - lastProgressValue , progress , total );
112
+ long lastLastProgress = lastProgress ;
113
+ lastProgress = progress ;
114
+ ProgressAsyncHandler .class .cast (asyncHandler ).onContentWriteProgress (progress - lastLastProgress , progress , total );
108
115
}
109
116
}
110
117
}
0 commit comments