ACS-406: S3 Connector: support for content direct access urls throws … (#1080)

-  added implementation for CachingContentStore and AggregatingContentStore
  -  added tests
This commit is contained in:
Cristian Turlica
2020-07-07 12:31:59 +03:00
committed by GitHub
parent 8885b75e0b
commit b16e62761b
4 changed files with 1347 additions and 1045 deletions

View File

@@ -25,6 +25,7 @@
*/
package org.alfresco.repo.content.caching;
import java.util.Date;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
@@ -39,6 +40,7 @@ import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentStreamListener;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
@@ -475,4 +477,14 @@ public class CachingContentStore implements ContentStore, ApplicationEventPublis
{
return this.beanName;
}
public boolean isDirectAccessSupported()
{
return backingStore.isDirectAccessSupported();
}
public DirectAccessUrl getDirectAccessUrl(String contentUrl, Date expiresAt)
{
return backingStore.getDirectAccessUrl(contentUrl, expiresAt);
}
}

View File

@@ -25,6 +25,7 @@
*/
package org.alfresco.repo.content.replication;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
@@ -39,6 +40,7 @@ import org.alfresco.repo.content.caching.CachingContentStore;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -262,4 +264,115 @@ public class AggregatingContentStore extends AbstractContentStore
}
return deleted;
}
/**
* @return Returns <tt>true</tt> if at least one store supports direct access
*/
public boolean isDirectAccessSupported()
{
// Check the primary store
boolean isDirectAccessSupported = primaryStore.isDirectAccessSupported();
if (!isDirectAccessSupported)
{
// Direct access is not supported by the primary store so we have to check the
// other stores
for (ContentStore store : secondaryStores)
{
isDirectAccessSupported = store.isDirectAccessSupported();
if (isDirectAccessSupported)
{
break;
}
}
}
return isDirectAccessSupported;
}
public DirectAccessUrl getDirectAccessUrl(String contentUrl, Date expiresAt)
{
if (primaryStore == null)
{
throw new AlfrescoRuntimeException("ReplicatingContentStore not initialised");
}
// get a read lock so that we are sure that no replication is underway
readLock.lock();
try
{
// Keep track of the unsupported state of the content URL - it might be a rubbish URL
boolean contentUrlSupported = true;
boolean directAccessUrlSupported = true;
DirectAccessUrl directAccessUrl = null;
// Check the primary store
try
{
directAccessUrl = primaryStore.getDirectAccessUrl(contentUrl, expiresAt);
}
catch (UnsupportedOperationException e)
{
// The store does not support direct access URL
directAccessUrlSupported = false;
}
catch (UnsupportedContentUrlException e)
{
// The store can't handle the content URL
contentUrlSupported = false;
}
if (directAccessUrl != null)
{
return directAccessUrl;
}
// the content is not in the primary store so we have to go looking for it
for (ContentStore store : secondaryStores)
{
try
{
directAccessUrl = store.getDirectAccessUrl(contentUrl, expiresAt);
}
catch (UnsupportedOperationException e)
{
// The store does not support direct access URL
directAccessUrlSupported = false;
}
catch (UnsupportedContentUrlException e)
{
// The store can't handle the content URL
contentUrlSupported = false;
}
if (directAccessUrl != null)
{
break;
}
}
if (directAccessUrl == null)
{
if (!directAccessUrlSupported)
{
// The direct access URL was not supported
throw new UnsupportedOperationException("Retrieving direct access URLs is not supported by this content store.");
}
else if (!contentUrlSupported)
{
// The content URL was not supported
throw new UnsupportedContentUrlException(this, contentUrl);
}
}
return directAccessUrl;
}
finally
{
readLock.unlock();
}
}
}

View File

@@ -31,6 +31,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -54,6 +55,7 @@ import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentStreamListener;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -487,4 +489,35 @@ public class CachingContentStoreTest
when(backingStore.delete("url")).thenReturn(false);
assertFalse(cachingStore.delete("url"));
}
@Test
public void isDirectAccessSupported()
{
assertFalse(cachingStore.isDirectAccessSupported());
when(backingStore.isDirectAccessSupported()).thenReturn(true);
assertTrue(cachingStore.isDirectAccessSupported());
}
@Test
public void getDirectAccessUrlUnsupported()
{
try
{
when(backingStore.getDirectAccessUrl(anyString(), any())).thenThrow(new UnsupportedOperationException());
cachingStore.getDirectAccessUrl("url", null);
fail();
}
catch (UnsupportedOperationException e)
{
// expected
}
}
@Test
public void getDirectAccessUrl()
{
when(backingStore.getDirectAccessUrl(anyString(), any())).thenReturn(new DirectAccessUrl());
cachingStore.getDirectAccessUrl("url", null);
}
}

