[ 
https://issues.apache.org/jira/browse/SLING-2853?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13649346#comment-13649346
 ] 

Alexander Klimetschek edited comment on SLING-2853 at 5/5/13 2:52 PM:
----------------------------------------------------------------------

Here's my review of the patch from the Star Wars day ;-)

Content Structure:

- my proposal, see below for discussion
  (legend: + = node, - = property, [nodetype], # comment)

  + <name> [nt:unstructured] # but node type should be free
      - sling:resourceType = "sling/collection"
      - key = "value" # collection-level metadata
      + thumbnail     # metadata with child resources/nodes
        - ...
      ...
      + members [nt:unstructured] # optional?
          - sling:resources = ["/one", "/two", "/three"]
          + member1 [nt:unstructured]
              - sling:resource = "/one"
              - key = "value" # reference-level metadata
              ...
          + member2
              - sling:resource = "/three"
              - key = "value"
              ...


- The node type on the collection node should not be restricted to allow
  custom metadata having child nodes with any type. For example, a child
  node of type nt:file would not work within a nt:unstructured. This
  requires the create collection API to allow for a node type being passed.
  Also we have a so-called replication mechanism for individual nodes that
  depends on certain node types, so in some case you might want this type
  and in others another one.

- I think the "members" node could be left out completely. Nesting of
  collections isn't really something that makes sense. Leaving it out
  has only the disadvantage that custom metadata that needs child resources
  cannot use any of the "member1", "member2" ... node names, instead of
  just "members" as an excluded name. For simple collections without any
  metadata this would truly optimize the structure to the minimum.
  But I am not fully decided on that.

- The properties should be namespaced, since they could overlap with custom
  properties. I guess "sling:" is the namespace to use.
  
- I would prefer naming the property "path" different, like "sling:resource" or
  "sling:reference". While the content of the property is a path now, it might
  be something else in the future (like a http url, uuid, etc.), and it
  actually addresses a resource or reference to a resource. "resource"
  would also be in line with the getResources() API name.
  
- Similarly, "pathorder" is a suboptimal name. It's not camel-cased and
  as above, "sling:resources" or "sling:references" sounds better. That it's
  ordered doesn't have to be included in the name.

- Moreover, I think that multi-value property should define the whole
  references list. So it would not be required that there is actually a
  child resource (entry) being present (applies to getEntries()) to
  return that resource in the list. The child resource would only be
  needed in case there are additional properties set.

API:

- ResourceCollection: For the implementation reading that list (getEntries())
  the point above would mean no need to iterate over the child resources at all.
  There needs to be some way to get the metadata, if there is some:
  + get properties for one reference
    ValueMap getProperties(String reference) or (Resource resource)
  + optional, to batch read everything:
    Iterator<Entry> getEntries()
    Entry = simple struct-like class with Resource (the referenced
            resource) and a ValueMap or ModifiableValueMap
  
- ResourceCollection.getEntries()
  I don't think if getEntries() separate from getResources() is really needed,
  as this exposes too much of the inner content structure in the API.
  As proposed above, I see an optimization here where there might not be
  actual child resources for every single reference defined in the array 
property.
  
- ResourceCollection.DEFAULT_SLING_RES_TYPE rename to simply RESOURCE_TYPE
  The "default" and "sling" in it is misleading; it is *the* rt for the 
ResourceCollection,
  and I guess it's rather unlikely that someone extends the resource collection 
rt,
  let alone being a central feature to be pointed out.
  
- ResourceCollectionManager methods should IMHO all be consistently based on
  passing Resource instead of path (makes e.g. the createCollection() 
implementation
  simpler in that it does not have to getResource() and check for existence)
  
- I suppose a common use case will be a getOrCreateCollection() that gets an
  existing one or creates it if it doesn't exist, would provide that right away.
  
- ResourceCollectionManager.deleteCollection() - agree with Bertrand, not 
needed.
  A getResource() on the collection interface would also make getName() and 
getPath()
  there obsolete. Maybe one could have the ResourceCollection extend from 
Resource?

- The ResourceCollectionManager is really only needed to create a new collection
  (get and delete can be done via adaptTo and Resource directly). That somewhat
  bloats API client code a bit, "only" getting the manager for creation. But 
  I don't know what is better - a static create method on ResourceCollection 
would
  break into the API and don't see other ways.
  Do we have any precedence in Sling with code like this, creating content
  structures on top of the resource API?

Implementation:

- ResourceCollectionManagerImpl.createCollection() could maybe use
  ResourceUtil.normalize() on the final concatenated path (solved if using 
Resource
  instead of path as argument)

- ResourceCollectionManagerImpl.getCollection relies on adaptTo() in 
getCollection()
  It is good practice to not rely on the adaptTo mechanism inside a bundle 
itself
  (for the classes that it provides itself). This can quickly run into a
  chicken-and-egg situation on startups/bundle activations, since the 
AdapterFactory
  of the bundle might get activated later than the bundle code being available,
  and then the adaptTo() returns null (had this case already, tricky to find).
  It's also a lot of intermediate steps through the whole adapter mechanism and 
also
  potentially allows another adapterfactory to jump in here and return 
something else.
  The "right" code to use instead is already inside the 
ResourceCollectionAdapterFactory.
  An AdapterFactory should only be seen as a helper on top of the bundle, not an
  integral part of the bundle's inner workings.
  
- ResourceCollectionAdapterFactory adapts to a collection only if the "members" 
child
  is present. IMHO the resource type should be enough. If there are no members 
yet, the
  node could be missing. Any code reading content should be very liberal in 
what it
  expects, and empty content should always work. So all writing methods should 
have
  a step in them to create the members node if not present yet.
  
- Resource type: ResourceCollectionAdapterFactory should use 
Resource.isResourceType() for
  the type/super type check.
  
  But ;-) I think we don't need to support super types as it's
  very unclear yet how an extended collection resource type would work (another 
collection
  API taking over? what would be added?). Explicitly not supporting extension 
