diff --git a/config/alfresco/extension/replicating-content-services-context.xml.sample b/config/alfresco/extension/replicating-content-services-context.xml.sample
index 9e53220166..40a39b7d92 100644
--- a/config/alfresco/extension/replicating-content-services-context.xml.sample
+++ b/config/alfresco/extension/replicating-content-services-context.xml.sample
@@ -74,9 +74,6 @@
+ * 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 null + * @param contentUrl the content URL - may be null + */ + 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 null + */ + public ContentReader getExistingContentReader() + { + return existingContentReader; + } + + /** + * @return Returns the content URL for the content's context - may be null + */ + public String getContentUrl() + { + return contentUrl; + } + +} diff --git a/source/java/org/alfresco/repo/content/ContentStore.java b/source/java/org/alfresco/repo/content/ContentStore.java index 1552410755..d8d379e55b 100644 --- a/source/java/org/alfresco/repo/content/ContentStore.java +++ b/source/java/org/alfresco/repo/content/ContentStore.java @@ -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; *
+ * The store will ensure that the {@link ContentAccessor#getContentUrl() new content URL} will + * be valid for all subsequent read attempts. + *
* 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 *
* 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 true is returned.
* @throws ContentIOException
*/
public boolean delete(String contentUrl) throws ContentIOException;
diff --git a/source/java/org/alfresco/repo/content/EmptyContentReader.java b/source/java/org/alfresco/repo/content/EmptyContentReader.java
new file mode 100644
index 0000000000..fc342df616
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/EmptyContentReader.java
@@ -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 exists()
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;
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/NodeContentContext.java b/source/java/org/alfresco/repo/content/NodeContentContext.java
new file mode 100644
index 0000000000..392ec56c79
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/NodeContentContext.java
@@ -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 null
+ * @param contentUrl the content URL - may be null
+ * @param nodeRef the node holding the content metadata - may not be null
+ * @param propertyQName the property holding the content metadata - may not be null
+ */
+ 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;
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/RoutingContentService.java b/source/java/org/alfresco/repo/content/RoutingContentService.java
index f0156edd66..d20ca5adad 100644
--- a/source/java/org/alfresco/repo/content/RoutingContentService.java
+++ b/source/java/org/alfresco/repo/content/RoutingContentService.java
@@ -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);
}
/**
diff --git a/source/java/org/alfresco/repo/content/filestore/FileContentStore.java b/source/java/org/alfresco/repo/content/filestore/FileContentStore.java
index 7d21aa7b4d..3c8d0ba09f 100644
--- a/source/java/org/alfresco/repo/content/filestore/FileContentStore.java
+++ b/source/java/org/alfresco/repo/content/filestore/FileContentStore.java
@@ -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}.
*
* 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;
diff --git a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java
index b77aa1ae7e..6d1f7e0156 100644
--- a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java
+++ b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java
@@ -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