This is an automated email from the ASF dual-hosted git repository. bdelacretaz pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
commit 3eff62c8cba12b1d912eda7c35ae037d5d642fa0 Author: Bertrand Delacretaz <[email protected]> AuthorDate: Thu May 6 18:25:40 2021 +0200 Add sling:dmap:debug --- .../documentmapper/api/Annotations.java | 50 +++++++++++++++---- .../documentmapper/api/DocumentMapper.java | 11 +++- .../documentmapper/impl/ContentDocumentMapper.java | 58 ++++++++++++++++------ .../samples/graphql/DocumentDataFetcher.java | 10 +--- .../samples/graphql/DocumentsDataFetcher.java | 17 ++++--- .../annotations/AnnotationsRegistryImpl.java | 23 ++++++--- .../apps/samples/graphql/GQLschema.jsp | 4 +- 7 files changed, 124 insertions(+), 49 deletions(-) diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java index a0402a0..4f00c4f 100644 --- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java +++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java @@ -34,10 +34,12 @@ public class Annotations { private boolean navigable; private boolean visitContent; private boolean documentRoot; + private String childSubstitutePath; private Pattern visitContentResourceNamePattern; private Pattern includePropertyPattern; private Pattern excludePropertyPattern; - private List<String> dereferenceByPathProperties; + private List<String> resolveByPathProperties; + private List<String> excludeNodeNames; private Annotations(String resourceType) { this.resourceType = resourceType; @@ -46,7 +48,7 @@ public class Annotations { @Override public String toString() { return String.format( - "RT=%s N=%b VC=%b DR=%b VCRN=%s IP=%s EP=%s DR=%s", + "RT=%s N=%b VC=%b DR=%b VCRN=%s IP=%s EP=%s DR=%s ENN=%s", resourceType, navigable, visitContent, @@ -54,7 +56,8 @@ public class Annotations { visitContentResourceNamePattern, includePropertyPattern, excludePropertyPattern, - dereferenceByPathProperties + resolveByPathProperties, + excludeNodeNames ); } @@ -89,14 +92,26 @@ public class Annotations { return result; } - public Collection<String> dereferenceByPathPropertyNames() { - if(dereferenceByPathProperties != null) { - return dereferenceByPathProperties; + public Collection<String> resolveByPathPropertyNames() { + if(resolveByPathProperties != null) { + return resolveByPathProperties; } else { return Collections.emptyList(); } } + public Collection<String> excludeNodeNames() { + if(excludeNodeNames != null) { + return excludeNodeNames; + } else { + return Collections.emptyList(); + } + } + + public String childSubstitutePath() { + return childSubstitutePath; + } + public static Builder forResourceType(String resourceType) { return new Builder(resourceType); } @@ -137,16 +152,31 @@ public class Annotations { return this; } - public Builder withDereferenceByPathProperties(String ... names) { - if(target.dereferenceByPathProperties == null) { - target.dereferenceByPathProperties = new ArrayList<String>(); + public Builder withResolveByPathPropertyNames(String ... names) { + if(target.resolveByPathProperties == null) { + target.resolveByPathProperties = new ArrayList<String>(); + } + for(String name : names) { + target.resolveByPathProperties.add(name); + } + return this; + } + + public Builder withExcludeNodeNames(String ... names) { + if(target.excludeNodeNames == null) { + target.excludeNodeNames = new ArrayList<String>(); } for(String name : names) { - target.dereferenceByPathProperties.add(name); + target.excludeNodeNames.add(name); } return this; } + public Builder withChildSubstituePath(String path) { + target.childSubstitutePath = path; + return this; + } + public Annotations build() { return target; } diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java index 94e47d8..31435d0 100644 --- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java +++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java @@ -34,6 +34,15 @@ public interface DocumentMapper { interface UrlBuilder { String pathToUrl(String path); } + + public static class Options { + public final boolean debug; + public final UrlBuilder urlBuilder; + public Options(boolean debug, UrlBuilder urlBuilder) { + this.debug = debug; + this.urlBuilder = urlBuilder; + } + } - void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode destination, UrlBuilder urlb); + void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode destination, Options opt); } \ No newline at end of file diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java index 40cbfda..7561acc 100644 --- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java +++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java @@ -41,32 +41,62 @@ public class ContentDocumentMapper implements DocumentMapper { private AnnotationsRegistry annotationsRegistry; @Override - public void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, UrlBuilder urlb) { - final String resourceType = r.getResourceType(); - final Annotations annot = annotationsRegistry.getAnnotations(resourceType); - dest.addValue("path", r.getPath()); + public void map(@NotNull Resource originalResource, @NotNull MappingTarget.TargetNode dest, DocumentMapper.Options opt) { + Annotations annot = annotationsRegistry.getAnnotations(originalResource.getResourceType()); + dest.addValue("path", originalResource.getPath()); + final String substPath = annot.childSubstitutePath(); + Resource r = originalResource; + if(substPath != null) { + r = r.getChild(substPath); + if(r == null) { + throw new RuntimeException("Child " + substPath + " of resource " + originalResource.getPath() + "not found"); + } + annot = annotationsRegistry.getAnnotations(r.getResourceType()); + } log.debug("Top level Resource map {} as {}: {}", r.getPath(), r.getResourceType(), annot); - mapResource(r, dest, urlb, resourceType, annot, annot.isDocumentRoot()); + mapResource(r, dest, opt, r.getResourceType(), annot, annot.isDocumentRoot()); } private void mapResource(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, - UrlBuilder urlb, String documentResourceType, Annotations documentAnnot, boolean recurse) { + DocumentMapper.Options opt, String documentResourceType, Annotations documentAnnot, boolean recurse) { + + final Annotations resourceAnnot = annotationsRegistry.getAnnotations(r.getResourceType()); + final MappingTarget.TargetNode debug = opt.debug ? dest.addChild("sling:dmap:debug") : null; + if(debug != null) { + debug.addValue("sling:dmap:path", r.getPath()); + debug.addValue("sling:dmap:resourceType", r.getResourceType()); + debug.addValue("sling:dmap:documentAnnot", documentAnnot.toString()); + debug.addValue("sling:dmap:resourceAnnot", resourceAnnot.toString()); + } + + for(String name : documentAnnot.excludeNodeNames()) { + if(name.equals(r.getName())) { + if(debug != null) { + debug.addValue("sling:dmap:excluded", documentAnnot.toString()); + } + log.debug("Resource {} excluded by node name ({})", r.getPath(), documentAnnot); + return; + } + } log.debug("Mapping Resource {} as {}: {}", r.getPath(), r.getResourceType(), documentAnnot); propertiesMapper.mapProperties(dest, r, documentAnnot); - final Annotations thisAnnot = annotationsRegistry.getAnnotations(r.getResourceType()); - // Dereference by path if specified + // Resolve by path if specified // TODO detect cycles which might lead to infinite loops - thisAnnot.dereferenceByPathPropertyNames().forEach(derefPathPropertyName -> { - log.debug("Dereferencing {} on {}", r.getPath(), derefPathPropertyName); + resourceAnnot.resolveByPathPropertyNames().forEach(derefPathPropertyName -> { + log.debug("Resolving by path {} on {}", r.getPath(), derefPathPropertyName); final ValueMap vm = r.adaptTo(ValueMap.class); final String derefPath = vm == null ? null : vm.get(derefPathPropertyName, String.class); if(derefPath != null) { final Resource dereferenced = r.getResourceResolver().getResource(derefPath); if(dereferenced != null) { - final MappingTarget.TargetNode derefNode = dest.addChild("dereferenced_by_" + derefPathPropertyName); - mapResource(dereferenced, derefNode, urlb, documentResourceType, documentAnnot, recurse); + final MappingTarget.TargetNode derefNode = dest.addChild("sling:dmap:resolved"); + derefNode.addValue("sling:dmap:resolvedFrom", derefPathPropertyName); + derefNode.addValue("sling:dmap:resolvePath", derefPath); + mapResource(dereferenced, derefNode, opt, documentResourceType, documentAnnot, recurse); + } else if(debug != null) { + debug.addValue("Resolve by path " + derefPathPropertyName, "not found:" + derefPath); } } }); @@ -75,7 +105,7 @@ public class ContentDocumentMapper implements DocumentMapper { if(recurse) { log.debug("Recursing into {}", r.getPath()); for(Resource child : r.getChildren()) { - final boolean visit = thisAnnot.visitChildResource(child.getName()); + final boolean visit = resourceAnnot.visitChildResource(child.getName()); log.debug("child resource {} visit decision {}", child.getName(), visit); if(!visit) { continue; @@ -83,7 +113,7 @@ public class ContentDocumentMapper implements DocumentMapper { final String childResourceType = child.getResourceType(); if(annotationsRegistry.getAnnotations(childResourceType).visitContent()) { final MappingTarget.TargetNode childDest = dest.addChild(child.getName()); - mapResource(child, childDest, urlb, childResourceType, documentAnnot, true); + mapResource(child, childDest, opt, childResourceType, documentAnnot, true); } } } else if(log.isDebugEnabled()) { diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java index 69aa950..ff432e0 100644 --- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java +++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java @@ -42,13 +42,6 @@ public class DocumentDataFetcher implements SlingDataFetcher<Object> { @Reference private DocumentMapper documentMapper; - static final UrlBuilder DUMMY_URL_BUILDER = new UrlBuilder() { - @Override - public String pathToUrl(String path) { - return getClass().getName(); - } - }; - @Override public @Nullable Object get(@NotNull SlingDataFetcherEnvironment e) throws Exception { final String path = e.getArgument("path"); @@ -56,13 +49,14 @@ public class DocumentDataFetcher implements SlingDataFetcher<Object> { final Map<String, Object> data = new HashMap<>(); data.put("path", path); data.put("selectors", e.getArgument("selectors")); + final DocumentMapper.Options opt = new DocumentMapper.Options(e.getArgument("debug", true), new UrlBuilderStub()); // Get the target Resource final Resource target = e.getCurrentResource().getResourceResolver().getResource(path); // Use DocumentMapper to build the body final MappingTarget.TargetNode body = mappingTarget.newTargetNode(); - documentMapper.map(target, body, DUMMY_URL_BUILDER); + documentMapper.map(target, body, opt); body.close(); data.put("body", body.adaptTo(Map.class)); return data; diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java index 8f00320..581a905 100644 --- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java +++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java @@ -45,22 +45,21 @@ public class DocumentsDataFetcher implements SlingDataFetcher<Object> { @Reference private DocumentMapper documentMapper; - private void addDocumentData(final Map<String, Object> data, String key, Resource r, DocumentMapper mapper) { + private void addDocumentData(final Map<String, Object> data, String key, Resource r, DocumentMapper mapper, DocumentMapper.Options opt) { final MappingTarget.TargetNode target = mappingTarget.newTargetNode(); - mapper.map(r, target, new UrlBuilderStub()); + mapper.map(r, target, opt); target.close(); data.put(key, target.adaptTo(Map.class)); } - private Map<String, Object> toDocument(Resource r) { + private Map<String, Object> toDocument(Resource r, DocumentMapper.Options opt) { final Map<String, Object> data = new HashMap<>(); data.put("path", r.getPath()); - // TODO how to find out whether those fields are actually needed - // or how to evaluate them lazily - addDocumentData(data, "body", r, documentMapper); - addDocumentData(data, "summary", r, documentMapper); + // TODO for now those are the same... + addDocumentData(data, "body", r, documentMapper, opt); + addDocumentData(data, "summary", r, documentMapper, opt); return data; } @@ -70,6 +69,8 @@ public class DocumentsDataFetcher implements SlingDataFetcher<Object> { // Use a suffix as we might not keep these built-in language in the long term final String langSuffix = "2020"; + final DocumentMapper.Options opt = new DocumentMapper.Options(e.getArgument("debug", true), new UrlBuilderStub()); + String lang = e.getArgument("lang", "xpath" + langSuffix); if(!lang.endsWith(langSuffix)) { throw new RuntimeException("Query langage must end with suffix " + langSuffix); @@ -81,7 +82,7 @@ public class DocumentsDataFetcher implements SlingDataFetcher<Object> { final ResourceResolver resolver = e.getCurrentResource().getResourceResolver(); final Iterator<Resource> it = resolver.findResources(query, lang); while(it.hasNext()) { - result.add(toDocument(it.next())); + result.add(toDocument(it.next(), opt)); } return result; } diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java index 1750928..4915be7 100644 --- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java +++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java @@ -50,28 +50,39 @@ public class AnnotationsRegistryImpl implements AnnotationsRegistry { @Activate public void activate() { + final String generalIgnoreProperties = "jcr:.*|cq:.*|crs:.*|tiff:.*|xmpMM:.*|xmp:.*|psAux:.*"; + final String [] generalExcludeNodeNames = { "xmpMM:History", "xmpMM:DerivedFrom", "metadata" }; + add( Annotations.forResourceType("cq:Page") .withDocumentRoot(true) + .withChildSubstituePath("jcr:content") .withNavigable(true) .withVisitContent(true) - .withVisitContentChildResourceNamePattern("jcr:content") - .withIncludePropertyPattern("sling:ResourceType|cq:tags") - .withExcludePropertyPattern("jcr:.*|cq:.*") + .withIncludePropertyPattern("sling:ResourceType|cq:tags|jcr:title|jcr:description") + .withExcludePropertyPattern(generalIgnoreProperties) + .withExcludeNodeNames(generalExcludeNodeNames) ); add( Annotations.forResourceType("wknd/components/page") // TODO shall we only have "visit content"? .withDocumentRoot(true) .withVisitContent(true) - .withIncludePropertyPattern("sling:ResourceType|jcr:description") - .withExcludePropertyPattern("jcr:.*|cq:.*") + .withIncludePropertyPattern("sling:ResourceType|jcr:title|jcr:description") + .withExcludePropertyPattern(generalIgnoreProperties) + .withExcludeNodeNames(generalExcludeNodeNames) ); add( Annotations.forResourceType("wknd/components/image") .withVisitContent(true) - .withDereferenceByPathProperties("fileReference") + .withResolveByPathPropertyNames("fileReference") + ); + add( + Annotations.forResourceType("wknd/components/contentfragment") + .withVisitContent(true) + .withResolveByPathPropertyNames("fragmentPath") ); + /* add( Builder.forResourceType("sling:Folder") diff --git a/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp b/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp index 425ff57..79361a2 100644 --- a/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp +++ b/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp @@ -22,8 +22,8 @@ scalar Object type Query { - document(path : String, selectors : [String]) : Document @fetcher(name:"samples/document") - documents(lang: String, query : String, selectors : [String]) : [Document] @fetcher(name:"samples/documents") + document(path : String, selectors : [String], debug : Boolean) : Document @fetcher(name:"samples/document") + documents(lang: String, query : String, selectors : [String], debug : Boolean) : [Document] @fetcher(name:"samples/documents") } type Mutation {
