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