Package aQute.bnd.deployer.repository.aether

Source Code of aQute.bnd.deployer.repository.aether.AetherRepository$ResultHolder

package aQute.bnd.deployer.repository.aether;

import static aQute.bnd.deployer.repository.RepoConstants.*;

import java.io.*;
import java.net.*;
import java.security.*;
import java.util.*;

import org.apache.maven.repository.internal.*;
import org.eclipse.aether.*;
import org.eclipse.aether.artifact.*;
import org.eclipse.aether.connector.basic.*;
import org.eclipse.aether.deployment.*;
import org.eclipse.aether.impl.*;
import org.eclipse.aether.impl.DefaultServiceLocator.ErrorHandler;
import org.eclipse.aether.repository.*;
import org.eclipse.aether.repository.RemoteRepository.Builder;
import org.eclipse.aether.resolution.*;
import org.eclipse.aether.spi.connector.*;
import org.eclipse.aether.spi.connector.transport.*;
import org.eclipse.aether.transfer.*;
import org.eclipse.aether.transfer.TransferEvent.RequestType;
import org.eclipse.aether.transport.file.*;
import org.eclipse.aether.transport.http.*;
import org.eclipse.aether.util.repository.*;

import aQute.bnd.deployer.repository.*;
import aQute.bnd.osgi.*;
import aQute.bnd.service.*;
import aQute.bnd.version.*;
import aQute.lib.io.*;
import aQute.service.reporter.*;

@aQute.bnd.annotation.plugin.BndPlugin(name="aether", parameters=AetherRepository.Config.class)
public class AetherRepository implements Plugin, RegistryPlugin, RepositoryPlugin, IndexProvider {

  interface Config {
    String name();
    URI url();
    URI indexUrl();
    String username();
    String password();
    String cache();
  }
  public static final String PROP_NAME = "name";
  public static final String PROP_MAIN_URL = "url";
  public static final String PROP_INDEX_URL = "indexUrl";
  public static final String PROP_USERNAME = "username";
  public static final String PROP_PASSWORD = "password";
  public static final String PROP_CACHE = "cache";

  private static final String  META_OBR  = ".meta/obr.xml";

  Reporter reporter;
  private Registry registry;
 
  // Config Properties
  private String name = this.getClass().getSimpleName();
  private URI mainUri;
  private URI indexUri;
  private File cacheDir = new File(System.getProperty("user.home")+ File.separator + DEFAULT_CACHE_DIR);
  private String username = null;
  private String password = "";

  // Initialisation Fields
  private boolean initialised;
  private RepositorySystem repoSystem;
  private RemoteRepository remoteRepo;
  private LocalRepository localRepo;
  private FixedIndexedRepo indexedRepo;

  @Override
  public void setReporter(Reporter reporter) {
    this.reporter = reporter;
  }
 
  @Override
  public void setRegistry(Registry registry) {
    this.registry = registry;
  }
 
