public void prepareMsg() {
    while (true) {
      BatchMessage msgTuple = null;
      try {
        msgTuple = super.getBatchQueue().poll(1, TimeUnit.MILLISECONDS);
      } catch (InterruptedException e) {
        return;
      }
      if (msgTuple == null) {
        return;
      }

      if (msgTuple.getMsgList().size() == 0) {
        super.finish(msgTuple.getBatchId());
        return;
      }

      BatchMsgsTag partTag = new BatchMsgsTag();
      Set<String> msgIds = partTag.getMsgIds();
      for (MessageExt msg : msgTuple.getMsgList()) {
        String msgId = msg.getMsgId();
        msgIds.add(msgId);
        MessageCacheItem item =
            new MessageCacheItem(msgTuple.getBatchId(), msg, msgTuple.getMessageStat());
        msgCache.put(msgId, item);
        msgQueue.offer(item);
      }
      batchMsgsMap.put(msgTuple.getBatchId(), partTag);
    }
  }
  public void open(
      @SuppressWarnings("rawtypes") final Map conf,
      final TopologyContext context,
      final SpoutOutputCollector collector) {
    super.open(conf, context, collector);
    ExpiredCallback<String, MessageCacheItem> callback =
        new ExpiredCallback<String, MessageCacheItem>() {
          public void expire(String key, MessageCacheItem val) {
            LOG.warn("Long time no ack,key is {},value is {} !", key, val);
            msgCache.put(key, val);
            fail(key);
          }
        };
    msgCache = new RotatingMap<String, MessageCacheItem>(3600 * 5, callback);

    LOG.info(
        "Topology {} opened {} spout successfully !",
        new Object[] {topologyName, config.getTopic()});
  }
  public void finish(String msgId) {
    MessageCacheItem cacheItem = (MessageCacheItem) msgCache.remove(msgId);
    if (cacheItem == null) {
      LOG.warn("Failed to get from cache {} !", msgId);
      return;
    }

    UUID batchId = cacheItem.getId();
    BatchMsgsTag partTag = batchMsgsMap.get(batchId);
    if (partTag == null) {
      throw new RuntimeException("In partOffset map, no entry of " + batchId);
    }

    Set<String> msgIds = partTag.getMsgIds();

    msgIds.remove(msgId);

    if (msgIds.size() == 0) {
      batchMsgsMap.remove(batchId);
      super.finish(batchId);
    }
  }