Expand my Community achievements bar.

Enhance your AEM Assets & Boost Your Development: [AEM Gems | June 19, 2024] Improving the Developer Experience with New APIs and Events
SOLVED

OSGI R6 servlet paths list property

Avatar

Level 4

I am trying to use multiple paths in servlet. I am able to achieve this using below syntax:

@Component(service=Servlet.class,

name="Sample Servlet",

property={

"sling.servlet.methods=" + HttpConstants.METHOD_POST,

"sling.servlet.paths="+ "/bin/path1",

"sling.servlet.paths="+ "/bin/path2"

})

Is there a way to improve above annotation so that I don't have to define paths multiple time.Instead I should be able to set it as a list or with REGEX pattern?

I tried below syntax but seems it is not working:

@Component(service=Servlet.class,

name="Sample Servlet",

property={

"sling.servlet.methods=" + HttpConstants.METHOD_POST,

"sling.servlet.paths="+ "/bin/path*"

})

@Component(service=Servlet.class,

name="Sample Servlet",

property={

"sling.servlet.methods=" + HttpConstants.METHOD_POST,

"sling.servlet.paths="+ "[/bin/path1,/bin/path2]"

})

Please share the various options for above.

Thanks,
Rajeev

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

You clearly need to separate the client-side part from the server-side part. On the client-side you need to know which endpoint to call in what situation, but this is the case for both approaches. In your case I even wonder if you need to have 2 distinct URLs, but you should be able to handle the details of the submission based on request parameters.

You need to map a servlet to a Sling resource via the sling:resourceType property. Then you don't need to hardcode any path in the servlet annotations itself.

