1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.channel;
17
18 import org.jboss.netty.util.internal.ConcurrentHashMap;
19
20 import java.net.SocketAddress;
21 import java.util.Random;
22 import java.util.concurrent.ConcurrentMap;
23
24
25
26
27 public abstract class AbstractChannel implements Channel {
28
29 static final ConcurrentMap<Integer, Channel> allChannels = new ConcurrentHashMap<Integer, Channel>();
30
31 private static final Random random = new Random();
32
33 private static Integer allocateId(Channel channel) {
34 Integer id = random.nextInt();
35 for (;;) {
36
37
38 if (allChannels.putIfAbsent(id, channel) == null) {
39
40 return id;
41 } else {
42
43 id = id.intValue() + 1;
44 }
45 }
46 }
47
48 private final Integer id;
49 private final Channel parent;
50 private final ChannelFactory factory;
51 private final ChannelPipeline pipeline;
52 private final ChannelFuture succeededFuture = new SucceededChannelFuture(this);
53 private final ChannelCloseFuture closeFuture = new ChannelCloseFuture();
54 private volatile int interestOps = OP_READ;
55
56
57 private boolean strValConnected;
58 private String strVal;
59 private volatile Object attachment;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 protected AbstractChannel(
75 Channel parent, ChannelFactory factory,
76 ChannelPipeline pipeline, ChannelSink sink) {
77
78 this.parent = parent;
79 this.factory = factory;
80 this.pipeline = pipeline;
81
82 id = allocateId(this);
83
84 pipeline.attach(this, sink);
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 protected AbstractChannel(
102 Integer id,
103 Channel parent, ChannelFactory factory,
104 ChannelPipeline pipeline, ChannelSink sink) {
105
106 this.id = id;
107 this.parent = parent;
108 this.factory = factory;
109 this.pipeline = pipeline;
110 pipeline.attach(this, sink);
111 }
112
113 public final Integer getId() {
114 return id;
115 }
116
117 public Channel getParent() {
118 return parent;
119 }
120
121 public ChannelFactory getFactory() {
122 return factory;
123 }
124
125 public ChannelPipeline getPipeline() {
126 return pipeline;
127 }
128
129
130
131
132 protected ChannelFuture getSucceededFuture() {
133 return succeededFuture;
134 }
135
136
137
138
139
140 protected ChannelFuture getUnsupportedOperationFuture() {
141 return new FailedChannelFuture(this, new UnsupportedOperationException());
142 }
143
144
145
146
147 @Override
148 public final int hashCode() {
149 return id;
150 }
151
152
153
154
155
156 @Override
157 public final boolean equals(Object o) {
158 return this == o;
159 }
160
161
162
163
164 public final int compareTo(Channel o) {
165 return getId().compareTo(o.getId());
166 }
167
168 public boolean isOpen() {
169 return !closeFuture.isDone();
170 }
171
172
173
174
175
176
177
178
179
180 protected boolean setClosed() {
181
182
183 allChannels.remove(id);
184
185 return closeFuture.setClosed();
186 }
187
188 public ChannelFuture bind(SocketAddress localAddress) {
189 return Channels.bind(this, localAddress);
190 }
191
192 public ChannelFuture unbind() {
193 return Channels.unbind(this);
194 }
195
196 public ChannelFuture close() {
197 ChannelFuture returnedCloseFuture = Channels.close(this);
198 assert closeFuture == returnedCloseFuture;
199 return closeFuture;
200 }
201
202 public ChannelFuture getCloseFuture() {
203 return closeFuture;
204 }
205
206 public ChannelFuture connect(SocketAddress remoteAddress) {
207 return Channels.connect(this, remoteAddress);
208 }
209
210 public ChannelFuture disconnect() {
211 return Channels.disconnect(this);
212 }
213
214 public int getInterestOps() {
215 return interestOps;
216 }
217
218 public ChannelFuture setInterestOps(int interestOps) {
219 return Channels.setInterestOps(this, interestOps);
220 }
221
222
223
224
225
226
227 protected void setInterestOpsNow(int interestOps) {
228 this.interestOps = interestOps;
229 }
230
231 public boolean isReadable() {
232 return (getInterestOps() & OP_READ) != 0;
233 }
234
235 public boolean isWritable() {
236 return (getInterestOps() & OP_WRITE) == 0;
237 }
238
239 public ChannelFuture setReadable(boolean readable) {
240 if (readable) {
241 return setInterestOps(getInterestOps() | OP_READ);
242 } else {
243 return setInterestOps(getInterestOps() & ~OP_READ);
244 }
245 }
246
247 public ChannelFuture write(Object message) {
248 return Channels.write(this, message);
249 }
250
251 public ChannelFuture write(Object message, SocketAddress remoteAddress) {
252 return Channels.write(this, message, remoteAddress);
253 }
254
255 public Object getAttachment() {
256 return attachment;
257 }
258
259 public void setAttachment(Object attachment) {
260 this.attachment = attachment;
261 }
262
263
264
265
266
267
268 @Override
269 public String toString() {
270 boolean connected = isConnected();
271 if (strValConnected == connected && strVal != null) {
272 return strVal;
273 }
274
275 StringBuilder buf = new StringBuilder(128);
276 buf.append("[id: 0x");
277 buf.append(getIdString());
278
279 SocketAddress localAddress = getLocalAddress();
280 SocketAddress remoteAddress = getRemoteAddress();
281 if (remoteAddress != null) {
282 buf.append(", ");
283 if (getParent() == null) {
284 buf.append(localAddress);
285 buf.append(connected? " => " : " :> ");
286 buf.append(remoteAddress);
287 } else {
288 buf.append(remoteAddress);
289 buf.append(connected? " => " : " :> ");
290 buf.append(localAddress);
291 }
292 } else if (localAddress != null) {
293 buf.append(", ");
294 buf.append(localAddress);
295 }
296
297 buf.append(']');
298
299 String strVal = buf.toString();
300 this.strVal = strVal;
301 strValConnected = connected;
302 return strVal;
303 }
304
305 private String getIdString() {
306 String answer = Integer.toHexString(id.intValue());
307 switch (answer.length()) {
308 case 0:
309 answer = "00000000";
310 break;
311 case 1:
312 answer = "0000000" + answer;
313 break;
314 case 2:
315 answer = "000000" + answer;
316 break;
317 case 3:
318 answer = "00000" + answer;
319 break;
320 case 4:
321 answer = "0000" + answer;
322 break;
323 case 5:
324 answer = "000" + answer;
325 break;
326 case 6:
327 answer = "00" + answer;
328 break;
329 case 7:
330 answer = '0' + answer;
331 break;
332 }
333 return answer;
334 }
335
336 private final class ChannelCloseFuture extends DefaultChannelFuture {
337
338 public ChannelCloseFuture() {
339 super(AbstractChannel.this, false);
340 }
341
342 @Override
343 public boolean setSuccess() {
344
345 return false;
346 }
347
348 @Override
349 public boolean setFailure(Throwable cause) {
350
351 return false;
352 }
353
354 boolean setClosed() {
355 return super.setSuccess();
356 }
357 }
358 }