Fix for ALF-10826

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@32797 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Steven Glover
2011-12-15 18:09:53 +00:00
parent beb261ed4e
commit bf7181452c
23 changed files with 3023 additions and 2349 deletions

View File

@@ -38,6 +38,7 @@ import org.alfresco.query.CannedQueryFactory;
import org.alfresco.query.CannedQueryResults;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.model.filefolder.HiddenAspect.Visibility;
import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery;
import org.alfresco.repo.node.getchildren.GetChildrenCannedQueryFactory;
import org.alfresco.repo.search.QueryParameterDefImpl;
@@ -69,6 +70,8 @@ import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.FileFilterMode;
import org.alfresco.util.FileFilterMode.Client;
import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
@@ -120,6 +123,7 @@ public class FileFolderServiceImpl implements FileFolderService
private static Log logger = LogFactory.getLog(FileFolderServiceImpl.class);
private HiddenAspect hiddenAspect;
private NamespaceService namespaceService;
private DictionaryService dictionaryService;
private NodeService nodeService;
@@ -179,7 +183,12 @@ public class FileFolderServiceImpl implements FileFolderService
{
this.mimetypeService = mimetypeService;
}
public void setHiddenAspect(HiddenAspect hiddenAspect)
{
this.hiddenAspect = hiddenAspect;
}
/**
* Set the registry of {@link CannedQueryFactory canned queries}
*/
@@ -230,10 +239,15 @@ public class FileFolderServiceImpl implements FileFolderService
private List<FileInfo> toFileInfo(List<NodeRef> nodeRefs) throws InvalidTypeException
{
List<FileInfo> results = new ArrayList<FileInfo>(nodeRefs.size());
Client client = FileFilterMode.getClient();
for (NodeRef nodeRef : nodeRefs)
{
try
{
if(hiddenAspect.getVisibility(client, nodeRef) == Visibility.NotVisible)
{
continue;
}
FileInfo fileInfo = toFileInfo(nodeRef, true);
results.add(fileInfo);
}
@@ -257,12 +271,13 @@ public class FileFolderServiceImpl implements FileFolderService
QName typeQName = nodeService.getType(nodeRef);
boolean isFolder = isFolder(typeQName);
boolean isHidden = false;
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN))
Client client = FileFilterMode.getClient();
if(hiddenAspect.getVisibility(client, nodeRef) == Visibility.HiddenAttribute)
{
isHidden = true;
isHidden = true;
}
// Construct the file info and add to the results
FileInfo fileInfo = new FileInfoImpl(nodeRef, typeQName, isFolder, isHidden, properties);
@@ -380,8 +395,14 @@ public class FileFolderServiceImpl implements FileFolderService
}
final List<FileInfo> nodeInfos = new ArrayList<FileInfo>(nodeRefs.size());
final Client client = FileFilterMode.getClient();
for (NodeRef nodeRef : nodeRefs)
{
if(hiddenAspect.getVisibility(client, nodeRef) == Visibility.NotVisible)
{
continue;
}
nodeInfos.add(toFileInfo(nodeRef, true));
}
PermissionCheckedCollectionMixin.create(nodeInfos, nodeRefs);
@@ -1208,6 +1229,7 @@ public class FileFolderServiceImpl implements FileFolderService
}
NodeRef nodeRef = assocRef.getChildRef();
FileInfo fileInfo = toFileInfo(nodeRef, true);
// done
if (logger.isDebugEnabled())
@@ -1441,19 +1463,4 @@ public class FileFolderServiceImpl implements FileFolderService
}
return new Pair<String, String>(base, ext);
}
public List<FileInfo> removeHiddenFiles(List<FileInfo> files)
{
List<FileInfo> ret = new ArrayList<FileInfo>(files.size());
for(FileInfo file : files)
{
if(!nodeService.hasAspect(file.getNodeRef(), ContentModel.ASPECT_HIDDEN))
{
ret.add(file);
}
}
return ret;
}
}

View File

