1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.cometd;
16
17 import java.util.Arrays;
18 import java.util.Collection;
19 import java.util.List;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ConcurrentMap;
22
23 import org.cometd.Bayeux;
24 import org.cometd.Channel;
25 import org.cometd.ChannelBayeuxListener;
26 import org.cometd.ChannelListener;
27 import org.cometd.Client;
28 import org.cometd.DataFilter;
29 import org.cometd.Message;
30 import org.cometd.SubscriptionListener;
31 import org.mortbay.log.Log;
32 import org.mortbay.util.LazyList;
33
34
35
36
37
38
39
40
41 public class ChannelImpl implements Channel
42 {
43 protected AbstractBayeux _bayeux;
44 private volatile ClientImpl[] _subscribers=new ClientImpl[0];
45 private volatile DataFilter[] _dataFilters=new DataFilter[0];
46 private volatile SubscriptionListener[] _subscriptionListeners=new SubscriptionListener[0];
47 private ChannelId _id;
48 private ConcurrentMap<String,ChannelImpl> _children = new ConcurrentHashMap<String, ChannelImpl>();
49 private ChannelImpl _wild;
50 private ChannelImpl _wildWild;
51 private boolean _persistent;
52 private int _split;
53 private boolean _lazy;
54
55
56 ChannelImpl(String id,AbstractBayeux bayeux)
57 {
58 _id=new ChannelId(id);
59 _bayeux=bayeux;
60 }
61
62
63
64
65
66
67
68
69 public boolean isLazy()
70 {
71 return _lazy;
72 }
73
74
75
76
77
78
79
80
81 public void setLazy(boolean lazy)
82 {
83 _lazy = lazy;
84 }
85
86
87 public void addChild(ChannelImpl channel)
88 {
89 ChannelId child=channel.getChannelId();
90 if (!_id.isParentOf(child))
91 {
92 throw new IllegalArgumentException(_id+" not parent of "+child);
93 }
94
95 String next = child.getSegment(_id.depth());
96
97 if ((child.depth()-_id.depth())==1)
98 {
99
100 synchronized(this)
101 {
102
103 ChannelImpl old = _children.putIfAbsent(next,channel);
104 if (old!=null)
105 throw new IllegalArgumentException("Already Exists");
106
107 if (ChannelId.WILD.equals(next))
108 _wild=channel;
109 else if (ChannelId.WILDWILD.equals(next))
110 _wildWild=channel;
111 _bayeux.addChannel(channel);
112 }
113 }
114 else
115 {
116
117 ChannelImpl branch=(ChannelImpl)_bayeux.getChannel((_id.depth()==0?"/":(_id.toString()+"/"))+next,true);
118 branch.addChild(channel);
119 }
120
121 }
122
123
124
125
126
127 public void addDataFilter(DataFilter filter)
128 {
129 synchronized(this)
130 {
131 _dataFilters=(DataFilter[])LazyList.addToArray(_dataFilters,filter,null);
132 }
133 }
134
135
136
137
138
139
140 public ChannelId getChannelId()
141 {
142 return _id;
143 }
144
145
146 public ChannelImpl getChild(ChannelId id)
147 {
148 String next=id.getSegment(_id.depth());
149 if (next==null)
150 return null;
151
152 ChannelImpl channel = _children.get(next);
153
154 if (channel==null || channel.getChannelId().depth()==id.depth())
155 {
156 return channel;
157 }
158 return channel.getChild(id);
159 }
160
161
162 public void getChannels(List<Channel> list)
163 {
164 synchronized(this)
165 {
166 list.add(this);
167 for (ChannelImpl channel: _children.values())
168 channel.getChannels(list);
169 }
170 }
171
172
173 public int getChannelCount()
174 {
175 return _children.size();
176 }
177
178
179
180
181
182 public String getId()
183 {
184 return _id.toString();
185 }
186
187
188
189 public boolean isPersistent()
190 {
191 return _persistent;
192 }
193
194
195 public void deliver(Client from, Iterable<Client> to, Object data, String id)
196 {
197 MessageImpl message=_bayeux.newMessage();
198 message.put(Bayeux.CHANNEL_FIELD,getId());
199 message.put(Bayeux.DATA_FIELD,data);
200 if (id!=null)
201 message.put(Bayeux.ID_FIELD,id);
202
203 Message m=_bayeux.extendSendBayeux(from,message);
204
205 if (m!=null)
206 {
207 for (Client t : to)
208 ((ClientImpl)t).doDelivery(from,m);
209 }
210 if (m instanceof MessageImpl)
211 ((MessageImpl)m).decRef();
212 }
213
214
215 public void publish(Client fromClient, Object data, String msgId)
216 {
217 _bayeux.doPublish(getChannelId(),fromClient,data,msgId,false);
218 }
219
220
221 public void publishLazy(Client fromClient, Object data, String msgId)
222 {
223 _bayeux.doPublish(getChannelId(),fromClient,data,msgId,true);
224 }
225
226
227 public boolean remove()
228 {
229 return _bayeux.removeChannel(this);
230 }
231
232
233 public boolean doRemove(ChannelImpl channel, List<ChannelBayeuxListener> listeners)
234 {
235 ChannelId channelId = channel.getChannelId();
236 int diff = channel._id.depth()-_id.depth();
237
238 if (diff>=1)
239 {
240 String key = channelId.getSegment(_id.depth());
241 ChannelImpl child = _children.get(key);
242
243 if (child!=null)
244 {
245
246 if (diff==1)
247 {
248 if (!child.isPersistent())
249 {
250
251 synchronized(this)
252 {
253 if (child.getChannelCount()>0)
254 {
255
256 for (ChannelImpl c : child._children.values())
257 child.doRemove(c,listeners);
258 }
259
260
261 _children.remove(key);
262 }
263 for (ChannelBayeuxListener l : listeners)
264 l.channelRemoved(channel);
265 return true;
266 }
267 return false;
268 }
269
270 boolean removed = child.doRemove(channel,listeners);
271 if (removed && !child.isPersistent() && child.getChannelCount()==0 && child.getSubscriberCount()==0)
272 {
273
274 synchronized(this)
275 {
276 _children.remove(key);
277 }
278 for (ChannelBayeuxListener l : listeners)
279 l.channelRemoved(channel);
280 }
281
282 return removed;
283 }
284
285 }
286 return false;
287 }
288
289
290
291
292
293
294 public DataFilter removeDataFilter(DataFilter filter)
295 {
296 synchronized(this)
297 {
298 _dataFilters=(DataFilter[])LazyList.removeFromArray(_dataFilters,filter);
299 return filter;
300 }
301 }
302
303
304 public void setPersistent(boolean persistent)
305 {
306 _persistent=persistent;
307 }
308
309
310
311
312
313 public void subscribe(Client client)
314 {
315 if (!(client instanceof ClientImpl))
316 throw new IllegalArgumentException("Client instance not obtained from Bayeux.newClient()");
317
318 synchronized (this)
319 {
320 for (ClientImpl c : _subscribers)
321 {
322 if (client.equals(c))
323 return;
324 }
325 _subscribers=(ClientImpl[])LazyList.addToArray(_subscribers,client,null);
326
327 for (SubscriptionListener l : _subscriptionListeners)
328 l.subscribed(client, this);
329 }
330
331 ((ClientImpl)client).addSubscription(this);
332 }
333
334
335 @Override
336 public String toString()
337 {
338 return _id.toString();
339 }
340
341
342
343
344
345 public void unsubscribe(Client client)
346 {
347 if (!(client instanceof ClientImpl))
348 throw new IllegalArgumentException("Client instance not obtained from Bayeux.newClient()");
349 ((ClientImpl)client).removeSubscription(this);
350 synchronized(this)
351 {
352 _subscribers=(ClientImpl[])LazyList.removeFromArray(_subscribers,client);
353
354 for (SubscriptionListener l : _subscriptionListeners)
355 l.unsubscribed(client,this);
356
357 if (!_persistent && _subscribers.length==0 && _children.size()==0)
358 remove();
359 }
360 }
361
362
363 protected void doDelivery(ChannelId to, Client from, Message msg)
364 {
365 int tail = to.depth()-_id.depth();
366
367 Object data = msg.getData();
368
369 if (data!=null)
370 {
371 Object old = data;
372
373 try
374 {
375 switch(tail)
376 {
377 case 0:
378 {
379 final DataFilter[] filters=_dataFilters;
380 for (DataFilter filter: filters)
381 {
382 data=filter.filter(from,this,data);
383 if (data==null)
384 return;
385 }
386 }
387 break;
388
389 case 1:
390 if (_wild!=null)
391 {
392 final DataFilter[] filters=_wild._dataFilters;
393 for (DataFilter filter: filters)
394 {
395 data=filter.filter(from,this,data);
396 if (data==null)
397 return;
398 }
399 }
400
401 default:
402 if (_wildWild!=null)
403 {
404 final DataFilter[] filters=_wildWild._dataFilters;
405 for (DataFilter filter: filters)
406 {
407 data=filter.filter(from,this,data);
408 if (data==null)
409 return;
410 }
411 }
412 }
413 }
414 catch (IllegalStateException e)
415 {
416 Log.debug(e);
417 return;
418 }
419
420
421
422 if (data!=old)
423 msg.put(AbstractBayeux.DATA_FIELD,data);
424 }
425
426 switch(tail)
427 {
428 case 0:
429 {
430 if (_lazy && msg instanceof MessageImpl)
431 ((MessageImpl)msg).setLazy(true);
432
433 final ClientImpl[] subscribers=_subscribers;
434 if (subscribers.length>0)
435 {
436
437 int split=_split++%_subscribers.length;
438 for (int i=split;i<subscribers.length;i++)
439 subscribers[i].doDelivery(from,msg);
440 for (int i=0;i<split;i++)
441 subscribers[i].doDelivery(from,msg);
442 }
443 break;
444 }
445
446 case 1:
447 if (_wild!=null)
448 {
449 if (_wild._lazy && msg instanceof MessageImpl)
450 ((MessageImpl)msg).setLazy(true);
451 final ClientImpl[] subscribers=_wild._subscribers;
452 for (ClientImpl client: subscribers)
453 client.doDelivery(from,msg);
454 }
455
456 default:
457 {
458 if (_wildWild!=null)
459 {
460 if (_wildWild._lazy && msg instanceof MessageImpl)
461 ((MessageImpl)msg).setLazy(true);
462 final ClientImpl[] subscribers=_wildWild._subscribers;
463 for (ClientImpl client: subscribers)
464 client.doDelivery(from,msg);
465 }
466 String next = to.getSegment(_id.depth());
467 ChannelImpl channel = _children.get(next);
468 if (channel!=null)
469 channel.doDelivery(to,from,msg);
470 }
471 }
472 }
473
474
475 public Collection<Client> getSubscribers()
476 {
477 synchronized(this)
478 {
479 return Arrays.asList((Client[])_subscribers);
480 }
481 }
482
483
484 public int getSubscriberCount()
485 {
486 synchronized(this)
487 {
488 return _subscribers.length;
489 }
490 }
491
492
493
494
495
496
497 public Collection<DataFilter> getDataFilters()
498 {
499 synchronized(this)
500 {
501 return Arrays.asList(_dataFilters);
502 }
503 }
504
505
506 public void addListener(ChannelListener listener)
507 {
508 synchronized(this)
509 {
510 if (listener instanceof SubscriptionListener)
511 _subscriptionListeners=(SubscriptionListener[])LazyList.addToArray(_subscriptionListeners,listener,null);
512 }
513 }
514
515 }