Added the notion of a ContentContext to select the content store to write to.

Added AbstractRoutingContentStore as a start base implementation.
Added warnings to drive config away from disused setTransactionService towards setRetryingTransactionHelper.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5734 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-05-21 09:16:31 +00:00
parent 8ee3f781f4
commit 6f4ab835fe
14 changed files with 631 additions and 56 deletions

View File

@@ -55,7 +55,8 @@ import org.springframework.util.FileCopyUtils;
* Implements all the convenience methods of the interface. The only methods
* that need to be implemented, i.e. provide low-level content access are:
* <ul>
* <li>{@link #getDirectReadableChannel()} to read content from the repository</li>
* <li>{@link #createReader()} to read content from the repository</li>
* <li>{@link #getDirectReadableChannel()} to provide direct storage access</li>
* </ul>
*
* @author Derek Hulley

View File

@@ -31,6 +31,7 @@ import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.GUID;
/**
@@ -45,16 +46,6 @@ import org.alfresco.util.GUID;
*/
public abstract class AbstractContentStore implements ContentStore
{
/**
* Simple implementation that uses the
* {@link ContentReader#exists() reader's exists} method as its implementation.
*/
public boolean exists(String contentUrl) throws ContentIOException
{
ContentReader reader = getReader(contentUrl);
return reader.exists();
}
/**
* Creates a new content URL. This must be supported by all
* stores that are compatible with Alfresco.
@@ -126,8 +117,33 @@ public abstract class AbstractContentStore implements ContentStore
return path;
}
/**
* Simple implementation that uses the
* {@link ContentReader#exists() reader's exists} method as its implementation.
*/
public boolean exists(String contentUrl) throws ContentIOException
{
ContentReader reader = getReader(contentUrl);
return reader.exists();
}
/**
* Searches for URLs using null dates.
*
* @see ContentStore#getUrls(java.util.Date, java.util.Date)
*/
public final Set<String> getUrls() throws ContentIOException
{
return getUrls(null, null);
}
/**
* @see ContentContext
* @see ContentStore#getWriter(ContentContext)
*/
public final ContentWriter getWriter(ContentReader existingContentReader, String newContentUrl) throws ContentIOException
{
ContentContext ctx = new ContentContext(existingContentReader, newContentUrl);
return getWriter(ctx);
}
}

View File

@@ -55,6 +55,7 @@ import org.springframework.util.FileCopyUtils;
* Implements all the convenience methods of the interface. The only methods
* that need to be implemented, i.e. provide low-level content access are:
* <ul>
* <li>{@link #getReader()} to create a reader to the underlying content</li>
* <li>{@link #getDirectWritableChannel()} to write content to the repository</li>
* </ul>
*

View File

@@ -0,0 +1,298 @@
/*
* 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.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A store providing support for content store implementations that provide
* routing of content read and write requests based on context.
*
* @see ContentContext
*
* @since 2.1
* @author Derek Hulley
*/
public abstract class AbstractRoutingContentStore implements ContentStore
{
private static Log logger = LogFactory.getLog(AbstractRoutingContentStore.class);
private SimpleCache<String, ContentStore> storesByContentUrl;
private ReadLock storesCacheReadLock;
private WriteLock storesCacheWriteLock;
protected AbstractRoutingContentStore()
{
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
storesCacheReadLock = lock.readLock();
storesCacheWriteLock = lock.writeLock();
}
/**
* @param storesCache cache of stores used to access URLs
*/
public void setStoresCache(SimpleCache<String, ContentStore> storesCache)
{
this.storesByContentUrl = storesCache;
}
/**
* @return Returns a list of all possible stores available for reading or writing
*/
protected abstract List<ContentStore> getAllStores();
/**
* Get a content store based on the context provided. The applicability of the
* context and even the types of context allowed are up to the implementation, but
* normally there should be a fallback case for when the parameters are not adequate
* to make a decision.
*
* @param ctx the context to use to make the choice
* @return Returns the store most appropriate for the given context
*/
protected abstract ContentStore selectWriteStore(ContentContext ctx);
/**
* Checks the cache for the store and ensures that the URL is in the store.
*
* @param contentUrl the content URL to search for
* @return Returns the store matching the content URL
*/
private ContentStore selectReadStore(String contentUrl)
{
storesCacheReadLock.lock();
try
{
// Check if the store is in the cache
ContentStore store = storesByContentUrl.get(contentUrl);
if (store != null && store.exists(contentUrl))
{
// We found a store and can use it
return store;
}
}
finally
{
storesCacheReadLock.unlock();
}
// Get the write lock and double check
storesCacheWriteLock.lock();
try
{
// Double check
ContentStore store = storesByContentUrl.get(contentUrl);
if (store != null && store.exists(contentUrl))
{
// We found a store and can use it
if (logger.isDebugEnabled())
{
logger.debug(
"Found mapped store for content URL: \n" +
" Content URL: " + contentUrl + "\n" +
" Store: " + store);
}
return store;
}
// It isn't, so search all the stores
List<ContentStore> stores = getAllStores();
for (ContentStore storeInList : stores)
{
if (!store.exists(contentUrl))
{
// It is not in the store
continue;
}
// We found one
store = storeInList;
// Put the value in the cache
storesByContentUrl.put(contentUrl, store);
break;
}
// Done
if (logger.isDebugEnabled())
{
logger.debug(
"Mapped content URL to store for reading: \n" +
" Content URL: " + contentUrl + "\n" +
" Store: " + store);
}
return store;
}
finally
{
storesCacheWriteLock.unlock();
}
}
/**
* This operation has to be performed on all the stores in order to maintain the
* {@link ContentStore#exists(String)} contract.
*/
public boolean delete(String contentUrl) throws ContentIOException
{
boolean deleted = true;
List<ContentStore> stores = getAllStores();
for (ContentStore store : stores)
{
deleted &= store.delete(contentUrl);
}
// Done
if (logger.isDebugEnabled())
{
logger.debug("Deleted content URL from stores: \n" +
" Stores: " + stores.size() + "\n" +
" Deleted: " + deleted);
}
return deleted;
}
/**
* @see #selectReadStore(String)
*/
public boolean exists(String contentUrl) throws ContentIOException
{
ContentStore store = selectReadStore(contentUrl);
return (store != null);
}
/**
* @return Returns a valid reader from one of the stores otherwise
* a {@link EmptyContentReader} is returned.
*/
public ContentReader getReader(String contentUrl) throws ContentIOException
{
ContentStore store = selectReadStore(contentUrl);
if (store != null)
{
if (logger.isDebugEnabled())
{
logger.debug("Getting reader from store: \n" +
" Content URL: " + contentUrl + "\n" +
" Store: " + store);
}
return store.getReader(contentUrl);
}
else
{
if (logger.isDebugEnabled())
{
logger.debug("Getting empty reader for content URL: " + contentUrl);
}
return new EmptyContentReader(contentUrl);
}
}
/**
* Compile a set of URLs from all stores.
*/
public Set<String> getUrls() throws ContentIOException
{
Set<String> urls = new HashSet<String>(1139);
List<ContentStore> stores = getAllStores();
for (ContentStore store : stores)
{
Set<String> storeUrls = store.getUrls();
urls.addAll(storeUrls);
}
if (logger.isDebugEnabled())
{
logger.debug("Found " + urls.size() + " URLs from " + stores.size() + " stores");
}
return urls;
}
/**
* Compile a set of URLs from all stores given the date range.
*/
public Set<String> getUrls(Date createdAfter, Date createdBefore) throws ContentIOException
{
Set<String> urls = new HashSet<String>(1139);
List<ContentStore> stores = getAllStores();
for (ContentStore store : stores)
{
Set<String> storeUrls = store.getUrls(createdAfter, createdBefore);
urls.addAll(storeUrls);
}
if (logger.isDebugEnabled())
{
logger.debug("Found " + urls.size() + " URLs from " + stores.size() + " stores");
}
return urls;
}
/**
* Selects a store for the given context and caches store that was used.
*
* @see #selectWriteStore(ContentContext)
*/
public ContentWriter getWriter(ContentContext context) throws ContentIOException
{
// Select the store for writing
ContentStore store = selectWriteStore(context);
ContentWriter writer = store.getWriter(context);
// Cache the store against the URL
storesCacheWriteLock.lock();
try
{
String contentUrl = writer.getContentUrl();
storesByContentUrl.put(contentUrl, store);
}
finally
{
storesCacheWriteLock.unlock();
}
// Done
if (logger.isDebugEnabled())
{
logger.debug(
"Got writer and cache URL from store: \n" +
" Context: " + context + "\n" +
" Writer: " + writer + "\n" +
" Store: " + store);
}
return writer;
}
/**
* @see
*/
public ContentWriter getWriter(ContentReader existingContentReader, String newContentUrl) throws ContentIOException
{
return getWriter(new ContentContext(existingContentReader, newContentUrl));
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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.Serializable;
import org.alfresco.service.cmr.repository.ContentReader;
/**
* The location and lookup data for content. The very least data required to
* find content or assign a content writer is the content URL and any previous
* content that may have logically existed.
* <p>
* Although this class is doesn't enforce any conditions on the context,
* derived instances may have relationships that need to be maintained between
* various context values.
*
* @author Derek Hulley
*/
public class ContentContext implements Serializable
{
private static final long serialVersionUID = 6476617391229895125L;
/** An empty context. */
public static final ContentContext NULL_CONTEXT = new ContentContext(null, null);
private ContentReader existingContentReader;
private String contentUrl;
/**
* Construct the instance with the content URL.
*
* @param existingContentReader content with which to seed the new writer - may be <tt>null</tt>
* @param contentUrl the content URL - may be <tt>null</tt>
*/
public ContentContext(ContentReader existingContentReader, String contentUrl)
{
this.existingContentReader = existingContentReader;
this.contentUrl = contentUrl;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(128);
sb.append("ContentContext")
.append("[ contentUrl=").append(getContentUrl())
.append(", existing=").append((getExistingContentReader() == null ? false : true))
.append("]");
return sb.toString();
}
/**
* @return Returns the content to seed the writer with - may be <tt>null</tt>
*/
public ContentReader getExistingContentReader()
{
return existingContentReader;
}
/**
* @return Returns the content URL for the content's context - may be <tt>null</tt>
*/
public String getContentUrl()
{
return contentUrl;
}
}

View File

@@ -27,6 +27,7 @@ package org.alfresco.repo.content;
import java.util.Date;
import java.util.Set;
import org.alfresco.service.cmr.repository.ContentAccessor;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentStreamListener;
@@ -48,6 +49,8 @@ import org.alfresco.service.cmr.repository.ContentWriter;
* <li> <b>year</b>: year </li>
* <li> <b>month</b>: 1-based month of the year </li>
* <li> <b>day</b>: 1-based day of the month </li>
* <li> <b>hour</b>: 0-based hour of the day </li>
* <li> <b>minute</b>: 0-based minute of the hour </li>
* <li> <b>GUID</b>: A unique identifier </li>
* </ul>
* The old <b>file://</b> prefix must still be supported - and functionality
@@ -77,14 +80,12 @@ public interface ContentStore
public boolean exists(String contentUrl) throws ContentIOException;
/**
* Get the accessor with which to read from the content
* at the given URL. The reader is <b>stateful</b> and
* can <b>only be used once</b>.
* Get the accessor with which to read from the content at the given URL.
* The reader is <b>stateful</b> and can <b>only be used once</b>.
*
* @param contentUrl the path to where the content is located
* @return Returns a read-only content accessor for the given URL. There may
* be no content at the given URL, but the reader must still be returned.
* The reader may implement the {@link RandomAccessContent random access interface}.
* @throws ContentIOException
*
* @see #exists(String)
@@ -98,22 +99,31 @@ public interface ContentStore
* <b>only be used once</b>. The location may be specified but must, in that case,
* be a valid and unused URL.
* <p>
* The store will ensure that the {@link ContentAccessor#getContentUrl() new content URL} will
* be valid for all subsequent read attempts.
* <p>
* By supplying a reader to existing content, the store implementation may
* enable {@link RandomAccessContent random access}. The store implementation
* can enable this by copying the existing content into the new location
* before supplying a writer onto the new content.
*
* @param existingContentReader a reader onto any existing content for which
* a writer is required - may be null
* @param newContentUrl an unused, valid URL to use - may be null.
* @return Returns a write-only content accessor, possibly implementing
* the {@link RandomAccessContent random access interface}
* @throws ContentIOException if completely new content storage could not be
* created
* @param context the context of content.
* @return Returns a write-only content accessor
* @throws ContentIOException if completely new content storage could not be created
*
* @see #getWriter(ContentReader, String)
* @see ContentWriter#addListener(ContentStreamListener)
* @see ContentWriter#getContentUrl()
*/
public ContentWriter getWriter(ContentContext context) throws ContentIOException;
/**
* Shortcut method to {@link #getWriter(ContentContext)}.
*
* @see #getWriter(ContentContext)
*
* @deprecated
*/
public ContentWriter getWriter(ContentReader existingContentReader, String newContentUrl) throws ContentIOException;
/**
@@ -140,13 +150,11 @@ public interface ContentStore
* <p>
* A delete cannot be forced since it is much better to have the
* file remain longer than desired rather than deleted prematurely.
* The store implementation should safeguard files for certain
* minimum period, in which case all files younger than a certain
* age will not be deleted.
*
* @param contentUrl the URL of the content to delete
* @return Return true if the content was deleted (either by this or
* another operation), otherwise false
* another operation), otherwise false. If the content no longer
* exists, then <tt>true</tt> is returned.
* @throws ContentIOException
*/
public boolean delete(String contentUrl) throws ContentIOException;

View File

@@ -0,0 +1,76 @@
/*
* 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.nio.channels.ReadableByteChannel;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
/**
* A blank reader for which <code>exists()</code> always returns false.
*
* @author Derek Hulley
*/
public class EmptyContentReader extends AbstractContentReader
{
/**
* @param contentUrl the content URL
*/
public EmptyContentReader(String contentUrl)
{
super(contentUrl);
}
/**
* @return Returns an instance of the this class
*/
@Override
protected ContentReader createReader() throws ContentIOException
{
return new EmptyContentReader(this.getContentUrl());
}
@Override
protected ReadableByteChannel getDirectReadableChannel() throws ContentIOException
{
throw new UnsupportedOperationException("The content never exists");
}
public boolean exists()
{
return false;
}
public long getLastModified()
{
return 0L;
}
public long getSize()
{
return 0L;
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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 org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
/**
* Context information for node-related content.
*
* @author Derek Hulley
*/
public class NodeContentContext extends ContentContext
{
private static final long serialVersionUID = -1836714367516857907L;
private NodeRef nodeRef;
private QName propertyQName;
/**
* Construct the instance with the content URL.
*
* @param existingContentReader content with which to seed the new writer - may be <tt>null</tt>
* @param contentUrl the content URL - may be <tt>null</tt>
* @param nodeRef the node holding the content metadata - may not be <tt>null</tt>
* @param propertyQName the property holding the content metadata - may not be <tt>null</tt>
*/
public NodeContentContext(
ContentReader existingContentReader,
String contentUrl,
NodeRef nodeRef,
QName propertyQName)
{
super(existingContentReader, contentUrl);
ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("propertyQName", propertyQName);
this.nodeRef = nodeRef;
this.propertyQName = propertyQName;
}
/**
* @return Returns the node holding the content metadata
*/
public NodeRef getNodeRef()
{
return nodeRef;
}
/**
*
* @return Returns the property holding the content metadata
*/
public QName getPropertyQName()
{
return propertyQName;
}
}

View File

@@ -77,7 +77,6 @@ public class RoutingContentService implements ContentService
{
private static Log logger = LogFactory.getLog(RoutingContentService.class);
private TransactionService transactionService;
private DictionaryService dictionaryService;
private NodeService nodeService;
private AVMService avmService;
@@ -110,9 +109,12 @@ public class RoutingContentService implements ContentService
this.tempStore = new FileContentStore(TempFileProvider.getTempDir().getAbsolutePath());
}
/**
* @deprecated Replaced by {@link #setRetryingTransactionHelper(RetryingTransactionHelper)}
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
logger.warn("Property 'transactionService' has been replaced by 'retryingTransactionHelper'.");
}
public void setRetryingTransactionHelper(RetryingTransactionHelper helper)
@@ -313,7 +315,7 @@ public class RoutingContentService implements ContentService
}
String contentUrl = contentData.getContentUrl();
// TODO: Choose the store to read from at runtime
// The context of the read is entirely described by the URL
ContentReader reader = store.getReader(contentUrl);
// set extra data on the reader
@@ -338,12 +340,11 @@ public class RoutingContentService implements ContentService
public ContentWriter getWriter(NodeRef nodeRef, QName propertyQName, boolean update)
{
// TODO: Choose the store to write to at runtime
if (nodeRef == null)
{
ContentContext ctx = new ContentContext(null, null);
// for this case, we just give back a valid URL into the content store
ContentWriter writer = store.getWriter(null, null);
ContentWriter writer = store.getWriter(ctx);
// done
return writer;
}
@@ -353,7 +354,8 @@ public class RoutingContentService implements ContentService
// get the content using the (potentially) existing content - the new content
// can be wherever the store decides.
ContentWriter writer = store.getWriter(existingContentReader, null);
ContentContext ctx = new NodeContentContext(existingContentReader, null, nodeRef, propertyQName);
ContentWriter writer = store.getWriter(ctx);
// Special case for AVM repository.
Serializable contentValue = null;
@@ -395,7 +397,7 @@ public class RoutingContentService implements ContentService
public ContentWriter getTempWriter()
{
// there is no existing content and we don't specify the location of the new content
return tempStore.getWriter(null, null);
return tempStore.getWriter(ContentContext.NULL_CONTEXT);
}
/**

View File

@@ -32,6 +32,7 @@ import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
@@ -39,10 +40,11 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Provides a store of node content directly to the file system.
* Provides a store of node content directly to the file system. The writers
* are generated using information from the {@link ContentContext simple content context}.
* <p>
* The file names obey, as they must, the URL naming convention
* as specified in the {@link org.alfresco.repo.content.ContentStore}.
* as specified in the {@link org.alfresco.repo.content.ContentStore ContentStore interface}.
*
* @author Derek Hulley
*/
@@ -241,8 +243,10 @@ public class FileContentStore extends AbstractContentStore
/**
* @return Returns a writer onto a location based on the date
*/
public ContentWriter getWriter(ContentReader existingContentReader, String newContentUrl)
public ContentWriter getWriter(ContentContext ctx)
{
ContentReader existingContentReader = ctx.getExistingContentReader();
String newContentUrl = ctx.getContentUrl();
try
{
File file = null;

View File

@@ -35,6 +35,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ContentIOException;
@@ -106,7 +107,6 @@ public class ReplicatingContentStore extends AbstractContentStore
private static Log logger = LogFactory.getLog(ReplicatingContentStore.class);
private TransactionService transactionService;
private RetryingTransactionHelper transactionHelper;
private ContentStore primaryStore;
private List<ContentStore> secondaryStores;
@@ -131,17 +131,17 @@ public class ReplicatingContentStore extends AbstractContentStore
}
/**
* Required to ensure that content listeners are executed in a transaction
*
* @param transactionService
* @deprecated Replaced with {@link #setRetryingTransactionHelper(RetryingTransactionHelper)}
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
logger.warn("Property 'transactionService' has been replaced with 'retryingTransactionHelper'.");
}
/**
* Set the retrying transaction helper.
*
* @since 2.0
*/
public void setRetryingTransactionHelper(RetryingTransactionHelper helper)
{
@@ -273,7 +273,8 @@ public class ReplicatingContentStore extends AbstractContentStore
return primaryContentReader;
}
// get a writer
ContentWriter primaryContentWriter = primaryStore.getWriter(existingContentReader, contentUrl);
ContentContext ctx = new ContentContext(existingContentReader, contentUrl);
ContentWriter primaryContentWriter = primaryStore.getWriter(ctx);
// copy it over
primaryContentWriter.putContent(existingContentReader);
// get a writer to the new content
@@ -287,13 +288,10 @@ public class ReplicatingContentStore extends AbstractContentStore
}
}
/**
*
*/
public ContentWriter getWriter(ContentReader existingContentReader, String newContentUrl) throws ContentIOException
public ContentWriter getWriter(ContentContext ctx)
{
// get the writer
ContentWriter writer = primaryStore.getWriter(existingContentReader, newContentUrl);
ContentWriter writer = primaryStore.getWriter(ctx);
// attach a replicating listener if outbound replication is on
if (outbound)
@@ -434,7 +432,8 @@ public class ReplicatingContentStore extends AbstractContentStore
ContentReader reader = writer.getReader();
String contentUrl = reader.getContentUrl();
// in order to replicate, we have to specify the URL that we are going to write to
ContentWriter replicatedWriter = store.getWriter(null, contentUrl);
ContentContext ctx = new ContentContext(null, contentUrl);
ContentWriter replicatedWriter = store.getWriter(ctx);
// write it
replicatedWriter.putContent(reader);

View File

@@ -33,9 +33,9 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.alfresco.repo.content.AbstractContentReadWriteTest;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.repo.transaction.DummyTransactionService;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.GUID;
@@ -77,7 +77,6 @@ public class ReplicatingContentStoreTest extends AbstractContentReadWriteTest
secondaryStores.add(store);
}
replicatingStore = new ReplicatingContentStore();
replicatingStore.setTransactionService(new DummyTransactionService());
replicatingStore.setPrimaryStore(primaryStore);
replicatingStore.setSecondaryStores(secondaryStores);
replicatingStore.setOutbound(false);
@@ -184,7 +183,7 @@ public class ReplicatingContentStoreTest extends AbstractContentReadWriteTest
// pick a secondary store and write some content to it
ContentStore secondaryStore = secondaryStores.get(2);
ContentWriter writer = secondaryStore.getWriter(null, null);
ContentWriter writer = secondaryStore.getWriter(ContentContext.NULL_CONTEXT);
writer.putContent(SOME_CONTENT);
String contentUrl = writer.getContentUrl();

View File

@@ -28,6 +28,7 @@ import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.search.Indexer;
@@ -148,7 +149,8 @@ public class MissingContentReindexComponentTest extends TestCase
}
// now put some content in the store
ContentWriter writer = contentStore.getWriter(null, contentUrl);
ContentContext ctx = new ContentContext(null, contentUrl);
ContentWriter writer = contentStore.getWriter(ctx);
writer.setMimetype("text/plain");
writer.setEncoding("UTF8");
writer.putContent("123abc456def");