1 package org.apache.archiva.repository.storage;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.archiva.common.filelock.FileLockException;
23 import org.apache.archiva.common.filelock.FileLockManager;
24 import org.apache.archiva.common.filelock.Lock;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
28 import java.io.IOException;
29 import java.nio.channels.FileChannel;
30 import java.nio.file.*;
31 import java.util.HashSet;
35 * Utility class for assets. Allows to copy, move between different storage instances and
36 * recursively consume the tree.
38 * @author Martin Stockhammer <martin_s@apache.org>
40 public class FsStorageUtil
42 private static final Logger log = LoggerFactory.getLogger( FsStorageUtil.class);
45 * Copies the source asset to the target. The assets may be from different RepositoryStorage instances.
46 * If you know that source and asset are from the same storage instance, the copy method of the storage
47 * instance may be faster.
49 * @param source The source asset
50 * @param target The target asset
51 * @param locked If true, a readlock is set on the source and a write lock is set on the target.
52 * @param copyOptions Copy options
55 public static final void copyAsset( final StorageAsset source,
56 final StorageAsset target,
58 final CopyOption... copyOptions ) throws IOException
60 if (source.isFileBased() && target.isFileBased()) {
61 // Short cut for FS operations
62 final Path sourcePath = source.getFilePath();
63 final Path targetPath = target.getFilePath( );
65 final FileLockManager lmSource = ((FilesystemStorage)source.getStorage()).getFileLockManager();
66 final FileLockManager lmTarget = ((FilesystemStorage)target.getStorage()).getFileLockManager();
68 Lock lockWrite = null;
70 lockRead = lmSource.readFileLock(sourcePath);
71 } catch (Exception e) {
72 log.error("Could not create read lock on {}", sourcePath);
73 throw new IOException(e);
76 lockWrite = lmTarget.writeFileLock(targetPath);
77 } catch (Exception e) {
78 log.error("Could not create write lock on {}", targetPath);
79 throw new IOException(e);
82 Files.copy(sourcePath, targetPath, copyOptions);
86 lmSource.release(lockRead);
87 } catch (FileLockException e) {
88 log.error("Error during lock release of read lock {}", lockRead.getFile());
91 if (lockWrite!=null) {
93 lmTarget.release(lockWrite);
94 } catch (FileLockException e) {
95 log.error("Error during lock release of write lock {}", lockWrite.getFile());
101 Files.copy( sourcePath, targetPath, copyOptions );
105 final RepositoryStorage sourceStorage = source.getStorage();
106 final RepositoryStorage targetStorage = target.getStorage();
107 sourceStorage.consumeDataFromChannel( source, is -> org.apache.archiva.repository.storage.util.StorageUtil.wrapWriteFunction( is, targetStorage, target, locked ), locked);
108 } catch (IOException e) {
110 } catch (Throwable e) {
111 Throwable cause = e.getCause();
112 if (cause instanceof IOException) {
113 throw (IOException)cause;
116 throw new IOException( e );
123 public static final void copyToLocalFile(StorageAsset asset, Path destination, CopyOption... copyOptions) throws IOException {
124 if (asset.isFileBased()) {
125 Files.copy(asset.getFilePath(), destination, copyOptions);
129 HashSet<OpenOption> openOptions = new HashSet<>();
130 for (CopyOption option : copyOptions) {
131 if (option == StandardCopyOption.REPLACE_EXISTING) {
132 openOptions.add(StandardOpenOption.CREATE);
133 openOptions.add(StandardOpenOption.TRUNCATE_EXISTING);
134 openOptions.add(StandardOpenOption.WRITE);
136 openOptions.add(StandardOpenOption.WRITE);
137 openOptions.add(StandardOpenOption.CREATE_NEW);
140 asset.getStorage().consumeDataFromChannel(asset, channel -> {
142 FileChannel.open(destination, openOptions).transferFrom(channel, 0, Long.MAX_VALUE);
143 } catch (IOException e) {
144 throw new RuntimeException(e);
147 } catch (Throwable e) {
148 if (e.getCause() instanceof IOException) {
149 throw (IOException)e.getCause();
151 throw new IOException(e);
157 public static class PathInformation {
159 final boolean tmpFile;
161 PathInformation(Path path, boolean tmpFile) {
163 this.tmpFile = tmpFile;
166 public Path getPath() {
170 public boolean isTmpFile() {
176 public static final PathInformation getAssetDataAsPath(StorageAsset asset) throws IOException {
177 if (!asset.exists()) {
178 throw new IOException("Asset does not exist");
180 if (asset.isFileBased()) {
181 return new PathInformation(asset.getFilePath(), false);
183 Path tmpFile = Files.createTempFile(asset.getName(), org.apache.archiva.repository.storage.util.StorageUtil.getExtension(asset));
184 copyToLocalFile(asset, tmpFile, StandardCopyOption.REPLACE_EXISTING);
185 return new PathInformation(tmpFile, true);