  @Override
  public void setProperties(Map<String, String> props) throws Exception {
    // Read name property
    if (props.containsKey(PROP_NAME))
      name = props.get(PROP_NAME);

    // Read main Nexus URL property
    String mainUrlStr = props.get(PROP_MAIN_URL);
    if (mainUrlStr == null)
      throw new IllegalArgumentException(String.format("Attribute '%s' must be set on '%s' plugin.", PROP_MAIN_URL, getClass().getName()));
    try {
      if (mainUrlStr.endsWith("/"))
        mainUrlStr = mainUrlStr.substring(0, mainUrlStr.length() - 1);
      mainUri = new URI(mainUrlStr);
    } catch (URISyntaxException e) {
      throw new IllegalArgumentException(String.format("Invalid '%s' property in plugin %s", PROP_MAIN_URL), e);
    }

    // Read index URL property if present
    String indexUriStr = props.get(PROP_INDEX_URL);
    if (indexUriStr == null) {
      indexUri = findDefaultVirtualIndexUri(mainUri);
    } else {
      try {
        indexUri = new URI(indexUriStr);
      } catch (URISyntaxException e) {
        throw new IllegalArgumentException(String.format("Invalid '%s' property in plugin %s", PROP_INDEX_URL), e);
      }
    }

    // Read username and password
    if (props.containsKey(PROP_USERNAME))
      username = props.get(PROP_USERNAME);
    if (props.containsKey(PROP_PASSWORD))
      password = props.get(PROP_PASSWORD);

    // Read cache path property
    String cachePath = props.get(PROP_CACHE);
    if (cachePath != null) {
      cacheDir = new File(cachePath);
      if (!cacheDir.isDirectory()) {
        String canonicalPath;
        try {
          canonicalPath = cacheDir.getCanonicalPath();
        } catch (IOException e) {
          throw new IllegalArgumentException(String.format("Could not canonical path for cacheDir '%s'.", cachePath), e);
        }
        throw new IllegalArgumentException(String.format("Cache path '%s' does not exist, or is not a directory", canonicalPath));
      }
    }
  }
 
  protected final synchronized void init() throws Exception {
    if (initialised)
      return;

    // Initialise Aether
    DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
    locator.addService(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class);
    locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
    locator.addService(TransporterFactory.class, FileTransporterFactory.class);
    locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
    locator.setErrorHandler(new ErrorHandler() {
      @Override
      public void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable exception) {
        if (reporter != null)
          reporter.error("Service creation failed for type %s using impl %s: %s", type, impl, exception.getLocalizedMessage());
        exception.printStackTrace();
      }
    });
    repoSystem = locator.getService(RepositorySystem.class);
    if (repoSystem == null)
      throw new IllegalArgumentException("Failed to initialise Aether repository system");
   
    Builder builder = new RemoteRepository.Builder("remote", "default", mainUri.toString());
    if (username != null) {
      AuthenticationBuilder authBuilder = new AuthenticationBuilder().addUsername(username);
      if (password != null)
        authBuilder.addPassword(password);
      builder.setAuthentication(authBuilder.build());
    }
    remoteRepo = builder.build();
    localRepo = new LocalRepository(new File(cacheDir, "aether-local"));
   
    // Initialise Index
    if (indexUri == null) {
      indexedRepo = null;
    } else {
      // Test whether the index URI exists and is available.
      HttpURLConnection connection = (HttpURLConnection) indexUri.toURL().openConnection();
      try {
        connection.setRequestMethod("HEAD");
        int responseCode = connection.getResponseCode();
        if (responseCode >= 400) {
          indexedRepo = null;
        } else {
          indexedRepo = new FixedIndexedRepo();
          Map<String, String> config = new HashMap<String, String>();
          indexedRepo.setReporter(this.reporter);
          indexedRepo.setRegistry(registry);
         
          config.put(FixedIndexedRepo.PROP_CACHE, cacheDir.getAbsolutePath());
          config.put(FixedIndexedRepo.PROP_LOCATIONS, indexUri.toString());
          indexedRepo.setProperties(config);
        }
      }
      catch (UnknownHostException e) {
        return;
      }
      finally {
        connection.disconnect();
      }
    }

