2
votes

I have this api i am trying to consume and this is the link https://www.live-rates.com/api/price?key=123456&rate=EUR_USD

I have tried this in my controller

@ResponseBody
    @RequestMapping(value = { "/start" }, method = RequestMethod.GET)
    public String start() { 
RestTemplate restTemplate = new RestTemplate();

        String quote = restTemplate.getForObject("https://www.live-rates.com/api/price?key=123456&rate=EUR_USD", String.class);
        return quote.toString();
    }

and this in my scheduling program

package com.boilerplate.components;


import java.util.Date;
import org.slf4j.Logger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Async;

import com.boilerplate.services.MessageListenerService;
import java.util.Random;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

@Repository
@Transactional
@Configuration
@EnableAsync
@EnableScheduling
public class Scheduler {
//Database read and update and delete
    @Autowired
    private RabbitTemplate rabbitTemplate;

    private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(MessageListenerService.class);

    @Autowired 
    private SessionFactory sessionFactory;

    @Async
    @Scheduled(cron="*/60 * * * * *")
    public void doSomething(){

        RestTemplate restTemplate = new RestTemplate();

        String quote = restTemplate.getForObject("https://www.live-rates.com/api/price?key=123456&rate=EUR_USD", String.class);
        LOGGER.info(quote.toString());

  }


    }

and they all fail to get the exchange rate.

I get this error when using the scheduler

SEVERE: Unexpected error occurred invoking async method 'public void com.boilerplate.components.Scheduler.doSomething()'. org.springframework.web.client.HttpClientErrorException: 403 Forbidden at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:641) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:264) at com.boilerplate.components.Scheduler.doSomething(Scheduler.java:53) at com.boilerplate.components.Scheduler$$FastClassBySpringCGLIB$$17802b05.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.lang.Thread.run(Thread.java:748)

and this when using the controller

HTTP ERROR 500

Problem accessing /boilerplate/start. Reason:

Server Error

Caused by:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 403 Forbidden at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:979) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858) at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:800) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)

I have tried consuming other json apis like https://jsonplaceholder.typicode.com/posts/1 and i can get the json without any problem.

Why cant i get the exchange rate using the rest template.

3

3 Answers

4
votes

Did you try adding below code. You are trying to invoke with HTTPS.

CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); String quote = restTemplate.getForObject("https://www.live-rates.com/api/price?key=123456&rate=EUR_USD", String.class);

1
votes

You don't need to use @Async with your @Scheduled annotation. The scheduler will run on it's own thread anyways. Of course, one or more running scheduler will run sequentially, but that can be change. For your case though, regarding the documentation, it seems that, you might have to provide your restTemplate via dependency injection. So, @Autowire could do the trick. Documentation, section 27.4.2.

Notice that the methods to be scheduled must have void returns and must not expect any arguments. If the method needs to interact with other objects from the Application Context, then those would typically have been provided through dependency injection.

So, removing the @Async and adding the dependency injection of restTemplate could do the trick.

In case you need to know how to run multiple schedulers in different threads, you could check this answer.

0
votes

Unrelated to original question, but if the variable 'quote' is already of type 'String' why do you need to call the method 'toString()' on it?