Commit 7a090433 authored by Matija Obreza's avatar Matija Obreza

Repository path must be absolute (starting with /)

parent 62cf100e
Pipeline #6705 failed with stage
in 3 minutes and 26 seconds
......@@ -41,8 +41,9 @@ public interface ImageGalleryService {
* @param path Image gallery path in the repository
* @return the ImageGallery or <code>null</code> if no gallery exists at the
* specified path.
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
ImageGallery loadImageGallery(Path path);
ImageGallery loadImageGallery(Path path) throws InvalidRepositoryPathException;
/**
* Create a gallery at the specified path if it does not exist. Path of the
......@@ -52,7 +53,7 @@ public interface ImageGalleryService {
* @param title Image gallery title in English.
* @param description Image gallery description in English.
* @return the new ImageGallery or existing gallery at the specified path.
* @throws InvalidRepositoryPathException
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
ImageGallery createImageGallery(Path path, String title, String description) throws InvalidRepositoryPathException;
......@@ -60,7 +61,7 @@ public interface ImageGalleryService {
* Delete the image gallery, but don't remove the images at that path.
*
* @param imageGallery the image gallery
* @throws InvalidRepositoryPathException the invalid repository path exception
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
void removeGallery(ImageGallery imageGallery) throws InvalidRepositoryPathException;
......@@ -108,7 +109,7 @@ public interface ImageGalleryService {
* @param prefix the prefix
* @param pageable the pageable
* @return paginated image gallery data
* @throws InvalidRepositoryPathException
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
Page<ImageGallery> listImageGalleries(Path root, Pageable pageable) throws InvalidRepositoryPathException;
......
......@@ -50,7 +50,7 @@ public interface RepositoryService {
* @param bytes the bytes
* @param metaData the meta data
* @return the repository file
* @throws InvalidRepositoryPathException the invalid repository path exception
* @throws InvalidRepositoryPathException if path is not a valid repository path
* @throws InvalidRepositoryFileDataException the invalid repository file data
* exception
* @throws IOException when things go wrong on bytes storage level
......@@ -67,7 +67,7 @@ public interface RepositoryService {
* @param bytes the bytes
* @param metaData the meta data
* @return the repository image
* @throws InvalidRepositoryPathException the invalid repository path exception
* @throws InvalidRepositoryPathException if path is not a valid repository path
* @throws InvalidRepositoryFileDataException the invalid repository file data
* exception
* @throws IOException when things go wrong on bytes storage level
......@@ -103,9 +103,10 @@ public interface RepositoryService {
* @param path the path
* @param filename the filename
* @return the file
* @throws InvalidRepositoryPathException if path is not a valid repository path
* @throws NoSuchRepositoryFileException the no such repository file exception
*/
RepositoryFile getFile(Path path, String filename) throws NoSuchRepositoryFileException;
RepositoryFile getFile(Path path, String filename) throws NoSuchRepositoryFileException, InvalidRepositoryPathException;
/**
* Get repository file bytes by its path and filename.
......@@ -131,9 +132,10 @@ public interface RepositoryService {
*
* @param folderPath the folder path
* @return the files
* @throws InvalidRepositoryPathException if path is not a valid repository path
* @throws NoSuchRepositoryFileException
*/
List<RepositoryFile> getFiles(Path folderPath);
List<RepositoryFile> getFiles(Path folderPath) throws InvalidRepositoryPathException;
/**
* Stream file info at the specified repository path.
......@@ -199,7 +201,7 @@ public interface RepositoryService {
* @param newPath the new path
* @return the repository file
* @throws NoSuchRepositoryFileException the no such repository file exception
* @throws InvalidRepositoryPathException when the new path is invalid
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
RepositoryFile moveFile(RepositoryFile repositoryFile, Path target) throws NoSuchRepositoryFileException, InvalidRepositoryPathException;
......@@ -209,7 +211,7 @@ public interface RepositoryService {
* @param repositoryFile the repository file
* @param fullPath the full path
* @return the repository file
* @throws InvalidRepositoryPathException the invalid repository path exception
* @throws InvalidRepositoryPathException if path is not a valid repository path
* @throws InvalidRepositoryFileDataException the invalid repository file data
* exception
*/
......@@ -229,7 +231,7 @@ public interface RepositoryService {
*
* @param prefix the prefix
* @return the list
* @throws InvalidRepositoryPathException the invalid repository path exception
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
List<RepositoryFolder> listPaths(Path root) throws InvalidRepositoryPathException;
......@@ -259,15 +261,16 @@ public interface RepositoryService {
*
* @param folderPath the folder path
* @return the folder
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
RepositoryFolder getFolder(Path folderPath);
RepositoryFolder getFolder(Path folderPath) throws InvalidRepositoryPathException;
/**
* Test if repository contains the path.
*
* @param path the path
* @return true if at least one entry exists at specified path
* @throws InvalidRepositoryPathException the invalid repository path exception
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
boolean hasPath(Path path) throws InvalidRepositoryPathException;
......@@ -277,7 +280,7 @@ public interface RepositoryService {
* @param currentPath the current path
* @param newPath the new path
* @return Repository folder of the new path
* @throws InvalidRepositoryPathException the invalid repository path exception
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
RepositoryFolder renamePath(Path currentPath, Path newPath) throws InvalidRepositoryPathException;
......@@ -297,15 +300,17 @@ public interface RepositoryService {
* @param string repository path
* @return the deleted repository folder
* @throws FolderNotEmptyException if folder contains sub-folders or files
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
RepositoryFolder deleteFolder(Path path) throws FolderNotEmptyException;
RepositoryFolder deleteFolder(Path path) throws FolderNotEmptyException, InvalidRepositoryPathException;
/**
* Get subfolders of root
*
* @param root
* @return
* @throws InvalidRepositoryPathException if path is not a valid repository path
*/
List<RepositoryFolder> getFolders(Path root);
List<RepositoryFolder> getFolders(Path root) throws InvalidRepositoryPathException;
}
......@@ -20,6 +20,8 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.genesys.filerepository.FileRepositoryException;
import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.model.RepositoryImage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -47,7 +49,13 @@ public abstract class AbstractImageGalleryAspects {
LOG.debug("Many images were saved: {}", repositoryImages);
if (repositoryImages != null) {
repositoryImages.forEach(ri -> addImageToGallery(ri));
repositoryImages.forEach(ri -> {
try {
addImageToGallery(ri);
} catch (FileRepositoryException e) {
LOG.error("Error adding image to gallery: {}", e.getMessage(), e);
}
});
}
return repositoryImages;
......@@ -57,8 +65,9 @@ public abstract class AbstractImageGalleryAspects {
* Adds the image to gallery.
*
* @param repositoryImage the repository image
* @throws InvalidRepositoryPathException
*/
protected abstract void addImageToGallery(RepositoryImage repositoryImage);
protected abstract void addImageToGallery(RepositoryImage repositoryImage) throws InvalidRepositoryPathException;
/**
* After repository image save.
......@@ -116,6 +125,7 @@ public abstract class AbstractImageGalleryAspects {
* Removes the image from gallery.
*
* @param repositoryImage the repository image
* @throws InvalidRepositoryPathException
*/
protected abstract void removeImageFromGallery(RepositoryImage repositoryImage);
protected abstract void removeImageFromGallery(RepositoryImage repositoryImage) throws InvalidRepositoryPathException;
}
\ No newline at end of file
......@@ -76,9 +76,10 @@ public class ImageGalleryAspectsImpl extends AbstractImageGalleryAspects impleme
* add it to the gallery if it exists.
*
* @param repositoryImage the repository image
* @throws InvalidRepositoryPathException
*/
@Override
public void addImageToGallery(final RepositoryImage repositoryImage) {
public void addImageToGallery(final RepositoryImage repositoryImage) throws InvalidRepositoryPathException {
if (repositoryImage == null) {
return;
}
......@@ -111,9 +112,10 @@ public class ImageGalleryAspectsImpl extends AbstractImageGalleryAspects impleme
* Check if image is part of a gallery at the specified path and remove it.
*
* @param repositoryImage the repository image
* @throws InvalidRepositoryPathException
*/
@Override
public void removeImageFromGallery(final RepositoryImage repositoryImage) {
public void removeImageFromGallery(final RepositoryImage repositoryImage) throws InvalidRepositoryPathException {
if (repositoryImage == null) {
return;
}
......
......@@ -18,7 +18,6 @@ package org.genesys.filerepository.service.aspect;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
......
......@@ -50,9 +50,8 @@ import org.springframework.util.CollectionUtils;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
// TODO: Auto-generated Javadoc
/**
* The Class ImageGalleryServiceImpl.
* Image Gallery service
*/
@Service
@Transactional(readOnly = true)
......@@ -89,7 +88,8 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
*/
@Override
@PostAuthorize("returnObject == null or hasRole('ADMINISTRATOR') or hasPermission(returnObject, 'read')")
public ImageGallery loadImageGallery(final Path path) {
public ImageGallery loadImageGallery(final Path path) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(path);
final ImageGallery imageGallery = imageGalleryPersistence.findByFolder(repositoryService.getFolder(path));
return deepLoad(imageGallery);
}
......@@ -118,9 +118,15 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
@Transactional
@PreAuthorize("isAuthenticated()")
public ImageGallery createImageGallery(final Path path, final String title, final String description) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(path);
if (path.normalize().toAbsolutePath().toString().equals("/")) {
throw new InvalidRepositoryPathException("Image gallery cannot be created at " + path);
}
LOG.debug("Creating ImageGallery at path={}", path);
RepositoryFolder repositoryFolder = repositoryService.ensureFolder(path.normalize().toAbsolutePath());
RepositoryFolder repositoryFolder = repositoryService.ensureFolder(path);
ImageGallery imageGallery = imageGalleryPersistence.findByFolder(repositoryFolder);
if (imageGallery != null) {
......@@ -134,7 +140,7 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
LOG.info("Creating new image gallery at path={}", path);
imageGallery = new ImageGallery();
imageGallery.setFolder(repositoryFolder);
imageGallery.setPath(path.normalize().toAbsolutePath().toString());
imageGallery.setPath(path.toString());
imageGallery.setTitle(title);
imageGallery.setDescription(description);
......@@ -325,6 +331,7 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
*/
@Override
public Page<ImageGallery> listImageGalleries(final Path root, final Pageable pageable) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(root);
List<RepositoryFolder> folders = repositoryService.listPaths(root);
// Remove folders user can't read
folders.removeIf(folder -> !SecurityContextUtil.hasRole("ADMINISTRATOR") && !SecurityContextUtil.hasPermission(folder, "READ"));
......
......@@ -88,6 +88,8 @@ public class PathValidator {
public static void checkValidPath(Path repositoryPath) throws InvalidRepositoryPathException {
if (repositoryPath == null) {
throw new InvalidRepositoryPathException("null path not allowed");
} else if (! repositoryPath.isAbsolute()) {
throw new InvalidRepositoryPathException("Path must be absolute. Path was " + repositoryPath);
}
checkValidPath(repositoryPath.normalize().toAbsolutePath().toString());
}
......
......@@ -313,7 +313,9 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
*/
@Override
@PostAuthorize("hasRole('ADMINISTRATOR') or hasPermission(returnObject, 'read')")
public RepositoryFile getFile(final Path path, final String originalFilename) throws NoSuchRepositoryFileException {
public RepositoryFile getFile(final Path path, final String originalFilename) throws NoSuchRepositoryFileException, InvalidRepositoryPathException {
PathValidator.checkValidPath(path);
RepositoryFolder folder = folderRepository.findByPath(path.toString());
if (folder == null) {
throw new NoSuchRepositoryFileException("No file at path=" + path + " originalFilename=" + originalFilename);
......@@ -332,6 +334,9 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
* @see org.genesys.filerepository.service.RepositoryService#getFileBytes
* (java.lang.String, java.lang.String)
*/
/**
* @deprecated Permission check not possible, use {@link #getFileBytes(RepositoryFile)}
*/
@Override
public byte[] getFileBytes(final Path filePath) throws NoSuchRepositoryFileException {
byte[] data = null;
......@@ -364,7 +369,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
* Path)
*/
@Override
public List<RepositoryFile> getFiles(Path folderPath) {
public List<RepositoryFile> getFiles(Path folderPath) throws InvalidRepositoryPathException {
RepositoryFolder folder = getFolder(folderPath);
if (folder == null) {
return Collections.emptyList();
......@@ -379,7 +384,8 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
* .Path)
*/
@Override
public List<RepositoryFolder> getFolders(Path root) {
public List<RepositoryFolder> getFolders(Path root) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(root);
if (root == null || "/".equals(root.normalize().toAbsolutePath().toString())) {
return (List<RepositoryFolder>) folderRepository.findAll(QRepositoryFolder.repositoryFolder.parent.isNull());
} else {
......@@ -391,7 +397,8 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
}
@Override
public RepositoryFolder getFolder(Path folderPath) {
public RepositoryFolder getFolder(Path folderPath) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(folderPath);
return folderRepository.findByPath(folderPath.normalize().toAbsolutePath().toString());
}
......@@ -403,6 +410,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
*/
@Override
public Stream<RepositoryFile> streamFiles(Path root) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(root);
BooleanExpression q = QRepositoryFile.repositoryFile.folder.in(listPaths(root));
return StreamSupport.stream(repositoryFilePersistence.findAll(q).spliterator(), false);
}
......@@ -693,6 +701,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
*/
@Override
public boolean hasPath(final Path path) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(path);
final String p = path.normalize().toAbsolutePath().toString();
PathValidator.checkValidPath(p);
LOG.trace("Is directory path={}", p);
......@@ -742,6 +751,9 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
@Override
@Transactional
public RepositoryFolder renamePath(final Path currentPath, final Path newPath) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(currentPath);
PathValidator.checkValidPath(newPath);
final Path cPath = currentPath.normalize().toAbsolutePath();
final Path nPath = newPath.normalize().toAbsolutePath();
PathValidator.checkValidPath(cPath.toString());
......@@ -780,6 +792,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
@Override
@Transactional
public RepositoryFolder ensureFolder(Path folderPath) throws InvalidRepositoryPathException {
PathValidator.checkValidPath(folderPath);
folderPath = folderPath.normalize().toAbsolutePath();
PathValidator.checkValidPath(folderPath.toString());
......@@ -822,7 +835,8 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
*/
@Override
@Transactional
public RepositoryFolder deleteFolder(Path path) throws FolderNotEmptyException {
public RepositoryFolder deleteFolder(Path path) throws FolderNotEmptyException, InvalidRepositoryPathException {
PathValidator.checkValidPath(path);
final Path cPath = path.normalize().toAbsolutePath();
RepositoryFolder folder = folderRepository.findByPath(cPath.toString());
......
......@@ -224,7 +224,7 @@ public class FileRepositoryAddTest extends RepositoryServiceTest {
* exception
* @throws IOException
*/
@Test // no longer (expected = InvalidRepositoryPathException.class)
@Test(expected = InvalidRepositoryPathException.class)
public void invalidAddMissingStartSlash() throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException {
repositoryService.addFile(Paths.get("invalidpath/here/"), "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null);
}
......
......@@ -97,9 +97,10 @@ public class FileRepositoryUpdateTest extends RepositoryServiceTest {
/**
* Test basic submission to file repository.
* @throws NoSuchRepositoryFileException
* @throws InvalidRepositoryPathException
*/
@Test
public void fetchFilesByPath() throws NoSuchRepositoryFileException {
public void fetchFilesByPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException {
final List<RepositoryFile> repoFiles = repositoryService.getFiles(initialPath);
assertThat("List should have one element", repoFiles.size(), is(1));
......
......@@ -73,7 +73,7 @@ public class ImageGalleryTest extends RepositoryServiceTest {
@Autowired
private ImageGalleryPersistence galleryRepository;
/**
* After test.
*/
......@@ -86,16 +86,38 @@ public class ImageGalleryTest extends RepositoryServiceTest {
/**
* Load missing gallery.
* @throws InvalidRepositoryPathException
*/
@Test
public void loadMissingGallery() {
final ImageGallery imageGallery = imageGalleryService.loadImageGallery(Paths.get("no-such-gallery/" + timestamp));
public void loadMissingGallery() throws InvalidRepositoryPathException {
final ImageGallery imageGallery = imageGalleryService.loadImageGallery(Paths.get("/no-such-gallery/" + timestamp));
assertThat("Must be null", imageGallery, nullValue());
}
/**
* Gallery path must not be "" folder
*
* @throws InvalidRepositoryPathException
*/
@Test(expected = InvalidRepositoryPathException.class)
public void createGalleryOnBlank() throws InvalidRepositoryPathException {
imageGalleryService.createImageGallery(Paths.get(""), DEFAULT_GALLERY_TITLE, DEFAULT_GALLERY_DESCRIPTION);
}
/**
* Gallery path must not be / folder
*
* @throws InvalidRepositoryPathException
*/
@Test(expected = InvalidRepositoryPathException.class)
public void createGalleryOnRoot() throws InvalidRepositoryPathException {
imageGalleryService.createImageGallery(Paths.get("/"), DEFAULT_GALLERY_TITLE, DEFAULT_GALLERY_DESCRIPTION);
}
/**
* Creates the gallery.
* @throws InvalidRepositoryPathException
*
* @throws InvalidRepositoryPathException
*/
@Test
public void createGallery() throws InvalidRepositoryPathException {
......@@ -135,7 +157,8 @@ public class ImageGalleryTest extends RepositoryServiceTest {
/**
* Creates the gallery update blah.
* @throws InvalidRepositoryPathException
*
* @throws InvalidRepositoryPathException
*/
@Test
public void createGalleryUpdateBlah() throws InvalidRepositoryPathException {
......@@ -196,14 +219,16 @@ public class ImageGalleryTest extends RepositoryServiceTest {
// Add an image to the gallery path
final TestImage image1 = new TestImage("10x10.png", "image/png");
final RepositoryImage repoImage1 = (RepositoryImage) fileRepoService.addFile(initialPath, image1.getOriginalFilename(), image1.getContentType(), image1.getImageBytes(), null);
final RepositoryImage repoImage1 = (RepositoryImage) fileRepoService.addFile(initialPath, image1.getOriginalFilename(), image1.getContentType(), image1.getImageBytes(),
null);
// Expect the image to be included in the list!
assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(initialPath).getImages(), contains(repoImage1));
// Add an image to the gallery path
final TestImage image2 = new TestImage("11x10.png", "image/png");
final RepositoryImage repoImage2 = (RepositoryImage) fileRepoService.addFile(initialPath, image2.getOriginalFilename(), image2.getContentType(), image2.getImageBytes(), null);
final RepositoryImage repoImage2 = (RepositoryImage) fileRepoService.addFile(initialPath, image2.getOriginalFilename(), image2.getContentType(), image2.getImageBytes(),
null);
assertThat("Image gallery must include both images!", imageGalleryService.loadImageGallery(initialPath).getImages(), contains(repoImage1, repoImage2));
......@@ -372,7 +397,6 @@ public class ImageGalleryTest extends RepositoryServiceTest {
fileRepoService.removeFile(repoImage2);
fileRepoService.removeFile(repoImage1);
}
/**
* Delete gallery.
......@@ -388,7 +412,7 @@ public class ImageGalleryTest extends RepositoryServiceTest {
Page<ImageGallery> page = imageGalleryService.listImageGalleries(new PageRequest(0, 3));
assertThat(page.getContent().size(), is(3));
assertThat(page.getTotalElements(), is(3l));
page = imageGalleryService.listImageGalleries(new PageRequest(0, 2));
assertThat(page.getContent().size(), is(2));
assertThat(page.getTotalElements(), is(3l));
......
......@@ -31,7 +31,7 @@ import org.apache.ftpserver.ftplet.FileSystemView;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.FtpFile;
import org.apache.ftpserver.ftplet.User;
import org.genesys.filerepository.FolderNotEmptyException;
import org.genesys.filerepository.FileRepositoryException;
import org.genesys.filerepository.InvalidRepositoryFileDataException;
import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.NoSuchRepositoryFileException;
......@@ -180,12 +180,16 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ
@Override
public List<? extends FtpFile> listFiles() {
return FtpRunAs.asFtpUser(session.user, () -> {
return _listFiles();
});
try {
return FtpRunAs.asFtpUser(session.user, () -> {
return _listFiles();
});
} catch (FileRepositoryException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private List<? extends FtpFile> _listFiles() {
private List<? extends FtpFile> _listFiles() throws InvalidRepositoryPathException {
final Path root = path.normalize().toAbsolutePath();
LOG.debug("Listing files in path={}", root);
final ArrayList<FtpFile> all = new ArrayList<>();
......@@ -225,7 +229,7 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ
try {
repositoryService.deleteFolder(path);
return true;
} catch (FolderNotEmptyException e) {
} catch (FileRepositoryException e) {
return false;
}
});
......@@ -273,6 +277,8 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ
} catch (final AuthenticationException e) {
LOG.warn("Authentication problem {}", e.getMessage(), e);
throw new AuthenticationFailedException(e.getMessage());
} catch (InvalidRepositoryPathException e) {
throw new FtpException(e.getMessage());
} catch (NoSuchRepositoryFileException e) {
LOG.warn("No such file {}", file);
......@@ -312,6 +318,8 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ
}
}
};
} catch (FileRepositoryException e) {
throw new FtpException(e.getMessage());
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment