package org.sakaiproject.component.app.messageforums;
import java.util.Date;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.api.app.scheduler.DelayedInvocation;
import org.sakaiproject.api.app.scheduler.ScheduledInvocationManager;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.time.api.TimeService;
import org.sakaiproject.api.app.messageforums.Area;
import org.sakaiproject.api.app.messageforums.AreaManager;
import org.sakaiproject.api.app.messageforums.DiscussionForum;
import org.sakaiproject.api.app.messageforums.DiscussionTopic;
import org.sakaiproject.api.app.messageforums.ForumScheduleNotification;
import org.sakaiproject.api.app.messageforums.MessageForumsTypeManager;
import org.sakaiproject.api.app.messageforums.SynopticMsgcntrManager;
import org.sakaiproject.api.app.messageforums.cover.SynopticMsgcntrManagerCover;
import org.sakaiproject.api.app.messageforums.ui.DiscussionForumManager;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
public class ForumScheduleNotificationImpl implements ForumScheduleNotification {
private static final Log LOG = LogFactory.getLog(ForumScheduleNotificationImpl.class);
private static final String AREA_PREFIX = "area-";
private static final String FORUM_PREFIX = "forum-";
private static final String TOPIC_PREFIX = "topic-";
private MessageForumsTypeManager typeManager;
public void setTypeManager(MessageForumsTypeManager typeManager){
this.typeManager = typeManager;
}
private AreaManager areaManager;
public void setAreaManager(AreaManager areaManager){
this.areaManager = areaManager;
}
private DiscussionForumManager forumManager;
public void setForumManager(DiscussionForumManager forumManager){
this.forumManager = forumManager;
}
private TimeService timeService;
public void setTimeService(TimeService timeService)
{
this.timeService = timeService;
}
private ScheduledInvocationManager scheduledInvocationManager;
public void setScheduledInvocationManager(
ScheduledInvocationManager scheduledInvocationManager)
{
this.scheduledInvocationManager = scheduledInvocationManager;
}
public void init() {
LOG.info("init()");
}
public void scheduleAvailability(Area area)
{
scheduleAvailability(AREA_PREFIX + area.getContextId(), area.getAvailabilityRestricted(), area.getOpenDate(), area.getCloseDate());
}
public void scheduleAvailability(DiscussionForum forum)
{
scheduleAvailability(FORUM_PREFIX + forum.getId().toString(), forum.getAvailabilityRestricted(), forum.getOpenDate(), forum.getCloseDate());
}
public void scheduleAvailability(DiscussionTopic topic)
{
scheduleAvailability(TOPIC_PREFIX + topic.getId().toString(), topic.getAvailabilityRestricted(), topic.getOpenDate(), topic.getCloseDate());
}
private void scheduleAvailability(String id, boolean availabilityRestricted, Date openDate, Date closeDate){
// Remove any existing notifications for this area
DelayedInvocation[] fdi = scheduledInvocationManager.findDelayedInvocations("org.sakaiproject.api.app.messageforums.ForumScheduleNotification",
id);
if (fdi != null && fdi.length > 0)
{
for (DelayedInvocation d : fdi)
{
scheduledInvocationManager.deleteDelayedInvocation(d.uuid);
}
}
if (availabilityRestricted)
{
Time openTime = null;
Time closeTime = null;
if(openDate != null){
openTime = timeService.newTime(openDate.getTime());
}
if(closeDate != null){
closeTime = timeService.newTime(closeDate.getTime());
}
// Schedule the new notification
if (openTime != null && openTime.after(timeService.newTime()))
{
scheduledInvocationManager.createDelayedInvocation(openTime,
"org.sakaiproject.api.app.messageforums.ForumScheduleNotification",
id);
}
if(closeTime != null && closeTime.after(timeService.newTime())){
scheduledInvocationManager.createDelayedInvocation(closeTime,
"org.sakaiproject.api.app.messageforums.ForumScheduleNotification",
id);
}
}
}
public void execute(String opaqueContext){
LOG.info("ForumScheduleNotificationImpl.execute(): " + opaqueContext);
if(opaqueContext.startsWith(AREA_PREFIX)){
String siteId = opaqueContext.substring(AREA_PREFIX.length());
Area area = areaManager.getAreaByContextIdAndTypeId(siteId, typeManager.getDiscussionForumType());
boolean makeAvailable = makeAvailableHelper(area.getAvailabilityRestricted(), area.getOpenDate(), area.getCloseDate());
boolean madeChange = false;
if(area.getAvailability()){
if(!makeAvailable){
//make area unavailable:
area.setAvailability(makeAvailable);
madeChange = true;
}
}else{
if(makeAvailable){
//make area available:
area.setAvailability(makeAvailable);
madeChange = true;
}
}
if(madeChange){
//save area and update synoptic counts
areaManager.saveArea(area);
SynopticMsgcntrManagerCover.resetAllUsersSynopticInfoInSite(siteId);
}
}else if(opaqueContext.startsWith(FORUM_PREFIX)){
Long forumId = Long.parseLong(opaqueContext.substring(FORUM_PREFIX.length()));
DiscussionForum forum = forumManager.getForumById(forumId);
boolean makeAvailable = makeAvailableHelper(forum.getAvailabilityRestricted(), forum.getOpenDate(), forum.getCloseDate());
boolean madeChange = false;
if(forum.getAvailability()){
if(!makeAvailable){
//make area unavailable:
forum.setAvailability(makeAvailable);
madeChange = true;
}
}else{
if(makeAvailable){
//make area available:
forum.setAvailability(makeAvailable);
madeChange = true;
}
}
if(madeChange){
//save forum and update synoptic counts
String siteId = forumManager.getContextForForumById(forumId);
HashMap<String, Integer> beforeChangeHM = SynopticMsgcntrManagerCover.getUserToNewMessagesForForumMap(siteId, forum.getId(), null);
forumManager.saveForum(forum, forum.getDraft(), siteId, false, "-forumScheduler-");
updateSynopticMessagesForForumComparingOldMessagesCount(siteId, forum.getId(), null, beforeChangeHM, SynopticMsgcntrManager.NUM_OF_ATTEMPTS);
}
}else if(opaqueContext.startsWith(TOPIC_PREFIX)){
Long topicId = Long.parseLong(opaqueContext.substring(TOPIC_PREFIX.length()));
DiscussionTopic topic = forumManager.getTopicById(topicId);
boolean makeAvailable = makeAvailableHelper(topic.getAvailabilityRestricted(), topic.getOpenDate(), topic.getCloseDate());
boolean madeChange = false;
if(topic.getAvailability()){
if(!makeAvailable){
//make area unavailable:
topic.setAvailability(makeAvailable);
madeChange = true;
}
}else{
if(makeAvailable){
//make area available:
topic.setAvailability(makeAvailable);
madeChange = true;
}
}
if(madeChange){
//save forum and update synoptic counts
String siteId = forumManager.getContextForTopicById(topicId);
HashMap<String, Integer> beforeChangeHM = SynopticMsgcntrManagerCover.getUserToNewMessagesForForumMap(siteId, topic.getBaseForum().getId(), topic.getId());
forumManager.saveTopic(topic, topic.getDraft(), false, "-forumScheduler-");
updateSynopticMessagesForForumComparingOldMessagesCount(siteId, topic.getBaseForum().getId(), topic.getId(), beforeChangeHM, SynopticMsgcntrManager.NUM_OF_ATTEMPTS);
}
}
}
public boolean makeAvailableHelper(boolean availabilityRestricted, Date openDate, Date closeDate){
boolean makeAvailable = true;
if(availabilityRestricted){
//availability is being restricted:
makeAvailable = false;
boolean afterOpen = false;
boolean beforeClose = false;
Time openTime = null;
Time closeTime = null;
if(openDate != null){
openTime = timeService.newTime(openDate.getTime());
}
if(closeDate != null){
closeTime = timeService.newTime(closeDate.getTime());
}
if(closeDate == null && openDate == null){
//user didn't specify either, so open topic
makeAvailable = true;
}
if(openTime != null && openTime.before(timeService.newTime())){
afterOpen = true;
}else if(openTime == null){
afterOpen = true;
}
if(closeTime != null && closeTime.after(timeService.newTime())){
beforeClose = true;
}else if(closeTime == null){
beforeClose = true;
}
if(afterOpen && beforeClose){
makeAvailable = true;
}
}
return makeAvailable;
}
public void updateSynopticMessagesForForumComparingOldMessagesCount(String siteId, Long forumId, Long topicId, HashMap<String, Integer> beforeChangeHM, int numOfAttempts) {
try {
// update synotpic info for forums only:
SynopticMsgcntrManagerCover
.updateSynopticMessagesForForumComparingOldMessagesCount(
siteId, forumId, topicId, beforeChangeHM);
} catch (HibernateOptimisticLockingFailureException holfe) {
// failed, so wait and try again
try {
Thread.sleep(SynopticMsgcntrManager.OPT_LOCK_WAIT);
} catch (InterruptedException e) {
e.printStackTrace();
}
numOfAttempts--;
if (numOfAttempts <= 0) {
System.out
.println("ForumScheduleNotificationImpl: HibernateOptimisticLockingFailureException no more retries left");
holfe.printStackTrace();
} else {
System.out
.println("ForumScheduleNotificationImpl: HibernateOptimisticLockingFailureException: attempts left: "
+ numOfAttempts);
updateSynopticMessagesForForumComparingOldMessagesCount(siteId,
forumId, topicId, beforeChangeHM, numOfAttempts);
}
}
}
}