All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jasig.schedassist.impl.reminder.DefaultReminderServiceImpl Maven / Gradle / Ivy

There is a newer version: 1.1.4
Show newest version
/**
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig licenses this file to you under the Apache 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://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.jasig.schedassist.impl.reminder;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.property.Location;
import net.fortuna.ical4j.model.property.Summary;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.schedassist.ICalendarAccountDao;
import org.jasig.schedassist.SchedulingAssistantService;
import org.jasig.schedassist.impl.events.EmailNotificationApplicationListener;
import org.jasig.schedassist.impl.owner.OwnerDao;
import org.jasig.schedassist.model.AvailableBlock;
import org.jasig.schedassist.model.AvailableBlockBuilder;
import org.jasig.schedassist.model.ICalendarAccount;
import org.jasig.schedassist.model.IScheduleOwner;
import org.jasig.schedassist.model.Reminders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Default {@link ReminderService} implementation.
 * 
 * @author Nicholas Blair
 * @version $Id: DefaultReminderServiceImpl.java 3070 2011-02-09 13:53:34Z npblair $
 */
@Service
public class DefaultReminderServiceImpl implements ReminderService, Runnable {

	private static final String NEWLINE = System.getProperty("line.separator");
	
	private SimpleJdbcTemplate simpleJdbcTemplate;
	private MailSender mailSender;
	private DataFieldMaxValueIncrementer reminderIdSequence;
	private OwnerDao ownerDao;
	private SchedulingAssistantService schedulingAssistantService;
	private ICalendarAccountDao calendarAccountDao;
	private MessageSource messageSource;
	private String noReplyFromAddress = "[email protected]";
	private final Log LOG = LogFactory.getLog(this.getClass());
	/**
	 * 
	 * @param ds
	 */
	@Autowired
	public void setDataSource(DataSource ds) {
		this.simpleJdbcTemplate = new SimpleJdbcTemplate(ds);
	}
	/**
	 * @param mailSender the mailSender to set
	 */
	@Autowired
	public void setMailSender(MailSender mailSender) {
		this.mailSender = mailSender;
	}
	/**
	 * @param reminderIdSequence the reminderIdSequence to set
	 */
	@Autowired
	public void setReminderIdSequence(
			@Qualifier("reminders") DataFieldMaxValueIncrementer reminderIdSequence) {
		this.reminderIdSequence = reminderIdSequence;
	}
	/**
	 * @param ownerDao the ownerDao to set
	 */
	@Autowired
	public void setOwnerDao(OwnerDao ownerDao) {
		this.ownerDao = ownerDao;
	}
	/**
	 * @param schedulingAssistantService the schedulingAssistantService to set
	 */
	@Autowired
	public void setSchedulingAssistantService(
			SchedulingAssistantService schedulingAssistantService) {
		this.schedulingAssistantService = schedulingAssistantService;
	}
	/**
	 * @param calendarAccountDao the calendarAccountDao to set
	 */
	@Autowired
	public void setCalendarAccountDao(@Qualifier("composite") ICalendarAccountDao calendarAccountDao) {
		this.calendarAccountDao = calendarAccountDao;
	}
	/**
	 * @param messageSource the messageSource to set
	 */
	@Autowired
	public void setMessageSource(MessageSource messageSource) {
		this.messageSource = messageSource;
	}
	/**
	 * @param noReplyFromAddress the noReplyFromAddress to set
	 */
	public void setNoReplyFromAddress(String noReplyFromAddress) {
		this.noReplyFromAddress = noReplyFromAddress;
	}

