@Override
  public synchronized void stop() throws Exception {
    if (!started) {
      return;
    }

    // Channel may be null if there isn't a connection to a live server
    if (channel != null) {
      channel.close();
    }

    for (ReplicatedLargeMessage largeMessage : largeMessages.values()) {
      largeMessage.releaseResources();
    }
    largeMessages.clear();

    for (Entry<JournalContent, Map<Long, JournalSyncFile>> entry :
        filesReservedForSync.entrySet()) {
      for (JournalSyncFile filesReserved : entry.getValue().values()) {
        filesReserved.close();
      }
    }

    filesReservedForSync.clear();
    if (journals != null) {
      for (Journal j : journals) {
        if (j instanceof FileWrapperJournal) j.stop();
      }
    }

    for (ConcurrentMap<Integer, Page> map : pageIndex.values()) {
      for (Page page : map.values()) {
        try {
          page.sync();
          page.close();
        } catch (Exception e) {
          ActiveMQServerLogger.LOGGER.errorClosingPageOnReplication(e);
        }
      }
    }
    pageManager.stop();

    pageIndex.clear();
    final CountDownLatch latch = new CountDownLatch(1);
    executor.execute(
        new Runnable() {

          @Override
          public void run() {
            latch.countDown();
          }
        });
    latch.await(30, TimeUnit.SECONDS);

    // Storage needs to be the last to stop
    storageManager.stop();

    started = false;
  }
  /**
   * Receives 'raw' journal/page/large-message data from live server for synchronization of logs.
   *
   * @param msg
   * @throws Exception
   */
  private synchronized void handleReplicationSynchronization(ReplicationSyncFileMessage msg)
      throws Exception {
    Long id = Long.valueOf(msg.getId());
    byte[] data = msg.getData();
    SequentialFile channel1;
    switch (msg.getFileType()) {
      case LARGE_MESSAGE:
        {
          ReplicatedLargeMessage largeMessage = lookupLargeMessage(id, false);
          if (!(largeMessage instanceof LargeServerMessageInSync)) {
            ActiveMQServerLogger.LOGGER.largeMessageIncompatible();
            return;
          }
          LargeServerMessageInSync largeMessageInSync = (LargeServerMessageInSync) largeMessage;
          channel1 = largeMessageInSync.getSyncFile();
          break;
        }
      case PAGE:
        {
          Page page = getPage(msg.getPageStore(), (int) msg.getId());
          channel1 = page.getFile();
          break;
        }
      case JOURNAL:
        {
          JournalSyncFile journalSyncFile =
              filesReservedForSync.get(msg.getJournalContent()).get(id);
          FileChannel channel2 = journalSyncFile.getChannel();
          if (data == null) {
            channel2.close();
            return;
          }
          channel2.write(ByteBuffer.wrap(data));
          return;
        }
      default:
        throw ActiveMQMessageBundle.BUNDLE.replicationUnhandledFileType(msg.getFileType());
    }

    if (data == null) {
      channel1.close();
      return;
    }

    if (!channel1.isOpen()) {
      channel1.open();
    }
    channel1.writeDirect(ByteBuffer.wrap(data), true);
  }