Java tutorial
/* * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * The Apereo Foundation licenses this file to you under the Educational * Community License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the * License at: * * http://opensource.org/licenses/ecl2.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sakaiproject.signup.tool.jsf.organizer.action; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.StringUtils; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.signup.logic.SakaiFacade; import org.sakaiproject.signup.logic.SignupEmailFacade; import org.sakaiproject.signup.logic.SignupMeetingService; import org.sakaiproject.signup.logic.SignupUserActionException; import org.sakaiproject.signup.logic.messages.SignupEventTrackingInfoImpl; import org.sakaiproject.signup.model.MeetingTypes; import org.sakaiproject.signup.model.SignupAttachment; import org.sakaiproject.signup.model.SignupAttendee; import org.sakaiproject.signup.model.SignupMeeting; import org.sakaiproject.signup.model.SignupTimeslot; import org.sakaiproject.signup.tool.jsf.TimeslotWrapper; import org.sakaiproject.signup.tool.jsf.attachment.AttachmentHandler; import org.sakaiproject.signup.tool.jsf.organizer.UserDefineTimeslotBean; import org.sakaiproject.signup.tool.util.Utilities; import org.sakaiproject.signup.util.SignupDateFormat; import org.springframework.dao.OptimisticLockingFailureException; /** * <p> * This class will provide business logic for modifying meeting action * by organizer. * </P> */ public class EditMeeting extends SignupAction implements MeetingTypes { private int maxNumOfAttendees; private boolean showAttendeeName; private int currentNumberOfSlots; private int timeSlotDuration; private boolean unlimited; // private int totalEventDuration;// for group/announcement types private SignupMeeting originalMeetingCopy; private String signupBeginsType; /* singup can start before this minutes/hours/days */ private int signupBegins; /*True means that the current recurring events have already start_Now Type*/ private boolean isStartNowTypeForRecurEvents = false; private boolean signupBeginModifiedByUser; private String deadlineTimeType; /* singup deadline before this minutes/hours/days */ private int deadlineTime; private boolean convertToNoRecurrent; private List<SignupMeeting> savedMeetings; private String recurringType = null; // may not used private Date firstRecurMeetingModifyDate = null; private Date lastRecurMeetingModifyDate = null; private List<SignupAttachment> currentAttachList; private List<SignupAttachment> needToCleanUpAttachInContentHS = new ArrayList<SignupAttachment>(); private List<SignupAttachment> attachsForFutureRecurrences = new ArrayList<SignupAttachment>(); private AttachmentHandler attachmentHandler; /*keep the final user-modified ts-list*/ private List<TimeslotWrapper> customTimeSlotWrpList = null; private boolean userDefinedTS = false; private UserDefineTimeslotBean userDefineTimeslotBean; private List<SignupTimeslot> toBedeletedTSList = null; private SakaiFacade sakaiFacade; private boolean createGroups; private String coordinators; private boolean sendEmailByOwner; //it make sure not running this job multiple times private boolean hasProcessedSyn_createGroups_job = false; public EditMeeting(String userId, String siteId, SignupMeetingService signupMeetingService, AttachmentHandler attachmentHandler, boolean isOrganizer) { super(userId, siteId, signupMeetingService, isOrganizer); this.attachmentHandler = attachmentHandler; } public void saveModifiedMeeting(SignupMeeting meeting) throws Exception { handleVersion(meeting); /* * give a warning to user and for announcement type no update is * required */ if (!unlimited && this.maxNumOfAttendees < originalMeetingCopy.getMaxNumberOfAttendees()) { Utilities.addErrorMessage( Utilities.rb.getString("max.num_attendee_changed_and_attendee_mayOver_limit_inTS")); } logger.info("Meeting Name:" + meeting.getTitle() + " - UserId:" + userId + " - has modified the meeting at meeting time:" + SignupDateFormat.format_date_h_mm_a(meeting.getStartTime())); if (getMaxNumOfAttendees() > this.originalMeetingCopy.getMaxNumberOfAttendees()) logger.info("Meeting Name:" + meeting.getTitle() + " - UserId:" + userId + this.signupEventTrackingInfo.getAllAttendeeTransferLogInfo()); /*cleanup unused attachments*/ if (needToCleanUpAttachInContentHS != null) { for (SignupAttachment one : needToCleanUpAttachInContentHS) { getAttachmentHandler().removeAttachmentInContentHost(one); } } } /* * give it a number of tries to update the event/meeting object into DB * storage if this still satisfy the pre-condition regardless some changes * in DB storage */ public void handleVersion(SignupMeeting meeting) throws Exception { for (int i = 0; i < MAX_NUMBER_OF_RETRY; i++) { try { this.signupEventTrackingInfo = new SignupEventTrackingInfoImpl(); /* * TODO current eventTracking is not working for multiple * recurring meetings. It's a bit more complex and need modify * the SignupEventTrackingInfoImpl object or other way. * Currently, no email are sent out to newly promoted people for * multiple recurring meetings. */ this.signupEventTrackingInfo.setMeeting(meeting); //reset it this.toBedeletedTSList = null; List<SignupMeeting> sMeetings = prepareModify(meeting); signupMeetingService.updateModifiedMeetings(sMeetings, this.toBedeletedTSList, true); //signupMeetingService.updateMSignupMeetings(sMeetings, this.toBedeletedTSList, true); setSavedMeetings(sMeetings);// for email & postCalendar purpose return; } catch (OptimisticLockingFailureException oe) { // don't do any thing } } throw new SignupUserActionException(Utilities.rb.getString("edit.failed_due_to_other_updated_db")); } private SignupMeeting reloadMeeting(SignupMeeting meeting) { return signupMeetingService.loadSignupMeeting(meeting.getId(), userId, siteId); } /* put the modification into right place */ private List<SignupMeeting> prepareModify(SignupMeeting userModifiedMeeting) throws Exception { List<SignupMeeting> upTodateOrginMeetings = null; List<SignupMeeting> newlyModifyMeetings = new ArrayList<SignupMeeting>(); Long recurrenceId = userModifiedMeeting.getRecurrenceId(); if (recurrenceId != null && recurrenceId.longValue() > 0 && !isConvertToNoRecurrent()) { /* only update the future recurring meeting now now today */ upTodateOrginMeetings = signupMeetingService.getRecurringSignupMeetings(siteId, userId, recurrenceId, new Date()); retrieveRecurrenceData(upTodateOrginMeetings); } else { SignupMeeting upTodateOrginMeeting = reloadMeeting(userModifiedMeeting); upTodateOrginMeetings = new ArrayList<SignupMeeting>(); upTodateOrginMeetings.add(upTodateOrginMeeting); } /* * Since recurring meetings are identical by title, location, etc. only * the corresponding one to original one will be checked here. */ /* * If someone has changed it before you,it should be caught by versionId * since meetings are saved as a bulk. */ SignupMeeting upToDateMatchOne = getCorrespondingMeeting(upTodateOrginMeetings, userModifiedMeeting); checkPreCondition(upToDateMatchOne, upTodateOrginMeetings); Calendar calendar = Calendar.getInstance(); int recurNum = 0; //initialize to-be-removed TS list for advanced user-defined cases this.toBedeletedTSList = new ArrayList<SignupTimeslot>(); for (SignupMeeting upTodateOrginMeeting : upTodateOrginMeetings) { SignupMeeting newlyModifyMeeting = upTodateOrginMeeting; /* * set event starting time for calendar due to multiple-recurring * meetings */ long startTimeChangeDiff = userModifiedMeeting.getStartTime().getTime() - getOriginalMeetingCopy().getStartTime().getTime(); calendar.setTimeInMillis(upTodateOrginMeeting.getStartTime().getTime() + startTimeChangeDiff); /* pass user changes */ passModifiedValues(userModifiedMeeting, calendar, newlyModifyMeeting, recurNum); recurNum++; newlyModifyMeetings.add(newlyModifyMeeting); } return newlyModifyMeetings; } private void passModifiedValues(SignupMeeting modifiedMeeting, Calendar calendar, SignupMeeting newlyModifyMeeting, int recurNum) throws Exception { //for Group title synch purpose boolean hasMeetingTitleChanged = false; if (!newlyModifyMeeting.getTitle().equals(modifiedMeeting.getTitle())) { hasMeetingTitleChanged = true; } newlyModifyMeeting.setTitle(modifiedMeeting.getTitle()); newlyModifyMeeting.setLocation(modifiedMeeting.getLocation()); newlyModifyMeeting.setCategory(modifiedMeeting.getCategory()); newlyModifyMeeting.setCreatorUserId(modifiedMeeting.getCreatorUserId()); newlyModifyMeeting.setStartTime(calendar.getTime()); newlyModifyMeeting.setDescription(modifiedMeeting.getDescription()); newlyModifyMeeting.setLocked(modifiedMeeting.isLocked()); newlyModifyMeeting.setCanceled(modifiedMeeting.isCanceled()); newlyModifyMeeting.setReceiveEmailByOwner(modifiedMeeting.isReceiveEmailByOwner()); newlyModifyMeeting.setAllowWaitList(modifiedMeeting.isAllowWaitList()); newlyModifyMeeting.setAllowComment(modifiedMeeting.isAllowComment()); newlyModifyMeeting.setAutoReminder(modifiedMeeting.isAutoReminder()); newlyModifyMeeting.setEidInputMode(modifiedMeeting.isEidInputMode()); newlyModifyMeeting.setAllowAttendance(modifiedMeeting.isAllowAttendance()); newlyModifyMeeting.setCreateGroups(modifiedMeeting.isCreateGroups()); newlyModifyMeeting.setMaxNumOfSlots(modifiedMeeting.getMaxNumOfSlots()); newlyModifyMeeting.setSendEmailByOwner(isSendEmailByOwner()); newlyModifyMeeting.setCoordinatorIds(getCoordinators()); /*new attachments changes*/ if (this.currentAttachList != null) { updateWithOrigalAttachments(newlyModifyMeeting, this.currentAttachList, recurNum);//what to do with recurrence } if (newlyModifyMeeting.getMeetingType().equals(INDIVIDUAL) && !isUserDefinedTS()) { List<SignupTimeslot> timeslots = newlyModifyMeeting.getSignupTimeSlots(); /* add increased time slots */ int newAddTs = getCurrentNumberOfSlots() - timeslots.size(); for (int i = 0; i < newAddTs; i++) { SignupTimeslot newTs = new SignupTimeslot(); newTs.setMaxNoOfAttendees(maxNumOfAttendees); newTs.setDisplayAttendees(showAttendeeName); timeslots.add(newTs); } int rownum = 1; for (SignupTimeslot timeslot : timeslots) { timeslot.setMaxNoOfAttendees(maxNumOfAttendees); timeslot.setDisplayAttendees(showAttendeeName); timeslot.setStartTime(calendar.getTime()); calendar.add(Calendar.MINUTE, timeSlotDuration); timeslot.setEndTime(calendar.getTime()); if (!newlyModifyMeeting.isAllowWaitList()) { timeslot.setWaitingList(null); } //create the groups for the timeslots, if enabled //this also loads the groupId into the timeslot object to be saved afterwards if (isCreateGroups() && !this.hasProcessedSyn_createGroups_job) { logger.error("Timeslot groupId: " + timeslot.getGroupId()); boolean justCreated = false; //if we don't already have a group for this timeslot, or the group has been deleted, create a group and set into timeslot if (StringUtils.isBlank(timeslot.getGroupId()) || !sakaiFacade .checkForGroup(sakaiFacade.getCurrentLocationId(), timeslot.getGroupId())) { logger.error("Need to create a group for timeslot... "); String title = generateGroupTitle(newlyModifyMeeting.getTitle(), timeslot, rownum); String description = generateGroupDescription(newlyModifyMeeting.getTitle(), timeslot); String groupId = sakaiFacade.createGroup(sakaiFacade.getCurrentLocationId(), title, description, null); logger.error("Created group for timeslot: " + groupId); timeslot.setGroupId(groupId); justCreated = true; } //Synch the group title with new meeting title if (hasMeetingTitleChanged && !justCreated) { //use case: if the group title has been changes via Site-Info tool by removing GROUP_PREFIX : "SIGNUP_", //it will be not synch any more for that group. String newTitle = generateGroupTitle(newlyModifyMeeting.getTitle(), timeslot, rownum); boolean success = this.sakaiFacade.synchonizeGroupTitle(sakaiFacade.getCurrentLocationId(), timeslot.getGroupId(), newTitle); if (!success) { Utilities.addErrorMessage(Utilities.rb.getString("error.no.change.group.title")); } } } rownum++; } if (isCreateGroups()) { //JUST NEED TO RUN ONECE, the sequential recurrence meetings need not to create/sync groups again. this.hasProcessedSyn_createGroups_job = true; } } /*process user custom-defined timeslot blocks*/ if (newlyModifyMeeting.getMeetingType().equals(CUSTOM_TIMESLOTS) || isUserDefinedTS()) { List<SignupTimeslot> timeslots = newlyModifyMeeting.getSignupTimeSlots(); UserDefineTimeslotBean uBean = getUserDefineTimeslotBean(); if (uBean == null || !uBean.MODIFY_MEETING.equals(uBean.getPlaceOrderBean())) { throw new SignupUserActionException( MessageFormat.format(Utilities.rb.getString("you.have.multiple.tabs.in.browser"), new Object[] { ServerConfigurationService.getServerName() })); } uBean.modifyTimesSlotsWithChanges(this.customTimeSlotWrpList, timeslots, calendar, showAttendeeName, toBedeletedTSList); if (recurNum == 0) { /*TODO currently we only notify attendee for the first event at recurrence * Need implementation for recurrence case*/ notifyAttendeeIndeleteTimeslots(toBedeletedTSList); } newlyModifyMeeting.setMeetingType(CUSTOM_TIMESLOTS); /*for end time purpose*/ int duration = getUserDefineTimeslotBean().getEventDuration(); calendar.add(Calendar.MINUTE, duration); } if (newlyModifyMeeting.getMeetingType().equals(GROUP)) { List<SignupTimeslot> signupTimeSlots = newlyModifyMeeting.getSignupTimeSlots(); SignupTimeslot timeslot = signupTimeSlots.get(0); timeslot.setStartTime(newlyModifyMeeting.getStartTime()); calendar.add(Calendar.MINUTE, getTimeSlotDuration()); timeslot.setEndTime(calendar.getTime()); timeslot.setDisplayAttendees(showAttendeeName); int maxAttendees = (unlimited) ? SignupTimeslot.UNLIMITED : maxNumOfAttendees; timeslot.setMaxNoOfAttendees(maxAttendees); if (!newlyModifyMeeting.isAllowWaitList()) { timeslot.setWaitingList(null); } } if (newlyModifyMeeting.getMeetingType().equals(ANNOUNCEMENT)) { calendar.add(Calendar.MINUTE, getTimeSlotDuration()); } /* * Promoting waiter to attendee status if max size increased and is * allowed */ if (maxNumOfAttendees > originalMeetingCopy.getMaxNumberOfAttendees()) { promotingWaiters(newlyModifyMeeting); } // set up meeting end time newlyModifyMeeting.setEndTime(calendar.getTime()); /* setup sign-up begin / deadline */ setSignupBeginDeadlineData(newlyModifyMeeting, getSignupBegins(), getSignupBeginsType(), getDeadlineTime(), getDeadlineTimeType()); /* This can happen only once to promote recurring meeting to stand-alone */ if (isConvertToNoRecurrent()) { newlyModifyMeeting.setRecurrenceId(null); } if (newlyModifyMeeting.getRecurrenceId() != null) { newlyModifyMeeting.setRepeatType(getRecurringType()); newlyModifyMeeting.setRepeatUntil(getLastRecurMeetingModifyDate()); } } private void notifyAttendeeIndeleteTimeslots(List<SignupTimeslot> toBedeletedTSList) { for (SignupTimeslot timeslot : toBedeletedTSList) { List<SignupAttendee> attendees = timeslot.getAttendees(); if (attendees != null && !attendees.isEmpty()) { for (SignupAttendee attendee : attendees) { signupEventTrackingInfo.addOrUpdateAttendeeAllocationInfo(attendee, timeslot, SignupEmailFacade.SIGNUP_ATTENDEE_CANCEL, true); } } } } private SignupMeeting getCorrespondingMeeting(List<SignupMeeting> upTodateOrginMeetings, SignupMeeting modifyMeeting) { for (SignupMeeting sm : upTodateOrginMeetings) { if (sm.getId().equals(modifyMeeting.getId())) return sm; } return null; } /* Promoting all possible waiters to attendee status */ private void promotingWaiters(SignupMeeting modifiedMeeting) { List<SignupTimeslot> timeSlots = modifiedMeeting.getSignupTimeSlots(); if (timeSlots == null || timeSlots.isEmpty()) return; for (SignupTimeslot timeslot : timeSlots) { List attList = timeslot.getAttendees(); int maxNumOfAttendees = timeslot.getMaxNoOfAttendees(); if (attList == null) continue;// nobody on wait list for sure if (attList.size() < maxNumOfAttendees) { int availNum = maxNumOfAttendees - attList.size(); for (int i = 0; i < availNum; i++) { promoteAttendeeFromWaitingList(modifiedMeeting, timeslot); } } } } /* * Check if there is any update in DB before this one is saved into DB * storage. */ private void checkPreCondition(SignupMeeting upTodateMeeting, List<SignupMeeting> upTodateOrginMeetings) throws SignupUserActionException { if (upTodateMeeting == null || !originalMeetingCopy.getTitle().equals(upTodateMeeting.getTitle()) || !originalMeetingCopy.getLocation().equals(upTodateMeeting.getLocation()) || !StringUtils.equals(originalMeetingCopy.getCategory(), upTodateMeeting.getCategory()) || !StringUtils.equals(originalMeetingCopy.getCreatorUserId(), upTodateMeeting.getCreatorUserId()) || originalMeetingCopy.getStartTime().getTime() != upTodateMeeting.getStartTime().getTime() || originalMeetingCopy.getEndTime().getTime() != upTodateMeeting.getEndTime().getTime() || originalMeetingCopy.getSignupBegins().getTime() != upTodateMeeting.getSignupBegins().getTime() || originalMeetingCopy.getSignupDeadline().getTime() != upTodateMeeting.getSignupDeadline() .getTime() /* TODO more case to consider here */ || !originalMeetingCopy.getMeetingType().equals(upTodateMeeting.getMeetingType()) || !((originalMeetingCopy.getRecurrenceId() == null && upTodateMeeting.getRecurrenceId() == null) || (originalMeetingCopy.getRecurrenceId() != null && originalMeetingCopy.getRecurrenceId().equals(upTodateMeeting.getRecurrenceId()))) || originalMeetingCopy.getNoOfTimeSlots() != upTodateMeeting.getNoOfTimeSlots() || originalMeetingCopy.getMaxNumOfSlots().intValue() != upTodateMeeting.getMaxNumOfSlots() .intValue() || originalMeetingCopy.isSendEmailByOwner() != upTodateMeeting.isSendEmailByOwner() //|| originalMeetingCopy.getCoordinatorIds() !=null && !originalMeetingCopy.getCoordinatorIds().equals(upTodateMeeting.getCoordinatorIds()) || !((originalMeetingCopy.getDescription() == null && upTodateMeeting.getDescription() == null) || (originalMeetingCopy.getDescription() != null && upTodateMeeting.getDescription() != null) && (originalMeetingCopy.getDescription().length() == upTodateMeeting .getDescription().length())) || checkAttachmentsChanges(upTodateMeeting) || checkAdvancedUserDefinedTSCase(originalMeetingCopy, upTodateMeeting, upTodateOrginMeetings)) { throw new SignupUserActionException(Utilities.rb.getString("someone.modified.event.content")); } } private boolean checkAdvancedUserDefinedTSCase(SignupMeeting originalMeetingCopy, SignupMeeting upTodateMeeting, List<SignupMeeting> upTodateOrginMeetings) throws SignupUserActionException { if (!upTodateMeeting.getMeetingType().equals(CUSTOM_TIMESLOTS) && !isUserDefinedTS()) { return false; } List<SignupTimeslot> origTSList = originalMeetingCopy.getSignupTimeSlots(); /*any unexpected events with timeslots changes on one of the recurrences * for example, one TS is deleted via DB by other somehow. * It happens very rarely and just for data integrity issue*/ if (origTSList != null) { int numOf_ts = origTSList.size(); for (SignupMeeting upMeeting : upTodateOrginMeetings) { if (numOf_ts != upMeeting.getNoOfTimeSlots()) { throw new SignupUserActionException( "One of the recurring event has been modified without synchronization with others! " + "You have to disassociate it from the recurring events. The event starting date:" + upMeeting.getStartTime().toLocaleString()); } } } /*any changes by others*/ List<SignupTimeslot> upTodateTSList = upTodateMeeting.getSignupTimeSlots(); if (origTSList != null && upTodateTSList != null) { for (SignupTimeslot oTS : origTSList) { if (oTS.getId() == null) continue; boolean found = false; for (SignupTimeslot uTS : upTodateTSList) { if (oTS.getId().equals(uTS.getId())) { found = true; if (oTS.getMaxNoOfAttendees() != uTS.getMaxNoOfAttendees()) { /*one of the TS Max# has been changed by others */ return true; } if (oTS.getStartTime().getTime() != uTS.getStartTime().getTime() || (oTS.getEndTime().getTime() != uTS.getEndTime().getTime())) { return true; } break; } } if (!found) { return true;//one TS is deleted or replaced by others } } return false; } return true;//any unexpected case } private boolean checkAttachmentsChanges(SignupMeeting latestOne) { //TODO excluding attendee's attachment??? List<SignupAttachment> latestList = getEventMainAttachments(latestOne.getSignupAttachments()); List<SignupAttachment> orignalAttachList = getEventMainAttachments( this.originalMeetingCopy.getSignupAttachments()); if (latestList.isEmpty() != orignalAttachList.isEmpty()) { return true; } if (latestList.size() != orignalAttachList.size()) { return true; } for (int i = 0; i < latestList.size(); i++) { Date latest = latestList.get(i).getLastModifiedDate(); Date orignal = orignalAttachList.get(i).getLastModifiedDate(); if (!latest.equals(orignal)) return true; } return false; } /** * setup the event/meeting's signup begin and deadline time and validate it * too */ private void setSignupBeginDeadlineData(SignupMeeting meeting, int signupBegin, String signupBeginType, int signupDeadline, String signupDeadlineType) throws Exception { Date sBegin = Utilities.subTractTimeToDate(meeting.getStartTime(), signupBegin, signupBeginType); Date sDeadline = Utilities.subTractTimeToDate(meeting.getEndTime(), signupDeadline, signupDeadlineType); boolean origSignupStarted = originalMeetingCopy.getSignupBegins().before(new Date());// ???? /* TODO have to pass it in?? */ if (!START_NOW.equals(signupBeginType) && sBegin.before(new Date()) && !origSignupStarted) { // a warning for user Utilities.addErrorMessage( Utilities.rb.getString("warning.your.event.singup.begin.time.passed.today.time")); } if (!isSignupBeginModifiedByUser() && this.isStartNowTypeForRecurEvents) { /*do nothing and keep the original value since the Sign-up process is already started * No need to re-assign a new start_now value*/ } else { meeting.setSignupBegins(sBegin); } if (sBegin.after(sDeadline)) throw new SignupUserActionException(Utilities.rb.getString("signup.deadline.is.before.signup.begin")); meeting.setSignupDeadline(sDeadline); } public int getCurrentNumberOfSlots() { return currentNumberOfSlots; } public void setCurrentNumberOfSlots(int currentNumberOfSlots) { this.currentNumberOfSlots = currentNumberOfSlots; } public int getDeadlineTime() { return deadlineTime; } public void setDeadlineTime(int deadlineTime) { this.deadlineTime = deadlineTime; } public String getDeadlineTimeType() { return deadlineTimeType; } public void setDeadlineTimeType(String deadlineTimeType) { this.deadlineTimeType = deadlineTimeType; } public int getTimeSlotDuration() { return timeSlotDuration; } public void setTimeSlotDuration(int timeSlotDuration) { this.timeSlotDuration = timeSlotDuration; } public int getMaxNumOfAttendees() { return maxNumOfAttendees; } public void setMaxNumOfAttendees(int maxNumOfAttendees) { this.maxNumOfAttendees = maxNumOfAttendees; } public SignupMeeting getOriginalMeetingCopy() { return originalMeetingCopy; } public void setOriginalMeetingCopy(SignupMeeting originalMeetingCopy) { this.originalMeetingCopy = originalMeetingCopy; } public boolean isShowAttendeeName() { return showAttendeeName; } public void setShowAttendeeName(boolean showAttendeeName) { this.showAttendeeName = showAttendeeName; } public int getSignupBegins() { return signupBegins; } public void setSignupBegins(int signupBegins) { this.signupBegins = signupBegins; } public String getSignupBeginsType() { return signupBeginsType; } public void setSignupBeginsType(String signupBeginsType) { this.signupBeginsType = signupBeginsType; } /* * public int getTotalEventDuration() { return totalEventDuration; } * * public void setTotalEventDuration(int totalEventDuration) { * this.totalEventDuration = totalEventDuration; } */ public boolean isUnlimited() { return unlimited; } public void setUnlimited(boolean unlimited) { this.unlimited = unlimited; } public boolean isConvertToNoRecurrent() { return convertToNoRecurrent; } public void setConvertToNoRecurrent(boolean convertToNoRecurrent) { this.convertToNoRecurrent = convertToNoRecurrent; } public List<SignupMeeting> getSavedMeetings() { return savedMeetings; } private void setSavedMeetings(List<SignupMeeting> savedMeetings) { this.savedMeetings = savedMeetings; } public List<SignupAttachment> getCurrentAttachList() { return currentAttachList; } public void setCurrentAttachList(List<SignupAttachment> currentAttachList) { this.currentAttachList = currentAttachList; } public AttachmentHandler getAttachmentHandler() { return attachmentHandler; } public boolean isSignupBeginModifiedByUser() { return signupBeginModifiedByUser; } public void setSignupBeginModifiedByUser(boolean signupBeginModifiedByUser) { this.signupBeginModifiedByUser = signupBeginModifiedByUser; } private void retrieveRecurrenceData(List<SignupMeeting> upTodateOrginMeetings) { /*to see if the recurring events have a 'Start_Now' type already*/ this.isStartNowTypeForRecurEvents = Utilities.testSignupBeginStartNowType(upTodateOrginMeetings); String repeatType = upTodateOrginMeetings.get(0).getRepeatType(); if (repeatType != null && !ONCE_ONLY.equals(repeatType)) { int lSize = upTodateOrginMeetings.size(); setLastRecurMeetingModifyDate(upTodateOrginMeetings.get(lSize - 1).getStartTime()); setRecurringType(repeatType); return; } /*The following code is to make it old version backward compatible*/ setFirstRecurMeetingModifyDate(null); setLastRecurMeetingModifyDate(null); if (upTodateOrginMeetings == null || upTodateOrginMeetings.isEmpty()) return; setFirstRecurMeetingModifyDate(upTodateOrginMeetings.get(0).getStartTime()); /* in case: it's the last one */ setLastRecurMeetingModifyDate(upTodateOrginMeetings.get(0).getStartTime()); int listSize = upTodateOrginMeetings.size(); if (listSize > 1) { setLastRecurMeetingModifyDate(upTodateOrginMeetings.get(listSize - 1).getStartTime()); Calendar calFirst = Calendar.getInstance(); Calendar calSecond = Calendar.getInstance(); /* * we can only get approximate estimation by assuming it's a * succession */ calFirst.setTime(upTodateOrginMeetings.get(listSize - 2).getStartTime()); calFirst.set(Calendar.SECOND, 0); calFirst.set(Calendar.MILLISECOND, 0); calSecond.setTime(upTodateOrginMeetings.get(listSize - 1).getStartTime()); calSecond.set(Calendar.SECOND, 0); calSecond.set(Calendar.MILLISECOND, 0); int tmp = calSecond.get(Calendar.DATE); int daysDiff = (int) (calSecond.getTimeInMillis() - calFirst.getTimeInMillis()) / DAY_IN_MILLISEC; if (daysDiff == perDay) setRecurringType(DAILY); else if (daysDiff == perWeek) setRecurringType(WEEKLY); else if (daysDiff == perBiweek) setRecurringType(BIWEEKLY); else if (daysDiff == 3 && calFirst.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) setRecurringType(WEEKDAYS); } } private Date getFirstRecurMeetingModifyDate() { return firstRecurMeetingModifyDate; } private void setFirstRecurMeetingModifyDate(Date firstRecurMeetingModifyDate) { this.firstRecurMeetingModifyDate = firstRecurMeetingModifyDate; } private Date getLastRecurMeetingModifyDate() { return lastRecurMeetingModifyDate; } private void setLastRecurMeetingModifyDate(Date lastRecurMeetingModifyDate) { this.lastRecurMeetingModifyDate = lastRecurMeetingModifyDate; } private String getRecurringType() { return recurringType; } private void setRecurringType(String recurringType) { this.recurringType = recurringType; } private void updateWithOrigalAttachments(SignupMeeting sMeeting, List<SignupAttachment> currentAttachList, int recurNum) { List<SignupAttachment> upToDateList = sMeeting.getSignupAttachments(); if (upToDateList == null) upToDateList = new ArrayList<SignupAttachment>(); if (currentAttachList == null) currentAttachList = new ArrayList<SignupAttachment>(); /*case: original one has no attachments*/ if (upToDateList.isEmpty()) { for (SignupAttachment curAttach : currentAttachList) { upToDateList.add(getAttachmentHandler().copySignupAttachment(sMeeting, true, curAttach, ATTACH_MODIFY + recurNum)); } sMeeting.setSignupAttachments(upToDateList); return; } if (recurNum == 0) { for (int i = upToDateList.size() - 1; i >= 0; i--) { String upToDateResourceId = upToDateList.get(i).getResourceId(); int index = upToDateResourceId.lastIndexOf("/"); if (index > -1) { upToDateResourceId = upToDateResourceId.substring(0, index + 1) + ATTACH_TEMP + "/" + upToDateResourceId.substring(index + 1, upToDateResourceId.length()); } boolean found = false; for (Iterator iter = currentAttachList.iterator(); iter.hasNext();) { SignupAttachment mdOne = (SignupAttachment) iter.next(); String tm = mdOne.getResourceId(); if (upToDateResourceId.equals(mdOne.getResourceId())) { found = true; this.needToCleanUpAttachInContentHS.add(mdOne); /*duplicated one with original and keep original one*/ iter.remove(); break; } } if (!found) { if (upToDateList.get(i).getTimeslotId() == null) { /*not there any more but not the attendee's attachments*/ this.needToCleanUpAttachInContentHS.add(upToDateList.get(i)); upToDateList.remove(i); } } } /*unchanged attachments needed to copy over for recurrence events purpose*/ List<SignupAttachment> tempList = new ArrayList<SignupAttachment>(upToDateList); for (SignupAttachment curAttach : currentAttachList) { upToDateList.add(getAttachmentHandler().copySignupAttachment(sMeeting, true, curAttach, ATTACH_MODIFY + recurNum)); } /*get currentAttachList contain all and ready for upcoming recurring events*/ for (SignupAttachment tmp : tempList) { if (tmp.getTimeslotId() == null) currentAttachList .add(getAttachmentHandler().copySignupAttachment(sMeeting, true, tmp, ATTACH_TEMP));//recurring purpose } } else { /*case: after first recurring events */ /*clean up*/ if (upToDateList.size() > 0) { for (int i = upToDateList.size() - 1; i >= 0; i--) { SignupAttachment one = upToDateList.get(i); if (one.getTimeslotId() == null) {//only cleanup the main attachments this.needToCleanUpAttachInContentHS.add(one); upToDateList.remove(i); } } } for (SignupAttachment curAttach : currentAttachList) { upToDateList.add(getAttachmentHandler().copySignupAttachment(sMeeting, true, curAttach, ATTACH_MODIFY + recurNum)); } } } public List<TimeslotWrapper> getCustomTimeSlotWrpList() { return customTimeSlotWrpList; } public void setCustomTimeSlotWrpList(List<TimeslotWrapper> customTimeSlotWrpList) { this.customTimeSlotWrpList = customTimeSlotWrpList; } public boolean isUserDefinedTS() { return userDefinedTS; } public void setUserDefinedTS(boolean userDefinedTS) { this.userDefinedTS = userDefinedTS; } public UserDefineTimeslotBean getUserDefineTimeslotBean() { return userDefineTimeslotBean; } public void setUserDefineTimeslotBean(UserDefineTimeslotBean userDefineTimeslotBean) { this.userDefineTimeslotBean = userDefineTimeslotBean; } public SakaiFacade getSakaiFacade() { return sakaiFacade; } public void setSakaiFacade(SakaiFacade sakaiFacade) { this.sakaiFacade = sakaiFacade; } public boolean isCreateGroups() { return createGroups; } public void setCreateGroups(boolean createGroups) { this.createGroups = createGroups; } public String getCoordinators() { return coordinators; } public void setCoordinators(String coordinators) { this.coordinators = coordinators; } public boolean isSendEmailByOwner() { return sendEmailByOwner; } public void setSendEmailByOwner(boolean sendEmailByOwner) { this.sendEmailByOwner = sendEmailByOwner; } }