mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merge 3.2 to HEAD:
16691: Merge 3.1 to 3.2 15827: Fixed bug in delete node event processing 16695: Merge 3.1 to 3.2 16163: Added timestamp tracking via file state cache, added support for . and .. pseudo entries in wildcard folder search git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16976 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2009 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.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.state.FileState;
|
||||||
|
import org.alfresco.filesys.state.FileStateTable;
|
||||||
|
import org.alfresco.jlan.server.filesys.FileInfo;
|
||||||
|
import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache Lookup Search Context Class
|
||||||
|
*
|
||||||
|
* <p>Use the file state cache to check for current timestamp values for file information being returned in
|
||||||
|
* the current search.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class CacheLookupSearchContext extends ContentSearchContext {
|
||||||
|
|
||||||
|
// Debug logging
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(CacheLookupSearchContext.class);
|
||||||
|
|
||||||
|
// File state cache
|
||||||
|
|
||||||
|
private FileStateTable m_stateCache;
|
||||||
|
|
||||||
|
// File information for the '.' and '..' pseduo entries, returned during a wildcard search
|
||||||
|
|
||||||
|
private FileInfo m_dotInfo;
|
||||||
|
private FileInfo m_dotDotInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param cifsHelper Filesystem helper class
|
||||||
|
* @param results List of file/folder nodes that match the search pattern
|
||||||
|
* @param searchStr Search path
|
||||||
|
* @param pseudoList List of pseudo files to be blended into the returned list of files
|
||||||
|
* @param relPath Relative path being searched
|
||||||
|
* @param stateCache File state cache
|
||||||
|
*/
|
||||||
|
protected CacheLookupSearchContext(
|
||||||
|
CifsHelper cifsHelper,
|
||||||
|
List<NodeRef> results,
|
||||||
|
String searchStr,
|
||||||
|
PseudoFileList pseudoList,
|
||||||
|
String relPath,
|
||||||
|
FileStateTable stateCache)
|
||||||
|
{
|
||||||
|
super(cifsHelper, results, searchStr, pseudoList, relPath);
|
||||||
|
super.setSearchString(searchStr);
|
||||||
|
|
||||||
|
m_stateCache = stateCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return file information for the next file in the active search. Returns false if the search
|
||||||
|
* is complete.
|
||||||
|
*
|
||||||
|
* @param info FileInfo to return the file information.
|
||||||
|
* @return true if the file information is valid, else false
|
||||||
|
*/
|
||||||
|
public boolean nextFileInfo(FileInfo info)
|
||||||
|
{
|
||||||
|
// Get the file information for the next file
|
||||||
|
|
||||||
|
if ( super.nextFileInfo( info) == false)
|
||||||
|
return false;
|
||||||
|
else if ( returningPseudoFiles() == true || m_stateCache == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// We have a real file entry, check if there is a cache entry
|
||||||
|
|
||||||
|
StringBuilder relPath = new StringBuilder( getRelativePath());
|
||||||
|
relPath.append( info.getFileName());
|
||||||
|
|
||||||
|
FileState fstate = m_stateCache.findFileState( relPath.toString());
|
||||||
|
|
||||||
|
if ( fstate != null)
|
||||||
|
{
|
||||||
|
// Check if there are current timestamps that can be used to override the database values
|
||||||
|
|
||||||
|
if ( fstate.hasAccessDateTime())
|
||||||
|
info.setAccessDateTime( fstate.getAccessDateTime());
|
||||||
|
|
||||||
|
if ( fstate.hasModifyDateTime())
|
||||||
|
info.setModifyDateTime( fstate.getModifyDateTime());
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
|
||||||
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug("Search timestamps from cache, path=" + info.getFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicate that the file information is valid
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the '.' and '..' pseudo file entries are available
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean hasDotFiles() {
|
||||||
|
return (m_dotInfo != null && m_dotDotInfo != null) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the '.' pseudo file entry details
|
||||||
|
*
|
||||||
|
* @param finfo FileInfo
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean getDotInfo(FileInfo finfo) {
|
||||||
|
|
||||||
|
// Check if the '.' file information is valid
|
||||||
|
|
||||||
|
if ( m_dotInfo != null) {
|
||||||
|
finfo.copyFrom( m_dotInfo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// File information not valid
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the '..' pseudo file entry details
|
||||||
|
*
|
||||||
|
* @param finfo FileInfo
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean getDotDotInfo(FileInfo finfo) {
|
||||||
|
|
||||||
|
// Check if the '..' file information is valid
|
||||||
|
|
||||||
|
if ( m_dotDotInfo != null) {
|
||||||
|
finfo.copyFrom( m_dotDotInfo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// File information not valid
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the '.' pseudo file entry details
|
||||||
|
*
|
||||||
|
* @param finfo FileInfo
|
||||||
|
*/
|
||||||
|
protected void setDotInfo(FileInfo finfo) {
|
||||||
|
m_dotInfo = finfo;
|
||||||
|
if ( m_dotInfo != null)
|
||||||
|
m_dotInfo.setFileName( ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the '..' pseudo file entry details
|
||||||
|
*
|
||||||
|
* @param finfo FileInfo
|
||||||
|
*/
|
||||||
|
protected void setDotDotInfo(FileInfo finfo) {
|
||||||
|
m_dotDotInfo = finfo;
|
||||||
|
if ( m_dotDotInfo != null)
|
||||||
|
m_dotDotInfo.setFileName( ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the search as a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(60);
|
||||||
|
|
||||||
|
sb.append("[CacheLookupSearchContext searchStr=");
|
||||||
|
sb.append(getSearchString());
|
||||||
|
sb.append(", resultCount=");
|
||||||
|
sb.append(getResultsSize());
|
||||||
|
sb.append(", pseudoList=");
|
||||||
|
if ( getPseudoListSize() != 0)
|
||||||
|
sb.append( getPseudoListSize());
|
||||||
|
else
|
||||||
|
sb.append("NULL");
|
||||||
|
sb.append(",cache=");
|
||||||
|
sb.append(m_stateCache);
|
||||||
|
|
||||||
|
if ( m_dotInfo != null)
|
||||||
|
sb.append(",Dot");
|
||||||
|
if ( m_dotDotInfo != null)
|
||||||
|
sb.append(",DotDot");
|
||||||
|
sb.append("]");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -875,7 +875,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
// Access the device context
|
// Access the device context
|
||||||
|
|
||||||
ContentContext ctx = (ContentContext) tree.getContext();
|
ContentContext ctx = (ContentContext) tree.getContext();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
String searchFileSpec = searchPath;
|
String searchFileSpec = searchPath;
|
||||||
@@ -1027,15 +1027,107 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the search context to store the results
|
// Build the search context to store the results, use the cache lookup search for wildcard searches
|
||||||
|
|
||||||
SearchContext searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0]);
|
SearchContext searchCtx = null;
|
||||||
|
|
||||||
|
if ( searchFileSpec.equals( "*"))
|
||||||
|
{
|
||||||
|
// Use a cache lookup search context
|
||||||
|
|
||||||
|
CacheLookupSearchContext cacheContext = new CacheLookupSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0], ctx.getStateTable());
|
||||||
|
searchCtx = cacheContext;
|
||||||
|
|
||||||
|
// Set the '.' and '..' pseudo file entry details
|
||||||
|
|
||||||
|
if ( searchFolderState != null && searchFolderState.hasNodeRef())
|
||||||
|
{
|
||||||
|
// Get the '.' pseudo entry file details
|
||||||
|
|
||||||
|
FileInfo finfo = cifsHelper.getFileInformation( searchFolderState.getNodeRef());
|
||||||
|
|
||||||
|
// Blend in any cached timestamps
|
||||||
|
|
||||||
|
if ( searchFolderState != null) {
|
||||||
|
if ( searchFolderState.hasAccessDateTime())
|
||||||
|
finfo.setAccessDateTime( searchFolderState.getAccessDateTime());
|
||||||
|
|
||||||
|
if ( searchFolderState.hasChangeDateTime())
|
||||||
|
finfo.setChangeDateTime( searchFolderState.getChangeDateTime());
|
||||||
|
|
||||||
|
if ( searchFolderState.hasModifyDateTime())
|
||||||
|
finfo.setModifyDateTime( searchFolderState.getModifyDateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the '.' pseudo entry details
|
||||||
|
|
||||||
|
cacheContext.setDotInfo( finfo);
|
||||||
|
|
||||||
|
// Check if the search folder has a parent, if we are at the root of the filesystem then re-use
|
||||||
|
// the file information
|
||||||
|
|
||||||
|
if ( searchFolderState.getPath().equals( FileName.DOS_SEPERATOR_STR)) {
|
||||||
|
|
||||||
|
// Searching the root folder, re-use the search folder file information for the '..' pseudo entry
|
||||||
|
|
||||||
|
cacheContext.setDotDotInfo( finfo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Get the parent folder path
|
||||||
|
|
||||||
|
String parentPath = searchFolderState.getPath();
|
||||||
|
if ( parentPath.endsWith( FileName.DOS_SEPERATOR_STR) && parentPath.length() > 1)
|
||||||
|
parentPath = parentPath.substring(0, parentPath.length() - 1);
|
||||||
|
|
||||||
|
int pos = parentPath.lastIndexOf( FileName.DOS_SEPERATOR_STR);
|
||||||
|
if ( pos != -1)
|
||||||
|
parentPath = parentPath.substring(0, pos + 1);
|
||||||
|
|
||||||
|
// Get the file state for the parent path, if available
|
||||||
|
|
||||||
|
FileState parentState = ctx.getStateTable().findFileState( parentPath);
|
||||||
|
NodeRef parentNode = null;
|
||||||
|
|
||||||
|
if ( parentState != null)
|
||||||
|
parentNode = parentState.getNodeRef();
|
||||||
|
|
||||||
|
if ( parentState == null || parentNode == null)
|
||||||
|
parentNode = getNodeForPath( tree, parentPath);
|
||||||
|
|
||||||
|
// Get the file information for the parent folder
|
||||||
|
|
||||||
|
finfo = cifsHelper.getFileInformation( parentNode);
|
||||||
|
|
||||||
|
// Blend in any cached timestamps
|
||||||
|
|
||||||
|
if ( parentState != null) {
|
||||||
|
if ( parentState.hasAccessDateTime())
|
||||||
|
finfo.setAccessDateTime( parentState.getAccessDateTime());
|
||||||
|
|
||||||
|
if ( parentState.hasChangeDateTime())
|
||||||
|
finfo.setChangeDateTime( parentState.getChangeDateTime());
|
||||||
|
|
||||||
|
if ( parentState.hasModifyDateTime())
|
||||||
|
finfo.setModifyDateTime( parentState.getModifyDateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the '..' pseudo entry details
|
||||||
|
|
||||||
|
cacheContext.setDotDotInfo( finfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0]);
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
|
||||||
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH))
|
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH))
|
||||||
logger.debug("Started search: search path=" + searchPath + " attributes=" + attributes);
|
logger.debug("Started search: search path=" + searchPath + " attributes=" + attributes + ", ctx=" + searchCtx);
|
||||||
|
|
||||||
|
// Return the search context
|
||||||
|
|
||||||
return searchCtx;
|
return searchCtx;
|
||||||
}
|
}
|
||||||
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
|
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
|
||||||
@@ -1618,7 +1710,9 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
// Get the device root
|
// Get the device root
|
||||||
|
|
||||||
NodeRef deviceRootNodeRef = ctx.getRootNode();
|
NodeRef deviceRootNodeRef = ctx.getRootNode();
|
||||||
|
|
||||||
String path = params.getPath();
|
String path = params.getPath();
|
||||||
|
FileState parentState = null;
|
||||||
|
|
||||||
// If the state table is available then try to find the parent folder node for the new file
|
// If the state table is available then try to find the parent folder node for the new file
|
||||||
// to save having to walk the path
|
// to save having to walk the path
|
||||||
@@ -1644,6 +1738,12 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
||||||
logger.debug("Create file using cached noderef for path " + paths[0]);
|
logger.debug("Create file using cached noderef for path " + paths[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the file state for the parent folder
|
||||||
|
|
||||||
|
parentState = getStateForPath(tree, paths[0]);
|
||||||
|
if ( parentState == null && ctx.hasStateTable())
|
||||||
|
parentState = ctx.getStateTable().findFileState( paths[0], true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1695,12 +1795,19 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
||||||
logger.debug("Create file, state=" + fstate);
|
logger.debug("Create file, state=" + fstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the parent folder file state
|
||||||
|
|
||||||
|
if ( parentState != null)
|
||||||
|
parentState.updateModifyDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
|
||||||
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
||||||
logger.debug("Created file: path=" + path + " file open parameters=" + params + " node=" + nodeRef + " network file=" + netFile);
|
logger.debug("Created file: path=" + path + " file open parameters=" + params + " node=" + nodeRef + " network file=" + netFile);
|
||||||
|
|
||||||
|
// Return the new network file
|
||||||
|
|
||||||
return netFile;
|
return netFile;
|
||||||
}
|
}
|
||||||
@@ -1762,6 +1869,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
NodeRef deviceRootNodeRef = ctx.getRootNode();
|
NodeRef deviceRootNodeRef = ctx.getRootNode();
|
||||||
|
|
||||||
String path = params.getPath();
|
String path = params.getPath();
|
||||||
|
FileState parentState = null;
|
||||||
|
|
||||||
// If the state table is available then try to find the parent folder node for the new folder
|
// If the state table is available then try to find the parent folder node for the new folder
|
||||||
// to save having to walk the path
|
// to save having to walk the path
|
||||||
@@ -1787,6 +1895,12 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
||||||
logger.debug("Create file using cached noderef for path " + paths[0]);
|
logger.debug("Create file using cached noderef for path " + paths[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the file state for the parent folder
|
||||||
|
|
||||||
|
parentState = getStateForPath(tree, paths[0]);
|
||||||
|
if ( parentState == null && ctx.hasStateTable())
|
||||||
|
parentState = ctx.getStateTable().findFileState( paths[0], true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1809,8 +1923,13 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
// DEBUG
|
// DEBUG
|
||||||
|
|
||||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
||||||
logger.debug("Creaste folder, state=" + fstate);
|
logger.debug("Create folder, state=" + fstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the parent folder file state
|
||||||
|
|
||||||
|
if ( parentState != null)
|
||||||
|
parentState.updateModifyDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
@@ -1879,7 +1998,27 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
// Remove the file state
|
// Remove the file state
|
||||||
|
|
||||||
if ( ctx.hasStateTable())
|
if ( ctx.hasStateTable())
|
||||||
|
{
|
||||||
|
// Remove the file state
|
||||||
|
|
||||||
ctx.getStateTable().removeFileState(dir);
|
ctx.getStateTable().removeFileState(dir);
|
||||||
|
|
||||||
|
// Update, or create, a parent folder file state
|
||||||
|
|
||||||
|
String[] paths = FileName.splitPath(dir);
|
||||||
|
if ( paths[0] != null && paths[0].length() > 1)
|
||||||
|
{
|
||||||
|
// Get the file state for the parent folder
|
||||||
|
|
||||||
|
FileState parentState = getStateForPath(tree, paths[0]);
|
||||||
|
if ( parentState == null && ctx.hasStateTable())
|
||||||
|
parentState = ctx.getStateTable().findFileState( paths[0], true, true);
|
||||||
|
|
||||||
|
// Update the modification timestamp
|
||||||
|
|
||||||
|
parentState.updateModifyDateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new DirectoryNotEmptyException( dir);
|
throw new DirectoryNotEmptyException( dir);
|
||||||
@@ -1970,6 +2109,21 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
|
|
||||||
if ( fstate.decrementOpenCount() == 0)
|
if ( fstate.decrementOpenCount() == 0)
|
||||||
fstate.setSharedAccess( SharingMode.READWRITE + SharingMode.DELETE);
|
fstate.setSharedAccess( SharingMode.READWRITE + SharingMode.DELETE);
|
||||||
|
|
||||||
|
// Check if there is a cached modification timestamp to be written out
|
||||||
|
|
||||||
|
if ( file.hasDeleteOnClose() == false && fstate.hasModifyDateTime() && fstate.hasNodeRef()) {
|
||||||
|
|
||||||
|
// Update the modification date on the file/folder node
|
||||||
|
|
||||||
|
Date modifyDate = new Date( fstate.getModifyDateTime());
|
||||||
|
nodeService.setProperty( fstate.getNodeRef(), ContentModel.PROP_MODIFIED, modifyDate);
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
|
||||||
|
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
|
||||||
|
logger.debug("Updated modifcation timestamp, " + file.getFullName() + ", modTime=" + modifyDate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2087,7 +2241,27 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
// Remove the file state
|
// Remove the file state
|
||||||
|
|
||||||
if ( ctx.hasStateTable())
|
if ( ctx.hasStateTable())
|
||||||
|
{
|
||||||
|
// Remove the file state
|
||||||
|
|
||||||
ctx.getStateTable().removeFileState(name);
|
ctx.getStateTable().removeFileState(name);
|
||||||
|
|
||||||
|
// Update, or create, a parent folder file state
|
||||||
|
|
||||||
|
String[] paths = FileName.splitPath(name);
|
||||||
|
if ( paths[0] != null && paths[0].length() > 1)
|
||||||
|
{
|
||||||
|
// Get the file state for the parent folder
|
||||||
|
|
||||||
|
FileState parentState = getStateForPath(tree, paths[0]);
|
||||||
|
if ( parentState == null && ctx.hasStateTable())
|
||||||
|
parentState = ctx.getStateTable().findFileState( paths[0], true, true);
|
||||||
|
|
||||||
|
// Update the modification timestamp
|
||||||
|
|
||||||
|
parentState.updateModifyDateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
@@ -2575,15 +2749,17 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
|
|
||||||
beginWriteTransaction( sess);
|
beginWriteTransaction( sess);
|
||||||
|
|
||||||
// Set the creation date on the file/folder node
|
// Set the modification date on the file/folder node
|
||||||
|
|
||||||
Date modifyDate = new Date( info.getModifyDateTime());
|
Date modifyDate = new Date( info.getModifyDateTime());
|
||||||
nodeService.setProperty( nodeRef, ContentModel.PROP_MODIFIED, modifyDate);
|
nodeService.setProperty( nodeRef, ContentModel.PROP_MODIFIED, modifyDate);
|
||||||
|
|
||||||
// Update the change date/time
|
// Update the change date/time, clear the cached modification date/time
|
||||||
|
|
||||||
if ( fstate != null)
|
if ( fstate != null) {
|
||||||
fstate.updateChangeDateTime();
|
fstate.updateChangeDateTime();
|
||||||
|
fstate.updateModifyDateTime( 0L);
|
||||||
|
}
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
|
|
||||||
|
@@ -224,6 +224,8 @@ public class ContentNetworkFile extends NodeRefNetworkFile
|
|||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
str.append( "[");
|
str.append( "[");
|
||||||
|
str.append(getFullName());
|
||||||
|
str.append(",");
|
||||||
str.append( getNodeRef().getId());
|
str.append( getNodeRef().getId());
|
||||||
str.append( ",channel=");
|
str.append( ",channel=");
|
||||||
str.append( channel);
|
str.append( channel);
|
||||||
|
@@ -496,4 +496,40 @@ public class ContentSearchContext extends SearchContext
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the search is returning pseudo files or real file entries
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected boolean returningPseudoFiles() {
|
||||||
|
return donePseudoFiles ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the relative path that is being searched
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
protected String getRelativePath() {
|
||||||
|
return m_relPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the results array size
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected int getResultsSize() {
|
||||||
|
return results != null ? results.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the pseudo file list size
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected int getPseudoListSize() {
|
||||||
|
return pseudoList != null ? pseudoList.numberOfFiles() : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -551,25 +551,30 @@ public class NodeMonitor extends TransactionListenerAdapter
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for a node delete
|
||||||
|
|
||||||
|
if ( nodeEvent instanceof DeleteNodeEvent) {
|
||||||
|
|
||||||
|
// Node deleted
|
||||||
|
|
||||||
|
processDeleteNode((DeleteNodeEvent) nodeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the node is still valid
|
// Check that the node is still valid
|
||||||
|
|
||||||
if (!m_nodeService.exists(nodeEvent.getNodeRef()))
|
else if (!m_nodeService.exists(nodeEvent.getNodeRef()))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the node event, for an existing node
|
||||||
|
|
||||||
if ( nodeEvent instanceof CreateNodeEvent) {
|
if ( nodeEvent instanceof CreateNodeEvent) {
|
||||||
|
|
||||||
// Node created
|
// Node created
|
||||||
|
|
||||||
processCreateNode((CreateNodeEvent) nodeEvent);
|
processCreateNode((CreateNodeEvent) nodeEvent);
|
||||||
}
|
}
|
||||||
else if ( nodeEvent instanceof DeleteNodeEvent) {
|
|
||||||
|
|
||||||
// Node deleted
|
|
||||||
|
|
||||||
processDeleteNode((DeleteNodeEvent) nodeEvent);
|
|
||||||
}
|
|
||||||
else if ( nodeEvent instanceof MoveNodeEvent) {
|
else if ( nodeEvent instanceof MoveNodeEvent) {
|
||||||
|
|
||||||
// Node moved
|
// Node moved
|
||||||
@@ -745,7 +750,7 @@ public class NodeMonitor extends TransactionListenerAdapter
|
|||||||
|
|
||||||
if ( m_changeHandler.getGlobalNotifyMask() != 0) {
|
if ( m_changeHandler.getGlobalNotifyMask() != 0) {
|
||||||
|
|
||||||
// Send a file created event to the change notification handler
|
// Send a file deleted event to the change notification handler
|
||||||
|
|
||||||
if ( deleteEvent.getFileType() == FileFolderServiceType.FILE)
|
if ( deleteEvent.getFileType() == FileFolderServiceType.FILE)
|
||||||
m_changeHandler.notifyFileChanged(NotifyChange.ActionRemoved, relPath);
|
m_changeHandler.notifyFileChanged(NotifyChange.ActionRemoved, relPath);
|
||||||
|
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2009 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.state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File State Listener Interface
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public interface FileStateListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File state has expired. The listener can control whether the file state is removed
|
||||||
|
* from the cache, or not.
|
||||||
|
*
|
||||||
|
* @param state FileState
|
||||||
|
* @return true to remove the file state from the cache, or false to leave the file state in the cache
|
||||||
|
*/
|
||||||
|
public boolean fileStateExpired(FileState state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File state cache is closing down, any resources attached to the file state must be released.
|
||||||
|
*
|
||||||
|
* @param state FileState
|
||||||
|
*/
|
||||||
|
public void fileStateClosed(FileState state);
|
||||||
|
}
|
@@ -51,6 +51,10 @@ public class FileStateTable
|
|||||||
|
|
||||||
private long m_cacheTimer = 2 * 60000L; // 2 minutes default
|
private long m_cacheTimer = 2 * 60000L; // 2 minutes default
|
||||||
|
|
||||||
|
// File state listener, can veto expiring of file states
|
||||||
|
|
||||||
|
private FileStateListener m_stateListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor
|
* Class constructor
|
||||||
*/
|
*/
|
||||||
@@ -287,6 +291,11 @@ public class FileStateTable
|
|||||||
|
|
||||||
FileState state = m_stateTable.get(enm.nextElement());
|
FileState state = m_stateTable.get(enm.nextElement());
|
||||||
|
|
||||||
|
// Check if there is a state listener
|
||||||
|
|
||||||
|
if ( m_stateListener != null)
|
||||||
|
m_stateListener.fileStateClosed(state);
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
@@ -336,19 +345,23 @@ public class FileStateTable
|
|||||||
|
|
||||||
if (state.hasExpired(curTime) && state.getOpenCount() == 0)
|
if (state.hasExpired(curTime) && state.getOpenCount() == 0)
|
||||||
{
|
{
|
||||||
|
// Check with the state listener before removing the file state, if enabled
|
||||||
// Remove the expired file state
|
|
||||||
|
if ( hasStateListener() == false || m_stateListener.fileStateExpired( state) == true)
|
||||||
m_stateTable.remove(state.getPath());
|
{
|
||||||
|
// Remove the expired file state
|
||||||
// DEBUG
|
|
||||||
|
m_stateTable.remove(state.getPath());
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Expired file state: " + state);
|
// DEBUG
|
||||||
|
|
||||||
// Update the expired count
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Expired file state: " + state);
|
||||||
expiredCnt++;
|
|
||||||
|
// Update the expired count
|
||||||
|
|
||||||
|
expiredCnt++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,4 +394,32 @@ public class FileStateTable
|
|||||||
logger.debug(" " + fname + "(" + state.getSecondsToExpire(curTime) + ") : " + state);
|
logger.debug(" " + fname + "(" + state.getSecondsToExpire(curTime) + ") : " + state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a file state listener
|
||||||
|
*
|
||||||
|
* @param l FileStateListener
|
||||||
|
*/
|
||||||
|
public final void addStateListener(FileStateListener l) {
|
||||||
|
m_stateListener = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a file state listener
|
||||||
|
*
|
||||||
|
* @param l FileStateListener
|
||||||
|
*/
|
||||||
|
public final void removeStateListener(FileStateListener l) {
|
||||||
|
if ( m_stateListener == l)
|
||||||
|
m_stateListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the file state listener is set
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasStateListener() {
|
||||||
|
return m_stateListener != null ? true : false;
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user