Halting program execution between certain hours of the week - java

I am writing a Java program that is required to copy files and folders between the following hours:
Mon - 18:00 to 06:30
Tue - 18:00 to 06:30
Wed - 18:00 to 06:30
Thu - 18:00 to 06:30
Fri - 18:00 to 06:30
Sat - all day
Sun - all day
The program will run continuously until it has finished copying all files and folders. However, outside of the above hours the program should just sleep.
I am using a properties file to store the above settings.
UPDATE
I am looking for the simplest possible implementation including the format of the properties in the properties file as well as the code that will make the checks.

I would do it like this
final Map<Integer, String> schedule = new HashMap<>();
// parse your settings and fill schedule
schedule.put(Calendar.MONDAY, "18:00 to 06:30");
// ...
// create timer to fire e.g. every hour
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
Calendar c = Calendar.getInstance();
String s = schedule.get(c.get(Calendar.DAY_OF_WEEK));
if (withinTimeRange(c, s)) { // implement withinTimeRange func
// copy files
}
}}, 0, 1000 * 3600);

Since your program is going to run continuously, the simplest solution is to check the day and time before copying a file. If the time is during off hours, go ahead and copy the next file, otherwise Thread.sleep.
If this is an internal, one-off kind of program, I would go ahead and hard-code the business hours instead of reading the properties file. No need to add complexity.

whenever your program is launched, get the current time, and check day today's day.
check whether it lies in permissible time if yes let it continue. If not, find the time at 00:00am of that 'day'. and find the time at xx:yyZZ (start of permissible time). calculate the difference, and let the program sleep for that much of time.

