/**
  * @param snapshotDirectoryPath Path to a repository snapshot directory (eg, /a/path/1.0-SNAPSHOT)
  * @param buildNumber The file with build number to search for or 0 if doesn't matter
  * @param timestamp The file with timestamp to search for or null if doesn't matter
  * @param fileExtension The file type to search for. Use null for any type
  * @return The path of the first unique snapshot file with the input build number.
  */
 private String findSnapshotFile(
     RepoPath snapshotDirectoryPath, int buildNumber, String timestamp, String fileExtension) {
   log.debug(
       "Searching for unique snapshot file in {} with build number {} and timestamp {}",
       new Object[] {snapshotDirectoryPath, buildNumber, timestamp});
   RepositoryService repoService = ContextHelper.get().getRepositoryService();
   if (repoService.exists(snapshotDirectoryPath)) {
     List<String> children = repoService.getChildrenNames(snapshotDirectoryPath);
     for (String child : children) {
       if (MavenNaming.isUniqueSnapshotFileName(child)) {
         // now match against all the conditions
         boolean buildNumberMatches =
             buildNumber == 0
                 || buildNumber == MavenNaming.getUniqueSnapshotVersionBuildNumber(child);
         boolean timestampMatches =
             timestamp == null
                 || timestamp.equals(MavenNaming.getUniqueSnapshotVersionTimestamp(child));
         boolean typeMatches =
             fileExtension == null || fileExtension.equals(PathUtils.getExtension(child));
         if (buildNumberMatches && timestampMatches && typeMatches) {
           // passed all the search requirements...
           log.debug("Found unique snapshot: {}", child);
           return child;
         }
       }
     }
   }
   log.debug(
       "Unique snapshot file not found in {} for build number {}",
       snapshotDirectoryPath,
       buildNumber);
   return null;
 }
  @Override
  protected String adapt(MavenSnapshotVersionAdapterContext context) {
    String path = context.getRepoPath().getPath();

    String fileName = PathUtils.getFileName(path);
    if (MavenNaming.isUniqueSnapshotFileName(fileName)) {
      log.debug(
          "File '{}' has already a unique snapshot version. Returning the original path.",
          fileName);
      return path;
    }

    String pathBaseVersion = context.getModuleInfo().getBaseRevision();
    if (!fileName.contains(pathBaseVersion + "-" + MavenNaming.SNAPSHOT)) {
      log.debug(
          "File '{}' doesn't contain the non-unique snapshot version {}. "
              + "Returning the original path.",
          fileName,
          pathBaseVersion);
      return path;
    }

    // Replace 'SNAPSHOT' with version timestamp for unique snapshot repo
    return adjustNonUniqueSnapshotToUnique(context);
  }
 /**
  * @param snapshotDirectoryPath Path to a repository snapshot directory (eg, /a/path/1.0-SNAPSHOT)
  * @param buildNumber The file with build number to search for
  * @return The timestamp of the unique snapshot file with the input build number.
  */
 private String getSnapshotTimestamp(RepoPath snapshotDirectoryPath, int buildNumber) {
   String snapshotFile = findSnapshotFileByBuildNumber(snapshotDirectoryPath, buildNumber);
   if (snapshotFile != null) {
     int childBuildNumber = MavenNaming.getUniqueSnapshotVersionBuildNumber(snapshotFile);
     if (childBuildNumber == buildNumber) {
       String timestamp = MavenNaming.getUniqueSnapshotVersionTimestamp(snapshotFile);
       log.debug("Extracted timestamp {} from {}", timestamp, snapshotFile);
       return timestamp;
     }
   }
   log.debug(
       "Snapshot timestamp not found in {} for build number {}",
       snapshotDirectoryPath,
       buildNumber);
   return null;
 }
 private String adjustNonUniqueSnapshotToUnique(MavenSnapshotVersionAdapterContext context) {
   long timestamp = context.getTimestamp();
   if (timestamp > 0) {
     return adjustUsingClientTimestamp(context);
   } else if (MavenNaming.isChecksum(context.getRepoPath().getPath())) {
     return adjustChecksum(context);
   } else {
     return adjustUsingServerData(context);
   }
 }
  private String adjustUsingServerData(MavenSnapshotVersionAdapterContext context) {
    // Get the latest build number from the metadata
    RepoPath repoPath = context.getRepoPath();
    String filePath = repoPath.getPath();
    int metadataBuildNumber = getLastBuildNumber(repoPath);
    int nextBuildNumber = metadataBuildNumber + 1;

    RepoPath parentPath = repoPath.getParent();

    // determine if the next build number should be the one read from the metadata
    ModuleInfo moduleInfo = context.getModuleInfo();
    String classifier = moduleInfo.getClassifier();
    boolean isPomChecksum =
        MavenNaming.isChecksum(filePath) && MavenNaming.isPom(PathUtils.stripExtension(filePath));
    if (metadataBuildNumber > 0 && (StringUtils.isNotBlank(classifier) || isPomChecksum)) {
      // pom checksums and artifacts with classifier are always deployed after the pom (which
      // triggers the
      // maven-metadata.xml calculation) so use the metadata build number
      nextBuildNumber = metadataBuildNumber;
    }
    if (metadataBuildNumber > 0 && MavenNaming.isPom(filePath)) {
      // the metadata might already represent an existing main artifact (in case the
      // maven-metadata.xml was deployed after the main artifact and before the pom/classifier)
      // so first check if there's already a file with the next build number
      if (findSnapshotFileByBuildNumber(parentPath, metadataBuildNumber + 1) == null) {
        // no files deployed with the next build number so either this is a pom deployment (parent
        // pom)
        // or this is a pom of a main artifact for which the maven-metadata.xml was deployed before
        // this pom
        if (findSnapshotPomFile(parentPath, metadataBuildNumber) == null) {
          // this is a pom attached to a main artifact deployed after maven-metadata.xml
          nextBuildNumber = metadataBuildNumber;
        }
      }
    }

    String timestamp = getSnapshotTimestamp(parentPath, nextBuildNumber);
    if (timestamp == null) {
      // probably the first deployed file for this build, use now for the timestamp
      timestamp = MavenModelUtils.dateToUniqueSnapshotTimestamp(new Date());
    }
    return buildUniqueSnapshotFileName(nextBuildNumber, timestamp, moduleInfo);
  }
  private String adjustUsingClientTimestamp(MavenSnapshotVersionAdapterContext context) {
    // artifact was uploaded with a timestamp, we use it for the unique snapshot timestamp and to
    // locate build number
    long timestamp = context.getTimestamp();
    String uniqueTimestamp = MavenModelUtils.dateToUniqueSnapshotTimestamp(new Date(timestamp));
    RepoPath repoPath = context.getRepoPath();
    String existingArtifact = findSnapshotFileByTimestamp(repoPath.getParent(), uniqueTimestamp);
    int buildNumber;
    if (existingArtifact != null) {
      buildNumber = MavenNaming.getUniqueSnapshotVersionBuildNumber(existingArtifact);
    } else {
      buildNumber = getLastBuildNumber(repoPath) + 1;
    }

    return buildUniqueSnapshotFileName(buildNumber, uniqueTimestamp, context.getModuleInfo());
  }
  private String adjustChecksum(MavenSnapshotVersionAdapterContext context) {
    // find latest unique file matching the checksum coordinates
    RepositoryService repoService = ContextHelper.get().getRepositoryService();
    RepoPath repoPath = context.getRepoPath();
    RepoPath parentRepoPath = repoPath.getParent();
    RepoDescriptor repoDescriptor = repoService.repoDescriptorByKey(parentRepoPath.getRepoKey());
    RepoLayout repoLayout = repoDescriptor.getRepoLayout();

    String latestMatching = null;

    String originalChecksumRequestPath = repoPath.getPath();
    String originalRequestPathWithNoChecksum =
        PathUtils.stripExtension(originalChecksumRequestPath);

    if (repoService.exists(parentRepoPath)) {
      List<String> children = repoService.getChildrenNames(parentRepoPath);
      for (String child : children) {
        if (MavenNaming.isUniqueSnapshotFileName(child)) {

          ModuleInfo childModule =
              repoService.getItemModuleInfo(InternalRepoPathFactory.create(parentRepoPath, child));
          String fileRevisionIntegration = childModule.getFileIntegrationRevision();

          // Try to construct a new non-unique path as a descriptor
          String nonUniquePath =
              replaceIntegration(
                  ModuleInfoUtils.constructDescriptorPath(childModule, repoLayout, true),
                  fileRevisionIntegration);

          // If the path as a descriptor doesn't match, perhaps it's an artifact path
          if (!nonUniquePath.equals(originalRequestPathWithNoChecksum)) {
            // Try to construct a new non-unique path as an artifact
            nonUniquePath =
                replaceIntegration(
                    ModuleInfoUtils.constructArtifactPath(childModule, repoLayout),
                    fileRevisionIntegration);
          }

          if (nonUniquePath.equals(originalRequestPathWithNoChecksum)) {
            if (latestMatching == null
                || MavenNaming.getUniqueSnapshotVersionBuildNumber(latestMatching)
                    < MavenNaming.getUniqueSnapshotVersionBuildNumber(child)) {
              latestMatching = child;
            }
          }
        }
      }
    }

    // if latest not found, return invalid path which will fail and return a message to the client
    String timestamp =
        latestMatching != null
            ? MavenNaming.getUniqueSnapshotVersionTimestamp(latestMatching)
            : System.currentTimeMillis() + "";
    int buildNumber =
        latestMatching != null
            ? MavenNaming.getUniqueSnapshotVersionBuildNumber(latestMatching)
            : 0;

    // use the timestamp and build number from it. if not found return something that will fail?
    return buildUniqueSnapshotFileName(buildNumber, timestamp, context.getModuleInfo());
  }