ALF-10967 Webdav content link is not usable in IMAP

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31577 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Mark Rogers
2011-10-31 17:37:06 +00:00
parent b0c0f9f15f
commit 338bd282d6
10 changed files with 504 additions and 60 deletions

View File

@@ -43,5 +43,6 @@
<import resource="classpath:alfresco/activities/activities-feed-context.xml" />
<import resource="classpath:alfresco/tagging-services-context.xml"/>
<import resource="classpath:alfresco/invitation-service-context.xml"/>
<import resource="classpath:alfresco/webdav-context.xml"/>
<import resource="classpath*:alfresco/patch/*-context.xml" />
</beans>

View File

@@ -0,0 +1,28 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="webdavRootNode" class="org.alfresco.repo.webdav.MTNodesCache2"
init-method="init">
<property name="nodeService" ref="NodeService" />
<property name="searchService" ref="SearchService" />
<property name="tenantService" ref="tenantService" />
<property name="namespaceService" ref="NamespaceService" />
<property name="storeName"><value>${system.webdav.storeName}</value></property>
<property name="rootPath"><value>${system.webdav.rootPath}</value></property>
<property name="enabled" ><value>${system.webdav.servlet.enabled}</value></property>
</bean>
<!-- WebDav Client -->
<bean id="webdavService" class="org.alfresco.repo.webdav.WebDavServiceImpl"
init-method="init">
<property name="dictionaryService" ref="dictionaryService" />
<property name="nodeService" ref="NodeService" />
<property name="fileFolderService" ref="FileFolderService" />
<property name="rootNode" ref="webdavRootNode" />
<property name="enabled" ><value>${system.webdav.servlet.enabled}</value></property>
</bean>
</beans>

View File

