View Javadoc

    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 }