code: @VisibleForTesting
    File downloadProjectIfNotExists(final ProjectDirectoryMetadata proj, final int execId)
        throws IOException {
      final String projectDir = generateProjectDirName(proj);
      if (proj.getInstalledDir() == null) {
        proj.setInstalledDir(new File(this.projectCacheDir, projectDir));
      }
  
      // If directory exists, assume it's prepared and skip.
      if (proj.getInstalledDir().exists()) {
        log.info("Project {} already cached. Skipping download. ExecId: {}", proj, execId);
        // Hit the local cache.
        this.projectCacheHitRatio.markHit();
        // Update last modified time of the file keeping project dir size when the project is
        // accessed. This last modified time will be used to determined least recently used
        // projects when performing project directory clean-up.
        updateLastModifiedTime(
            Paths.get(proj.getInstalledDir().getPath(), PROJECT_DIR_SIZE_FILE_NAME));
        return null;
      }
  
      this.projectCacheHitRatio.markMiss();
  
      final long start = System.currentTimeMillis();
  
      // Download project to a temp dir if not exists in local cache.
      final File tempDir = createTempDir(proj);
      downloadAndUnzipProject(proj, tempDir);
  
      log.info("Downloading zip file for project {} when preparing execution [execid {}] "
              + "completed in {} second(s)", proj, execId,
          (System.currentTimeMillis() - start) / 1000);
  
      return tempDir;
    }
docs: Download project zip and unzip it if not exists locally.
  
  @param proj project to download
  @return the temp dir where the new project is downloaded to, null if no project is downloaded.
  @throws IOException if downloading or unzipping fails.