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.FileInputStream;
24 import java.io.IOException;
25 import java.nio.ByteBuffer;
26 import java.security.MessageDigest;
27 import java.security.NoSuchAlgorithmException;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
37 import org.eclipse.aether.util.ChecksumUtils;
38
39
40
41
42 final class ChecksumCalculator
43 {
44
45 static class Checksum
46 {
47 final String algorithm;
48
49 final MessageDigest digest;
50
51 Exception error;
52
53 public Checksum( String algorithm )
54 {
55 this.algorithm = algorithm;
56 MessageDigest digest = null;
57 try
58 {
59 digest = MessageDigest.getInstance( algorithm );
60 }
61 catch ( NoSuchAlgorithmException e )
62 {
63 error = e;
64 }
65 this.digest = digest;
66 }
67
68 public void update( ByteBuffer buffer )
69 {
70 if ( digest != null )
71 {
72 digest.update( buffer );
73 }
74 }
75
76 public void reset()
77 {
78 if ( digest != null )
79 {
80 digest.reset();
81 error = null;
82 }
83 }
84
85 public void error( Exception error )
86 {
87 if ( digest != null )
88 {
89 this.error = error;
90 }
91 }
92
93 public Object get()
94 {
95 if ( error != null )
96 {
97 return error;
98 }
99 return ChecksumUtils.toHexString( digest.digest() );
100 }
101
102 }
103
104 private final List<Checksum> checksums;
105
106 private final File targetFile;
107
108 public static ChecksumCalculator newInstance( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
109 {
110 if ( checksums == null || checksums.isEmpty() )
111 {
112 return null;
113 }
114 return new ChecksumCalculator( targetFile, checksums );
115 }
116
117 private ChecksumCalculator( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
118 {
119 this.checksums = new ArrayList<Checksum>();
120 Set<String> algos = new HashSet<String>();
121 for ( RepositoryLayout.Checksum checksum : checksums )
122 {
123 String algo = checksum.getAlgorithm();
124 if ( algos.add( algo ) )
125 {
126 this.checksums.add( new Checksum( algo ) );
127 }
128 }
129 this.targetFile = targetFile;
130 }
131
132 public void init( long dataOffset )
133 {
134 for ( Checksum checksum : checksums )
135 {
136 checksum.reset();
137 }
138 if ( dataOffset <= 0 )
139 {
140 return;
141 }
142 try
143 {
144 FileInputStream fis = new FileInputStream( targetFile );
145 try
146 {
147 long total = 0;
148 ByteBuffer buffer = ByteBuffer.allocate( 1024 * 32 );
149 for ( byte[] array = buffer.array(); total < dataOffset; )
150 {
151 int read = fis.read( array );
152 if ( read < 0 )
153 {
154 if ( total < dataOffset )
155 {
156 throw new IOException( targetFile + " contains only " + total
157 + " bytes, cannot resume download from offset " + dataOffset );
158 }
159 break;
160 }
161 total += read;
162 if ( total > dataOffset )
163 {
164 read -= total - dataOffset;
165 }
166 buffer.rewind();
167 buffer.limit( read );
168 update( buffer );
169 }
170 }
171 finally
172 {
173 try
174 {
175 fis.close();
176 }
177 catch ( IOException e )
178 {
179
180 }
181 }
182 }
183 catch ( IOException e )
184 {
185 for ( Checksum checksum : checksums )
186 {
187 checksum.error( e );
188 }
189 }
190 }
191
192 public void update( ByteBuffer data )
193 {
194 for ( Checksum checksum : checksums )
195 {
196 data.mark();
197 checksum.update( data );
198 data.reset();
199 }
200 }
201
202 public Map<String, Object> get()
203 {
204 Map<String, Object> results = new HashMap<String, Object>();
205 for ( Checksum checksum : checksums )
206 {
207 results.put( checksum.algorithm, checksum.get() );
208 }
209 return results;
210 }
211
212 }