I'm developing a web application using Spring-MVC (4.2.5) and Spring-Security (4.0.3). My issue is that I need a method which runs at set time intervals, such as every 30 seconds, but before it's executed I have to make sure that the user is logged in.
When the user submit login form, an HTTP request is send to an external server and, if the credentials are correct, an HTTP response containing a session token is returned.
The session token is fundamental for all other request, including the ones I want to forward within the timed method.
In my controller I can obtain the session token from the Spring Security Context, in every moment:
String token = SecurityContextHolder.getContext().getAuthentication().getDetails().toString();
I tried to use a scheduled task but unfortunately that doesn't work, because this is started at application launch, when there is no session and runs in a thread separated from the servlet container. The following exception is thrown:
GRAVE: Unexpected error occurred in scheduled task.
java.lang.NullPointerException
at service.RetrieveBettingOdds.retrieveMatchByNationality(RetrieveBettingOdds.java:54)
at tasks.OddsTask.run(OddsTask.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
because SecurityContextHolder.getContext() is null.
OddsTask
@Component
public class OddsTask {
@Autowired
private BettingService bettingService;
@Autowired
private MatchDao matchDao;
private List<Match> betfairMatches;
private List<Match> databaseMatches;
public void run() {
betfairMatches = new ArrayList<>();
databaseMatches = new ArrayList<>();
databaseMatches = matchDao.retrieveAllMatches();
for(Country country : Country.values()) {
betfairMatches = bettingService.retrieveMatchByNationality(country.name(), getCompetitionId(country.name()));
}
//cut code
}
RetrieveBettingOdds
@Service
public class RetrieveBettingOdds implements BettingService {
private static final String BETTING_END_POINT = "https://api.betfair.com/exchange/betting/json-rpc/v1";
private static final String APP_KEY = "my_app_key";
private String token;
@Override
public List<Match> retrieveMatchByNationality(String country, String competitionId) {
token = SecurityContextHolder.getContext().getAuthentication().getDetails().toString();
/**
* Cut the following code, in which I create an HTTP request including the token
**/
}
spring-mvc.xml
<bean id="oddsTask" class="tasks.OddsTask">
</bean>
<task:scheduler id="myScheduler" pool-size="10" />
<task:scheduled-tasks scheduler="myScheduler">
<task:scheduled ref="oddsTask" method="run"
fixed-delay="10000" initial-delay="60000" />
</task:scheduled-tasks>
What can I use instead? How can I fix it?