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 java.io.BufferedInputStream;
22  import java.io.ByteArrayInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.UncheckedIOException;
26  import java.nio.ByteBuffer;
27  import java.nio.file.Files;
28  import java.nio.file.Path;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.LinkedHashMap;
32  import java.util.Map;
33  import java.util.Objects;
34  import java.util.stream.Collectors;
35  
36  import org.apache.maven.api.di.Inject;
37  import org.apache.maven.api.di.Named;
38  import org.apache.maven.api.di.Singleton;
39  import org.apache.maven.api.services.ChecksumAlgorithmService;
40  import org.apache.maven.api.services.ChecksumAlgorithmServiceException;
41  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
42  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
43  
44  import static org.apache.maven.internal.impl.Utils.nonNull;
45  
46  @Named
47  @Singleton
48  public class DefaultChecksumAlgorithmService implements ChecksumAlgorithmService {
49      private final ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector;
50  
51      @Inject
52      public DefaultChecksumAlgorithmService(ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector) {
53          this.checksumAlgorithmFactorySelector =
54                  nonNull(checksumAlgorithmFactorySelector, "checksumAlgorithmFactorySelector");
55      }
56  
57      @Override
58      public Collection<String> getChecksumAlgorithmNames() {
59          return checksumAlgorithmFactorySelector.getChecksumAlgorithmFactories().stream()
60                  .map(ChecksumAlgorithmFactory::getName)
61                  .collect(Collectors.toList());
62      }
63  
64      @Override
65      public ChecksumAlgorithm select(String algorithmName) {
66          nonNull(algorithmName, "algorithmName");
67          try {
68              return new DefaultChecksumAlgorithm(checksumAlgorithmFactorySelector.select(algorithmName));
69          } catch (IllegalArgumentException e) {
70              throw new ChecksumAlgorithmServiceException("unsupported algorithm", e);
71          }
72      }
73  
74      @Override
75      public Collection<ChecksumAlgorithm> select(Collection<String> algorithmNames) {
76          nonNull(algorithmNames, "algorithmNames");
77          try {
78              return checksumAlgorithmFactorySelector.selectList(new ArrayList<>(algorithmNames)).stream()
79                      .map(DefaultChecksumAlgorithm::new)
80                      .collect(Collectors.toList());
81          } catch (IllegalArgumentException e) {
82              throw new ChecksumAlgorithmServiceException("unsupported algorithm", e);
83          }
84      }
85  
86      @Override
87      public Map<ChecksumAlgorithm, String> calculate(byte[] data, Collection<ChecksumAlgorithm> algorithms) {
88          nonNull(data, "data");
89          nonNull(algorithms, "algorithms");
90          try {
91              return calculate(new ByteArrayInputStream(data), algorithms);
92          } catch (IOException e) {
93              throw new UncheckedIOException(e); // really unexpected
94          }
95      }
96  
97      @Override
98      public Map<ChecksumAlgorithm, String> calculate(ByteBuffer data, Collection<ChecksumAlgorithm> algorithms) {
99          nonNull(data, "data");
100         nonNull(algorithms, "algorithms");
101         LinkedHashMap<ChecksumAlgorithm, ChecksumCalculator> algMap = new LinkedHashMap<>();
102         algorithms.forEach(f -> algMap.put(f, f.getCalculator()));
103         data.mark();
104         for (ChecksumCalculator checksumCalculator : algMap.values()) {
105             checksumCalculator.update(data);
106             data.reset();
107         }
108         LinkedHashMap<ChecksumAlgorithm, String> result = new LinkedHashMap<>();
109         algMap.forEach((k, v) -> result.put(k, v.checksum()));
110         return result;
111     }
112 
113     @Override
114     public Map<ChecksumAlgorithm, String> calculate(Path file, Collection<ChecksumAlgorithm> algorithms)
115             throws IOException {
116         nonNull(file, "file");
117         nonNull(algorithms, "algorithms");
118         try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(file))) {
119             return calculate(inputStream, algorithms);
120         }
121     }
122 
123     @Override
124     public Map<ChecksumAlgorithm, String> calculate(InputStream stream, Collection<ChecksumAlgorithm> algorithms)
125             throws IOException {
126         nonNull(stream, "stream");
127         nonNull(algorithms, "algorithms");
128         LinkedHashMap<ChecksumAlgorithm, ChecksumCalculator> algMap = new LinkedHashMap<>();
129         algorithms.forEach(f -> algMap.put(f, f.getCalculator()));
130         final byte[] buffer = new byte[1024 * 32];
131         for (; ; ) {
132             int read = stream.read(buffer);
133             if (read < 0) {
134                 break;
135             }
136             for (ChecksumCalculator checksumCalculator : algMap.values()) {
137                 checksumCalculator.update(ByteBuffer.wrap(buffer, 0, read));
138             }
139         }
140         LinkedHashMap<ChecksumAlgorithm, String> result = new LinkedHashMap<>();
141         algMap.forEach((k, v) -> result.put(k, v.checksum()));
142         return result;
143     }
144 
145     private static class DefaultChecksumAlgorithm implements ChecksumAlgorithm {
146         private final ChecksumAlgorithmFactory factory;
147 
148         DefaultChecksumAlgorithm(ChecksumAlgorithmFactory factory) {
149             this.factory = factory;
150         }
151 
152         @Override
153         public String getName() {
154             return factory.getName();
155         }
156 
157         @Override
158         public String getFileExtension() {
159             return factory.getFileExtension();
160         }
161 
162         @Override
163         public ChecksumCalculator getCalculator() {
164             return new DefaultChecksumCalculator(factory.getAlgorithm());
165         }
166 
167         @Override
168         public boolean equals(Object o) {
169             if (this == o) {
170                 return true;
171             }
172             if (o == null || getClass() != o.getClass()) {
173                 return false;
174             }
175             DefaultChecksumAlgorithm that = (DefaultChecksumAlgorithm) o;
176             return Objects.equals(factory.getName(), that.factory.getName());
177         }
178 
179         @Override
180         public int hashCode() {
181             return Objects.hash(factory.getName());
182         }
183     }
184 
185     private static class DefaultChecksumCalculator implements ChecksumCalculator {
186         private final org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm algorithm;
187 
188         DefaultChecksumCalculator(org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm algorithm) {
189             this.algorithm = algorithm;
190         }
191 
192         @Override
193         public void update(ByteBuffer input) {
194             algorithm.update(input);
195         }
196 
197         @Override
198         public String checksum() {
199             return algorithm.checksum();
200         }
201     }
202 }