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