Search code examples
javasling

Is there a better alternative to extending the SlingPostServlet?


In a Sling application, I want to ensure that nodes created with a particular sling:resourceType always have a child node created with specific properties. What way to achieve this conforms to best practice?

  1. Extending the SlingPostServlet class and adding functionality to add the child node within the doPost() method. This would appear a good fit since one could, on first glance, link the servlet to the specific resource type, and call super.doPost() to make use of the default SlingPostServlet processing. However, when installing the bundle, org.apache.sling.servlets.post.impl cannot be resolved (a similar problem was encountered by another user), which prevents the bundle from running at all.

  2. Creating a SlingPostProcessor and adding functionality within the process() method. This seems less desirable since it is not tied to one particular resource type.

  3. Using Sling Eventing.

I wanted to avoid extending SlingAllMethodsServlet, since it would be useful to maintain access to all the default functionality in SlingPostServlet. However, is it even possible to extend SlingPostServlet, rather than SlingAllMethodsServlet?


Solution

  • I don't think there is a simple solution to bind that behavior to a single resource Type. you will need to check the new resource and apply your changes if needed. I think the two best options are the SlingPostProcessor you mentioned and Resource observation.

    Resource observation allows you to 'listen' for changes in resources and perform any operation you might see fit.

    The implementation is fairly straight forward as well. Create a new OSGi service that implements the ResourceChangeListener interface and add some properties to filter what kind of changes you are interested in. This is similar to using JCR events and a job, but much more straight forward.

    The benefit of this is that this is independent on any post request. the drawback is that you need to use a new session to perform your changes. (You can use ResourceResolverFactory.getServiceResourceResolver)

    For example.

    @Component(property = {
        ResourceChangeListener.CHANGES + "=ADDED",
        ResourceChangeListener.PATHS + "=glob:/content/*",
    })
    public class ResourceObserver implements ResourceChangeListener {
    
      @Override
      public void onChange(@Nonnull List<ResourceChange> changes) {
          //go through the list of changes and do what you need to do.
      }
    }