@@ -33,7 +33,6 @@ import javax.transaction.UserTransaction;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.jlan.server.FileFilterMode;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ForumModel;
import org.alfresco.query.PagingRequest;
@@ -43,6 +42,7 @@ import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.dictionary.M2Type;
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl.InvalidTypeException;
import org.alfresco.repo.model.filefolder.HiddenAspect.Visibility;
import org.alfresco.repo.node.integrity.IntegrityChecker;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
@@ -69,6 +69,8 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.FileFilterMode;
import org.alfresco.util.FileFilterMode.Client;
import org.alfresco.util.GUID;
import org.springframework.context.ApplicationContext;
import org.springframework.extensions.surf.util.I18NUtil;
@@ -97,6 +99,7 @@ public class FileFolderServiceImplTest extends TestCase
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private HiddenAspect hiddenAspect;
private TransactionService transactionService;
private NodeService nodeService;
private FileFolderService fileFolderService;
@@ -117,6 +120,7 @@ public class FileFolderServiceImplTest extends TestCase
permissionService = serviceRegistry.getPermissionService();
authenticationService = (MutableAuthenticationService) ctx.getBean("AuthenticationService");
dictionaryDAO = (DictionaryDAO) ctx.getBean("dictionaryDAO");
hiddenAspect = (HiddenAspect)ctx.getBean("hiddenAspect");
// start the transaction
txn = transactionService.getUserTransaction();
@@ -1280,31 +1284,74 @@ public class FileFolderServiceImplTest extends TestCase
public void testHiddenFiles()
{
FileFilterMode.setMode(FileFilterMode.Mode.ENHANCED);
FileFilterMode.setClient(Client.webdav);
NodeRef parent = fileFolderService.create(rootNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child = fileFolderService.create(parent, "file.tmp", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertTrue(!nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
try
{
NodeRef parent = fileFolderService.create(rootNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child = fileFolderService.create(parent, "file.tmp", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertTrue(!nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
NodeRef parent1 = fileFolderService.create(rootNodeRef, ".TemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child1 = fileFolderService.create(parent1, "file1", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_TEMPORARY));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_HIDDEN));
NodeRef parent2 = fileFolderService.create(rootNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child2 = fileFolderService.create(parent2, "Thumbs.db", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(!nodeService.hasAspect(child2, ContentModel.ASPECT_TEMPORARY));
assertTrue(nodeService.hasAspect(child2, ContentModel.ASPECT_HIDDEN));
// set hidden attribute for cifs, webdav should be able to see, other clients not
assertEquals(Visibility.Visible, hiddenAspect.getVisibility(Client.webdav, child2));
assertEquals(Visibility.HiddenAttribute, hiddenAspect.getVisibility(Client.cifs, child2));
assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(Client.script, child2));
assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(Client.webclient, child2));
NodeRef parent1 = fileFolderService.create(rootNodeRef, ".TemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child1 = fileFolderService.create(parent1, "file1", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_TEMPORARY));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_HIDDEN));
NodeRef node1 = fileFolderService.create(rootNodeRef, "surf-config", ContentModel.TYPE_FOLDER).getNodeRef();
assertTrue(nodeService.hasAspect(node1, ContentModel.ASPECT_HIDDEN));
// surf-config should not be visible to any client
for(Client client : hiddenAspect.getClients())
{
assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(client, node1));
}
NodeRef node2 = fileFolderService.create(rootNodeRef, ".DS_Store", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(node2, ContentModel.ASPECT_HIDDEN));
// .DS_Store is a system path and so is visible in nfs and webdav, as a hidden file in cifs and hidden to all other clients
for(Client client : hiddenAspect.getClients())
{
if(client == Client.cifs)
{
assertEquals(Visibility.HiddenAttribute, hiddenAspect.getVisibility(client, node2));
}
else if(client == Client.webdav)
{
assertEquals(Visibility.Visible, hiddenAspect.getVisibility(client, node2));
}
else if(client == Client.nfs)
{
assertEquals(Visibility.Visible, hiddenAspect.getVisibility(client, node2));
}
else
{
assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(client, node2));
}
}
NodeRef parent2 = fileFolderService.create(rootNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child2 = fileFolderService.create(parent2, "Thumbs.db", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(!nodeService.hasAspect(child2, ContentModel.ASPECT_TEMPORARY));
assertTrue(nodeService.hasAspect(child2, ContentModel.ASPECT_HIDDEN));
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(1, children.size());
children = fileFolderService.list(parent1);
assertEquals(1, children.size());
children = fileFolderService.list(parent2);
assertEquals(1, children.size());
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(1, children.size());
children = fileFolderService.list(parent1);
assertEquals(1, children.size());
children = fileFolderService.list(parent2);
assertEquals(1, children.size());
}
finally
{
FileFilterMode.clearClient();
}
}
public void testPatterns()

View File

@@ -42,7 +42,7 @@ public class FileInfoImpl implements FileInfo
private NodeRef linkNodeRef;
private boolean isFolder;
private boolean isLink;
private boolean isHindden;
private boolean isHidden;
private Map<QName, Serializable> properties;
private QName typeQName;
@@ -61,7 +61,7 @@ public class FileInfoImpl implements FileInfo
this.isFolder = isFolder;
this.properties = properties;
this.isHindden = isHidden;
this.isHidden = isHidden;
// Check if this is a link node
if ( properties.containsKey( ContentModel.PROP_LINK_DESTINATION))
@@ -94,6 +94,11 @@ public class FileInfoImpl implements FileInfo
return (this.getNodeRef().equals(that.getNodeRef()));
}
void setHidden(boolean isHidden)
{
this.isHidden = isHidden;
}
/**
* @see #getNodeRef()
* @see NodeRef#hashCode()
@@ -139,7 +144,7 @@ public class FileInfoImpl implements FileInfo
}
public boolean isHidden() {
return isHindden;
return isHidden;
}
public NodeRef getLinkNodeRef()

View File

@@ -17,14 +17,10 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. */
package org.alfresco.repo.model.filefolder;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.alfresco.jlan.server.FileFilterMode;
import org.alfresco.jlan.server.FileFilterMode.Mode;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.filefolder.HiddenAspect.Visibility;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -33,6 +29,9 @@ import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.FileFilterMode;
import org.alfresco.util.FileFilterMode.Client;
import org.alfresco.util.FileFilterMode.Mode;
import org.alfresco.util.PatternFilter;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -40,8 +39,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* An interceptor that intercepts the FileFolderService create method, creating files and folders as the system user
* and applying temporary and hidden aspects when they match a pattern.
* An interceptor that intercepts FileFolderService methods, ensuring system, temporary and hidden files
* and paths are marked with the correct aspects.
*
*/
public class FilenameFilteringInterceptor implements MethodInterceptor
@@ -52,22 +51,13 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
private PermissionService permissionService;
private PatternFilter temporaryFiles;
private PatternFilter hiddenFiles;
private PatternFilter systemPaths;
private HiddenAspect hiddenAspect;
public FilenameFilteringInterceptor()
{
}
/**
* A list of regular expressions that represent patterns of hidden files.
*
*/
public void setHiddenFiles(PatternFilter hiddenFiles)
{
this.hiddenFiles = hiddenFiles;
}
/**
* A list of regular expressions that represent patterns of temporary files.
*
@@ -77,7 +67,12 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
this.temporaryFiles = temporaryFiles;
}
/**
public void setHiddenAspect(HiddenAspect hiddenAspect)
{
this.hiddenAspect = hiddenAspect;
}
/**
* A list of regular expressions that represent patterns of system paths.
*
*/
@@ -90,6 +85,11 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
{
return FileFilterMode.getMode();
}
public Client getClient()
{
return FileFilterMode.getClient();
}
/**
* @param nodeService the service to use to apply the <b>sys:temporary</b> aspect
@@ -134,49 +134,6 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
}
}
}
private void checkHiddenAspect(boolean isHidden, FileInfo fileInfo)
{
NodeRef nodeRef = fileInfo.getNodeRef();
if (isHidden)
{
nodeService.addAspect(nodeRef, ContentModel.ASPECT_HIDDEN, null);
Map<QName, Serializable> props = new HashMap<QName, Serializable>(2);
props.put(ContentModel.PROP_IS_INDEXED, Boolean.FALSE);
props.put(ContentModel.PROP_IS_CONTENT_INDEXED, Boolean.FALSE);
nodeService.addAspect(nodeRef, ContentModel.ASPECT_INDEX_CONTROL, props);
if (logger.isDebugEnabled())
{
logger.debug("Applied hidden marker: " + fileInfo);
}
}
else
{
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN))
{
// Remove the aspect
nodeService.removeAspect(nodeRef, ContentModel.ASPECT_HIDDEN);
if (logger.isDebugEnabled())
{
logger.debug("Removed hidden marker: " + fileInfo);
}
}
}
}
private void addIndexedAspect(FileInfo fileInfo)
{
NodeRef nodeRef = fileInfo.getNodeRef();
Map<QName, Serializable> props = new HashMap<QName, Serializable>(2);
props.put(ContentModel.PROP_IS_INDEXED, Boolean.FALSE);
props.put(ContentModel.PROP_IS_CONTENT_INDEXED, Boolean.FALSE);
nodeService.addAspect(nodeRef, ContentModel.ASPECT_INDEX_CONTROL, props);
}
private Object runAsSystem(MethodInvocation invocation) throws Throwable
{
@@ -219,6 +176,15 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
return ret;
}
private int getSystemFileVisibilityMask()
{
int mask = 0;
mask |= hiddenAspect.getClientVisibilityMask(Client.cifs, Visibility.HiddenAttribute);
mask |= hiddenAspect.getClientVisibilityMask(Client.webdav, Visibility.Visible);
mask |= hiddenAspect.getClientVisibilityMask(Client.nfs, Visibility.Visible);
return mask;
}
public Object invoke(final MethodInvocation invocation) throws Throwable
{
// execute and get the result
@@ -237,34 +203,32 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
{
// it's a system file/folder, create as system and allow full control to all authorities
ret = runAsSystem(invocation);
permissionService.setPermission(((FileInfo)ret).getNodeRef(), PermissionService.ALL_AUTHORITIES, PermissionService.FULL_CONTROL, true);
FileInfoImpl fileInfo = (FileInfoImpl)ret;
permissionService.setPermission(fileInfo.getNodeRef(), PermissionService.ALL_AUTHORITIES, PermissionService.FULL_CONTROL, true);
// it's always marked temporary and hidden
checkTemporaryAspect(true, (FileInfo)ret);
checkHiddenAspect(true, (FileInfo)ret);
addIndexedAspect((FileInfo)ret);
checkTemporaryAspect(true, fileInfo);
hiddenAspect.hideNode(fileInfo, getSystemFileVisibilityMask());
}
else
{
// it's not a temporary file/folder, create as normal
ret = invocation.proceed();
FileInfoImpl fileInfo = (FileInfoImpl)ret;
// NodeRef retNodeRef = fileInfo.getNodeRef();
// if it's on a temporary path check whether temporary and hidden aspects need to be applied
if(isSystemPath(nodeRef, filename))
{
checkTemporaryAspect(true, (FileInfo)ret);
checkHiddenAspect(true, (FileInfo)ret);
addIndexedAspect((FileInfo)ret);
// it's on a system path, check whether temporary, hidden and noindex aspects need to be applied
checkTemporaryAspect(true, fileInfo);
hiddenAspect.hideNode(fileInfo, getSystemFileVisibilityMask());
}
else
{
// check whether it's a temporary or hidden file
checkTemporaryAspect(temporaryFiles.isFiltered(filename), (FileInfo)ret);
boolean isHidden = hiddenFiles.isFiltered(filename);
checkHiddenAspect(isHidden, (FileInfo)ret);
if(isHidden)
{
addIndexedAspect((FileInfo)ret);
}
hiddenAspect.checkHidden(fileInfo);
}
}
}
@@ -272,7 +236,11 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
{
ret = invocation.proceed();
checkTemporaryAspect(temporaryFiles.isFiltered(filename), (FileInfo)ret);
FileInfoImpl fileInfo = (FileInfoImpl)ret;
//NodeRef retNodeRef = fileInfo.getNodeRef();
checkTemporaryAspect(temporaryFiles.isFiltered(filename), fileInfo);
hiddenAspect.checkHidden(fileInfo);
}
}
else if (methodName.startsWith("rename") ||
@@ -281,23 +249,19 @@ public class FilenameFilteringInterceptor implements MethodInterceptor
{
ret = invocation.proceed();
FileInfo fileInfo = (FileInfo) ret;
FileInfoImpl fileInfo = (FileInfoImpl) ret;
String filename = fileInfo.getName();
// NodeRef retNodeRef = fileInfo.getNodeRef();
if (logger.isDebugEnabled())
{
logger.debug("Checking filename returned by " + methodName + ": " + filename);
}
// check against all the regular expressions
checkTemporaryAspect(temporaryFiles.isFiltered(filename), fileInfo);
boolean isHidden = hiddenFiles.isFiltered(filename);
checkHiddenAspect(isHidden, fileInfo);
if(isHidden)
{
addIndexedAspect((FileInfo)ret);
}
hiddenAspect.checkHidden(fileInfo);
// hiddenAspect.checkHidden(retNodeRef);
}
else
{

View File

@@ -0,0 +1,454 @@
package org.alfresco.repo.model.filefolder;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.FileFilterMode;
import org.alfresco.util.FileFilterMode.Client;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Functionality relating to hidden files and folders.
*
* Support for nodes marked as hidden but with visibility constraints for specific clients. A node
* can have the hidden aspect applied, which means that the node is hidden. However,
* for specific clients it can be defined whether the node is visible or will have its hidden attribute
* set in FileInfo.
*
*/
public class HiddenAspect
{
private static Log logger = LogFactory.getLog(HiddenAspect.class);
public static enum Visibility
{
NotVisible, Visible, HiddenAttribute;
public int getMask()
{
if(this == Visible)
{
return 2;
}
else if(this == HiddenAttribute)
{
return 1;
}
else if(this == NotVisible)
{
return 0;
}
else
{
throw new IllegalArgumentException();
}
}
public static Visibility getVisibility(int mask)
{
if(mask == 2)
{
return Visible;
}
else if(mask == 1)
{
return HiddenAttribute;
}
else if(mask == 0)
{
return NotVisible;
}
else
{
throw new IllegalArgumentException();
}
}
};
private List<HiddenFileInfoImpl> filters = new ArrayList<HiddenFileInfoImpl>(10);
private NodeService nodeService;
public HiddenAspect()
{
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setPatterns(List<HiddenFileFilter> filters)
{
for(HiddenFileFilter filter : filters)
{
this.filters.add(new HiddenFileInfoImpl(filter.getFilter(), filter.getVisibility(), filter.getHiddenAttribute()));
}
}
public Client[] getClients()
{
return Client.values();
}
private Integer getClientIndex(Client client)
{
return client.ordinal();
}
private void addIndexControlAspect(NodeRef nodeRef)
{
Map<QName, Serializable> props = new HashMap<QName, Serializable>(2);
props.put(ContentModel.PROP_IS_INDEXED, Boolean.FALSE);
props.put(ContentModel.PROP_IS_CONTENT_INDEXED, Boolean.FALSE);
nodeService.addAspect(nodeRef, ContentModel.ASPECT_INDEX_CONTROL, props);
if (logger.isDebugEnabled())
{
logger.debug("Applied index control marker: " + nodeRef);
}
}
private void addHiddenAspect(NodeRef nodeRef, int visibilityMask)
{
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
props.put(ContentModel.PROP_VISIBILITY_MASK, visibilityMask);
nodeService.addAspect(nodeRef, ContentModel.ASPECT_HIDDEN, props);
if (logger.isDebugEnabled())
{
logger.debug("Applied hidden marker: " + nodeRef);
}
}
private void removeHiddenAspect(NodeRef nodeRef)
{
// Remove the aspect
nodeService.removeAspect(nodeRef, ContentModel.ASPECT_HIDDEN);
if (logger.isDebugEnabled())
{
logger.debug("Removed hidden marker: " + nodeRef);
}
}
private Visibility getVisibility(Integer mask, Client client)
{
if(mask == null || mask.intValue() == 0)
{
return Visibility.NotVisible;
}
mask = (mask.intValue() >> (getClientIndex(client))*2) & 3;
return Visibility.getVisibility(mask);
}
/**
* Determines whether the path matches any one of the hidden file patterns and, if so,
* returns the matching pattern.
*
* @param path
* @return
*/
private HiddenFileInfo isHidden(String path)
{
// check against all the filters
HiddenFileInfoImpl matched = null;
for(HiddenFileInfoImpl filter : filters)
{
if(filter.isHidden(path))
{
matched = filter;
break;
}
}
return matched;
}
public int getClientVisibilityMask(Client client, Visibility visibility)
{
return visibility.getMask() << getClientIndex(client)*2;
}
/**
* Checks whether the node is on a hidden path
*
* @param nodeRef
* @return the matching filter, or null if no match
*/
public HiddenFileInfo isHidden(NodeRef nodeRef)
{
HiddenFileInfo ret = null;
// TODO would be nice to check each part of the path in turn, bailing out if a match is found
Path path = nodeService.getPath(nodeRef);
Iterator<Element> it = path.iterator();
while(it.hasNext())
{
Path.ChildAssocElement elem = (Path.ChildAssocElement)it.next();
QName qname = elem.getRef().getQName();
if(qname != null)
{
ret = isHidden(qname.getLocalName());
if(ret != null)
{
break;
}
}
}
return ret;
}
/**
* Hides the node by applying the hidden and not indexed aspects. The node will be hidden from all clients.
*
* @param client
* @param fileInfo
* @return
*/
public void hideNode(NodeRef nodeRef)
{
addHiddenAspect(nodeRef, 0);
addIndexControlAspect(nodeRef);
}
/**
* Hides the node by applying the hidden and not indexed aspects. The node will be hidden from clients
* according to the visibility mask.
*
* @param client
* @param fileInfo
* @return
*/
public void hideNode(NodeRef nodeRef, int clientVisibilityMask)
{
addHiddenAspect(nodeRef, clientVisibilityMask);
addIndexControlAspect(nodeRef);
}
public void checkHidden(FileInfoImpl fileInfo)
{
NodeRef nodeRef = fileInfo.getNodeRef();
HiddenFileInfo hiddenFileInfo = checkHidden(nodeRef);
if(hiddenFileInfo != null)
{
fileInfo.setHidden(true);
}
}
public void hideNode(FileInfoImpl fileInfo, int visibilityMask)
{
hideNode(fileInfo.getNodeRef(), visibilityMask);
fileInfo.setHidden(true);
}
/**
* Checks whether the file should be hidden and applies the hidden and not indexed aspects if so.
*
* @param client
* @param fileInfo
* @return
*/
public HiddenFileInfo checkHidden(NodeRef nodeRef)
{
HiddenFileInfo filter = isHidden(nodeRef);
if(filter != null)
{
// the file matches a pattern, apply the hidden and aspect control aspects
addHiddenAspect(nodeRef, filter.getVisibilityMask());
addIndexControlAspect(nodeRef);
}
else
{
// the file does not match the pattern, ensure that the hidden aspect is not present
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN))
{
removeHiddenAspect(nodeRef);
}
}
return filter;
}
/**
* Gets the visibility constraint for the given client on the given node.
*
* @param client
* @param nodeRef
*
* @return the visibility constraint for the given client and node
*/
public Visibility getVisibility(Client client, NodeRef nodeRef)
{
Visibility ret = null;
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN))
{
Integer visibilityMask = (Integer)nodeService.getProperty(nodeRef, ContentModel.PROP_VISIBILITY_MASK);
if(visibilityMask != null)
{
if(visibilityMask.intValue() == 0)
{
ret = Visibility.NotVisible;
}
else if(client == null)
{
ret = Visibility.NotVisible;
}
else
{
ret = getVisibility(visibilityMask.intValue(), client);
}
}
else
{
// no visibility mask property, so retain backwards compatibility with 3.4 hidden aspect behaviour
if(client == Client.cifs)
{
ret = Visibility.HiddenAttribute;
}
else if(client == Client.webdav || client == Client.nfs || client == Client.imap)
{
ret = Visibility.Visible;
}
else
{
ret = Visibility.NotVisible;
}
}
}
return ret;
}
/**
* Return the list of files with hidden files filtered out if required for the given client.
*
* @param client
* @param files
* @return
*/
// public List<FileInfo> removeHiddenFiles(Client client, List<FileInfo> files)
// {
// // TODO bulk load aspects and properties of nodes first?
// List<FileInfo> ret = new ArrayList<FileInfo>(files.size());
// int numHiddenFiles = 0;
//
// for(FileInfo file : files)
// {
// if(getVisibility(client, file.getNodeRef()) == Visibility.NotVisible)
// {
// numHiddenFiles++;
// continue;
// }
//
// ret.add(file);
// }
//
// return ret;
// }
private class HiddenFileInfoImpl implements HiddenFileInfo
{
private Pattern filter;
private Set<Client> clientVisibility = new HashSet<Client>(10);
private Set<Client> hiddenAttribute = new HashSet<Client>(10);
private int visibilityMask;
public HiddenFileInfoImpl(String regexp, String visibility, String hiddenAttribute)
{
this.filter = Pattern.compile(regexp);
setVisibility(visibility);
setHiddenAttribute(hiddenAttribute);
calculateVisibilityMask();
}
private void setVisibility(String visibility)
{
if(visibility != null && !visibility.equals(""))
{
for(String clientStr : visibility.split(","))
{
Client client = Client.getClient(clientStr);
this.clientVisibility.add(client);
}
}
}
private void setHiddenAttribute(String hiddenAttribute)
{
if(hiddenAttribute != null && !hiddenAttribute.equals(""))
{
for(String clientStr : hiddenAttribute.split(","))
{
Client client = Client.getClient(clientStr);
this.hiddenAttribute.add(client);
}
}
}
private void calculateVisibilityMask()
{
visibilityMask = 0;
for(Client client : getClients())
{
if(clientVisibility.contains(client))
{
visibilityMask |= getClientVisibilityMask(client, Visibility.Visible);
}
else if(hiddenAttribute.contains(client))
{
visibilityMask |= getClientVisibilityMask(client, Visibility.HiddenAttribute);
}
else
{
visibilityMask |= getClientVisibilityMask(client, Visibility.NotVisible);
}
}
}
public String getFilter()
{
return filter.pattern();
}
public Set<Client> getVisibility()
{
return clientVisibility;
}
public Set<Client> getHiddenAttribute()
{
return hiddenAttribute;
}
public int getVisibilityMask()
{
return visibilityMask;
}
boolean isHidden(String path)
{
return filter.matcher(path).matches();
}
}
}

View File

@@ -0,0 +1,62 @@
package org.alfresco.repo.model.filefolder;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
public class HiddenFileFilter implements InitializingBean
{
private String filter;
private String visibility;
private String hiddenAttribute;
public HiddenFileFilter()
{
}
public void setFilter(String filter)
{
this.filter = filter;
}
public void setVisibility(String visibility)
{
this.visibility = visibility;
}
public String getFilter()
{
return filter;
}
public String getVisibility()
{
return visibility;
}
public String getHiddenAttribute()
{
return hiddenAttribute;
}
public void setHiddenAttribute(String hiddenAttribute)
{
this.hiddenAttribute = hiddenAttribute;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "filter", filter);
if(visibility == null)
{
visibility = "";
}
if(hiddenAttribute == null)
{
hiddenAttribute = "";
}
}
}

View File

@@ -0,0 +1,12 @@
package org.alfresco.repo.model.filefolder;
import java.util.Set;
import org.alfresco.util.FileFilterMode.Client;
public interface HiddenFileInfo
{
public Set<Client> getVisibility();
public int getVisibilityMask();
public String getFilter();
}