How to get the path of the component instance under a page, that's invoking a servlet?

Avatar

Avatar

BHAVYA_S

Avatar

BHAVYA_S

BHAVYA_S

24-05-2018

Hi All,

Here's my requirement.

I have a component which is invoking the servlet via an Ajax call.

I would like to get the path of this component's instance under the page in the servlet.

1494189_pastedImage_0.png

If test is the page and comp1, comp2 are the instances of the same component dragged and dropped twice in the parsys called par,

I would like to get the path /content/test/jcr:content/par/comp1 in my servlet invoked from comp1, similarly /content/test/jcr:content/par/comp2 for comp2.

Alternatively, I am currently achieving this by using the resource HTL Global Object ${resource.path} in the JavaScript which gives the path of the current resource instance and passing it as a request parameter to the servlet.

But this is not admissible as I am trying to eliminate any query parameters being passed to the servlet due to caching constraints.

Is there a way to get path of the component instance under par which invokes the servlet at the back-end???

Please Help!!

Accepted Solutions (1)

Accepted Solutions (1)

Avatar

Avatar

Jörg_Hoh

Employee

Total Posts

3.0K

Likes

891

Correct Answer

1.0K

Avatar

Jörg_Hoh

Employee

Total Posts

3.0K

Likes

891

Correct Answer

1.0K
Jörg_Hoh
Employee

27-05-2018

Your requirement is quite easy to solve.

I assume that:

* the page is https://mycorp.com/content/mycorp/test.html

* and the servlet invoked is

** https://mycorp.com/bin/myservlet?comp=/content/mycorp/test/jcr:content/comp1 and

** https://mycorp.com/bin/myservlet?comp=/content/mycorp/test/jcr:content/comp2

and the servlet calls should be changed so the query string goes away.

Just change it in the way, that

* the page is https://mycorp.com/content/mycorp/test.html

* the servlet is called like this

** https://mycorp.com/content/mycorp/test/jcr:content/comp2.myservlet.json

** https://mycorp.com/content/mycorp/test/jcr:content/comp2.myservlet.json

And that's quite easy to achieve, because you have to bind the servlet as a selector to the resourcetype of "comp". The result is a perfectly cachable URL.

regards,

Jörg

Answers (13)

Answers (13)

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K
smacdonald2008

14-08-2018

Result of an AJAX CALL -

Page56.png

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K
smacdonald2008

14-08-2018

Joerg is correct - although the Sling Servlet docs say both ways are supported - Apache Sling :: Servlets and Scripts - Reg by Resource type is better practice.

When you build a Maven 13 archetype, it builds a servlet that is OOTB bound to the page that is created. For example - in a package named com.aem.community.core.servlets you will find  SimpleServlet.

For example- see this (I added "sling.servlet.selectors=" + "groups") :

@Component(service=Servlet.class,

           property={

                   Constants.SERVICE_DESCRIPTION + "=Simple Demo Servlet",

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

                   "sling.servlet.resourceTypes="+ "AEMMaven13/components/structure/page",

                   "sling.servlet.selectors=" + "groups"

           })

public class SimpleServlet extends SlingSafeMethodsServlet {

    private static final long serialVersionUid = 1L;

    @Override

