This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.fsresource-2.0.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-fsresource.git
commit 0115c1a694f71f4f0493e7c4cc2d517eff872c59 Author: Stefan Seifert <[email protected]> AuthorDate: Tue Feb 28 15:28:31 2017 +0000 SLING-6440 refactor fs jcr implementation to avoid cyclic dependencies to resource API and some further improvements git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/fsresource@1784754 13f79535-47bb-0310-9956-ffa450edef68 --- .../fsprovider/internal/ContentFileExtensions.java | 7 ++ .../fsprovider/internal/mapper/ContentFile.java | 9 +++ .../internal/mapper/ContentFileResource.java | 2 +- .../internal/mapper/ContentFileResourceMapper.java | 6 ++ .../fsprovider/internal/mapper/jcr/FsItem.java | 56 ++++++++-------- .../fsprovider/internal/mapper/jcr/FsNode.java | 77 ++++++++++++++++++---- .../internal/mapper/jcr/FsNodeIterator.java | 36 ++++++++-- .../fsprovider/internal/mapper/jcr/FsProperty.java | 9 +-- .../internal/mapper/jcr/FsPropertyIterator.java | 13 ++-- .../sling/fsprovider/internal/FileMonitorTest.java | 53 ++++++++------- .../sling/fsprovider/internal/JsonContentTest.java | 4 +- 11 files changed, 191 insertions(+), 81 deletions(-) diff --git a/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java b/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java index 3711ac9..5097750 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java @@ -65,4 +65,11 @@ public final class ContentFileExtensions { return contentFileSuffixes; } + /** + * @return true if not suffixes are defined. + */ + public boolean isEmpty() { + return contentFileSuffixes.isEmpty(); + } + } diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java index 2e60b1f..d31a851 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java @@ -128,6 +128,15 @@ public final class ContentFile { return valueMap; } + /** + * Navigate to another sub path position in content file. + * @param newSubPath New sub path + * @return Content file + */ + public ContentFile navigateTo(String newSubPath) { + return new ContentFile(file, path, newSubPath, contentFileCache); + } + @SuppressWarnings("unchecked") private static Object getDeepContent(Object object, String subPath) { if (object == null) { diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java index 410419e..dbbb5d0 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java @@ -108,7 +108,7 @@ public final class ContentFileResource extends AbstractResource { } else if (type == Node.class && contentFile.isResource()) { // support a subset of JCR API for content file resources - return (AdapterType)new FsNode(this); + return (AdapterType)new FsNode(contentFile, getResourceResolver()); } return super.adaptTo(type); } diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java index b5306b9..e6edd04 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java @@ -55,6 +55,9 @@ public final class ContentFileResourceMapper implements FsResourceMapper { @Override public Resource getResource(final ResourceResolver resolver, final String resourcePath) { + if (contentFileExtensions.isEmpty()) { + return null; + } ContentFile contentFile = getFile(resourcePath, null); if (contentFile != null && contentFile.hasContent()) { return new ContentFileResource(resolver, contentFile); @@ -67,6 +70,9 @@ public final class ContentFileResourceMapper implements FsResourceMapper { @SuppressWarnings("unchecked") @Override public Iterator<Resource> getChildren(final ResourceResolver resolver, final Resource parent) { + if (contentFileExtensions.isEmpty()) { + return null; + } final String parentPath = parent.getPath(); ContentFile parentContentFile = parent.adaptTo(ContentFile.class); diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsItem.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsItem.java index 11e1836..d5689a9 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsItem.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsItem.java @@ -38,53 +38,49 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; -import org.apache.sling.api.resource.ResourceUtil; import org.apache.sling.api.resource.ValueMap; +import org.apache.sling.fsprovider.internal.mapper.ContentFile; /** * Simplified implementation of read-only content access via the JCR API. */ abstract class FsItem implements Item { - protected final Resource resource; - protected final ValueMap props; + protected final ContentFile contentFile; protected final ResourceResolver resolver; + protected final ValueMap props; - public FsItem(Resource resource) { - this.resource = resource; - this.props = resource.getValueMap(); - this.resolver = resource.getResourceResolver(); + public FsItem(ContentFile contentFile, ResourceResolver resolver) { + this.contentFile = contentFile; + this.resolver = resolver; + this.props = contentFile.getValueMap(); } @Override public String getPath() throws RepositoryException { - return resource.getPath(); - } - - @Override - public String getName() throws RepositoryException { - return resource.getName(); - } - - @Override - public FsItem getAncestor(int depth) throws ItemNotFoundException, AccessDeniedException, RepositoryException { - String path = ResourceUtil.getParent(resource.getPath(), getDepth() - depth - 1); - if (path != null) { - Resource ancestor = resolver.getResource(path); - if (ancestor != null) { - return new FsNode(ancestor); - } + if (contentFile.getSubPath() == null) { + return contentFile.getPath(); + } + else { + return contentFile.getPath() + "/" + contentFile.getSubPath(); } - throw new ItemNotFoundException(path); } @Override - public Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException { - Resource parent = resource.getParent(); - if (parent != null) { - Node parentNode = parent.adaptTo(Node.class); - if (parentNode != null) { - return parentNode; + public Item getAncestor(int depth) throws ItemNotFoundException, AccessDeniedException, RepositoryException { + String path; + if (depth == 0) { + path = "/"; + } + else { + String[] pathParts = StringUtils.splitPreserveAllTokens(getPath(), "/"); + path = StringUtils.join(pathParts, "/", 0, depth + 1); + } + Resource resource = resolver.getResource(path); + if (resource != null) { + Node refNode = resource.adaptTo(Node.class); + if (refNode != null) { + return refNode; } } throw new ItemNotFoundException(); diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java index 1d4b842..6f52691 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java @@ -53,18 +53,21 @@ import javax.jcr.version.VersionHistory; import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.fsprovider.internal.mapper.ContentFile; /** * Simplified implementation of read-only content access via the JCR API. */ public final class FsNode extends FsItem implements Node { - public FsNode(Resource resource) { - super(resource); + public FsNode(ContentFile contentFile, ResourceResolver resolver) { + super(contentFile, resolver); } private String getPrimaryTypeName() { - return props.get("jcr:primaryType", String.class); + return props.get("jcr:primaryType", String.class); } private String[] getMixinTypeNames() { @@ -72,30 +75,76 @@ public final class FsNode extends FsItem implements Node { } @Override + public String getName() throws RepositoryException { + if (contentFile.getSubPath() == null) { + return ResourceUtil.getName(contentFile.getPath()); + } + else { + return ResourceUtil.getName(contentFile.getSubPath()); + } + } + + @Override + public Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException { + return getNode(ResourceUtil.getParent(getPath())); + } + + @Override public Node getNode(String relPath) throws PathNotFoundException, RepositoryException { - Resource child = resource.getChild(relPath); - if (child != null) { - return new FsNode(child); + if (relPath == null) { + throw new PathNotFoundException(); + } + + // get absolute node path + String path = relPath; + if (!StringUtils.startsWith(path, "/")) { + path = ResourceUtil.normalize(getPath() + "/" + relPath); + } + + if (StringUtils.equals(path, contentFile.getPath()) || StringUtils.startsWith(path, contentFile.getPath() + "/")) { + // node is contained in content file + String subPath; + if (StringUtils.equals(path, contentFile.getPath())) { + subPath = null; + } + else { + subPath = path.substring(contentFile.getPath().length() + 1); + } + ContentFile referencedFile = contentFile.navigateTo(subPath); + if (referencedFile.hasContent()) { + return new FsNode(referencedFile, resolver); + } + } + else { + // node is outside content file + Node refNode = null; + Resource resource = resolver.getResource(path); + if (resource != null) { + refNode = resource.adaptTo(Node.class); + if (refNode != null) { + return refNode; + } + } } throw new PathNotFoundException(relPath); } @Override public NodeIterator getNodes() throws RepositoryException { - return new FsNodeIterator(resource.listChildren()); + return new FsNodeIterator(contentFile, resolver); } @Override public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException { if (props.containsKey(relPath)) { - return new FsProperty(resource, relPath, this); + return new FsProperty(contentFile, resolver, relPath, this); } throw new PathNotFoundException(relPath); } @Override public PropertyIterator getProperties() throws RepositoryException { - return new FsPropertyIterator(props.keySet().iterator(), resource, this); + return new FsPropertyIterator(props.keySet().iterator(), contentFile, resolver, this); } @Override @@ -111,7 +160,13 @@ public final class FsNode extends FsItem implements Node { @Override public boolean hasNode(String relPath) throws RepositoryException { - return resource.getChild(relPath) != null; + try { + getNode(relPath); + return true; + } + catch (RepositoryException ex) { + return false; + } } @Override @@ -121,7 +176,7 @@ public final class FsNode extends FsItem implements Node { @Override public boolean hasNodes() throws RepositoryException { - return resource.listChildren().hasNext(); + return getNodes().hasNext(); } @Override diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeIterator.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeIterator.java index a2ef2fe..f03b0a7 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeIterator.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeIterator.java @@ -19,25 +19,41 @@ package org.apache.sling.fsprovider.internal.mapper.jcr; import java.util.Iterator; +import java.util.Map; import javax.jcr.Node; import javax.jcr.NodeIterator; -import org.apache.sling.api.resource.Resource; +import org.apache.commons.collections.IteratorUtils; +import org.apache.commons.collections.Predicate; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.fsprovider.internal.mapper.ContentFile; /** * Simplified implementation of read-only content access via the JCR API. */ class FsNodeIterator implements NodeIterator { - private final Iterator<Resource> resources; + private final ContentFile contentFile; + private final ResourceResolver resolver; + private final Iterator<Map.Entry<String,Map<String,Object>>> children; - public FsNodeIterator(Iterator<Resource> resources) { - this.resources = resources; + @SuppressWarnings("unchecked") + public FsNodeIterator(ContentFile contentFile, ResourceResolver resolver) { + this.contentFile = contentFile; + this.resolver = resolver; + Map<String,Object> content = (Map<String,Object>)contentFile.getContent(); + this.children = IteratorUtils.filteredIterator(content.entrySet().iterator(), new Predicate() { + @Override + public boolean evaluate(Object object) { + Map.Entry<String,Object> entry = (Map.Entry<String,Object>)object; + return (entry.getValue() instanceof Map); + } + }); } public boolean hasNext() { - return resources.hasNext(); + return children.hasNext(); } public Object next() { @@ -46,7 +62,15 @@ class FsNodeIterator implements NodeIterator { @Override public Node nextNode() { - return resources.next().adaptTo(Node.class); + Map.Entry<String,Map<String,Object>> nextEntry = children.next(); + String subPath; + if (contentFile.getSubPath() == null) { + subPath = nextEntry.getKey(); + } + else { + subPath = contentFile.getSubPath() + "/" + nextEntry.getKey(); + } + return new FsNode(contentFile.navigateTo(subPath), resolver); } diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java index 469bd11..bf24aa7 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java @@ -36,7 +36,8 @@ import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.PropertyDefinition; import javax.jcr.version.VersionException; -import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.fsprovider.internal.mapper.ContentFile; /** * Simplified implementation of read-only content access via the JCR API. @@ -46,8 +47,8 @@ class FsProperty extends FsItem implements Property { private final String propertyName; private final Node node; - public FsProperty(Resource resource, String propertyName, Node node) { - super(resource); + public FsProperty(ContentFile contentFile, ResourceResolver resolver, String propertyName, Node node) { + super(contentFile, resolver); this.propertyName = propertyName; this.node = node; } @@ -69,7 +70,7 @@ class FsProperty extends FsItem implements Property { @Override public String getPath() throws RepositoryException { - return resource.getPath() + "/" + propertyName; + return super.getPath() + "/" + propertyName; } @Override diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyIterator.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyIterator.java index de2d572..335472f 100644 --- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyIterator.java +++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyIterator.java @@ -24,7 +24,8 @@ import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.PropertyIterator; -import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.fsprovider.internal.mapper.ContentFile; /** * Simplified implementation of read-only content access via the JCR API. @@ -32,12 +33,14 @@ import org.apache.sling.api.resource.Resource; class FsPropertyIterator implements PropertyIterator { private final Iterator<String> propertyNames; - private final Resource resource; + private final ContentFile contentFile; + private final ResourceResolver resolver; private final Node node; - public FsPropertyIterator(Iterator<String> propertyNames, Resource resource, Node node) { + public FsPropertyIterator(Iterator<String> propertyNames, ContentFile contentFile, ResourceResolver resolver, Node node) { this.propertyNames = propertyNames; - this.resource = resource; + this.contentFile = contentFile; + this.resolver = resolver; this.node = node; } @@ -51,7 +54,7 @@ class FsPropertyIterator implements PropertyIterator { @Override public Property nextProperty() { - return new FsProperty(resource, propertyNames.next(), node); + return new FsProperty(contentFile, resolver, propertyNames.next(), node); } diff --git a/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java b/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java index 591a85c..f9cc25c 100644 --- a/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java +++ b/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.resource.observation.ResourceChange; import org.apache.sling.api.resource.observation.ResourceChange.ChangeType; import org.apache.sling.api.resource.observation.ResourceChangeListener; @@ -93,7 +94,7 @@ public class FileMonitorTest { Thread.sleep(250); assertEquals(1, changes.size()); - assertChange(changes, 0, "/fs-test/folder1/file1a.txt", ChangeType.CHANGED); + assertChange(changes, "/fs-test/folder1/file1a.txt", ChangeType.CHANGED); } @Test @@ -107,8 +108,8 @@ public class FileMonitorTest { Thread.sleep(250); assertEquals(2, changes.size()); - assertChange(changes, 0, "/fs-test/folder1", ChangeType.CHANGED); - assertChange(changes, 1, "/fs-test/folder1/file1c.txt", ChangeType.ADDED); + assertChange(changes, "/fs-test/folder1", ChangeType.CHANGED); + assertChange(changes, "/fs-test/folder1/file1c.txt", ChangeType.ADDED); } @Test @@ -122,8 +123,8 @@ public class FileMonitorTest { Thread.sleep(250); assertEquals(2, changes.size()); - assertChange(changes, 0, "/fs-test/folder1", ChangeType.CHANGED); - assertChange(changes, 1, "/fs-test/folder1/file1a.txt", ChangeType.REMOVED); + assertChange(changes, "/fs-test/folder1", ChangeType.CHANGED); + assertChange(changes, "/fs-test/folder1/file1a.txt", ChangeType.REMOVED); } @Test @@ -137,8 +138,8 @@ public class FileMonitorTest { Thread.sleep(250); assertEquals(2, changes.size()); - assertChange(changes, 0, "/fs-test", ChangeType.CHANGED); - assertChange(changes, 1, "/fs-test/folder99", ChangeType.ADDED); + assertChange(changes, "/fs-test", ChangeType.CHANGED); + assertChange(changes, "/fs-test/folder99", ChangeType.ADDED); } @Test @@ -152,8 +153,8 @@ public class FileMonitorTest { Thread.sleep(250); assertEquals(2, changes.size()); - assertChange(changes, 0, "/fs-test", ChangeType.CHANGED); - assertChange(changes, 1, "/fs-test/folder1", ChangeType.REMOVED); + assertChange(changes, "/fs-test", ChangeType.CHANGED); + assertChange(changes, "/fs-test/folder1", ChangeType.REMOVED); } @Test @@ -167,9 +168,9 @@ public class FileMonitorTest { Thread.sleep(250); assertTrue(changes.size() > 1); - assertChange(changes, 0, "/fs-test/folder2/content", ChangeType.REMOVED); - assertChange(changes, 1, "/fs-test/folder2/content", ChangeType.ADDED); - assertChange(changes, 2, "/fs-test/folder2/content/jcr:content", ChangeType.ADDED); + assertChange(changes, "/fs-test/folder2/content", ChangeType.REMOVED); + assertChange(changes, "/fs-test/folder2/content", ChangeType.ADDED); + assertChange(changes, "/fs-test/folder2/content/jcr:content", ChangeType.ADDED); } @Test @@ -183,9 +184,9 @@ public class FileMonitorTest { Thread.sleep(250); assertEquals(3, changes.size()); - assertChange(changes, 0, "/fs-test/folder1", ChangeType.CHANGED); - assertChange(changes, 1, "/fs-test/folder1/file1c", ChangeType.ADDED, "prop1"); - assertChange(changes, 2, "/fs-test/folder1/file1c/child1", ChangeType.ADDED, "prop2"); + assertChange(changes, "/fs-test/folder1", ChangeType.CHANGED); + assertChange(changes, "/fs-test/folder1/file1c", ChangeType.ADDED, "prop1"); + assertChange(changes, "/fs-test/folder1/file1c/child1", ChangeType.ADDED, "prop2"); } @Test @@ -199,18 +200,24 @@ public class FileMonitorTest { Thread.sleep(250); assertEquals(2, changes.size()); - assertChange(changes, 0, "/fs-test/folder2", ChangeType.CHANGED); - assertChange(changes, 1, "/fs-test/folder2/content", ChangeType.REMOVED); + assertChange(changes, "/fs-test/folder2", ChangeType.CHANGED); + assertChange(changes, "/fs-test/folder2/content", ChangeType.REMOVED); } - private void assertChange(List<ResourceChange> changes, int index, String path, ChangeType changeType, String... addedPropertyNames) { - ResourceChange change = changes.get(index); - assertEquals(path, change.getPath()); - assertEquals(changeType, change.getType()); - if (addedPropertyNames.length > 0) { - assertEquals(ImmutableSet.copyOf(addedPropertyNames), change.getAddedPropertyNames()); + private void assertChange(List<ResourceChange> changes, String path, ChangeType changeType, String... addedPropertyNames) { + boolean found = false; + for (ResourceChange change : changes) { + if (StringUtils.equals(change.getPath(), path) && change.getType() == changeType) { + found = true; + if (addedPropertyNames.length > 0) { + assertEquals(ImmutableSet.copyOf(addedPropertyNames), change.getAddedPropertyNames()); + } + break; + } } + assertTrue("Change with path=" + path + ", changeType=" + changeType, found); + } static class ResourceListener implements ResourceChangeListener { diff --git a/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java b/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java index a78d601..797575b 100644 --- a/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java +++ b/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java @@ -198,8 +198,10 @@ public class JsonContentTest { assertEquals(7, rightpar.getDepth()); Node parent = rightpar.getParent(); assertTrue(node.isSame(parent)); - Node ancestor = (Node)rightpar.getAncestor(4); + Node ancestor = (Node)rightpar.getAncestor(5); assertEquals(underTest.getParent().getPath(), ancestor.getPath()); + Node root = (Node)rightpar.getAncestor(0); + assertEquals("/", root.getPath()); // node types assertTrue(node.isNodeType("app:PageContent")); -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
