0

I have a server that handles requests, and with regular intervals (every 1-2 minutes) needs to call another server and update a list of objects that is used to create the response to the request. Inspired by for example the accepted answer for this question, I tried to use the Schedule annotation, but can't get it to work.

How to run a background task in a servlet based web application?

A simplified view of the server is:

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "MyServer", urlPatterns = {"/data/*", "/scheduled/*"}, loadOnStartup = 1)
public class MyServlet extends HttpServlet {

    private static final String UTF_8 = "UTF-8";
    private static final String APPLICATION_JSON = "application/json";
    private static final long serialVersionUID = 1L;
    private static connector connector;

    public MyServlet() {
        super();
    }

    public void destroy() {}

    @Override
    public void init() throws ServletException {
        connector = new connector();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = request.getServletPath();
        String pathInfo = request.getPathInfo().substring(1);
        response.setContentType(APPLICATION_JSON);
        response.setCharacterEncoding(UTF_8);

        if (path.endsWith("/data")) {
            List<DataItem> dataItems = connector.currentData;
            response.getWriter().write(JsonUtility.convertToJsonString(dataItems));
        } else if (path.endsWith("/scheduled")) {
            connector.fetchData();
            response.getWriter().write("Done");
        } else {
            response.getWriter()
            .write(pathInfo + " Is not Found but not returning 404");
            return;
        }
    }
}

The connector class that is supposed to update the stored data from the other server at regular intervals is:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

@Startup
@Singleton
public class Connector {
    public List<DataItem> currentData = new LinkedList<>();

    @Lock(LockType.READ)
    @Schedule(second = "*", minute = "*/2", hour = "*", persistent = false)
    public void fetchNews() {
        logger.debug("Fetching data");
        String response = sendGet(url, bearerToken);

        JsonObject json = new Gson().fromJson(response, JsonObject.class);
        //Transform the response to a list of DataItems.
        List<DataItem> retrievedData = toDataList(json)

        System.out.println(retrievedData);
        synchronized(currentData) {
            currentData = retrievedData;
        }

    }

    private String sendGet(String path, String authorizationProperty) {
        URL url;
        try {
            url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            conn.setRequestProperty("Authorization", authorizationProperty);
            conn.setRequestProperty("Content-Type","application/json");
            conn.setRequestMethod("GET");

            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            String output;

            StringBuffer response = new StringBuffer();
            while ((output = in.readLine()) != null) {
                response.append(output);
            }

            in.close();
            return response.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

However, the method fetchData is not firing every second minute as I was expecting. I don't know what I am missing. I have played around a bit with adding/removing the @Startup annotation, creating an instance of the class in the init() method on the server, but still have no result.

Mattias
  • 81
  • 11
  • What application server are you using? For example, Tomcat by itself can't run this type of code as it doesn't support EJB's. – stdunbar Sep 30 '19 at 19:24
  • Oh, Is that so? I don't think I was aware of that. I use Tomcat + Maven and added the depencies to javax.ejb. The code compiles, and I don't get any errors in the logs, so I just assumed it should work. I thought maven just added the required libraries in the war file. – Mattias Oct 01 '19 at 06:33
  • 2
    If you're generating a .war file try something like Wildfly to run this. Ultimately you need support from the container to run the EJB related code. – stdunbar Oct 01 '19 at 14:46

0 Answers0