View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.internal.impl;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.*;
26  import java.nio.ByteBuffer;
27  import java.nio.file.Files;
28  import java.nio.file.Path;
29  import java.util.*;
30  import java.util.stream.Collectors;
31  
32  import org.apache.maven.api.services.*;
33  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
34  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
35  
36  import static org.apache.maven.internal.impl.Utils.nonNull;
37  
38  @Named
39  @Singleton
40  public class DefaultChecksumAlgorithmService implements ChecksumAlgorithmService {
41      private final ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector;
42  
43      @Inject
44      public DefaultChecksumAlgorithmService(ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector) {
45          this.checksumAlgorithmFactorySelector =
46                  nonNull(checksumAlgorithmFactorySelector, "checksumAlgorithmFactorySelector");
47      }
48  
49      @Override
50      public Collection<String> getChecksumAlgorithmNames() {
51          return checksumAlgorithmFactorySelector.getChecksumAlgorithmFactories().stream()
52                  .map(ChecksumAlgorithmFactory::getName)
53                  .collect(Collectors.toList());
54      }
55  
56      @Override
57      public ChecksumAlgorithm select(String algorithmName) {
58          nonNull(algorithmName, "algorithmName");
59          try {
60              return new DefaultChecksumAlgorithm(checksumAlgorithmFactorySelector.select(algorithmName));
61          } catch (IllegalArgumentException e) {
62              throw new ChecksumAlgorithmServiceException("unsupported algorithm", e);
63          }
64      }
65  
66      @Override
67      public Collection<ChecksumAlgorithm> select(Collection<String> algorithmNames) {
68          nonNull(algorithmNames, "algorithmNames");
69          try {
70              return checksumAlgorithmFactorySelector.selectList(new ArrayList<>(algorithmNames)).stream()
71                      .map(DefaultChecksumAlgorithm::new)
72                      .collect(Collectors.toList());
73          } catch (IllegalArgumentException e) {
74              throw new ChecksumAlgorithmServiceException("unsupported algorithm", e);
75          }
76      }
77  
78      @Override
79      public Map<ChecksumAlgorithm, String> calculate(byte[] data, Collection<ChecksumAlgorithm> algorithms) {
80          nonNull(data, "data");
81          nonNull(algorithms, "algorithms");
82          try {
83              return calculate(new ByteArrayInputStream(data), algorithms);
84          } catch (IOException e) {
85              throw new UncheckedIOException(e); // really unexpected
86          }
87      }
88  
89      @Override
90      public Map<ChecksumAlgorithm, String> calculate(ByteBuffer data, Collection<ChecksumAlgorithm> algorithms) {
91          nonNull(data, "data");
92          nonNull(algorithms, "algorithms");
93          LinkedHashMap<ChecksumAlgorithm, ChecksumCalculator> algMap = new LinkedHashMap<>();
94          algorithms.forEach(f -> algMap.put(f, f.getCalculator()));
95          data.mark();
96          for (ChecksumCalculator checksumCalculator : algMap.values()) {
97              checksumCalculator.update(data);
98              data.reset();
99          }
100         LinkedHashMap<ChecksumAlgorithm, String> result = new LinkedHashMap<>();
101         algMap.forEach((k, v) -> result.put(k, v.checksum()));
102         return result;
103     }
104 
105     @Override
106     public Map<ChecksumAlgorithm, String> calculate(Path file, Collection<ChecksumAlgorithm> algorithms)
107             throws IOException {
108         nonNull(file, "file");
109         nonNull(algorithms, "algorithms");
110         try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(file))) {
111             return calculate(inputStream, algorithms);
112         }
113     }
114 
115     @Override
116     public Map<ChecksumAlgorithm, String> calculate(InputStream stream, Collection<ChecksumAlgorithm> algorithms)
117             throws IOException {
118         nonNull(stream, "stream");
119         nonNull(algorithms, "algorithms");
120         LinkedHashMap<ChecksumAlgorithm, ChecksumCalculator> algMap = new LinkedHashMap<>();
121         algorithms.forEach(f -> algMap.put(f, f.getCalculator()));
122         final byte[] buffer = new byte[1024 * 32];
123         for (; ; ) {
124             int read = stream.read(buffer);
125             if (read < 0) {
126                 break;
127             }
128             for (ChecksumCalculator checksumCalculator : algMap.values()) {
129                 checksumCalculator.update(ByteBuffer.wrap(buffer, 0, read));
130             }
131         }
132         LinkedHashMap<ChecksumAlgorithm, String> result = new LinkedHashMap<>();
133         algMap.forEach((k, v) -> result.put(k, v.checksum()));
134         return result;
135     }
136 
137     private static class DefaultChecksumAlgorithm implements ChecksumAlgorithm {
138         private final ChecksumAlgorithmFactory factory;
139 
140         DefaultChecksumAlgorithm(ChecksumAlgorithmFactory factory) {
141             this.factory = factory;
142         }
143 
144         @Override
145         public String getName() {
146             return factory.getName();
147         }
148 
149         @Override
150         public String getFileExtension() {
151             return factory.getFileExtension();
152         }
153 
154         @Override
155         public ChecksumCalculator getCalculator() {
156             return new DefaultChecksumCalculator(factory.getAlgorithm());
157         }
158 
159         @Override
160         public boolean equals(Object o) {
161             if (this == o) {
162                 return true;
163             }
164             if (o == null || getClass() != o.getClass()) {
165                 return false;
166             }
167             DefaultChecksumAlgorithm that = (DefaultChecksumAlgorithm) o;
168             return Objects.equals(factory.getName(), that.factory.getName());
169         }
170 
171         @Override
172         public int hashCode() {
173             return Objects.hash(factory.getName());
174         }
175     }
176 
177     private static class DefaultChecksumCalculator implements ChecksumCalculator {
178         private final org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm algorithm;
179 
180         DefaultChecksumCalculator(org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm algorithm) {
181             this.algorithm = algorithm;
182         }
183 
184         @Override
185         public void update(ByteBuffer input) {
186             algorithm.update(input);
187         }
188 
189         @Override
190         public String checksum() {
191             return algorithm.checksum();
192         }
193     }
194 }