Package org.sonatype.nexus.proxy.maven.maven2

Source Code of org.sonatype.nexus.proxy.maven.maven2.M2GroupRepository

/*
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2014 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
* which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.proxy.maven.maven2;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.enterprise.inject.Typed;
import javax.inject.Inject;
import javax.inject.Named;

import org.sonatype.nexus.configuration.Configurator;
import org.sonatype.nexus.configuration.model.CRepository;
import org.sonatype.nexus.configuration.model.CRepositoryExternalConfigurationHolderFactory;
import org.sonatype.nexus.proxy.IllegalOperationException;
import org.sonatype.nexus.proxy.ItemNotFoundException;
import org.sonatype.nexus.proxy.LocalStorageException;
import org.sonatype.nexus.proxy.ResourceStoreRequest;
import org.sonatype.nexus.proxy.StorageException;
import org.sonatype.nexus.proxy.events.RepositoryItemValidationEvent;
import org.sonatype.nexus.proxy.item.ByteArrayContentLocator;
import org.sonatype.nexus.proxy.item.ContentLocator;
import org.sonatype.nexus.proxy.item.DefaultStorageCompositeFileItem;
import org.sonatype.nexus.proxy.item.DefaultStorageFileItem;
import org.sonatype.nexus.proxy.item.StorageCompositeFileItem;
import org.sonatype.nexus.proxy.item.StorageFileItem;
import org.sonatype.nexus.proxy.item.StorageItem;
import org.sonatype.nexus.proxy.maven.AbstractMavenGroupRepository;
import org.sonatype.nexus.proxy.maven.MavenRepository;
import org.sonatype.nexus.proxy.maven.MavenRepositoryMetadataValidationEventFailed;
import org.sonatype.nexus.proxy.maven.RepositoryPolicy;
import org.sonatype.nexus.proxy.maven.gav.Gav;
import org.sonatype.nexus.proxy.maven.gav.GavCalculator;
import org.sonatype.nexus.proxy.maven.gav.M2ArtifactRecognizer;
import org.sonatype.nexus.proxy.maven.metadata.operations.MetadataBuilder;
import org.sonatype.nexus.proxy.maven.metadata.operations.MetadataException;
import org.sonatype.nexus.proxy.maven.metadata.operations.MetadataOperand;
import org.sonatype.nexus.proxy.maven.metadata.operations.MetadataOperation;
import org.sonatype.nexus.proxy.maven.metadata.operations.NexusMergeOperation;
import org.sonatype.nexus.proxy.registry.ContentClass;
import org.sonatype.nexus.proxy.repository.GroupRepository;
import org.sonatype.nexus.proxy.storage.UnsupportedStorageOperationException;
import org.sonatype.nexus.proxy.utils.RepositoryStringUtils;
import org.sonatype.nexus.util.DigesterUtils;

import org.apache.maven.artifact.repository.metadata.Metadata;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.sisu.Description;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.sonatype.nexus.proxy.ItemNotFoundException.reasonFor;

@Named(M2GroupRepository.ID)
@Typed(GroupRepository.class)
@Description("Maven2 Repository Group")
public class M2GroupRepository
    extends AbstractMavenGroupRepository
{
  /**
   * This "mimics" the @Named("maven2")
   */
  public static final String ID = Maven2ContentClass.ID;

  private final ContentClass contentClass;

  /**
   * The GAV Calculator.
   */
  private final GavCalculator gavCalculator;

  /**
   * Content class.
   */
  private final M2GroupRepositoryConfigurator m2GroupRepositoryConfigurator;

  @Inject
  public M2GroupRepository(final @Named(Maven2ContentClass.ID) ContentClass contentClass,
                           final @Named("maven2") GavCalculator gavCalculator,
                           final M2GroupRepositoryConfigurator m2GroupRepositoryConfigurator)
  {
    this.contentClass = checkNotNull(contentClass);
    this.gavCalculator = checkNotNull(gavCalculator);
    this.m2GroupRepositoryConfigurator = checkNotNull(m2GroupRepositoryConfigurator);
  }

  @Override
  protected M2GroupRepositoryConfiguration getExternalConfiguration(boolean forWrite) {
    return (M2GroupRepositoryConfiguration) super.getExternalConfiguration(forWrite);
  }

  @Override
  protected CRepositoryExternalConfigurationHolderFactory<M2GroupRepositoryConfiguration> getExternalConfigurationHolderFactory() {
    return new CRepositoryExternalConfigurationHolderFactory<M2GroupRepositoryConfiguration>()
    {
      public M2GroupRepositoryConfiguration createExternalConfigurationHolder(CRepository config) {
        return new M2GroupRepositoryConfiguration((Xpp3Dom) config.getExternalConfiguration());
      }
    };
  }

  @Override
  public ContentClass getRepositoryContentClass() {
    return contentClass;
  }

  @Override
  public GavCalculator getGavCalculator() {
    return gavCalculator;
  }

  @Override
  protected Configurator getConfigurator() {
    return m2GroupRepositoryConfigurator;
  }

  @Override
  public boolean isMavenMetadataPath(String path) {
    return M2ArtifactRecognizer.isMetadata(path);
  }

  @Override
  protected StorageItem doRetrieveItem(ResourceStoreRequest request)
      throws IllegalOperationException, ItemNotFoundException, StorageException
  {
    if (M2ArtifactRecognizer.isMetadata(request.getRequestPath())
        && !M2ArtifactRecognizer.isChecksum(request.getRequestPath())) {
      // metadata checksum files are calculated and cached as side-effect
      // of doRetrieveMetadata.

      try {
        return doRetrieveMetadata(request);
      }
      catch (UnsupportedStorageOperationException e) {
        throw new LocalStorageException(e);
      }
    }

    return super.doRetrieveItem(request);
  }

  /**
   * Parse a maven Metadata object from a storage file item
   */
  private Metadata parseMetadata(StorageFileItem fileItem)
      throws IOException, MetadataException
  {
    Metadata metadata;
    try (InputStream inputStream = fileItem.getInputStream()) {
      metadata = MetadataBuilder.read(inputStream);
    }

    MavenRepository repo = fileItem.getRepositoryItemUid().getRepository().adaptToFacet(MavenRepository.class);
    RepositoryPolicy policy = repo.getRepositoryPolicy();
    if (metadata != null && metadata.getVersioning() != null) {
      List<String> versions = metadata.getVersioning().getVersions();
      if (RepositoryPolicy.RELEASE.equals(policy)) {
        metadata.getVersioning().setSnapshot(null);
        String latest = filterMetadata(versions, false);
        metadata.getVersioning().setLatest(latest);
      }
      else if (RepositoryPolicy.SNAPSHOT.equals(policy)) {
        metadata.getVersioning().setRelease(null);
        String latest = filterMetadata(versions, true);
        metadata.getVersioning().setLatest(latest);
      }
    }

    return metadata;
  }

  private String filterMetadata(List<String> versions, boolean allowSnapshot) {
    String latest = null;
    for (Iterator<String> it = versions.iterator(); it.hasNext(); ) {
      String version = it.next();
      if (allowSnapshot ^ Gav.isSnapshot(version)) {
        it.remove();
      }
      else {
        latest = version;
      }
    }
    return latest;
  }

  /**
   * Aggregates metadata from all member repositories
   */
  private StorageItem doRetrieveMetadata(ResourceStoreRequest request)
      throws StorageException, IllegalOperationException, UnsupportedStorageOperationException, ItemNotFoundException
  {
    List<StorageItem> items = doRetrieveItems(request);

    if (items.isEmpty()) {
      throw new ItemNotFoundException(reasonFor(request, this,
          "Metadata %s not found in any of the members of %s.", request.getRequestPath(),
          RepositoryStringUtils.getHumanizedNameString(this)));
    }

    if (!isMergeMetadata()) {
      // not merging: return the 1st and ciao
      return items.get(0);
    }

    List<Metadata> existingMetadatas = new ArrayList<Metadata>();

    try {
      for (StorageItem item : items) {
        if (!(item instanceof StorageFileItem)) {
          break;
        }

        StorageFileItem fileItem = (StorageFileItem) item;

        try {
          existingMetadatas.add(parseMetadata(fileItem));
        }
        catch (IOException e) {
          log.warn(
              "IOException during parse of metadata UID=\"" + fileItem.getRepositoryItemUid().toString()
                  + "\", will be skipped from aggregation!", e);

          eventBus().post(
              newMetadataFailureEvent(fileItem,
                  "Invalid metadata served by repository. If repository is proxy, please check out what is it serving!"));
        }
        catch (MetadataException e) {
          log.warn(
              "Metadata exception during parse of metadata from UID=\""
                  + fileItem.getRepositoryItemUid().toString() + "\", will be skipped from aggregation!", e);

          eventBus().post(
              newMetadataFailureEvent(fileItem,
                  "Invalid metadata served by repository. If repository is proxy, please check out what is it serving!"));
        }
      }

      if (existingMetadatas.isEmpty()) {
        throw new ItemNotFoundException(reasonFor(request, this,
            "Metadata %s not parseable in any of the members of %s.", request.getRequestPath(),
            RepositoryStringUtils.getHumanizedNameString(this)));
      }

      Metadata result = existingMetadatas.get(0);

      // do a merge if necessary
      if (existingMetadatas.size() > 1) {
        List<MetadataOperation> ops = new ArrayList<MetadataOperation>();

        for (int i = 1; i < existingMetadatas.size(); i++) {
          ops.add(new NexusMergeOperation(new MetadataOperand(existingMetadatas.get(i))));
        }

        final Collection<MetadataException> metadataExceptions =
            MetadataBuilder.changeMetadataIgnoringFailures(result, ops);
        if (metadataExceptions != null && !metadataExceptions.isEmpty()) {
          for (final MetadataException metadataException : metadataExceptions) {
            log.warn(
                "Ignored exception during M2 metadata merging: " + metadataException.getMessage()
                    + " (request " + request.getRequestPath() + ")", metadataException);
          }
        }
      }

      // build the result item
      ByteArrayOutputStream resultOutputStream = new ByteArrayOutputStream();

      MetadataBuilder.write(result, resultOutputStream);

      StorageItem item = createMergedMetadataItem(request, resultOutputStream.toByteArray(), items);

      // build checksum files
      String md5Digest = DigesterUtils.getMd5Digest(resultOutputStream.toByteArray());

      String sha1Digest = DigesterUtils.getSha1Digest(resultOutputStream.toByteArray());

      storeMergedMetadataItemDigest(request, md5Digest, items, "MD5");

      storeMergedMetadataItemDigest(request, sha1Digest, items, "SHA1");

      resultOutputStream.close();

      if (log.isDebugEnabled()) {
        log.debug(
            "Item for path " + request.toString() + " merged from " + Integer.toString(items.size())
                + " found items.");
      }

      return item;

    }
    catch (IOException e) {
      throw new LocalStorageException("Got IOException during M2 metadata merging.", e);
    }
    catch (MetadataException e) {
      throw new LocalStorageException("Got MetadataException during M2 metadata merging.", e);
    }
  }

  protected void storeMergedMetadataItemDigest(ResourceStoreRequest request, String digest,
                                               List<StorageItem> sources, String algorithm)
      throws IOException, UnsupportedStorageOperationException, IllegalOperationException
  {
    String digestFileName = request.getRequestPath() + "." + algorithm.toLowerCase();

    String mimeType = getMimeSupport().guessMimeTypeFromPath(getMimeRulesSource(), digestFileName);

    byte[] bytes = (digest + '\n').getBytes("UTF-8");

    ContentLocator contentLocator = new ByteArrayContentLocator(bytes, mimeType);

    ResourceStoreRequest req = new ResourceStoreRequest(digestFileName);

    req.getRequestContext().setParentContext(request.getRequestContext());

    // Metadata checksum files are not composite ones, they are derivatives of the Metadata (and metadata file _is_
    // composite one)
    DefaultStorageFileItem digestFileItem = new DefaultStorageFileItem(this, req, true, false, contentLocator);

    storeItem(false, digestFileItem);
  }

  protected StorageCompositeFileItem createMergedMetadataItem(ResourceStoreRequest request, byte[] content,
                                                              List<StorageItem> sources)
  {
    // we are creating file maven-metadata.xml, and ask the MimeUtil for it's exact MIME type to honor potential
    // user configuration
    String mimeType = getMimeSupport().guessMimeTypeFromPath(getMimeRulesSource(), "maven-metadata.xml");

    ContentLocator contentLocator = new ByteArrayContentLocator(content, mimeType);

    DefaultStorageCompositeFileItem result =
        new DefaultStorageCompositeFileItem(this, request, true, false, contentLocator, sources);

    result.setCreated(getNewestCreatedDate(sources));

    result.setModified(result.getCreated());

    return result;
  }

  private long getNewestCreatedDate(List<StorageItem> sources) {
    long result = 0;

    for (StorageItem source : sources) {
      result = Math.max(result, source.getCreated());
    }

    return result;
  }

  private RepositoryItemValidationEvent newMetadataFailureEvent(StorageFileItem item, String msg) {
    return new MavenRepositoryMetadataValidationEventFailed(this, item, msg);
  }
}
TOP

Related Classes of org.sonatype.nexus.proxy.maven.maven2.M2GroupRepository

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.