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