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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче