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.Queue;
21 import java.util.concurrent.ConcurrentHashMap;
22 import java.util.concurrent.ConcurrentMap;
23
24 import org.cometd.Channel;
25 import org.cometd.ChannelListener;
26 import org.cometd.Client;
27 import org.cometd.DataFilter;
28 import org.cometd.Message;
29 import org.cometd.SubscriptionListener;
30 import org.mortbay.log.Log;
31 import org.mortbay.util.ArrayQueue;
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 ChannelImpl old = _children.putIfAbsent(next,channel);
101 if (old!=null)
102 throw new IllegalArgumentException("Already Exists");
103
104 if (ChannelId.WILD.equals(next))
105 _wild=channel;
106 else if (ChannelId.WILDWILD.equals(next))
107 _wildWild=channel;
108 _bayeux.addChannel(channel);
109 }
110 else
111 {
112 ChannelImpl branch=_children.get(next);
113 branch=(ChannelImpl)_bayeux.getChannel((_id.depth()==0?"/":(_id.toString()+"/"))+next,true);
114 branch.addChild(channel);
115 }
116 }
117
118
119
120
121
122 public void addDataFilter(DataFilter filter)
123 {
124 synchronized(this)
125 {
126 _dataFilters=(DataFilter[])LazyList.addToArray(_dataFilters,filter,null);
127 }
128 }
129
130
131
132
133
134
135 public ChannelId getChannelId()
136 {
137 return _id;
138 }
139
140
141 public ChannelImpl getChild(ChannelId id)
142 {
143 String next=id.getSegment(_id.depth());
144 if (next==null)
145 return null;
146
147 ChannelImpl channel = _children.get(next);
148
149 if (channel==null || channel.getChannelId().depth()==id.depth())
150 {
151 return channel;
152 }
153 return channel.getChild(id);
154 }
155
156
157 public void getChannels(List<Channel> list)
158 {
159 list.add(this);
160 for (ChannelImpl channel: _children.values())
161 channel.getChannels(list);
162 }
163
164
165 public int getChannelCount()
166 {
167 int count = 1;
168
169 for(ChannelImpl channel: _children.values())
170 count += channel.getChannelCount();
171
172 return count;
173 }
174
175
176
177
178
179 public String getId()
180 {
181 return _id.toString();
182 }
183
184
185
186 public boolean isPersistent()
187 {
188 return _persistent;
189 }
190
191
192 public void publish(Client fromClient, Object data, String msgId)
193 {
194 _bayeux.doPublish(getChannelId(),fromClient,data,msgId,false);
195 }
196
197
198 public void publishLazy(Client fromClient, Object data, String msgId)
199 {
200 _bayeux.doPublish(getChannelId(),fromClient,data,msgId,true);
201 }
202
203
204 public boolean remove()
205 {
206 return _bayeux.removeChannel(this);
207 }
208
209
210 public boolean doRemove(ChannelImpl channel)
211 {
212 ChannelId channelId = channel.getChannelId();
213 String key = channelId.getSegment(channelId.depth()-1);
214 if (_children.containsKey(key))
215 {
216 ChannelImpl child = _children.get(key);
217
218 synchronized (this)
219 {
220 synchronized (child)
221 {
222 if (!child.isPersistent() && child.getSubscriberCount()==0 && child.getChannelCount()==1)
223 {
224 _children.remove(key);
225 return true;
226 }
227 else
228 return false;
229 }
230 }
231 }
232 else
233 {
234 for (ChannelImpl child : _children.values())
235 {
236 if (child.doRemove(channel))
237 return true;
238 }
239 }
240 return false;
241 }
242
243
244
245
246
247
248 public DataFilter removeDataFilter(DataFilter filter)
249 {
250 synchronized(this)
251 {
252 _dataFilters=(DataFilter[])LazyList.removeFromArray(_dataFilters,filter);
253 return filter;
254 }
255 }
256
257
258 public void setPersistent(boolean persistent)
259 {
260 _persistent=persistent;
261 }
262
263
264
265
266
267 public void subscribe(Client client)
268 {
269 if (!(client instanceof ClientImpl))
270 throw new IllegalArgumentException("Client instance not obtained from Bayeux.newClient()");
271
272 synchronized (this)
273 {
274 for (ClientImpl c : _subscribers)
275 {
276 if (client.equals(c))
277 return;
278 }
279 _subscribers=(ClientImpl[])LazyList.addToArray(_subscribers,client,null);
280
281 for (SubscriptionListener l : _subscriptionListeners)
282 l.subscribed(client, this);
283 }
284
285 ((ClientImpl)client).addSubscription(this);
286 }
287
288
289 @Override
290 public String toString()
291 {
292 return _id.toString();
293 }
294
295
296
297
298
299 public void unsubscribe(Client client)
300 {
301 if (!(client instanceof ClientImpl))
302 throw new IllegalArgumentException("Client instance not obtained from Bayeux.newClient()");
303 ((ClientImpl)client).removeSubscription(this);
304 synchronized(this)
305 {
306 _subscribers=(ClientImpl[])LazyList.removeFromArray(_subscribers,client);
307
308 for (SubscriptionListener l : _subscriptionListeners)
309 l.unsubscribed(client,this);
310
311 if (!_persistent && _subscribers.length==0 && _children.size()==0)
312 remove();
313 }
314 }
315
316
317 protected void doDelivery(ChannelId to, Client from, Message msg)
318 {
319 int tail = to.depth()-_id.depth();
320
321 Object data = msg.getData();
322 Object old = data;
323
324 try
325 {
326 switch(tail)
327 {
328 case 0:
329 {
330 final DataFilter[] filters=_dataFilters;
331 for (DataFilter filter: filters)
332 {
333 data=filter.filter(from,this,data);
334 if (data==null)
335 return;
336 }
337 }
338 break;
339
340 case 1:
341 if (_wild!=null)
342 {
343 final DataFilter[] filters=_wild._dataFilters;
344 for (DataFilter filter: filters)
345 {
346 data=filter.filter(from,this,data);
347 if (data==null)
348 return;
349 }
350 }
351
352 default:
353 if (_wildWild!=null)
354 {
355 final DataFilter[] filters=_wildWild._dataFilters;
356 for (DataFilter filter: filters)
357 {
358 data=filter.filter(from,this,data);
359 if (data==null)
360 return;
361 }
362 }
363 }
364 }
365 catch (IllegalStateException e)
366 {
367 Log.debug(e);
368 return;
369 }
370
371
372
373 if (data!=old)
374 msg.put(AbstractBayeux.DATA_FIELD,data);
375
376
377 switch(tail)
378 {
379 case 0:
380 {
381 if (_lazy && msg instanceof MessageImpl)
382 ((MessageImpl)msg).setLazy(true);
383
384 final ClientImpl[] subscribers=_subscribers;
385 if (subscribers.length>0)
386 {
387
388 int split=_split++%_subscribers.length;
389 for (int i=split;i<subscribers.length;i++)
390 subscribers[i].doDelivery(from,msg);
391 for (int i=0;i<split;i++)
392 subscribers[i].doDelivery(from,msg);
393 }
394 break;
395 }
396
397 case 1:
398 if (_wild!=null)
399 {
400 if (_wild._lazy && msg instanceof MessageImpl)
401 ((MessageImpl)msg).setLazy(true);
402 final ClientImpl[] subscribers=_wild._subscribers;
403 for (ClientImpl client: subscribers)
404 client.doDelivery(from,msg);
405 }
406
407 default:
408 {
409 if (_wildWild!=null)
410 {
411 if (_wildWild._lazy && msg instanceof MessageImpl)
412 ((MessageImpl)msg).setLazy(true);
413 final ClientImpl[] subscribers=_wildWild._subscribers;
414 for (ClientImpl client: subscribers)
415 client.doDelivery(from,msg);
416 }
417 String next = to.getSegment(_id.depth());
418 ChannelImpl channel = _children.get(next);
419 if (channel!=null)
420 channel.doDelivery(to,from,msg);
421 }
422 }
423 }
424
425
426 public Collection<Client> getSubscribers()
427 {
428 synchronized(this)
429 {
430 return Arrays.asList((Client[])_subscribers);
431 }
432 }
433
434
435 public int getSubscriberCount()
436 {
437 synchronized(this)
438 {
439 return _subscribers.length;
440 }
441 }
442
443
444
445
446
447
448 public Collection<DataFilter> getDataFilters()
449 {
450 synchronized(this)
451 {
452 return Arrays.asList(_dataFilters);
453 }
454 }
455
456
457 public void addListener(ChannelListener listener)
458 {
459 synchronized(this)
460 {
461 if (listener instanceof SubscriptionListener)
462 _subscriptionListeners=(SubscriptionListener[])LazyList.addToArray(_subscriptionListeners,listener,null);
463 }
464 }
465
466 }