1 package org.eclipse.aether.connector.basic;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.net.URI;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Locale;
29 import java.util.Map;
30 import java.util.UUID;
31
32 import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
33 import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum;
34 import org.eclipse.aether.spi.io.FileProcessor;
35 import org.eclipse.aether.spi.log.Logger;
36 import org.eclipse.aether.transfer.ChecksumFailureException;
37 import org.eclipse.aether.util.ChecksumUtils;
38
39
40
41
42 final class ChecksumValidator
43 {
44
45 interface ChecksumFetcher
46 {
47
48 boolean fetchChecksum( URI remote, File local )
49 throws Exception;
50
51 }
52
53 private final Logger logger;
54
55 private final File dataFile;
56
57 private final Collection<File> tempFiles;
58
59 private final FileProcessor fileProcessor;
60
61 private final ChecksumFetcher checksumFetcher;
62
63 private final ChecksumPolicy checksumPolicy;
64
65 private final Collection<Checksum> checksums;
66
67 private final Map<File, Object> checksumFiles;
68
69 ChecksumValidator( Logger logger, File dataFile, FileProcessor fileProcessor,
70 ChecksumFetcher checksumFetcher, ChecksumPolicy checksumPolicy,
71 Collection<Checksum> checksums )
72 {
73 this.logger = logger;
74 this.dataFile = dataFile;
75 this.tempFiles = new HashSet<File>();
76 this.fileProcessor = fileProcessor;
77 this.checksumFetcher = checksumFetcher;
78 this.checksumPolicy = checksumPolicy;
79 this.checksums = checksums;
80 checksumFiles = new HashMap<File, Object>();
81 }
82
83 public ChecksumCalculator newChecksumCalculator( File targetFile )
84 {
85 if ( checksumPolicy != null )
86 {
87 return ChecksumCalculator.newInstance( targetFile, checksums );
88 }
89 return null;
90 }
91
92 public void validate( Map<String, ?> actualChecksums, Map<String, ?> inlinedChecksums )
93 throws ChecksumFailureException
94 {
95 if ( checksumPolicy == null )
96 {
97 return;
98 }
99 if ( inlinedChecksums != null && validateInlinedChecksums( actualChecksums, inlinedChecksums ) )
100 {
101 return;
102 }
103 if ( validateExternalChecksums( actualChecksums ) )
104 {
105 return;
106 }
107 checksumPolicy.onNoMoreChecksums();
108 }
109
110 private boolean validateInlinedChecksums( Map<String, ?> actualChecksums, Map<String, ?> inlinedChecksums )
111 throws ChecksumFailureException
112 {
113 for ( Map.Entry<String, ?> entry : inlinedChecksums.entrySet() )
114 {
115 String algo = entry.getKey();
116 Object calculated = actualChecksums.get( algo );
117 if ( !( calculated instanceof String ) )
118 {
119 continue;
120 }
121
122 String actual = String.valueOf( calculated );
123 String expected = entry.getValue().toString();
124 checksumFiles.put( getChecksumFile( algo ), expected );
125
126 if ( !isEqualChecksum( expected, actual ) )
127 {
128 checksumPolicy.onChecksumMismatch( algo, ChecksumPolicy.KIND_UNOFFICIAL,
129 new ChecksumFailureException( expected, actual ) );
130 }
131 else if ( checksumPolicy.onChecksumMatch( algo, ChecksumPolicy.KIND_UNOFFICIAL ) )
132 {
133 return true;
134 }
135 }
136 return false;
137 }
138
139 private boolean validateExternalChecksums( Map<String, ?> actualChecksums )
140 throws ChecksumFailureException
141 {
142 for ( Checksum checksum : checksums )
143 {
144 String algo = checksum.getAlgorithm();
145 Object calculated = actualChecksums.get( algo );
146 if ( calculated instanceof Exception )
147 {
148 checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( (Exception) calculated ) );
149 continue;
150 }
151 try
152 {
153 File checksumFile = getChecksumFile( checksum.getAlgorithm() );
154 File tmp = createTempFile( checksumFile );
155 try
156 {
157 if ( !checksumFetcher.fetchChecksum( checksum.getLocation(), tmp ) )
158 {
159 continue;
160 }
161 }
162 catch ( Exception e )
163 {
164 checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( e ) );
165 continue;
166 }
167
168 String actual = String.valueOf( calculated );
169 String expected = ChecksumUtils.read( tmp );
170 checksumFiles.put( checksumFile, tmp );
171
172 if ( !isEqualChecksum( expected, actual ) )
173 {
174 checksumPolicy.onChecksumMismatch( algo, 0, new ChecksumFailureException( expected, actual ) );
175 }
176 else if ( checksumPolicy.onChecksumMatch( algo, 0 ) )
177 {
178 return true;
179 }
180 }
181 catch ( IOException e )
182 {
183 checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( e ) );
184 }
185 }
186 return false;
187 }
188
189 private static boolean isEqualChecksum( String expected, String actual )
190 {
191 return expected.equalsIgnoreCase( actual );
192 }
193
194 private File getChecksumFile( String algorithm )
195 {
196 String ext = algorithm.replace( "-", "" ).toLowerCase( Locale.ENGLISH );
197 return new File( dataFile.getPath() + '.' + ext );
198 }
199
200 private File createTempFile( File path )
201 throws IOException
202 {
203 File file =
204 File.createTempFile( path.getName() + "-"
205 + UUID.randomUUID().toString().replace( "-", "" ).substring( 0, 8 ), ".tmp", path.getParentFile() );
206 tempFiles.add( file );
207 return file;
208 }
209
210 private void clearTempFiles()
211 {
212 for ( File file : tempFiles )
213 {
214 if ( !file.delete() && file.exists() )
215 {
216 logger.debug( "Could not delete temorary file " + file );
217 }
218 }
219 tempFiles.clear();
220 }
221
222 public void retry()
223 {
224 checksumPolicy.onTransferRetry();
225 checksumFiles.clear();
226 clearTempFiles();
227 }
228
229 public boolean handle( ChecksumFailureException exception )
230 {
231 return checksumPolicy.onTransferChecksumFailure( exception );
232 }
233
234 public void commit()
235 {
236 for ( Map.Entry<File, Object> entry : checksumFiles.entrySet() )
237 {
238 File checksumFile = entry.getKey();
239 Object tmp = entry.getValue();
240 try
241 {
242 if ( tmp instanceof File )
243 {
244 fileProcessor.move( (File) tmp, checksumFile );
245 tempFiles.remove( tmp );
246 }
247 else
248 {
249 fileProcessor.write( checksumFile, String.valueOf( tmp ) );
250 }
251 }
252 catch ( IOException e )
253 {
254 logger.debug( "Failed to write checksum file " + checksumFile + ": " + e.getMessage(), e );
255 }
256 }
257 checksumFiles.clear();
258 }
259
260 public void close()
261 {
262 clearTempFiles();
263 }
264
265 }