/*
* Created on Apr 27, 2004
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package net.reliableresponse.notification.usermgmt;
import java.io.FileInputStream;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Vector;
import net.reliableresponse.notification.broker.BrokerFactory;
/**
* @author drig
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class OnCallGroup extends Group {
Vector onCallSchedules;
private static Hashtable cachedMonths;
static {
BrokerFactory.getLoggingBroker().logDebug("initializing month cache");
cachedMonths = new Hashtable();
}
public OnCallGroup() {
onCallSchedules = new Vector();
}
public int getType() {
return ONCALL;
}
public void addMember(Member member, int order) throws InvalidGroupException {
super.addMember(member, order);
flushCache();
}
public void addMembers(Member[] members) throws InvalidGroupException {
super.addMembers(members);
flushCache();
}
public void reloadMembers() {
super.reloadMembers();
flushCache();
}
public void removeMemberFromGroup(int memberNum) {
super.removeMemberFromGroup(memberNum);
flushCache();
}
private OnCallSchedule makeNewDefaultSchedule() {
OnCallSchedule schedule = new OnCallSchedule();
schedule.setAllDay(true);
schedule.setRepetition(OnCallSchedule.REPEAT_DAILY);
schedule.setRepetitionCount(1);
schedule.setFromDate(new Date());
schedule.setToDate(new Date());
schedule.setAllDay(true);
return schedule;
}
public void setOnCallSchedule(OnCallSchedule schedule, int memberNum) {
setOnCallSchedule(schedule, memberNum, true);
}
public void setOnCallSchedule(OnCallSchedule schedule, int memberNum, boolean flush) {
// If we get a member number that's higher than the currently set
// schedules, backfill w/ dummy data. Otherwise, we can't store the
// schedule in the vector
while (memberNum > onCallSchedules.size()) {
OnCallSchedule newSchedule = makeNewDefaultSchedule();
onCallSchedules.addElement(newSchedule);
BrokerFactory.getGroupMgmtBroker().setOnCallSchedule(newSchedule, this, onCallSchedules.size() - 1);
}
if (memberNum == onCallSchedules.size()) {
onCallSchedules.addElement(schedule);
} else {
onCallSchedules.setElementAt(schedule, memberNum);
}
if (flush)
flushCache();
if (autocommit) {
BrokerFactory.getGroupMgmtBroker().setOnCallSchedule(schedule, this, memberNum);
}
}
public OnCallSchedule[] getOnCallSchedules() {
OnCallSchedule[] schedules = new OnCallSchedule[members.size()];
for (int i = 0; i < schedules.length; i++) {
OnCallSchedule schedule = null;
if (i < onCallSchedules.size()) {
schedule = (OnCallSchedule) onCallSchedules.elementAt(i);
}
if (schedule == null) {
schedule = BrokerFactory.getGroupMgmtBroker().getOnCallSchedule(this, i);
}
if (schedule == null) {
schedule = makeNewDefaultSchedule();
}
setAutocommit(false);
setOnCallSchedule(schedule, i, false);
setAutocommit(true);
schedules[i] = schedule;
}
return schedules;
}
public Member[] getOnCallMembers(Date date) {
int monthInt = date.getMonth();
int yearInt = date.getYear();
Vector[][][] month = getMonth(monthInt, yearInt);
Vector members = month[date.getMinutes()][date.getHours()][date.getDate()];
if (members == null) {
return new Member[0];
}
return (Member[]) (members.toArray(new Member[0]));
}
private int daysInMonth(GregorianCalendar c) {
return c.getActualMaximum(GregorianCalendar.DATE);
}
private void flushCache() {
BrokerFactory.getLoggingBroker().logDebug("flushing month cache");
OnCallGroup.cachedMonths.clear();
}
/**
* This builds a month's representation of this oncall schedule. It will
* return who is on call for each [minute][hour][day]
*
* @param month
* The number of the month (January is 0, December is 11)
* @param year
* The number of the year
* @return An array representing the month's minutes/hours/days
*/
public Vector[][][] getMonth(int monthInt, int yearInt) {
Vector[][][] month = (Vector[][][]) OnCallGroup.cachedMonths.get(monthInt + "/" + yearInt);
if (month == null) {
month = innerGetMonth(monthInt, yearInt);
BrokerFactory.getLoggingBroker().logDebug("Adding month to cache");
OnCallGroup.cachedMonths.put(monthInt + "/" + yearInt, month);
}
return month;
}
private Vector[][][] innerGetMonth(int month, int year) {
BrokerFactory.getLoggingBroker().logDebug("inner get month for " + month + "/" + year);
// Check for the number of days in a month
GregorianCalendar calendarForCheckingDays = new GregorianCalendar(year, month + 1, 0);
// Create an initialize the representation
Vector<Member>[][][] representation = new Vector[60][24][daysInMonth(calendarForCheckingDays)];
for (int d = 0; d < representation[0][0].length; d++) {
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
representation[m][h][d] = new Vector();
}
}
}
Member[] members = getMembers();
OnCallSchedule[] schedules = getOnCallSchedules();
if (members == null) {
return representation;
}
// Loop through for each member
for (int memberNum = members.length - 1; memberNum >= 0; memberNum--) {
Member member = members[memberNum];
OnCallSchedule schedule = schedules[memberNum];
// This section figures out how much we skip for each increment
int repetitionDays = 0;
int repetitionMonths = 0;
if (schedule.getRepetition() == OnCallSchedule.REPEAT_DAILY) {
repetitionDays = schedule.getRepetitionCount();
} else if (schedule.getRepetition() == OnCallSchedule.REPEAT_WEEKLY) {
repetitionDays = schedule.getRepetitionCount() * 7;
} else if (schedule.getRepetition() == OnCallSchedule.REPEAT_MONTHLY_DATE) {
repetitionMonths = schedule.getRepetitionCount();
} else if (schedule.getRepetition() == OnCallSchedule.REPEAT_MONTHLY_DAY) {
repetitionMonths = schedule.getRepetitionCount();
}
Date from = schedule.getFromDate();
Date to = schedule.getToDate();
BrokerFactory.getLoggingBroker().logDebug("from=" + from + "\nto=" + to);
// Make sure the from is earlier than the to
if (to.compareTo(from) < 0) {
Date temp = (Date) to.clone();
to = (Date) from.clone();
from = (Date) temp.clone();
}
// This adjusts the to date, so that it doesn't match the time it
// ends on
// like, 9AM to 5PM really ends on 4:59:59 PM
to.setSeconds(to.getSeconds() - 1);
Date pointer = (Date) from.clone();
int daysBeforeBeginningOfMonth = 0;
if ((pointer.getMonth() != to.getMonth()) &&
(to.getYear() == year) &&
(to.getMonth() == month)) {
daysBeforeBeginningOfMonth = daysInMonth(new GregorianCalendar(from.getYear(), from.getMonth() + 1, 0)) - (pointer.getDate()-1);
pointer.setDate(1);
pointer.setMonth(to.getMonth());
pointer.setYear(to.getYear());
}
Date endPointer = (Date) to.clone();
BrokerFactory.getLoggingBroker().logDebug("starting pointer=" + pointer);
BrokerFactory.getLoggingBroker().logDebug("starting end pointer=" + endPointer);
// If there's no repetition, then we only need
// to do this part if the month matches
if ((schedule.getRepetitionCount() > 0) ||
((pointer.getMonth() == month) && (pointer.getYear() == year)) ||
((endPointer.getMonth() == month) && (endPointer.getYear() == year))
) {
// Actually do the skip until we're in the right year
while ((pointer.getYear() < year) && (endPointer.getYear() < year)) {
pointer.setDate(pointer.getDate() + repetitionDays);
pointer.setMonth(pointer.getMonth() + repetitionMonths);
endPointer.setDate(endPointer.getDate() + repetitionDays);
endPointer.setMonth(endPointer.getMonth() + repetitionMonths);
//BrokerFactory.getLoggingBroker().logDebug("pointer=" + pointer);
//BrokerFactory.getLoggingBroker().logDebug("end pointer=" + endPointer);
//BrokerFactory.getLoggingBroker().logDebug("pointer=" + pointer.getYear());
//BrokerFactory.getLoggingBroker().logDebug("end pointer=" + endPointer.getYear());
//BrokerFactory.getLoggingBroker().logDebug("year=" + year);
}
//BrokerFactory.getLoggingBroker().logDebug("pointer's year=" + pointer.getYear());
//BrokerFactory.getLoggingBroker().logDebug("end pointer's year=" + endPointer.getYear());
// Now move up to the right month
while ((pointer.getMonth() != month) && (endPointer.getMonth() != month) &&
(pointer.getYear() != year) && (endPointer.getYear() != year)) {
pointer.setDate(pointer.getDate() + repetitionDays);
pointer.setMonth(pointer.getMonth() + repetitionMonths);
endPointer.setDate(endPointer.getDate() + repetitionDays);
endPointer.setMonth(endPointer.getMonth() + repetitionMonths);
}
//BrokerFactory.getLoggingBroker().logDebug("pointer's month=" + pointer.getMonth());
//BrokerFactory.getLoggingBroker().logDebug("end pointer's month=" + endPointer.getMonth());
//BrokerFactory.getLoggingBroker().logDebug("pointer=" + pointer);
//BrokerFactory.getLoggingBroker().logDebug("end pointer=" + endPointer);
// We use this to figure out the distance, in days, between the
// start and end
int startLength = from.getDate();
int endLength = to.getDate();
if (endLength < startLength) {
BrokerFactory.getLoggingBroker().logDebug(
"from's month is "
+ daysInMonth(new GregorianCalendar(from.getYear(), from.getMonth() + 1, 0))
+ " days long");
endLength += daysInMonth(new GregorianCalendar(from.getYear(), from.getMonth() + 1, 0));
}
int numDays = endLength - startLength;
//BrokerFactory.getLoggingBroker().logDebug("schedule is " + numDays + " days long");
int monthsTimeYears = month+(year*12);
int pointerMonthsTimeYears = pointer.getMonth()+(pointer.getYear()*12);
// Now, fill in the month
while (pointerMonthsTimeYears <= monthsTimeYears) {
int d = pointer.getDate() - 1;
// Create the "from" pointer. This one will move
// towards the "to" pointer
Date fromPointer = (Date) pointer.clone();
fromPointer.setMinutes(from.getMinutes());
fromPointer.setHours(from.getHours());
// if the from is the previous month,
// like this goes from March 29 to April 10th,
// and we're looking at March
// this will set it to the 1st day of the month
if (fromPointer.getMonth() != month) {
fromPointer.setDate(1);
fromPointer.setMonth(month);
fromPointer.setYear(year);
fromPointer.setHours(0);
fromPointer.setMinutes(0);
fromPointer.setSeconds(0);
}
// This is the end-point. From will move towards To
Date toPointer = (Date) pointer.clone();
toPointer.setMinutes(to.getMinutes());
toPointer.setHours(to.getHours());
toPointer.setDate(toPointer.getDate() + numDays);
// Adjust for the times where the schedule started
// before the 1st of this month
toPointer.setDate(toPointer.getDate()-daysBeforeBeginningOfMonth);
// Adjust for a To date that is the next month.
// Like, this goes from March 29 to April 10th,
// and we're looking at April
// this will set it to the last day of the month
if (toPointer.getMonth() > month) {
toPointer.setMonth(month);
toPointer.setDate(daysInMonth(calendarForCheckingDays));
toPointer.setHours(23);
toPointer.setMinutes(59);
toPointer.setSeconds(59);
}
// Adjust for an all day schedule
// BrokerFactory.getLoggingBroker().logDebug("Is all day? "+schedule.isAllDay());
if (schedule.isAllDay()) {
pointer.setMinutes(0);
pointer.setHours(0);
pointer.setSeconds(0); // shouldn't be necessary
fromPointer.setHours(0);
fromPointer.setMinutes(0);
fromPointer.setSeconds(0); // shouldn't be necessary
toPointer.setHours(23);
toPointer.setMinutes(59);
toPointer.setSeconds(59); // shouldn't be necessary
}
//BrokerFactory.getLoggingBroker().logDebug("from pointer=" + fromPointer);
// From minutes and To minutes are the number of minutes
// into the
// day they are. Like 3AM is 180 minutes into the day.
int fromMinutes = (fromPointer.getHours() * 60) + fromPointer.getMinutes();
int toMinutes = (toPointer.getHours() * 60) + toPointer.getMinutes();
//BrokerFactory.getLoggingBroker().logDebug("fromMinutes=" + fromMinutes);
//BrokerFactory.getLoggingBroker().logDebug("toMinutes=" + toMinutes);
// This handles the case where the from is less than the
// to.
// The "normal" case, which is probably going to be
// around
// 50%
// of the time
// BrokerFactory.getLoggingBroker().logDebug("toMinutes="+toMinutes);
if (fromMinutes < toMinutes) {
/*
* BrokerFactory.getLoggingBroker().logDebug("fromTime="
* + fromPointer.getTime());
* BrokerFactory.getLoggingBroker
* ().logDebug("toTime="+toPointer.getTime());
* BrokerFactory
* .getLoggingBroker().logDebug("fromHour="+
* fromPointer.getHours());
* BrokerFactory.getLoggingBroker
* ().logDebug("toHour="+toPointer.getHours());
* BrokerFactory .getLoggingBroker().logDebug("fromMin="
* +fromPointer .getMinutes());
* BrokerFactory.getLoggingBroker().logDebug
* ("toMin="+toPointer.getMinutes());
*/
// start at From and move to To
//BrokerFactory.getLoggingBroker().logDebug("Filling in the minutes from "+fromPointer+" to "+toPointer);
while ((fromPointer.getTime() <= toPointer.getTime()) && (fromPointer.getMonth() == month)) {
if ((fromPointer.getHours() < toPointer.getHours())
|| ((fromPointer.getHours() == toPointer.getHours()) && (fromPointer.getMinutes() <= toPointer
.getMinutes()))) {
//if ((fromPointer.getHours() >= pointer.getHours())
// && (fromPointer.getMinutes() >= pointer.getMinutes())) {
// Actually mark the minute with the
// member
representation[fromPointer.getMinutes()][fromPointer.getHours()][fromPointer
.getDate() - 1].addElement(member);
//}
}
fromPointer.setMinutes(fromPointer.getMinutes() + 1);
}
}
// This handles the case where the To minutes is less
// than
// the From
// This handles in day-spanning cases. Like, the
// nightshift
// is 10PM to 6AM. From 10PM is later than To 6AM
// It does it in 2 steps, from midnight to the end, and
// from the start to midnight
else if (fromMinutes > toMinutes) {
while ((fromPointer.getTime() <= toPointer.getTime()) && (fromPointer.getMonth() == month)) {
//BrokerFactory.getLoggingBroker().logDebug("doing the nightshift case");
// Fill in from the "from" time to the end of the day
//BrokerFactory.getLoggingBroker().logDebug("filling from "+fromMinutes+" to "+(60*24));
for (int i = fromMinutes; i < (60 * 24); i++) {
representation[i % 60][i / 60][fromPointer.getDate() - 1].addElement(member);
}
// Fill in from the beginning of the day to the "to" time, but only if From isn't the last
// day of the month
if (daysInMonth(calendarForCheckingDays) > fromPointer.getDate()) {
for (int i = 0; i <= toMinutes; i++) {
representation[i % 60][i / 60][fromPointer.getDate()].addElement(member);
}
}
fromPointer.setDate(fromPointer.getDate() + 1);
}
}
//toPointer.setDate(toPointer.getDate() + 1);
pointer.setDate(pointer.getDate() + repetitionDays);
pointer.setMonth(pointer.getMonth() + repetitionMonths);
if ((repetitionDays <= 0) && (repetitionMonths <= 0)) {
pointer.setMonth(month + 1);
}
monthsTimeYears = month+(year*12);
pointerMonthsTimeYears = pointer.getMonth()+(pointer.getYear()*12);
}
}
}
return representation;
}
private Vector innerGetMembers(Member member, int day, int month, int year, int hours, int minutes, int count) {
Vector members = new Vector();
if (count > 20) return members;
if (member instanceof User) {
members.addElement(member);
return members;
} else {
Member[] groupsMembers = ((Group)member).getMembers();
for (int memberNum = 0; memberNum < groupsMembers.length; memberNum++) {
Member groupMember = groupsMembers[memberNum];
if (groupMember instanceof OnCallGroup) {
members.addAll(((OnCallGroup)groupMember).getIndividualMembers(day, month, year, hours, minutes));
}
members.addAll(innerGetMembers(groupMember, day, month, year, hours, minutes, count++));
}
}
return members;
}
public Vector getIndividualMembers(Date date) {
int day = date.getDate()-1;
int month = date.getMonth();
int year = date.getYear();
int hours = date.getHours();
int minutes = date.getMinutes();
return getIndividualMembers(day, month, year, hours, minutes);
}
public Vector getIndividualMembers(int day, int month, int year, int hours, int minutes) {
Vector members = new Vector();
Vector[][][] representation = getMonth(month, year);
if (day > representation[0][0].length) {
return members;
}
Vector daysMembers = representation[minutes][hours][day];
for (int memberNum = 0; memberNum < daysMembers.size(); memberNum++) {
Member member = (Member)daysMembers.elementAt(memberNum);
if (member instanceof User) {
members.addElement(member);
} else {
members.addAll(innerGetMembers(member, day, month, year, hours, minutes, 0));
}
}
return members;
}
public static void main(String[] args) throws Exception {
BrokerFactory.getConfigurationBroker().setConfiguration(new FileInputStream("conf/reliable.properties"));
OnCallGroup oc = (OnCallGroup) BrokerFactory.getGroupMgmtBroker().getGroupByName("oc");
System.out.print(oc.getIndividualMembers(new Date(109, 11, 28, 5, 59)));
/* for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m ++) {
System.out.print(new Date(2009, 11, 28, h, m));
System.out.print(oc.getIndividualMembers(new Date(2009, 11, 28, h, m)));
}
}
Vector[][][] representation = (oc).getMonth(11, 109);
for (int d = 0; d < representation[0][0].length; d++) {
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m ++) {
System.out.print(representation[m][h][d].size());
}
System.out.println ("\n");
}
System.out.println ("\n------------\n");
}
*/
}
}