diff --git a/source/java/org/alfresco/filesys/repo/CacheLookupSearchContext.java b/source/java/org/alfresco/filesys/repo/CacheLookupSearchContext.java
new file mode 100644
index 0000000000..c9b492c002
--- /dev/null
+++ b/source/java/org/alfresco/filesys/repo/CacheLookupSearchContext.java
@@ -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
+ *
+ *
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 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();
+ }
+}
diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
index 6d5338ed83..d49c6b462f 100644
--- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
+++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
@@ -875,7 +875,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Access the device context
ContentContext ctx = (ContentContext) tree.getContext();
-
+
try
{
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
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;
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
@@ -1618,7 +1710,9 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Get the device root
NodeRef deviceRootNodeRef = ctx.getRootNode();
+
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
// 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))
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))
logger.debug("Create file, state=" + fstate);
}
+
+ // Update the parent folder file state
+
+ if ( parentState != null)
+ parentState.updateModifyDateTime();
}
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Created file: path=" + path + " file open parameters=" + params + " node=" + nodeRef + " network file=" + netFile);
+
+ // Return the new network file
return netFile;
}
@@ -1762,6 +1869,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
NodeRef deviceRootNodeRef = ctx.getRootNode();
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
// 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))
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
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
@@ -1879,7 +1998,27 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Remove the file state
if ( ctx.hasStateTable())
+ {
+ // Remove the file state
+
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
throw new DirectoryNotEmptyException( dir);
@@ -1970,6 +2109,21 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( fstate.decrementOpenCount() == 0)
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
if ( ctx.hasStateTable())
+ {
+ // Remove the file state
+
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
@@ -2575,15 +2749,17 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
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());
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.updateModifyDateTime( 0L);
+ }
// DEBUG
diff --git a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
index 8f87e281c0..97bfa7d2a1 100644
--- a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
+++ b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
@@ -224,6 +224,8 @@ public class ContentNetworkFile extends NodeRefNetworkFile
StringBuilder str = new StringBuilder();
str.append( "[");
+ str.append(getFullName());
+ str.append(",");
str.append( getNodeRef().getId());
str.append( ",channel=");
str.append( channel);
diff --git a/source/java/org/alfresco/filesys/repo/ContentSearchContext.java b/source/java/org/alfresco/filesys/repo/ContentSearchContext.java
index 02d27838c0..4d0ad9a268 100644
--- a/source/java/org/alfresco/filesys/repo/ContentSearchContext.java
+++ b/source/java/org/alfresco/filesys/repo/ContentSearchContext.java
@@ -496,4 +496,40 @@ public class ContentSearchContext extends SearchContext
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;
+ }
}
diff --git a/source/java/org/alfresco/filesys/repo/NodeMonitor.java b/source/java/org/alfresco/filesys/repo/NodeMonitor.java
index 11276214e7..05a6b6b0f7 100644
--- a/source/java/org/alfresco/filesys/repo/NodeMonitor.java
+++ b/source/java/org/alfresco/filesys/repo/NodeMonitor.java
@@ -551,25 +551,30 @@ public class NodeMonitor extends TransactionListenerAdapter
return null;
}
+ // check for a node delete
+
+ if ( nodeEvent instanceof DeleteNodeEvent) {
+
+ // Node deleted
+
+ processDeleteNode((DeleteNodeEvent) nodeEvent);
+ }
+
// Check that the node is still valid
- if (!m_nodeService.exists(nodeEvent.getNodeRef()))
+ else if (!m_nodeService.exists(nodeEvent.getNodeRef()))
{
return null;
}
+ // Process the node event, for an existing node
+
if ( nodeEvent instanceof CreateNodeEvent) {
// Node created
processCreateNode((CreateNodeEvent) nodeEvent);
}
- else if ( nodeEvent instanceof DeleteNodeEvent) {
-
- // Node deleted
-
- processDeleteNode((DeleteNodeEvent) nodeEvent);
- }
else if ( nodeEvent instanceof MoveNodeEvent) {
// Node moved
@@ -745,7 +750,7 @@ public class NodeMonitor extends TransactionListenerAdapter
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)
m_changeHandler.notifyFileChanged(NotifyChange.ActionRemoved, relPath);
diff --git a/source/java/org/alfresco/filesys/state/FileStateListener.java b/source/java/org/alfresco/filesys/state/FileStateListener.java
new file mode 100644
index 0000000000..ac3a934063
--- /dev/null
+++ b/source/java/org/alfresco/filesys/state/FileStateListener.java
@@ -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);
+}
diff --git a/source/java/org/alfresco/filesys/state/FileStateTable.java b/source/java/org/alfresco/filesys/state/FileStateTable.java
index 9f9f5fb577..eb2f2ce6d8 100644
--- a/source/java/org/alfresco/filesys/state/FileStateTable.java
+++ b/source/java/org/alfresco/filesys/state/FileStateTable.java
@@ -51,6 +51,10 @@ public class FileStateTable
private long m_cacheTimer = 2 * 60000L; // 2 minutes default
+ // File state listener, can veto expiring of file states
+
+ private FileStateListener m_stateListener;
+
/**
* Class constructor
*/
@@ -287,6 +291,11 @@ public class FileStateTable
FileState state = m_stateTable.get(enm.nextElement());
+ // Check if there is a state listener
+
+ if ( m_stateListener != null)
+ m_stateListener.fileStateClosed(state);
+
// DEBUG
if (logger.isDebugEnabled())
@@ -336,19 +345,23 @@ public class FileStateTable
if (state.hasExpired(curTime) && state.getOpenCount() == 0)
{
-
- // Remove the expired file state
-
- m_stateTable.remove(state.getPath());
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- logger.debug("Expired file state: " + state);
-
- // Update the expired count
-
- expiredCnt++;
+ // Check with the state listener before removing the file state, if enabled
+
+ if ( hasStateListener() == false || m_stateListener.fileStateExpired( state) == true)
+ {
+ // Remove the expired file state
+
+ m_stateTable.remove(state.getPath());
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("Expired file state: " + state);
+
+ // Update the expired count
+
+ expiredCnt++;
+ }
}
}
}
@@ -381,4 +394,32 @@ public class FileStateTable
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;
+ }
}
\ No newline at end of file