code: /**
   * This file is part of Eclipse Steady.
   *
   * Licensed 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.
   *
   * SPDX-License-Identifier: Apache-2.0
   * SPDX-FileCopyrightText: Copyright (c) 2018-2020 SAP SE or an SAP affiliate company and Eclipse Steady contributors
   */
  package org.eclipse.steady.cia.util;
  
  import java.io.BufferedInputStream;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.util.TreeSet;
  import java.util.jar.JarFile;
  import java.util.HashSet;
  import java.util.ServiceLoader;
  import java.util.Set;
  
  import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
  import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
  import org.apache.commons.lang.NotImplementedException;
  import org.eclipse.steady.shared.connectivity.ServiceConnectionException;
  import org.eclipse.steady.shared.enums.ProgrammingLanguage;
  import org.eclipse.steady.shared.json.model.Artifact;
  import org.eclipse.steady.shared.json.model.LibraryId;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * <p>RepositoryDispatcher class.</p>
   */
  public class RepositoryDispatcher implements RepositoryWrapper {
  
    private static Logger log = LoggerFactory.getLogger(RepositoryDispatcher.class);
  
    /** {@inheritDoc} */
    @Override
    public Set<ProgrammingLanguage> getSupportedLanguages() {
      final Set<ProgrammingLanguage> l = new HashSet<ProgrammingLanguage>();
      final ServiceLoader<RepositoryWrapper> loader = ServiceLoader.load(RepositoryWrapper.class);
      for (RepositoryWrapper dv : loader) {
        l.addAll(dv.getSupportedLanguages());
      }
      return l;
    }
  
    /** {@inheritDoc} */
    @Override
    public Set<Artifact> getAllArtifactVersions(
        String group, String artifact, String classifier, String packaging) throws Exception {
  
      Set<Artifact> result = new TreeSet<Artifact>();
      Set<LibraryId> lids = new TreeSet<LibraryId>();
      final ServiceLoader<RepositoryWrapper> loader = ServiceLoader.load(RepositoryWrapper.class);
      Set<Artifact> partial_result = null;
      for (RepositoryWrapper dv : loader) {
        if (dv.isConfigured()) {
          try {
            partial_result = dv.getAllArtifactVersions(group, artifact, classifier, packaging);
            if (partial_result != null && !partial_result.isEmpty()) {
              for (Artifact a : partial_result) {
                if (!lids.contains(a.getLibId())) {
                  result.add(a);
                  lids.add(a.getLibId());
                }
              }
            }
          } catch (NotImplementedException e) {
  
          } catch (UnsupportedOperationException e) {
          }
        }
      }
      return result;
    }
  
    /** {@inheritDoc} */
    @Override
    public Set<Artifact> getGreaterArtifactVersions(
        String group, String artifact, String greaterThanVersion, String classifier, String packaging)
        throws Exception {
      Set<Artifact> result = null;
      final ServiceLoader<RepositoryWrapper> loader = ServiceLoader.load(RepositoryWrapper.class);
      for (RepositoryWrapper dv : loader) {
        if (dv.isConfigured()) {
          try {
            result =
                dv.getGreaterArtifactVersions(
                    group, artifact, greaterThanVersion, classifier, packaging);
            if (result != null && !result.isEmpty()) break;
          } catch (NotImplementedException e) {
  
          } catch (UnsupportedOperationException e) {
          } catch (ServiceConnectionException e) {
            log.error("Invoked service was unavailable: " + e.getMessage());
          }
        }
      }
      return result;
    }
  
    /** {@inheritDoc} */
    @Override
    public Artifact getLatestArtifactVersion(
        String group, String artifact, String classifier, String packaging) throws Exception {
      Artifact result = null;
      final ServiceLoader<RepositoryWrapper> loader = ServiceLoader.load(RepositoryWrapper.class);
  
      for (RepositoryWrapper dv : loader) {
        if (dv.isConfigured()) {
          try {
            result = dv.getLatestArtifactVersion(group, artifact, classifier, packaging);
            if (result != null) break;
          } catch (NotImplementedException e) {
  
          } catch (UnsupportedOperationException e) {
          }
        }
      }
      return result;
    }
  
    /** {@inheritDoc} */
    @Override
    public Artifact getArtifactVersion(
        String group,
        String artifact,
        String version,
        String classifier,
        String packaging,
        ProgrammingLanguage lang)
        throws Exception {
      Artifact result = null;
      final ServiceLoader<RepositoryWrapper> loader = ServiceLoader.load(RepositoryWrapper.class);
      for (RepositoryWrapper dv : loader) {
        if (dv.isConfigured()
            && (lang == null
                || lang.toString().equals("")
                || dv.getSupportedLanguages().contains(lang))) {
          try {
            result = dv.getArtifactVersion(group, artifact, version, classifier, packaging, null);
            if (result != null) break;
          } catch (NotImplementedException e) {
  
          } catch (UnsupportedOperationException e) {
          }
        }
      }
      return result;
    }
  
    /** {@inheritDoc} */
    @Override
    public Path downloadArtifact(Artifact a) throws Exception {
      Path p = null;
  
      if (!a.isReadyForDownload())
        throw new IllegalArgumentException("Artifact not fully specified: " + a);
  
      // Already downloaded?
      if (a.isCached()) {
        log.debug(a.toString() + " available in local m2 repo: [" + a.getAbsM2Path() + "]");
        p = a.getAbsM2Path();
  
        try {
          if (a.getProgrammingLanguage() == ProgrammingLanguage.JAVA) {
            JarFile j = new JarFile(p.toFile(), false, java.util.zip.ZipFile.OPEN_READ);
            j.close();
          } else if (a.getProgrammingLanguage() == ProgrammingLanguage.PY
              && a.getPackaging().equals("sdist")) {
            TarArchiveInputStream t =
                new TarArchiveInputStream(
                    new GzipCompressorInputStream(
                        new BufferedInputStream(new FileInputStream(p.toFile()))));
            t.getNextTarEntry();
            t.close();
          }
        } catch (Exception e) {
          e.printStackTrace();
          log.error("Exception when opening archive file [" + p.toFile() + "]: " + e.getMessage());
          boolean deleted = p.toFile().delete();
          if (!deleted) log.warn("Couldn't delete presumibly corrupted archive [" + p + "]");
          p = this.downloadArtifactFile(a);
        }
      }
      // No, download!
      else {
        p = this.downloadArtifactFile(a);
      }
      return p;
    }
  
    private Path downloadArtifactFile(Artifact a) throws Exception {
      Path p = null;
      // Create the dir
      Path artifact_dir = a.getAbsM2Path().getParent();
      if (!artifact_dir.toFile().exists()) Files.createDirectories(artifact_dir);
  
      final ServiceLoader<RepositoryWrapper> loader = ServiceLoader.load(RepositoryWrapper.class);
      for (RepositoryWrapper dv : loader) {
        if (dv.isConfigured() && (dv.getSupportedLanguages().contains(a.getProgrammingLanguage()))) {
          try {
            p = dv.downloadArtifact(a);
            if (p != null) break;
          } catch (NotImplementedException e) {
  
          } catch (UnsupportedOperationException e) {
          }
        }
      }
      if (p == null) throw new FileNotFoundException();
  
      return p;
    }
  
    /** {@inheritDoc} */
    @Override
    public Artifact getArtifactForDigest(String digest) throws RepoException, InterruptedException {
      Artifact result = null;
      final ServiceLoader<RepositoryWrapper> loader = ServiceLoader.load(RepositoryWrapper.class);
      for (RepositoryWrapper dv : loader) {
        if (dv.isConfigured()) {
          try {
            result = dv.getArtifactForDigest(digest);
            if (result != null) break;
          } catch (NotImplementedException e) {
  
          } catch (UnsupportedOperationException e) {
          }
        }
      }
      return result;
    }
  
    // this method should never be called
    /** {@inheritDoc} */
    @Override
    public boolean isConfigured() {
      return false;
    }
  }
  