Java tutorial
/* * Copyright (C) 2005-2013 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 jp.aegif.alfresco.online_webdav; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.NetworkInterface; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.alfresco.jlan.util.IPAddress; import org.alfresco.model.ContentModel; import org.alfresco.repo.lock.LockUtils; import org.alfresco.repo.model.filefolder.HiddenAspect; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.webdav.WebDAV; import org.alfresco.repo.webdav.WebDAVLockService; import org.alfresco.repo.webdav.WebDAVServerException; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.lock.LockService; 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.CopyService; import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.util.EqualsHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.surf.util.URLDecoder; import org.springframework.extensions.surf.util.URLEncoder; import org.springframework.util.StringUtils; import org.xml.sax.helpers.AttributesImpl; /** * WebDAV Protocol Helper Class * * <p>Provides helper methods for repository access using the WebDAV protocol. * * @author GKSpencer */ public class WebDAVHelper { // Constants public static final String BEAN_NAME = "webDAVHelper"; private static final String HTTPS_SCHEME = "https://"; private static final String HTTP_SCHEME = "http://"; // Path seperator public static final String PathSeperator = "/"; public static final char PathSeperatorChar = '/'; public static final String EMPTY_SITE_ID = ""; // Logging protected static Log logger = LogFactory.getLog("org.alfresco.webdav.protocol"); // Service registry TODO: eliminate this - not dependency injection! private ServiceRegistry m_serviceRegistry; // Services private NodeService m_nodeService; private FileFolderService m_fileFolderService; private SearchService m_searchService; private NamespaceService m_namespaceService; private DictionaryService m_dictionaryService; private MimetypeService m_mimetypeService; private WebDAVLockService m_lockService; private ActionService m_actionService; private AuthenticationService m_authService; private PermissionService m_permissionService; private TenantService m_tenantService; private HiddenAspect m_hiddenAspect; // pattern is tested against full path after it has been lower cased. private Pattern m_renameShufflePattern = Pattern.compile( "(.*/\\..*)|(.*[a-f0-9]{8}+$)|(.*\\.tmp$)|(.*\\.wbk$)|(.*\\.bak$)|(.*\\~$)|(.*backup.*\\.do[ct]{1}[x]?[m]?$)"); // Empty XML attribute list private final AttributesImpl m_nullAttribs = new AttributesImpl(); private BehaviourFilter m_policyBehaviourFilter; private String m_urlPathPrefix; /** * Set the regular expression that will be applied to filenames during renames * to detect whether clients are performing a renaming shuffle - common during * file saving on various clients. * <p/> * <bALF-3856, ALF-7079, MNT-181</b> * * @param renameShufflePattern a regular expression filename match */ public void setRenameShufflePattern(Pattern renameShufflePattern) { this.m_renameShufflePattern = renameShufflePattern; } /** * @return Return the authentication service */ public final AuthenticationService getAuthenticationService() { return m_authService; } /** * @return Return the service registry */ public final ServiceRegistry getServiceRegistry() { // TODO: eliminate this - not dependency injection! return m_serviceRegistry; } /** * @return Return the node service */ public final NodeService getNodeService() { return m_nodeService; } public FileFolderService getFileFolderService() { return m_fileFolderService; } /** * @return Return the search service */ public final SearchService getSearchService() { return m_searchService; } /** * @return Return the namespace service */ public final NamespaceService getNamespaceService() { return m_namespaceService; } /** * @return Return the dictionary service */ public final DictionaryService getDictionaryService() { return m_dictionaryService; } /** * @return Return the mimetype service */ public final MimetypeService getMimetypeService() { return m_mimetypeService; } /** * @return Return the lock service */ public WebDAVLockService getLockService() { return m_lockService; } /** * @return Return the action service */ public final ActionService getActionService() { return m_actionService; } /** * * @return Return the permission service */ public final PermissionService getPermissionService() { return m_permissionService; } /** * @return the hidden aspect bean */ public final HiddenAspect getHiddenAspect() { return m_hiddenAspect; } /** * Retrieve the {@link TenantService} held by the helper. * * @return TenantService */ public TenantService getTenantService() { return m_tenantService; } /** * @return Return the copy service */ public final CopyService getCopyService() { return getServiceRegistry().getCopyService(); } public void setTenantService(TenantService tenantService) { this.m_tenantService = tenantService; } /** * @param serviceRegistry the service registry */ public void setServiceRegistry(ServiceRegistry serviceRegistry) { this.m_serviceRegistry = serviceRegistry; } /** * @param nodeService the node service */ public void setNodeService(NodeService nodeService) { this.m_nodeService = nodeService; } /** * @param fileFolderService the fileFolder service */ public void setFileFolderService(FileFolderService fileFolderService) { this.m_fileFolderService = fileFolderService; } /** * @param searchService the search service */ public void setSearchService(SearchService searchService) { this.m_searchService = searchService; } /** * @param namespaceService the namespace service */ public void setNamespaceService(NamespaceService namespaceService) { this.m_namespaceService = namespaceService; } /** * @param dictionaryService the dictionary service */ public void setDictionaryService(DictionaryService dictionaryService) { this.m_dictionaryService = dictionaryService; } /** * @param mimetypeService the mimetype service */ public void setMimetypeService(MimetypeService mimetypeService) { this.m_mimetypeService = mimetypeService; } /** * @param lockService the lock service */ public void setLockService(WebDAVLockService lockService) { this.m_lockService = lockService; } /** * @param actionService the action service */ public void setActionService(ActionService actionService) { this.m_actionService = actionService; } /** * @param authService the authentication service */ public void setAuthenticationService(AuthenticationService authService) { this.m_authService = authService; } /** * @param permissionService the permission service */ public void setPermissionService(PermissionService permissionService) { this.m_permissionService = permissionService; } /** * @param hiddenAspect the hiddenAspect to set */ public void setHiddenAspect(HiddenAspect hiddenAspect) { this.m_hiddenAspect = hiddenAspect; } public BehaviourFilter getPolicyBehaviourFilter() { return m_policyBehaviourFilter; } public void setPolicyBehaviourFilter(BehaviourFilter behaviourFilter) { m_policyBehaviourFilter = behaviourFilter; } /** * Checks a new path in a move operation to detect whether clients are starting a renaming shuffle - common during * file saving on various clients. * <p/> * <b>ALF-3856, ALF-7079, MNT-181</b> */ public boolean isRenameShuffle(String newPath) { return m_renameShufflePattern.matcher(newPath.toLowerCase()).matches(); } /** * Split the path into seperate directory path and file name strings. * If the path is not empty, then there will always be an entry for the filename * * @param path Full path string. * @return Returns a String[2] with the folder path and file path. */ public final String[] splitPath(String path) { if (path == null) throw new IllegalArgumentException("path may not be null"); // Create an array of strings to hold the path and file name strings String[] pathStr = new String[] { "", "" }; // Check if the path has a trailing seperator, if so then there is no file name. int pos = path.lastIndexOf(PathSeperatorChar); if (pos == -1 || pos == (path.length() - 1)) { // Set the path string in the returned string array pathStr[1] = path; } else { pathStr[0] = path.substring(0, pos); pathStr[1] = path.substring(pos + 1); } // Return the path strings return pathStr; } /** * Split the path into all the component directories and filename * * @param path the string to split * @return an array of all the path components */ public List<String> splitAllPaths(String path) { if (path == null || path.length() == 0) { return Collections.emptyList(); } // split the path StringTokenizer token = new StringTokenizer(path, PathSeperator); List<String> results = new ArrayList<String>(10); while (token.hasMoreTokens()) { results.add(token.nextToken()); } return results; } public String getURLForPath(HttpServletRequest request, String path, boolean isCollection) { return getURLForPath(request, path, isCollection, null); } public String getURLForPath(HttpServletRequest request, String path, boolean isCollection, String userAgent) { String urlPathPrefix = getUrlPathPrefix(request); StringBuilder urlStr = new StringBuilder(urlPathPrefix); if (path.equals(WebDAV.RootPath) == false) { // split the path and URL encode each path element for (StringTokenizer t = new StringTokenizer(path, PathSeperator); t.hasMoreTokens(); /**/) { urlStr.append(WebDAVHelper.encodeURL(t.nextToken(), userAgent)); if (t.hasMoreTokens()) { urlStr.append(PathSeperator); } } } // If the URL is to a collection add a trailing slash if (isCollection && urlStr.charAt(urlStr.length() - 1) != PathSeperatorChar) { urlStr.append(PathSeperator); } logger.debug("getURLForPath() path:" + path + " => url:" + urlStr); // Return the URL string return urlStr.toString(); } /** * Get the file info for the given paths * * @param rootNodeRef the acting webdav root * @param path the path to search for * @return Return the file info for the path * @throws FileNotFoundException * if the path doesn't refer to a valid node */ public FileInfo getNodeForPath(NodeRef rootNodeRef, String path) throws FileNotFoundException { if (rootNodeRef == null) { throw new IllegalArgumentException("Root node may not be null"); } else if (path == null) { throw new IllegalArgumentException("Path may not be null"); } FileFolderService fileFolderService = getFileFolderService(); // Check for the root path if (path.length() == 0 || path.equals(PathSeperator)) { return fileFolderService.getFileInfo(rootNodeRef); } // split the paths up List<String> splitPath = splitAllPaths(path); // find it FileInfo fileInfo = m_fileFolderService.resolveNamePath(rootNodeRef, splitPath); // done if (logger.isDebugEnabled()) { logger.debug("Fetched node for path: \n" + " root: " + rootNodeRef + "\n" + " path: " + path + "\n" + " result: " + fileInfo); } return fileInfo; } public boolean isRootPath(String path, String servletPath) { // Check for the root path return (path.length() == 0 || path.equals(PathSeperator) || EqualsHelper.nullSafeEquals(path, servletPath)); } public final FileInfo getParentNodeForPath(NodeRef rootNodeRef, String path) throws FileNotFoundException { if (rootNodeRef == null) { throw new IllegalArgumentException("Root node may not be null"); } else if (path == null) { throw new IllegalArgumentException("Path may not be null"); } // shorten the path String[] paths = splitPath(path); return getNodeForPath(rootNodeRef, paths[0]); } /** * Return the relative path for the node walking back to the specified root node * * @param rootNodeRef the root below which the path will be valid * @param nodeRef the node's path to get * @return Returns string of form <b>/A/B/C</b> where C represents the from node and */ public final String getPathFromNode(NodeRef rootNodeRef, NodeRef nodeRef) throws FileNotFoundException { // Check if the nodes are valid, or equal if (rootNodeRef == null || nodeRef == null) throw new IllegalArgumentException("Invalid node(s) in getPathFromNode call"); // short cut if the path node is the root node if (rootNodeRef.equals(nodeRef)) return ""; FileFolderService fileFolderService = getFileFolderService(); // get the path elements List<String> pathInfos = fileFolderService.getNameOnlyPath(rootNodeRef, nodeRef); // build the path string StringBuilder sb = new StringBuilder(pathInfos.size() * 20); for (String fileInfo : pathInfos) { sb.append(WebDAVHelper.PathSeperatorChar); sb.append(fileInfo); } // done if (logger.isDebugEnabled()) { logger.debug("Build name path for node: \n" + " root: " + rootNodeRef + "\n" + " target: " + nodeRef + "\n" + " path: " + sb); } return sb.toString(); } public FileInfo createFile(FileInfo parentNodeInfo, String path) throws WebDAVServerException { return m_fileFolderService.create(parentNodeInfo.getNodeRef(), path, ContentModel.TYPE_CONTENT); } public List<FileInfo> getChildren(FileInfo fileInfo) throws WebDAVServerException { return m_fileFolderService.list(fileInfo.getNodeRef()); } /** * Make an ETag value for a node using the GUID and modify date/time */ public final String makeETag(FileInfo nodeInfo) { // Get the modify date/time property for the node StringBuilder etag = new StringBuilder(); makeETagString(nodeInfo, etag); return etag.toString(); } /** * Make an ETag value for a node using the GUID and modify date/time */ public final String makeQuotedETag(FileInfo nodeInfo) { StringBuilder etag = new StringBuilder(); etag.append("\""); makeETagString(nodeInfo, etag); etag.append("\""); return etag.toString(); } /** * Make an ETag value for a node using the GUID and modify date/time */ protected final void makeETagString(FileInfo nodeInfo, StringBuilder etag) { // Get the modify date/time property for the node Object modVal = nodeInfo.getProperties().get(ContentModel.PROP_MODIFIED); etag.append(nodeInfo.getNodeRef().getId()); if (modVal != null) { etag.append("_"); etag.append(DefaultTypeConverter.INSTANCE.longValue(modVal)); } } /** * @return Return the null XML attribute list */ public final AttributesImpl getNullAttributes() { return m_nullAttribs; } /** * Encodes the given string to valid URL format * * @param s the String to convert */ public final static String encodeURL(String s) { return encodeURL(s, null); } public final static String encodeURL(String s, String userAgent) { return URLEncoder.encode(s); } public final static String decodeURL(String s) { return URLDecoder.decode(s); } /** * Encodes the given string to valid HTML format * * @param string the String to convert */ public final static String encodeHTML(String string) { if (string == null) { return ""; } StringBuilder sb = null; //create on demand String enc; char c; for (int i = 0; i < string.length(); i++) { enc = null; c = string.charAt(i); switch (c) { case '"': enc = """; break; //" case '&': enc = "&"; break; //& case '<': enc = "<"; break; //< case '>': enc = ">"; break; //> //misc case '\u20AC': enc = "€"; break; case '\u00AB': enc = "«"; break; case '\u00BB': enc = "»"; break; case '\u00A0': enc = " "; break; default: if (((int) c) >= 0x80) { //encode all non basic latin characters enc = "&#" + ((int) c) + ";"; } break; } if (enc != null) { if (sb == null) { String soFar = string.substring(0, i); sb = new StringBuilder(i + 8); sb.append(soFar); } sb.append(enc); } else { if (sb != null) { sb.append(c); } } } if (sb == null) { return string; } else { return sb.toString(); } } /** * ALF-5333: Microsoft clients use ISO-8859-1 to decode WebDAV responses * so this method should only be used for Microsoft user agents. * * @param string * @return The encoded string for Microsoft clients * @throws UnsupportedEncodingException */ public final static String encodeUrlReservedSymbols(String string) throws UnsupportedEncodingException { if (string == null) { return ""; } StringBuilder sb = null; // create on demand String enc; char c; for (int i = 0; i < string.length(); i++) { enc = null; c = string.charAt(i); switch (c) { // reserved case ';': enc = URLEncoder.encode(String.valueOf(c)); break; case '/': enc = URLEncoder.encode(String.valueOf(c)); break; case '?': enc = URLEncoder.encode(String.valueOf(c)); break; case ':': enc = URLEncoder.encode(String.valueOf(c)); break; case '@': enc = URLEncoder.encode(String.valueOf(c)); break; case '&': enc = URLEncoder.encode(String.valueOf(c)); break; case '=': enc = URLEncoder.encode(String.valueOf(c)); break; case '+': enc = URLEncoder.encode(String.valueOf(c)); break; // unsafe case '\"': enc = URLEncoder.encode(String.valueOf(c)); break; case '#': enc = URLEncoder.encode(String.valueOf(c)); break; case '%': enc = URLEncoder.encode(String.valueOf(c)); break; case '>': enc = URLEncoder.encode(String.valueOf(c)); break; case '<': enc = URLEncoder.encode(String.valueOf(c)); break; default: break; } if (enc != null) { if (sb == null) { String soFar = string.substring(0, i); sb = new StringBuilder(i + 8); sb.append(soFar); } sb.append(enc); } else { if (sb != null) { sb.append(c); } } } if (sb == null) { return string; } else { return sb.toString(); } } public String determineSiteId(WebDAVMethod method) { SiteService siteService = getServiceRegistry().getSiteService(); String siteId; try { FileInfo fileInfo = getNodeForPath(method.getRootNodeRef(), method.getPath()); siteId = siteService.getSiteShortName(fileInfo.getNodeRef()); if (siteId == null) { throw new RuntimeException("Node is not contained by a site: " + method.getPath()); } } catch (Exception error) { siteId = EMPTY_SITE_ID; } return siteId; } public String determineTenantDomain(WebDAVMethod method) { TenantService tenantService = getTenantService(); String tenantDomain = tenantService.getCurrentUserDomain(); if (tenantDomain == null) { return TenantService.DEFAULT_DOMAIN; } return tenantDomain; } /** * Extract the destination path for MOVE or COPY commands from the * supplied destination URL header. * * @param servletPath Path prefix of the WebDAV servlet. * @param destURL The Destination header. * @return The path to move/copy the file to. */ public String getDestinationPath(String contextPath, String servletPath, String destURL) { if (destURL != null && destURL.length() > 0) { int offset = -1; if (destURL.startsWith(HTTP_SCHEME)) { // Set the offset to the start of the host name offset = HTTP_SCHEME.length(); } else if (destURL.startsWith(HTTPS_SCHEME)) { // Set the offset to the start of the host name offset = HTTPS_SCHEME.length(); } // Strip the start of the path if not a relative path if (offset != -1) { offset = destURL.indexOf(WebDAV.PathSeperator, offset); if (offset != -1) { // Strip the host from the beginning String strPath = destURL.substring(offset); // If it starts with /contextPath/servletPath/ (e.g. /alfresco/webdav/path/to/file) - then // strip the servlet path from the start of the path. String pathPrefix = contextPath + servletPath + WebDAV.PathSeperator; if (strPath.startsWith(pathPrefix)) { strPath = strPath.substring(pathPrefix.length()); } return WebDAV.decodeURL(strPath); } } } // Unable to get the path. return null; } /** * Check that the destination path is on this server and is a valid WebDAV * path for this server * * @param request The request made against the WebDAV server. * @param urlStr String * @exception WebDAVServerException */ public void checkDestinationURL(HttpServletRequest request, String urlStr) throws WebDAVServerException { try { // Parse the URL URL url = new URL(urlStr); // Check if the path is on this WebDAV server boolean localPath = true; if (url.getPort() != -1 && url.getPort() != request.getServerPort()) { // Debug if (logger.isDebugEnabled()) logger.debug("Destination path, different server port"); localPath = false; } else if (url.getHost().equalsIgnoreCase(request.getServerName()) == false && url.getHost().equals(request.getLocalAddr()) == false) { // The target host may contain a domain or be specified as a numeric IP address String targetHost = url.getHost(); if (IPAddress.isNumericAddress(targetHost) == false) { String localHost = request.getServerName(); int pos = targetHost.indexOf("."); if (pos != -1) targetHost = targetHost.substring(0, pos); pos = localHost.indexOf("."); if (pos != -1) localHost = localHost.substring(0, pos); // compare the host names if (targetHost.equalsIgnoreCase(localHost) == false) localPath = false; } else { try { // Check if the target IP address is a local address InetAddress targetAddr = InetAddress.getByName(targetHost); if (NetworkInterface.getByInetAddress(targetAddr) == null) localPath = false; } catch (Exception ex) { // DEBUG if (logger.isDebugEnabled()) logger.debug("Failed to check target IP address, " + targetHost); localPath = false; } } // Debug if (localPath == false && logger.isDebugEnabled()) { logger.debug("Destination path, different server name/address"); logger.debug(" URL host=" + url.getHost() + ", ServerName=" + request.getServerName() + ", localAddr=" + request.getLocalAddr()); } } else if (!url.getPath().startsWith(getUrlPathPrefix(request))) { // Debug if (logger.isDebugEnabled()) logger.debug("Destination path, different serlet path"); localPath = false; } // If the URL does not refer to this WebDAV server throw an // exception if (localPath != true) throw new WebDAVServerException(HttpServletResponse.SC_BAD_GATEWAY); } catch (MalformedURLException ex) { // Debug if (logger.isDebugEnabled()) logger.debug("Bad destination path, " + urlStr); throw new WebDAVServerException(HttpServletResponse.SC_BAD_GATEWAY); } } public void setUrlPathPrefix(String urlPathPrefix) { m_urlPathPrefix = urlPathPrefix; } public String getUrlPathPrefix(HttpServletRequest request) { StringBuilder urlStr = null; if (StringUtils.hasText(m_urlPathPrefix)) { // A specific prefix has been configured in, so use it. urlStr = new StringBuilder(m_urlPathPrefix); } else { // Extract the path prefix from the request, using the servlet path as a guide. // e.g. "/preamble/servlet-mapping/folder/file.txt" // with a servlet path of "/servlet-mapping" // would result in a path prefix of "/preamble/servlet-mapping" being discovered. urlStr = new StringBuilder(request.getRequestURI()); String servletPath = request.getServletPath(); int rootPos = urlStr.indexOf(servletPath); if (rootPos != -1) { urlStr.setLength(rootPos + servletPath.length()); } } // Ensure the prefix ends in the path separator. if (urlStr.length() == 0 || urlStr.charAt(urlStr.length() - 1) != PathSeperatorChar) { urlStr.append(PathSeperator); } return urlStr.toString(); } public String getRepositoryPath(HttpServletRequest request) { // Try and get the path String strPath = null; try { strPath = WebDAVHelper.decodeURL(request.getRequestURI()); } catch (Exception ex) { } // Find the servlet path and trim from the request path String servletPath = request.getServletPath(); int rootPos = strPath.indexOf(servletPath); if (rootPos != -1) { strPath = strPath.substring(rootPos); } // If we failed to get the path from the request try and get the path from the servlet path if (strPath == null) { strPath = request.getServletPath(); } if (strPath == null || strPath.length() == 0) { // If we still have not got a path then default to the root directory strPath = WebDAV.RootPath; } else if (strPath.startsWith(request.getServletPath())) { // Check if the path starts with the base servlet path int len = request.getServletPath().length(); if (strPath.length() > len) { strPath = strPath.substring(len); } else { strPath = WebDAV.RootPath; } } // Make sure there are no trailing slashes if (strPath.length() > 1 && strPath.endsWith(WebDAV.PathSeperator)) { strPath = strPath.substring(0, strPath.length() - 1); } // Return the path return strPath; } /** * Indicates if the node is unlocked or the current user has a WRITE_LOCK<p> * * @see LockService#isLockedAndReadOnly(NodeRef) * * @param nodeRef the node reference */ public boolean isLockedAndReadOnly(final NodeRef nodeRef) { return LockUtils.isLockedAndReadOnly(nodeRef, m_serviceRegistry.getLockService()); } /** * * @param request */ public NodeRef getNodeRefFromRequestPath(HttpServletRequest request) { String requestURI = request.getRequestURI(); Pattern p = Pattern.compile(".*/webdav2/(.*)/(.*)\\..*"); Matcher m = p.matcher(requestURI); if (m.matches()) { return new NodeRef("workspace://SpacesStore/" + m.group(2)); } else { return null; } } /** * * @param request */ public FileInfo getFileInfoFromRequestPath(HttpServletRequest request) throws FileNotFoundException { NodeRef node = getNodeRefFromRequestPath(request); if (node == null) return null; try { FileInfo fi = m_fileFolderService.getFileInfo(node); return fi; } catch (net.sf.acegisecurity.AccessDeniedException ex) { throw new FileNotFoundException(node); } } }