View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.impl.nio.reactor;
29  
30  import java.io.IOException;
31  import java.net.SocketAddress;
32  import java.nio.channels.Channel;
33  import java.nio.channels.SelectionKey;
34  
35  import org.apache.http.annotation.ThreadingBehavior;
36  import org.apache.http.annotation.Contract;
37  import org.apache.http.nio.reactor.IOSession;
38  import org.apache.http.nio.reactor.SessionRequest;
39  import org.apache.http.nio.reactor.SessionRequestCallback;
40  import org.apache.http.util.Args;
41  
42  /**
43   * Default implementation of {@link SessionRequest}.
44   *
45   * @since 4.0
46   */
47  @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
48  public class SessionRequestImpl implements SessionRequest {
49  
50      private volatile boolean completed;
51      private volatile SelectionKey key;
52  
53      private final SocketAddress remoteAddress;
54      private final SocketAddress localAddress;
55      private final Object attachment;
56      private final SessionRequestCallback callback;
57  
58      private volatile int connectTimeout;
59      private volatile IOSession session = null;
60      private volatile IOException exception = null;
61  
62      public SessionRequestImpl(
63              final SocketAddress remoteAddress,
64              final SocketAddress localAddress,
65              final Object attachment,
66              final SessionRequestCallback callback) {
67          super();
68          Args.notNull(remoteAddress, "Remote address");
69          this.remoteAddress = remoteAddress;
70          this.localAddress = localAddress;
71          this.attachment = attachment;
72          this.callback = callback;
73          this.connectTimeout = 0;
74      }
75  
76      @Override
77      public SocketAddress getRemoteAddress() {
78          return this.remoteAddress;
79      }
80  
81      @Override
82      public SocketAddress getLocalAddress() {
83          return this.localAddress;
84      }
85  
86      @Override
87      public Object getAttachment() {
88          return this.attachment;
89      }
90  
91      @Override
92      public boolean isCompleted() {
93          return this.completed;
94      }
95  
96      protected void setKey(final SelectionKey key) {
97          this.key = key;
98      }
99  
100     @Override
101     public void waitFor() throws InterruptedException {
102         if (this.completed) {
103             return;
104         }
105         synchronized (this) {
106             while (!this.completed) {
107                 wait();
108             }
109         }
110     }
111 
112     @Override
113     public IOSession getSession() {
114         synchronized (this) {
115             return this.session;
116         }
117     }
118 
119     @Override
120     public IOException getException() {
121         synchronized (this) {
122             return this.exception;
123         }
124     }
125 
126     public void completed(final IOSession session) {
127         Args.notNull(session, "Session");
128         if (this.completed) {
129             return;
130         }
131         this.completed = true;
132         synchronized (this) {
133             this.session = session;
134             if (this.callback != null) {
135                 this.callback.completed(this);
136             }
137             notifyAll();
138         }
139     }
140 
141     public void failed(final IOException exception) {
142         if (exception == null) {
143             return;
144         }
145         if (this.completed) {
146             return;
147         }
148         this.completed = true;
149         final SelectionKey key = this.key;
150         if (key != null) {
151             key.cancel();
152             final Channel channel = key.channel();
153             try {
154                 channel.close();
155             } catch (final IOException ignore) {}
156         }
157         synchronized (this) {
158             this.exception = exception;
159             if (this.callback != null) {
160                 this.callback.failed(this);
161             }
162             notifyAll();
163         }
164     }
165 
166     public void timeout() {
167         if (this.completed) {
168             return;
169         }
170         this.completed = true;
171         final SelectionKey key = this.key;
172         if (key != null) {
173             key.cancel();
174             final Channel channel = key.channel();
175             if (channel.isOpen()) {
176                 try {
177                     channel.close();
178                 } catch (final IOException ignore) {}
179             }
180         }
181         synchronized (this) {
182             if (this.callback != null) {
183                 this.callback.timeout(this);
184             }
185         }
186     }
187 
188     @Override
189     public int getConnectTimeout() {
190         return this.connectTimeout;
191     }
192 
193     @Override
194     public void setConnectTimeout(final int timeout) {
195         if (this.connectTimeout != timeout) {
196             this.connectTimeout = timeout;
197             final SelectionKey key = this.key;
198             if (key != null) {
199                 key.selector().wakeup();
200             }
201         }
202     }
203 
204     @Override
205     public void cancel() {
206         if (this.completed) {
207             return;
208         }
209         this.completed = true;
210         final SelectionKey key = this.key;
211         if (key != null) {
212             key.cancel();
213             final Channel channel = key.channel();
214             if (channel.isOpen()) {
215                 try {
216                     channel.close();
217                 } catch (final IOException ignore) {}
218             }
219         }
220         synchronized (this) {
221             if (this.callback != null) {
222                 this.callback.cancelled(this);
223             }
224             notifyAll();
225         }
226     }
227 
228 }