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