001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl.checksum; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.io.IOException; 026import java.io.UncheckedIOException; 027import java.nio.file.Files; 028import java.nio.file.Path; 029import java.util.HashMap; 030import java.util.List; 031import java.util.Map; 032 033import org.eclipse.aether.RepositorySystemSession; 034import org.eclipse.aether.artifact.Artifact; 035import org.eclipse.aether.internal.impl.LocalPathComposer; 036import org.eclipse.aether.repository.ArtifactRepository; 037import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; 038import org.eclipse.aether.spi.io.FileProcessor; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042import static java.util.Objects.requireNonNull; 043 044/** 045 * Sparse file {@link FileTrustedChecksumsSourceSupport} implementation that use specified directory as base 046 * directory, where it expects artifacts checksums on standard Maven2 "local" layout. This implementation uses Artifact 047 * coordinates solely to form path from basedir, pretty much as Maven local repository does. 048 * <p> 049 * The source by default is "origin aware", it will factor in origin repository ID as well into base directory name 050 * (for example ".checksums/central/..."). 051 * <p> 052 * The checksums files are directly loaded from disk, so in-flight file changes during lifecycle of session are picked 053 * up. This implementation can be simultaneously used to lookup and also write checksums. The written checksums 054 * will become visible across all sessions right after the moment they were written. 055 * <p> 056 * The name of this implementation is "sparseDirectory". 057 * 058 * @see LocalPathComposer 059 * @since 1.9.0 060 */ 061@Singleton 062@Named(SparseDirectoryTrustedChecksumsSource.NAME) 063public final class SparseDirectoryTrustedChecksumsSource extends FileTrustedChecksumsSourceSupport { 064 public static final String NAME = "sparseDirectory"; 065 066 private static final Logger LOGGER = LoggerFactory.getLogger(SparseDirectoryTrustedChecksumsSource.class); 067 068 private final FileProcessor fileProcessor; 069 070 private final LocalPathComposer localPathComposer; 071 072 @Inject 073 public SparseDirectoryTrustedChecksumsSource(FileProcessor fileProcessor, LocalPathComposer localPathComposer) { 074 super(NAME); 075 this.fileProcessor = requireNonNull(fileProcessor); 076 this.localPathComposer = requireNonNull(localPathComposer); 077 } 078 079 @Override 080 protected Map<String, String> doGetTrustedArtifactChecksums( 081 RepositorySystemSession session, 082 Artifact artifact, 083 ArtifactRepository artifactRepository, 084 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories) { 085 final boolean originAware = isOriginAware(session); 086 final HashMap<String, String> checksums = new HashMap<>(); 087 Path basedir = getBasedir(session, false); 088 if (Files.isDirectory(basedir)) { 089 for (ChecksumAlgorithmFactory checksumAlgorithmFactory : checksumAlgorithmFactories) { 090 Path checksumPath = basedir.resolve( 091 calculateArtifactPath(originAware, artifact, artifactRepository, checksumAlgorithmFactory)); 092 093 if (!Files.isRegularFile(checksumPath)) { 094 LOGGER.debug( 095 "Artifact '{}' trusted checksum '{}' not found on path '{}'", 096 artifact, 097 checksumAlgorithmFactory.getName(), 098 checksumPath); 099 continue; 100 } 101 102 try { 103 String checksum = fileProcessor.readChecksum(checksumPath.toFile()); 104 if (checksum != null) { 105 checksums.put(checksumAlgorithmFactory.getName(), checksum); 106 } 107 } catch (IOException e) { 108 // unexpected, log 109 LOGGER.warn( 110 "Could not read artifact '{}' trusted checksum on path '{}'", artifact, checksumPath, e); 111 throw new UncheckedIOException(e); 112 } 113 } 114 } 115 return checksums; 116 } 117 118 @Override 119 protected SparseDirectoryWriter doGetTrustedArtifactChecksumsWriter(RepositorySystemSession session) { 120 return new SparseDirectoryWriter(getBasedir(session, true), isOriginAware(session)); 121 } 122 123 private String calculateArtifactPath( 124 boolean originAware, 125 Artifact artifact, 126 ArtifactRepository artifactRepository, 127 ChecksumAlgorithmFactory checksumAlgorithmFactory) { 128 String path = localPathComposer.getPathForArtifact(artifact, false) + "." 129 + checksumAlgorithmFactory.getFileExtension(); 130 if (originAware) { 131 path = artifactRepository.getId() + "/" + path; 132 } 133 return path; 134 } 135 136 private class SparseDirectoryWriter implements Writer { 137 private final Path basedir; 138 139 private final boolean originAware; 140 141 private SparseDirectoryWriter(Path basedir, boolean originAware) { 142 this.basedir = basedir; 143 this.originAware = originAware; 144 } 145 146 @Override 147 public void addTrustedArtifactChecksums( 148 Artifact artifact, 149 ArtifactRepository artifactRepository, 150 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories, 151 Map<String, String> trustedArtifactChecksums) 152 throws IOException { 153 for (ChecksumAlgorithmFactory checksumAlgorithmFactory : checksumAlgorithmFactories) { 154 Path checksumPath = basedir.resolve( 155 calculateArtifactPath(originAware, artifact, artifactRepository, checksumAlgorithmFactory)); 156 String checksum = requireNonNull(trustedArtifactChecksums.get(checksumAlgorithmFactory.getName())); 157 fileProcessor.writeChecksum(checksumPath.toFile(), checksum); 158 } 159 } 160 } 161}