1 package org.apache.maven.index.reader;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.index.reader.ResourceHandler.Resource;
23
24 import java.io.Closeable;
25 import java.io.IOException;
26 import java.text.ParseException;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Date;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Properties;
33
34 import static org.apache.maven.index.reader.Utils.loadProperties;
35 import static org.apache.maven.index.reader.Utils.storeProperties;
36
37
38
39
40
41
42
43 public class IndexReader
44 implements Iterable<ChunkReader>, Closeable
45 {
46 private final WritableResourceHandler local;
47
48 private final ResourceHandler remote;
49
50 private final Properties localIndexProperties;
51
52 private final Properties remoteIndexProperties;
53
54 private final String indexId;
55
56 private final Date publishedTimestamp;
57
58 private final boolean incremental;
59
60 private final List<String> chunkNames;
61
62 public IndexReader( final WritableResourceHandler local, final ResourceHandler remote )
63 throws IOException
64 {
65 if ( remote == null )
66 {
67 throw new NullPointerException( "remote resource handler null" );
68 }
69 this.local = local;
70 this.remote = remote;
71 remoteIndexProperties = loadProperties( remote.locate( Utils.INDEX_FILE_PREFIX + ".properties" ) );
72 if ( remoteIndexProperties == null )
73 {
74 throw new IllegalArgumentException( "Non-existent remote index" );
75 }
76 try
77 {
78 if ( local != null )
79 {
80 Properties localProperties =
81 loadProperties( local.locate( Utils.INDEX_FILE_PREFIX + ".properties" ) );
82 if ( localProperties != null )
83 {
84 this.localIndexProperties = localProperties;
85 String remoteIndexId = remoteIndexProperties.getProperty( "nexus.index.id" );
86 String localIndexId = localIndexProperties.getProperty( "nexus.index.id" );
87 if ( remoteIndexId == null || localIndexId == null || !remoteIndexId.equals( localIndexId ) )
88 {
89 throw new IllegalArgumentException(
90 "local and remote index IDs does not match or is null: " + localIndexId + ", "
91 + remoteIndexId );
92 }
93 this.indexId = localIndexId;
94 this.incremental = canRetrieveAllChunks();
95 }
96 else
97 {
98 localIndexProperties = null;
99 this.indexId = remoteIndexProperties.getProperty( "nexus.index.id" );
100 this.incremental = false;
101 }
102 }
103 else
104 {
105 localIndexProperties = null;
106 this.indexId = remoteIndexProperties.getProperty( "nexus.index.id" );
107 this.incremental = false;
108 }
109 this.publishedTimestamp =
110 Utils.INDEX_DATE_FORMAT.parse( remoteIndexProperties.getProperty( "nexus.index.timestamp" ) );
111 this.chunkNames = calculateChunkNames();
112 }
113 catch ( ParseException e )
114 {
115 IOException ex = new IOException( "Index properties corrupted" );
116 ex.initCause( e );
117 throw ex;
118 }
119 }
120
121
122
123
124
125 public String getIndexId()
126 {
127 return indexId;
128 }
129
130
131
132
133 public Date getPublishedTimestamp()
134 {
135 return publishedTimestamp;
136 }
137
138
139
140
141
142 public boolean isIncremental()
143 {
144 return incremental;
145 }
146
147
148
149
150
151
152 public List<String> getChunkNames()
153 {
154 return chunkNames;
155 }
156
157
158
159
160
161
162
163
164 public void close()
165 throws IOException
166 {
167 remote.close();
168 if ( local != null )
169 {
170 try
171 {
172 syncLocalWithRemote();
173 }
174 finally
175 {
176 local.close();
177 }
178 }
179 }
180
181
182
183
184
185
186 public Iterator<ChunkReader> iterator()
187 {
188 return new ChunkReaderIterator( remote, chunkNames.iterator() );
189 }
190
191
192
193
194
195 private void syncLocalWithRemote()
196 throws IOException
197 {
198 storeProperties( local.locate( Utils.INDEX_FILE_PREFIX + ".properties" ), remoteIndexProperties );
199 }
200
201
202
203
204 private List<String> calculateChunkNames()
205 {
206 if ( incremental )
207 {
208 ArrayList<String> chunkNames = new ArrayList<>();
209 int maxCounter = Integer.parseInt( remoteIndexProperties.getProperty( "nexus.index.last-incremental" ) );
210 int currentCounter = Integer.parseInt( localIndexProperties.getProperty( "nexus.index.last-incremental" ) );
211 currentCounter++;
212 while ( currentCounter <= maxCounter )
213 {
214 chunkNames.add( Utils.INDEX_FILE_PREFIX + "." + currentCounter++ + ".gz" );
215 }
216 return Collections.unmodifiableList( chunkNames );
217 }
218 else
219 {
220 return Collections.singletonList( Utils.INDEX_FILE_PREFIX + ".gz" );
221 }
222 }
223
224
225
226
227 private boolean canRetrieveAllChunks()
228 {
229 String localChainId = localIndexProperties.getProperty( "nexus.index.chain-id" );
230 String remoteChainId = remoteIndexProperties.getProperty( "nexus.index.chain-id" );
231
232
233 if ( localChainId == null || remoteChainId == null || !localChainId.equals( remoteChainId ) )
234 {
235 return false;
236 }
237
238 try
239 {
240 int localLastIncremental =
241 Integer.parseInt( localIndexProperties.getProperty( "nexus.index.last-incremental" ) );
242 String currentLocalCounter = String.valueOf( localLastIncremental );
243 String nextLocalCounter = String.valueOf( localLastIncremental + 1 );
244
245 for ( Object key : remoteIndexProperties.keySet() )
246 {
247 String sKey = (String) key;
248 if ( sKey.startsWith( "nexus.index.incremental-" ) )
249 {
250 String value = remoteIndexProperties.getProperty( sKey );
251 if ( currentLocalCounter.equals( value ) || nextLocalCounter.equals( value ) )
252 {
253 return true;
254 }
255 }
256 }
257 }
258 catch ( NumberFormatException e )
259 {
260
261 }
262 return false;
263 }
264
265
266
267
268
269 private static class ChunkReaderIterator
270 implements Iterator<ChunkReader>
271 {
272 private final ResourceHandler resourceHandler;
273
274 private final Iterator<String> chunkNamesIterator;
275
276 private Resource currentResource;
277
278 private ChunkReader currentChunkReader;
279
280 private ChunkReaderIterator( final ResourceHandler resourceHandler, final Iterator<String> chunkNamesIterator )
281 {
282 this.resourceHandler = resourceHandler;
283 this.chunkNamesIterator = chunkNamesIterator;
284 }
285
286 public boolean hasNext()
287 {
288 return chunkNamesIterator.hasNext();
289 }
290
291 public ChunkReader next()
292 {
293 String chunkName = chunkNamesIterator.next();
294 try
295 {
296 if ( currentChunkReader != null )
297 {
298 currentChunkReader.close();
299 }
300 currentResource = resourceHandler.locate( chunkName );
301 currentChunkReader = new ChunkReader( chunkName, currentResource.read() );
302 return currentChunkReader;
303 }
304 catch ( IOException e )
305 {
306 throw new RuntimeException( "IO problem while switching chunk readers", e );
307 }
308 }
309
310 public void remove()
311 {
312 throw new UnsupportedOperationException( "remove" );
313 }
314 }
315 }