content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.camel.itest.springboot.util;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.nio.file.Files;
  import java.nio.file.attribute.BasicFileAttributes;
  import java.nio.file.attribute.FileTime;
  import java.util.Arrays;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.TreeMap;
  
  import org.apache.camel.itest.springboot.ITestConfig;
  import org.apache.commons.io.FileUtils;
  import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
  import org.eclipse.aether.DefaultRepositorySystemSession;
  import org.eclipse.aether.RepositorySystem;
  import org.eclipse.aether.artifact.Artifact;
  import org.eclipse.aether.artifact.DefaultArtifact;
  import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
  import org.eclipse.aether.deployment.DeployRequest;
  import org.eclipse.aether.graph.Dependency;
  import org.eclipse.aether.impl.DefaultServiceLocator;
  import org.eclipse.aether.repository.LocalRepository;
  import org.eclipse.aether.repository.RemoteRepository;
  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
  import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
  import org.eclipse.aether.spi.connector.transport.TransporterFactory;
  import org.eclipse.aether.transport.file.FileTransporterFactory;
  import org.eclipse.aether.transport.http.HttpTransporterFactory;
  
  import static org.apache.camel.itest.springboot.util.LocationUtils.camelRoot;
  
  public final class BOMResolver {
  
      private static final String LOCAL_REPO = "target/maven-aether-repo";
  
      private static final File CACHE_FILE = LocationUtils
              .camelRoot("tests/camel-itest-spring-boot/target/bom-versions-cache");
  
      private static BOMResolver instance;
  
      private ITestConfig config;
  
      private Map<String, String> versions;
  
      @SuppressWarnings("unchecked")
      private BOMResolver(ITestConfig config) {
          try {
              this.config = config;
              cleanupLocalRepo();
  
              if (canUseCache()) {
                  try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(CACHE_FILE))) {
                      this.versions = (Map<String, String>) in.readObject();
                  }
              } else {
                  retrieveUpstreamBOMVersions();
  
                  CACHE_FILE.delete();
                  try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(CACHE_FILE))) {
                      out.writeObject(versions);
                  }
              }
  
          } catch (Exception e) {
              throw new IllegalStateException("Cannot initialize the version resolver", e);
          }
  
      }
  
      private boolean canUseCache() throws IOException {
          if (CACHE_FILE.exists()) {
              BasicFileAttributes attr = Files.readAttributes(CACHE_FILE.toPath(), BasicFileAttributes.class);
              FileTime fileTime = attr != null ? attr.creationTime() : null;
              Long time = fileTime != null ? fileTime.toMillis() : null;
              // Update the cache every day
              return time != null && time.compareTo(System.currentTimeMillis() - 1000 * 60 * 60 * 24) > 0;
          }
  
          return false;
      }
  
      private void retrieveUpstreamBOMVersions() throws Exception {
          RepositorySystem system = newRepositorySystem();
          DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
          LocalRepository localRepo = new LocalRepository(LOCAL_REPO);
          session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
  
          String camelVersion = DependencyResolver.resolveCamelParentProperty("${project.version}");
  
          List<Artifact> neededArtifacts = new LinkedList<>();
          Artifact camelRoot = new DefaultArtifact("org.apache.camel:camel:pom:" + camelVersion)
                  .setFile(camelRoot("pom.xml"));
          neededArtifacts.add(camelRoot);
          Artifact camelParent = new DefaultArtifact("org.apache.camel:camel-parent:pom:" + camelVersion)
                  .setFile(camelRoot("parent/pom.xml"));
          neededArtifacts.add(camelParent);
          neededArtifacts.add(new DefaultArtifact("org.apache.camel.springboot:spring-boot:pom:" + camelVersion)
                  .setFile(camelRoot("platforms/spring-boot/pom.xml")));
          neededArtifacts.add(new DefaultArtifact("org.apache.camel.springboot:camel-spring-boot-dm:pom:" + camelVersion)
                  .setFile(camelRoot("platforms/spring-boot/spring-boot-dm/pom.xml")));
          neededArtifacts.add(new DefaultArtifact(
                  "org.apache.camel.springboot:camel-spring-boot-dependencies:pom:" + camelVersion).setFile(
                          camelRoot("platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml")));
          Artifact camelStarterParent = new DefaultArtifact(
                  "org.apache.camel.springboot:camel-starter-parent:pom:" + camelVersion)
                          .setFile(camelRoot("platforms/spring-boot/spring-boot-dm/camel-starter-parent/pom.xml"));
          neededArtifacts.add(camelStarterParent);
  
          RemoteRepository localRepoDist = new RemoteRepository.Builder("org.apache.camel.itest.springboot", "default",
                  new File(LOCAL_REPO).toURI().toString()).build();
  
          for (Artifact artifact : neededArtifacts) {
              DeployRequest deployRequest = new DeployRequest();
              deployRequest.addArtifact(artifact);
              deployRequest.setRepository(localRepoDist);
  
              system.deploy(session, deployRequest);
          }
  
          RemoteRepository mavenCentral = new RemoteRepository.Builder("central", "default",
                  "https://repo1.maven.org/maven2/").build();
          RemoteRepository apacheSnapshots = new RemoteRepository.Builder("apache-snapshots", "default",
                  "http://repository.apache.org/snapshots/").build();
          RemoteRepository springMilestones = new RemoteRepository.Builder("spring-milestones", "default",
                  "https://repo.spring.io/libs-milestone/").build();
  
          this.versions = new TreeMap<>();
  
          ArtifactDescriptorRequest springBootParentReq = new ArtifactDescriptorRequest(camelStarterParent,
                  Arrays.asList(localRepoDist, mavenCentral, apacheSnapshots, springMilestones), null);
          ArtifactDescriptorResult springBootParentRes = system.readArtifactDescriptor(session, springBootParentReq);
          for (Dependency dependency : springBootParentRes.getManagedDependencies()) {
              Artifact a = dependency.getArtifact();
              String key = a.getGroupId() + ":" + a.getArtifactId();
              versions.put(key, dependency.getArtifact().getVersion());
          }
  
          Artifact springBootDependencies = new DefaultArtifact(
                  "org.springframework.boot:spring-boot-dependencies:pom:" + config.getSpringBootVersion());
          ArtifactDescriptorRequest springBootDependenciesReq = new ArtifactDescriptorRequest(springBootDependencies,
                  Arrays.asList(localRepoDist, mavenCentral, apacheSnapshots, springMilestones), null);
          ArtifactDescriptorResult springBootDependenciesRes = system.readArtifactDescriptor(session,
                  springBootDependenciesReq);
          for (Dependency dependency : springBootDependenciesRes.getManagedDependencies()) {
              Artifact a = dependency.getArtifact();
              String key = a.getGroupId() + ":" + a.getArtifactId();
              versions.put(key, dependency.getArtifact().getVersion());
          }
      }
  
      public static BOMResolver getInstance(ITestConfig config) {
          if (instance == null) {
              instance = new BOMResolver(config);
          }
          return instance;
      }
  
      public String getBOMVersion(String groupId, String artifactId) {
          return versions.get(groupId + ":" + artifactId);
      }
  
      private void cleanupLocalRepo() throws IOException {
          File f = new File(LOCAL_REPO);
          if (f.exists()) {
              FileUtils.deleteDirectory(f);
          }
      }
  
      private RepositorySystem newRepositorySystem() {
          DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
          locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
          locator.addService(TransporterFactory.class, FileTransporterFactory.class);
          locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
          RepositorySystem system = locator.getService(RepositorySystem.class);
          return system;
      }
  
  }
  