diff --git a/config/alfresco/cache-context.xml b/config/alfresco/cache-context.xml
index f3d98b8d79..d0cb9c2586 100644
--- a/config/alfresco/cache-context.xml
+++ b/config/alfresco/cache-context.xml
@@ -484,6 +484,11 @@
+
+
+
+
+
diff --git a/config/alfresco/caches.properties b/config/alfresco/caches.properties
index 6d8c105eb0..1c36f418a3 100644
--- a/config/alfresco/caches.properties
+++ b/config/alfresco/caches.properties
@@ -528,6 +528,17 @@ cache.publicapi.webScriptsRegistryCache.eviction-policy=LRU
cache.publicapi.webScriptsRegistryCache.eviction-percentage=25
cache.publicapi.webScriptsRegistryCache.merge-policy=hz.ADD_NEW_ENTRY
+cache.deletePseudoFileCache.tx.maxItems=50000
+cache.deletePseudoFileCache.maxItems=50000
+cache.deletePseudoFileCache.timeToLiveSeconds=180
+cache.deletePseudoFileCache.maxIdleSeconds=0
+cache.deletePseudoFileCache.cluster.type=fully-distributed
+cache.deletePseudoFileCache.backup-count=1
+cache.deletePseudoFileCache.eviction-policy=LRU
+cache.deletePseudoFileCache.eviction-percentage=25
+cache.deletePseudoFileCache.merge-policy=hz.ADD_NEW_ENTRY
+
+
#
# RM Caveat cache
diff --git a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml
index 0946bc192a..6aa52d18a5 100644
--- a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml
+++ b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml
@@ -408,6 +408,7 @@
+
diff --git a/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlay.java b/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlay.java
index 60d961a373..1808f31356 100644
--- a/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlay.java
+++ b/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlay.java
@@ -44,5 +44,16 @@ public interface PseudoFileOverlay
* @return list of pseudo files.
*/
public PseudoFileList searchPseudoFiles(NodeRef parentDir, String name);
+
+ /**
+ * Delete a pseudo file.
+ *
+ * Pseudo files may need to be deleted for delete folder operations to work
+ * correctly.
+ *
+ * A pseudo file can be deleted for a short time. However it may re-appear at some point
+ * later since there is no permanent persistence of pseudo files which are ephemeral!
+ */
+ public void delete(NodeRef parentDir, String name);
}
diff --git a/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlayImpl.java b/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlayImpl.java
index 84b10822f6..2671ae793c 100644
--- a/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlayImpl.java
+++ b/source/java/org/alfresco/filesys/alfresco/PseudoFileOverlayImpl.java
@@ -18,9 +18,12 @@
*/
package org.alfresco.filesys.alfresco;
+import java.io.Serializable;
import java.util.Enumeration;
+import java.util.Map;
import org.alfresco.filesys.repo.ContentDiskDriver2;
+import org.alfresco.jlan.server.filesys.FileInfo;
import org.alfresco.jlan.server.filesys.FileName;
import org.alfresco.jlan.server.filesys.pseudo.MemoryPseudoFile;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFile;
@@ -28,6 +31,7 @@ import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
import org.alfresco.jlan.util.WildCard;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.SysAdminParams;
+import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.site.SiteModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
@@ -47,6 +51,7 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
private SysAdminParams sysAdminParams;
private AlfrescoContext context;
private NodeService nodeService;
+ private SimpleCache deletePseudoFileCache;
private static final Log logger = LogFactory.getLog(PseudoFileOverlayImpl.class);
@@ -57,6 +62,7 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
PropertyCheck.mandatory(this, "nodeService", getNodeService());
PropertyCheck.mandatory(this, "context", context);
PropertyCheck.mandatory(this, "sysAdminParams", sysAdminParams);
+ PropertyCheck.mandatory(this, "deletePseudoFileCache", deletePseudoFileCache);
DesktopActionTable actions = context.getDesktopActions();
@@ -322,23 +328,39 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
for ( int i = 0; i < pl.numberOfFiles(); i++)
{
PseudoFile pseudoFile = pl.getFileAt(i);
- filterList.addFile(pseudoFile);
+ if(!isDeleted(parentDir, pseudoFile.getFileName()))
+ {
+ // File is not deleted
+ filterList.addFile(pseudoFile);
+ }
}
// The URL file is dependent upon the parent dir
if(context.isAlfrescoURLEnabled())
{
- filterList.addFile(generateAlfrescoURLShortcut(parentDir));
+ if(!isDeleted(parentDir, context.getURLFileName()))
+ {
+ filterList.addFile(generateAlfrescoURLShortcut(parentDir));
+ }
+ else
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("alfresco URL pseudo file deleted");
+ }
+ }
}
if(context.isShareURLEnabled())
{
- PseudoFile sharePseudoFile = generateShareURLShortcut(parentDir);
-
- if(sharePseudoFile != null)
+ if(!isDeleted(parentDir, context.getShareURLFileName()))
{
- filterList.addFile(sharePseudoFile);
- }
+ PseudoFile sharePseudoFile = generateShareURLShortcut(parentDir);
+ if(sharePseudoFile != null)
+ {
+ filterList.addFile(sharePseudoFile);
+ }
+ }
}
return filterList;
@@ -355,8 +377,11 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
PseudoFile pseudoFile = pl.getFileAt( i);
if ( wildCard.matchesPattern( pseudoFile.getFileName()))
{
- // Add the pseudo file to the filtered list
- filterList.addFile( pseudoFile);
+ if(!isDeleted(parentDir, pseudoFile.getFileName()))
+ {
+ // Add the pseudo file to the filtered list
+ filterList.addFile( pseudoFile);
+ }
}
}
@@ -365,7 +390,10 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
{
if(wildCard.matchesPattern(context.getURLFileName()))
{
- filterList.addFile(generateAlfrescoURLShortcut(parentDir));
+ if(!isDeleted(parentDir, context.getURLFileName()))
+ {
+ filterList.addFile(generateAlfrescoURLShortcut(parentDir));
+ }
}
}
@@ -373,12 +401,15 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
{
if(wildCard.matchesPattern(context.getShareURLFileName()))
{
- PseudoFile sharePseudoFile = generateShareURLShortcut(parentDir);
+ if(!isDeleted(parentDir, context.getShareURLFileName()))
+ {
+ PseudoFile sharePseudoFile = generateShareURLShortcut(parentDir);
- if(sharePseudoFile != null)
- {
- filterList.addFile(sharePseudoFile);
- }
+ if(sharePseudoFile != null)
+ {
+ filterList.addFile(sharePseudoFile);
+ }
+ }
}
}
@@ -392,7 +423,7 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
PseudoFileList filterList = new PseudoFileList();
PseudoFile file = getPseudoFile(parentDir, fname);
- if(file != null)
+ if(file != null && !isDeleted(parentDir, fname))
{
filterList.addFile(file);
}
@@ -400,6 +431,32 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
return filterList;
}
}
+
+ @Override
+ public void delete(NodeRef parentDir, String name)
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("delete pseudo file parentDir:" + parentDir + ", name: " + name);
+ }
+ getDeletePseudoFileCache().put(toDeleteKey(parentDir, name), "Deleted");
+ }
+
+ private String toDeleteKey(NodeRef parentNoderef, String name)
+ {
+ return (parentNoderef.toString() + "/" + name + ":" + context.getDeviceName()).toLowerCase();
+ }
+
+ private boolean isDeleted(NodeRef parentDir, String name)
+ {
+ String key = toDeleteKey(parentDir, name);
+ boolean isDeleted = getDeletePseudoFileCache().contains(key);
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("pseudoFile isDeleted: " + isDeleted + ", for name:" + name);
+ }
+ return isDeleted;
+ }
//
public void setNodeService(NodeService nodeService)
@@ -440,4 +497,13 @@ public class PseudoFileOverlayImpl implements PseudoFileOverlay
{
return sysAdminParams;
}
+
+ public SimpleCache getDeletePseudoFileCache()
+ {
+ return deletePseudoFileCache;
+ }
+
+ public void setDeletePseudoFileCache(SimpleCache deletePseudoFileCache) {
+ this.deletePseudoFileCache = deletePseudoFileCache;
+ }
}
diff --git a/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java b/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java
index c0c8df770a..2a71959024 100644
--- a/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java
+++ b/source/java/org/alfresco/filesys/alfresco/RepositoryDiskInterface.java
@@ -96,7 +96,7 @@ public interface RepositoryDiskInterface
* @throws FileNotFoundException
* @return node ref of deleted file or null if no file deleted
*/
- public NodeRef closeFile(NodeRef rootNode, String Path, NetworkFile file) throws IOException;
+ public NodeRef closeFile(TreeConnection tree, NodeRef rootNode, String Path, NetworkFile file) throws IOException;
/**
diff --git a/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java b/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java
index bd1e3e71ad..8c23756931 100644
--- a/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java
+++ b/source/java/org/alfresco/filesys/repo/CommandExecutorImpl.java
@@ -220,7 +220,7 @@ public class CommandExecutorImpl implements CommandExecutor
{
logger.debug("close file command");
CloseFileCommand c = (CloseFileCommand)command;
- return repositoryDiskInterface.closeFile(c.getRootNodeRef(), c.getPath(), c.getNetworkFile());
+ return repositoryDiskInterface.closeFile(tree, c.getRootNodeRef(), c.getPath(), c.getNetworkFile());
}
else if(command instanceof ReduceQuotaCommand)
{
diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java
index e17169a786..af43d9882d 100644
--- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java
+++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java
@@ -59,6 +59,7 @@ import org.alfresco.jlan.server.filesys.SearchContext;
import org.alfresco.jlan.server.filesys.SrvDiskInfo;
import org.alfresco.jlan.server.filesys.TreeConnection;
import org.alfresco.jlan.server.filesys.cache.FileState;
+import org.alfresco.jlan.server.filesys.pseudo.MemoryNetworkFile;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFile;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
import org.alfresco.jlan.server.filesys.pseudo.PseudoNetworkFile;
@@ -74,6 +75,7 @@ import org.alfresco.jlan.smb.server.SMBSrvSession;
import org.alfresco.jlan.util.DataBuffer;
import org.alfresco.jlan.util.MemorySize;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.repo.content.filestore.FileContentReader;
@@ -178,6 +180,7 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
PropertyCheck.mandatory(this, "nodeArchiveService", nodeArchiveService);
PropertyCheck.mandatory(this, "hiddenAspect", hiddenAspect);
PropertyCheck.mandatory(this, "lockKeeper", lockKeeper);
+ PropertyCheck.mandatory(this, "deletePseudoFileCache", deletePseudoFileCache);
}
/**
@@ -601,6 +604,7 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
ps.setContext(context);
ps.setNodeService(nodeService);
ps.setSysAdminParams(context.getSysAdminParams());
+ ps.setDeletePseudoFileCache(deletePseudoFileCache);
context.setPseudoFileOverlay(ps);
ps.init();
}
@@ -1231,9 +1235,11 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
// lookup parent directory
NodeRef dirNodeRef = getNodeForPath(tree, paths[0]);
- // Check whether we are opening a pseudo file
+ // Check whether we are closing a pseudo file
if(ctx.getPseudoFileOverlay().isPseudoFile(dirNodeRef, paths[1]))
{
+ // pseudo delete a pseudo file
+ ctx.getPseudoFileOverlay().delete(dirNodeRef, paths[1]);
return null;
}
}
@@ -2863,16 +2869,34 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
* @exception java.io.IOException If an error occurs.
* @return node ref of deleted file
*/
- public NodeRef closeFile(NodeRef rootNode, String path, NetworkFile file) throws IOException
+ public NodeRef closeFile(TreeConnection tree, NodeRef rootNode, String path, NetworkFile file) throws IOException
{
if ( logger.isDebugEnabled())
{
logger.debug("Close file:" + path + ", readOnly=" + file.isReadOnly() );
}
- if( file instanceof PseudoNetworkFile)
+ if( file instanceof PseudoNetworkFile || file instanceof MemoryNetworkFile)
{
file.close();
+
+ if(file.hasDeleteOnClose())
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("delete on close a pseudo file");
+ }
+ final ContentContext ctx = (ContentContext) tree.getContext();
+
+ String[] paths = FileName.splitPath(path);
+
+ if (paths[0] != null && paths[0].length() > 1)
+ {
+ // lookup parent directory
+ NodeRef dirNodeRef = getNodeForPath(tree, paths[0]);
+ ctx.getPseudoFileOverlay().delete(dirNodeRef, paths[1]);
+ }
+ }
return null;
}
@@ -3205,4 +3229,12 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
{
return nodeArchiveService;
}
+
+ private SimpleCache deletePseudoFileCache;
+
+ public void setDeletePseudoFileCache(SimpleCache deletePseudoFileCache)
+ {
+ this.deletePseudoFileCache = deletePseudoFileCache;
+ }
+
}