Implementation for searching resources on Azure Storage (#717)
* Initial implementation for searching resource on Azure Storage * Added tests * Reworked slightly using Optionals * Reworked slightly using Optionals Co-authored-by: Manfred Riem <mriem@manorrock.com>
This commit is contained in:
Родитель
f468778f2d
Коммит
121c343086
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.azure.spring.cloud.storage;
|
||||
|
||||
import com.azure.storage.blob.BlobContainerClient;
|
||||
import com.azure.storage.blob.BlobServiceClient;
|
||||
import com.azure.storage.blob.models.BlobContainerItem;
|
||||
import com.azure.storage.blob.models.BlobItem;
|
||||
import com.azure.storage.file.share.ShareClient;
|
||||
import com.azure.storage.file.share.ShareServiceClient;
|
||||
import com.azure.storage.file.share.models.ShareFileItem;
|
||||
import com.azure.storage.file.share.models.ShareItem;
|
||||
import static com.microsoft.azure.spring.cloud.storage.AzureStorageUtils.isAzureStorageResource;
|
||||
import static com.microsoft.azure.spring.cloud.storage.StorageType.BLOB;
|
||||
import static com.microsoft.azure.spring.cloud.storage.StorageType.FILE;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
/**
|
||||
* An Azure Storage specific ResourcePatternResolver.
|
||||
*/
|
||||
public class AzureStorageResourcePatternResolver implements ResourcePatternResolver {
|
||||
|
||||
/**
|
||||
* Stores the Ant path matcher.
|
||||
*/
|
||||
private final AntPathMatcher matcher = new AntPathMatcher();
|
||||
|
||||
/**
|
||||
* Stores the BlobServiceClient.
|
||||
*/
|
||||
private Optional<BlobServiceClient> blobServiceClient;
|
||||
|
||||
/**
|
||||
* Stores the ShareServiceClient shareServiceClient
|
||||
*/
|
||||
private Optional<ShareServiceClient> shareServiceClient;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param blobServiceClient the BlobServiceClient.
|
||||
*/
|
||||
public AzureStorageResourcePatternResolver(BlobServiceClient blobServiceClient) {
|
||||
this(blobServiceClient, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param shareServiceClient the ShareServiceClient.
|
||||
*/
|
||||
public AzureStorageResourcePatternResolver(ShareServiceClient shareServiceClient) {
|
||||
this(null, shareServiceClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param blobServiceClient the BlobServiceClient.
|
||||
* @param shareServiceClient the ShareServiceClient.
|
||||
*/
|
||||
public AzureStorageResourcePatternResolver(
|
||||
BlobServiceClient blobServiceClient, ShareServiceClient shareServiceClient) {
|
||||
this.blobServiceClient = Optional.ofNullable(blobServiceClient);
|
||||
this.shareServiceClient = Optional.ofNullable(shareServiceClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResourcePatternResolver#getResources(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Resource[] getResources(String pattern) throws IOException {
|
||||
Resource[] resources = null;
|
||||
|
||||
if (isAzureStorageResource(pattern, BLOB)) {
|
||||
resources = getBlobResources(pattern);
|
||||
} else if (isAzureStorageResource(pattern, FILE)) {
|
||||
resources = getShareResources(pattern);
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResourcePatternResolver#getResource(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
Resource resource = null;
|
||||
|
||||
if (isAzureStorageResource(location, BLOB) && blobServiceClient.isPresent()) {
|
||||
resource = new BlobStorageResource(blobServiceClient.get(), location, true);
|
||||
} else if (isAzureStorageResource(location, FILE) && shareServiceClient.isPresent()) {
|
||||
resource = new FileStorageResource(shareServiceClient.get(), location, true);
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResourcePatternResolver#getClassLoader()
|
||||
*/
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return getClass().getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the blob resources for the given pattern.
|
||||
*
|
||||
* @param pattern the pattern.
|
||||
* @return the blob resources.
|
||||
*/
|
||||
private Resource[] getBlobResources(String pattern) {
|
||||
ArrayList<Resource> resources = new ArrayList<>();
|
||||
blobServiceClient.ifPresent(client -> {
|
||||
Iterator<BlobContainerItem> containerIterator
|
||||
= client.listBlobContainers().iterator();
|
||||
while (containerIterator.hasNext()) {
|
||||
BlobContainerItem containerItem = containerIterator.next();
|
||||
String containerName = containerItem.getName();
|
||||
BlobContainerClient blobContainerClient
|
||||
= client.getBlobContainerClient(containerItem.getName());
|
||||
Iterator<BlobItem> blobIterator = blobContainerClient.listBlobs().iterator();
|
||||
while (blobIterator.hasNext()) {
|
||||
BlobItem blobItem = blobIterator.next();
|
||||
String blobName = blobItem.getName();
|
||||
String location = "azure-blob://" + containerName + "/" + blobName;
|
||||
if (matcher.match(pattern, location)) {
|
||||
resources.add(new BlobStorageResource(client, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return resources.toArray(new Resource[]{});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the share resources for the given pattern.
|
||||
*
|
||||
* @param pattern the pattern.
|
||||
* @return the share resources.
|
||||
*/
|
||||
private Resource[] getShareResources(String pattern) {
|
||||
ArrayList<Resource> resources = new ArrayList<>();
|
||||
shareServiceClient.ifPresent(client -> {
|
||||
Iterator<ShareItem> shareIterator
|
||||
= client.listShares().iterator();
|
||||
while (shareIterator.hasNext()) {
|
||||
ShareItem shareItem = shareIterator.next();
|
||||
String shareName = shareItem.getName();
|
||||
ShareClient shareClient
|
||||
= client.getShareClient(shareItem.getName());
|
||||
Iterator<ShareFileItem> shareFileIterator = shareClient
|
||||
.getRootDirectoryClient().listFilesAndDirectories().iterator();
|
||||
while (shareFileIterator.hasNext()) {
|
||||
ShareFileItem fileItem = shareFileIterator.next();
|
||||
String filename = fileItem.getName();
|
||||
if (!fileItem.isDirectory()) {
|
||||
String location = "azure-file://" + shareName + "/" + filename;
|
||||
if (matcher.match(pattern, location)) {
|
||||
resources.add(new FileStorageResource(client, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return resources.toArray(new Resource[]{});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.azure.spring.cloud.storage;
|
||||
|
||||
import com.azure.core.http.rest.PagedIterable;
|
||||
import com.azure.storage.blob.BlobClient;
|
||||
import com.azure.storage.blob.BlobContainerClient;
|
||||
import com.azure.storage.blob.BlobServiceClient;
|
||||
import com.azure.storage.blob.models.BlobContainerItem;
|
||||
import com.azure.storage.blob.models.BlobItem;
|
||||
import com.azure.storage.blob.specialized.BlockBlobClient;
|
||||
import com.azure.storage.file.share.ShareClient;
|
||||
import com.azure.storage.file.share.ShareDirectoryClient;
|
||||
import com.azure.storage.file.share.ShareServiceClient;
|
||||
import com.azure.storage.file.share.models.ShareFileItem;
|
||||
import com.azure.storage.file.share.models.ShareItem;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* The JUnit tests for the AzureStorageResourcePatternResolver class.
|
||||
*/
|
||||
@SpringBootTest(properties = "spring.main.banner-mode=off")
|
||||
@RunWith(SpringRunner.class)
|
||||
public class AzureStorageResourcePatternResolverTest {
|
||||
|
||||
/**
|
||||
* Stores the BlobServiceClient.
|
||||
*/
|
||||
@Autowired
|
||||
private BlobServiceClient blobServiceClient;
|
||||
|
||||
/**
|
||||
* Stores the ShareServiceClient.
|
||||
*/
|
||||
@Autowired
|
||||
private ShareServiceClient shareServiceClient;
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(blobServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-blob://mycontainer/myblob"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources2() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(blobServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-blob://mycontainer/*"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources3() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(blobServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-blob://*/myblob"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources4() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(blobServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-blob://*/*"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources5() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(shareServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-file://myshare/myfile"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources6() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(shareServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-file://myshare/*"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources7() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(shareServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-file://*/myfile"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getResources method.
|
||||
*
|
||||
* @throws IOException when an I/O error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testGetResources8() throws IOException {
|
||||
AzureStorageResourcePatternResolver resolver
|
||||
= new AzureStorageResourcePatternResolver(shareServiceClient);
|
||||
assertNotNull(resolver.getResources("azure-file://*/*"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(AzureStorageProtocolResolver.class)
|
||||
static class StorageApplication {
|
||||
|
||||
@Bean
|
||||
public BlobServiceClient getBlobServiceClient() {
|
||||
BlobServiceClient client = mock(BlobServiceClient.class);
|
||||
PagedIterable<BlobContainerItem> blobContainerItems = mock(PagedIterable.class);
|
||||
BlobContainerClient containerClient = mock(BlobContainerClient.class);
|
||||
PagedIterable<BlobItem> blobItems = mock(PagedIterable.class);
|
||||
BlobClient blobClient = mock(BlobClient.class);
|
||||
BlockBlobClient blockBlobClient = mock(BlockBlobClient.class);
|
||||
|
||||
BlobContainerItem containerItem1 = new BlobContainerItem();
|
||||
containerItem1.setName("mycontainer");
|
||||
ArrayList containerList = new ArrayList<BlobContainerItem>();
|
||||
containerList.add(containerItem1);
|
||||
|
||||
BlobItem blobItem1 = new BlobItem();
|
||||
blobItem1.setName("myblob");
|
||||
ArrayList blobList = new ArrayList<>();
|
||||
blobList.add(blobItem1);
|
||||
|
||||
when(client.listBlobContainers()).thenReturn(blobContainerItems);
|
||||
when(blobContainerItems.iterator()).thenReturn(containerList.iterator());
|
||||
when(client.getBlobContainerClient("mycontainer")).thenReturn(containerClient);
|
||||
when(containerClient.listBlobs()).thenReturn(blobItems);
|
||||
when(blobItems.iterator()).thenReturn(blobList.iterator());
|
||||
when(client.getBlobContainerClient("mycontainer")).thenReturn(containerClient);
|
||||
when(containerClient.getBlobClient("myblob")).thenReturn(blobClient);
|
||||
when(blobClient.getBlockBlobClient()).thenReturn(blockBlobClient);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ShareServiceClient getShareServiceClient() {
|
||||
ShareServiceClient client = mock(ShareServiceClient.class);
|
||||
PagedIterable<ShareItem> shareItems = mock(PagedIterable.class);
|
||||
ShareClient shareClient = mock(ShareClient.class);
|
||||
ShareDirectoryClient shareDirectoryClient = mock(ShareDirectoryClient.class);
|
||||
PagedIterable<ShareFileItem> shareFileItems = mock(PagedIterable.class);
|
||||
|
||||
ShareItem shareItem1 = new ShareItem();
|
||||
shareItem1.setName("myshare");
|
||||
ArrayList shareList = new ArrayList<ShareItem>();
|
||||
shareList.add(shareItem1);
|
||||
|
||||
ShareFileItem shareFileItem1 = new ShareFileItem("myfile", false, 0L);
|
||||
ArrayList shareFileList = new ArrayList<ShareFileItem>();
|
||||
shareFileList.add(shareFileItem1);
|
||||
|
||||
when(client.listShares()).thenReturn(shareItems);
|
||||
when(shareItems.iterator()).thenReturn(shareList.iterator());
|
||||
when(client.getShareClient("myshare")).thenReturn(shareClient);
|
||||
when(shareClient.getRootDirectoryClient()).thenReturn(shareDirectoryClient);
|
||||
when(shareDirectoryClient.listFilesAndDirectories()).thenReturn(shareFileItems);
|
||||
when(shareFileItems.iterator()).thenReturn(shareFileList.iterator());
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче