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, boolean lazy)
418 {
419 final MessageImpl 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.setLazy(lazy);
435
436 final Message m=extendSendBayeux(from,message);
437
438 if (m!=null)
439 _root.doDelivery(to,from,m);
440 if (m instanceof MessageImpl)
441 ((MessageImpl)m).decRef();
442 }
443
444
445 public boolean removeChannel(ChannelImpl channel)
446 {
447 return _root.doRemove(channel,_channelListeners);
448 }
449
450
451 public void addChannel(ChannelImpl channel)
452 {
453 for (ChannelBayeuxListener l : _channelListeners)
454 l.channelAdded(channel);
455 }
456
457
458 protected String newClientId(long variation, String idPrefix)
459 {
460 if (idPrefix==null)
461 return Long.toString(getRandom(),36)+Long.toString(variation,36);
462 else
463 return idPrefix+"_"+Long.toString(getRandom(),36);
464 }
465
466
467 protected void addClient(ClientImpl client,String idPrefix)
468 {
469 while(true)
470 {
471 String id = newClientId(client.hashCode(),idPrefix);
472 client.setId(id);
473
474 ClientImpl other = _clients.putIfAbsent(id,client);
475 if (other==null)
476 {
477 for (ClientBayeuxListener l : _clientListeners)
478 l.clientAdded((Client)client);
479
480 return;
481 }
482 }
483 }
484
485
486
487
488
489 public Client removeClient(String client_id)
490 {
491 ClientImpl client;
492 synchronized(this)
493 {
494 if (client_id==null)
495 return null;
496 client = _clients.remove(client_id);
497 }
498 if (client!=null)
499 {
500 for (ClientBayeuxListener l : _clientListeners)
501 l.clientRemoved((Client)client);
502 client.unsubscribeAll();
503 }
504 return client;
505 }
506
507
508
509
510
511 public void setMaxInterval(long ms)
512 {
513 _maxInterval=ms;
514 }
515
516
517
518
519
520 public void setJSONCommented(boolean commented)
521 {
522 if (commented)
523 _context.log("JSONCommented is deprecated");
524 }
525
526
527
528
529
530
531 public void setLogLevel(int logLevel)
532 {
533 _logLevel=logLevel;
534 }
535
536
537
538
539
540 public void setSecurityPolicy(SecurityPolicy securityPolicy)
541 {
542 _securityPolicy=securityPolicy;
543 }
544
545
546
547 public void setTimeout(long ms)
548 {
549 _timeout = ms;
550 generateAdvice();
551 }
552
553
554
555 public void setInterval(long ms)
556 {
557 _interval = ms;
558 generateAdvice();
559 }
560
561
562
563
564
565
566
567
568 public void setMultiFrameInterval(int multiFrameInterval)
569 {
570 _multiFrameInterval=multiFrameInterval;
571 generateAdvice();
572 }
573
574
575
576
577
578 public int getMultiFrameInterval()
579 {
580 return _multiFrameInterval;
581 }
582
583
584 void generateAdvice()
585 {
586 setAdvice(new JSON.Literal("{\"reconnect\":\"retry\",\"interval\":"+getInterval()+",\"timeout\":"+getTimeout()+"}"));
587 }
588
589
590 public void setAdvice(JSON.Literal advice)
591 {
592 synchronized(this)
593 {
594 _adviceVersion++;
595 _advice=advice;
596 _multiFrameAdvice=new JSON.Literal(JSON.toString(multiFrameAdvice(advice)));
597 }
598 }
599
600
601 private Map<String,Object> multiFrameAdvice(JSON.Literal advice)
602 {
603 Map<String,Object> a = (Map<String,Object>)JSON.parse(_advice.toString());
604 a.put("multiple-clients",Boolean.TRUE);
605 if (_multiFrameInterval>0)
606 {
607 a.put("reconnect","retry");
608 a.put("interval",_multiFrameInterval);
609 }
610 else
611 a.put("reconnect","none");
612 return a;
613 }
614
615
616 public JSON.Literal getAdvice()
617 {
618 return _advice;
619 }
620
621
622
623
624
625 public boolean isRequestAvailable()
626 {
627 return _requestAvailable;
628 }
629
630
631
632
633
634 public void setRequestAvailable(boolean requestAvailable)
635 {
636 _requestAvailable=requestAvailable;
637 }
638
639
640
641
642
643 public HttpServletRequest getCurrentRequest()
644 {
645 return _request.get();
646 }
647
648
649
650
651
652 void setCurrentRequest(HttpServletRequest request)
653 {
654 _request.set(request);
655 }
656
657
658
659
660 public Collection<Channel> getChannels()
661 {
662 List<Channel> channels = new ArrayList<Channel>();
663 _root.getChannels(channels);
664 return channels;
665 }
666
667
668
669
670
671 public int getChannelCount()
672 {
673 return _root.getChannelCount();
674 }
675
676
677 public Collection<Client> getClients()
678 {
679 synchronized(this)
680 {
681 return new ArrayList<Client>(_clients.values());
682 }
683 }
684
685
686
687
688
689 public int getClientCount()
690 {
691 synchronized(this)
692 {
693 return _clients.size();
694 }
695 }
696
697
698 public boolean hasClient(String clientId)
699 {
700 synchronized(this)
701 {
702 if (clientId==null)
703 return false;
704 return _clients.containsKey(clientId);
705 }
706 }
707
708
709 public Channel removeChannel(String channelId)
710 {
711 Channel channel = getChannel(channelId);
712
713 boolean removed = false;
714 if (channel!=null)
715 removed = channel.remove();
716
717 if (removed)
718 return channel;
719 else
720 return null;
721 }
722
723
724 protected void initialize(ServletContext context)
725 {
726 synchronized(this)
727 {
728 _initialized=true;
729 _context=context;
730 try
731 {
732 _random=SecureRandom.getInstance("SHA1PRNG");
733 }
734 catch (Exception e)
735 {
736 context.log("Could not get secure random for ID generation",e);
737 _random=new Random();
738 }
739 _random.setSeed(_random.nextLong()^hashCode()^System.nanoTime()^Runtime.getRuntime().freeMemory());
740 _channelIdCache=new ConcurrentHashMap<String, ChannelId>();
741
742 _root.addChild(new ServiceChannel(Bayeux.SERVICE));
743
744 }
745 }
746
747
748 long getRandom()
749 {
750 long l=_random.nextLong();
751 return l<0?-l:l;
752 }
753
754
755 void clientOnBrowser(String browserId,String clientId)
756 {
757 List<String> clients=_browser2client.get(browserId);
758 if (clients==null)
759 {
760 List<String> new_clients=new CopyOnWriteArrayList<String>();
761 clients=_browser2client.putIfAbsent(browserId,new_clients);
762 if (clients==null)
763 clients=new_clients;
764 }
765 clients.add(clientId);
766 }
767
768
769 void clientOffBrowser(String browserId,String clientId)
770 {
771 List<String> clients=_browser2client.get(browserId);
772
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
782 if (clients==null)
783 return Collections.emptyList();
784 return clients;
785 }
786
787
788 public void addListener(BayeuxListener listener)
789 {
790 if (listener instanceof ClientBayeuxListener)
791 _clientListeners.add((ClientBayeuxListener)listener);
792 if(listener instanceof ChannelBayeuxListener)
793 _channelListeners.add((ChannelBayeuxListener)listener);
794 }
795
796
797 public int getMaxClientQueue()
798 {
799 return _maxClientQueue;
800 }
801
802
803 public void setMaxClientQueue(int size)
804 {
805 _maxClientQueue=size;
806 }
807
808
809 protected Message extendRcv(ClientImpl from, Message message)
810 {
811 if (_extensions!=null)
812 {
813 for (int i=_extensions.length;message!=null && i-->0;)
814 message=_extensions[i].rcv(from, message);
815 }
816
817 if (from!=null)
818 {
819 Extension[] client_exs = from.getExtensions();
820 if (client_exs!=null)
821 {
822 for (int i=client_exs.length;message!=null && i-->0;)
823 message=client_exs[i].rcv(from, message);
824 }
825 }
826
827 return message;
828 }
829
830
831 protected Message extendRcvMeta(ClientImpl from, Message message)
832 {
833 if (_extensions!=null)
834 {
835 for (int i=_extensions.length;message!=null && i-->0;)
836 message=_extensions[i].rcvMeta(from, message);
837 }
838
839 if (from!=null)
840 {
841 Extension[] client_exs = from.getExtensions();
842 if (client_exs!=null)
843 {
844 for (int i=client_exs.length;message!=null && i-->0;)
845 message=client_exs[i].rcvMeta(from, message);
846 }
847 }
848 return message;
849 }
850
851
852 protected Message extendSendBayeux(Client from, Message message)
853 {
854 if (_extensions!=null)
855 {
856 for (int i=0;message!=null && i<_extensions.length;i++)
857 {
858 message=_extensions[i].send(from, message);
859 }
860 }
861
862 return message;
863 }
864
865
866 public Message extendSendClient(Client from, ClientImpl to, Message message)
867 {
868 if (to!=null)
869 {
870 Extension[] client_exs = to.getExtensions();
871 if (client_exs!=null)
872 {
873 for (int i=0;message!=null && i<client_exs.length;i++)
874 message=client_exs[i].send(from, message);
875 }
876 }
877
878 return message;
879 }
880
881
882 public Message extendSendMeta(ClientImpl from, Message message)
883 {
884 if (_extensions!=null)
885 {
886 for (int i=0;message!=null && i<_extensions.length;i++)
887 message=_extensions[i].sendMeta(from, message);
888 }
889
890 if (from!=null)
891 {
892 Extension[] client_exs = from.getExtensions();
893 if (client_exs!=null)
894 {
895 for (int i=0;message!=null && i<client_exs.length;i++)
896 message=client_exs[i].sendMeta(from, message);
897 }
898 }
899
900 return message;
901 }
902
903
904
905
906 public static class DefaultPolicy implements SecurityPolicy
907 {
908 public boolean canHandshake(Message message)
909 {
910 return true;
911 }
912
913 public boolean canCreate(Client client, String channel, Message message)
914 {
915 return client!=null && !channel.startsWith(Bayeux.META_SLASH);
916 }
917
918 public boolean canSubscribe(Client client, String channel, Message message)
919 {
920 if (client!=null && ("/**".equals(channel) || "/*".equals(channel)))
921 return false;
922 return client!=null && !channel.startsWith(Bayeux.META_SLASH);
923 }
924
925 public boolean canPublish(Client client, String channel, Message message)
926 {
927 return client!=null || client==null && Bayeux.META_HANDSHAKE.equals(channel);
928 }
929
930 }
931
932
933
934
935 protected abstract class Handler
936 {
937 abstract void handle(ClientImpl client, Transport transport, Message message) throws IOException;
938 abstract ChannelId getMetaChannelId();
939 void unknownClient(Transport transport,String channel) throws IOException
940 {
941 MessageImpl reply=newMessage();
942
943 reply.put(CHANNEL_FIELD,channel);
944 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
945 reply.put(ERROR_FIELD,"402::Unknown client");
946 reply.put("advice",_handshakeAdvice);
947 transport.send(reply);
948 reply.decRef();
949 }
950
951 void sendMetaReply(final ClientImpl client,Message reply, final Transport transport) throws IOException
952 {
953 reply=extendSendMeta(client,reply);
954 if (reply!=null)
955 {
956 transport.send(reply);
957 if (reply instanceof MessageImpl)
958 ((MessageImpl)reply).decRef();
959 }
960 }
961 }
962
963
964
965 protected class ConnectHandler extends Handler
966 {
967 protected String _metaChannel=META_CONNECT;
968
969 @Override
970 ChannelId getMetaChannelId()
971 {
972 return META_CONNECT_ID;
973 }
974
975 @Override
976 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
977 {
978 if (client==null)
979 {
980 unknownClient(transport,_metaChannel);
981 return;
982 }
983
984
985 String type=client.getConnectionType();
986 boolean polling=true;
987 if (type==null)
988 {
989 type=(String)message.get(Bayeux.CONNECTION_TYPE_FIELD);
990 client.setConnectionType(type);
991 polling=false;
992 }
993
994 Object advice = message.get(ADVICE_FIELD);
995 if (advice!=null)
996 {
997 Long timeout=(Long)((Map)advice).get("timeout");
998 if (timeout!=null && timeout.longValue()>0)
999 client.setTimeout(timeout.longValue());
1000 else
1001 client.setTimeout(0);
1002 }
1003 else
1004 client.setTimeout(0);
1005
1006 advice=null;
1007
1008
1009 if (polling && _multiFrameInterval>0 && client.getBrowserId()!=null)
1010 {
1011 List<String> clients=clientsOnBrowser(client.getBrowserId());
1012 int count=clients.size();
1013 if (count>1)
1014 {
1015 polling=clients.get(0).equals(client.getId());
1016 advice=client.getAdvice();
1017 if (advice==null)
1018 advice=_multiFrameAdvice;
1019 else
1020 advice=multiFrameAdvice((JSON.Literal)advice);
1021 }
1022 }
1023
1024 synchronized(this)
1025 {
1026 if (advice==null)
1027 {
1028 if (_adviceVersion!=client._adviseVersion)
1029 {
1030 advice=_advice;
1031 client._adviseVersion=_adviceVersion;
1032 }
1033 }
1034 else
1035 client._adviseVersion=-1;
1036 }
1037
1038
1039 String id=message.getId();
1040
1041 Message reply=newMessage(message);
1042
1043 reply.put(CHANNEL_FIELD,META_CONNECT);
1044 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1045 if (advice!=null)
1046 reply.put(ADVICE_FIELD,advice);
1047 if (id!=null)
1048 reply.put(ID_FIELD,id);
1049
1050 if (polling)
1051 transport.setMetaConnnectReply(reply);
1052 else
1053 sendMetaReply(client,reply,transport);
1054 }
1055 }
1056
1057
1058
1059 protected class DisconnectHandler extends Handler
1060 {
1061 @Override
1062 ChannelId getMetaChannelId()
1063 {
1064 return META_DISCONNECT_ID;
1065 }
1066
1067 @Override
1068 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1069 {
1070 if (client==null)
1071 {
1072 unknownClient(transport,META_DISCONNECT);
1073 return;
1074 }
1075 if (isLogInfo())
1076 logInfo("Disconnect "+client.getId());
1077
1078 client.remove(false);
1079
1080 Message reply=newMessage(message);
1081 reply.put(CHANNEL_FIELD,META_DISCONNECT);
1082 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1083 String id=message.getId();
1084 if (id!=null)
1085 reply.put(ID_FIELD,id);
1086
1087 reply=extendSendMeta(client,reply);
1088
1089 Message pollReply = transport.getMetaConnectReply();
1090 if (pollReply!=null)
1091 {
1092 transport.setMetaConnnectReply(null);
1093 sendMetaReply(client,pollReply,transport);
1094 }
1095 sendMetaReply(client,reply,transport);
1096 }
1097 }
1098
1099
1100
1101
1102 protected class HandshakeHandler extends Handler
1103 {
1104 @Override
1105 ChannelId getMetaChannelId()
1106 {
1107 return META_HANDSHAKE_ID;
1108 }
1109
1110 @Override
1111 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1112 {
1113 if (client!=null)
1114 throw new IllegalStateException();
1115
1116 if (_securityPolicy!=null && !_securityPolicy.canHandshake(message))
1117 {
1118 Message reply=newMessage(message);
1119 reply.put(CHANNEL_FIELD,META_HANDSHAKE);
1120 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1121 reply.put(ERROR_FIELD,"403::Handshake denied");
1122
1123 sendMetaReply(client,reply,transport);
1124 return;
1125 }
1126
1127 client=newRemoteClient();
1128
1129 Message reply=newMessage(message);
1130 reply.put(CHANNEL_FIELD, META_HANDSHAKE);
1131 reply.put(VERSION_FIELD, "1.0");
1132 reply.put(MIN_VERSION_FIELD, "0.9");
1133
1134 if (client!=null)
1135 {
1136 reply.put(SUPP_CONNECTION_TYPE_FIELD, _transports);
1137 reply.put(SUCCESSFUL_FIELD, Boolean.TRUE);
1138 reply.put(CLIENT_FIELD, client.getId());
1139 if (_advice!=null)
1140 reply.put(ADVICE_FIELD,_advice);
1141 }
1142 else
1143 {
1144 reply.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
1145 if (_advice!=null)
1146 reply.put(ADVICE_FIELD,_advice);
1147 }
1148
1149 if (isLogDebug())
1150 logDebug("handshake.handle: reply="+reply);
1151
1152 String id=message.getId();
1153 if (id!=null)
1154 reply.put(ID_FIELD,id);
1155
1156 sendMetaReply(client,reply,transport);
1157 }
1158 }
1159
1160
1161
1162 protected class PublishHandler extends Handler
1163 {
1164 @Override
1165 ChannelId getMetaChannelId()
1166 {
1167 return null;
1168 }
1169
1170 @Override
1171 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1172 {
1173 String channel_id=message.getChannel();
1174
1175 if (client==null && message.containsKey(CLIENT_FIELD))
1176 {
1177 unknownClient(transport,channel_id);
1178 return;
1179 }
1180
1181 String id=message.getId();
1182
1183 ChannelId cid=getChannelId(channel_id);
1184 Object data=message.get(Bayeux.DATA_FIELD);
1185
1186 Message reply=newMessage(message);
1187 reply.put(CHANNEL_FIELD,channel_id);
1188 if (id!=null)
1189 reply.put(ID_FIELD,id);
1190
1191 if (data!=null&&_securityPolicy.canPublish(client,channel_id,message))
1192 {
1193 message.remove(CLIENT_FIELD);
1194 message=extendSendBayeux(client,message);
1195
1196 if (message!=null)
1197 {
1198 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1199 }
1200 else
1201 {
1202 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1203 reply.put(ERROR_FIELD,"404::Message deleted");
1204 }
1205 }
1206 else
1207 {
1208 message=null;
1209 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1210 reply.put(ERROR_FIELD,"403::Publish denied");
1211 }
1212
1213 sendMetaReply(client,reply,transport);
1214
1215 if (message!=null)
1216 _root.doDelivery(cid,client,message);
1217 }
1218 }
1219
1220
1221
1222 protected class MetaPublishHandler extends Handler
1223 {
1224 @Override
1225 ChannelId getMetaChannelId()
1226 {
1227 return null;
1228 }
1229
1230 @Override
1231 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1232 {
1233 String channel_id=message.getChannel();
1234
1235 if (client==null && !META_HANDSHAKE.equals(channel_id))
1236 {
1237
1238 return;
1239 }
1240
1241 if(_securityPolicy.canPublish(client,channel_id,message))
1242 {
1243 _root.doDelivery(getChannelId(channel_id),client,message);
1244 }
1245 }
1246 }
1247
1248
1249
1250 protected class SubscribeHandler extends Handler
1251 {
1252 @Override
1253 ChannelId getMetaChannelId()
1254 {
1255 return META_SUBSCRIBE_ID;
1256 }
1257
1258 @Override
1259 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1260 {
1261 if (client==null)
1262 {
1263 unknownClient(transport,META_SUBSCRIBE);
1264 return;
1265 }
1266
1267 String subscribe_id=(String)message.get(SUBSCRIPTION_FIELD);
1268
1269
1270 if (subscribe_id==null)
1271 {
1272 subscribe_id=Long.toString(getRandom(),36);
1273 while (getChannel(subscribe_id)!=null)
1274 subscribe_id=Long.toString(getRandom(),36);
1275 }
1276
1277 ChannelId cid=null;
1278 boolean can_subscribe=false;
1279
1280 if (subscribe_id.startsWith(Bayeux.SERVICE_SLASH))
1281 {
1282 can_subscribe=true;
1283 }
1284 else if (subscribe_id.startsWith(Bayeux.META_SLASH))
1285 {
1286 can_subscribe=false;
1287 }
1288 else
1289 {
1290 cid=getChannelId(subscribe_id);
1291 can_subscribe=_securityPolicy.canSubscribe(client,subscribe_id,message);
1292 }
1293
1294 Message reply=newMessage(message);
1295 reply.put(CHANNEL_FIELD,META_SUBSCRIBE);
1296 reply.put(SUBSCRIPTION_FIELD,subscribe_id);
1297
1298 if (can_subscribe)
1299 {
1300 if (cid!=null)
1301 {
1302 ChannelImpl channel=getChannel(cid);
1303 if (channel==null&&_securityPolicy.canCreate(client,subscribe_id,message))
1304 channel=(ChannelImpl)getChannel(subscribe_id, true);
1305
1306 if (channel!=null)
1307 channel.subscribe(client);
1308 else
1309 can_subscribe=false;
1310 }
1311
1312 if (can_subscribe)
1313 {
1314 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1315 }
1316 else
1317 {
1318 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1319 reply.put(ERROR_FIELD,"403::cannot create");
1320 }
1321 }
1322 else
1323 {
1324 reply.put(SUCCESSFUL_FIELD,Boolean.FALSE);
1325 reply.put(ERROR_FIELD,"403::cannot subscribe");
1326
1327 }
1328
1329 String id=message.getId();
1330 if (id!=null)
1331 reply.put(ID_FIELD,id);
1332
1333 sendMetaReply(client,reply,transport);
1334 }
1335 }
1336
1337
1338
1339 protected class UnsubscribeHandler extends Handler
1340 {
1341 @Override
1342 ChannelId getMetaChannelId()
1343 {
1344 return META_UNSUBSCRIBE_ID;
1345 }
1346
1347 @Override
1348 public void handle(ClientImpl client, Transport transport, Message message) throws IOException
1349 {
1350 if (client==null)
1351 {
1352 unknownClient(transport,META_UNSUBSCRIBE);
1353 return;
1354 }
1355
1356 String channel_id=(String)message.get(SUBSCRIPTION_FIELD);
1357 ChannelImpl channel=getChannel(channel_id);
1358 if (channel!=null)
1359 channel.unsubscribe(client);
1360
1361 Message reply=newMessage(message);
1362 reply.put(CHANNEL_FIELD,META_UNSUBSCRIBE);
1363 reply.put(SUBSCRIPTION_FIELD,channel_id);
1364 reply.put(SUCCESSFUL_FIELD,Boolean.TRUE);
1365
1366 String id=message.getId();
1367 if (id!=null)
1368 reply.put(ID_FIELD,id);
1369
1370 sendMetaReply(client,reply,transport);
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 sendMetaReply(client,reply,transport);
1396 }
1397 }
1398
1399
1400
1401
1402 protected class ServiceChannel extends ChannelImpl
1403 {
1404 ServiceChannel(String id)
1405 {
1406 super(id,AbstractBayeux.this);
1407 }
1408
1409
1410
1411
1412
1413 @Override
1414 public void addChild(ChannelImpl channel)
1415 {
1416 super.addChild(channel);
1417 setPersistent(true);
1418 }
1419
1420
1421 @Override
1422 public void subscribe(Client client)
1423 {
1424 if (client.isLocal())
1425 super.subscribe(client);
1426 }
1427
1428 }
1429 }