protected String getNextAccountToRetrieve() {
    try {
      if (accountsToRetrieve == null) {
        logInfo("Getting list of accounts");
        NetworkResponse response = gateway.listAccountsForMirroring(getSecurity());
        String resultCode = response.getResultCode();
        if (resultCode.equals(NetworkInterfaceConstants.OK)) {
          accountsToRetrieve = new Vector(response.getResultVector());
          logNotice("Account count:" + accountsToRetrieve.size());
        } else {
          logError("error returned by " + ip + ": " + resultCode);
        }
      }

      if (accountsToRetrieve == null || accountsToRetrieve.size() == 0) {
        accountsToRetrieve = null;
        return null;
      }

      return (String) accountsToRetrieve.remove(0);
    } catch (Exception e) {
      logError("getNextAccountToRetrieve: ", e);
      return null;
    }
  }
  public boolean doWeWantThis(BulletinMirroringInformation mirroringInfo) {
    // TODO handle delete requests when we are propagating deletes,
    DatabaseKey key = getDatabaseKey(mirroringInfo);
    if (store.isHidden(key)) return false;

    UniversalId uid = mirroringInfo.getUid();
    DatabaseKey sealedKey = DatabaseKey.createSealedKey(uid);
    if (store.doesBulletinRevisionExist(sealedKey)) return false;

    try {
      if (mirroringInfo.isSealed()) return (!store.doesBulletinRevisionExist(key));

      if (store.doesBulletinDelRecordExist(DeleteRequestRecord.getDelKey(uid))) {
        DeleteRequestRecord delRecord =
            new DeleteRequestRecord(store.getDatabase(), uid, store.getSignatureVerifier());
        if (delRecord.isBefore(mirroringInfo.mTime)) return true;
        return false;
      }

      if (!store.doesBulletinRevisionExist(key)) return true;

      long currentBulletinsmTime = store.getDatabase().getmTime(key);
      if (mirroringInfo.getmTime() > currentBulletinsmTime) return true;
      return false;
    } catch (Exception e) {
      logError(e.getMessage(), e);
    }
    return false;
  }
  protected BulletinMirroringInformation getNextItemToRetrieve() {
    try {
      while (itemsToRetrieve.size() == 0) {
        String nextAccountId = getNextAccountToRetrieve();
        if (nextAccountId == null) return null;

        int totalIdsReturned = 0;
        String mirroringCallUsed = "listAvailableIdsForMirroring";
        NetworkResponse response =
            gateway.listAvailableIdsForMirroring(getSecurity(), nextAccountId);
        if (networkResponseOk(response)) {
          Vector listwithBulletinMirroringInfo = response.getResultVector();
          totalIdsReturned = listwithBulletinMirroringInfo.size();
          itemsToRetrieve =
              listOnlyPacketsThatWeWantUsingBulletinMirroringInformation(
                  nextAccountId, listwithBulletinMirroringInfo);
        } else {
          mirroringCallUsed = "OLD MIRRORING CALL(listBulletinsForMirroring)";
          response = gateway.listBulletinsForMirroring(getSecurity(), nextAccountId);
          if (networkResponseOk(response)) {
            Vector listWithLocalIds = response.getResultVector();
            totalIdsReturned = listWithLocalIds.size();
            itemsToRetrieve =
                listOnlyPacketsThatWeWantUsingLocalIds(nextAccountId, listWithLocalIds);
          }
        }

        if (networkResponseOk(response)) {
          String publicCode = MartusCrypto.getFormattedPublicCode(nextAccountId);
          if (totalIdsReturned > 0 || itemsToRetrieve.size() > 0)
            logInfo(
                mirroringCallUsed
                    + ": "
                    + publicCode
                    + " -> "
                    + totalIdsReturned
                    + " -> "
                    + itemsToRetrieve.size());
        } else {
          logWarning(
              "MirroringRetriever.getNextItemToRetrieve: Returned NetworkResponse: "
                  + response.getResultCode());
        }
      }

      if (itemsToRetrieve.size() == 0) return null;

      return (BulletinMirroringInformation) itemsToRetrieve.remove(0);

    } catch (Exception e) {
      logError("MirroringRetriever.getNextUidToRetrieve: ", e);
      MartusLogger.logException(e);
      return null;
    }
  }
  public void processNextBulletin() {
    if (isSleeping()) return;

    BulletinMirroringInformation item = getNextItemToRetrieve();
    if (item == null) {
      scheduleSleep();
      return;
    }

    // TODO handle delete requests when we are propagating deletes.

    try {
      UniversalId uid = item.getUid();
      String publicCode = MartusCrypto.getFormattedPublicCode(uid.getAccountId());
      logNotice("Getting bulletin: " + publicCode + "->" + uid.getLocalId());
      String bur = retrieveBurFromMirror(uid);
      File zip = File.createTempFile("$$$MirroringRetriever", null);
      try {
        zip.deleteOnExit();
        retrieveOneBulletin(zip, uid);
        long zipSize = zip.length();
        long mTime = item.getmTime();
        BulletinHeaderPacket bhp = store.saveZipFileToDatabase(zip, uid.getAccountId(), mTime);
        store.writeBur(bhp, bur);
        store.deleteDel(bhp.getUniversalId());
        logNotice(
            "Stored bulletin:  " + publicCode + "->" + uid.getLocalId() + " Size: " + zipSize);
      } finally {
        zip.delete();
      }
    } catch (ServerErrorException e) {
      logError("Supplier server:", e);
    } catch (ServerNotAvailableException e) {
      // TODO: Notify once per hour that something is wrong
    } catch (Exception e) {
      logError(e);
    }
  }
  protected void retrieveOneBulletin(File destFile, UniversalId uid) throws Exception {
    FileOutputStream out = new FileOutputStream(destFile);

    int chunkSize = MIRRORING_MAX_CHUNK_SIZE;
    ProgressMeterInterface nullProgressMeter = null;
    int totalLength =
        BulletinZipUtilities.retrieveBulletinZipToStream(
            uid, out, chunkSize, gateway, getSecurity(), nullProgressMeter);

    out.close();

    if (destFile.length() != totalLength) {
      logError("file=" + destFile.length() + ", returned=" + totalLength);
      throw new ServerErrorException("totalSize didn't match data length");
    }
  }
 public void logError(String message, Exception e) {
   logError(message);
   logError(e);
 }
 public void logError(Exception e) {
   logError(LoggerUtil.getStackTrace(e));
 }