View File

@@ -32,17 +32,33 @@ import java.util.List;
import org.alfresco.repo.content.AbstractWritableContentStoreTest;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.UnsupportedContentUrlException;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.GUID;
import org.alfresco.util.TempFileProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests read and write functionality for the aggregating store.
@@ -62,6 +78,16 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
private ContentStore primaryStore;
private List<ContentStore> secondaryStores;
@Mock
ContentStore primaryStoreMock;
@Mock
ContentStore secondaryStoreMock;
@Mock
AggregatingContentStore aggregatingContentStoreMock;
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@Before
public void before() throws Exception
{
@@ -163,5 +189,123 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
checkForUrl(contentUrl, true);
}
@Test
public void testIsDirectAccessSupported()
{
// Create the aggregating store
AggregatingContentStore aggStore = new AggregatingContentStore();
aggStore.setPrimaryStore(primaryStoreMock);
aggStore.setSecondaryStores(List.of(secondaryStoreMock));
// By default it is unsupported
assertFalse(aggStore.isDirectAccessSupported());
// Supported if at least one store supports direct access
{
when(primaryStoreMock.isDirectAccessSupported()).thenReturn(false);
when(secondaryStoreMock.isDirectAccessSupported()).thenReturn(true);
assertTrue(aggStore.isDirectAccessSupported());
when(primaryStoreMock.isDirectAccessSupported()).thenReturn(true);
when(secondaryStoreMock.isDirectAccessSupported()).thenReturn(true);
assertTrue(aggStore.isDirectAccessSupported());
when(primaryStoreMock.isDirectAccessSupported()).thenReturn(true);
when(secondaryStoreMock.isDirectAccessSupported()).thenReturn(false);
assertTrue(aggStore.isDirectAccessSupported());
}
}
@Test
public void testGetDirectAccessUrl()
{
// Create the aggregating store
AggregatingContentStore aggStore = new AggregatingContentStore();
aggStore.setPrimaryStore(primaryStoreMock);
aggStore.setSecondaryStores(List.of(secondaryStoreMock));
UnsupportedOperationException unsupportedExc = new UnsupportedOperationException();
UnsupportedContentUrlException unsupportedContentUrlExc = new UnsupportedContentUrlException(aggStore, "");
// By default it is unsupported
DirectAccessUrl directAccessUrl = aggStore.getDirectAccessUrl("url", null);
assertNull(directAccessUrl);
// Direct access not supported
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
aggStore.getDirectAccessUrl("urlDANotSupported", null);
fail();
}
catch (UnsupportedOperationException e)
{
// Expected
}
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
aggStore.getDirectAccessUrl("urlDANotSupported", null);
fail();
}
catch (UnsupportedOperationException e)
{
// Expected
}
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedContentUrlExc);
aggStore.getDirectAccessUrl("urlDANotSupported", null);
fail();
}
catch (UnsupportedOperationException e)
{
// Expected
}
// Content url not supported
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlNotSupported"), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlNotSupported"), any())).thenThrow(unsupportedContentUrlExc);
aggStore.getDirectAccessUrl("urlNotSupported", null);
fail();
}
catch (UnsupportedContentUrlException e)
{
// Expected
}
when(primaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenThrow(unsupportedExc);
directAccessUrl = aggStore.getDirectAccessUrl("urlPriSupported", null);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenThrow(unsupportedContentUrlExc);
directAccessUrl = aggStore.getDirectAccessUrl("urlPriSupported", null);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.getDirectAccessUrl("urlSecSupported", null);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.getDirectAccessUrl("urlSecSupported", null);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.getDirectAccessUrl("urlPriSupported", null);
assertNotNull(directAccessUrl);
directAccessUrl = aggStore.getDirectAccessUrl("urlSecSupported", null);
assertNotNull(directAccessUrl);
}
}