Various fixes for MS Office problems (two versions on edit/save, version generated when file opened and not changed (ACT 3691).

Added file access/change/modification timestamp tracking for open files via the file state cache.
Added set file information support for setting creation and modification timestamps, used by MS Office to transfer original timestamp to new document.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10007 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gary Spencer
2008-07-24 14:26:09 +00:00
parent 18164f15cc
commit 4935889656
10 changed files with 618 additions and 61 deletions

View File

@@ -346,7 +346,7 @@ public class AVMContext extends AlfrescoContext
// Update the file state modify time // Update the file state modify time
rootState.setLastUpdated( System.currentTimeMillis()); rootState.updateModifyDateTime();
// Send a change notification for the deleted folder // Send a change notification for the deleted folder

View File

@@ -25,10 +25,8 @@ package org.alfresco.filesys.avm;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@@ -41,7 +39,6 @@ import org.alfresco.jlan.server.SrvSession;
import org.alfresco.jlan.server.auth.ClientInfo; import org.alfresco.jlan.server.auth.ClientInfo;
import org.alfresco.jlan.server.core.DeviceContext; import org.alfresco.jlan.server.core.DeviceContext;
import org.alfresco.jlan.server.core.DeviceContextException; import org.alfresco.jlan.server.core.DeviceContextException;
import org.alfresco.jlan.server.core.DeviceInterface;
import org.alfresco.jlan.server.filesys.AccessDeniedException; import org.alfresco.jlan.server.filesys.AccessDeniedException;
import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException; import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException;
import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.DiskInterface;
@@ -81,14 +78,9 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2006-2008 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.filesys.repo;
/**
* Buffered Write Class
*
* <p>Contains the details and data for a buffered write.
*
* @author gkspencer
*/
public class BufferedWrite {
// Write details
private long m_offset;
private byte[] m_data;
/**
* Class constructor
*
* @param buf byte[]
* @param offset long
*/
public BufferedWrite( byte[] buf, long offset) {
m_data = buf;
m_offset = offset;
}
/**
* Return the file offset
*
* @return long
*/
public final long getOffset() {
return m_offset;
}
/**
* Return the write data
*
* @return byte[]
*/
public final byte[] getData() {
return m_data;
}
/**
* Return the data length
*
* @return int
*/
public final int getDataLength() {
return m_data != null ? m_data.length : 0;
}
/**
* Return the buffered write details as a string
*
* @return String
*/
public String toString() {
StringBuilder str = new StringBuilder();
str.append("[Data len=");
str.append(m_data.length);
str.append(",Offset=");
str.append(m_offset);
str.append("]");
return str.toString();
}
}

View File

@@ -636,10 +636,6 @@ public class CifsHelper
{ {
try try
{ {
// Check if the new file name is a temporary file name
if ( newName.endsWith(".tmp") || newName.endsWith(".temp"))
nodeService.addAspect(nodeToRenameRef, ContentModel.ASPECT_TEMPORARY, null);
fileFolderService.rename(nodeToRenameRef, newName); fileFolderService.rename(nodeToRenameRef, newName);
} }
catch (org.alfresco.service.cmr.model.FileExistsException e) catch (org.alfresco.service.cmr.model.FileExistsException e)

View File

@@ -27,6 +27,7 @@ package org.alfresco.filesys.repo;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Date;
import java.util.List; import java.util.List;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
@@ -606,8 +607,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Debug // Debug
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Added file state for pseudo files folder (getinfo) - " + paths[0]); logger.debug( "Added file state for pseudo files folder (getinfo) - " + paths[0]);
} }
else if ( fstate.hasPseudoFiles() == false) else if ( fstate.hasPseudoFiles() == false)
{ {
@@ -626,8 +627,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Debug // Debug
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Added pseudo files for folder (exists) - " + paths[0]); logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
} }
@@ -657,6 +658,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Get the node ref for the path, chances are there is a file state in the cache // Get the node ref for the path, chances are there is a file state in the cache
NodeRef nodeRef = getNodeForPath(tree, infoPath); NodeRef nodeRef = getNodeForPath(tree, infoPath);
if ( nodeRef != null) if ( nodeRef != null)
{ {
// Get the file information for the node // Get the file information for the node
@@ -665,7 +667,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// DEBUG // DEBUG
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.debug("getInfo using cached noderef for path " + path); logger.debug("getInfo using cached noderef for path " + path);
} }
@@ -689,7 +691,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// DEBUG // DEBUG
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.debug("getInfo using cached noderef for parent " + path); logger.debug("getInfo using cached noderef for parent " + path);
} }
} }
@@ -710,9 +712,25 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Set the file id for the file using the relative path // Set the file id for the file using the relative path
if ( finfo != null) if ( finfo != null) {
// Set the file id
finfo.setFileId( path.hashCode()); finfo.setFileId( path.hashCode());
// Copy cached timestamps, if available
FileState fstate = getStateForPath(tree, infoPath);
if ( fstate != null) {
if ( fstate.hasAccessDateTime())
finfo.setAccessDateTime(fstate.getAccessDateTime());
if ( fstate.hasChangeDateTime())
finfo.setChangeDateTime(fstate.getChangeDateTime());
if ( fstate.hasModifyDateTime())
finfo.setModifyDateTime(fstate.getModifyDateTime());
}
}
// Return the file information // Return the file information
return finfo; return finfo;
@@ -1019,8 +1037,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Debug // Debug
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Added file state for pseudo files folder (exists) - " + paths[0]); logger.debug( "Added file state for pseudo files folder (exists) - " + paths[0]);
} }
} }
else if ( fstate.hasPseudoFiles() == false) else if ( fstate.hasPseudoFiles() == false)
@@ -1044,8 +1062,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Debug // Debug
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Added pseudo files for folder (exists) - " + paths[0]); logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
} }
// Check if the path is to a pseudo file // Check if the path is to a pseudo file
@@ -1061,8 +1079,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
{ {
// Failed to find pseudo file // Failed to find pseudo file
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Failed to find pseudo file (exists) - " + name); logger.debug( "Failed to find pseudo file (exists) - " + name);
} }
} }
} }
@@ -1167,8 +1185,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Debug // Debug
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Added file state for pseudo files folder (open) - " + paths[0]); logger.debug( "Added file state for pseudo files folder (open) - " + paths[0]);
} }
} }
else if ( fstate.hasPseudoFiles() == false) else if ( fstate.hasPseudoFiles() == false)
@@ -1179,8 +1197,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Debug // Debug
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Added pseudo files for folder (open) - " + paths[0]); logger.debug( "Added pseudo files for folder (open) - " + paths[0]);
} }
// Check if the path is to a pseudo file // Check if the path is to a pseudo file
@@ -1196,8 +1214,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
{ {
// Failed to find pseudo file // Failed to find pseudo file
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.info( "Failed to find pseudo file (open) - " + params.getPath()); logger.debug( "Failed to find pseudo file (open) - " + params.getPath());
} }
} }
} }
@@ -1439,7 +1457,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// DEBUG // DEBUG
if ( logger.isInfoEnabled()) if ( logger.isDebugEnabled())
logger.debug("Create file using cached noderef for path " + paths[0]); logger.debug("Create file using cached noderef for path " + paths[0]);
} }
} }
@@ -2019,9 +2037,46 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( sameFolder == true) if ( sameFolder == true)
{ {
// Check if the new file name is a temporary file name
String newNameNorm = newName.toLowerCase();
boolean isTempFile = false;
if ( newNameNorm.endsWith(".tmp") || newNameNorm.endsWith(".temp")) {
// Add the temporary aspect, also prevents versioning
nodeService.addAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY, null);
// Indicate that the new file is a temporary file
isTempFile = true;
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Added Temporary aspect to renamed file " + newName);
}
// Rename the file/folder // Rename the file/folder
cifsHelper.rename(nodeToMoveRef, name); cifsHelper.rename(nodeToMoveRef, name);
// Check if the temporary aspect should be removed from the renamed file
String oldNameNorm = oldName.toLowerCase();
if ( isTempFile == false && (oldNameNorm.endsWith(".tmp") || oldNameNorm.endsWith(".temp"))) {
// Remove the temporary aspect
nodeService.removeAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Removed Temporary aspect from renamed file " + newName);
}
// DEBUG // DEBUG
@@ -2151,6 +2206,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Get the file/folder node // Get the file/folder node
NodeRef nodeRef = getNodeForPath(tree, name); NodeRef nodeRef = getNodeForPath(tree, name);
FileState fstate = getStateForPath(tree, name);
// Check permissions on the file/folder node // Check permissions on the file/folder node
@@ -2164,6 +2220,10 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose()) if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose())
{ {
// Start a transaction
beginReadTransaction( sess);
// Check if the node is locked // Check if the node is locked
if ( nodeService.hasAspect( nodeRef, ContentModel.ASPECT_LOCKABLE)) if ( nodeService.hasAspect( nodeRef, ContentModel.ASPECT_LOCKABLE))
@@ -2175,6 +2235,64 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( lockTypeStr != null) if ( lockTypeStr != null)
throw new AccessDeniedException("Node locked, cannot mark for delete"); throw new AccessDeniedException("Node locked, cannot mark for delete");
} }
// Update the change date/time
if ( fstate != null)
fstate.updateChangeDateTime();
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Set deleteOnClose=true file=" + name);
}
// Set the creation date/time
if ( info.hasSetFlag(FileInfo.SetCreationDate)) {
// Create the transaction
beginWriteTransaction( sess);
// Set the creation date on the file/folder node
Date createDate = new Date( info.getCreationDateTime());
nodeService.setProperty( nodeRef, ContentModel.PROP_CREATED, createDate);
// Update the change date/time
if ( fstate != null)
fstate.updateChangeDateTime();
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Set creationDate=" + createDate + " file=" + name);
}
// Set the modification date/time
if ( info.hasSetFlag(FileInfo.SetModifyDate)) {
// Create the transaction
beginWriteTransaction( sess);
// Set the creation date on the file/folder node
Date modifyDate = new Date( info.getModifyDateTime());
nodeService.setProperty( nodeRef, ContentModel.PROP_MODIFIED, modifyDate);
// Update the change date/time
if ( fstate != null)
fstate.updateChangeDateTime();
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Set modifyDate=" + modifyDate + " file=" + name);
} }
} }
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex) catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)

