/**
  * @throws IOException
  * @see org.apache.activemq.store.TransactionStore#rollback(TransactionId)
  */
 public void rollback(TransactionId txid) throws IOException {
   if (txid.isXATransaction() || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
     KahaTransactionInfo info = getTransactionInfo(txid);
     theStore.store(new KahaRollbackCommand().setTransactionInfo(info), false, null, null);
     forgetRecoveredAcks(txid);
   } else {
     inflightTransactions.remove(txid);
   }
 }
 /**
  * @throws IOException
  * @see org.apache.activemq.store.TransactionStore#prepare(TransactionId)
  */
 public void prepare(TransactionId txid) throws IOException {
   KahaTransactionInfo info = getTransactionInfo(txid);
   if (txid.isXATransaction() || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
     theStore.store(new KahaPrepareCommand().setTransactionInfo(info), true, null, null);
   } else {
     Tx tx = inflightTransactions.remove(txid);
     if (tx != null) {
       theStore.store(new KahaPrepareCommand().setTransactionInfo(info), true, null, null);
     }
   }
 }
  public void commit(
      TransactionId txid, boolean wasPrepared, Runnable preCommit, Runnable postCommit)
      throws IOException {
    if (txid != null) {
      if (!txid.isXATransaction() && theStore.isConcurrentStoreAndDispatchTransactions()) {
        if (preCommit != null) {
          preCommit.run();
        }
        Tx tx = inflightTransactions.remove(txid);
        if (tx != null) {
          List<Future<Object>> results = tx.commit();
          boolean doneSomething = false;
          for (Future<Object> result : results) {
            try {
              result.get();
            } catch (InterruptedException e) {
              theStore.brokerService.handleIOException(new IOException(e.getMessage()));
            } catch (ExecutionException e) {
              theStore.brokerService.handleIOException(new IOException(e.getMessage()));
            } catch (CancellationException e) {
            }
            if (!result.isCancelled()) {
              doneSomething = true;
            }
          }
          if (postCommit != null) {
            postCommit.run();
          }
          if (doneSomething) {
            KahaTransactionInfo info = getTransactionInfo(txid);
            theStore.store(new KahaCommitCommand().setTransactionInfo(info), true, null, null);
          }
        } else {
          // The Tx will be null for failed over clients - lets run their post commits
          if (postCommit != null) {
            postCommit.run();
          }
        }

      } else {
        KahaTransactionInfo info = getTransactionInfo(txid);
        theStore.store(
            new KahaCommitCommand().setTransactionInfo(info), true, preCommit, postCommit);
        forgetRecoveredAcks(txid);
      }
    } else {
      LOG.error("Null transaction passed on commit");
    }
  }
  public synchronized void recover(TransactionRecoveryListener listener) throws IOException {
    for (Map.Entry<TransactionId, List<Operation>> entry :
        theStore.preparedTransactions.entrySet()) {
      XATransactionId xid = (XATransactionId) entry.getKey();
      ArrayList<Message> messageList = new ArrayList<Message>();
      ArrayList<MessageAck> ackList = new ArrayList<MessageAck>();

      for (Operation op : entry.getValue()) {
        if (op.getClass() == AddOpperation.class) {
          AddOpperation addOp = (AddOpperation) op;
          Message msg =
              (Message)
                  wireFormat()
                      .unmarshal(new DataInputStream(addOp.getCommand().getMessage().newInput()));
          messageList.add(msg);
        } else {
          RemoveOpperation rmOp = (RemoveOpperation) op;
          Buffer ackb = rmOp.getCommand().getAck();
          MessageAck ack =
              (MessageAck) wireFormat().unmarshal(new DataInputStream(ackb.newInput()));
          ackList.add(ack);
        }
      }

      Message[] addedMessages = new Message[messageList.size()];
      MessageAck[] acks = new MessageAck[ackList.size()];
      messageList.toArray(addedMessages);
      ackList.toArray(acks);
      xid.setPreparedAcks(ackList);
      theStore.trackRecoveredAcks(ackList);
      listener.recover(xid, addedMessages, acks);
    }
  }
  final void removeAsyncMessage(
      ConnectionContext context, final MessageStore destination, final MessageAck ack)
      throws IOException {

    if (ack.isInTransaction()) {
      if (ack.getTransactionId().isXATransaction()
          || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
        destination.removeAsyncMessage(context, ack);
      } else {
        Tx tx = getTx(ack.getTransactionId());
        tx.add(
            new RemoveMessageCommand(context) {
              @Override
              public MessageAck getMessageAck() {
                return ack;
              }

              @Override
              public Future<Object> run(ConnectionContext ctx) throws IOException {
                destination.removeMessage(ctx, ack);
                return AbstractMessageStore.FUTURE;
              }
            });
      }
    } else {
      destination.removeAsyncMessage(context, ack);
    }
  }
  Future<Object> asyncAddTopicMessage(
      ConnectionContext context, final MessageStore destination, final Message message)
      throws IOException {

    if (message.getTransactionId() != null) {
      if (message.getTransactionId().isXATransaction()
          || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
        destination.addMessage(context, message);
        return AbstractMessageStore.FUTURE;
      } else {
        Tx tx = getTx(message.getTransactionId());
        tx.add(
            new AddMessageCommand(context) {
              @Override
              public Message getMessage() {
                return message;
              }

              @Override
              public Future<Object> run(ConnectionContext ctx) throws IOException {
                return destination.asyncAddTopicMessage(ctx, message);
              }
            });
        return AbstractMessageStore.FUTURE;
      }
    } else {
      return destination.asyncAddTopicMessage(context, message);
    }
  }
  final void acknowledge(
      ConnectionContext context,
      final TopicMessageStore destination,
      final String clientId,
      final String subscriptionName,
      final MessageId messageId,
      final MessageAck ack)
      throws IOException {

    if (ack.isInTransaction()) {
      if (ack.getTransactionId().isXATransaction()
          || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
        destination.acknowledge(context, clientId, subscriptionName, messageId, ack);
      } else {
        Tx tx = getTx(ack.getTransactionId());
        tx.add(
            new RemoveMessageCommand(context) {
              public MessageAck getMessageAck() {
                return ack;
              }

              public Future<Object> run(ConnectionContext ctx) throws IOException {
                destination.acknowledge(ctx, clientId, subscriptionName, messageId, ack);
                return AbstractMessageStore.FUTURE;
              }
            });
      }
    } else {
      destination.acknowledge(context, clientId, subscriptionName, messageId, ack);
    }
  }
 public boolean isEnableIndexPageCaching() {
   return letter.isEnableIndexPageCaching();
 }
 /** @param maxAsyncJobs the maxAsyncJobs to set */
 public void setMaxAsyncJobs(int maxAsyncJobs) {
   letter.setMaxAsyncJobs(maxAsyncJobs);
 }
 public boolean isEnableIndexRecoveryFile() {
   return letter.isEnableIndexRecoveryFile();
 }
 public void setEnableIndexPageCaching(boolean enable) {
   letter.setEnableIndexPageCaching(enable);
 }
 public boolean isEnableIndexDiskSyncs() {
   return letter.isEnableIndexDiskSyncs();
 }
 public void setEnableIndexRecoveryFile(boolean enable) {
   letter.setEnableIndexRecoveryFile(enable);
 }
 protected void forgetRecoveredAcks(TransactionId txid) throws IOException {
   if (txid.isXATransaction()) {
     XATransactionId xaTid = ((XATransactionId) txid);
     theStore.forgetRecoveredAcks(xaTid.getPreparedAcks());
   }
 }
 public void setForceRecoverIndex(boolean forceRecoverIndex) {
   letter.setForceRecoverIndex(forceRecoverIndex);
 }
 public void setIndexLFUEvictionFactor(float indexLFUEvictionFactor) {
   letter.setIndexLFUEvictionFactor(indexLFUEvictionFactor);
 }
 public int getMaxAsyncJobs() {
   return letter.getMaxAsyncJobs();
 }
 public float getIndexLFUEvictionFactor() {
   return letter.getIndexLFUEvictionFactor();
 }
 public boolean isRewriteOnRedelivery() {
   return letter.isRewriteOnRedelivery();
 }
 /**
  * When true, persist the redelivery status such that the message redelivery flag can survive a
  * broker failure used with
  * org.apache.activemq.ActiveMQConnectionFactory#setTransactedIndividualAck(boolean) true
  */
 public void setRewriteOnRedelivery(boolean rewriteOnRedelivery) {
   letter.setRewriteOnRedelivery(rewriteOnRedelivery);
 }
 public void setArchiveCorruptedIndex(boolean archiveCorruptedIndex) {
   letter.setArchiveCorruptedIndex(archiveCorruptedIndex);
 }
 public boolean isArchiveCorruptedIndex() {
   return letter.isArchiveCorruptedIndex();
 }
 public void setConcurrentStoreAndDispatchTopics(boolean concurrentStoreAndDispatch) {
   letter.setConcurrentStoreAndDispatchTopics(concurrentStoreAndDispatch);
 }
 public boolean isConcurrentStoreAndDispatchTopics() {
   return letter.isConcurrentStoreAndDispatchTopics();
 }
 public boolean isUseIndexLFRUEviction() {
   return letter.isUseIndexLFRUEviction();
 }
 public boolean getForceRecoverIndex() {
   return letter.getForceRecoverIndex();
 }
 public void setUseIndexLFRUEviction(boolean useIndexLFRUEviction) {
   letter.setUseIndexLFRUEviction(useIndexLFRUEviction);
 }
 public void setEnableIndexDiskSyncs(boolean diskSyncs) {
   letter.setEnableIndexDiskSyncs(diskSyncs);
 }
 private KahaTransactionInfo getTransactionInfo(TransactionId txid) {
   return TransactionIdConversion.convert(theStore.getTransactionIdTransformer().transform(txid));
 }
 public void setDirectoryArchive(File directoryArchive) {
   letter.setDirectoryArchive(directoryArchive);
 }