I don't know if you can combine path-based bindings and selectors/extensions (haven't tried it). But you can always use URL parameters with path-based bindings (and cacheability isn't a topic here).

But still, I recommend to use resourcetype-based binding. Because then your form can be self-contained in a way, that

GET /.../form.html

will render the form, while

POST /.../form.submission

will invoke the handling of the form submission. When you build the form, you don't need to hardcode any knowledge about other functions (like the path to the submission servlet) into the form rendering logic. Also if you annotate the form which kind of submission you want to use, this can be easily determined by the submission servlet. In most cases this means that all settings regarding the form and the submission logic applying to this specific form instance can and should be made on the form itself. Without any duplication.

(Maybe I should do a blog post about it ...)

View solution in original post

16 Replies

Avatar

Level 10

I have always used a static value for a path prop for a Servlet - which works well.  What benefit is there to try and use multiple values like this?

Avatar

Level 10

Hi Rajeev,

As Scott stated, please use the static value for path property. I don't see anywhere using multiple paths in sling servlet.

See this docs: Apache Sling :: Servlets and Scripts

Hope this helps!!

Thanks,

Ratna Kumar.

Avatar

Community Advisor

Hi Rajiv,

You can't use pattern while registering servlet using path or resourceType.

In case you want to use servlet for many paths Slings provide option to create default servlet.

Apache Sling :: Servlets and Scripts

but for this you need to use particular selector e.g.

  • model selector which convert all the request in JSON.
  • offline.doc selector+extension which converts page into doc
  • export.zip selector+extension which export page as zip.

You can do something like below

@Component(service=Servlet.class,

name="Sample Servlet",

property={

"sling.servlet.methods=" + HttpConstants.METHOD_POST,

"sling.servlet.resourceTypes="+ "sling/servlet/default",

"sling.servlet.selectors = mypathselector"

})

Thanks

Arun



Arun Patidar

Avatar

Level 4

We are trying to call single servlet as controller for 2 separate paths and then trying to delegate the request to appropriate service based on path from which the request came.

Thanks,

Rajeev

Avatar

Level 9

Hi Rajeev,

To differentiate multiple requests based on paths is one way to solve the problem, however, selectors or query parameter can serve the purpose.

Are the paths you are predicting not limited?

Avatar

Level 4

These paths are limited but I don't want to write "sling.servlet.paths" line for each path added for controller. I want to define it in an array or using regex.

Avatar

Level 4

Hi Arun,

Servlet  documents says that we can define array of paths.

A list of absolute paths under which the servlet is accessible as a Resource. The property value must either be a single String, an array of Strings or a Vector of Strings.

A servlet using this property might be ignored unless its path is included in the Execution Paths (servletresolver.paths) configuration setting of the SlingServletResolver service. Either this property or the sling.servlet.resourceTypes property must be set, or the servlet is ignored. If both are set, the servlet is registered using both ways.

I want to know how the array needs to be defined. I tried 2 approaches as stated in my original questions( array syntax & regex) and both are not working. Seems like there is something wrong in below array syntax for path. Can you please help me with correct array syntax in below example.

@Component(service=Servlet.class,

name="Sample Servlet",

property={

"sling.servlet.methods=" + HttpConstants.METHOD_POST,

"sling.servlet.paths="+ "[/bin/path1,/bin/path2]"

})

Avatar

Level 10

Got this working on the new MBEAN Article -- Creating Adobe Experience Manager 6.4 Sling Servlets that invoke MBean operations

@Component(service=Servlet.class,

        property={

                Constants.SERVICE_DESCRIPTION + "=Simple Count Servlet",

                "sling.servlet.methods=" + HttpConstants.METHOD_GET,

                "sling.servlet.paths="+ "/bin/myDataCount",

                "sling.servlet.paths="+ "/bin/myDataCount2"

           })

Both Paths invoked the Servlet. It looks like this is the only way - like you i tried other syntax and it did not work.

Avatar

Level 4

@smacdonald2008

This syntax worked for me too but array syntax is not working.

Avatar

Level 10

I verified that array syntax is not working. I used comma separated, etc,

The Sling Docs may be wrong. They  do not give any examples either.

If you want multiple paths - use the syntax that works.

Avatar

Level 4

Does same holds true for sling.servlet.methods?? If want to define array of methods?

Avatar

Level 10

I have never tried that. I would think so however - if you can define different paths - you should be able to define different sling.servlet.methods and then use both a GET or POST.

Avatar

Employee Advisor

That's not possible.

Also please be aware that binding servlets to paths is not best practice. For me it seems that you want to react differently based on the actual path, and that's an excellent usecase for "bind a servlet to a resourcetype"! (best practice btw)

Imagine, that you want to bind your servlet to

/content/countryA/endpoint

/content/countryB/endpoint

/content/countryC/endpoint

Then just create "endpoint" as nt:unstructured nodes and add a property "sling:resourcetype" with the value "myapp/endpoint" (you probably can come up with a better name). Then bind your servlet to that resource type "myapp/endpoint" and voila, everything works. Within the servlet you can use "request.getResource()" to get the "/content/countryX/endpoint" resource and react accordingly. It's even dynamic and you can limit access with ACLs on a JCR level.

Without knowing more about your usecase, that's a perfect match.

Jörg

Avatar

Level 4

Hi Jorg,

Below is the use case:

We have two identical forms  with slight differences. We want to call same servlet from both the forms. Both forms will use the common code in servlet and then will execute separate logic based on from which form the request was received. Eg. Form 1 might save data in cookie while form 2 may skip the logic of setting cookie.

Now in this case how can we map submit button click to servlet with resourcetype? I think path is the only option irrespective of whether the request is traditional form submission or ajax submission. Now if we use single path mapping in servlet then selectors and extensions can't be used as these are supported only for resourceTypes. Therefore we are trying to use different paths and then based on request path trying to execute separate logic.

Avatar

Correct answer by
Employee Advisor

You clearly need to separate the client-side part from the server-side part. On the client-side you need to know which endpoint to call in what situation, but this is the case for both approaches. In your case I even wonder if you need to have 2 distinct URLs, but you should be able to handle the details of the submission based on request parameters.

You need to map a servlet to a Sling resource via the sling:resourceType property. Then you don't need to hardcode any path in the servlet annotations itself.

I don't know if you can combine path-based bindings and selectors/extensions (haven't tried it). But you can always use URL parameters with path-based bindings (and cacheability isn't a topic here).

But still, I recommend to use resourcetype-based binding. Because then your form can be self-contained in a way, that

GET /.../form.html

will render the form, while

POST /.../form.submission

will invoke the handling of the form submission. When you build the form, you don't need to hardcode any knowledge about other functions (like the path to the submission servlet) into the form rendering logic. Also if you annotate the form which kind of submission you want to use, this can be easily determined by the submission servlet. In most cases this means that all settings regarding the form and the submission logic applying to this specific form instance can and should be made on the form itself. Without any duplication.

(Maybe I should do a blog post about it ...)

Avatar

Level 4

Hey Jorge,

This was really helpful. Having a separate blog for these scenarios would be a nice idea. I guess there are many who agrees to resource type mapping but need some reference it blog with example for this kind of scenario.

Thanks,

Rajeev