diff --git a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java index 89df4bd0bf..fe93d04f4a 100644 --- a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java +++ b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java @@ -68,26 +68,20 @@ public class ContentNetworkFile extends NodeRefNetworkFile private static final Log logger = LogFactory.getLog(ContentNetworkFile.class); // Services - private NodeService nodeService; private ContentService contentService; private MimetypeService mimetypeService; - // File channel to file content - private FileChannel channel; - - // File content - - private ContentAccessor content; + private FileChannel channel; // File channel to file content + private ContentAccessor content; // content + private String preUpdateContentURL; // Indicate if file has been written to or truncated/resized - private boolean modified; // Flag to indicate if the file channel is writable - private boolean writableChannel; /** @@ -265,6 +259,8 @@ public class ContentNetworkFile extends NodeRefNetworkFile /** * Opens the channel for reading or writing depending on the access mode. *
+ * Side effect: sets fileSize + *
* If the channel is already open, it is left.
*
* @param write true if the channel must be writable
@@ -277,122 +273,137 @@ public class ContentNetworkFile extends NodeRefNetworkFile
* @see NetworkFile#WRITEONLY
* @see NetworkFile#READWRITE
*/
- protected void openContent(boolean write, boolean trunc)
+ public void openContent(boolean write, boolean trunc)
throws AccessDeniedException, AlfrescoRuntimeException
{
// Check if the file is a directory
if (isDirectory())
{
- throw new AlfrescoRuntimeException("Unable to open channel for a directory network file: " + this);
+ throw new AlfrescoRuntimeException("Unable to open content for a directory network file: " + this);
+ }
+
+ if(channel != null && !write)
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("channel is already open for read-only");
+ }
+ return;
}
// Check if write access is required and the current channel is read-only
- else if ( write && writableChannel == false && channel != null)
+ // update of channel and content member variables need to be serialized
+ synchronized(this)
{
- // Close the existing read-only channel
-
- try
+ if ( write && writableChannel == false && channel != null)
{
- channel.close();
- channel = null;
+ // Close the existing read-only channel
+
+ try
+ {
+ channel.close();
+ channel = null;
+ content = null;
+ }
+ catch (IOException ex)
+ {
+ logger.error("Error closing read-only channel", ex);
+ }
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ {
+ logger.debug("Switching to writable channel for " + getName());
+ }
}
- catch (IOException ex)
+ else if (channel != null)
{
- logger.error("Error closing read-only channel", ex);
+ // Already have read/write channel open
+ return;
}
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Switching to writable channel for " + getName());
- }
- else if (channel != null)
- {
- // Already have channel open
-
- return;
- }
+
+ // We need to create the channel
- // We need to create the channel
-
- if (write && !isWritable())
- {
- throw new AccessDeniedException("The network file was created for read-only: " + this);
- }
-
- content = null;
- preUpdateContentURL = null;
- if (write)
- {
- // Get a writeable channel to the content, along with the original content
- if(logger.isDebugEnabled())
+ if (write && !isWritable())
{
- logger.debug("get writer for content property");
+ throw new AccessDeniedException("The network file was created for read-only: " + this);
}
+
+ preUpdateContentURL = null;
+
+ // Need to open content for write
+ if (write)
+ {
+ // Get a writeable channel to the content, along with the original content
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("open writer for content property");
+ }
- content = contentService.getWriter( getNodeRef(), ContentModel.PROP_CONTENT, false);
+ content = contentService.getWriter( getNodeRef(), ContentModel.PROP_CONTENT, false);
- // Keep the original content for later comparison
+ // Keep the original content for later comparison
- ContentData preUpdateContentData = (ContentData) nodeService.getProperty( getNodeRef(), ContentModel.PROP_CONTENT);
- if (preUpdateContentData != null)
- {
- preUpdateContentURL = preUpdateContentData.getContentUrl();
+ ContentData preUpdateContentData = (ContentData) nodeService.getProperty( getNodeRef(), ContentModel.PROP_CONTENT);
+ if (preUpdateContentData != null)
+ {
+ preUpdateContentURL = preUpdateContentData.getContentUrl();
+ }
+
+ // Indicate that we have a writable channel to the file
+
+ writableChannel = true;
+
+ // Get the writable channel, do not copy existing content data if the file is to be truncated
+ channel = ((ContentWriter) content).getFileChannel( trunc);
}
-
- // Indicate that we have a writable channel to the file
-
- writableChannel = true;
-
- // Get the writable channel, do not copy existing content data if the file is to be truncated
-
- channel = ((ContentWriter) content).getFileChannel( trunc);
- }
- else
- {
- // Get a read-only channel to the content
- if(logger.isDebugEnabled())
+ else
{
- logger.debug("get reader for content property");
- }
+ // Get a read-only channel to the content
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("open reader for content property");
+ }
- content = contentService.getReader( getNodeRef(), ContentModel.PROP_CONTENT);
+ content = contentService.getReader( getNodeRef(), ContentModel.PROP_CONTENT);
- // Ensure that the content we are going to read is valid
+ // Ensure that the content we are going to read is valid
- content = FileContentReader.getSafeContentReader(
+ content = FileContentReader.getSafeContentReader(
(ContentReader) content,
I18NUtil.getMessage(FileContentReader.MSG_MISSING_CONTENT),
getNodeRef(), content);
- // Indicate that we only have a read-only channel to the data
+ // Indicate that we only have a read-only channel to the data
- writableChannel = false;
+ writableChannel = false;
- // Get the read-only channel
+ // Get the read-only channel
- channel = ((ContentReader) content).getFileChannel();
- }
-
- // Update the current file size
-
- if ( channel != null)
- {
- try
- {
- setFileSize(channel.size());
+ channel = ((ContentReader) content).getFileChannel();
}
- catch (IOException ex)
+
+ // Update the current file size
+
+ if ( channel != null)
{
- logger.error( ex);
+ try
+ {
+ setFileSize(channel.size());
+ }
+ catch (IOException ex)
+ {
+ logger.error( ex);
+ }
+
+ // Indicate that the file is open
+
+ setClosed( false);
}
-
- // Indicate that the file is open
-
- setClosed( false);
- }
+ } // release lock
}
/**
@@ -420,9 +431,8 @@ public class ContentNetworkFile extends NodeRefNetworkFile
setClosed( true);
return;
}
- else if (!hasContent())
- {
- // File was not read/written so channel was not opened
+ else if (!hasContent()) {
+ // File was not read/written so content was not opened
if(logger.isDebugEnabled())
{
logger.debug("no content to write - nothing to do");
@@ -434,18 +444,27 @@ public class ContentNetworkFile extends NodeRefNetworkFile
// Check if the file has been modified
- if (modified)
+ // update of channel and content member variables need to be serialized
+ synchronized(this)
{
- if(logger.isDebugEnabled())
+
+ if (modified)
{
- logger.debug("content has been modified");
- }
- NodeRef contentNodeRef = getNodeRef();
- ContentWriter writer = (ContentWriter)content;
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("content has been modified");
+ }
+ NodeRef contentNodeRef = getNodeRef();
+ ContentWriter writer = (ContentWriter)content;
- // We may be in a retry block, in which case this section will already have executed and channel will be null
- if (channel != null)
- {
+ // We may be in a retry block, in which case this section will already have executed and channel will be null
+ if (channel != null)
+ {
+ // Close the channel
+ channel.close();
+ channel = null;
+ }
+
// Do we need the mimetype guessing for us when we're done?
if (content.getMimetype() == null || content.getMimetype().equals(MimetypeMap.MIMETYPE_BINARY) )
{
@@ -456,73 +475,79 @@ public class ContentNetworkFile extends NodeRefNetworkFile
// We always want the encoding guessing
writer.guessEncoding();
- // Close the channel
- channel.close();
- channel = null;
- }
+ // Retrieve the content data and stop the content URL from being 'eagerly deleted', in case we need to
+ // retry the transaction
+
+ final ContentData contentData = content.getContentData();
+
+ // Update node properties, but only if the binary has changed (ETHREEOH-1861)
- // Retrieve the content data and stop the content URL from being 'eagerly deleted', in case we need to
- // retry the transaction
+ ContentReader postUpdateContentReader = writer.getReader();
- final ContentData contentData = content.getContentData();
-
- // Update node properties, but only if the binary has changed (ETHREEOH-1861)
-
- ContentReader postUpdateContentReader = writer.getReader();
-
- RunAsWork