    initialised = true;
  }
 
  @Override
  public PutResult put(InputStream stream, PutOptions options) throws Exception {
    init();

    DigestInputStream digestStream = new DigestInputStream(stream, MessageDigest.getInstance("SHA-1"));
    final File tmpFile = IO.createTempFile(cacheDir, "put", ".bnd");
    try {
      IO.copy(digestStream, tmpFile);
      byte[] digest = digestStream.getMessageDigest().digest();
     
      if (options.digest != null && !Arrays.equals(options.digest, digest))
        throw new IOException("Retrieved artifact digest doesn't match specified digest");
     
      // Get basic info about the bundle we're deploying
      Jar jar = new Jar(tmpFile);
      Artifact artifact = ConversionUtils.fromBundleJar(jar);
      artifact.setFile(tmpFile);
 
      // Setup the Aether repo session and create the deployment request
      DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
      session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(session, localRepo));
      final DeployRequest request = new DeployRequest();
      request.addArtifact(artifact);
      request.setRepository(remoteRepo);
     
      // Capture the result including remote resource URI
      final ResultHolder resultHolder = new ResultHolder();
      session.setTransferListener(new AbstractTransferListener() {
        @Override
        public void transferSucceeded(TransferEvent event) {
          TransferResource resource = event.getResource();
          if (event.getRequestType() == RequestType.PUT && tmpFile.equals(resource.getFile())) {
            PutResult result = new PutResult();
            result.artifact = URI.create(resource.getRepositoryUrl() + resource.getResourceName());
            resultHolder.result = result;
            System.out.println("UPLOADED to: " + URI.create(resource.getRepositoryUrl() + resource.getResourceName()));
          }
        }
        @Override
        public void transferFailed(TransferEvent event) {
          if (event.getRequestType() == RequestType.PUT && tmpFile.equals(event.getResource().getFile()))
            resultHolder.error = event.getException();
        }
        @Override
        public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
          if (event.getRequestType() == RequestType.PUT && tmpFile.equals(event.getResource().getFile()))
            resultHolder.error = event.getException();
        }
      });
     
      // Do the deploy and report results
      repoSystem.deploy(session, request);

      if (resultHolder.result != null) {
        if (indexedRepo != null)
          indexedRepo.reset();

        return resultHolder.result;
      } else if (resultHolder.error != null) {
        throw new Exception("Error during artifact upload", resultHolder.error);
      } else {
        throw new Exception("Artifact was not uploaded");
      }
    } finally {
      if (tmpFile != null && tmpFile.isFile())
        IO.delete(tmpFile);
    }
  }

  @Override
  public List<String> list(String pattern) throws Exception {
    init();

    // only supported with a valid index
    return indexedRepo != null ? indexedRepo.list(pattern) : null;
  }
 
  @Override
  public SortedSet<Version> versions(String bsn) throws Exception {
    init();

    // Use the index by preference
    if (indexedRepo != null)
      return indexedRepo.versions(ConversionUtils.maybeMavenCoordsToBsn(bsn));

    Artifact artifact = null;

    try {
      artifact = new DefaultArtifact(bsn + ":[0,)");
    }
    catch (Exception e) {
      // ignore non-GAV style dependencies
    }

    if (artifact == null)
      return null;

    // Setup the Aether repo session and create the range request
    DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
    session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(session, localRepo));

    VersionRangeRequest rangeRequest = new VersionRangeRequest();
    rangeRequest.setArtifact(artifact);
    rangeRequest.setRepositories(Collections.singletonList(remoteRepo));
   
    // Resolve the range
    VersionRangeResult rangeResult = repoSystem.resolveVersionRange(session, rangeRequest);
   
    // Add to the result
    SortedSet<Version> versions = new TreeSet<Version>();
    for (org.eclipse.aether.version.Version version : rangeResult.getVersions()) {
      MvnVersion parsed = MvnVersion.parseString(version.toString());

      if (parsed != null)
        versions.add(parsed.getOSGiVersion());
    }
    return versions;
  }
 
  @Override
  public File get(String bsn, Version version, Map<String, String> properties, DownloadListener... listeners) throws Exception {
    init();
   
    // Use the index by preference
    if (indexedRepo != null)
      return indexedRepo.get(ConversionUtils.maybeMavenCoordsToBsn(bsn), version, properties, listeners);
   
    File file = null;
    boolean getSource = false;
    try {
      // Setup the Aether repo session and request
      DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
      session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(session, localRepo));

      if (bsn.endsWith(".source")) {
        String originalBsn = properties.get("bsn");

        if (originalBsn != null) {
          bsn = originalBsn;
          getSource = true;
        }
      }

      String[] coords = ConversionUtils.getGroupAndArtifactForBsn(bsn);

      MvnVersion mvnVersion = new MvnVersion(version);

      String versionStr = null;

      if ("exact".equals(properties.get("strategy")) || getSource) {
        versionStr = properties.get("version");
      }
      else {
        versionStr = mvnVersion.toString();
      }

      Artifact artifact = null;

      if (getSource) {
        artifact = new DefaultArtifact(coords[0], coords[1], "sources", "jar", versionStr);
      }
      else {
        artifact = new DefaultArtifact(coords[0], coords[1], "jar", versionStr);
      }

      ArtifactRequest request = new ArtifactRequest();
      request.setArtifact(artifact);
      request.setRepositories(Collections.singletonList(remoteRepo));

      // Log the transfer
      session.setTransferListener(new AbstractTransferListener() {
        @Override
        public void transferStarted(TransferEvent event) throws TransferCancelledException {
          System.err.println(event);
        }
        @Override
        public void transferSucceeded(TransferEvent event) {
          System.err.println(event);
        }
        @Override
        public void transferFailed(TransferEvent event) {
          System.err.println(event);
        }
      });
     
      try {
        // Resolve the version
        ArtifactResult artifactResult = repoSystem.resolveArtifact(session, request);
        artifact = artifactResult.getArtifact();
        file = artifact.getFile();
      }
      catch (ArtifactResolutionException ex) {
        // could not download artifact, simply return null
      }
     
      return file;
    } finally {
      for (DownloadListener dl : listeners) {
        if (file != null)
          dl.success(file);
        else
          dl.failure(null, "Download failed");
      }
    }
  }

  @Override
  public boolean canWrite() {
    return true;
  }

  @Override
  public String getName() {
    return name;
  }

  @Override
  public String getLocation() {
    return "http://localhost:8080/nexus/content/repositories/scratch1";
  }
 
  /**
   * <p>
   * Find the default URI of the OBR index for a hosted repository, assuming
   * that the OBR plugin is used to generate a Virtual repository with the
   * same name as the referenced repository with the addition of "-obr" to its
   * name.
   * </p>
   * <p>
   * For example suppose there is a hosted repository with the identity
   * "releases"; it will have the URI
   * {@code http://hostname/nexus/content/repositories/releases}. We assume
   * there is a Virtual OBR repository with ID "releases-obr". It will have
   * the URL {@code http://hostname/nexus/content/repositories/releases-obr}, and
   * the OBR index will be at
   * {@code http://hostname/nexus/content/repositories/releases-obr/.meta/obr.xml}.
   *
   * @param hostedUri
   *            The URI of the source Hosted repository.
   * @return
   */
  private static URI findDefaultVirtualIndexUri(URI hostedUri) {
    StringBuilder sb = new StringBuilder();
    sb.append(hostedUri.getScheme());
    sb.append("://");
    sb.append(hostedUri.getHost());

    if (hostedUri.getPort() > 0)
      sb.append(":" + hostedUri.getPort());

    String path = hostedUri.getPath();

    if (path != null && path.endsWith("/"))
      path = path.substring(0, path.length() - 1);

    if (path == null || path.length() == 0)
      sb.append("/");
    else
      sb.append(path);
 
    return URI.create(sb.toString() + "-obr/" + META_OBR);
  }

  @Override
  public List<URI> getIndexLocations() throws Exception {
    init();
    return indexedRepo != null ? indexedRepo.getIndexLocations() : Collections.<URI>emptyList();
  }
 
  @Override
  public Set<ResolutionPhase> getSupportedPhases() {
    return EnumSet.allOf(ResolutionPhase.class);
  }
 
  static class ResultHolder {
    RepositoryPlugin.PutResult result;
    Exception error;
  }

}
TOP

Related Classes of aQute.bnd.deployer.repository.aether.AetherRepository$ResultHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.