javaweb-servicesscheduled-tasksplayframework-2.5onstart

How can I call a function on start and periodically on Playframework 2.5


I need to make a WS petition when I start play so I can log in a external service to obtain a token. I need that token for make future petitions. I know how to make WS petitions, I don't know where to place that code to execute on start. At this time, it is in a function of a controller.

If you want some code of this:

// login data
  ObjectNode tvdbaccount = Json.newObject();
  tvdbaccount.put("apikey", "*****");
  tvdbaccount.put("username", "*****");
  tvdbaccount.put("userkey", "*****");

  // try to login
  String token = "";
  CompletionStage<JsonNode> request = WS.url("https://api.thetvdb.com/login")
                                        .post(tvdbaccount)
                                        .thenApply(WSResponse::asJson);

  try {
    JsonNode response = request.toCompletableFuture()
                               .get(5, TimeUnit.SECONDS);

    token = response.get("token").asText();
  } catch (Exception ex) {
    System.out.println(ex.getMessage());
  }

That token expires after 24 hours so I want for example to call a function every 12 hours that refreshes that token. That function is similar to the previous one, it's only a WS petition.

I'm using playframework 2.5 where GlobalSettings is deprecated and I see multiple answers not very clear for 2.5 so I fail to get it done.


Solution

  • Thanks to Alexander B, I've been able to get what I wanted.

    Eager Singleton

    I resolved the on start function call with the eager singleton.

    What I've done is a class for the TVDB things and the important part is to write what you want to do on start inside the constructor of this class. And then to bind it on a module:

    bind(TVDB.class).asEagerSingleton();
    

    Akka actors

    For the periodically function call I used an Akka actor.

    I've implemented an actor which calls itself every 12 hours, so I placed the scheduling code in the same actor on the preStart void. I think the Playframework documentation for the Scheduling asynchronous tasks isn't updated and doesn't work the way it is (at least for me).

    Then, I binded it on the module:

    bindActor(TVDBActor.class, "TVDBActor");
    

    If someone need the actor code here it is:

    public class TVDBActor extends UntypedActor {
    
      @Inject
      public void preStart(final ActorSystem system, @Named("TVDBActor") ActorRef tvdbActor) {
        system.scheduler().schedule(
          Duration.create(12, TimeUnit.HOURS),
          Duration.create(12, TimeUnit.HOURS),
          tvdbActor,
          "tick",
          system.dispatcher(),
          null
        );
      }
    
      @Override
      public void onReceive(Object msg) throws Exception {
        TVDB.refreshToken();
      }
    
    }