mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-15 15:02:20 +00:00
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:
@@ -67,6 +67,7 @@ import org.alfresco.query.EmptyPagingResults;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.query.PagingResults;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.model.filefolder.HiddenAspect;
|
||||
import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery;
|
||||
import org.alfresco.repo.search.QueryParameterDefImpl;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
@@ -107,6 +108,8 @@ import org.alfresco.service.cmr.version.VersionType;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.FileFilterMode;
|
||||
import org.alfresco.util.FileFilterMode.Client;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -351,6 +354,11 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
|
||||
{
|
||||
lifecycle.setApplicationContext(applicationContext);
|
||||
}
|
||||
|
||||
public void setHiddenAspect(HiddenAspect hiddenAspect)
|
||||
{
|
||||
this.hiddenAspect = hiddenAspect;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
@@ -587,6 +595,8 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
|
||||
}
|
||||
}
|
||||
|
||||
private HiddenAspect hiddenAspect;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getChildren(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.cmis.CMISTypesFilterEnum, java.lang.String)
|
||||
@@ -595,12 +605,14 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
|
||||
throws CMISInvalidArgumentException
|
||||
{
|
||||
PagingResults<FileInfo> pageOfNodeInfos = getChildren(folderNodeRef, typesFilter, BigInteger.valueOf(Integer.MAX_VALUE), BigInteger.valueOf(0), orderBy);
|
||||
|
||||
int pageCnt = pageOfNodeInfos.getPage().size();
|
||||
|
||||
// List<FileInfo> filteredChildren = hiddenAspect.removeHiddenFiles(Client.cmis, pageOfNodeInfos.getPage());
|
||||
List<FileInfo> filteredChildren = pageOfNodeInfos.getPage();
|
||||
int pageCnt = filteredChildren.size();
|
||||
NodeRef[] result = new NodeRef[pageCnt];
|
||||
|
||||
|
||||
int idx = 0;
|
||||
for (FileInfo child : pageOfNodeInfos.getPage())
|
||||
for (FileInfo child : filteredChildren)
|
||||
{
|
||||
result[idx] = child.getNodeRef();
|
||||
idx++;
|
||||
@@ -694,14 +706,22 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
|
||||
// numItems may be
|
||||
// returned
|
||||
|
||||
PagingResults<FileInfo> result = fileFolderService.list(folderNodeRef, listFiles, listFolders, null, sortProps, pageRequest);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
FileFilterMode.setClient(Client.cmis);
|
||||
try
|
||||
{
|
||||
logger.debug("getChildren: " + result.getPage().size() + " in " + (System.currentTimeMillis() - start) + " msecs");
|
||||
PagingResults<FileInfo> result = fileFolderService.list(folderNodeRef, listFiles, listFolders, null, sortProps, pageRequest);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("getChildren: " + result.getPage().size() + " in " + (System.currentTimeMillis() - start) + " msecs");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
FileFilterMode.clearClient();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -36,6 +36,8 @@ import org.alfresco.jlan.server.filesys.FileName;
|
||||
import org.alfresco.jlan.server.filesys.FileType;
|
||||
import org.alfresco.jlan.util.WildCard;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.model.filefolder.HiddenAspect;
|
||||
import org.alfresco.repo.model.filefolder.HiddenAspect.Visibility;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileFolderUtil;
|
||||
@@ -49,6 +51,7 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.FileFilterMode.Client;
|
||||
import org.alfresco.util.SearchLanguageConversion;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -70,6 +73,7 @@ public class CifsHelper
|
||||
private FileFolderService fileFolderService;
|
||||
private MimetypeService mimetypeService;
|
||||
private PermissionService permissionService;
|
||||
private HiddenAspect hiddenAspect;
|
||||
|
||||
private Set<QName> excludedTypes = new HashSet<QName>();
|
||||
|
||||
@@ -107,6 +111,11 @@ public class CifsHelper
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
public void setHiddenAspect(HiddenAspect hiddenAspect)
|
||||
{
|
||||
this.hiddenAspect = hiddenAspect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node service
|
||||
*
|
||||
@@ -285,10 +294,9 @@ public class CifsHelper
|
||||
if (name != null)
|
||||
{
|
||||
fileInfo.setFileName(name);
|
||||
|
||||
|
||||
// Check for file names that should be hidden
|
||||
|
||||
if(nodeService.hasAspect(fileInfo.getNodeRef(), ContentModel.ASPECT_HIDDEN))
|
||||
if(hiddenAspect.getVisibility(Client.cifs, fileInfo.getNodeRef()) == Visibility.HiddenAttribute)
|
||||
{
|
||||
// Add the hidden file attribute
|
||||
int attr = fileInfo.getFileAttributes();
|
||||
|
@@ -6,10 +6,7 @@ import java.util.List;
|
||||
|
||||
import org.alfresco.filesys.alfresco.ExtendedDiskInterface;
|
||||
import org.alfresco.filesys.alfresco.RepositoryDiskInterface;
|
||||
import org.alfresco.filesys.repo.FilesystemTransactionAdvice.PropagatingException;
|
||||
import org.alfresco.filesys.repo.rules.Command;
|
||||
import org.alfresco.filesys.repo.rules.Operation;
|
||||
import org.alfresco.filesys.repo.rules.OperationExecutor;
|
||||
import org.alfresco.filesys.repo.rules.commands.CloseFileCommand;
|
||||
import org.alfresco.filesys.repo.rules.commands.CompoundCommand;
|
||||
import org.alfresco.filesys.repo.rules.commands.CopyContentCommand;
|
||||
@@ -22,23 +19,17 @@ import org.alfresco.filesys.repo.rules.commands.RemoveNoContentFileOnError;
|
||||
import org.alfresco.filesys.repo.rules.commands.RemoveTempFileCommand;
|
||||
import org.alfresco.filesys.repo.rules.commands.RenameFileCommand;
|
||||
import org.alfresco.filesys.repo.rules.commands.ReturnValueCommand;
|
||||
import org.alfresco.filesys.repo.rules.operations.CreateFileOperation;
|
||||
import org.alfresco.filesys.repo.rules.operations.DeleteFileOperation;
|
||||
import org.alfresco.filesys.repo.rules.operations.RenameFileOperation;
|
||||
import org.alfresco.jlan.server.SrvSession;
|
||||
import org.alfresco.jlan.server.filesys.AccessMode;
|
||||
import org.alfresco.jlan.server.filesys.FileAction;
|
||||
import org.alfresco.jlan.server.filesys.FileAttribute;
|
||||
import org.alfresco.jlan.server.filesys.FileOpenParams;
|
||||
import org.alfresco.jlan.server.filesys.TreeConnection;
|
||||
import org.alfresco.jlan.smb.SharingMode;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.FileFilterMode;
|
||||
import org.alfresco.util.FileFilterMode.Client;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
|
||||
/**
|
||||
* Content Disk Driver Command Executor
|
||||
@@ -164,6 +155,27 @@ public class CommandExecutorImpl implements CommandExecutor
|
||||
return ret;
|
||||
}
|
||||
|
||||
private Client getClient(SrvSession srvSession)
|
||||
{
|
||||
String clientStr = srvSession.getServer().getProtocolName().toLowerCase();
|
||||
if(clientStr.equals("cifs"))
|
||||
{
|
||||
return Client.cifs;
|
||||
}
|
||||
else if(clientStr.equals("nfs"))
|
||||
{
|
||||
return Client.nfs;
|
||||
}
|
||||
else if(clientStr.equals("ftp"))
|
||||
{
|
||||
return Client.ftp;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sess
|
||||
* @param tree
|
||||
@@ -174,122 +186,129 @@ public class CommandExecutorImpl implements CommandExecutor
|
||||
*/
|
||||
private Object executeInternal(SrvSession sess, TreeConnection tree, Command command, Object result) throws IOException
|
||||
{
|
||||
if(command instanceof CompoundCommand)
|
||||
FileFilterMode.setClient(getClient(sess));
|
||||
try
|
||||
{
|
||||
Object ret = null;
|
||||
logger.debug("compound command received");
|
||||
CompoundCommand x = (CompoundCommand)command;
|
||||
|
||||
for(Command compoundPart : x.getCommands())
|
||||
{
|
||||
logger.debug("running part of compound command");
|
||||
Object val = executeInternal(sess, tree, compoundPart, result);
|
||||
if(val != null)
|
||||
if(command instanceof CompoundCommand)
|
||||
{
|
||||
Object ret = null;
|
||||
logger.debug("compound command received");
|
||||
CompoundCommand x = (CompoundCommand)command;
|
||||
|
||||
for(Command compoundPart : x.getCommands())
|
||||
{
|
||||
// Return the value from the last command.
|
||||
ret = val;
|
||||
logger.debug("running part of compound command");
|
||||
Object val = executeInternal(sess, tree, compoundPart, result);
|
||||
if(val != null)
|
||||
{
|
||||
// Return the value from the last command.
|
||||
ret = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
else if(command instanceof CreateFileCommand)
|
||||
{
|
||||
logger.debug("create file command");
|
||||
CreateFileCommand create = (CreateFileCommand)command;
|
||||
return repositoryDiskInterface.createFile(create.getRootNode(), create.getPath(), create.getAllocationSize());
|
||||
}
|
||||
else if(command instanceof DeleteFileCommand)
|
||||
{
|
||||
logger.debug("delete file command");
|
||||
DeleteFileCommand delete = (DeleteFileCommand)command;
|
||||
diskInterface.deleteFile(sess, tree, delete.getPath());
|
||||
}
|
||||
else if(command instanceof OpenFileCommand)
|
||||
{
|
||||
logger.debug("open file command");
|
||||
OpenFileCommand o = (OpenFileCommand)command;
|
||||
|
||||
OpenFileMode mode = o.getMode();
|
||||
return repositoryDiskInterface.openFile(sess, tree, o.getRootNodeRef(), o.getPath(), mode, o.isTruncate());
|
||||
|
||||
}
|
||||
else if(command instanceof CloseFileCommand)
|
||||
{
|
||||
logger.debug("close file command");
|
||||
CloseFileCommand c = (CloseFileCommand)command;
|
||||
repositoryDiskInterface.closeFile(c.getRootNodeRef(), c.getPath(), c.getNetworkFile());
|
||||
}
|
||||
else if(command instanceof ReduceQuotaCommand)
|
||||
{
|
||||
logger.debug("reduceQuota file command");
|
||||
ReduceQuotaCommand r = (ReduceQuotaCommand)command;
|
||||
repositoryDiskInterface.reduceQuota(sess, tree, r.getNetworkFile());
|
||||
}
|
||||
else if(command instanceof RenameFileCommand)
|
||||
{
|
||||
logger.debug("rename command");
|
||||
RenameFileCommand rename = (RenameFileCommand)command;
|
||||
diskInterface.renameFile(sess, tree, rename.getFromPath(), rename.getToPath());
|
||||
}
|
||||
else if(command instanceof CopyContentCommand)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Copy content command - copy content");
|
||||
return ret;
|
||||
}
|
||||
CopyContentCommand copy = (CopyContentCommand)command;
|
||||
repositoryDiskInterface.copyContent(copy.getRootNode(), copy.getFromPath(), copy.getToPath());
|
||||
}
|
||||
else if(command instanceof DoNothingCommand)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
else if(command instanceof CreateFileCommand)
|
||||
{
|
||||
logger.debug("Do Nothing Command - doing nothing");
|
||||
logger.debug("create file command");
|
||||
CreateFileCommand create = (CreateFileCommand)command;
|
||||
return repositoryDiskInterface.createFile(create.getRootNode(), create.getPath(), create.getAllocationSize());
|
||||
}
|
||||
else if(command instanceof DeleteFileCommand)
|
||||
{
|
||||
logger.debug("delete file command");
|
||||
DeleteFileCommand delete = (DeleteFileCommand)command;
|
||||
diskInterface.deleteFile(sess, tree, delete.getPath());
|
||||
}
|
||||
else if(command instanceof OpenFileCommand)
|
||||
{
|
||||
logger.debug("open file command");
|
||||
OpenFileCommand o = (OpenFileCommand)command;
|
||||
|
||||
OpenFileMode mode = o.getMode();
|
||||
return repositoryDiskInterface.openFile(sess, tree, o.getRootNodeRef(), o.getPath(), mode, o.isTruncate());
|
||||
|
||||
}
|
||||
else if(command instanceof CloseFileCommand)
|
||||
{
|
||||
logger.debug("close file command");
|
||||
CloseFileCommand c = (CloseFileCommand)command;
|
||||
repositoryDiskInterface.closeFile(c.getRootNodeRef(), c.getPath(), c.getNetworkFile());
|
||||
}
|
||||
else if(command instanceof ReduceQuotaCommand)
|
||||
{
|
||||
logger.debug("reduceQuota file command");
|
||||
ReduceQuotaCommand r = (ReduceQuotaCommand)command;
|
||||
repositoryDiskInterface.reduceQuota(sess, tree, r.getNetworkFile());
|
||||
}
|
||||
else if(command instanceof RenameFileCommand)
|
||||
{
|
||||
logger.debug("rename command");
|
||||
RenameFileCommand rename = (RenameFileCommand)command;
|
||||
diskInterface.renameFile(sess, tree, rename.getFromPath(), rename.getToPath());
|
||||
}
|
||||
else if(command instanceof CopyContentCommand)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Copy content command - copy content");
|
||||
}
|
||||
CopyContentCommand copy = (CopyContentCommand)command;
|
||||
repositoryDiskInterface.copyContent(copy.getRootNode(), copy.getFromPath(), copy.getToPath());
|
||||
}
|
||||
else if(command instanceof DoNothingCommand)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Do Nothing Command - doing nothing");
|
||||
}
|
||||
}
|
||||
else if(command instanceof ResultCallback)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Result Callback");
|
||||
}
|
||||
ResultCallback callback = (ResultCallback)command;
|
||||
callback.execute(result);
|
||||
}
|
||||
else if(command instanceof RemoveTempFileCommand)
|
||||
{
|
||||
RemoveTempFileCommand r = (RemoveTempFileCommand)command;
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Remove Temp File:" + r.getNetworkFile());
|
||||
}
|
||||
File file = r.getNetworkFile().getFile();
|
||||
boolean isDeleted = file.delete();
|
||||
|
||||
if(!isDeleted)
|
||||
{
|
||||
logger.debug("unable to delete temp file:" + r.getNetworkFile() + ", closed="+ r.getNetworkFile().isClosed());
|
||||
}
|
||||
}
|
||||
else if(command instanceof ReturnValueCommand)
|
||||
{
|
||||
ReturnValueCommand r = (ReturnValueCommand)command;
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Return value");
|
||||
}
|
||||
return r.getReturnValue();
|
||||
}
|
||||
else if(command instanceof RemoveNoContentFileOnError)
|
||||
{
|
||||
RemoveNoContentFileOnError r = (RemoveNoContentFileOnError)command;
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Remove no content file on error");
|
||||
}
|
||||
repositoryDiskInterface.deleteEmptyFile(r.getRootNodeRef(), r.getPath());
|
||||
}
|
||||
}
|
||||
else if(command instanceof ResultCallback)
|
||||
finally
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Result Callback");
|
||||
}
|
||||
ResultCallback callback = (ResultCallback)command;
|
||||
callback.execute(result);
|
||||
FileFilterMode.clearClient();
|
||||
}
|
||||
else if(command instanceof RemoveTempFileCommand)
|
||||
{
|
||||
RemoveTempFileCommand r = (RemoveTempFileCommand)command;
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Remove Temp File:" + r.getNetworkFile());
|
||||
}
|
||||
File file = r.getNetworkFile().getFile();
|
||||
boolean isDeleted = file.delete();
|
||||
|
||||
if(!isDeleted)
|
||||
{
|
||||
logger.debug("unable to delete temp file:" + r.getNetworkFile() + ", closed="+ r.getNetworkFile().isClosed());
|
||||
}
|
||||
}
|
||||
else if(command instanceof ReturnValueCommand)
|
||||
{
|
||||
ReturnValueCommand r = (ReturnValueCommand)command;
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Return value");
|
||||
}
|
||||
return r.getReturnValue();
|
||||
}
|
||||
else if(command instanceof RemoveNoContentFileOnError)
|
||||
{
|
||||
RemoveNoContentFileOnError r = (RemoveNoContentFileOnError)command;
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Remove no content file on error");
|
||||
}
|
||||
repositoryDiskInterface.deleteEmptyFile(r.getRootNodeRef(), r.getPath());
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@ import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||
import org.alfresco.repo.batch.BatchProcessWorkProvider;
|
||||
import org.alfresco.repo.batch.BatchProcessor;
|
||||
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||
import org.alfresco.repo.model.filefolder.HiddenAspect;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
|
||||
@@ -112,6 +113,7 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
||||
private SiteService siteService;
|
||||
private AVMService avmService;
|
||||
private RuleService ruleService;
|
||||
private HiddenAspect hiddenAspect;
|
||||
private String avmStore;
|
||||
private String avmRootPath = "/";
|
||||
|
||||
@@ -175,6 +177,11 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
||||
}
|
||||
}
|
||||
|
||||
public void setHiddenAspect(HiddenAspect hiddenAspect)
|
||||
{
|
||||
this.hiddenAspect = hiddenAspect;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkProperties()
|
||||
{
|
||||
@@ -624,9 +631,9 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
||||
ChildAssociationRef ref = this.nodeService.createNode(
|
||||
rootRef, ContentModel.ASSOC_CONTAINS, assocQName, ContentModel.TYPE_FOLDER, properties);
|
||||
surfConfigRef = ref.getChildRef();
|
||||
Map<QName, Serializable> aspectProperties = new HashMap<QName, Serializable>(1, 1.0f);
|
||||
aspectProperties.put(ContentModel.PROP_IS_INDEXED, false);
|
||||
this.nodeService.addAspect(surfConfigRef, ContentModel.ASPECT_INDEX_CONTROL, aspectProperties);
|
||||
|
||||
// surf-config needs to be hidden
|
||||
hiddenAspect.hideNode(ref.getChildRef());
|
||||
}
|
||||
catch (DuplicateChildNodeNameException dupErr)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@ import java.util.Set;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.importer.view.NodeContext;
|
||||
import org.alfresco.repo.model.filefolder.HiddenAspect;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationContext;
|
||||
import org.alfresco.repo.version.Version2Model;
|
||||
@@ -108,6 +109,7 @@ public class ImporterComponent
|
||||
private AuthenticationContext authenticationContext;
|
||||
private OwnableService ownableService;
|
||||
private VersionService versionService;
|
||||
private HiddenAspect hiddenAspect;
|
||||
|
||||
/**
|
||||
* The db node service, used when updating the version store.
|
||||
@@ -236,6 +238,11 @@ public class ImporterComponent
|
||||
this.dbNodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setHiddenAspect(HiddenAspect hiddenAspect)
|
||||
{
|
||||
this.hiddenAspect = hiddenAspect;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.view.ImporterService#importView(java.io.InputStreamReader, org.alfresco.service.cmr.view.Location, java.util.Properties, org.alfresco.service.cmr.view.ImporterProgress)
|
||||
*/
|
||||
@@ -611,6 +618,9 @@ public class ImporterComponent
|
||||
}
|
||||
}
|
||||
|
||||
// check whether the node should be hidden
|
||||
hiddenAspect.checkHidden(nodeRef);
|
||||
|
||||
// import content, if applicable
|
||||
for (Map.Entry<QName,Serializable> property : context.getProperties().entrySet())
|
||||
{
|
||||
|
@@ -92,6 +92,8 @@ import org.alfresco.service.namespace.NamespacePrefixResolverProvider;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.FileFilterMode;
|
||||
import org.alfresco.util.FileFilterMode.Client;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.ISO9075;
|
||||
import org.alfresco.util.Pair;
|
||||
@@ -649,10 +651,18 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
PagingRequest pageRequest = new PagingRequest(skipOffset, maxItems, queryExecutionId);
|
||||
pageRequest.setRequestTotalCountMax(requestTotalCountMax);
|
||||
|
||||
PagingResults<FileInfo> pageOfNodeInfos = this.fileFolderService.list(this.nodeRef, files, folders, null, ignoreTypeQNames, sortProps, pageRequest);
|
||||
|
||||
PagingResults<FileInfo> pageOfNodeInfos = null;
|
||||
FileFilterMode.setClient(Client.script);
|
||||
try
|
||||
{
|
||||
pageOfNodeInfos = this.fileFolderService.list(this.nodeRef, files, folders, null, ignoreTypeQNames, sortProps, pageRequest);
|
||||
}
|
||||
finally
|
||||
{
|
||||
FileFilterMode.clearClient();
|
||||
}
|
||||
|
||||
List<FileInfo> nodeInfos = pageOfNodeInfos.getPage();
|
||||
|
||||
int size = nodeInfos.size();
|
||||
results = new Object[size];
|
||||
for (int i=0; i<size; i++)
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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()
|
||||
|
@@ -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()
|
||||
|
@@ -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
|
||||
{
|
||||
|
454
source/java/org/alfresco/repo/model/filefolder/HiddenAspect.java
Normal file
454
source/java/org/alfresco/repo/model/filefolder/HiddenAspect.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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 = "";
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
@@ -396,12 +396,4 @@ public interface FileFolderService
|
||||
*/
|
||||
@Auditable(parameters = {"typeQName"})
|
||||
public FileFolderServiceType getType(QName typeQName);
|
||||
|
||||
/**
|
||||
* Removes any hidden files from the file list.
|
||||
*
|
||||
* @param files
|
||||
* @return a list of files with hidden files removed
|
||||
*/
|
||||
public List<FileInfo> removeHiddenFiles(List<FileInfo> files);
|
||||
}
|
||||
|
Reference in New Issue
Block a user