mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Added a raw download servlet at URL http://.../alfresco/dr?contentUrl=...?ticket=...
Added ContentService.getRawReader to get content directly using a content URL. To access this, you need to be admin. Fixed EHCacheAdapter to handle non-Serializable values. Added tests for above and for AbstractRoutingContentStore. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5841 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -55,6 +55,7 @@ public class CacheTest extends TestCase
|
||||
private SimpleCache<String, Serializable> standaloneCache;
|
||||
private SimpleCache<String, Serializable> backingCache;
|
||||
private SimpleCache<String, Serializable> transactionalCache;
|
||||
private SimpleCache<String, Object> objectCache;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@@ -64,6 +65,7 @@ public class CacheTest extends TestCase
|
||||
standaloneCache = (SimpleCache<String, Serializable>) ctx.getBean("ehCache1");
|
||||
backingCache = (SimpleCache<String, Serializable>) ctx.getBean("backingCache");
|
||||
transactionalCache = (SimpleCache<String, Serializable>) ctx.getBean("transactionalCache");
|
||||
objectCache = (SimpleCache<String, Object>) ctx.getBean("objectCache");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,6 +88,14 @@ public class CacheTest extends TestCase
|
||||
assertNotNull(backingCache);
|
||||
assertNotNull(standaloneCache);
|
||||
assertNotNull(transactionalCache);
|
||||
assertNotNull(objectCache);
|
||||
}
|
||||
|
||||
public void testObjectCache() throws Exception
|
||||
{
|
||||
objectCache.put("A", this);
|
||||
Object obj = objectCache.get("A");
|
||||
assertTrue("Object not cached properly", this == obj);
|
||||
}
|
||||
|
||||
public void testEhcacheAdaptors() throws Exception
|
||||
|
@@ -87,7 +87,7 @@ public class EhCacheAdapter<K extends Serializable, V extends Object>
|
||||
Element element = cache.get(key);
|
||||
if (element != null)
|
||||
{
|
||||
return (V) element.getValue();
|
||||
return (V) element.getObjectValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -97,7 +97,8 @@ public class EhCacheAdapter<K extends Serializable, V extends Object>
|
||||
catch (CacheException e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to get from EhCache: \n" +
|
||||
" key: " + key);
|
||||
" key: " + key,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -102,7 +102,8 @@ public abstract class AbstractContentReadWriteTest extends TestCase
|
||||
*/
|
||||
protected final ContentWriter getWriter()
|
||||
{
|
||||
return getStore().getWriter(null, contentUrl);
|
||||
ContentContext contentCtx = new ContentContext(null, contentUrl);
|
||||
return getStore().getWriter(contentCtx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,7 +188,8 @@ public abstract class AbstractContentReadWriteTest extends TestCase
|
||||
assertFalse("Reader exists failure", reader.exists());
|
||||
|
||||
// write something
|
||||
ContentWriter writer = store.getWriter(null, contentUrl);
|
||||
ContentContext contentContext = new ContentContext(null, contentUrl);
|
||||
ContentWriter writer = store.getWriter(contentContext);
|
||||
writer.putContent("ABC");
|
||||
|
||||
assertTrue("Store exists should show URL to be present", store.exists(contentUrl));
|
||||
@@ -298,10 +300,11 @@ public abstract class AbstractContentReadWriteTest extends TestCase
|
||||
String contentUrl = AbstractContentStore.createNewUrl();
|
||||
ContentStore store = getStore();
|
||||
|
||||
ContentWriter firstWriter = store.getWriter(null, contentUrl);
|
||||
ContentContext contentCtx = new ContentContext(null, contentUrl);
|
||||
ContentWriter firstWriter = store.getWriter(contentCtx);
|
||||
try
|
||||
{
|
||||
ContentWriter secondWriter = store.getWriter(null, contentUrl);
|
||||
ContentWriter secondWriter = store.getWriter(contentCtx);
|
||||
fail("Store issued two writers for the same URL: " + store);
|
||||
}
|
||||
catch (ContentIOException e)
|
||||
@@ -620,7 +623,8 @@ public abstract class AbstractContentReadWriteTest extends TestCase
|
||||
}
|
||||
|
||||
// get a new writer from the store, using the existing content and perform a truncation check
|
||||
ContentWriter writerTruncate = getStore().getWriter(writer.getReader(), AbstractContentStore.createNewUrl());
|
||||
ContentContext writerTruncateCtx = new ContentContext(writer.getReader(), AbstractContentStore.createNewUrl());
|
||||
ContentWriter writerTruncate = getStore().getWriter(writerTruncateCtx);
|
||||
assertEquals("Content size incorrect", 0, writerTruncate.getSize());
|
||||
// get the channel with truncation
|
||||
FileChannel fcTruncate = writerTruncate.getFileChannel(true);
|
||||
@@ -628,7 +632,8 @@ public abstract class AbstractContentReadWriteTest extends TestCase
|
||||
assertEquals("Content not truncated", 0, writerTruncate.getSize());
|
||||
|
||||
// get a new writer from the store, using the existing content and perform a non-truncation check
|
||||
ContentWriter writerNoTruncate = getStore().getWriter(writer.getReader(), AbstractContentStore.createNewUrl());
|
||||
ContentContext writerNoTruncateCtx = new ContentContext(writer.getReader(), AbstractContentStore.createNewUrl());
|
||||
ContentWriter writerNoTruncate = getStore().getWriter(writerNoTruncateCtx);
|
||||
assertEquals("Content size incorrect", 0, writerNoTruncate.getSize());
|
||||
// get the channel without truncation
|
||||
FileChannel fcNoTruncate = writerNoTruncate.getFileChannel(false);
|
||||
|
@@ -86,6 +86,10 @@ public abstract class AbstractContentStore implements ContentStore
|
||||
* @param contentUrl a URL of the content to check
|
||||
* @return Returns the relative part of the URL
|
||||
* @throws RuntimeException if the URL is not correct
|
||||
*
|
||||
* @deprecated Stores can really have any prefix in the URL. This method was
|
||||
* really specific to the FileContentStore and has been moved into
|
||||
* it.
|
||||
*/
|
||||
public static String getRelativePart(String contentUrl) throws RuntimeException
|
||||
{
|
||||
|
@@ -83,7 +83,8 @@ public abstract class AbstractRoutingContentStore implements ContentStore
|
||||
* to make a decision.
|
||||
*
|
||||
* @param ctx the context to use to make the choice
|
||||
* @return Returns the store most appropriate for the given context
|
||||
* @return Returns the store most appropriate for the given context and
|
||||
* <b>never <tt>null</tt></b>
|
||||
*/
|
||||
protected abstract ContentStore selectWriteStore(ContentContext ctx);
|
||||
|
||||
@@ -132,9 +133,19 @@ public abstract class AbstractRoutingContentStore implements ContentStore
|
||||
List<ContentStore> stores = getAllStores();
|
||||
for (ContentStore storeInList : stores)
|
||||
{
|
||||
if (!store.exists(contentUrl))
|
||||
boolean exists = false;
|
||||
try
|
||||
{
|
||||
// It is not in the store
|
||||
exists = storeInList.exists(contentUrl);
|
||||
if (!exists)
|
||||
{
|
||||
// It is not in the store
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// The API used to allow failure when the URL wasn't there
|
||||
continue;
|
||||
}
|
||||
// We found one
|
||||
@@ -264,6 +275,10 @@ public abstract class AbstractRoutingContentStore implements ContentStore
|
||||
{
|
||||
// Select the store for writing
|
||||
ContentStore store = selectWriteStore(context);
|
||||
if (store == null)
|
||||
{
|
||||
throw new NullPointerException("Unable to find a writer. 'selectWriteStore' may not return null.");
|
||||
}
|
||||
ContentWriter writer = store.getWriter(context);
|
||||
// Cache the store against the URL
|
||||
storesCacheWriteLock.lock();
|
||||
|
@@ -71,8 +71,10 @@ public interface ContentStore
|
||||
* reader to {@link ContentReader#exists() check for existence}, although
|
||||
* that check should also be performed.
|
||||
*
|
||||
* @param contentUrl the path to the content
|
||||
* @return Returns true if the content exists.
|
||||
* @param contentUrl the path to the content
|
||||
* @return Returns true if the content exists, otherwise
|
||||
* false if the content doesn't exist or if the URL
|
||||
* is not applicable to this store.
|
||||
* @throws ContentIOException
|
||||
*
|
||||
* @see ContentReader#exists()
|
||||
@@ -90,6 +92,7 @@ public interface ContentStore
|
||||
*
|
||||
* @see #exists(String)
|
||||
* @see ContentReader#exists()
|
||||
* @see EmptyContentReader
|
||||
*/
|
||||
public ContentReader getReader(String contentUrl) throws ContentIOException;
|
||||
|
||||
|
@@ -84,6 +84,7 @@ public class ContentTestSuite extends TestSuite
|
||||
suite.addTestSuite(ContentDataTest.class);
|
||||
suite.addTestSuite(MimetypeMapTest.class);
|
||||
suite.addTestSuite(RoutingContentServiceTest.class);
|
||||
suite.addTestSuite(RoutingContentStoreTest.class);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.repo.avm.AVMNodeConverter;
|
||||
import org.alfresco.repo.content.ContentServicePolicies.OnContentReadPolicy;
|
||||
import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy;
|
||||
@@ -267,7 +268,31 @@ public class RoutingContentService implements ContentService
|
||||
policy.onContentUpdate(nodeRef, newContent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ContentReader getRawReader(String contentUrl)
|
||||
{
|
||||
ContentReader reader = store.getReader(contentUrl);
|
||||
if (reader == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("ContentStore implementations may not return null ContentReaders");
|
||||
}
|
||||
// set extra data on the reader
|
||||
reader.setMimetype(MimetypeMap.MIMETYPE_BINARY);
|
||||
reader.setEncoding("UTF-8");
|
||||
reader.setLocale(I18NUtil.getLocale());
|
||||
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(
|
||||
"Direct request for reader: \n" +
|
||||
" Content URL: " + contentUrl + "\n" +
|
||||
" Reader: " + reader);
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
public ContentReader getReader(NodeRef nodeRef, QName propertyQName)
|
||||
{
|
||||
return getReader(nodeRef, propertyQName, true);
|
||||
@@ -318,6 +343,10 @@ public class RoutingContentService implements ContentService
|
||||
|
||||
// The context of the read is entirely described by the URL
|
||||
ContentReader reader = store.getReader(contentUrl);
|
||||
if (reader == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("ContentStore implementations may not return null ContentReaders");
|
||||
}
|
||||
|
||||
// set extra data on the reader
|
||||
reader.setMimetype(contentData.getMimetype());
|
||||
|
@@ -269,6 +269,21 @@ public class RoutingContentServiceTest extends TestCase
|
||||
assertNull("Reader must be null if the content URL is null", reader);
|
||||
}
|
||||
|
||||
public void testGetRawReader() throws Exception
|
||||
{
|
||||
ContentReader reader = contentService.getRawReader("blah");
|
||||
assertNotNull("A reader is expected with content URL referencing no content", reader);
|
||||
assertFalse("Reader should not have any content", reader.exists());
|
||||
// Now write something
|
||||
ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, false);
|
||||
writer.putContent("ABC from " + getName());
|
||||
// Try again
|
||||
String contentUrl = writer.getContentUrl();
|
||||
reader = contentService.getRawReader(contentUrl);
|
||||
assertNotNull("Expected reader for live, raw content", reader);
|
||||
assertEquals("Content sizes don't match", writer.getSize(), reader.getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks what happens when the physical content disappears
|
||||
*/
|
||||
|
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.content;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
|
||||
import org.alfresco.repo.cache.EhCacheAdapter;
|
||||
import org.alfresco.repo.content.filestore.FileContentStore;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
|
||||
/**
|
||||
* Ensures that the routing of URLs based on context is working.
|
||||
*
|
||||
* @see AbstractRoutingContentStore
|
||||
* @since 2.1
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class RoutingContentStoreTest extends TestCase
|
||||
{
|
||||
private ContentStore storeA;
|
||||
private ContentStore storeB;
|
||||
private ContentStore routingStore;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
File tempDir = TempFileProvider.getTempDir();
|
||||
// Create a subdirectory for A
|
||||
File storeADir = new File(tempDir, "A");
|
||||
storeA = new FileContentStore(storeADir);
|
||||
// Create a subdirectory for B
|
||||
File storeBDir = new File(tempDir, "B");
|
||||
storeB = new FileContentStore(storeBDir);
|
||||
// Create the routing store
|
||||
routingStore = new RandomRoutingContentStore(storeA, storeB);
|
||||
}
|
||||
|
||||
public void testSetUp() throws Exception
|
||||
{
|
||||
assertNotNull(storeA);
|
||||
assertNotNull(storeB);
|
||||
assertNotNull(routingStore);
|
||||
}
|
||||
|
||||
private void checkForContent(String contentUrl, String content)
|
||||
{
|
||||
for (ContentStore store : new ContentStore[] {storeA, storeB})
|
||||
{
|
||||
// Does the store have it
|
||||
if (store.exists(contentUrl))
|
||||
{
|
||||
// Check it
|
||||
ContentReader reader = store.getReader(contentUrl);
|
||||
String checkContent = reader.getContentString();
|
||||
assertEquals("Content found but is incorrect", content, checkContent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail("Content not found in any of the stores: " + contentUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that requests for missing content URLs are served.
|
||||
*/
|
||||
public void testMissingUrl()
|
||||
{
|
||||
ContentReader reader = routingStore.getReader("blah");
|
||||
assertNotNull("Missing URL should not return null", reader);
|
||||
assertFalse("Empty reader should say content doesn't exist.", reader.exists());
|
||||
try
|
||||
{
|
||||
reader.getContentString();
|
||||
fail("Empty reader cannot return content.");
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testHandlingInCache()
|
||||
{
|
||||
for (int i = 0 ; i < 20; i++)
|
||||
{
|
||||
ContentContext contentContext = new ContentContext(null, null);
|
||||
ContentWriter writer = routingStore.getWriter(contentContext);
|
||||
String content = "This was generated by " + this.getClass().getName() + "#" + getName() + " number " + i;
|
||||
writer.putContent(content);
|
||||
// Check that it exists
|
||||
String contentUrl = writer.getContentUrl();
|
||||
checkForContent(contentUrl, content);
|
||||
|
||||
// Now go direct to the routing store and check that it is able to find the appropriate URLs
|
||||
ContentReader reader = routingStore.getReader(contentUrl);
|
||||
assertNotNull("Null reader returned", reader);
|
||||
assertTrue("Reader should be onto live content", reader.exists());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that content URLs are matched to the appropriate stores when in the cache limit.
|
||||
*/
|
||||
public void testReadFindInCache()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A test routing store that directs content writes to a randomly-chosen store.
|
||||
* Matching of content URLs back to the stores is handled by the base class.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
private static class RandomRoutingContentStore extends AbstractRoutingContentStore
|
||||
{
|
||||
private List<ContentStore> stores;
|
||||
private Random random;
|
||||
|
||||
public RandomRoutingContentStore(ContentStore ... stores)
|
||||
{
|
||||
this.random = new Random();
|
||||
this.stores = new ArrayList<ContentStore>(5);
|
||||
for (ContentStore store : stores)
|
||||
{
|
||||
this.stores.add(store);
|
||||
}
|
||||
Cache ehCache = new Cache("RandomRoutingContentStore", 50, false, true, 0L, 0L);
|
||||
CacheManager cacheManager = new CacheManager();
|
||||
cacheManager.addCache(ehCache);
|
||||
EhCacheAdapter<String, ContentStore> cache = new EhCacheAdapter<String, ContentStore>();
|
||||
cache.setCache(ehCache);
|
||||
super.setStoresCache(cache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ContentStore> getAllStores()
|
||||
{
|
||||
return stores;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContentStore selectWriteStore(ContentContext ctx)
|
||||
{
|
||||
int size = stores.size();
|
||||
int index = (int) Math.floor(random.nextDouble() * (double) size);
|
||||
return stores.get(index);
|
||||
}
|
||||
}
|
||||
}
|
@@ -57,12 +57,22 @@ public class FileContentStore extends AbstractContentStore
|
||||
private boolean allowRandomAccess;
|
||||
|
||||
/**
|
||||
* @param rootDirectory the root under which files will be stored. The
|
||||
* directory will be created if it does not exist.
|
||||
* @param rootDirectoryStr the root under which files will be stored.
|
||||
* The directory will be created if it does not exist.
|
||||
*
|
||||
* @see FileContentStore#FileContentStore(File)
|
||||
*/
|
||||
public FileContentStore(String rootDirectoryStr)
|
||||
{
|
||||
rootDirectory = new File(rootDirectoryStr);
|
||||
this(new File(rootDirectoryStr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rootDirectory the root under which files will be stored.
|
||||
* The directory will be created if it does not exist.
|
||||
*/
|
||||
public FileContentStore(File rootDirectory)
|
||||
{
|
||||
if (!rootDirectory.exists())
|
||||
{
|
||||
if (!rootDirectory.mkdirs())
|
||||
@@ -70,11 +80,11 @@ public class FileContentStore extends AbstractContentStore
|
||||
throw new ContentIOException("Failed to create store root: " + rootDirectory, null);
|
||||
}
|
||||
}
|
||||
rootDirectory = rootDirectory.getAbsoluteFile();
|
||||
this.rootDirectory = rootDirectory.getAbsoluteFile();
|
||||
rootAbsolutePath = rootDirectory.getAbsolutePath();
|
||||
allowRandomAccess = true;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(36);
|
||||
@@ -183,8 +193,7 @@ public class FileContentStore extends AbstractContentStore
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file from the given relative URL. The URL must start with
|
||||
* the required {@link FileContentStore#STORE_PROTOCOL protocol prefix}.
|
||||
* Creates a file from the given relative URL.
|
||||
*
|
||||
* @param contentUrl the content URL including the protocol prefix
|
||||
* @return Returns a file representing the URL - the file may or may not
|
||||
@@ -195,7 +204,14 @@ public class FileContentStore extends AbstractContentStore
|
||||
private File makeFile(String contentUrl)
|
||||
{
|
||||
// take just the part after the protocol
|
||||
String relativeUrl = getRelativePart(contentUrl);
|
||||
String relativeUrl = FileContentStore.getRelativePart(contentUrl);
|
||||
if (relativeUrl == null)
|
||||
{
|
||||
throw new ContentIOException(
|
||||
"The content URL is not valid for this store: \n" +
|
||||
" Store: " + this + "\n" +
|
||||
" Content URL: " + contentUrl);
|
||||
}
|
||||
// get the file
|
||||
File file = new File(rootDirectory, relativeUrl);
|
||||
// done
|
||||
@@ -366,4 +382,47 @@ public class FileContentStore extends AbstractContentStore
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to ensure that URLs conform to the required format.
|
||||
* If subclasses have to parse the URL, then a call to this may not be required -
|
||||
* provided that the format is checked.
|
||||
* <p>
|
||||
* The protocol part of the URL (including legacy protocols)
|
||||
* is stripped out and just the relative path is returned. If no known prefix is
|
||||
* found, or if the relative part is empty, then <tt>null</tt> is returned.
|
||||
*
|
||||
* @param contentUrl a URL of the content to check
|
||||
* @return Returns the relative part of the URL. If there is no
|
||||
* prefix, then the URL is assumed to be the relative part.
|
||||
*/
|
||||
public static String getRelativePart(String contentUrl)
|
||||
{
|
||||
int index = 0;
|
||||
if (contentUrl.startsWith(STORE_PROTOCOL))
|
||||
{
|
||||
index = 8;
|
||||
}
|
||||
else if (contentUrl.startsWith("file://"))
|
||||
{
|
||||
index = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (contentUrl.length() == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid FileStore content URL: " + contentUrl);
|
||||
}
|
||||
return contentUrl;
|
||||
}
|
||||
|
||||
// extract the relative part of the URL
|
||||
String path = contentUrl.substring(index);
|
||||
// more extensive checks can be added in, but it seems overkill
|
||||
if (path.length() == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid FileStore content URL: " + contentUrl);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
@@ -54,6 +54,21 @@ import org.alfresco.service.namespace.QName;
|
||||
@PublicService
|
||||
public interface ContentService
|
||||
{
|
||||
/**
|
||||
* Fetch content from the low-level stores using a content URL. None of the
|
||||
* metadata associated with the content will be populated. This method should
|
||||
* be used only to stream the binary data out when no other metadata is
|
||||
* required.
|
||||
* <p>
|
||||
* <tt>null</tt> is never returned, but the reader should always be checked for
|
||||
* {@link ContentReader#exists() existence}.
|
||||
*
|
||||
* @param contentUrl a content store URL
|
||||
* @return Returns a reader for the URL that needs to be checked.
|
||||
*/
|
||||
@Auditable(key = Auditable.Key.ARG_0, parameters = {"contentUrl"})
|
||||
public ContentReader getRawReader(String contentUrl);
|
||||
|
||||
/**
|
||||
* Gets a reader for the content associated with the given node property.
|
||||
* <p>
|
||||
|
@@ -45,4 +45,14 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean name="objectCache" class="org.alfresco.repo.cache.EhCacheAdapter">
|
||||
<property name="cache">
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean" >
|
||||
<property name="cacheName">
|
||||
<value>objectCache</value>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
Reference in New Issue
Block a user