1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.cometd;
16
17 import java.io.IOException;
18 import java.security.SecureRandom;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Random;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.CopyOnWriteArrayList;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.http.HttpServletRequest;
32
33 import org.cometd.Bayeux;
34 import org.cometd.BayeuxListener;
35 import org.cometd.Channel;
36 import org.cometd.ChannelBayeuxListener;
37 import org.cometd.Client;
38 import org.cometd.ClientBayeuxListener;
39 import org.cometd.Extension;
40 import org.cometd.Message;
41 import org.cometd.SecurityPolicy;
42 import org.mortbay.util.LazyList;
43 import org.mortbay.util.ajax.JSON;
44
45
46
47
48
49
50
51
52 public abstract class AbstractBayeux extends MessagePool implements Bayeux
53 {
54 public static final ChannelId META_ID=new ChannelId(META);
55 public static final ChannelId META_CONNECT_ID=new ChannelId(META_CONNECT);
56 public static final ChannelId META_CLIENT_ID=new ChannelId(META_CLIENT);
57 public static final ChannelId META_DISCONNECT_ID=new ChannelId(META_DISCONNECT);
58 public static final ChannelId META_HANDSHAKE_ID=new ChannelId(META_HANDSHAKE);
59 public static final ChannelId META_PING_ID=new ChannelId(META_PING);
60 public static final ChannelId META_STATUS_ID=new ChannelId(META_STATUS);
61 public static final ChannelId META_SUBSCRIBE_ID=new ChannelId(META_SUBSCRIBE);
62 public static final ChannelId META_UNSUBSCRIBE_ID=new ChannelId(META_UNSUBSCRIBE);
63
64
65 private HashMap<String,Handler> _handlers=new HashMap<String,Handler>();
66
67 private ChannelImpl _root = new ChannelImpl("/",this);
68 private ConcurrentHashMap<String,ClientImpl> _clients=new ConcurrentHashMap<String,ClientImpl>();
69 protected SecurityPolicy _securityPolicy=new DefaultPolicy();
70 protected JSON.Literal _advice;
71 protected JSON.Literal _multiFrameAdvice;
72 protected int _adviceVersion=0;
73 protected Object _handshakeAdvice=new JSON.Literal("{\"reconnect\":\"handshake\",\"interval\":500}");
74 protected int _logLevel;
75 protected long _timeout=240000;
76 protected long _interval=0;
77 protected long _maxInterval=30000;
78 protected boolean _initialized;
79 protected ConcurrentHashMap<String, List<String>> _browser2client=new ConcurrentHashMap<String, List<String>>();
80 protected int _multiFrameInterval=-1;
81
82 protected boolean _requestAvailable;
83 protected ThreadLocal<HttpServletRequest> _request = new ThreadLocal<HttpServletRequest>();
84
85 transient ServletContext _context;
86 transient Random _random;
87 transient ConcurrentHashMap<String, ChannelId> _channelIdCache;
88 protected Handler _publishHandler;
89 protected Handler _metaPublishHandler;
90 protected int _maxClientQueue=-1;
91
92 protected Extension[] _extensions;
93 protected JSON.Literal _transports=new JSON.Literal("[\""+Bayeux.TRANSPORT_LONG_POLL+ "\",\""+Bayeux.TRANSPORT_CALLBACK_POLL+"\"]");
94 protected JSON.Literal _replyExt = new JSON.Literal("{\"ack\":\"true\"}");
95 protected List<ClientBayeuxListener> _clientListeners=new CopyOnWriteArrayList<ClientBayeuxListener>();
96 protected List<ChannelBayeuxListener> _channelListeners=new CopyOnWriteArrayList<ChannelBayeuxListener>();
97
98
99
100
101
102
103
104 protected AbstractBayeux()
105 {
106 _publishHandler=new PublishHandler();
107 _metaPublishHandler=new MetaPublishHandler();
108 _handlers.put(META_HANDSHAKE,new HandshakeHandler());
109 _handlers.put(META_CONNECT,new ConnectHandler());
110 _handlers.put(META_DISCONNECT,new DisconnectHandler());
111 _handlers.put(META_SUBSCRIBE,new SubscribeHandler());
112 _handlers.put(META_UNSUBSCRIBE,new UnsubscribeHandler());
113 _handlers.put(META_PING,new PingHandler());
114
115 setTimeout(getTimeout());
116 }
117
118
119 public void addExtension(Extension ext)
120 {
121 _extensions = (Extension[])LazyList.addToArray(_extensions,ext,Extension.class);
122 }
123
124
125
126
127
128
129 public ChannelImpl getChannel(ChannelId id)
130 {
131 return _root.getChild(id);
132 }
133
134
135 public ChannelImpl getChannel(String id)
136 {
137 ChannelId cid=getChannelId(id);
138 if (cid.depth()==0)
139 return null;
140 return _root.getChild(cid);
141 }
142
143
144 public Channel getChannel(String id, boolean create)
145 {
146 synchronized(this)
147 {
148 ChannelImpl channel=getChannel(id);
149
150 if (channel==null && create)
151 {
152 channel=new ChannelImpl(id,this);
153 _root.addChild(channel);
154
155 if (isLogInfo())
156 logInfo("newChannel: "+channel);
157 }
158 return channel;
159 }
160 }
161
162
163 public ChannelId getChannelId(String id)
164 {
165 ChannelId cid = _channelIdCache.get(id);
166 if (cid==null)
167 {
168
169 cid=new ChannelId(id);
170 _channelIdCache.put(id,cid);
171 }
172 return cid;
173 }
174
175
176
177
178
179 public Client getClient(String client_id)
180 {
181 synchronized(this)
182 {
183 if (client_id==null)
184 return null;
185 Client client = _clients.get(client_id);
186 return client;
187 }
188 }
189
190
191 public Set<String> getClientIDs()
192 {
193 return _clients.keySet();
194 }
195
196
197
198
199
200 public long getMaxInterval()
201 {
202 return _maxInterval;
203 }
204
205
206
207
208
209 public int getLogLevel()
210 {
211 return _logLevel;
212 }
213
214
215
216
217
218 public SecurityPolicy getSecurityPolicy()
219 {
220 return _securityPolicy;
221 }
222
223
224 public long getTimeout()
225 {
226 return _timeout;
227 }
228
229
230 public long getInterval()
231 {
232 return _interval;
233 }
234
235
236
237
238
239
240 public boolean isDirectDeliver()
241 {
242 return false;
243 }
244
245
246
247
248
249
250
251 public void setDirectDeliver(boolean directDeliver)
252 {
253 _context.log("directDeliver is deprecated");
254 }
255
256
257
258
259
260
261
262
263 public String handle(ClientImpl client, Transport transport, Message message) throws IOException
264 {
265 String channel_id=message.getChannel();
266
267 Handler handler=(Handler)_handlers.get(channel_id);
268 if (handler!=null)
269 {
270 message=extendRcvMeta(client,message);
271 handler.handle(client,transport,message);
272 _metaPublishHandler.handle(client,transport,message);
273 }
274 else if (channel_id.startsWith(META_SLASH))
275 {
276 message=extendRcvMeta(client,message);
277 _metaPublishHandler.handle(client,transport,message);
278 }
279 else
280 {
281
282 handler=_publishHandler;
283 message=extendRcv(client,message);
284 handler.handle(client,transport,message);
285 }
286
287 return channel_id;
288 }
289
290
291 public boolean hasChannel(String id)
292 {
293 ChannelId cid=getChannelId(id);
294 return _root.getChild(cid)!=null;
295 }
296
297
298 public boolean isInitialized()
299 {
300 return _initialized;
301 }
302
303
304
305
306
307
308 public boolean isJSONCommented()
309 {
310 return false;
311 }
312
313
314 public boolean isLogDebug()
315 {
316 return _logLevel>1;
317 }
318
319
320 public boolean isLogInfo()
321 {
322 return _logLevel>0;
323 }
324
325
326 public void logDebug(String message)
327 {
328 if (_logLevel>1)
329 _context.log(message);
330 }
331
332
333 public void logDebug(String message, Throwable th)
334 {
335 if (_logLevel>1)
336 _context.log(message,th);
337 }
338
339
340 public void logWarn(String message, Throwable th)
341 {
342 _context.log(message+": "+th.toString());
343 }
344
345
346 public void logWarn(String message)
347 {
348 _context.log(message);
349 }
350
351
352 public void logInfo(String message)
353 {
354 if (_logLevel>0)
355 _context.log(message);
356 }
357
358
359 public Client newClient(String idPrefix)
360 {
361 ClientImpl client = new ClientImpl(this,idPrefix);
362 return client;
363 }
364
365
366 public abstract ClientImpl newRemoteClient();
367
368
369
370
371
372
373
374 public Transport newTransport(ClientImpl client, Map<?,?> message)
375 {
376 if (isLogDebug())
377 logDebug("newTransport: client="+client+",message="+message);
378
379 Transport result=null;
380
381 try
382 {
383 String type=client==null?null:client.getConnectionType();
384 if (type==null)
385 type=(String)message.get(Bayeux.CONNECTION_TYPE_FIELD);
386
387 if (Bayeux.TRANSPORT_CALLBACK_POLL.equals(type) || type==null)
388 {
389 String jsonp=(String)message.get(Bayeux.JSONP_PARAMETER);
390 if(jsonp!=null)
391 result=new JSONPTransport(jsonp);
392 else
393 result=new JSONTransport();
394 }
395 else
396 result=new JSONTransport();
397
398 }
399 catch (Exception e)
400 {
401 throw new RuntimeException(e);
402 }
403
404 if (isLogDebug())
405 logDebug("newTransport: result="+result);
406 return result;
407 }
408
409
410
411
412
413
414
415
416
417 protected void doPublish(ChannelId to, Client from, Object data, String msgId)
418 {
419 Message message = newMessage();
420 message.put(CHANNEL_FIELD,to.toString());
421
422 if (msgId==null)
423 {
424 long id=message.hashCode()
425 ^(to==null?0:to.hashCode())
426 ^(from==null?0:from.hashCode());
427 id=id<0?-id:id;
428 message.put(ID_FIELD,Long.toString(id,36));
429 }
430 else
431 message.put(ID_FIELD,msgId);
432 message.put(DATA_FIELD,data);
433
434 message=extendSendBayeux(from,message);
435
436 if (message!=null)
437 _root.doDelivery(to,from,message);
438 ((MessageImpl)message).decRef();
439 }
440
441
442 public boolean removeChannel(ChannelImpl channel)
443 {
444 boolean removed = _root.doRemove(channel);
445 if (removed)
446 for (ChannelBayeuxListener l : _channelListeners)
447 l.channelRemoved(channel);
448 return removed;
449 }
450
451
452 public void addChannel(ChannelImpl channel)
453 {
454 for (ChannelBayeuxListener l : _channelListeners)
455 l.channelAdded(channel);
456 }
457
458
459 protected String newClientId(long variation, String idPrefix)
460 {
461 if (idPrefix==null)
462 return Long.toString(getRandom(),36)+Long.toString(variation,36);
463 else
464 return idPrefix+"_"+Long.toString(getRandom(),36);
465 }
466
467
468 protected void addClient(ClientImpl client,String idPrefix)
469 {
470 while(true)
471 {
472 String id = newClientId(client.hashCode(),idPrefix);
473 client.setId(id);
474
475 ClientImpl other = _clients.putIfAbsent(id,client);
476 if (other==null)
477 {
478 for (ClientBayeuxListener l : _clientListeners)
479 l.clientAdded((Client)client);
480
481 return;
482 }
483 }
484 }
485
486
487
488
489
490 public Client removeClient(String client_id)
491 {
492 ClientImpl client;
493 synchronized(this)
494 {
495 if (client_id==null)
496 return null;
497 client = _clients.remove(client_id);
498 }
499 if (client!=null)
500 {
501 client.unsubscribeAll();
502 for (ClientBayeuxListener l : _clientListeners)
503 l.clientRemoved((Client)client);
504 }
505 return client;
506 }
507
508
509
510
511
512 public void setMaxInterval(long ms)
513 {
514 _maxInterval=ms;
515 }
516
517
518
519
520
521 public void setJSONCommented(boolean commented)
522 {
523 if (commented)
524 _context.log("JSONCommented is deprecated");
525 }
526
527
528
529
530
531
532 public void setLogLevel(int logLevel)
533 {
534 _logLevel=logLevel;
535 }
536
537
538
539
540
541 public void setSecurityPolicy(SecurityPolicy securityPolicy)
542 {
543 _securityPolicy=securityPolicy;
544 }
545
546
547
548 public void setTimeout(long ms)
549 {
550 _timeout = ms;
551 generateAdvice();
552 }
553
554
555
556 public void setInterval(long ms)
557 {
558 _interval = ms;
559 generateAdvice();
560 }
561
562
563
564
565
566
567
568
569 public void setMultiFrameInterval(int multiFrameInterval)
570 {
571 _multiFrameInterval=multiFrameInterval;
572 generateAdvice();
573 }
574
575
576
577
578
579 public int getMultiFrameInterval()
580 {
581 return _multiFrameInterval;
582 }
583
584
585 void generateAdvice()
586 {
587 setAdvice(new JSON.Literal("{\"reconnect\":\"retry\",\"interval\":"+getInterval()+",\"timeout\":"+getTimeout()+"}"));
588 }
589
590
591 public void setAdvice(JSON.Literal advice)
592 {
593 synchronized(this)
594 {
595 _adviceVersion++;
596 _advice=advice;
597 _multiFrameAdvice=new JSON.Literal(JSON.toString(multiFrameAdvice(advice)));
598 }
599 }
600
601
602 private Map<String,Object> multiFrameAdvice(JSON.Literal advice)
603 {
604 Map<String,Object> a = (Map<String,Object>)JSON.parse(_advice.toString());
605 a.put("multiple-clients",Boolean.TRUE);
606 if (_multiFrameInterval>0)
607 {
608 a.put("reconnect","retry");
609 a.put("interval",_multiFrameInterval);
610 }
611 else
612 a.put("reconnect","none");
613 return a;
614 }
615
616
617 public JSON.Literal getAdvice()
618 {
619 return _advice;
620 }
621
622
623
624
625
626 public boolean isRequestAvailable()
627 {
628 return _requestAvailable;
629 }
630
631
632
633
634
635 public void setRequestAvailable(boolean requestAvailable)
636 {
637 _requestAvailable=requestAvailable;
638 }
639
640
641
642
643
644 public HttpServletRequest getCurrentRequest()
645 {
646 return _request.get();
647 }
648
649
650
651
652
653 void setCurrentRequest(HttpServletRequest request)
654 {
655 _request.set(request);
656 }
657
658
659
660
661 public Collection<Channel> getChannels()
662 {
663 List<Channel> channels = new ArrayList<Channel>();
664 _root.getChannels(channels);
665 return channels;
666 }
667
668
669
670
671
672 public int getChannelCount()
673 {
674 return _root.getChannelCount();
675 }
676
677
678 public Collection<Client> getClients()
679 {
680 synchronized(this)
681 {
682 return new ArrayList<Client>(_clients.values());
683 }
684 }
685
686
687
688
689
690 public int getClientCount()
691 {
692 synchronized(this)
693 {
694 return _clients.size();
695 }
696 }
697
698
699 public boolean hasClient(String clientId)
700 {
701 synchronized(this)
702 {
703 if (clientId==null)
704 return false;
705 return _clients.containsKey(clientId);
706 }
707 }
708
709
710 public Channel removeChannel(String channelId)
711 {
712 Channel channel = getChannel(channelId);
713
714 boolean removed = false;
715 if (channel!=null)
716 removed = channel.remove();
717
718 if (removed)
719 return channel;
720 else
721 return null;
722 }
723
724
725 protected void initialize(ServletContext context)
726 {
727 synchronized(this)
728 {
729 _initialized=true;
730 _context=context;
731 try
732 {
733 _random=SecureRandom.getInstance("SHA1PRNG");
734 }
735 catch (Exception e)
736 {
737 context.log("Could not get secure random for ID generation",e);
738 _random=new Random();
739 }
740 _random.setSeed(_random.nextLong()^hashCode()^(context.hashCode()<<32)^Runtime.getRuntime().freeMemory());
741 _channelIdCache=new ConcurrentHashMap<String, ChannelId>();
742
743 _root.addChild(new ServiceChannel(Bayeux.SERVICE));
744
745 }
746 }
747
748
749 long getRandom()
750 {
751 long l=_random.nextLong();
752 return l<0?-l:l;
753 }
754
755
756 void clientOnBrowser(String browserId,String clientId)
757 {
758 List<String> clients=_browser2client.get(browserId);
759 if (clients==null)
760 {
761 List<String> new_clients=new CopyOnWriteArrayList<String>();
762 clients=_browser2client.putIfAbsent(browserId,new_clients);
763 if (clients==null)
764 clients=new_clients;
765 }
766 clients.add(clientId);
767 }
768
769
770 void clientOffBrowser(String browserId,String clientId)
771 {
772 List<String> clients=_browser2client.get(browserId);
773 if (clients!=null)
774 clients.remove(clientId);
775 }
776
777
778 List<String> clientsOnBrowser(String browserId)
779 {
780 List<String> clients=_browser2client.get(browserId);
781 if (clients==null)
782 return Collections.emptyList();
783 return clients;
784 }
785
786
787 public void addListener(BayeuxListener listener)
788 {
789 if (listener instanceof ClientBayeuxListener)
790 _clientListeners.add((ClientBayeuxListener)listener);
791 else if(listener instanceof ChannelBayeuxListener)
792 _channelListeners.add((ChannelBayeuxListener)listener);
793 }
794
795
796 public int getMaxClientQueue()
797 {
798 return _maxClientQueue;
799 }
800
801
802 public void setMaxClientQueue(int size)
803 {
804 _maxClientQueue=size;
805 }
806
807
808 protected Message extendRcv(ClientImpl from, Message message)
809 {
810 if (_extensions!=null)
811 {
812 for (int i=_extensions.length;message!=null && i-->0;)
813 message=_extensions[i].rcv(from, message);
814 }
815
816 if (from!=null)
817 {
818 Extension[] client_exs = from.getExtensions();
819 if (client_exs!=null)
820 {
821 for (int i=client_exs.length;message!=null && i-->0;)
822 message=client_exs[i].rcv(from, message);
823 }
824 }
825
826 return message;
827 }
828
829
830 protected Message extendRcvMeta(ClientImpl from, Message message)
831 {
832 if (_extensions!=null)
833 {
834 for (int i=_extensions.length;message!=null && i-->0;)
835 message=_extensions[i].rcvMeta(from, message);
836 }
837
838 if (from!=null)
839 {
840 Extension[] client_exs = from.getExtensions();
841 if (client_exs!=null)
842 {
843 for (int i=client_exs.length;message!=null && i-->0;)
844 message=client_exs[i].rcvMeta(from, message);
845 }
846 }
847 return message;
848 }
849
850
851 protected Message extendSendBayeux(Client from, Message message)
852 {
853 if (_extensions!=null)
854 {
855 for (int i=0;message!=null && i<_extensions.length;i++)
856 message=_extensions[i].send(from, message);
857 }
858
859 return message;
860 }
861
862
863 public Message extendSendClient(Client from, ClientImpl to, Message message)
864 {
865 if (to!=null)
866 {
867 Extension[] client_exs = to.getExtensions();
868 if (client_exs!=null)
869 {
870 for (int i=0;message!=null && i<client_exs.length;i++)
871 message=client_exs[i].send(from, message);
872 }
873 }
874
875 return message;
876 }
877
878
879 public Message extendSendMeta(ClientImpl from, Message message)
880 {
881 if (_extensions!=null)
882 {
883 for (int i=0;message!=null && i<_extensions.length;i++)
884 message=_extensions[i].sendMeta(from, message);
885 }
886
887 if (from!=null)
888 {
889 Extension[] client_exs = from.getExtensions();
890 if (client_exs!=null)
891 {
892 for (int i=0;message!=null && i<client_exs.length;i++)
893 message=client_exs[i].sendMeta(from, message);
894 }
895 }
896
897 return message;
898 }
899
900
901
902
903 public static class DefaultPolicy implements SecurityPolicy
904 {
905 public boolean canHandshake(Message message)
906 {
907 return true;
908 }
909
910 public boolean canCreate(Client client, String channel, Message message)
911 {
912 return client!=null && !channel.startsWith(Bayeux.META_SLASH);
913 }
914
915 public boolean canSubscribe(Client client, String channel, Message message)
916 {
917 if (client!=null && ("/**".equals(channel) || "/*".equals(channel)))
918 return false;
919 return client!=null && !channel.startsWith(Bayeux.META_SLASH);
920 }
921
922 public boolean canPublish(Client client, String channel, Message message)
923 {
924 return client!=null || client==null && Bayeux.META_HANDSHAKE.equals(channel);
925 }
926
927 }
928
929
930
931
932 protected abstract class Handler
933 {
934 abstract void handle(ClientImpl client, Transport transport, Message message) throws IOException;
935 abstract ChannelId getMetaChannelId();
936 void unknownClient(Transport transport,String channel) throws IOException
937 {
938 MessageImpl reply=newMessage();
939
940 reply.put(CHANNEL_FIELD,channel);
941 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
942 reply.put(ERROR_FIELD,"402::Unknown client");
943 reply.put("advice",_handshakeAdvice);
944 transport.send(reply);
945 }
946 }
947
948
949
950 protected class ConnectHandler extends Handler
951 {
952 protected String _metaChannel=META_CONNECT;
953
954 @Override
955 ChannelId getMetaChannelId()
956 {
957 return META_CONNECT_ID;
958 }
959
960 @Override
961 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
962 {
963 if (client==null)
964 {
965 unknownClient(transport,_metaChannel);
966 return;
967 }
968
969
970 String type=client.getConnectionType();
971 boolean polling=true;
972 if (type==null)
973 {
974 type=(String)message.get(Bayeux.CONNECTION_TYPE_FIELD);
975 client.setConnectionType(type);
976 polling=false;
977 }
978
979 Object advice = message.get(ADVICE_FIELD);
980 if (advice!=null)
981 {
982 Long timeout=(Long)((Map)advice).get("timeout");
983 if (timeout!=null && timeout.longValue()>0)
984 client.setTimeout(timeout.longValue());
985 else
986 client.setTimeout(0);
987 }
988 else
989 client.setTimeout(0);
990
991 advice=null;
992
993
994 if (polling && _multiFrameInterval>0 && client.getBrowserId()!=null)
995 {
996 List<String> clients=clientsOnBrowser(client.getBrowserId());
997 int count=clients.size();
998 if (count>1)
999 {
1000 polling=clients.get(0).equals(client.getId());
1001 advice=client.getAdvice();
1002 if (advice==null)
1003 advice=_multiFrameAdvice;
1004 else
1005 advice=multiFrameAdvice((JSON.Literal)advice);
1006 }
1007 }
1008
1009 synchronized(this)
1010 {
1011 if (advice==null)
1012 {
1013 if (_adviceVersion!=client._adviseVersion)
1014 {
1015 advice=_advice;
1016 client._adviseVersion=_adviceVersion;
1017 }
1018 }
1019 else
1020 client._adviseVersion=-1;
1021 }
1022
1023
1024 String id=message.getId();
1025
1026 Message reply=newMessage(message);
1027
1028 reply.put(CHANNEL_FIELD,META_CONNECT);
1029 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1030 if (advice!=null)
1031 reply.put(ADVICE_FIELD,advice);
1032 if (id!=null)
1033 reply.put(ID_FIELD,id);
1034
1035 if (polling)
1036 transport.setPollReply(reply);
1037 else
1038 {
1039 reply=extendSendMeta(client,reply);
1040 if (reply!=null)
1041 transport.send(reply);
1042 }
1043 }
1044 }
1045
1046
1047
1048 protected class DisconnectHandler extends Handler
1049 {
1050 @Override
1051 ChannelId getMetaChannelId()
1052 {
1053 return META_DISCONNECT_ID;
1054 }
1055
1056 @Override
1057 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1058 {
1059 if (client==null)
1060 {
1061 unknownClient(transport,META_DISCONNECT);
1062 return;
1063 }
1064 if (isLogInfo())
1065 logInfo("Disconnect "+client.getId());
1066
1067 client.remove(false);
1068
1069 Message reply=newMessage(message);
1070 reply.put(CHANNEL_FIELD,META_DISCONNECT);
1071 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1072 String id=message.getId();
1073 if (id!=null)
1074 reply.put(ID_FIELD,id);
1075
1076 reply=extendSendMeta(client,reply);
1077
1078 Message pollReply = transport.getPollReply();
1079 if (pollReply!=null)
1080 {
1081 pollReply=extendSendMeta(client,pollReply);
1082 if (pollReply!=null)
1083 transport.send(pollReply);
1084 transport.setPollReply(null);
1085 }
1086 transport.send(reply);
1087 }
1088 }
1089
1090
1091
1092
1093 protected class HandshakeHandler extends Handler
1094 {
1095 @Override
1096 ChannelId getMetaChannelId()
1097 {
1098 return META_HANDSHAKE_ID;
1099 }
1100
1101 @Override
1102 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1103 {
1104 if (client!=null)
1105 throw new IllegalStateException();
1106
1107 if (_securityPolicy!=null && !_securityPolicy.canHandshake(message))
1108 {
1109 Message reply=newMessage(message);
1110 reply.put(CHANNEL_FIELD,META_HANDSHAKE);
1111 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1112 reply.put(ERROR_FIELD,"403::Handshake denied");
1113
1114 reply=extendSendBayeux(client,reply);
1115 if (reply!=null)
1116 transport.send(reply);
1117 return;
1118 }
1119
1120 client=newRemoteClient();
1121
1122 Message reply=newMessage(message);
1123 reply.put(CHANNEL_FIELD, META_HANDSHAKE);
1124 reply.put(VERSION_FIELD, "1.0");
1125 reply.put(MIN_VERSION_FIELD, "0.9");
1126
1127 if (client!=null)
1128 {
1129 reply.put(SUPP_CONNECTION_TYPE_FIELD, _transports);
1130 reply.put(SUCCESSFUL_FIELD, Boolean.TRUE);
1131 reply.put(CLIENT_FIELD, client.getId());
1132 if (_advice!=null)
1133 reply.put(ADVICE_FIELD,_advice);
1134 }
1135 else
1136 {
1137 reply.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
1138 if (_advice!=null)
1139 reply.put(ADVICE_FIELD,_advice);
1140 }
1141
1142 if (isLogDebug())
1143 logDebug("handshake.handle: reply="+reply);
1144
1145 String id=message.getId();
1146 if (id!=null)
1147 reply.put(ID_FIELD,id);
1148
1149 reply=extendSendMeta(client,reply);
1150 if (reply!=null)
1151 transport.send(reply);
1152 }
1153 }
1154
1155
1156
1157 protected class PublishHandler extends Handler
1158 {
1159 @Override
1160 ChannelId getMetaChannelId()
1161 {
1162 return null;
1163 }
1164
1165 @Override
1166 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1167 {
1168 String channel_id=message.getChannel();
1169
1170 if (client==null && message.containsKey(CLIENT_FIELD))
1171 {
1172 unknownClient(transport,channel_id);
1173 return;
1174 }
1175
1176 String id=message.getId();
1177
1178 ChannelId cid=getChannelId(channel_id);
1179 Object data=message.get(Bayeux.DATA_FIELD);
1180
1181 Message reply=newMessage(message);
1182 reply.put(CHANNEL_FIELD,channel_id);
1183 if (id!=null)
1184 reply.put(ID_FIELD,id);
1185
1186 if (data!=null&&_securityPolicy.canPublish(client,channel_id,message))
1187 {
1188 message.remove(CLIENT_FIELD);
1189 message=extendSendBayeux(client,message);
1190
1191 if (message!=null)
1192 {
1193 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1194 }
1195 else
1196 {
1197 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1198 reply.put(ERROR_FIELD,"404::Message deleted");
1199 }
1200 }
1201 else
1202 {
1203 message=null;
1204 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1205 reply.put(ERROR_FIELD,"403::Publish denied");
1206 }
1207
1208 reply=extendSendBayeux(client,reply);
1209 if (reply!=null)
1210 transport.send(reply);
1211
1212 if (message!=null)
1213 _root.doDelivery(cid,client,message);
1214 }
1215 }
1216
1217
1218
1219 protected class MetaPublishHandler extends Handler
1220 {
1221 @Override
1222 ChannelId getMetaChannelId()
1223 {
1224 return null;
1225 }
1226
1227 @Override
1228 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1229 {
1230 String channel_id=message.getChannel();
1231
1232 if (client==null && !META_HANDSHAKE.equals(channel_id))
1233 {
1234
1235 return;
1236 }
1237
1238 if(_securityPolicy.canPublish(client,channel_id,message))
1239 {
1240 _root.doDelivery(getChannelId(channel_id),client,message);
1241 }
1242 }
1243 }
1244
1245
1246
1247 protected class SubscribeHandler extends Handler
1248 {
1249 @Override
1250 ChannelId getMetaChannelId()
1251 {
1252 return META_SUBSCRIBE_ID;
1253 }
1254
1255 @Override
1256 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1257 {
1258 if (client==null)
1259 {
1260 unknownClient(transport,META_SUBSCRIBE);
1261 return;
1262 }
1263
1264 String subscribe_id=(String)message.get(SUBSCRIPTION_FIELD);
1265
1266
1267 if (subscribe_id==null)
1268 {
1269 subscribe_id=Long.toString(getRandom(),36);
1270 while (getChannel(subscribe_id)!=null)
1271 subscribe_id=Long.toString(getRandom(),36);
1272 }
1273
1274 ChannelId cid=null;
1275 boolean can_subscribe=false;
1276
1277 if (subscribe_id.startsWith(Bayeux.SERVICE_SLASH))
1278 {
1279 can_subscribe=true;
1280 }
1281 else if (subscribe_id.startsWith(Bayeux.META_SLASH))
1282 {
1283 can_subscribe=false;
1284 }
1285 else
1286 {
1287 cid=getChannelId(subscribe_id);
1288 can_subscribe=_securityPolicy.canSubscribe(client,subscribe_id,message);
1289 }
1290
1291 Message reply=newMessage(message);
1292 reply.put(CHANNEL_FIELD,META_SUBSCRIBE);
1293 reply.put(SUBSCRIPTION_FIELD,subscribe_id);
1294
1295 if (can_subscribe)
1296 {
1297 if (cid!=null)
1298 {
1299 ChannelImpl channel=getChannel(cid);
1300 if (channel==null&&_securityPolicy.canCreate(client,subscribe_id,message))
1301 channel=(ChannelImpl)getChannel(subscribe_id, true);
1302
1303 if (channel!=null)
1304 channel.subscribe(client);
1305 else
1306 can_subscribe=false;
1307 }
1308
1309 if (can_subscribe)
1310 {
1311 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1312 }
1313 else
1314 {
1315 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1316 reply.put(ERROR_FIELD,"403::cannot create");
1317 }
1318 }
1319 else
1320 {
1321 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1322 reply.put(ERROR_FIELD,"403::cannot subscribe");
1323
1324 }
1325
1326 String id=message.getId();
1327 if (id!=null)
1328 reply.put(ID_FIELD,id);
1329
1330 reply=extendSendMeta(client,reply);
1331 if (reply!=null)
1332 transport.send(reply);
1333 }
1334 }
1335
1336
1337
1338 protected class UnsubscribeHandler extends Handler
1339 {
1340 @Override
1341 ChannelId getMetaChannelId()
1342 {
1343 return META_UNSUBSCRIBE_ID;
1344 }
1345
1346 @Override
1347 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1348 {
1349 if (client==null)
1350 {
1351 unknownClient(transport,META_UNSUBSCRIBE);
1352 return;
1353 }
1354
1355 String channel_id=(String)message.get(SUBSCRIPTION_FIELD);
1356 ChannelImpl channel=getChannel(channel_id);
1357 if (channel!=null)
1358 channel.unsubscribe(client);
1359
1360 Message reply=newMessage(message);
1361 reply.put(CHANNEL_FIELD,META_UNSUBSCRIBE);
1362 reply.put(SUBSCRIPTION_FIELD,channel.getId());
1363 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1364
1365 String id=message.getId();
1366 if (id!=null)
1367 reply.put(ID_FIELD,id);
1368 reply=extendSendMeta(client,reply);
1369 if (reply!=null)
1370 transport.send(reply);
1371 }
1372 }
1373
1374
1375
1376 protected class PingHandler extends Handler
1377 {
1378 @Override
1379 ChannelId getMetaChannelId()
1380 {
1381 return META_PING_ID;
1382 }
1383
1384 @Override
1385 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1386 {
1387 Message reply=newMessage(message);
1388 reply.put(CHANNEL_FIELD,META_PING);
1389 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1390
1391 String id=message.getId();
1392 if (id!=null)
1393 reply.put(ID_FIELD,id);
1394
1395 reply=extendSendMeta(client,reply);
1396 if (reply!=null)
1397 transport.send(reply);
1398 }
1399 }
1400
1401
1402
1403
1404 protected class ServiceChannel extends ChannelImpl
1405 {
1406 ServiceChannel(String id)
1407 {
1408 super(id,AbstractBayeux.this);
1409 }
1410
1411
1412
1413
1414
1415 @Override
1416 public void addChild(ChannelImpl channel)
1417 {
1418 super.addChild(channel);
1419 setPersistent(true);
1420 }
1421
1422
1423 @Override
1424 public void subscribe(Client client)
1425 {
1426 if (client.isLocal())
1427 super.subscribe(client);
1428 }
1429
1430 }
1431 }