1

I have a requirement where I need to take a copy of some of my files and put that to the internal server. This need to happen periodically, something like at 8 PM every day. This is a Swing application as well, running in my local PC. I know I can schedule a task using Java, either by using java.util.Time, JodaTime or even better Quartz Scheduler.

But, here comes the issue. No one is going to keep the computer turn on for 24 hours just for this scheduler. And as far as I know, if someone restarted the PC, the Java schedulers will die too. Instead once the task is scheduled, if the computer is turned on, the scheduled task should happen everyday at 8PM without a human interaction. That means, no need to restart the application again and re-schedule.

This feature I described is very common, can be seen in all the Virus guards, windows based alarms etc. But how can I achieve the same in Java? For the moment if I have to use a windows specific solution like using JNI or some hack with batch files etc (I am using windows), that is also fine.

At least is this is possible with java?

PeakGen
  • 21,894
  • 86
  • 261
  • 463
  • Why not make the application run on startup? – Thomas Nairn May 15 '15 at 15:21
  • @ThomasNairn: Quartz scheduler dies when the machine is shut down. I don't know how this happens with GUI, but I have seen this happening in web servers. – PeakGen May 15 '15 at 15:22
  • But if the application is running in the background. (setVisible(false);) you can reschedule or even just monitor the time using a simple thread? – Thomas Nairn May 15 '15 at 15:23
  • What if the computer is still down at the given time? Either way, you need an OS level tool (or equivalently, something that can persist tasks and is launched at startup), something like `cron` for example. – biziclop May 15 '15 at 15:24
  • @biziclop: If the computer is down, no matter. No copies. – PeakGen May 15 '15 at 15:25
  • @ThomasNairn: Idea is good, but doubt about it.. – PeakGen May 15 '15 at 15:27
  • It's your only option other than working with native code. – Thomas Nairn May 15 '15 at 15:29
  • @ThomasNairn: Will consider as the last option, as I will have to reschedule the quartz. However, how to start the application on startup? and making it `setVisible(false)` could be a huge issue because then the will not be able to see it even he open it manually. – PeakGen May 15 '15 at 15:31
  • https://docs.oracle.com/javase/tutorial/uiswing/misc/systemtray.html Is what I used in one of my applications, bear in mind that when you start the application, you could always use arguments to determine whether the user opened the application or the system did. – Thomas Nairn May 15 '15 at 15:33
  • You need to run some kind of service that is on all the time the computer is on. The service needs to be able to persist tasks given to it. Alternatively you can say that you don't mind the tasks only running when your application is launched by the user, in that case it's your application's responsibility to persist each task when scheduled, and remove it from the persisted storage when the task is completed. – biziclop May 15 '15 at 15:34
  • @ThomasNairn: Can we monitor whether the app is started by system or by user? how? `systemtray` link is interesting... – PeakGen May 15 '15 at 15:35
  • @JustCause `public static void main(String[] args) {` https://docs.oracle.com/javase/tutorial/essential/environment/cmdLineArgs.html You can have the application started by a batch script? – Thomas Nairn May 15 '15 at 15:37
  • @ThomasNairn: Yea that is the other issue. Starting the app automatically. I can't ask the user to run the app by manually clicking a batch or manually scheduling it in windows scheduler. You know how to do this? – PeakGen May 15 '15 at 15:39
  • @JustCause http://www.computerhope.com/issues/ch000322.htm Do some research. – Thomas Nairn May 15 '15 at 15:40
  • @ThomasNairn: I need to do that task programatically. – PeakGen May 15 '15 at 15:41
  • @JustCause Then do some research. I believe it can be done by copying a file to a directory. I'm not going to spoon-feed you. – Thomas Nairn May 15 '15 at 15:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77916/discussion-between-thomas-nairn-and-justcause). – Thomas Nairn May 15 '15 at 15:43
  • @ThomasNairn: I didn't ask for a spoon feed. I asked the way of executing the batch using Java. – PeakGen May 15 '15 at 15:44
  • @ThomasNairn: However your comments make more sense. Please provide as an answer. – PeakGen May 15 '15 at 15:47

2 Answers2

3

In order to schedule and keep an application scheduled (In Java) after restart is to have the Java application restart and schedule again.

Have the application run on startup: Run Java application at Windows startup and then reschedule.

Community
  • 1
  • 1
Thomas Nairn
  • 1,186
  • 8
  • 34
1

The Answer by Nairn is correct. Here is detail about coding to set the schedule once you have restarted the Java app.

ScheduledExecutorService

If using the ScheduledExecutorService interface to schedule you recurring task, one of the arguments is initialDelay. You specify the amount of time to wait until the first occurrence of your task. After that one-time delay, then your task is scheduled to reoccur after every amount of time specified by another argument, period.

So after every restart, you compare the current moment to the moment desired for that first run. The span of time in between is the amount you specify as the initialDelay argument.

First get the current moment.

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

Set the time-of-day you desire (target) on the same day.

LocalTime target = LocalTime.of( 20 , 0 );
ZonedDateTime then = ZonedDateTime.of( now.toLocalDate() , target , z );

Check to see if that time-of-day today has already past. If past, add a day to get to the day after.

if ( ! then.isAfter( now ) ) {  // If already past our target of 8 PM today, move to tomorrow.
    then = then.plusDays( 1 );
}

Calculate the span of time (Duration) between now and that future moment when we want to run the first occurance of our task.

Duration initialDelay = Duration.between( now ; then );

Specify how often we want to run this task (period) as a Duration object.

Duration period = Duration.ofHours( 24 );

Translate our pair of Duration objects to some number of minutes or seconds or milliseconds or whatever granularity you desire. Keep in mind that your task does not at the exact split-second you desire. Your task may be delayed for reasons such as scheduling of the thread’s execution or because the next run of your task is waiting for the previous run to complete. So I suspect TimeUnit.SECONDS or even minutes is a fine-enough granularity for a daily task.

myScheduledExecutorService.scheduleAtFixedRate( 
    myRunnable , 
    initialDelay.getSeconds() , 
    period.getSeconds() , 
    TimeUnit.SECONDS 
) ; 

To recap:

  • The initialDelay is the span of time used once after your app restarts, to schedule the first run of your task.
  • The period is the span of time used in repeatedly running your task.
Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154