I've created a service that connects to Dropbox and makes it possible to download and upload files, create and list folders and remove file or folder.
Full code is available on GitHub: https://github.com/MajewskiKrzysztof/spring-boot-dropbox
DropboxConfiguration
@Configurationclass DropboxConfiguration { @Value("${dropbox.accessToken}") private String accessToken; @Bean public DbxClientV2 dropboxClient() { DbxRequestConfig config = DbxRequestConfig.newBuilder("example-app").build(); return new DbxClientV2(config, accessToken); }}
DropboxServiceImpl
@Serviceclass DropboxServiceImpl implements DropboxService { private final DbxClientV2 client; public DropboxServiceImpl(DbxClientV2 client) { this.client = client; } @Override public InputStream downloadFile(String filePath) throws DropboxException { return handleDropboxAction(() -> client.files().download(filePath).getInputStream(), String.format("Error downloading file: %s", filePath)); } @Override public FileMetadata uploadFile(String filePath, InputStream fileStream) throws DropboxException { return handleDropboxAction(() -> client.files().uploadBuilder(filePath).uploadAndFinish(fileStream), String.format("Error uploading file: %s", filePath)); } @Override public CreateFolderResult createFolder(String folderPath) { return handleDropboxAction(() -> client.files().createFolderV2(folderPath), "Error creating folder"); } @Override public FolderMetadata getFolderDetails(String folderPath) throws DropboxException { return getMetadata(folderPath, FolderMetadata.class, String.format("Error getting folder details: %s", folderPath)); } @Override public FileMetadata getFileDetails(String filePath) throws DropboxException { return getMetadata(filePath, FileMetadata.class, String.format("Error getting file details: %s", filePath)); } @Override public ListFolderResult listFolder(String folderPath, Boolean recursiveListing, Long limit) throws DropboxException { ListFolderBuilder listFolderBuilder = client.files().listFolderBuilder(folderPath); if (Objects.nonNull(recursiveListing)) { listFolderBuilder.withRecursive(recursiveListing); } if (Objects.nonNull(limit)) { listFolderBuilder.withLimit(limit); } return handleDropboxAction(listFolderBuilder::start, String.format("Error listing folder: %s", folderPath)); } @Override public ListFolderResult listFolderContinue(String cursor) throws DropboxException { return handleDropboxAction(() -> client.files().listFolderContinue(cursor), "Error listing folder"); } @Override public void deleteFile(String filePath) { handleDropboxAction(() -> client.files().deleteV2(filePath), String.format("Error deleting file: %s", filePath)); } @Override public void deleteFolder(String folderPath) { handleDropboxAction(() -> client.files().deleteV2(folderPath), String.format("Error deleting folder: %s", folderPath)); } private <T> T handleDropboxAction(DropboxActionResolver<T> action, String exceptionMessage) { try { return action.perform(); } catch (Exception e) { String messageWithCause = String.format("%s with cause: %s", exceptionMessage, e.getMessage()); throw new DropboxException(messageWithCause, e); } } @SuppressWarnings("unchecked") private <T> T getMetadata(String path, Class<T> type, String message) { Metadata metadata = handleDropboxAction(() -> client.files().getMetadata(path), String.format("Error accessing details of: %s", path)); checkIfMetadataIsInstanceOfGivenType(metadata, type, message); return (T) metadata; } private <T> void checkIfMetadataIsInstanceOfGivenType(Metadata metadata, Class<T> validType, String exceptionMessage) { boolean isValidType = validType.isInstance(metadata); if (!isValidType) { throw new DropboxException(exceptionMessage); } }}
DropboxIntTest
@RunWith(SpringRunner.class)@SpringBootTest(classes = SpringBootSharepointRestApplication.class)public class DropboxIntTest { private static final String TEST_FOLDER_PATH = "/Test Folder"; private static final String TEST_FILE_PATH = String.format("%s/%s", TEST_FOLDER_PATH, "testFile.txt"); private static final Integer TEST_FILE_SIZE = 17; @Autowired private DropboxService dropboxService; @Rule public final ExpectedException exceptions = ExpectedException.none(); @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before public void createTestFolder() throws Exception { dropboxService.createFolder(TEST_FOLDER_PATH); File tempUploadFile = temporaryFolder.newFile("testFile.txt"); FileUtils.writeStringToFile(tempUploadFile, "test file content", "UTF-8"); String testFilePath = String.format("%s/%s", TEST_FOLDER_PATH, "testFile.txt"); dropboxService.uploadFile(testFilePath, new FileInputStream(tempUploadFile)); } @After public void deleteTestFolder() { dropboxService.deleteFolder(TEST_FOLDER_PATH); } @Test public void downloadFile_shouldReturnNotEmptyInputStream() throws Exception { InputStream inputStream = dropboxService.downloadFile(TEST_FILE_PATH); assertThat(inputStream.available()).isEqualTo(TEST_FILE_SIZE); } @Test public void downloadFile_shouldThrowExceptionIfFileNotExists() { exceptions.expect(DropboxException.class); dropboxService.downloadFile("not-existing-file"); } @Test public void uploadFile_shouldReturnUploadedFileDetails() throws Exception { File tempUploadFile = temporaryFolder.newFile("teamLogo.png"); String filePath = String.format("%s/%s", TEST_FOLDER_PATH, tempUploadFile.getName()); FileMetadata fileMetadata = dropboxService.uploadFile(filePath, new FileInputStream(tempUploadFile)); assertThat(fileMetadata.getId()).isNotBlank(); } @Test public void uploadFile_shouldCreateFolderIfNotExists() throws Exception { File tempUploadFile = temporaryFolder.newFile("teamLogo.png"); String filePath = String.format("%s/%s/%s", TEST_FOLDER_PATH, "not existing folder", tempUploadFile.getName()); dropboxService.uploadFile(filePath, new FileInputStream(tempUploadFile)); FolderMetadata folderDetails = dropboxService .getFolderDetails(String.format("%s/%s", TEST_FOLDER_PATH, "not existing folder")); assertThat(folderDetails.getId()).isNotBlank(); } @Test public void createFolder_shouldCreateFolder() { String folderPath = String.format("%s/%s", TEST_FOLDER_PATH, "new folder"); CreateFolderResult folder = dropboxService.createFolder(folderPath); FolderMetadata folderDetails = dropboxService.getFolderDetails(folderPath); assertThat(folderDetails.getId()).isNotBlank(); assertThat(folderDetails.getId()).isEqualToIgnoringCase(folder.getMetadata().getId()); } @Test public void createFolder_shouldThrowExceptionIfFolderAlreadyExists() { String folderPath = String.format("%s/%s", TEST_FOLDER_PATH, "new folder"); dropboxService.createFolder(folderPath); exceptions.expect(DropboxException.class); dropboxService.createFolder(folderPath); } @Test public void getFolderDetails_shouldReturnFolderDetails() { FolderMetadata folderDetails = dropboxService.getFolderDetails(TEST_FOLDER_PATH); assertThat(folderDetails.getId()).isNotBlank(); assertThat(folderDetails.getName()).isNotBlank(); assertThat(folderDetails.getPathDisplay()).isNotBlank(); } @Test public void getFolderDetails_shouldThrowExceptionIfFolderNotExists() { exceptions.expect(DropboxException.class); dropboxService.getFolderDetails("/not existing folder"); } @Test public void getFileDetails_shouldReturnFileDetails() { FileMetadata fileDetails = dropboxService.getFileDetails(TEST_FILE_PATH); assertThat(fileDetails.getId()).isNotBlank(); assertThat(fileDetails.getPathDisplay()).isNotBlank(); assertThat(fileDetails.getName()).isNotBlank(); assertThat(fileDetails.getSize()).isEqualTo(TEST_FILE_SIZE.longValue()); assertThat(fileDetails.getServerModified()).isNotNull(); assertThat(fileDetails.getServerModified()).isBefore(new Date()); } @Test public void getFileDetails_shouldThrowExceptionIfFileNotExists() { exceptions.expect(DropboxException.class); dropboxService.getFileDetails("/not-existing-file.pdf"); } @Test public void listFolder_shouldReturnFolderItems() throws Exception { File tempUploadFile1 = temporaryFolder.newFile("testFile2.txt"); FileUtils.writeStringToFile(tempUploadFile1, "test file content", "UTF-8"); String testFilePath1 = String.format("%s/%s", TEST_FOLDER_PATH, "testFile2.txt"); dropboxService.uploadFile(testFilePath1, new FileInputStream(tempUploadFile1)); File tempUploadFile2 = temporaryFolder.newFile("testFile3.txt"); FileUtils.writeStringToFile(tempUploadFile2, "test file content", "UTF-8"); String testFilePath2 = String.format("%s/%s/%s", TEST_FOLDER_PATH, "inner folder", "testFile3.txt"); dropboxService.uploadFile(testFilePath2, new FileInputStream(tempUploadFile2)); ListFolderResult listFolderResult = dropboxService.listFolder(TEST_FOLDER_PATH, true, 10L); assertThat(listFolderResult.getEntries()).hasSize(5); List<FileMetadata> files = listFolderResult.getEntries().stream() .filter(entity -> entity instanceof FileMetadata) .map(entity -> (FileMetadata) entity) .collect(Collectors.toList()); assertThat(files).hasSize(3); List<FolderMetadata> folders = listFolderResult.getEntries().stream() .filter(entity -> entity instanceof FolderMetadata) .map(entity -> (FolderMetadata) entity) .collect(Collectors.toList()); assertThat(folders).hasSize(2); } @Test public void listFolder_shouldTrowExceptionIfFolderNotExists() { exceptions.expect(DropboxException.class); dropboxService.listFolder("/not existing folder", true, 10L); } @Test public void listFolderContinue_shouldListNextPathOfItems() throws Exception { File tempUploadFile = temporaryFolder.newFile("testFile2.txt"); FileUtils.writeStringToFile(tempUploadFile, "test file content", "UTF-8"); String testFilePath1 = String.format("%s/%s", TEST_FOLDER_PATH, "testFile2.txt"); dropboxService.uploadFile(testFilePath1, new FileInputStream(tempUploadFile)); ListFolderResult listFolderResult = dropboxService.listFolder(TEST_FOLDER_PATH, false, 1L); assertThat(listFolderResult.getEntries()).hasSize(1); String cursor = listFolderResult.getCursor(); listFolderResult = dropboxService.listFolderContinue(cursor); assertThat(listFolderResult.getEntries()).hasSize(1); cursor = listFolderResult.getCursor(); listFolderResult = dropboxService.listFolderContinue(cursor); assertThat(listFolderResult.getEntries()).hasSize(0); } @Test public void listFolderContinue_shouldThrowExceptionIfWrongCursorProvided() { exceptions.expect(DropboxException.class); dropboxService.listFolderContinue(UUID.randomUUID().toString()); } @Test public void deleteFile_shouldDeleteFile() { FileMetadata fileDetails = dropboxService.getFileDetails(TEST_FILE_PATH); assertThat(fileDetails.getId()).isNotBlank(); dropboxService.deleteFile(TEST_FILE_PATH); exceptions.expect(DropboxException.class); dropboxService.getFileDetails(TEST_FILE_PATH); } @Test public void deleteFile_shouldThrowExceptionIfFileNotExists() { exceptions.expect(DropboxException.class); dropboxService.deleteFolder("/not-existing-file"); } @Test public void deleteFolder_shouldDeleteFolder() { String testFolder = String.format("%s/%s", TEST_FOLDER_PATH, "test folder"); dropboxService.createFolder(testFolder); FolderMetadata folderDetails = dropboxService.getFolderDetails(testFolder); assertThat(folderDetails.getId()).isNotBlank(); dropboxService.deleteFolder(testFolder); exceptions.expect(DropboxException.class); dropboxService.getFolderDetails(testFolder); } @Test public void deleteFolder_shouldThrowExceptionIfFolderNotExists() { exceptions.expect(DropboxException.class); dropboxService.deleteFolder("/not-existing-folder"); }}
DropboxException
public class DropboxException extends RuntimeException { public DropboxException(String message) { super(message); } public DropboxException(String message, Exception cause) { super(message, cause); }}
DropboxActionResolver
@FunctionalInterfaceinterface DropboxActionResolver<T> { T perform() throws Exception;}
What do you think of it?