diff --git a/config/alfresco/application-context-core.xml b/config/alfresco/application-context-core.xml index 329f0c2fab..5e9b9851a9 100644 --- a/config/alfresco/application-context-core.xml +++ b/config/alfresco/application-context-core.xml @@ -43,5 +43,6 @@ + diff --git a/config/alfresco/webdav-context.xml b/config/alfresco/webdav-context.xml new file mode 100644 index 0000000000..25d83083be --- /dev/null +++ b/config/alfresco/webdav-context.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + ${system.webdav.storeName} + ${system.webdav.rootPath} + ${system.webdav.servlet.enabled} + + + + + + + + + ${system.webdav.servlet.enabled} + + + + \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java index 5494c84d10..2529adcb21 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver2.java @@ -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()) diff --git a/source/java/org/alfresco/repo/rendition/MockedTestServiceRegistry.java b/source/java/org/alfresco/repo/rendition/MockedTestServiceRegistry.java index 59f6a47a4c..cd3b3862a4 100644 --- a/source/java/org/alfresco/repo/rendition/MockedTestServiceRegistry.java +++ b/source/java/org/alfresco/repo/rendition/MockedTestServiceRegistry.java @@ -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; + } } diff --git a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java index d30dd28440..9fd2c76d31 100644 --- a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java +++ b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java @@ -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); + } } diff --git a/source/java/org/alfresco/repo/template/BaseContentNode.java b/source/java/org/alfresco/repo/template/BaseContentNode.java index 1d1fa30936..baf660b8f4 100644 --- a/source/java/org/alfresco/repo/template/BaseContentNode.java +++ b/source/java/org/alfresco/repo/template/BaseContentNode.java @@ -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 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. + */ +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 nodesCache = new ConcurrentHashMap(); + + 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 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; + } + + + +} diff --git a/source/java/org/alfresco/repo/webdav/WebDavServiceImpl.java b/source/java/org/alfresco/repo/webdav/WebDavServiceImpl.java new file mode 100644 index 0000000000..abcd090dfc --- /dev/null +++ b/source/java/org/alfresco/repo/webdav/WebDavServiceImpl.java @@ -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 . + */ +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 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. + */ +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); + +}