View File

@@ -69,6 +69,8 @@ public class ContentNetworkFile extends NodeRefNetworkFile
{ {
private static final Log logger = LogFactory.getLog(ContentNetworkFile.class); private static final Log logger = LogFactory.getLog(ContentNetworkFile.class);
// Services
private NodeService nodeService; private NodeService nodeService;
private ContentService contentService; private ContentService contentService;
private MimetypeService mimetypeService; private MimetypeService mimetypeService;
@@ -107,7 +109,20 @@ public class ContentNetworkFile extends NodeRefNetworkFile
// Create the file // Create the file
ContentNetworkFile netFile = new ContentNetworkFile(nodeService, contentService, mimetypeService, nodeRef, path); ContentNetworkFile netFile = null;
if ( isMSOfficeSpecialFile(path)) {
// Create a file for special processing
netFile = new MSOfficeContentNetworkFile( nodeService, contentService, mimetypeService, nodeRef, path);
}
else {
// Create a normal content file
netFile = new ContentNetworkFile(nodeService, contentService, mimetypeService, nodeRef, path);
}
// Set relevant parameters // Set relevant parameters
@@ -182,7 +197,7 @@ public class ContentNetworkFile extends NodeRefNetworkFile
* @param nodeRef NodeRef * @param nodeRef NodeRef
* @param name String * @param name String
*/ */
private ContentNetworkFile( protected ContentNetworkFile(
NodeService nodeService, NodeService nodeService,
ContentService contentService, ContentService contentService,
MimetypeService mimetypeService, MimetypeService mimetypeService,
@@ -439,6 +454,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile
setFileSize( size); setFileSize( size);
// Update the modification date/time
if ( getFileState() != null)
getFileState().updateModifyDateTime();
// DEBUG // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@@ -475,6 +495,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile
setFileSize(channel.size()); setFileSize(channel.size());
// Update the modification date/time
if ( getFileState() != null)
getFileState().updateModifyDateTime();
// DEBUG // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@@ -507,6 +532,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile
count = 0; // doesn't obey the same rules, i.e. just returns the bytes read count = 0; // doesn't obey the same rules, i.e. just returns the bytes read
} }
// Update the access date/time
if ( getFileState() != null)
getFileState().updateAccessDateTime();
// DEBUG // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@@ -574,6 +604,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile
break; break;
} }
// Update the access date/time
if ( getFileState() != null)
getFileState().updateAccessDateTime();
// DEBUG // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@@ -601,9 +636,31 @@ public class ContentNetworkFile extends NodeRefNetworkFile
channel.force(false); channel.force(false);
// Update the access date/time
if ( getFileState() != null)
getFileState().updateAccessDateTime();
// DEBUG // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Flush file=" + this); logger.debug("Flush file=" + this);
} }
/**
* Check if the file is an MS Office document type that needs special processing
*
* @param path String
* @return boolean
*/
private static final boolean isMSOfficeSpecialFile(String path) {
// Check if the file extension indicates a problem MS Office format
path = path.toLowerCase();
if ( path.endsWith( ".xls"))
return true;
return false;
}
} }