    protected void doGet(final SlingHttpServletRequest req,

            final SlingHttpServletResponse resp) throws ServletException, IOException {

        final Resource resource = req.getResource();

        resp.setContentType("text/plain");

        resp.getWriter().write("COOL Title = " + resource.adaptTo(ValueMap.class).get("jcr:title"));

This is bound too this page:

Page55.png

Now you can call this Servlet by using this URL:

http://localhost:4502/content/AEMMaven13/en.groups.html

And you can use this same URL to invoke this SERVLET via an AJAX CALL (that is called when a button is clicked for example):

$(document).ready(function() {

   

    $('body').hide().fadeIn(5000);

          

$('#submit').click(function() {

    var failure = function(err) {

             alert("Unable to retrive data "+err);

   };

   

 

   var claimId = 0;

   

    //Use JQuery AJAX request to post data to a Sling Servlet

    $.ajax({

         type: 'GET',   

         url:'http://localhost:4502/content/AEMMaven13/en.groups.html',

         success: function(msg){

           var myMsg = msg;

 

 

            alert(myMsg);

 

         }

     });

  });

      

}); // end ready

Avatar

Avatar

Jörg_Hoh

Employee

Total Posts

3.0K

Likes

891

Correct Answer

1.0K

Avatar

Jörg_Hoh

Employee

Total Posts

3.0K

Likes

891

Correct Answer

1.0K
Jörg_Hoh
Employee

14-08-2018

see [1] for an example where the selector "tagwidget" is bound to all resource types; you might want to be more specific with the resource type.

[1] acs-aem-commons/TagWidgetConfigurationServlet.java at 763d2968169be1d86937bc1f4354cf2f8e201866 · Ado...

Avatar

Avatar

ekta_aggarwal

Avatar

ekta_aggarwal

ekta_aggarwal

25-05-2018

Hi,

You can register your servlet using resourceType and can get component path in your servlet using :

Avatar

Avatar

edubey

Total Posts

1.5K

Likes

264

Correct Answer

392

Avatar

edubey

Total Posts

1.5K

Likes

264

Correct Answer

392
edubey

24-05-2018

Ajax call in front end will be completely unware of component structure in AEM node.

You wil have to pass params.

One more, Even if you dont use params and  think of caching, Ideally your servlet response should not be cached else it will not execute again for another component.

Whats the use case?

Avatar

Avatar

Ratna_Kumar

MVP

Avatar

Ratna_Kumar

MVP

Ratna_Kumar
MVP

15-08-2018

Hey Scott,

This works very nicely. I have tested this code snippet and this works!! Below is the screenshot.

ItWorks.PNG

ItWorks!.PNG

Thanks,

Ratna Kumar.

Avatar

Avatar

rajeev_yadav

Avatar

rajeev_yadav

rajeev_yadav

14-08-2018

Thanks Scott & Jorge..

This code sample is really helpful.

Avatar

Avatar

rajeev_yadav

Avatar

rajeev_yadav

rajeev_yadav

13-08-2018

Hi Jorge,

Do you have any sample code for above approach?

Thanks,
Rajeev

Avatar

Avatar

Arun_Patidar

MVP

Total Posts

2.9K

Likes

958

Correct Answer

820

Avatar

Arun_Patidar

MVP

Total Posts

2.9K

Likes

958

Correct Answer

820
Arun_Patidar
MVP

25-05-2018

There is a way to achieve this by making call to Sling servlet (which is registered via resourcesType="componentPath") using java and get component path using request.getResource().getPath()

But this required credential to make a succesful request in Author, I think you can do it without credential(Authentication) in the Publish instance.

I don't know if this is feasible or not from your end but I am able to do it in my local instance.

Below is JS file which making kind a ajax call from component

// Server-side JavaScript for the ajax call

use(function () {

    var curRes = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+resource.getPath();

    var getVar = new Packages.org.apache.commons.httpclient.methods.GetMethod(curRes);

    var client = new Packages.org.apache.commons.httpclient.HttpClient();

   // Authentication part

    var creds = new Packages.org.apache.commons.httpclient.UsernamePasswordCredentials("admin", "admin");

     client.getParams().setAuthenticationPreemptive(true);

    client.getState().setCredentials(org.apache.commons.httpclient.auth.AuthScope.ANY, creds);

   // Authentication part end

    client.executeMethod(getVar);

});

Thanks

Arun Patidar

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K
smacdonald2008

25-05-2018

That will give you path to page - then you still need to figure out which component on the page sent the AJAX request.

Avatar

Avatar

BHAVYA_S

Avatar

BHAVYA_S

BHAVYA_S

24-05-2018

The actual requirement is cache a servlet response, which is returned by a third party rest-api. The url for this rest-api is fetched from the dialog proeprties of the component 'comp1'.

So, I was hoping if I could get the path of the component instance under par from which the servlet invoked, I can directly fetch the dialog property using PropertyIterator without having to pass query params to the servlet. It would help me cache the response, provided I have an extension for the  servlet path. And when the author changes the URL in the dialog for that particular component and activates the page, the dispatcher might invalidate the cache and invoke the servlet again to fetch fresh response.

@edubey

Yes I totally agree with your point. This would be the next challenge. Any suggestions?

I have tried considering registering it with resourceTypes, selectors, extension and suffix. But I cannot bind the servlet to a single page resource as I would be using this servlet on multiple pages through various components serving the same purpose. Also, we cannot use wildcards to define a regex for the selector value while registering a servlet.

Alternatively I have also tried dispatcher level configurations such as ignoreUrlParams, Mod Rewrite Rules and resource mapping using etc/maps/http. It doesn't seem to work for my requirement.

Any suggestions?

I'm clearly going forward based on trial and error method.

Kindly correct me if my understanding is wrong.

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Answer

2.3K
smacdonald2008

24-05-2018

What problem are you trying to solve by getting this path. I am trying to understand what value this  is within a web site.