1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.cometd;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Queue;
20
21 import org.cometd.Bayeux;
22 import org.cometd.Client;
23 import org.cometd.ClientListener;
24 import org.cometd.DeliverListener;
25 import org.cometd.Extension;
26 import org.cometd.Message;
27 import org.cometd.MessageListener;
28 import org.cometd.QueueListener;
29 import org.cometd.RemoveListener;
30 import org.mortbay.util.ArrayQueue;
31 import org.mortbay.util.LazyList;
32 import org.mortbay.util.ajax.JSON;
33
34
35
36
37
38
39
40
41 public class ClientImpl implements Client
42 {
43 private String _id;
44 private String _type;
45 private int _responsesPending;
46 private ChannelImpl[] _subscriptions=new ChannelImpl[0];
47 private RemoveListener[] _rListeners;
48 private MessageListener[] _syncMListeners;
49 private MessageListener[] _asyncMListeners;
50 private QueueListener[] _qListeners;
51 private DeliverListener[] _dListeners;
52 protected AbstractBayeux _bayeux;
53 private String _browserId;
54 private JSON.Literal _advice;
55 private int _batch;
56 private int _maxQueue;
57 private ArrayQueue<Message> _queue=new ArrayQueue<Message>(8,16,this);
58 private long _timeout;
59 protected Extension[] _extensions;
60
61 protected boolean _deliverViaMetaConnectOnly;
62
63
64 int _adviseVersion;
65
66
67 protected ClientImpl(AbstractBayeux bayeux)
68 {
69 _bayeux=bayeux;
70 _maxQueue=bayeux.getMaxClientQueue();
71 _bayeux.addClient(this,null);
72 if (_bayeux.isLogInfo())
73 _bayeux.logInfo("newClient: "+this);
74 }
75
76
77 protected ClientImpl(AbstractBayeux bayeux, String idPrefix)
78 {
79 _bayeux=bayeux;
80 _maxQueue=0;
81
82 _bayeux.addClient(this,idPrefix);
83
84 if (_bayeux.isLogInfo())
85 _bayeux.logInfo("newClient: "+this);
86 }
87
88
89 public void addExtension(Extension ext)
90 {
91 _extensions = (Extension[])LazyList.addToArray(_extensions,ext,Extension.class);
92 }
93
94
95 Extension[] getExtensions()
96 {
97 return _extensions;
98 }
99
100
101 public void deliver(Client from, String toChannel, Object data, String id)
102 {
103 MessageImpl message=_bayeux.newMessage();
104 message.put(Bayeux.CHANNEL_FIELD,toChannel);
105 message.put(Bayeux.DATA_FIELD,data);
106 if (id!=null)
107 message.put(Bayeux.ID_FIELD,id);
108
109 Message m=_bayeux.extendSendBayeux(from,message);
110 if (m!=null)
111 doDelivery(from,m);
112 if (m instanceof MessageImpl)
113 ((MessageImpl)m).decRef();
114 }
115
116
117 public void deliverLazy(Client from, String toChannel, Object data, String id)
118 {
119 MessageImpl message=_bayeux.newMessage();
120 message.put(Bayeux.CHANNEL_FIELD,toChannel);
121 message.put(Bayeux.DATA_FIELD,data);
122 if (id!=null)
123 message.put(Bayeux.ID_FIELD,id);
124 message.setLazy(true);
125 Message m=_bayeux.extendSendBayeux(from,message);
126 if (m!=null)
127 doDelivery(from,m);
128 if (m instanceof MessageImpl)
129 ((MessageImpl)m).decRef();
130 }
131
132
133 protected void doDelivery(Client from, final Message msg)
134 {
135 final Message message=_bayeux.extendSendClient(from,this,msg);
136 if (message==null)
137 return;
138
139 MessageListener[] alisteners=null;
140 synchronized(this)
141 {
142 if (_maxQueue<0)
143 {
144 ((MessageImpl)message).incRef();
145 _queue.addUnsafe(message);
146 }
147 else
148 {
149 boolean add;
150 if (_queue.size()>=_maxQueue)
151 {
152 if (_qListeners!=null && _qListeners.length>0)
153 {
154 add=true;
155 for (QueueListener l : _qListeners)
156 add &= l.queueMaxed(from,this,message);
157 }
158 else
159 add=false;
160 }
161 else
162 add=true;
163
164 if (add)
165 {
166 ((MessageImpl)message).incRef();
167 _queue.addUnsafe(message);
168 }
169 }
170
171
172 if (_syncMListeners!=null)
173 for (MessageListener l:_syncMListeners)
174 l.deliver(from,this,message);
175 alisteners=_asyncMListeners;
176
177 if (_batch==0 && _responsesPending<1 && _queue.size()>0 && !((MessageImpl)message).isLazy())
178 resume();
179 }
180
181
182 if (alisteners!=null)
183 for (MessageListener l:alisteners)
184 l.deliver(from,this,message);
185 }
186
187
188 public void doDeliverListeners()
189 {
190 synchronized (this)
191 {
192 if (_dListeners!=null)
193 for (DeliverListener l:_dListeners)
194 l.deliver(this,_queue);
195 }
196 }
197
198
199 public void setMetaConnectDeliveryOnly(boolean deliverViaMetaConnectOnly)
200 {
201 _deliverViaMetaConnectOnly = deliverViaMetaConnectOnly;
202 }
203
204
205 public boolean isMetaConnectDeliveryOnly()
206 {
207 return _deliverViaMetaConnectOnly;
208 }
209
210
211 public void startBatch()
212 {
213 synchronized(this)
214 {
215 _batch++;
216 }
217 }
218
219
220 public void endBatch()
221 {
222 synchronized(this)
223 {
224 if (--_batch==0 && _responsesPending<1)
225 {
226 switch(_queue.size())
227 {
228 case 0:
229 break;
230 case 1:
231 if (!((MessageImpl)_queue.get(0)).isLazy())
232 resume();
233 break;
234 default:
235
236 resume();
237 }
238 }
239 }
240 }
241
242
243 public String getConnectionType()
244 {
245 return _type;
246 }
247
248
249
250
251
252 public String getId()
253 {
254 return _id;
255 }
256
257
258 public boolean hasMessages()
259 {
260 return _queue.size()>0;
261 }
262
263
264 public boolean isLocal()
265 {
266 return true;
267 }
268
269
270
271
272
273 public void disconnect()
274 {
275 synchronized(this)
276 {
277 if (_bayeux.hasClient(_id))
278 remove(false);
279 }
280 }
281
282
283
284
285
286 public void remove(boolean timeout)
287 {
288 Client client=_bayeux.removeClient(_id);
289
290 if (client!=null && _bayeux.isLogInfo())
291 _bayeux.logInfo("Remove client "+client+" timeout="+timeout);
292
293 final String browser_id;
294 final RemoveListener[] listeners;
295 synchronized(this)
296 {
297 browser_id=_browserId;
298 _browserId=null;
299 listeners=_rListeners;
300 }
301
302 if (browser_id!=null)
303 _bayeux.clientOffBrowser(browser_id,_id);
304 if (listeners!=null)
305 for (RemoveListener l:listeners)
306 l.removed(_id, timeout);
307
308 resume();
309 }
310
311
312 public int responded()
313 {
314 synchronized(this)
315 {
316 return _responsesPending--;
317 }
318 }
319
320
321 public int responsePending()
322 {
323 synchronized(this)
324 {
325 return ++_responsesPending;
326 }
327 }
328
329
330
331
332 public void resume()
333 {
334 }
335
336
337
338
339
340 public int getMessages()
341 {
342 return _queue.size();
343 }
344
345
346 public List<Message> takeMessages()
347 {
348 synchronized(this)
349 {
350 ArrayList<Message> list = new ArrayList<Message>(_queue);
351 _queue.clear();
352 return list;
353 }
354 }
355
356
357
358 public void returnMessages(List<Message> messages)
359 {
360 synchronized(this)
361 {
362 _queue.addAll(0,messages);
363 }
364 }
365
366
367 @Override
368 public String toString()
369 {
370 return _id;
371 }
372
373
374 protected void addSubscription(ChannelImpl channel)
375 {
376 synchronized (this)
377 {
378 _subscriptions=(ChannelImpl[])LazyList.addToArray(_subscriptions,channel,null);
379 }
380 }
381
382
383 protected void removeSubscription(ChannelImpl channel)
384 {
385 synchronized (this)
386 {
387 _subscriptions=(ChannelImpl[])LazyList.removeFromArray(_subscriptions,channel);
388 }
389 }
390
391
392 protected void setConnectionType(String type)
393 {
394 synchronized (this)
395 {
396 _type=type;
397 }
398 }
399
400
401 protected void setId(String _id)
402 {
403 synchronized (this)
404 {
405 this._id=_id;
406 }
407 }
408
409
410 protected void unsubscribeAll()
411 {
412 ChannelImpl[] subscriptions;
413 synchronized(this)
414 {
415 _queue.clear();
416 subscriptions=_subscriptions;
417 _subscriptions=new ChannelImpl[0];
418 }
419 for (ChannelImpl channel : subscriptions)
420 channel.unsubscribe(this);
421
422 }
423
424
425 public void setBrowserId(String id)
426 {
427 if (_browserId!=null && !_browserId.equals(id))
428 _bayeux.clientOffBrowser(_browserId,_id);
429 _browserId=id;
430 if (_browserId!=null)
431 _bayeux.clientOnBrowser(_browserId,_id);
432 }
433
434
435 public String getBrowserId()
436 {
437 return _browserId;
438 }
439
440
441 @Override
442 public boolean equals(Object o)
443 {
444 if (!(o instanceof Client))
445 return false;
446 return getId().equals(((Client)o).getId());
447 }
448
449
450
451
452
453
454 public JSON.Literal getAdvice()
455 {
456 return _advice;
457 }
458
459
460
461
462
463 public void setAdvice(JSON.Literal advice)
464 {
465 _advice=advice;
466 }
467
468
469
470 public void addListener(ClientListener listener)
471 {
472 synchronized(this)
473 {
474 if (listener instanceof MessageListener)
475 {
476 if (listener instanceof MessageListener.Synchronous)
477 _syncMListeners=(MessageListener[])LazyList.addToArray(_syncMListeners,listener,MessageListener.class);
478 else
479 _asyncMListeners=(MessageListener[])LazyList.addToArray(_asyncMListeners,listener,MessageListener.class);
480 }
481
482 if (listener instanceof RemoveListener)
483 _rListeners=(RemoveListener[])LazyList.addToArray(_rListeners,listener,RemoveListener.class);
484
485 if (listener instanceof QueueListener)
486 _qListeners=(QueueListener[])LazyList.addToArray(_qListeners,listener,QueueListener.class);
487
488 if (listener instanceof DeliverListener)
489 _dListeners=(DeliverListener[])LazyList.addToArray(_dListeners,listener,DeliverListener.class);
490 }
491 }
492
493
494 public void removeListener(ClientListener listener)
495 {
496 synchronized(this)
497 {
498 if (listener instanceof MessageListener)
499 {
500 _syncMListeners=(MessageListener[])LazyList.removeFromArray(_syncMListeners,listener);
501 _asyncMListeners=(MessageListener[])LazyList.removeFromArray(_asyncMListeners,listener);
502 }
503
504 if (listener instanceof RemoveListener)
505 _rListeners=(RemoveListener[])LazyList.removeFromArray(_rListeners,listener);
506
507 if (listener instanceof QueueListener)
508 _qListeners=(QueueListener[])LazyList.removeFromArray(_qListeners,listener);
509 }
510 }
511
512
513 public long getTimeout()
514 {
515 return _timeout;
516 }
517
518
519 public void setTimeout(long timeoutMS)
520 {
521 _timeout=timeoutMS;
522 }
523
524
525 public void setMaxQueue(int maxQueue)
526 {
527 _maxQueue=maxQueue;
528 }
529
530
531 public int getMaxQueue()
532 {
533 return _maxQueue;
534 }
535
536
537 public Queue<Message> getQueue()
538 {
539 return _queue;
540 }
541 }