View File

@@ -0,0 +1,213 @@
/*
* Copyright (C) 2006-2008 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.filesys.repo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Ms Office Content Network File Class
*
* <p>Provides special handling for MS Office files that are written to by the app even though the user does not
* change the file.
*
* @author gkspencer
*/
public class MSOfficeContentNetworkFile extends ContentNetworkFile {
private static final Log logger = LogFactory.getLog(MSOfficeContentNetworkFile.class);
// Count of file reads
private int m_readCnt;
// Buffered write list
private List<BufferedWrite> m_writeList;
/**
* Class constructor
*
* @param transactionService TransactionService
* @param nodeService NodeService
* @param contentService ContentService
* @param nodeRef NodeRef
* @param name String
*/
protected MSOfficeContentNetworkFile(
NodeService nodeService,
ContentService contentService,
MimetypeService mimetypeService,
NodeRef nodeRef,
String name)
{
super(nodeService, contentService, mimetypeService, nodeRef, name);
// Create the buffered write list
m_writeList = new ArrayList<BufferedWrite>();
}
/**
* Return the file read count
*
* @return int
*/
public final int getReadCount() {
return m_readCnt;
}
/**
* Read from the file.
*
* @param buf byte[]
* @param len int
* @param pos int
* @param fileOff long
* @return Length of data read.
* @exception IOException
*/
public int readFile(byte[] buffer, int length, int position, long fileOffset)
throws IOException
{
// Update the read count
m_readCnt++;
// Chain to the standard read
return super.readFile( buffer, length, position, fileOffset);
}
/**
* Write a block of data to the file.
*
* @param buf byte[]
* @param len int
* @param pos int
* @param fileOff long
* @exception IOException
*/
public void writeFile(byte[] buffer, int length, int position, long fileOffset)
throws IOException
{
// Check if writes are being buffered
if ( m_writeList != null) {
// Check if the write should be buffered
if ( getReadCount() > 0 && m_writeList.size() < 2) {
// Buffer the write, looks like a file open update. Do not buffer zero length writes.
if ( length == 0) {
byte[] data = new byte[ length];
System.arraycopy(buffer, position, data, 0, length);
BufferedWrite bufWrite = new BufferedWrite( data, fileOffset);
m_writeList.add( bufWrite);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("MSOfficeFile: Buffered write=" + bufWrite + ", cnt=" + m_writeList.size() + ", readCnt=" + getReadCount());
}
else if ( logger.isDebugEnabled())
logger.debug("MSOfficeFile: Ignored zero length write");
return;
}
// Check if there are any buffered writes to be flushed
if ( m_writeList.size() > 0) {
// Write out the buffered writes first
while ( m_writeList.size() > 0) {
// Get the current buffered write
BufferedWrite bufWrite = m_writeList.remove( 0);
try {
// Write the buffered data to the file
super.writeFile( bufWrite.getData(), bufWrite.getDataLength(), 0, bufWrite.getOffset());
}
catch ( Exception ex) {
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("MSOfficeFile: Buffered write error, " + ex.getMessage());
}
}
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("MSOfficeFile: Buffered writes flushed");
// Disable any more buffered writes
m_writeList = null;
}
}
// Now do the current write
super.writeFile(buffer, length, position, fileOffset);
}
/**
* Close the file
*
* @exception IOException
*/
public void closeFile()
throws IOException
{
// DEBUG
if ( logger.isDebugEnabled() && m_writeList != null)
logger.debug("MSOfficeFile: Discarded buffered writes - " + m_writeList.size());
// Chain to the standard close
super.closeFile();
}
}

