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