@@ -26,31 +26,18 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.nio.channels.Channels;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.alfresco.AlfrescoClientInfo;
import org.alfresco.filesys.alfresco.AlfrescoContext;
import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
import org.alfresco.filesys.alfresco.AlfrescoNetworkFile;
import org.alfresco.filesys.alfresco.DesktopAction;
import org.alfresco.filesys.alfresco.DesktopActionTable;
import org.alfresco.filesys.alfresco.DesktopParams;
import org.alfresco.filesys.alfresco.DesktopResponse;
import org.alfresco.filesys.alfresco.DesktopTarget;
import org.alfresco.filesys.alfresco.ExtendedDiskInterface;
import org.alfresco.filesys.alfresco.IOControl;
import org.alfresco.filesys.alfresco.IOControlHandler;
import org.alfresco.filesys.alfresco.PseudoFileOverlayImpl;
import org.alfresco.filesys.alfresco.RepositoryDiskInterface;
import org.alfresco.filesys.alfresco.ShuffleCache;
import org.alfresco.filesys.config.ServerConfigurationBean;
import org.alfresco.jlan.server.SrvSession;
import org.alfresco.jlan.server.core.DeviceContext;
import org.alfresco.jlan.server.core.DeviceContextException;
@@ -73,10 +60,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.cache.FileStateLockManager;
import org.alfresco.jlan.server.filesys.pseudo.MemoryPseudoFile;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFile;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFileInterface;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
import org.alfresco.jlan.server.filesys.pseudo.PseudoNetworkFile;
import org.alfresco.jlan.server.filesys.quota.QuotaManager;
@@ -87,29 +71,19 @@ import org.alfresco.jlan.server.locking.OpLockInterface;
import org.alfresco.jlan.server.locking.OpLockManager;
import org.alfresco.jlan.smb.SMBException;
import org.alfresco.jlan.smb.SMBStatus;
import org.alfresco.jlan.smb.nt.NTIOCtl;
import org.alfresco.jlan.smb.server.SMBServer;
import org.alfresco.jlan.smb.server.SMBSrvSession;
import org.alfresco.jlan.smb.server.disk.JavaNetworkFile;
import org.alfresco.jlan.server.filesys.FileAttribute;
import org.alfresco.jlan.util.DataBuffer;
import org.alfresco.jlan.util.MemorySize;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.SysAdminParams;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.lock.NodeLockedException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentData;
@@ -125,7 +99,6 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -133,7 +106,6 @@ import org.alfresco.util.PropertyCheck;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.james.mime4j.storage.TempFileStorageProvider;
import org.springframework.extensions.config.ConfigElement;
/**
@@ -762,19 +734,20 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
try
{
String searchFileSpec = searchPath;
NodeRef searchRootNodeRef = ctx.getRootNode();
String[] paths = FileName.splitPath(searchPath);
String dotPath = paths[0];
// lookup parent directory
NodeRef dirNodeRef = getNodeForPath(tree, paths[0]);
NodeRef dirNodeRef = getNodeForPath(tree, dotPath);
if(dirNodeRef != null)
{
searchRootNodeRef = dirNodeRef;
searchFileSpec = paths[1];
}
// Convert the all files wildcard
if ( searchFileSpec.equals( "*.*"))
{
@@ -815,10 +788,31 @@ public class ContentDiskDriver2 extends AlfrescoDiskDriver implements ExtendedD
}
DotDotContentSearchContext searchCtx = new DotDotContentSearchContext(getCifsHelper(), results, searchFileSpec, pseudoList, paths[0]);
FileInfo dotInfo = getCifsHelper().getFileInformation(searchRootNodeRef, false, isLockedFilesAsOffline);
// Need to set dot and dotdot
//searchCtx.setDotInfo(finfo);
//searchCtx.setDotDotInfo(finfo);
if ( searchPath.equals( FileName.DOS_SEPERATOR_STR)) {
// Searching the root folder, re-use the search folder file information for the '..' pseudo entry
FileInfo dotDotInfo = new FileInfo();
dotDotInfo.copyFrom(dotInfo);
searchCtx.setDotInfo(dotInfo);
searchCtx.setDotDotInfo( dotDotInfo);
}
else
{
String[] parent = FileName.splitPath(dotPath);
NodeRef parentNodeRef = getNodeForPath(tree, parent[0]);
if(parentNodeRef != null)
{
FileInfo dotDotInfo = getCifsHelper().getFileInformation(parentNodeRef, false, isLockedFilesAsOffline);
searchCtx.setDotDotInfo(dotDotInfo);
}
// Searching a normal, non root, folder
// Need to set dot and dotdot
searchCtx.setDotInfo(dotInfo);
}
// Debug
if (logger.isDebugEnabled())

View File

@@ -76,6 +76,7 @@ import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.cmr.view.ExporterService;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.webdav.WebDavService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
@@ -548,4 +549,12 @@ public class MockedTestServiceRegistry implements ServiceRegistry
// TODO Auto-generated method stub
return null;
}
@Override
public WebDavService getWebDavService()
{
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -74,6 +74,7 @@ import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.cmr.view.ExporterService;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.webdav.WebDavService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
@@ -637,4 +638,10 @@ public class ServiceDescriptorRegistry
final String beanName = "sysAdminParams";
return (SysAdminParams) beanFactory.getBean(beanName);
}
@Override
public WebDavService getWebDavService()
{
return (WebDavService)getService(WEBDAV_SERVICE);
}
}

View File

@@ -39,6 +39,7 @@ import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.FileTypeImageSize;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.webdav.WebDavService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ISO9075;
@@ -422,31 +423,8 @@ public abstract class BaseContentNode implements TemplateContent
*/
public String getWebdavUrl()
{
try
{
if (getIsContainer() || getIsDocument())
{
List<FileInfo> paths = this.services.getFileFolderService().getNamePath(null, getNodeRef());
// build up the webdav url
StringBuilder path = new StringBuilder(128);
path.append("/webdav");
// build up the path skipping the first path as it is the root folder
for (int i=1; i<paths.size(); i++)
{
path.append("/")
.append(URLEncoder.encode(paths.get(i).getName()));
}
return path.toString();
}
}
catch (FileNotFoundException nodeErr)
{
// cannot build path if file no longer exists
return "";
}
return "";
WebDavService webDavService = this.services.getWebDavService();
return webDavService.getWebdavUrl(getNodeRef());
}
/**

View File

@@ -0,0 +1,211 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.webdav;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.util.PropertyCheck;
/**
* In-memory cache that stores nodeRefs per tenant.
* It is initialized using path to node and allows to retrieve nodeRef for current tenant.
*
* @author Stas Sokolovsky
* @author Mark Rogers
*/
public class MTNodesCache2
{
private boolean enabled = false;
private NodeService nodeService;
private SearchService searchService;
private NamespaceService namespaceService;
private TenantService tenantService;
private Map<String, NodeRef> nodesCache = new ConcurrentHashMap<String, NodeRef>();
private NodeRef defaultNode = null;
private String storeName;
private String rootPath;
public void init()
{
PropertyCheck.mandatory(this, "nodeService", getNodeService());
PropertyCheck.mandatory(this, "searchService", getSearchService());
PropertyCheck.mandatory(this, "namespaceService", getNamespaceService());
PropertyCheck.mandatory(this, "tenantService", getTenantService());
if(!enabled)
{
return;
}
PropertyCheck.mandatory(this, "storeName", storeName);
PropertyCheck.mandatory(this, "rootPath", rootPath);
AuthenticationUtil.setRunAsUserSystem();
try
{
StoreRef storeRef = new StoreRef(storeName);
if (nodeService.exists(storeRef) == false)
{
throw new RuntimeException("No store for path: " + storeName);
}
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
List<NodeRef> nodeRefs = getSearchService().selectNodes(storeRootNodeRef, rootPath, null, getNamespaceService(), false);
if (nodeRefs.size() > 1)
{
throw new RuntimeException("Multiple possible children for : \n" + " path: " + rootPath + "\n" + " results: " + nodeRefs);
}
else if (nodeRefs.size() == 0)
{
throw new RuntimeException("Node is not found for : \n" + " root path: " + rootPath);
}
defaultNode = nodeRefs.get(0);
}
finally
{
AuthenticationUtil.clearCurrentSecurityContext();
}
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public NodeService getNodeService()
{
return nodeService;
}
/**
* Returns nodeRef for current user tenant
*
* @return nodeRef Node Reference
*/
public NodeRef getNodeForCurrentTenant()
{
NodeRef result = null;
if (!getTenantService().isEnabled())
{
result = defaultNode;
}
else
{
String domain = getTenantService().getCurrentUserDomain();
if (nodesCache.containsKey(domain))
{
result = nodesCache.get(domain);
}
else
{
result = getTenantService().getRootNode(nodeService, getSearchService(), getNamespaceService(), rootPath, defaultNode);
nodesCache.put(domain, result);
}
}
return result;
}
/**
* @return Returns the name of the store
* @throws ServletException if the store name was not set
*/
public String getStoreName()
{
return storeName;
}
public void setStoreName(String storeName)
{
this.storeName = storeName;
}
/**
* @return Returns the WebDAV root path within the store
* @throws ServletException if the root path was not set
*/
public String getRootPath()
{
return rootPath;
}
public void setRootPath(String rootPath)
{
this.rootPath = rootPath;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public SearchService getSearchService()
{
return searchService;
}
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
public NamespaceService getNamespaceService()
{
return namespaceService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public TenantService getTenantService()
{
return tenantService;
}
public boolean getEnabled()
{
return enabled;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
}

View File

@@ -0,0 +1,174 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.webdav;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.webdav.WebDavService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.URLEncoder;
/**
* The WebDav client is used by the repository to generate webdav URLs
*
* This is a bog standard spring bean for the repo side of WebDav.
*
* @See org.alfresco.repo.webdav.WebDavServlet the server side of webdav.
*
* @author mrogers
*/
public class WebDavServiceImpl implements WebDavService
{
private boolean enabled = false;
private NodeService nodeService;
private DictionaryService dictionaryService;
private FileFolderService fileFolderService;
private static Log logger = LogFactory.getLog(WebDavServiceImpl.class);
// Root nodes
private MTNodesCache2 rootNode;
public static final String WEBDAV_PREFIX = "webdav";
public boolean getEnabled()
{
return enabled;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
public void init()
{
PropertyCheck.mandatory(this, "nodeService", getNodeService());
PropertyCheck.mandatory(this, "dictionaryService", getDictionaryService());
PropertyCheck.mandatory(this, "fileFolderService", getFileFolderService());
PropertyCheck.mandatory(this, "rootNode", getRootNode());
}
/**
* Get the WebDavUrl for the specified nodeRef
*
* @param nodeRef the node that the webdav URL (or null)
* @return the URL of the node in webdav or "" if a URL cannot be built.
*/
public String getWebdavUrl(NodeRef nodeRef)
{
if(!enabled)
{
return "";
}
try
{
QName typeName = nodeService.getType(nodeRef);
if (getIsContainer(typeName) || getIsDocument(typeName))
{
List<FileInfo> paths = fileFolderService.getNamePath(getRootNode().getNodeForCurrentTenant(), nodeRef);
// build up the webdav url
StringBuilder path = new StringBuilder(128);
path.append("/" + WEBDAV_PREFIX);
// build up the path skipping the first path as it is the root folder
for (int i=1; i<paths.size(); i++)
{
path.append("/")
.append(URLEncoder.encode(paths.get(i).getName()));
}
return path.toString();
}
}
catch (FileNotFoundException nodeErr)
{
// cannot build path if file no longer exists
return "";
}
return "";
}
/**
* @return true if this Node is a container (i.e. a folder)
*/
private boolean getIsContainer(QName type)
{
boolean isContainer =
dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) &&
!dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER);
return isContainer;
}
/**
* @return true if this Node is a Document (i.e. with content)
*/
private boolean getIsDocument(QName type)
{
boolean isDocument = dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT);
return isDocument;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public NodeService getNodeService()
{
return nodeService;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
public DictionaryService getDictionaryService()
{
return dictionaryService;
}
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
public FileFolderService getFileFolderService()
{
return fileFolderService;
}
public void setRootNode(MTNodesCache2 rootNode)
{
this.rootNode = rootNode;
}
public MTNodesCache2 getRootNode()
{
return rootNode;
}
}

View File

@@ -73,6 +73,7 @@ import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.cmr.view.ExporterService;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.webdav.WebDavService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
@@ -166,7 +167,7 @@ public interface ServiceRegistry
static final QName PUBLIC_SERVICE_ACCESS_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "PublicServiceAccessService");
static final QName WEBDAV_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "webdavService");
/**
* Get the list of services provided by the Repository
@@ -602,4 +603,13 @@ public interface ServiceRegistry
*/
@NotAuditable
SysAdminParams getSysAdminParams();
/**
* Get the webdav service / helper bean.
* @return the webdav service / helper bean
*/
@NotAuditable
WebDavService getWebDavService();
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.service.cmr.webdav;
import org.alfresco.service.cmr.repository.NodeRef;
public interface WebDavService
{
/**
* Get the WebDavUrl for the specified nodeRef
* @param nodeRef the node that the webdav URL (or null)
* @return the URL of the node in webdav or "" if a URL cannot be built.
*/
public String getWebdavUrl(NodeRef nodeRef);
}