View File

@@ -95,9 +95,11 @@ public class FileState
private PseudoFileList m_pseudoFiles; private PseudoFileList m_pseudoFiles;
// Last updated time // File timestamps updated only whilst file is open
private long m_lastUpdate; private long m_accessDate;
private long m_modifyDate;
private long m_changeDate;
/** /**
* Class constructor * Class constructor
@@ -442,26 +444,6 @@ public class FileState
m_path = normalizePath(path); m_path = normalizePath(path);
} }
/**
* Return the last updated time
*
* @return long
*/
public final long getLastUpdated()
{
return m_lastUpdate;
}
/**
* Set the last updated time
*
* @param updateTime long
*/
public final void setLastUpdated(long updateTime)
{
m_lastUpdate = updateTime;
}
/** /**
* Return the count of active locks on this file * Return the count of active locks on this file
* *
@@ -544,6 +526,91 @@ public class FileState
} }
} }
/**
* Check if the access date/time has been set
*
* @return boolean
*/
public final boolean hasAccessDateTime() {
return m_accessDate != 0L ? true : false;
}
/**
* Return the access date/time
*
* @return long
*/
public final long getAccessDateTime() {
return m_accessDate;
}
/**
* Update the access date/time
*/
public final void updateAccessDateTime() {
m_accessDate = System.currentTimeMillis();
}
/**
* Check if the change date/time has been set
*
* @return boolean
*/
public final boolean hasChangeDateTime() {
return m_changeDate != 0L ? true : false;
}
/**
* Return the change date/time
*
* @return long
*/
public final long getChangeDateTime() {
return m_changeDate;
}
/**
* Update the change date/time
*/
public final void updateChangeDateTime() {
m_changeDate = System.currentTimeMillis();
}
/**
* Check if the modification date/time has been set
*
* @return boolean
*/
public final boolean hasModifyDateTime() {
return m_modifyDate != 0L ? true : false;
}
/**
* Return the modify date/time
*
* @return long
*/
public final long getModifyDateTime() {
return m_modifyDate;
}
/**
* Update the modify date/time
*/
public final void updateModifyDateTime() {
m_modifyDate = System.currentTimeMillis();
m_accessDate = m_modifyDate;
}
/**
* Update the modify date/time
*
* @param modTime long
*/
public final void updateModifyDateTime( long modTime) {
m_modifyDate = modTime;
}
/** /**
* Check if the file is readable for the specified section of the file and process id * Check if the file is readable for the specified section of the file and process id
* *

View File

@@ -127,7 +127,12 @@ public class FileStateTable
*/ */
public final synchronized FileState findFileState(String path) public final synchronized FileState findFileState(String path)
{ {
return m_stateTable.get(FileState.normalizePath(path)); FileState fstate = m_stateTable.get(FileState.normalizePath(path));
if ( fstate != null)
fstate.updateAccessDateTime();
return fstate;
} }
/** /**
@@ -168,6 +173,11 @@ public class FileStateTable
} }
} }
// Update the access date/time if valid
if ( state != null)
state.updateAccessDateTime();
// Return the file state // Return the file state
return state; return state;
@@ -182,7 +192,6 @@ public class FileStateTable
*/ */
public final synchronized FileState updateFileState(String oldName, String newName) public final synchronized FileState updateFileState(String oldName, String newName)
{ {
// Find the current file state // Find the current file state
FileState state = m_stateTable.remove(FileState.normalizePath(oldName)); FileState state = m_stateTable.remove(FileState.normalizePath(oldName));
@@ -193,6 +202,10 @@ public class FileStateTable
{ {
state.setPath(newName); state.setPath(newName);
addFileState(state); addFileState(state);
// Update the access date/time
state.updateAccessDateTime();
} }
// Return the updated file state // Return the updated file state
@@ -246,6 +259,10 @@ public class FileStateTable
state.setPath(FileState.normalizePath(newPath)); state.setPath(FileState.normalizePath(newPath));
m_stateTable.put(state.getPath(), state); m_stateTable.put(state.getPath(), state);
// Updaet the access date/time
state.updateAccessDateTime();
} }
/** /**

View File

@@ -228,8 +228,9 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void onContentUpdate(NodeRef nodeRef, boolean newContent) public void onContentUpdate(NodeRef nodeRef, boolean newContent)
{ {
if (this.nodeService.exists(nodeRef) == true && this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true) if (this.nodeService.exists(nodeRef) == true && this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true
{ && this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) == false)
{
Map<NodeRef, NodeRef> versionedNodeRefs = (Map)AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS); Map<NodeRef, NodeRef> versionedNodeRefs = (Map)AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS);
if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false) if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false)
{ {