	/*
	 * (non-Javadoc)
	 * @see org.jasig.schedassist.impl.reminder.ReminderService#createEventReminder(org.jasig.schedassist.model.IScheduleOwner, org.jasig.schedassist.model.ICalendarAccount, org.jasig.schedassist.model.AvailableBlock, net.fortuna.ical4j.model.component.VEvent, java.util.Date)
	 */
	@Override
	@Transactional
	public IReminder createEventReminder(IScheduleOwner owner,
			ICalendarAccount recipient, AvailableBlock appointmentBlock, VEvent event, Date sendTime) {
		
		long newReminderId = this.reminderIdSequence.nextLongValue();
		int rows = this.simpleJdbcTemplate.update("insert into reminders (reminder_id,owner_id,recipient,event_start,event_end,send_time) values (?,?,?,?,?,?)",
				newReminderId,
				owner.getId(),
				recipient.getUsername(),
				appointmentBlock.getStartTime(),
				appointmentBlock.getEndTime(),
				sendTime);
		
		if(rows == 1) {
			ReminderImpl reminder = new ReminderImpl(newReminderId, owner, recipient, sendTime, event);
			return reminder;
		} else {
			LOG.error("failed to store reminder for " + owner + ", " + recipient);
			return null;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.jasig.schedassist.impl.reminder.ReminderService#deleteEventReminder(org.jasig.schedassist.impl.reminder.IReminder)
	 */
	@Override
	@Transactional
	public void deleteEventReminder(IReminder reminder) {
		int rows = this.simpleJdbcTemplate.update("delete from reminders where reminder_id=?", reminder.getReminderId());
		if(LOG.isDebugEnabled()) {
			LOG.debug("delete " + reminder + ", rows affected=" + rows);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.jasig.schedassist.impl.reminder.ReminderService#getPendingReminders()
	 */
	@Override
	public List getPendingReminders() {
		Date now = new Date();
		List persisted = this.simpleJdbcTemplate.query(
				"select * from reminders where send_time <= ?", 
				new PersistedReminderImplRowMapper(), 
				now);
		
		List results = new ArrayList(persisted.size());
		for(PersistedReminderImpl p: persisted) {		
			ReminderImpl reminder = complete(p);
			if(reminder != null) {
				results.add(reminder);
			}
		}
		return results;
	}

	/*
	 * (non-Javadoc)
	 * @see org.jasig.schedassist.impl.reminder.ReminderService#getReminder(org.jasig.schedassist.model.IScheduleOwner, org.jasig.schedassist.model.ICalendarAccount, org.jasig.schedassist.model.AvailableBlock)
	 */
	@Override
	public IReminder getReminder(IScheduleOwner owner,
			ICalendarAccount recipient, AvailableBlock appointmentBlock) {
		List persisted = this.simpleJdbcTemplate.query(
				"select * from reminders where owner_id=? and recipient=? and event_start=? and event_end=?", 
				new PersistedReminderImplRowMapper(), 
				owner.getId(),
				recipient.getUsername(),
				appointmentBlock.getStartTime(),
				appointmentBlock.getEndTime());
		
		PersistedReminderImpl p = DataAccessUtils.singleResult(persisted);
		ReminderImpl result = complete(p);
		return result;
	}

	/**
	 * Complete a {@link PersistedReminderImpl} by consulting this instance's
	 * {@link OwnerDao}, {@link ICalendarAccountDao}, and P@link AvailableService}.
	 * 
	 * @param p
	 * @return
	 */
	protected ReminderImpl complete(PersistedReminderImpl p) {
		if(p == null) {
			return null;
		}
		final IScheduleOwner scheduleOwner = this.ownerDao.locateOwnerByAvailableId(p.getOwnerId());
		final ICalendarAccount recipient = this.calendarAccountDao.getCalendarAccount(p.getRecipientId());
		final VEvent event = this.schedulingAssistantService.getExistingAppointment(p.getTargetBlock(), scheduleOwner);
				
		ReminderImpl reminder = new ReminderImpl(p.getReminderId(), scheduleOwner, recipient, p.getSendTime(), event);
		return reminder;
	}
	/*
	 * (non-Javadoc)
	 * @see org.jasig.schedassist.impl.reminder.ReminderService#processPendingReminders()
	 */
	@Override
	public void processPendingReminders() {
		final String propertyValue = System.getProperty("org.jasig.schedassist.runScheduledTasks", "true");
		if(Boolean.parseBoolean(propertyValue)) {
			final List pending = getPendingReminders();
			final int size = pending.size();
			if(size == 0) {
				return;
			}

			LOG.info("begin processing " + size + " pending reminders");
			for(IReminder reminder : pending) {
				sendEmail(reminder);
				deleteEventReminder(reminder);
			}
			LOG.info("completed processing " + size + " reminders");
		} else {
			LOG.debug("ignoring processPendingReminders as 'org.jasig.schedassist.runScheduledTasks' set to false");
		}
	}
	
	/**
	 * Send an email message for this {@link IReminder}.
	 * 
	 * @param reminder
	 */
	protected void sendEmail(IReminder reminder) {
		final IScheduleOwner owner = reminder.getScheduleOwner();
		final ICalendarAccount recipient = reminder.getRecipient();
		final VEvent event = reminder.getEvent();
		if(null != owner && null != recipient && null != event) {
			Reminders reminderPrefs = owner.getRemindersPreference();
			final boolean includeOwner = reminderPrefs.isIncludeOwner();
			
			SimpleMailMessage message = new SimpleMailMessage();
			if(!EmailNotificationApplicationListener.isEmailAddressValid(owner.getCalendarAccount().getEmailAddress())) {
				message.setFrom(noReplyFromAddress);
			} else {
				message.setFrom(owner.getCalendarAccount().getEmailAddress());
			}	
			
			if(includeOwner) {
				message.setTo(new String[] { owner.getCalendarAccount().getEmailAddress(), recipient.getEmailAddress() });
			} else {
				message.setTo(new String[] { recipient.getEmailAddress() });
			}
			
			message.setSubject("Reminder: " + event.getSummary().getValue());
			final String messageBody = createMessageBody(event, owner);
			message.setText(messageBody);
			
			LOG.debug("sending message: " + message.toString());
			mailSender.send(message);
			LOG.debug("message successfully sent");
		} else {
			LOG.debug("skipping send email for reminder with null elements: " + reminder);
		}
	}
	
	/**
	 * Construct the body of the email reminder message from the specified {@link VEvent}.
	 * 
	 * @param event
	 * @param owner
	 * @return
	 */
	protected String createMessageBody(final VEvent event, IScheduleOwner owner) {
		StringBuilder messageBody = new StringBuilder();
		messageBody.append(this.messageSource.getMessage("reminder.email.introduction", new String[] { owner.getCalendarAccount().getDisplayName() }, null));
		messageBody.append(NEWLINE);
		messageBody.append(NEWLINE);
		Summary summary = event.getSummary();
		if(summary != null) {
			messageBody.append(this.messageSource.getMessage("reminder.email.title", new String[] { summary.getValue() }, null));
			messageBody.append(NEWLINE);
		}
		SimpleDateFormat df = new SimpleDateFormat("EEE, MMM d, yyyy");
		SimpleDateFormat tf = new SimpleDateFormat("h:mm a");
		messageBody.append(df.format(event.getStartDate().getDate()));
		messageBody.append(NEWLINE);
		messageBody.append(
				this.messageSource.getMessage("reminder.email.time", 
						new String[] { tf.format(event.getStartDate().getDate()), tf.format(event.getEndDate(true).getDate())}, 
						null));	
		Location location = event.getLocation();
		if(location != null) {
			messageBody.append(NEWLINE);
			messageBody.append(this.messageSource.getMessage("reminder.email.location", new String [] { location.getValue() }, null));
		}
		messageBody.append(NEWLINE);
		messageBody.append(NEWLINE);
		messageBody.append(this.messageSource.getMessage("reminder.email.footer", null, null));
		return messageBody.toString();
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	@Scheduled(fixedDelay=60000)
	@Override
	public void run() {
		processPendingReminders();
	}

	/**
	 * Represents a persisted {@link IReminder}.
	 * {@link #getRecipient()}, {@link #getScheduleOwner()}, and {@link #getEvent()} 
	 * intentionally always return null.
	 * 
	 * @see DefaultReminderServiceImpl#complete(PersistedReminderImpl)
	 * @author Nicholas Blair, [email protected]
	 * @version $Id: DefaultReminderServiceImpl.java 3070 2011-02-09 13:53:34Z npblair $
	 */
	protected static class PersistedReminderImpl implements IReminder {

		private long reminderId;
		private long ownerId;
		private String recipientId;
		private Date sendTime;
		private Date blockStartTime;
		private Date blockEndTime;
			
		/**
		 * @return the reminderId
		 */
		public long getReminderId() {
			return reminderId;
		}
		/**
		 * @param reminderId the reminderId to set
		 */
		public void setReminderId(long reminderId) {
			this.reminderId = reminderId;
		}
		/**
		 * @return the ownerId
		 */
		public long getOwnerId() {
			return ownerId;
		}
		/**
		 * @param ownerId the ownerId to set
		 */
		public void setOwnerId(long ownerId) {
			this.ownerId = ownerId;
		}
		/**
		 * @return the recipientId
		 */
		public String getRecipientId() {
			return recipientId;
		}
		/**
		 * @param recipientId the recipientId to set
		 */
		public void setRecipientId(String recipientId) {
			this.recipientId = recipientId;
		}
		/**
		 * @return the sendTime
		 */
		public Date getSendTime() {
			return sendTime;
		}
		/**
		 * @param sendTime the sendTime to set
		 */
		public void setSendTime(Date sendTime) {
			this.sendTime = sendTime;
		}
		/**
		 * @return the blockStartTime
		 */
		public Date getBlockStartTime() {
			return blockStartTime;
		}
		/**
		 * @param blockStartTime the blockStartTime to set
		 */
		public void setBlockStartTime(Date blockStartTime) {
			this.blockStartTime = blockStartTime;
		}
		/**
		 * @return the blockEndTime
		 */
		public Date getBlockEndTime() {
			return blockEndTime;
		}
		/**
		 * @param blockEndTime the blockEndTime to set
		 */
		public void setBlockEndTime(Date blockEndTime) {
			this.blockEndTime = blockEndTime;
		}
		/**
		 * 
		 * @return the {@link AvailableBlock} 
		 */
		public AvailableBlock getTargetBlock() {
			return AvailableBlockBuilder.createBlock(blockStartTime, blockEndTime);
		}
		
		
		@Override
		public IScheduleOwner getScheduleOwner() {
			return null;
		}
		
		@Override
		public ICalendarAccount getRecipient() {
			return null;
		}
		
		@Override
		public VEvent getEvent() {
			return null;
		}
	}
	/**
	 * {@link RowMapper} for persisted reminders.
	 *
	 * @author Nicholas Blair, [email protected]
	 * @version $Id: DefaultReminderServiceImpl.java 3070 2011-02-09 13:53:34Z npblair $
	 */
	static class PersistedReminderImplRowMapper implements RowMapper {

		/* (non-Javadoc)
		 * @see org.springframework.jdbc.core.RowMapper#mapRow(java.sql.ResultSet, int)
		 */
		@Override
		public PersistedReminderImpl mapRow(ResultSet rs, int rowNum)
				throws SQLException {
			PersistedReminderImpl result = new PersistedReminderImpl();
			result.setBlockEndTime(rs.getTimestamp("event_end"));
			result.setBlockStartTime(rs.getTimestamp("event_start"));
			result.setOwnerId(rs.getLong("owner_id"));
			result.setRecipientId(rs.getString("recipient"));
			result.setReminderId(rs.getLong("reminder_id"));
			result.setSendTime(rs.getTimestamp("send_time"));
			return result;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy