View Javadoc
1   package org.eclipse.aether.internal.impl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.eclipse.aether.RepositorySystemSession;
23  import org.eclipse.aether.spi.connector.ArtifactDownload;
24  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
25  import org.eclipse.aether.spi.connector.checksum.ProvidedChecksumsSource;
26  import org.eclipse.aether.spi.io.FileProcessor;
27  import org.eclipse.aether.util.ConfigUtils;
28  import org.eclipse.aether.util.artifact.ArtifactIdUtils;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  import javax.inject.Inject;
33  import javax.inject.Named;
34  import javax.inject.Singleton;
35  import java.io.IOException;
36  import java.net.URI;
37  import java.nio.file.Files;
38  import java.nio.file.Path;
39  import java.nio.file.Paths;
40  import java.util.ArrayList;
41  import java.util.HashMap;
42  import java.util.List;
43  import java.util.Map;
44  
45  import static java.util.Objects.requireNonNull;
46  
47  /**
48   * Local filesystem backed {@link ProvidedChecksumsSource} implementation that use specified directory as base
49   * directory, where it expects artifacts checksums on standard Maven2 "local" layout. This implementation uses Artifact
50   * (and Metadata) coordinates solely to form path from baseDir (for Metadata file name is
51   * {@code maven-metadata-local.xml.sha1} in case of SHA-1 checksum).
52   *
53   * @since 1.8.0
54   */
55  @Singleton
56  @Named( FileProvidedChecksumsSource.NAME )
57  public final class FileProvidedChecksumsSource
58      implements ProvidedChecksumsSource
59  {
60      public static final String NAME = "file";
61  
62      static final String CONFIG_PROP_BASE_DIR = "aether.artifactResolver.providedChecksumsSource.file.baseDir";
63  
64      static final String LOCAL_REPO_PREFIX = ".checksums";
65  
66      private static final Logger LOGGER = LoggerFactory.getLogger( FileProvidedChecksumsSource.class );
67  
68      private final FileProcessor fileProcessor;
69  
70      private final LocalPathComposer localPathComposer;
71  
72      @Inject
73      public FileProvidedChecksumsSource( FileProcessor fileProcessor, LocalPathComposer localPathComposer )
74      {
75          this.fileProcessor = requireNonNull( fileProcessor );
76          this.localPathComposer = requireNonNull( localPathComposer );
77      }
78  
79      @Override
80      public Map<String, String> getProvidedArtifactChecksums( RepositorySystemSession session,
81                                                               ArtifactDownload transfer,
82                                                               List<ChecksumAlgorithmFactory> checksumAlgorithmFactories )
83      {
84          Path baseDir = getBaseDir( session );
85          if ( baseDir == null )
86          {
87              return null;
88          }
89          ArrayList<ChecksumFilePath> checksumFilePaths = new ArrayList<>( checksumAlgorithmFactories.size() );
90          for ( ChecksumAlgorithmFactory checksumAlgorithmFactory : checksumAlgorithmFactories )
91          {
92              checksumFilePaths.add( new ChecksumFilePath(
93                      localPathComposer.getPathForArtifact( transfer.getArtifact(), false ) + '.'
94                      + checksumAlgorithmFactory.getFileExtension(), checksumAlgorithmFactory ) );
95          }
96          return getProvidedChecksums( baseDir, checksumFilePaths, ArtifactIdUtils.toId( transfer.getArtifact() ) );
97      }
98  
99      /**
100      * May return {@code null}.
101      */
102     private Map<String, String> getProvidedChecksums( Path baseDir,
103                                                       List<ChecksumFilePath> checksumFilePaths,
104                                                       String subjectId )
105     {
106         HashMap<String, String> checksums = new HashMap<>();
107         for ( ChecksumFilePath checksumFilePath : checksumFilePaths )
108         {
109             Path checksumPath =  baseDir.resolve( checksumFilePath.path );
110             if ( Files.isReadable( checksumPath ) )
111             {
112                 try
113                 {
114                     String checksum = fileProcessor.readChecksum( checksumPath.toFile() );
115                     if ( checksum != null )
116                     {
117                         LOGGER.debug( "Resolved provided checksum '{}:{}' for '{}'",
118                                 checksumFilePath.checksumAlgorithmFactory.getName(), checksum, subjectId );
119 
120                         checksums.put( checksumFilePath.checksumAlgorithmFactory.getName(), checksum );
121                     }
122                 }
123                 catch ( IOException e )
124                 {
125                     LOGGER.warn( "Could not read provided checksum for '{}' at path '{}'",
126                             subjectId, checksumPath, e );
127                 }
128             }
129         }
130         return checksums.isEmpty() ? null : checksums;
131     }
132 
133     /**
134      * Returns the base {@link URI} of directory where checksums are laid out, may return {@code null}.
135      */
136     private Path getBaseDir( RepositorySystemSession session )
137     {
138         final String baseDirPath = ConfigUtils.getString( session, null, CONFIG_PROP_BASE_DIR );
139         final Path baseDir;
140         if ( baseDirPath != null )
141         {
142             baseDir = Paths.get( baseDirPath );
143         }
144         else
145         {
146             baseDir = session.getLocalRepository().getBasedir().toPath().resolve( LOCAL_REPO_PREFIX );
147         }
148         if ( !Files.isDirectory( baseDir ) )
149         {
150             return null;
151         }
152         return baseDir;
153     }
154 
155     private static final class ChecksumFilePath
156     {
157         private final String path;
158 
159         private final ChecksumAlgorithmFactory checksumAlgorithmFactory;
160 
161         private ChecksumFilePath( String path, ChecksumAlgorithmFactory checksumAlgorithmFactory )
162         {
163             this.path = path;
164             this.checksumAlgorithmFactory = checksumAlgorithmFactory;
165         }
166     }
167 }