Thank you for your suggestions.
I came up with a working solution in the end which if it gets enough points I will mark as the answer. The way I attempted to solve this problem was by thinking about non-working hours rather than working hours. This code is just for illustration
# Properties
Mon = 06:30-18:00
Tue = 06:30-18:00
Wed = 06:30-18:00
Thu = 06:30-18:00
Fri = 06:30-18:00
Loop over the properties to get their values
String[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
Map<Integer, Integer[]> nonWorkingHours = new HashMap<Integer, Integer[]>();
for( int i = 0; i < days.length; i++ ) // for each property in file
{
// excluded implementation of getConfig
String prop = getConfig( days[ i ] ); // e.g. "06:00-19:00"
// +1 to match CALENDAR.DAY_OF_WEEK
nonWorkingHours.put( i + 1, getHours( prop );
}
My function to parse property excluding error handling
// e.g. if prop = "06:00-19:00" then { 6, 0, 19, 0 } is returned
public Integer[] getHours( String prop )
{
String times = prop.split( "(:|-)" );
Integer[] t = new Integer[4];
for( int i = 0; i < times.length; i++ )
{
t[i] = Integer.parseInt( times[i] );
}
return t;
}
And finally the function that implements the halt
private void sleepIfOutsideWorkingHours()
{
Integer[] data = nonWorkingHours.get( currentDay );
if( data != null )
{
Calendar c = Calendar.getInstance();
Integer currentSeconds = ( Calendar.HOUR_OF_DAY * 3600 ) + ( Calendar.MINUTE * 60 );
Integer stopFrom = ( data[ 0 ] * 3600 ) + ( data[ 1 ] * 60 );
Integer stopTill = ( data[ 2 ] * 3600 ) + ( data[ 3 ] * 60 );
if( currentSeconds > stopFrom && currentSeconds < stopTill )
{
Integer secondsDiff = stopTill - currentSeconds;
if( secondsDiff > 0 )
{
try
{
Thread.sleep( secondsDiff * 1000 ); // turn seconds to milliseconds
}
catch( InterruptedException e )
{
// error handling
}
}
}
}
}
And finally just call the function below just before copying each file and if it is being run outside working hours it will stop the program.
sleepIfOutsideWorkingHours();
I am sure there is a simpler way of doing it :-) but there it is.

You should try using a Continuous Integration system. That scenario can be easily set up using Jenkins CI for example.
The reason i advise doing it so in a ambient like that is that you can keep a better control on the history of your program runs.

Related

Quartz CronTrigger - fire time

I`m using quartz cron expression to build n schedule events, i have a start date and end date, but, when a crate a expression, the second event (getNextValidTimeAfter) its wrong...
08-03-19 08:00:00 -- first date
05-04-19 08:00:00 -- wrong date...
05-07-19 08:00:00
04-10-19 08:00:00
Follow the expression
0 0 8 ? 1/3 FRI#1 *
org.quartz.CronExpression expression = new org.quartz.CronExpression(cronExpression.getExpression());
List<Schedule> scheduleList = new ArrayList<>();
Date nextExecutionDate = cronExpression.getStartDate();
boolean first = true;
while (true) {
Schedule schedule = new Schedule();
schedule.setStatus(Enums.StatusSchedule.PROGRAMADO);
schedule.setCronExpression(cronExpression);
schedule.setServiceOrderType(cronExpression.getServiceOrderType());
schedule.setEstimatedTime(cronExpression.getEstimatedTime());
if (first == false)
nextExecutionDate = expression.getNextValidTimeAfter(nextExecutionDate);
else
first = false;
if (cronExpression.getEndDate().compareTo(nextExecutionDate) <= 0)
break;
schedule.setScheduleDate(nextExecutionDate);
if (CollectionUtils.isEmpty(schedule.getScheduleItems()))
schedule.setScheduleItems(new ArrayList<>());
for (GenericShelfData genericShelfData : genericShelfDataList) {
ScheduleItem scheduleItem = new ScheduleItem();
scheduleItem.setStatus(Enums.StatusSchedule.PROGRAMADO);
scheduleItem.setSchedule(schedule);
scheduleItem.setGenericShelfData(genericShelfData);
scheduleItem.setScheduleSeparate(Enums.YesOrNo.NAO);
schedule.getScheduleItems().add(scheduleItem);
}
scheduleList.add(schedule);
}
My expression was wrong... The correct is.. 0 0 8 ? 3/3 FRI#2 *
I use this site for build a expression: https://www.freeformatter.com/cron-expression-generator-quartz.html

Check if timestamp coming from DB is 2hrs ago or older

I want to compare a timestamp coming from db and see if it's 1 hr 59 minutes old or not,I have implemented the following code.Please review it and suggest changes:
private static final long TIME_LIMIT= 7199 * 1000;
private Token getTokenFromDB ()
{
InterfaceRequestResponseDAO.getInstance ().getEntityManager ().createNamedQuery (InterfaceRequestResponse.Queries.GET_TOKEN) //
.setParameter ("token", InterfaceRequestResponse.COL_RESPONSEEND)//
.setParameter ("interfaceRequestResponseID", this.getInterfaceRequestResponseID ())//
.executeUpdate ();
// authenticationToken.getResponseEnd ();
long responseEnd = System.currentTimeMillis ();
if (responseEnd < TIME_LIMIT)
return authenticationToken;
else
return NOT_VALID;
I suggest you to use JodaDate..
I implemented the same thing in a project. What I did was I saved the expire time instead of the timestamp created. This makes it more easy to handle.
Everytime I refresh the token, I update the expireTime by adding the offset
DateTime expireTime = new DateTime(new Date());
expireTime = expireTime.addHours(2);//because token expires in 2 hours
And then I store this time.
When I'm requesting, I used to check if the current time < expire time.
DateTime expireTime = getTimeFromDB();
DateTime now = new DateTime(new Date());
if( now.isBefore(expireTime))
{
//valid token.
}
else
{
// refresh your token and update the time.
}

MS Project showing incorrect start date and enddate

I'm using mpxj 4.5 to export ms project. When i open mpx file by ms project, I'm getting incorrect start date and finish date, but it's calculating duration correctly. What am i doing wrong, please tell.
To create mpx task I use following parametrs of mpxj:
public ProjectFile exportToMSProject(Integer projectID){
file.setAutoTaskID(true);
...........
}
private void createMSProjectTask(ProjectFile file, EUser user, ETask eTask)
Task task = file.addTask();
task.setUniqueID(eTask.getObjectID());
task.setName(eTask.getName());
task.setNotes(eTask.getDescription());
task.setType(TaskType.FIXED_DURATION);
long workTime = 0;
if(eTask.getDueDate() != null && eTask.getStartDate() != null){
workTime = (eTask.getDueDate().getTime() - eTask.getStartDate().getTime()) / (1000 * 60 * 60);
}
if(eTask.isAllDay()){
task.setDuration(Duration.getInstance(workTime / 24, TimeUnit.DAYS));
}else {
task.setDuration(Duration.getInstance(workTime, TimeUnit.HOURS));
}
if(eTask.getStartDate() != null)
task.setStart(user.getUserDate(eTask.getStartDate())); //get time from user time zone
if(eTask.getDueDate() != null)
task.setFinish(user.getUserDate(eTask.getDueDate()));
task.setPercentageComplete(eTask.getPercent() != null ? eTask.getPercent() : new Float(0.0));
if(eTask.getActualStartDate() != null)
task.setActualStart(eTask.getActualStartDate());
}
I'm getting repeatedly startdate and incorrect enddate. What is the problem here? Any suggestion will be appreciated.
I had the same issue. From my point of view, if you not have any predecessor or actual start date of your tasks, mpxj sets startdate automatically, I mean, it gets startdate from your project header or first task's start date of your project. That's why you got repeated startdate.
Here is the simple example (I'm using mpxj 4,5 and creating .mpx file):
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
ProjectFile file = new ProjectFile();
ProjectHeader header = file.getProjectHeader();
header.setStartDate(df.parse("01/05/2014"));
Task task1 = file.addTask();
task1.setName("Summary Task");
Task task2 = task1.addTask();
task2.setName("First Sub Task");
task2.setDuration(Duration.getInstance(10.5, TimeUnit.HOURS));
task2.setStart(df.parse("01/05/2014"));
task2.setPercentageComplete(NumberUtility.getDouble(50.0));
Task task3 = task1.addTask();
task3.setName("Second Sub Task");
task3.setStart(df.parse("11/05/2014"));
task3.setDuration(Duration.getInstance(10, TimeUnit.HOURS));
Task milestone1 = task1.addTask();
milestone1.setName("Milestone");
milestone1.setStart(df.parse("21/05/2014"));
milestone1.setDuration(Duration.getInstance(0, TimeUnit.HOURS));
Task task4 = file.addTask();
task4.setName("Last Task");
task4.setDuration(Duration.getInstance(8, TimeUnit.HOURS));
task4.setStart(df.parse("02/05/2014"));
task4.setPercentageComplete(NumberUtility.getDouble(70.0));
ProjectWriter writer = getWriter(filename);
writer.write(file, filename);
As you have seen, I'm not giving any predecessor or actual start date. If you run this you will get following result.
In order to get start date correctly, i gave an actual startdate not a startdate, and it worked. In addition if you have predecessor, you will get parent task's due date as a startdate.
task.setActualStart(df.parse("02/05/2014"));
By the way, ms project sets due date based on your duration.

Java7 GregorianCalendar timeInMillis from collection are not working well

I need to record a collection of objects that keep: Date, and average Day temperature.
and I need to be able to track back the date.
So I created a class that keeps these values and I made an ArrayList that keeps these objects.
In my code I test to keep 5 days. When I run the program and the ArrayList gets filled everything seems fine and the terminal displays:
dateSaved:2013-10-16 11:59:59 TimeStamp: 1381960799018
dateSaved:2013-10-17 11:59:59 TimeStamp: 1382047199018
dateSaved:2013-10-18 11:59:59 TimeStamp: 1382133599018
dateSaved:2013-10-19 11:59:59 TimeStamp: 1382219999018
These TimeStamps are all unique and seem to be fine.
however when I then enter the for loop and want to get the timestamps from each of these entries I get:
entry: 0 //removed since the first dateSaved has not been pasted*
entry: 1 timeInMillis: 1382306399018
entry: 2 timeInMillis: 1382306399018
entry: 3 timeInMillis: 1382306399018
entry: 4 timeInMillis: 1382306399018
These are all the same times and are: Sun, 20 Oct 2013 21:59:59 GMT
That is the date here. but not the time. And i'm not realy getting the values I expect to get.
What is going wrong here?
GregorianCalendar date = new GregorianCalendar();
GregorianCalendar beginDate = new GregorianCalendar();
beginDate.roll(beginDate.DAY_OF_YEAR ,-5);
while(beginDate.getTimeInMillis() < date.getTimeInMillis() )
{
GCalAndDouble dateAndTemp = new GCalAndDouble(beginDate, WeatherStation.Instance().getValue(Enums.MeasurementType.outsideTemperature, Enums.ValueType.average, beginDate) );
list.add(dateAndTemp);
System.out.println("dateSaved:" + new SimpleDateFormat("YYYY-MM-dd KK:mm:ss").format(new Timestamp(beginDate.getTimeInMillis())) + " TimeStamp: " + beginDate.getTimeInMillis() );
long timeTemp = beginDate.getTimeInMillis();
beginDate.setTimeInMillis(timeTemp + 86400000); // + the ammount of milliseconds in a day.
}
for(int j = 0; j < 5; j++)
{
GCalAndDouble tempdateandtemp = list.get(j);
long timestamptemp = tempdateandtemp.getDate().getTimeInMillis();
System.out.println("entry: " + j + " timeInMillis: " + timestamptemp);
}
Thanks for your help!
You are using the same beginDate object. This means that all the values will be the same. They might have changed as you were building the list, but the final value is all you will see.
Most likely you intended to create a new Date() object for each entry to give each one a different Date. BTW I prefer to use long which is not only more efficient but doesn't have this issue.

Google App Engine Query Execute only takes 3 arguments

Can anyone tell me why the following code is causing an error on the last line with the command "execute" with the error message:
The method execute(Object, Object, Object) in the type Query is not applicable for the arguments (Long, Long, Date, Date)
Query q = pm.newQuery(Appointment.class,"AdminID == AID"+
" && EmployeeID == CEID"+
" && Time > STime"+
" && Time < ETime");
q.declareImports("import java.util.Date");
q.declareParameters("Long AID, Long CEID, Date STime, Date ETime");
q.setOrdering("Time");
Appointments = (List<Appointment>) q.execute(AdminID, CurrentEmployeeID, Time1, Time2);
As far as I can tell (implied by the error message, the execute function can only take a maximum of 3 arguements, if this is the case, can anyone advise on how to achieve what I want to do? I have tried the following code, but I get a parsing error every time it runs!
Query q = pm.newQuery(Appointment.class,"AdminID == "+AdminID+
" && EmployeeID == "+CurrentEmployeeID+
" && Time > "+Time1+
" && Time < "+Time2);
q.declareImports("import java.util.Date");
q.setOrdering("Time");
Appointments = (List<Appointment>) q.execute();
The Parsing error I get is:
org.datanucleus.store.query.QueryCompilerSyntaxException: Portion of expression could not be parsed: Aug 13 11:44:55 BST 2012 && Time < Mon Aug 13 11:45:05 BST 2012
Try executeWithArray or executeWithMap.
HashMap<String, Object> params = new HashMap<String, Object>();
params.put( "AID", adminId );
params.put( "CEID", currentEmployeeId );
params.put( "STime", startTime );
params.put( "ETime", endTime );
query.executeWithMap( params );
Notes:
variables should be lowerCamelCase
startTime and endTime are more descriptive than Time1, Time2
"Id" is generally preferred over "ID" - What is correct Java naming convention for id?
your second attempt won't work because it's implicitly calling ..." && Time > " + Time1.toString() + ...

Categories