diff --git a/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java b/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java index 6fe3867442..c5eeabac8f 100644 --- a/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java +++ b/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java @@ -23,8 +23,8 @@ * along with Alfresco. If not, see . * #L% */ -package org.alfresco.repo.content.replication; - +package org.alfresco.repo.content.replication; + import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; @@ -34,161 +34,232 @@ 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.content.UnsupportedContentUrlException; 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.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - -/** - *

Aggregating Content Store

- *

- * A content store implementation that aggregates a set of stores. Content is not - * persisted by this store, but rather it relies on any number of - * child {@link org.alfresco.repo.content.ContentStore stores} to provide access - * to content readers and writers. - *

- * The order in which the stores appear in the list of stores participating is - * important. The first store in the list is known as the primary store. -

- * Content is written to the primary store only. The other stores are - * only used to retrieve content and the primary store is not updated with - * the content. - * - * @author Derek Hulley - * @author Mark Rogers - * @see CachingContentStore - */ -public class AggregatingContentStore extends AbstractContentStore -{ - private static Log logger = LogFactory.getLog(AggregatingContentStore.class); - - private ContentStore primaryStore; - private List secondaryStores; - - private Lock readLock; - - /** - * Default constructor - */ - public AggregatingContentStore() - { - ReadWriteLock storeLock = new ReentrantReadWriteLock(); - readLock = storeLock.readLock(); - } - - /** - * Set the primary store that content will be replicated to or from - * - * @param primaryStore the primary content store - */ - public void setPrimaryStore(ContentStore primaryStore) - { - this.primaryStore = primaryStore; - } - - /** - * Set the secondary stores that this component will replicate to or from - * - * @param secondaryStores a list of stores to replicate to or from - */ - public void setSecondaryStores(List secondaryStores) - { - this.secondaryStores = secondaryStores; - } - - /** - * @return Returns true if the primary store supports writing - */ - public boolean isWriteSupported() - { - return primaryStore.isWriteSupported(); - } - - /** - * @return Returns true if the primary store supports the URL - */ - @Override - public boolean isContentUrlSupported(String contentUrl) - { - return primaryStore.isContentUrlSupported(contentUrl); - } - - /** - * @return Return the primary store root location - */ - @Override - public String getRootLocation() - { - return primaryStore.getRootLocation(); - } - - /** - * Forwards the call directly to the first store in the list of stores. - */ - public ContentReader getReader(String contentUrl) throws ContentIOException - { - 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 - { - // get a reader from the primary store - ContentReader primaryReader = primaryStore.getReader(contentUrl); - - // give it straight back if the content is there - if (primaryReader.exists()) - { - return primaryReader; - } - - // the content is not in the primary reader so we have to go looking for it - for (ContentStore store : secondaryStores) - { - ContentReader reader = store.getReader(contentUrl); - if (reader.exists()) - { - // found the content in a secondary store - return reader; - } - } - - return primaryReader; - } - finally - { - readLock.unlock(); - } - } - - public ContentWriter getWriter(ContentContext ctx) - { - // get the writer - ContentWriter writer = primaryStore.getWriter(ctx); - - return writer; - } - - /** - * Performs a delete on the local store and if outbound replication is on, propogates - * the delete to the other stores too. - * - * @return Returns the value returned by the delete on the primary store. - */ - public boolean delete(String contentUrl) throws ContentIOException - { - // delete on the primary store - boolean deleted = primaryStore.delete(contentUrl); - - if (logger.isDebugEnabled()) - { - logger.debug("Deleted content for URL: " + contentUrl); - } - return deleted; - } -} + +/** + *

Aggregating Content Store

+ *

+ * A content store implementation that aggregates a set of stores. Content is not + * persisted by this store, but rather it relies on any number of + * child {@link org.alfresco.repo.content.ContentStore stores} to provide access + * to content readers and writers. + *

+ * The order in which the stores appear in the list of stores participating is + * important. The first store in the list is known as the primary store. +

+ * Content is written to the primary store only. The other stores are + * only used to retrieve content and the primary store is not updated with + * the content. + * + * @author Derek Hulley + * @author Mark Rogers + * @see CachingContentStore + */ +public class AggregatingContentStore extends AbstractContentStore +{ + private static Log logger = LogFactory.getLog(AggregatingContentStore.class); + + private ContentStore primaryStore; + private List secondaryStores; + + private Lock readLock; + + /** + * Default constructor + */ + public AggregatingContentStore() + { + ReadWriteLock storeLock = new ReentrantReadWriteLock(); + readLock = storeLock.readLock(); + } + + /** + * Set the primary store that content will be replicated to or from + * + * @param primaryStore the primary content store + */ + public void setPrimaryStore(ContentStore primaryStore) + { + this.primaryStore = primaryStore; + } + + /** + * Set the secondary stores that this component will replicate to or from + * + * @param secondaryStores a list of stores to replicate to or from + */ + public void setSecondaryStores(List secondaryStores) + { + this.secondaryStores = secondaryStores; + } + + /** + * @return Returns true if the primary store supports writing + */ + public boolean isWriteSupported() + { + return primaryStore.isWriteSupported(); + } + + /** + * @return Returns true if the primary store supports the URL + */ + @Override + public boolean isContentUrlSupported(String contentUrl) + { + return primaryStore.isContentUrlSupported(contentUrl); + } + + /** + * @return Return the primary store root location + */ + @Override + public String getRootLocation() + { + return primaryStore.getRootLocation(); + } + + /** + * Forwards the call directly to the first store in the list of stores. + */ + public ContentReader getReader(String contentUrl) throws ContentIOException + { + 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 + { + // get a reader from the primary store + ContentReader primaryReader = primaryStore.getReader(contentUrl); + + // give it straight back if the content is there + if (primaryReader.exists()) + { + return primaryReader; + } + + // the content is not in the primary reader so we have to go looking for it + for (ContentStore store : secondaryStores) + { + ContentReader reader = store.getReader(contentUrl); + if (reader.exists()) + { + // found the content in a secondary store + return reader; + } + } + + return primaryReader; + } + finally + { + readLock.unlock(); + } + } + + public boolean exists(String contentUrl) + { + 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 = false; + + boolean contentUrlExists = false; + + // Check the primary store + try + { + contentUrlExists = primaryStore.exists(contentUrl); + + // At least the content URL was supported + contentUrlSupported = true; + } + catch (UnsupportedContentUrlException e) + { + // The store can't handle the content URL + } + + if (contentUrlExists) + { + return true; + } + + // the content is not in the primary store so we have to go looking for it + for (ContentStore store : secondaryStores) + { + contentUrlExists = false; + try + { + contentUrlExists = store.exists(contentUrl); + + // At least the content URL was supported + contentUrlSupported = true; + } + catch (UnsupportedContentUrlException e) + { + // The store can't handle the content URL + } + + if (contentUrlExists) + { + break; + } + } + + // Check if the content URL was supported + if (!contentUrlSupported) + { + throw new UnsupportedContentUrlException(this, contentUrl); + } + + return contentUrlExists; + } + finally + { + readLock.unlock(); + } + } + + public ContentWriter getWriter(ContentContext ctx) + { + // get the writer + ContentWriter writer = primaryStore.getWriter(ctx); + + return writer; + } + + /** + * Performs a delete on the local store and if outbound replication is on, propogates + * the delete to the other stores too. + * + * @return Returns the value returned by the delete on the primary store. + */ + public boolean delete(String contentUrl) throws ContentIOException + { + // delete on the primary store + boolean deleted = primaryStore.delete(contentUrl); + + if (logger.isDebugEnabled()) + { + logger.debug("Deleted content for URL: " + contentUrl); + } + return deleted; + } +}