This project has retired. For details please refer to its
Attic page.
FilesystemStorage xref
1 package org.apache.archiva.repository.storage;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.archiva.common.filelock.FileLockException;
23 import org.apache.archiva.common.filelock.FileLockManager;
24 import org.apache.archiva.common.filelock.FileLockTimeoutException;
25 import org.apache.archiva.common.filelock.Lock;
26 import org.apache.archiva.common.utils.PathUtil;
27 import org.apache.commons.io.FileUtils;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 import java.io.FileNotFoundException;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.OutputStream;
35 import java.net.URI;
36 import java.nio.channels.FileChannel;
37 import java.nio.channels.ReadableByteChannel;
38 import java.nio.channels.WritableByteChannel;
39 import java.nio.file.*;
40 import java.util.function.Consumer;
41
42
43
44
45
46
47
48 public class FilesystemStorage implements RepositoryStorage {
49
50 private static final Logger log = LoggerFactory.getLogger(FilesystemStorage.class);
51
52 private Path basePath;
53 private final FileLockManager fileLockManager;
54
55 public FilesystemStorage(Path basePath, FileLockManager fileLockManager) throws IOException {
56 if (!Files.exists(basePath)) {
57 Files.createDirectories(basePath);
58 }
59 this.basePath = basePath.normalize().toRealPath();
60 this.fileLockManager = fileLockManager;
61 }
62
63 private Path normalize(final String path) {
64 String nPath = path;
65 while (nPath.startsWith("/")) {
66 nPath = nPath.substring(1);
67 }
68 return Paths.get(nPath);
69 }
70
71 private Path getAssetPath(String path) throws IOException {
72 Path assetPath = basePath.resolve(normalize(path)).normalize();
73 if (!assetPath.startsWith(basePath))
74 {
75 throw new IOException("Path navigation out of allowed scope: "+path);
76 }
77 return assetPath;
78 }
79
80 @Override
81 public void consumeData(StorageAsset asset, Consumer<InputStream> consumerFunction, boolean readLock ) throws IOException
82 {
83 final Path path = asset.getFilePath();
84 try {
85 if (readLock) {
86 consumeDataLocked( path, consumerFunction );
87 } else
88 {
89 try ( InputStream is = Files.newInputStream( path ) )
90 {
91 consumerFunction.accept( is );
92 }
93 catch ( IOException e )
94 {
95 log.error("Could not read the input stream from file {}", path);
96 throw e;
97 }
98 }
99 } catch (RuntimeException e)
100 {
101 log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
102 throw new IOException( e );
103 }
104
105 }
106
107 @Override
108 public void consumeDataFromChannel( StorageAsset asset, Consumer<ReadableByteChannel> consumerFunction, boolean readLock ) throws IOException
109 {
110 final Path path = asset.getFilePath();
111 try {
112 if (readLock) {
113 consumeDataFromChannelLocked( path, consumerFunction );
114 } else
115 {
116 try ( FileChannel is = FileChannel.open( path, StandardOpenOption.READ ) )
117 {
118 consumerFunction.accept( is );
119 }
120 catch ( IOException e )
121 {
122 log.error("Could not read the input stream from file {}", path);
123 throw e;
124 }
125 }
126 } catch (RuntimeException e)
127 {
128 log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
129 throw new IOException( e );
130 }
131 }
132
133 @Override
134 public void writeData( StorageAsset asset, Consumer<OutputStream> consumerFunction, boolean writeLock ) throws IOException
135 {
136 final Path path = asset.getFilePath();
137 try {
138 if (writeLock) {
139 writeDataLocked( path, consumerFunction );
140 } else
141 {
142 try ( OutputStream is = Files.newOutputStream( path ) )
143 {
144 consumerFunction.accept( is );
145 }
146 catch ( IOException e )
147 {
148 log.error("Could not write the output stream to file {}", path);
149 throw e;
150 }
151 }
152 } catch (RuntimeException e)
153 {
154 log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
155 throw new IOException( e );
156 }
157
158 }
159
160 @Override
161 public void writeDataToChannel( StorageAsset asset, Consumer<WritableByteChannel> consumerFunction, boolean writeLock ) throws IOException
162 {
163 final Path path = asset.getFilePath();
164 try {
165 if (writeLock) {
166 writeDataToChannelLocked( path, consumerFunction );
167 } else
168 {
169 try ( FileChannel os = FileChannel.open( path, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE ))
170 {
171 consumerFunction.accept( os );
172 }
173 catch ( IOException e )
174 {
175 log.error("Could not write the data to file {}", path);
176 throw e;
177 }
178 }
179 } catch (RuntimeException e)
180 {
181 log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
182 throw new IOException( e );
183 }
184 }
185
186 private void consumeDataLocked( Path file, Consumer<InputStream> consumerFunction) throws IOException
187 {
188
189 final Lock lock;
190 try
191 {
192 lock = fileLockManager.readFileLock( file );
193 try ( InputStream is = Files.newInputStream( lock.getFile()))
194 {
195 consumerFunction.accept( is );
196 }
197 catch ( IOException e )
198 {
199 log.error("Could not read the input stream from file {}", file);
200 throw e;
201 } finally
202 {
203 fileLockManager.release( lock );
204 }
205 }
206 catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
207 {
208 log.error("Locking error on file {}", file);
209 throw new IOException(e);
210 }
211 }
212
213 private void consumeDataFromChannelLocked( Path file, Consumer<ReadableByteChannel> consumerFunction) throws IOException
214 {
215
216 final Lock lock;
217 try
218 {
219 lock = fileLockManager.readFileLock( file );
220 try ( FileChannel is = FileChannel.open( lock.getFile( ), StandardOpenOption.READ ))
221 {
222 consumerFunction.accept( is );
223 }
224 catch ( IOException e )
225 {
226 log.error("Could not read the input stream from file {}", file);
227 throw e;
228 } finally
229 {
230 fileLockManager.release( lock );
231 }
232 }
233 catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
234 {
235 log.error("Locking error on file {}", file);
236 throw new IOException(e);
237 }
238 }
239
240
241 private void writeDataLocked( Path file, Consumer<OutputStream> consumerFunction) throws IOException
242 {
243
244 final Lock lock;
245 try
246 {
247 lock = fileLockManager.writeFileLock( file );
248 try ( OutputStream is = Files.newOutputStream( lock.getFile()))
249 {
250 consumerFunction.accept( is );
251 }
252 catch ( IOException e )
253 {
254 log.error("Could not write the output stream to file {}", file);
255 throw e;
256 } finally
257 {
258 fileLockManager.release( lock );
259 }
260 }
261 catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
262 {
263 log.error("Locking error on file {}", file);
264 throw new IOException(e);
265 }
266 }
267
268 private void writeDataToChannelLocked( Path file, Consumer<WritableByteChannel> consumerFunction) throws IOException
269 {
270
271 final Lock lock;
272 try
273 {
274 lock = fileLockManager.writeFileLock( file );
275 try ( FileChannel is = FileChannel.open( lock.getFile( ), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE ))
276 {
277 consumerFunction.accept( is );
278 }
279 catch ( IOException e )
280 {
281 log.error("Could not write to file {}", file);
282 throw e;
283 } finally
284 {
285 fileLockManager.release( lock );
286 }
287 }
288 catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
289 {
290 log.error("Locking error on file {}", file);
291 throw new IOException(e);
292 }
293 }
294
295 @Override
296 public URI getLocation() {
297 return basePath.toUri();
298 }
299
300
301
302
303
304
305
306
307 @Override
308 public void updateLocation(URI newLocation) throws IOException {
309 Path newPath = PathUtil.getPathFromUri(newLocation).toAbsolutePath();
310 if (!Files.exists(newPath)) {
311 Files.createDirectories(newPath);
312 }
313 basePath = newPath;
314 if (fileLockManager!=null) {
315 fileLockManager.clearLockFiles();
316 }
317 }
318
319 @Override
320 public StorageAsset getAsset( String path )
321 {
322 try {
323 return new FilesystemAsset(this, path, getAssetPath(path));
324 } catch (IOException e) {
325 throw new IllegalArgumentException("Path navigates outside of base directory "+path);
326 }
327 }
328
329 @Override
330 public StorageAsset addAsset( String path, boolean container )
331 {
332 try {
333 return new FilesystemAsset(this, path, getAssetPath(path), basePath, container);
334 } catch (IOException e) {
335 throw new IllegalArgumentException("Path navigates outside of base directory "+path);
336 }
337 }
338
339 @Override
340 public void removeAsset( StorageAsset asset ) throws IOException
341 {
342 Files.delete(asset.getFilePath());
343 }
344
345 @Override
346 public StorageAsset./../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset moveAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
347 {
348 boolean container = origin.isContainer();
349 FilesystemAssete/FilesystemAsset.html#FilesystemAsset">FilesystemAsset newAsset = new FilesystemAsset(this, destination, getAssetPath(destination), basePath, container );
350 moveAsset( origin, newAsset, copyOptions );
351 return newAsset;
352 }
353
354 @Override
355 public void moveAsset( StorageAsset./../../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
356 {
357 if (origin.getStorage()!=this) {
358 throw new IOException("The origin asset does not belong to this storage instance. Cannot copy between different storage instances.");
359 }
360 if (destination.getStorage()!=this) {
361 throw new IOException("The destination asset does not belong to this storage instance. Cannot copy between different storage instances.");
362 }
363 Files.move(origin.getFilePath(), destination.getFilePath(), copyOptions);
364 }
365
366 @Override
367 public StorageAsset./../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset copyAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
368 {
369 boolean container = origin.isContainer();
370 FilesystemAssete/FilesystemAsset.html#FilesystemAsset">FilesystemAsset newAsset = new FilesystemAsset(this, destination, getAssetPath(destination), basePath, container );
371 copyAsset( origin, newAsset, copyOptions );
372 return newAsset;
373 }
374
375 @Override
376 public void copyAsset( StorageAsset./../../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
377 {
378 if (origin.getStorage()!=this) {
379 throw new IOException("The origin asset does not belong to this storage instance. Cannot copy between different storage instances.");
380 }
381 if (destination.getStorage()!=this) {
382 throw new IOException("The destination asset does not belong to this storage instance. Cannot copy between different storage instances.");
383 }
384 Path destinationPath = destination.getFilePath();
385 boolean overwrite = false;
386 for (int i=0; i<copyOptions.length; i++) {
387 if (copyOptions[i].equals( StandardCopyOption.REPLACE_EXISTING )) {
388 overwrite=true;
389 }
390 }
391 if (Files.exists(destinationPath) && !overwrite) {
392 throw new IOException("Destination file exists already "+ destinationPath);
393 }
394 if (Files.isDirectory( origin.getFilePath() ))
395 {
396 FileUtils.copyDirectory(origin.getFilePath( ).toFile(), destinationPath.toFile() );
397 } else if (Files.isRegularFile( origin.getFilePath() )) {
398 if (!Files.exists( destinationPath )) {
399 Files.createDirectories( destinationPath );
400 }
401 Files.copy( origin.getFilePath( ), destinationPath, copyOptions );
402 }
403 }
404
405 public FileLockManager getFileLockManager() {
406 return fileLockManager;
407 }
408
409 }