1 /*
2  * Copyright 2012 The Netty Project
3  *
4  * The Netty Project licenses this file to you under the Apache License,
5  * version 2.0 (the "License"); you may not use this file except in compliance
6  * with the License. You may obtain a copy of the License at:
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */

16 package io.netty.channel;
17
18 import io.netty.util.concurrent.AbstractFuture;
19 import io.netty.util.concurrent.Future;
20 import io.netty.util.concurrent.GenericFutureListener;
21 import io.netty.util.internal.ObjectUtil;
22 import io.netty.util.internal.UnstableApi;
23
24 import java.util.concurrent.TimeUnit;
25
26 @UnstableApi
27 public final class VoidChannelPromise extends AbstractFuture<Void> implements ChannelPromise {
28
29     private final Channel channel;
30     // Will be null if we should not propagate exceptions through the pipeline on failure case.
31     private final ChannelFutureListener fireExceptionListener;
32
33     /**
34      * Creates a new instance.
35      *
36      * @param channel the {@link Channel} associated with this future
37      */

38     public VoidChannelPromise(final Channel channel, boolean fireException) {
39         ObjectUtil.checkNotNull(channel, "channel");
40         this.channel = channel;
41         if (fireException) {
42             fireExceptionListener = new ChannelFutureListener() {
43                 @Override
44                 public void operationComplete(ChannelFuture future) throws Exception {
45                     Throwable cause = future.cause();
46                     if (cause != null) {
47                         fireException0(cause);
48                     }
49                 }
50             };
51         } else {
52             fireExceptionListener = null;
53         }
54     }
55
56     @Override
57     public VoidChannelPromise addListener(GenericFutureListener<? extends Future<? super Void>> listener) {
58         fail();
59         return this;
60     }
61
62     @Override
63     public VoidChannelPromise addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners) {
64         fail();
65         return this;
66     }
67
68     @Override
69     public VoidChannelPromise removeListener(GenericFutureListener<? extends Future<? super Void>> listener) {
70         // NOOP
71         return this;
72     }
73
74     @Override
75     public VoidChannelPromise removeListeners(GenericFutureListener<? extends Future<? super Void>>... listeners) {
76         // NOOP
77         return this;
78     }
79
80     @Override
81     public VoidChannelPromise await() throws InterruptedException {
82         if (Thread.interrupted()) {
83             throw new InterruptedException();
84         }
85         return this;
86     }
87
88     @Override
89     public boolean await(long timeout, TimeUnit unit) {
90         fail();
91         return false;
92     }
93
94     @Override
95     public boolean await(long timeoutMillis) {
96         fail();
97         return false;
98     }
99
100     @Override
101     public VoidChannelPromise awaitUninterruptibly() {
102         fail();
103         return this;
104     }
105
106     @Override
107     public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
108         fail();
109         return false;
110     }
111
112     @Override
113     public boolean awaitUninterruptibly(long timeoutMillis) {
114         fail();
115         return false;
116     }
117
118     @Override
119     public Channel channel() {
120         return channel;
121     }
122
123     @Override
124     public boolean isDone() {
125         return false;
126     }
127
128     @Override
129     public boolean isSuccess() {
130         return false;
131     }
132
133     @Override
134     public boolean setUncancellable() {
135         return true;
136     }
137
138     @Override
139     public boolean isCancellable() {
140         return false;
141     }
142
143     @Override
144     public boolean isCancelled() {
145         return false;
146     }
147
148     @Override
149     public Throwable cause() {
150         return null;
151     }
152
153     @Override
154     public VoidChannelPromise sync() {
155         fail();
156         return this;
157     }
158
159     @Override
160     public VoidChannelPromise syncUninterruptibly() {
161         fail();
162         return this;
163     }
164
165     @Override
166     public VoidChannelPromise setFailure(Throwable cause) {
167         fireException0(cause);
168         return this;
169     }
170
171     @Override
172     public VoidChannelPromise setSuccess() {
173         return this;
174     }
175
176     @Override
177     public boolean tryFailure(Throwable cause) {
178         fireException0(cause);
179         return false;
180     }
181
182     /**
183      * {@inheritDoc}
184      *
185      * @param mayInterruptIfRunning this value has no effect in this implementation.
186      */

187     @Override
188     public boolean cancel(boolean mayInterruptIfRunning) {
189         return false;
190     }
191
192     @Override
193     public boolean trySuccess() {
194         return false;
195     }
196
197     private static void fail() {
198         throw new IllegalStateException("void future");
199     }
200
201     @Override
202     public VoidChannelPromise setSuccess(Void result) {
203         return this;
204     }
205
206     @Override
207     public boolean trySuccess(Void result) {
208         return false;
209     }
210
211     @Override
212     public Void getNow() {
213         return null;
214     }
215
216     @Override
217     public ChannelPromise unvoid() {
218         ChannelPromise promise = new DefaultChannelPromise(channel);
219         if (fireExceptionListener != null) {
220             promise.addListener(fireExceptionListener);
221         }
222         return promise;
223     }
224
225     @Override
226     public boolean isVoid() {
227         return true;
228     }
229
230     private void fireException0(Throwable cause) {
231         // Only fire the exception if the channel is open and registered
232         // if not the pipeline is not setup and so it would hit the tail
233         // of the pipeline.
234         // See https://github.com/netty/netty/issues/1517
235         if (fireExceptionListener != null && channel.isRegistered()) {
236             channel.pipeline().fireExceptionCaught(cause);
237         }
238     }
239 }
240