1 //========================================================================
2 // Copyright 2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //========================================================================
14
15 package org.mortbay.cometd.client.ext;
16
17 import java.util.Map;
18
19 import org.cometd.Bayeux;
20 import org.cometd.Client;
21 import org.cometd.Extension;
22 import org.cometd.Message;
23
24 /**
25 * AckExtension
26 *
27 * This client-side extension enables the client to acknowledge to the server
28 * the messages that the client has received.
29 * For the acknowledgement to work, the server must be configured with the
30 * correspondent server-side ack extension. If both client and server support
31 * the ack extension, then the ack functionality will take place automatically.
32 * By enabling this extension, all messages arriving from the server will arrive
33 * via the long poll, so the comet communication will be slightly chattier.
34 * The fact that all messages will return via long poll means also that the
35 * messages will arrive with total order, which is not guaranteed if messages
36 * can arrive via both long poll and normal response.
37 * Messages are not acknowledged one by one, but instead a group of messages is
38 * acknowledged when long poll returns.
39 *
40 * @author dyu
41 */
42
43 public class AckExtension implements Extension
44 {
45
46 public static final String EXT_FIELD = "ack";
47
48 private volatile boolean _serverSupportsAcks = false;
49 private volatile int _ackId = -1;
50
51 public AckExtension()
52 {
53
54 }
55
56 public Message send(Client from, Message message)
57 {
58 return message;
59 }
60
61 public Message rcv(Client from, Message message)
62 {
63 return message;
64 }
65
66 public Message sendMeta(Client from, Message message)
67 {
68 if(Bayeux.META_HANDSHAKE.equals(message.getChannel()))
69 {
70 message.getExt(true).put(EXT_FIELD, Boolean.TRUE);
71 _ackId = -1;
72 }
73 else if(_serverSupportsAcks && Bayeux.META_CONNECT.equals(message.getChannel()))
74 {
75 message.getExt(true).put(EXT_FIELD, _ackId);
76 }
77
78 return message;
79 }
80
81 public Message rcvMeta(Client from, Message message)
82 {
83 if(Bayeux.META_HANDSHAKE.equals(message.getChannel()))
84 {
85 Map<String,Object> ext = message.getExt(false);
86 _serverSupportsAcks = ext!=null && Boolean.TRUE.equals(ext.get(EXT_FIELD));
87 }
88 else if(_serverSupportsAcks && Boolean.TRUE.equals(message.get(Bayeux.SUCCESSFUL_FIELD))
89 && Bayeux.META_CONNECT.equals(message.getChannel()))
90 {
91 Map<String,Object> ext = message.getExt(false);
92 if(ext!=null)
93 {
94 Object ack = ext.get(EXT_FIELD);
95 if(ack instanceof Number)
96 _ackId = ((Number)ack).intValue();
97 }
98 }
99
100 return message;
101 }
102
103 }