Hi Olaf,

I'd like to dive into your last comment some further. "You can never
re-provide a resource resolved by a different resource
provider". In my case, I don't think I'm re-providing, I'm just providing -
if anything, I'm delegating to the resource resolving mechanism which ends
up at my ResourceProvider. So I'm not ending up at a different resource
provider at this point, but actually the same resource provider.

It's still not entirely clear to me conceptually speaking why this is a bad
practise.

Best regards

2017-06-08 23:34 GMT+02:00 Olaf <o...@x100.de>:

> Hi Bart,
>
> I put them right in the code, where they are probably hard to spot :-)
>
> The essential one should be the one next to the place where you add the
> resource to the list of resource in ResourceProvider#listChildren. Updated
> version:
>
> You can never re-provide a resource resolved by a different resource
> provider: A resource has resource meta-data containing, amongst others, the
> resolution path. Also, a resource is always tied to its resource resolver
> via resource#getResourceProvider(). Thus, you must create a new
> (Synthetic)
> resource here and add it to the list. For instance, you could extend
> SyntheticResource to create your own resource wrapper, and delegate
> Resource#adaptTo to your wrapped resource.
>
>
> Kind regards,
> Olaf
>
> -----Original Message-----
> From: Bart Wulteputte [mailto:bart.wultepu...@gmail.com]
> Sent: Donnerstag, 8. Juni 2017 23:31
> To: users@sling.apache.org
> Subject: Re: Resource provided by custom ResourceProvider crashes upon
> calling hasChildren()
>
> Hi Olaf,
>
> Is it possible that you didn't send your remarks? I don't see them in your
> first mail.
>
> Best regards
>
>
> _____________________________
> From: Olaf <o...@x100.de<mailto:o...@x100.de>>
> Sent: donderdag, juni 8, 2017 11:25 PM
> Subject: RE: Resource provided by custom ResourceProvider crashes upon
> calling hasChildren()
> To: <users@sling.apache.org<mailto:users@sling.apache.org>>
>
>
> Hi Bart,
>
> I just saw you already used ResourceProvider#(ResolveContext ctx, Resource
> parent), excellent. Forget my first remark then, providing a
> SyntheticResource should do.
>
> Cheers,
> Olaf
>
> -----Original Message-----
> From: Olaf [mailto:o...@x100.de]
> Sent: Donnerstag, 8. Juni 2017 23:23
> To: users@sling.apache.org<mailto:users@sling.apache.org>
> Subject: RE: Resource provided by custom ResourceProvider crashes upon
> calling hasChildren()
>
> Hi Bart!
>
> Resource providers are mighty, but tricky things indeed. Please find my
> >remarks below.
>
> Cheers,
> Olaf
>
> -----Original Message-----
> From: Bart Wulteputte [mailto:bart.wultepu...@gmail.com]
> Sent: Donnerstag, 8. Juni 2017 22:50
> To: users@sling.apache.org<mailto:users@sling.apache.org>
> Subject: Resource provided by custom ResourceProvider crashes upon calling
> hasChildren()
>
> Hi,
>
> While trying to implement a POC and I ran into a strange error, and I hope
> you guys can help identify whether this is a bug, or if I'm just doing
> something wrong.
>
> I'm playing around with custom resource providers to pull external data
> into
> sling. I don't do anything crazy in there (yet), but it's just as a poc. I
> want to combine it with custom resource implementations as well.
>
> My resource provider is registered on path "/content/data" and basically
> handles anything on this path. Currently I'm just building a virtual data
> structure. Inside this virtual structure some paths will have a very
> specific ResourceProvider implementation tied to said path which retrieve
> the resource info from an external system when calling listChildren. So for
> example "/content/data/2001/external/app" could have a more specific
> resource provider registered here (which should work based on provider
> priority). Unfortunately, I can't seem to get part 1 (building the virtual
> structure) working without some hacks.
>
> *My resource provider implementation looks like this:*
>
> @Override
> public Resource getResource(@Nonnull final ResolveContext resolveContext,
> @Nonnull final String path, @Nonnull final ResourceContext resourceContext,
> final Resource parent) { return new
> SyntheticResource(resolveContext.getResourceResolver(),
> path, SyntheticResource.RESOURCE_TYPE_NON_EXISTING);
> }
>
>
> > Resources must never provide their own children - this is the resource
> provider's responsibility, see ResourceProvider#listChildren(
> ResolveContext
> ctx, Resource parent). The reason is that resource providers can be nested,
> i.e. the child of a resource may be provided by a different resource
> provider. Thus, the code below should be situated in the before mentioned
> method of your resource provider.
>
> @Override
> public Iterator<Resource> listChildren(@Nonnull final ResolveContext
> resolveContext, @Nonnull final Resource resource) { final ResourceResolver
> resourceResolver = resolveContext.getResourceResolver();
> final List<Resource> list = new ArrayList<>(); // search data basically
> returns a list of child paths // e.g. /content/data/2000,
> /content/data/2001, ...
> // since these are 'children' the resolving ends up in this
> ResourceProvider
> // which yields a new SyntheticResource on the given path (for now) for
> (String path : searchData.childrenOf(resource)) { final Resource childRes
> =
> resourceResolver.getResource(path);
> if (childRes != null) {
>
>
> > You can never re-provide a resolved resource: A resource has resource
> meta-data containing, amongst others, the resolution path. Also, a resource
> is always tied to its resource resolver via resource#getResourceProvider()
> .
> Thus, you must create a new (Synthetic) resource here and add it to the
> list. For instance, you could extend SyntheticResource to create your own
> resource wrapper, and delegate Resource#adaptTo to your wrapped resource.
>
> list.add(childRes);
> }
> }
> return list.isEmpty() ? null : list.iterator(); }
>
>
>
> *The code producing my error:*
>
> Resource r=resourceResolver.getResource("/content/data");
> r.hasChildren();
>
>
> *My Error:*
>
> java.lang.UnsupportedOperationException: ResourceMetadata is locked at
> org.apache.sling.api.resource.ResourceMetadata.
> checkReadOnly(ResourceMetadat
> a.java:367)
> at
> org.apache.sling.api.resource.ResourceMetadata.put(
> ResourceMetadata.java:379
> )
> at
> org.apache.sling.api.resource.ResourceMetadata.
> setResolutionPath(ResourceMet
> adata.java:276)
> at
> org.apache.sling.resourceresolver.impl.helper.
> UniqueResourceIterator.seek(Un
> iqueResourceIterator.java:51)
> at
> org.apache.sling.resourceresolver.impl.helper.
> UniqueResourceIterator.seek(Un
> iqueResourceIterator.java:30)
> at
> org.apache.sling.resourceresolver.impl.helper.
> AbstractIterator.hasNext(Abstr
> actIterator.java:33)
> at
> org.apache.sling.resourceresolver.impl.helper.
> ResourceIteratorDecorator.hasN
> ext(ResourceIteratorDecorator.java:45)
> ...
>
>
> *My analysis so far:*
>
> Because I use resourceResolver.getResource() inside the listChildren method
> of my custom resource provider, I pass through some internal resolving
> which
> do some decorating on the resource and the iterators. This in itself is not
> a problem, but one of those decorators (the
> ResourceDecoratorTracker) locks the ResourceMedatadata object - which is a
> problem as other decorators like ResourceIteratorDecorator try to update
> data (in this case it tries to set/update the resolutionPath of the fetched
> resource's ResourceMetadata to the path of said resource during the
> execution of 'next()' - which seems a tad odd). And here we end up trying
> to
> modify a locked object.
>
>
> This feels like a bug. I can get around it by creating my own
> ResourceMetadata class which extends ResourceMetadata and overrides the
> lock() method to do nothing and passing that to the SyntheticResource upon
> creation. But this feels like hacking. Second option: I don't use the
> resourceResolver to get the resource, but instead create new
> SyntheticResource objects in the listChildren of my ResourceProvider
> directly (in the same way i would do 'getResource').
>
> Preferably I want to pass through the appropriate ResourceProvider (since
> the intend is to have more specific resource providers mounted on paths
> inside this virtual structure). In theory this should work, and in practise
> it does as well (if I hack it a bit as described before).
>
> So the main question is, can I do this in a non hackish way? And is this a
> bug?
>
>
>
>
>
>

Reply via email to