View Javadoc
1   package org.eclipse.aether.internal.impl.checksum;
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 javax.inject.Inject;
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  
26  import java.io.IOException;
27  import java.io.UncheckedIOException;
28  import java.nio.file.Files;
29  import java.nio.file.Path;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  import org.eclipse.aether.RepositorySystemSession;
35  import org.eclipse.aether.artifact.Artifact;
36  import org.eclipse.aether.internal.impl.LocalPathComposer;
37  import org.eclipse.aether.repository.ArtifactRepository;
38  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
39  import org.eclipse.aether.spi.io.FileProcessor;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  import static java.util.Objects.requireNonNull;
44  
45  /**
46   * Sparse file {@link FileTrustedChecksumsSourceSupport} implementation that use specified directory as base
47   * directory, where it expects artifacts checksums on standard Maven2 "local" layout. This implementation uses Artifact
48   * coordinates solely to form path from basedir, pretty much as Maven local repository does.
49   * <p>
50   * The source by default is "origin aware", it will factor in origin repository ID as well into base directory name
51   * (for example ".checksums/central/...").
52   * <p>
53   * The checksums files are directly loaded from disk, so in-flight file changes during lifecycle of session are picked
54   * up. This implementation can be simultaneously used to lookup and also write checksums. The written checksums
55   * will become visible across all sessions right after the moment they were written.
56   * <p>
57   * The name of this implementation is "sparseDirectory".
58   *
59   * @see LocalPathComposer
60   * @since 1.9.0
61   */
62  @Singleton
63  @Named( SparseDirectoryTrustedChecksumsSource.NAME )
64  public final class SparseDirectoryTrustedChecksumsSource
65          extends FileTrustedChecksumsSourceSupport
66  {
67      public static final String NAME = "sparseDirectory";
68  
69      private static final Logger LOGGER = LoggerFactory.getLogger( SparseDirectoryTrustedChecksumsSource.class );
70  
71      private final FileProcessor fileProcessor;
72  
73      private final LocalPathComposer localPathComposer;
74  
75      @Inject
76      public SparseDirectoryTrustedChecksumsSource( FileProcessor fileProcessor, LocalPathComposer localPathComposer )
77      {
78          super( NAME );
79          this.fileProcessor = requireNonNull( fileProcessor );
80          this.localPathComposer = requireNonNull( localPathComposer );
81      }
82  
83      @Override
84      protected Map<String, String> doGetTrustedArtifactChecksums(
85              RepositorySystemSession session, Artifact artifact, ArtifactRepository artifactRepository,
86              List<ChecksumAlgorithmFactory> checksumAlgorithmFactories )
87      {
88          final boolean originAware = isOriginAware( session );
89          final HashMap<String, String> checksums = new HashMap<>();
90          Path basedir = getBasedir( session, false );
91          if ( Files.isDirectory( basedir ) )
92          {
93              for ( ChecksumAlgorithmFactory checksumAlgorithmFactory : checksumAlgorithmFactories )
94              {
95                  Path checksumPath = basedir.resolve(
96                          calculateArtifactPath( originAware, artifact, artifactRepository, checksumAlgorithmFactory ) );
97  
98                  if ( !Files.isRegularFile( checksumPath ) )
99                  {
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 }