Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java (revision 9a059fff2d7f28f74b6faabb866d97f0e06e94bb) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java (revision 9a059fff2d7f28f74b6faabb866d97f0e06e94bb) @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.spi2dav; + +import java.util.LinkedHashMap; +import java.util.Map; +import org.apache.jackrabbit.spi.ItemId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * IdPathCache ... + */ +class IdPathCache { + + private static Logger log = LoggerFactory.getLogger(IdPathCache.class); + + /** + * @see JCR-3305: limit cache size + */ + private static final int CACHESIZE = 10000; + + private Map idToPathCache; + private Map pathToIdCache; + + public IdPathCache() { + idToPathCache = new LinkedHashMap(CACHESIZE, 1) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return this.size() > CACHESIZE; + } + }; + pathToIdCache = new LinkedHashMap(CACHESIZE, 1) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return this.size() > CACHESIZE; + } + }; + } + + public ItemId getItemId(String path) { + return pathToIdCache.get(path); + } + + public String getPath(ItemId itemId) { + return idToPathCache.get(itemId); + } + + public boolean containsPath(String path) { + return pathToIdCache.containsKey(path); + } + + public boolean containsItemId(ItemId itemId) { + return idToPathCache.containsKey(itemId); + } + + public void add(String path, ItemId itemId) { + pathToIdCache.put(path, itemId); + idToPathCache.put(itemId, path); + log.debug("Added: ItemId = " + itemId + " PATH = {}", path); + } + + public void remove(String path) { + ItemId itemId = pathToIdCache.remove(path); + if (itemId != null) { + idToPathCache.remove(itemId); + } + log.debug("Removed: ItemId = " + itemId + " PATH = {}", path); + } + + public void remove(ItemId itemId) { + String path = idToPathCache.remove(itemId); + if (path != null) { + pathToIdCache.remove(path); + } + log.debug("Removed: ItemId = " + itemId + " PATH = {}", path); + } + + public void clear() { + idToPathCache.clear(); + pathToIdCache.clear(); + } +} Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdURICache.java =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdURICache.java (revision 7f8f2fb) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdURICache.java (revision 7f8f2fb) @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.spi2dav; - -import java.util.LinkedHashMap; -import java.util.Map; -import org.apache.jackrabbit.spi.ItemId; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * IdURICache... - */ -class IdURICache { - private static Logger log = LoggerFactory.getLogger(IdURICache.class); - - /** - * @see JCR-3305: limit cache size - */ - private static final int CACHESIZE = 10000; - - private final String workspaceUri; - private Map idToUriCache; - private Map uriToIdCache; - - IdURICache(String workspaceUri) { - this.workspaceUri = workspaceUri; - idToUriCache = new LinkedHashMap(CACHESIZE, 1) { - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return this.size() > CACHESIZE; - } - }; - uriToIdCache = new LinkedHashMap(CACHESIZE, 1) { - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return this.size() > CACHESIZE; - } - }; - } - - public ItemId getItemId(String uri) { - return uriToIdCache.get(getCleanUri(uri)); - } - - public String getUri(ItemId itemId) { - return idToUriCache.get(itemId); - } - - public boolean containsUri(String uri) { - return uriToIdCache.containsKey(getCleanUri(uri)); - } - - public boolean containsItemId(ItemId itemId) { - return idToUriCache.containsKey(itemId); - } - - public void add(String uri, ItemId itemId) { - if (!uri.startsWith(workspaceUri)) { - throw new IllegalArgumentException("Workspace missmatch."); - } - String cleanUri = getCleanUri(uri); - uriToIdCache.put(cleanUri, itemId); - idToUriCache.put(itemId, cleanUri); - log.debug("Added: ItemId = " + itemId + " URI = " + cleanUri); - } - - public void remove(String uri) { - String cleanUri = getCleanUri(uri); - ItemId itemId = uriToIdCache.remove(cleanUri); - if (itemId != null) { - idToUriCache.remove(itemId); - } - log.debug("Removed: ItemId = " + itemId + " URI = " + cleanUri); - } - - public void remove(ItemId itemId) { - String uri = idToUriCache.remove(itemId); - if (uri != null) { - uriToIdCache.remove(uri); - } - log.debug("Removed: ItemId = " + itemId + " URI = " + uri); - } - - public void clear() { - idToUriCache.clear(); - uriToIdCache.clear(); - } - - private static String getCleanUri(String uri) { - if (uri.endsWith("/")) { - return uri.substring(0, uri.length() - 1); - } else { - return uri; - } - } -} Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java (revision 7f8f2fb) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java (revision 9a059fff2d7f28f74b6faabb866d97f0e06e94bb) @@ -40,11 +40,14 @@ import org.apache.jackrabbit.webdav.property.DavPropertySet; import org.apache.jackrabbit.webdav.version.report.ReportInfo; import org.apache.jackrabbit.webdav.xml.DomUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import javax.jcr.ItemNotFoundException; import javax.jcr.RepositoryException; import java.io.IOException; +import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; @@ -53,13 +56,15 @@ */ class URIResolverImpl implements URIResolver { + private static Logger log = LoggerFactory.getLogger(URIResolverImpl.class); + private final URI repositoryUri; private final RepositoryServiceImpl service; private final Document domFactory; // TODO: to-be-fixed. uri/id-caches don't get updated // for each workspace a separate idUri-cache is created - private final Map idURICaches = new HashMap(); + private final Map idPathCaches = new HashMap(); URIResolverImpl(URI repositoryUri, RepositoryServiceImpl service, Document domFactory) { this.repositoryUri = repositoryUri; @@ -67,13 +72,14 @@ this.domFactory = domFactory; } - private IdURICache getCache(String workspaceName) { - if (idURICaches.containsKey(workspaceName)) { - return idURICaches.get(workspaceName); + private IdPathCache getCache(String workspaceName) { + IdPathCache cache = idPathCaches.get(workspaceName); + if (cache != null) { + return cache; } else { - IdURICache c = new IdURICache(getWorkspaceUri(workspaceName)); - idURICaches.put(workspaceName, c); - return c; + IdPathCache emptyCache = new IdPathCache(); + idPathCaches.put(workspaceName, emptyCache); + return emptyCache; } } @@ -95,10 +101,10 @@ String getItemUri(ItemId itemId, String workspaceName, SessionInfo sessionInfo) throws RepositoryException { - IdURICache cache = getCache(workspaceName); + IdPathCache cache = getCache(workspaceName); // check if uri is available from cache if (cache.containsItemId(itemId)) { - return cache.getUri(itemId); + return getUri(cache.getPath(itemId)); } else { StringBuffer uriBuffer = new StringBuffer(); @@ -110,7 +116,7 @@ ItemId uuidId = (path == null) ? itemId : service.getIdFactory().createNodeId(uniqueID); if (path != null && cache.containsItemId(uuidId)) { // append uri of parent node, that is already cached - uriBuffer.append(cache.getUri(uuidId)); + uriBuffer.append(getUri(cache.getPath(uuidId))); } else { // try to request locate-by-uuid report to build the uri ReportInfo rInfo = new ReportInfo(JcrRemotingConstants.REPORT_LOCATE_BY_UUID, ItemResourceConstants.NAMESPACE); @@ -126,7 +132,7 @@ MultiStatus ms = rm.getResponseBodyAsMultiStatus(); if (ms.getResponses().length == 1) { uriBuffer.append(ms.getResponses()[0].getHref()); - cache.add(ms.getResponses()[0].getHref(), uuidId); + cache.add(getPath(ms.getResponses()[0].getHref()), uuidId); } else { throw new ItemNotFoundException("Cannot identify item with uniqueID " + uniqueID); } @@ -155,7 +161,7 @@ } String itemUri = uriBuffer.toString(); if (!cache.containsItemId(itemId)) { - cache.add(itemUri, itemId); + cache.add(getPath(itemUri), itemId); } return itemUri; } @@ -163,7 +169,7 @@ NodeId buildNodeId(NodeId parentId, MultiStatusResponse response, String workspaceName, NamePathResolver resolver) throws RepositoryException { - IdURICache cache = getCache(workspaceName); + IdPathCache cache = getCache(workspaceName); NodeId nodeId; DavPropertySet propSet = response.getProperties(DavServletResponse.SC_OK); @@ -181,15 +187,16 @@ } } // cache - cache.add(response.getHref(), nodeId); + cache.add(getPath(response.getHref()), nodeId); return nodeId; } PropertyId buildPropertyId(NodeId parentId, MultiStatusResponse response, String workspaceName, NamePathResolver resolver) throws RepositoryException { - IdURICache cache = getCache(workspaceName); - if (cache.containsUri(response.getHref())) { - ItemId id = cache.getItemId(response.getHref()); + IdPathCache cache = getCache(workspaceName); + String path = getPath(response.getHref()); + if (cache.containsPath(path)) { + ItemId id = cache.getItemId(path); if (!id.denotesNode()) { return (PropertyId) id; } @@ -200,22 +207,15 @@ Name name = resolver.getQName(propSet.get(JcrRemotingConstants.JCR_NAME_LN, ItemResourceConstants.NAMESPACE).getValue().toString()); PropertyId propertyId = service.getIdFactory().createPropertyId(parentId, name); - cache.add(response.getHref(), propertyId); + cache.add(getPath(response.getHref()), propertyId); return propertyId; } catch (NameException e) { throw new RepositoryException(e); } } - void clearCacheEntries(ItemId itemId, SessionInfo sessionInfo) { - IdURICache cache = getCache(sessionInfo.getWorkspaceName()); - if (cache.containsItemId(itemId)) { - cache.remove(itemId); - } - } - void clearCacheEntries(SessionInfo sessionInfo) { - IdURICache cache = getCache(sessionInfo.getWorkspaceName()); + IdPathCache cache = getCache(sessionInfo.getWorkspaceName()); cache.clear(); } @@ -233,10 +233,11 @@ } private NodeId getNodeId(String uri, SessionInfo sessionInfo, boolean nodeIsGone) throws RepositoryException { - IdURICache cache = getCache(sessionInfo.getWorkspaceName()); - if (cache.containsUri(uri)) { + IdPathCache cache = getCache(sessionInfo.getWorkspaceName()); + String path = getPath(uri); + if (cache.containsPath(path)) { // id has been accessed before and is cached - ItemId id = cache.getItemId(uri); + ItemId id = cache.getItemId(path); if (id.denotesNode()) { return (NodeId) id; } @@ -281,6 +282,32 @@ } } + /** + * @param uri the uri to be parsed + * @return the path (trailing slash removed) extracted from the given uri or null if the uri could not + * be parsed. + */ + private String getPath(String uri) { + try { + String path = new java.net.URI(uri).getPath(); + if (path.endsWith("/") && ! "/".equals(path)) { + return path.substring(0, path.length() - 1); + } + return path; + } catch (URISyntaxException e) { + log.warn("Failed to parse the URI = {}", uri); + } + return null; + } + + private String getUri(String path) { + String baseUri = getRepositoryUri(); + if (baseUri.endsWith("/")) { + return baseUri.substring(0, baseUri.length() - 1) + Text.escapePath(path); + } + return baseUri + Text.escapePath(path); + } + //-------------------------------------------------------< URI resolver >--- /** * @inheritDoc @@ -319,9 +346,10 @@ * @inheritDoc */ public PropertyId getPropertyId(String uri, SessionInfo sessionInfo) throws RepositoryException { - IdURICache cache = getCache(sessionInfo.getWorkspaceName()); - if (cache.containsUri(uri)) { - ItemId id = cache.getItemId(uri); + IdPathCache cache = getCache(sessionInfo.getWorkspaceName()); + String path = getPath(uri); + if (cache.containsPath(path)) { + ItemId id = cache.getItemId(path); if (!id.denotesNode()) { return (PropertyId) id; } @@ -337,7 +365,7 @@ try { Name name = service.getNamePathResolver(sessionInfo).getQName(propName); PropertyId propertyId = service.getIdFactory().createPropertyId(parentId, name); - cache.add(uri, propertyId); + cache.add(getPath(uri), propertyId); return propertyId; } catch (NameException e) {