Expand my Community achievements bar.

Call a servlet (GET request) from Sling model

Avatar

Level 2

All,

 

I have a deployed servlet in AEM that returns JSON result from external endpoint.

My use case is to call this servlet deployed in AEM with a GET request from a sling model (same AEM instance) to get this json result.

The issue is that its working in localhost but in Azure environements AEM instances i am getting a timeout on calling the servlet.

I tried changing the lib for requesting the servlet (HttpConnection, HttpClient, Jsoup, ...) but still i am getting a timeout.

When calling directly the path of the servlet without passing in the different environmnt i am getting correctly the JSON response.

My thoughts that AEM instance in (dev, stage) environments is blocking the internal call to the servlet (/bin/tests/test).

 

PS:

- i have tried using directly publish ip adress to avoid the dispatcher but i get the same issue.

- an OSGI Service istead of the servlet is working but i still need the use of servlet for caching the query and result easily.

 

Any idea of the cause and a possible solution ?

 

Best regards,

 

12 Replies

Avatar

Community Advisor

Hi @dopamine7, in my opinion you should not call servlet from your sling model - I think this is not a good practice. Instead if you need to run some operation from servlet and sling model you can extract your logic into separate class i.e. OSGi service and use it in all other classes. This should eliminate situation when you're calling servlet from sling model directly. If I good understand what you need is data from external service that are currently exposed by your servlet. You can try to refactor you code like below.

 

@Component(name = "OSGi service with your logic", service = MyService.class)
public class YourService {

    // place for your service methods that will run business logic
    public void doSomething(String param1, String param2) {
        // ...
    }

    //...
}
@Component(service = Servlet.class, property = {
        "sling.servlet.methods=GET", "sling.servlet.paths=/bin/path/to/your/servlet"})
public class YourServlet extends SlingSafeMethodsServlet {

    @Reference
    private transient YourService yourService;

    @Override
    protected void doGet(final SlingHttpServletRequest request, final SlingHttpServletResponse response) {
        yourService.doSomething(param1, param2);
        // ...
    }

    // ...
}
@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class YourSlingModel {

    @OSGiService
    private YourService yourService;

    // ...
}

 

As you can see above approach assure separation between business logic and classes where you need to access results provided by business logic class.

Avatar

Level 2

i need to use only the servlet from the sling model, they are no needs to request it seperately. The need from the use of the servlet is for caching the query and response easily.

I already tried passing by an OSGI Service and it works already but i have to implement a specific cache service to handle it which it complicate it for my use case.

It would be appreciable staying with the servlet call from the sling model to facilitate the caching

Avatar

Community Advisor

So just be clear - by cache you mean cache on dispatcher, right? How you are using data on sling model, and sling model itself. Did you consider instead of using servlet accessible by path to correlate it with specific resource type i.e. the same as sling model and add some selector? This potentially could eliminate need of calling servlet from sling model, and in the same time to use servlet in general and dispatcher cache.

Avatar

Level 2

yes i mean dispatcher cache, to be clear :

Assuming that servlet path is : /bin/tests/test

SlingModel gets contribution from component (City : madrid) -> sends a  GET Request to sling servlet (/bin/tests/test.madrid.json) -> The servlet call an endpoint and receive a json response -> SlingModel uses that response 

Avatar

Community Advisor

So the city value is manually configured by author, right? And you including this as a selector in your servlet request.

 

I am going into direction that if in the end the content on the page is static, maybe as alternative you can cache the page with results of your component, this will also allow you to easily invalidate the cache. This will allow you to use osgi service reference instead of servlet call, and you still can benefit from using dispatcher cache.

Avatar

Level 2

Yes, the city is contribuated via a content fragment inside the component.

The issue of that is that we have to cache the entire page because it contains other dynamic components that we don't need to cache.

Thank u again for ur responses and time

Avatar

Employee Advisor

@dopamine7 I agree to what @lukasz-m says and its not a good practice to call a servlet from a model.
The approach mentioned using service makes more sense and however, you can achieve the same functionality by using the service. Calling a servlet inside a model is a dirty implementation to me.

Avatar

Level 2

The timeout could be due to the performance of the query you are using to warm up your cache in the Azure Environments.

Avatar

Level 2

Please check the Query Performance/Easy Query in Operations Cosole. 

Avatar

Level 1

Hi dopamine7,

Have you found out solution of the problem? I am in the same boat as you, I need to call another servlet in my servlet code (they are in the same AEM instance), I use 

HttpURLConnection and pass user name/password to access another servlet which I don't have choice since that servlet is from another package. It works fine in my local, but get the exception: connect time out in our Dev system. We use Adobe Managed Services (AWS servers)
You also mentioned "When calling directly the path of the servlet without passing in the different environmnt i am getting correctly the JSON response.", could you explain what is the url you use?
 
Thanks!