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