feels
  safer to me for now - if that need comes up, it can still be added. This 
means:
  + adpterfactory: only match if rt == collection
  + create collection: force rt == collection (not allowing anything else to be 
set
    via the properties map); no need to check super type in the properties

                
      was (Author: alexander.klimetschek):
    Here's my review of the patch from the Star Wars day ;-)

Content Structure:

- my proposal, see below for discussion
  (legend: + = node, - = property, [nodetype])

  + <name> [nt:unstructured] # but node type should be free
      - sling:resourceType = "sling/collection"
      - key = "value" # collection-level metadata
      + thumbnail     # metadata with child resources/nodes
        - ...
      ...
      + members [nt:unstructured] # optional?
          - sling:resources = ["/one", "/two", "/three"]
          + member1 [nt:unstructured]
              - sling:resource = "/one"
              - key = "value" # reference-level metadata
              ...
          + member2
              - sling:resource = "/three"
              - key = "value"
              ...


- The node type on the collection node should not be restricted to allow
  custom metadata having child nodes with any type. For example, a child
  node of type nt:file would not work within a nt:unstructured. This
  requires the create collection API to allow for a node type being passed.
  Also we have a so-called replication mechanism for individual nodes that
  depends on certain node types, so in some case you might want this type
  and in others another one.

- I think the "members" node could be left out completely. Nesting of
  collections isn't really something that makes sense. Leaving it out
  has only the disadvantage that custom metadata that needs child resources
  cannot use any of the "member1", "member2" ... node names, instead of
  just "members" as an excluded name. For simple collections without any
  metadata this would truly optimize the structure to the minimum.
  But I am not fully decided on that.

- The properties should be namespaced, since they could overlap with custom
  properties. I guess "sling:" is the namespace to use.
  
- I would prefer naming the property "path" different, like "sling:resource" or
  "sling:reference". While the content of the property is a path now, it might
  be something else in the future (like a http url, uuid, etc.), and it
  actually addresses a resource or reference to a resource. "resource"
  would also be in line with the getResources() API name.
  
- Similarly, "pathorder" is a suboptimal name. It's not camel-cased and
  as above, "sling:resources" or "sling:references" sounds better. That it's
  ordered doesn't have to be included in the name.

- Moreover, I think that multi-value property should define the whole
  references list. So it would not be required that there is actually a
  child resource (entry) being present (applies to getEntries()) to
  return that resource in the list. The child resource would only be
  needed in case there are additional properties set.

API:

- ResourceCollection: For the implementation reading that list (getEntries())
  the point above would mean no need to iterate over the child resources at all.
  There needs to be some way to get the metadata, if there is some:
  + get properties for one reference
    ValueMap getProperties(String reference) or (Resource resource)
  + optional, to batch read everything:
    Iterator<Entry> getEntries()
    Entry = simple struct-like class with Resource (the referenced
            resource) and a ValueMap or ModifiableValueMap
  
- ResourceCollection.getEntries()
  I don't think if getEntries() separate from getResources() is really needed,
  as this exposes too much of the inner content structure in the API.
  As proposed above, I see an optimization here where there might not be
  actual child resources for every single reference defined in the array 
property.
  
- ResourceCollection.DEFAULT_SLING_RES_TYPE rename to simply RESOURCE_TYPE
  The "default" and "sling" in it is misleading; it is *the* rt for the 
ResourceCollection,
  and I guess it's rather unlikely that someone extends the resource collection 
rt,
  let alone being a central feature to be pointed out.
  
- ResourceCollectionManager methods should IMHO all be consistently based on
  passing Resource instead of path (makes e.g. the createCollection() 
implementation
  simpler in that it does not have to getResource() and check for existence)
  
- I suppose a common use case will be a getOrCreateCollection() that gets an
  existing one or creates it if it doesn't exist, would provide that right away.
  
- ResourceCollectionManager.deleteCollection() - agree with Bertrand, not 
needed.
  A getResource() on the collection interface would also make getName() and 
getPath()
  there obsolete. Maybe one could have the ResourceCollection extend from 
Resource?

- The ResourceCollectionManager is really only needed to create a new collection
  (get and delete can be done via adaptTo and Resource directly). That somewhat
  bloats API client code a bit, "only" getting the manager for creation. But 
  I don't know what is better - a static create method on ResourceCollection 
would
  break into the API and don't see other ways.
  Do we have any precedence in Sling with code like this, creating content
  structures on top of the resource API?

Implementation:

- ResourceCollectionManagerImpl.createCollection() could maybe use
  ResourceUtil.normalize() on the final concatenated path (solved if using 
Resource
  instead of path as argument)

- ResourceCollectionManagerImpl.getCollection relies on adaptTo() in 
getCollection()
  It is good practice to not rely on the adaptTo mechanism inside a bundle 
itself
  (for the classes that it provides itself). This can quickly run into a
  chicken-and-egg situation on startups/bundle activations, since the 
AdapterFactory
  of the bundle might get activated later than the bundle code being available,
  and then the adaptTo() returns null (had this case already, tricky to find).
  It's also a lot of intermediate steps through the whole adapter mechanism and 
also
  potentially allows another adapterfactory to jump in here and return 
something else.
  The "right" code to use instead is already inside the 
ResourceCollectionAdapterFactory.
  An AdapterFactory should only be seen as a helper on top of the bundle, not an
  integral part of the bundle's inner workings.
  
- ResourceCollectionAdapterFactory adapts to a collection only if the "members" 
child
  is present. IMHO the resource type should be enough. If there are no members 
yet, the
  node could be missing. Any code reading content should be very liberal in 
what it
  expects, and empty content should always work. So all writing methods should 
have
  a step in them to create the members node if not present yet.
  
- Resource type: ResourceCollectionAdapterFactory should use 
Resource.isResourceType() for
  the type/super type check.
  
  But ;-) I think we don't need to support super types as it's
  very unclear yet how an extended collection resource type would work (another 
collection
  API taking over? what would be added?). Explicitly not supporting extension 
feels
  safer to me for now - if that need comes up, it can still be added. This 
means:
  + adpterfactory: only match if rt == collection
  + create collection: force rt == collection (not allowing anything else to be 
set
    via the properties map); no need to check super type in the properties

                  
> Add ResourceCollection to Sling
> -------------------------------
>
>                 Key: SLING-2853
>                 URL: https://issues.apache.org/jira/browse/SLING-2853
>             Project: Sling
>          Issue Type: New Feature
>          Components: API
>    Affects Versions: API 2.0.2
>            Reporter: Amit Gupta
>            Priority: Minor
>         Attachments: collection.zip, resourcecollection.zip
>
>
> Creating a collection of resources has been a use case for a while and there 
> has been no inherent support in SLING for the same.
> This proposal is to add a ResourceCollection interface and implementation 
> that allows creation of collection of resources. 
> Collection is a simple list of members, where each member contains path of 
> resource it refers to. In future, we might need to store additional 
> information with the member, hence following structure is proposed
> N: resourceCollection (nt:unstructured)
>         + P: sling:resourceType
>         + N : members (nt:unstructured)
>             + N: member_res1  > nt:unstructured
>                 + P: path > string, reference to actual resource
>             + N: member_res2  > nt:unstructured
>                 + P: path > string, reference to actual resource

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to